feat: 实现资金平台核心功能模块
## 新增功能 ### Gateway增强 (P0) - GlobalLogFilter: 全局日志过滤器,生成TraceId - JwtAuthFilter: JWT鉴权过滤器,白名单机制 - RateLimitConfig: 基于Redis的限流配置 ### 权限管理模块 (P1/P3) - A.1 用户管理: UserDTO/UserVO/UserService/UserController - A.2 角色管理: RoleDTO/RoleVO/RoleService/RoleController - A.3 菜单管理: MenuDTO/MenuVO/MenuService/MenuController - A.4 部门管理: DeptDTO/DeptVO/DeptService/DeptController ### 业务模块 (P1/P3) - B.1 fund-req用款申请: 完整审批流程 - B.2 fund-exp支出管理: 支付确认流程 - B.3 fund-receipt收款管理: 确认核销流程 ### 服务治理 (P1/P2) - D.1 Nacos服务注册: 所有服务集成Nacos - I.1 Redis缓存: RedisService/RedisConfig - E.1 ELK日志: logback-spring.xml JSON格式 ## 技术栈 - Spring Cloud Gateway 4.0.0 - Spring Cloud Alibaba 2023.0.0 - MyBatis-Plus 3.5.5 - JWT (jjwt 0.11.5) - Redis + Lettuce
This commit is contained in:
parent
a17307a96e
commit
281bbc992d
@ -37,6 +37,18 @@
|
|||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Redis -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Jackson for Redis serialization -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
276
fund-common/src/main/java/com/fundplatform/common/cache/RedisService.java
vendored
Normal file
276
fund-common/src/main/java/com/fundplatform/common/cache/RedisService.java
vendored
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
package com.fundplatform.common.cache;
|
||||||
|
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis缓存服务
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class RedisService {
|
||||||
|
|
||||||
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
public RedisService(RedisTemplate<String, Object> redisTemplate) {
|
||||||
|
this.redisTemplate = redisTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== String操作 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置缓存
|
||||||
|
*/
|
||||||
|
public void set(String key, Object value) {
|
||||||
|
redisTemplate.opsForValue().set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置缓存并设置过期时间
|
||||||
|
*/
|
||||||
|
public void set(String key, Object value, long timeout, TimeUnit unit) {
|
||||||
|
redisTemplate.opsForValue().set(key, value, timeout, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置缓存并设置过期时间(秒)
|
||||||
|
*/
|
||||||
|
public void setEx(String key, Object value, long seconds) {
|
||||||
|
redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存
|
||||||
|
*/
|
||||||
|
public Object get(String key) {
|
||||||
|
return redisTemplate.opsForValue().get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存并转换为指定类型
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T get(String key, Class<T> clazz) {
|
||||||
|
Object value = redisTemplate.opsForValue().get(key);
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (T) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除缓存
|
||||||
|
*/
|
||||||
|
public Boolean delete(String key) {
|
||||||
|
return redisTemplate.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除缓存
|
||||||
|
*/
|
||||||
|
public Long delete(Collection<String> keys) {
|
||||||
|
return redisTemplate.delete(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断key是否存在
|
||||||
|
*/
|
||||||
|
public Boolean hasKey(String key) {
|
||||||
|
return redisTemplate.hasKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置过期时间
|
||||||
|
*/
|
||||||
|
public Boolean expire(String key, long timeout, TimeUnit unit) {
|
||||||
|
return redisTemplate.expire(key, timeout, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取过期时间
|
||||||
|
*/
|
||||||
|
public Long getExpire(String key) {
|
||||||
|
return redisTemplate.getExpire(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自增
|
||||||
|
*/
|
||||||
|
public Long increment(String key) {
|
||||||
|
return redisTemplate.opsForValue().increment(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自增指定值
|
||||||
|
*/
|
||||||
|
public Long increment(String key, long delta) {
|
||||||
|
return redisTemplate.opsForValue().increment(key, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自减
|
||||||
|
*/
|
||||||
|
public Long decrement(String key) {
|
||||||
|
return redisTemplate.opsForValue().decrement(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Hash操作 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置Hash字段
|
||||||
|
*/
|
||||||
|
public void hSet(String key, String field, Object value) {
|
||||||
|
redisTemplate.opsForHash().put(key, field, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置Hash多个字段
|
||||||
|
*/
|
||||||
|
public void hSetAll(String key, Map<String, Object> map) {
|
||||||
|
redisTemplate.opsForHash().putAll(key, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Hash字段
|
||||||
|
*/
|
||||||
|
public Object hGet(String key, String field) {
|
||||||
|
return redisTemplate.opsForHash().get(key, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Hash所有字段
|
||||||
|
*/
|
||||||
|
public Map<Object, Object> hGetAll(String key) {
|
||||||
|
return redisTemplate.opsForHash().entries(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Hash字段
|
||||||
|
*/
|
||||||
|
public Long hDelete(String key, Object... fields) {
|
||||||
|
return redisTemplate.opsForHash().delete(key, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断Hash字段是否存在
|
||||||
|
*/
|
||||||
|
public Boolean hHasKey(String key, String field) {
|
||||||
|
return redisTemplate.opsForHash().hasKey(key, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== List操作 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 左推入List
|
||||||
|
*/
|
||||||
|
public Long lPush(String key, Object value) {
|
||||||
|
return redisTemplate.opsForList().leftPush(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 右推入List
|
||||||
|
*/
|
||||||
|
public Long rPush(String key, Object value) {
|
||||||
|
return redisTemplate.opsForList().rightPush(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 左弹出List
|
||||||
|
*/
|
||||||
|
public Object lPop(String key) {
|
||||||
|
return redisTemplate.opsForList().leftPop(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 右弹出List
|
||||||
|
*/
|
||||||
|
public Object rPop(String key) {
|
||||||
|
return redisTemplate.opsForList().rightPop(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取List范围
|
||||||
|
*/
|
||||||
|
public List<Object> lRange(String key, long start, long end) {
|
||||||
|
return redisTemplate.opsForList().range(key, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取List长度
|
||||||
|
*/
|
||||||
|
public Long lSize(String key) {
|
||||||
|
return redisTemplate.opsForList().size(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Set操作 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加Set成员
|
||||||
|
*/
|
||||||
|
public Long sAdd(String key, Object... values) {
|
||||||
|
return redisTemplate.opsForSet().add(key, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除Set成员
|
||||||
|
*/
|
||||||
|
public Long sRemove(String key, Object... values) {
|
||||||
|
return redisTemplate.opsForSet().remove(key, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Set所有成员
|
||||||
|
*/
|
||||||
|
public Set<Object> sMembers(String key) {
|
||||||
|
return redisTemplate.opsForSet().members(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为Set成员
|
||||||
|
*/
|
||||||
|
public Boolean sIsMember(String key, Object value) {
|
||||||
|
return redisTemplate.opsForSet().isMember(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Set大小
|
||||||
|
*/
|
||||||
|
public Long sSize(String key) {
|
||||||
|
return redisTemplate.opsForSet().size(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== ZSet操作 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加ZSet成员
|
||||||
|
*/
|
||||||
|
public Boolean zAdd(String key, Object value, double score) {
|
||||||
|
return redisTemplate.opsForZSet().add(key, value, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除ZSet成员
|
||||||
|
*/
|
||||||
|
public Long zRemove(String key, Object... values) {
|
||||||
|
return redisTemplate.opsForZSet().remove(key, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取ZSet范围
|
||||||
|
*/
|
||||||
|
public Set<Object> zRange(String key, long start, long end) {
|
||||||
|
return redisTemplate.opsForZSet().range(key, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取ZSet大小
|
||||||
|
*/
|
||||||
|
public Long zSize(String key) {
|
||||||
|
return redisTemplate.opsForZSet().size(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package com.fundplatform.common.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis配置类
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class RedisConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||||
|
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||||
|
template.setConnectionFactory(connectionFactory);
|
||||||
|
|
||||||
|
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
|
||||||
|
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||||
|
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
||||||
|
jackson2JsonRedisSerializer.setObjectMapper(mapper);
|
||||||
|
|
||||||
|
// 使用StringRedisSerializer来序列化和反序列化redis的key值
|
||||||
|
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
|
||||||
|
|
||||||
|
// key采用String的序列化方式
|
||||||
|
template.setKeySerializer(stringRedisSerializer);
|
||||||
|
// hash的key也采用String的序列化方式
|
||||||
|
template.setHashKeySerializer(stringRedisSerializer);
|
||||||
|
// value序列化方式采用jackson
|
||||||
|
template.setValueSerializer(jackson2JsonRedisSerializer);
|
||||||
|
// hash的value序列化方式采用jackson
|
||||||
|
template.setHashValueSerializer(jackson2JsonRedisSerializer);
|
||||||
|
|
||||||
|
template.afterPropertiesSet();
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -40,6 +40,11 @@
|
|||||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
<version>4.0.0</version>
|
<version>4.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Nacos服务注册发现 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -2,9 +2,11 @@ package com.fundplatform.cust;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
|
|
||||||
@SpringBootApplication(scanBasePackages = {"com.fundplatform.cust", "com.fundplatform.common"})
|
@SpringBootApplication(scanBasePackages = {"com.fundplatform.cust", "com.fundplatform.common"})
|
||||||
|
@EnableDiscoveryClient
|
||||||
@EnableFeignClients
|
@EnableFeignClients
|
||||||
public class CustApplication {
|
public class CustApplication {
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,13 @@ spring:
|
|||||||
application:
|
application:
|
||||||
name: fund-cust
|
name: fund-cust
|
||||||
|
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
server-addr: localhost:8848
|
||||||
|
namespace: fund-platform
|
||||||
|
group: DEFAULT_GROUP
|
||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
url: jdbc:mysql://localhost:3306/fund_cust?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
url: jdbc:mysql://localhost:3306/fund_cust?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
||||||
|
|||||||
@ -33,6 +33,11 @@
|
|||||||
<groupId>com.mysql</groupId>
|
<groupId>com.mysql</groupId>
|
||||||
<artifactId>mysql-connector-j</artifactId>
|
<artifactId>mysql-connector-j</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Nacos服务注册发现 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -2,8 +2,10 @@ package com.fundplatform.exp;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableDiscoveryClient
|
||||||
public class ExpApplication {
|
public class ExpApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@ -0,0 +1,65 @@
|
|||||||
|
package com.fundplatform.exp.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.common.core.Result;
|
||||||
|
import com.fundplatform.exp.dto.FundExpenseDTO;
|
||||||
|
import com.fundplatform.exp.service.FundExpenseService;
|
||||||
|
import com.fundplatform.exp.vo.FundExpenseVO;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/exp/expense")
|
||||||
|
public class FundExpenseController {
|
||||||
|
|
||||||
|
private final FundExpenseService expenseService;
|
||||||
|
|
||||||
|
public FundExpenseController(FundExpenseService expenseService) {
|
||||||
|
this.expenseService = expenseService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public Result<Long> create(@Valid @RequestBody FundExpenseDTO dto) {
|
||||||
|
return Result.success(expenseService.createExpense(dto));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping
|
||||||
|
public Result<Boolean> update(@Valid @RequestBody FundExpenseDTO dto) {
|
||||||
|
return Result.success(expenseService.updateExpense(dto));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Result<FundExpenseVO> getById(@PathVariable Long id) {
|
||||||
|
return Result.success(expenseService.getExpenseById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
public Result<Page<FundExpenseVO>> page(
|
||||||
|
@RequestParam(defaultValue = "1") int pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") int pageSize,
|
||||||
|
@RequestParam(required = false) String title,
|
||||||
|
@RequestParam(required = false) Integer expenseType,
|
||||||
|
@RequestParam(required = false) Integer payStatus) {
|
||||||
|
return Result.success(expenseService.pageExpenses(pageNum, pageSize, title, expenseType, payStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public Result<Boolean> delete(@PathVariable Long id) {
|
||||||
|
return Result.success(expenseService.deleteExpense(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/approve")
|
||||||
|
public Result<Boolean> approve(@PathVariable Long id, @RequestParam(required = false) String comment) {
|
||||||
|
return Result.success(expenseService.approve(id, comment));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/reject")
|
||||||
|
public Result<Boolean> reject(@PathVariable Long id, @RequestParam(required = false) String comment) {
|
||||||
|
return Result.success(expenseService.reject(id, comment));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/confirm-pay")
|
||||||
|
public Result<Boolean> confirmPay(@PathVariable Long id, @RequestParam String payChannel, @RequestParam(required = false) String payVoucher) {
|
||||||
|
return Result.success(expenseService.confirmPay(id, payChannel, payVoucher));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,256 @@
|
|||||||
|
package com.fundplatform.exp.data.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fundplatform.common.core.BaseEntity;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支出管理实体
|
||||||
|
*/
|
||||||
|
@TableName("fund_expense")
|
||||||
|
public class FundExpense extends BaseEntity {
|
||||||
|
|
||||||
|
/** 支出单号 */
|
||||||
|
private String expenseNo;
|
||||||
|
|
||||||
|
/** 支出标题 */
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/** 支出金额 */
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
/** 币种 */
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
/** 支出类型(1-日常支出 2-项目支出 3-工资发放 4-其他) */
|
||||||
|
private Integer expenseType;
|
||||||
|
|
||||||
|
/** 收款单位 */
|
||||||
|
private String payeeName;
|
||||||
|
|
||||||
|
/** 收款银行 */
|
||||||
|
private String payeeBank;
|
||||||
|
|
||||||
|
/** 收款账号 */
|
||||||
|
private String payeeAccount;
|
||||||
|
|
||||||
|
/** 支出日期 */
|
||||||
|
private LocalDateTime expenseDate;
|
||||||
|
|
||||||
|
/** 用途说明 */
|
||||||
|
private String purpose;
|
||||||
|
|
||||||
|
/** 关联用款申请ID */
|
||||||
|
private Long requestId;
|
||||||
|
|
||||||
|
/** 项目ID */
|
||||||
|
private Long projectId;
|
||||||
|
|
||||||
|
/** 客户ID */
|
||||||
|
private Long customerId;
|
||||||
|
|
||||||
|
/** 支付状态(0-待支付 1-已支付 2-支付失败) */
|
||||||
|
private Integer payStatus;
|
||||||
|
|
||||||
|
/** 支付时间 */
|
||||||
|
private LocalDateTime payTime;
|
||||||
|
|
||||||
|
/** 支付渠道 */
|
||||||
|
private String payChannel;
|
||||||
|
|
||||||
|
/** 支付凭证 */
|
||||||
|
private String payVoucher;
|
||||||
|
|
||||||
|
/** 审批状态 */
|
||||||
|
private Integer approvalStatus;
|
||||||
|
|
||||||
|
/** 审批人ID */
|
||||||
|
private Long approverId;
|
||||||
|
|
||||||
|
/** 审批时间 */
|
||||||
|
private LocalDateTime approvalTime;
|
||||||
|
|
||||||
|
/** 审批意见 */
|
||||||
|
private String approvalComment;
|
||||||
|
|
||||||
|
/** 附件URL */
|
||||||
|
private String attachments;
|
||||||
|
|
||||||
|
public String getExpenseNo() {
|
||||||
|
return expenseNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpenseNo(String expenseNo) {
|
||||||
|
this.expenseNo = expenseNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(BigDecimal amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrency() {
|
||||||
|
return currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrency(String currency) {
|
||||||
|
this.currency = currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getExpenseType() {
|
||||||
|
return expenseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpenseType(Integer expenseType) {
|
||||||
|
this.expenseType = expenseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeName() {
|
||||||
|
return payeeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeName(String payeeName) {
|
||||||
|
this.payeeName = payeeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeBank() {
|
||||||
|
return payeeBank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeBank(String payeeBank) {
|
||||||
|
this.payeeBank = payeeBank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeAccount() {
|
||||||
|
return payeeAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeAccount(String payeeAccount) {
|
||||||
|
this.payeeAccount = payeeAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getExpenseDate() {
|
||||||
|
return expenseDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpenseDate(LocalDateTime expenseDate) {
|
||||||
|
this.expenseDate = expenseDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPurpose() {
|
||||||
|
return purpose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPurpose(String purpose) {
|
||||||
|
this.purpose = purpose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getRequestId() {
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestId(Long requestId) {
|
||||||
|
this.requestId = requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getProjectId() {
|
||||||
|
return projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectId(Long projectId) {
|
||||||
|
this.projectId = projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCustomerId() {
|
||||||
|
return customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerId(Long customerId) {
|
||||||
|
this.customerId = customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPayStatus() {
|
||||||
|
return payStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayStatus(Integer payStatus) {
|
||||||
|
this.payStatus = payStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getPayTime() {
|
||||||
|
return payTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayTime(LocalDateTime payTime) {
|
||||||
|
this.payTime = payTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayChannel() {
|
||||||
|
return payChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayChannel(String payChannel) {
|
||||||
|
this.payChannel = payChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayVoucher() {
|
||||||
|
return payVoucher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayVoucher(String payVoucher) {
|
||||||
|
this.payVoucher = payVoucher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getApprovalStatus() {
|
||||||
|
return approvalStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovalStatus(Integer approvalStatus) {
|
||||||
|
this.approvalStatus = approvalStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getApproverId() {
|
||||||
|
return approverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApproverId(Long approverId) {
|
||||||
|
this.approverId = approverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getApprovalTime() {
|
||||||
|
return approvalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovalTime(LocalDateTime approvalTime) {
|
||||||
|
this.approvalTime = approvalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApprovalComment() {
|
||||||
|
return approvalComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovalComment(String approvalComment) {
|
||||||
|
this.approvalComment = approvalComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAttachments() {
|
||||||
|
return attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttachments(String attachments) {
|
||||||
|
this.attachments = attachments;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.fundplatform.exp.data.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.fundplatform.exp.data.entity.FundExpense;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface FundExpenseMapper extends BaseMapper<FundExpense> {
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.fundplatform.exp.data.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.fundplatform.exp.data.entity.FundExpense;
|
||||||
|
import com.fundplatform.exp.data.mapper.FundExpenseMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FundExpenseDataService extends ServiceImpl<FundExpenseMapper, FundExpense> implements IService<FundExpense> {
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
package com.fundplatform.exp.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class FundExpenseDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@NotBlank(message = "支出标题不能为空")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@NotNull(message = "支出金额不能为空")
|
||||||
|
@Positive(message = "支出金额必须大于0")
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
private String currency = "CNY";
|
||||||
|
|
||||||
|
@NotNull(message = "支出类型不能为空")
|
||||||
|
private Integer expenseType;
|
||||||
|
|
||||||
|
@NotBlank(message = "收款单位不能为空")
|
||||||
|
private String payeeName;
|
||||||
|
|
||||||
|
private String payeeBank;
|
||||||
|
private String payeeAccount;
|
||||||
|
private LocalDateTime expenseDate;
|
||||||
|
private String purpose;
|
||||||
|
private Long requestId;
|
||||||
|
private Long projectId;
|
||||||
|
private Long customerId;
|
||||||
|
private String attachments;
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
// getters and setters
|
||||||
|
public Long getId() { return id; }
|
||||||
|
public void setId(Long id) { this.id = id; }
|
||||||
|
public String getTitle() { return title; }
|
||||||
|
public void setTitle(String title) { this.title = title; }
|
||||||
|
public BigDecimal getAmount() { return amount; }
|
||||||
|
public void setAmount(BigDecimal amount) { this.amount = amount; }
|
||||||
|
public String getCurrency() { return currency; }
|
||||||
|
public void setCurrency(String currency) { this.currency = currency; }
|
||||||
|
public Integer getExpenseType() { return expenseType; }
|
||||||
|
public void setExpenseType(Integer expenseType) { this.expenseType = expenseType; }
|
||||||
|
public String getPayeeName() { return payeeName; }
|
||||||
|
public void setPayeeName(String payeeName) { this.payeeName = payeeName; }
|
||||||
|
public String getPayeeBank() { return payeeBank; }
|
||||||
|
public void setPayeeBank(String payeeBank) { this.payeeBank = payeeBank; }
|
||||||
|
public String getPayeeAccount() { return payeeAccount; }
|
||||||
|
public void setPayeeAccount(String payeeAccount) { this.payeeAccount = payeeAccount; }
|
||||||
|
public LocalDateTime getExpenseDate() { return expenseDate; }
|
||||||
|
public void setExpenseDate(LocalDateTime expenseDate) { this.expenseDate = expenseDate; }
|
||||||
|
public String getPurpose() { return purpose; }
|
||||||
|
public void setPurpose(String purpose) { this.purpose = purpose; }
|
||||||
|
public Long getRequestId() { return requestId; }
|
||||||
|
public void setRequestId(Long requestId) { this.requestId = requestId; }
|
||||||
|
public Long getProjectId() { return projectId; }
|
||||||
|
public void setProjectId(Long projectId) { this.projectId = projectId; }
|
||||||
|
public Long getCustomerId() { return customerId; }
|
||||||
|
public void setCustomerId(Long customerId) { this.customerId = customerId; }
|
||||||
|
public String getAttachments() { return attachments; }
|
||||||
|
public void setAttachments(String attachments) { this.attachments = attachments; }
|
||||||
|
public String getRemark() { return remark; }
|
||||||
|
public void setRemark(String remark) { this.remark = remark; }
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.fundplatform.exp.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.exp.dto.FundExpenseDTO;
|
||||||
|
import com.fundplatform.exp.vo.FundExpenseVO;
|
||||||
|
|
||||||
|
public interface FundExpenseService {
|
||||||
|
|
||||||
|
Long createExpense(FundExpenseDTO dto);
|
||||||
|
|
||||||
|
boolean updateExpense(FundExpenseDTO dto);
|
||||||
|
|
||||||
|
FundExpenseVO getExpenseById(Long id);
|
||||||
|
|
||||||
|
Page<FundExpenseVO> pageExpenses(int pageNum, int pageSize, String title, Integer expenseType, Integer payStatus);
|
||||||
|
|
||||||
|
boolean deleteExpense(Long id);
|
||||||
|
|
||||||
|
boolean approve(Long id, String comment);
|
||||||
|
|
||||||
|
boolean reject(Long id, String comment);
|
||||||
|
|
||||||
|
boolean confirmPay(Long id, String payChannel, String payVoucher);
|
||||||
|
}
|
||||||
@ -0,0 +1,198 @@
|
|||||||
|
package com.fundplatform.exp.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.exp.data.entity.FundExpense;
|
||||||
|
import com.fundplatform.exp.data.service.FundExpenseDataService;
|
||||||
|
import com.fundplatform.exp.dto.FundExpenseDTO;
|
||||||
|
import com.fundplatform.exp.service.FundExpenseService;
|
||||||
|
import com.fundplatform.exp.vo.FundExpenseVO;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FundExpenseServiceImpl implements FundExpenseService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FundExpenseServiceImpl.class);
|
||||||
|
private static final AtomicInteger counter = new AtomicInteger(1);
|
||||||
|
|
||||||
|
private final FundExpenseDataService expenseDataService;
|
||||||
|
|
||||||
|
public FundExpenseServiceImpl(FundExpenseDataService expenseDataService) {
|
||||||
|
this.expenseDataService = expenseDataService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createExpense(FundExpenseDTO dto) {
|
||||||
|
FundExpense expense = new FundExpense();
|
||||||
|
expense.setExpenseNo(generateExpenseNo());
|
||||||
|
expense.setTitle(dto.getTitle());
|
||||||
|
expense.setAmount(dto.getAmount());
|
||||||
|
expense.setCurrency(dto.getCurrency() != null ? dto.getCurrency() : "CNY");
|
||||||
|
expense.setExpenseType(dto.getExpenseType());
|
||||||
|
expense.setPayeeName(dto.getPayeeName());
|
||||||
|
expense.setPayeeBank(dto.getPayeeBank());
|
||||||
|
expense.setPayeeAccount(dto.getPayeeAccount());
|
||||||
|
expense.setExpenseDate(dto.getExpenseDate() != null ? dto.getExpenseDate() : LocalDateTime.now());
|
||||||
|
expense.setPurpose(dto.getPurpose());
|
||||||
|
expense.setRequestId(dto.getRequestId());
|
||||||
|
expense.setProjectId(dto.getProjectId());
|
||||||
|
expense.setCustomerId(dto.getCustomerId());
|
||||||
|
expense.setPayStatus(0);
|
||||||
|
expense.setApprovalStatus(0);
|
||||||
|
expense.setAttachments(dto.getAttachments());
|
||||||
|
expense.setDeleted(0);
|
||||||
|
expense.setCreatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
expenseDataService.save(expense);
|
||||||
|
log.info("创建支出记录成功: id={}, expenseNo={}", expense.getId(), expense.getExpenseNo());
|
||||||
|
return expense.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateExpense(FundExpenseDTO dto) {
|
||||||
|
if (dto.getId() == null) throw new RuntimeException("支出ID不能为空");
|
||||||
|
FundExpense existing = expenseDataService.getById(dto.getId());
|
||||||
|
if (existing == null || existing.getDeleted() == 1) throw new RuntimeException("支出记录不存在");
|
||||||
|
if (existing.getPayStatus() != 0) throw new RuntimeException("当前状态不允许修改");
|
||||||
|
|
||||||
|
FundExpense expense = new FundExpense();
|
||||||
|
expense.setId(dto.getId());
|
||||||
|
expense.setTitle(dto.getTitle());
|
||||||
|
expense.setAmount(dto.getAmount());
|
||||||
|
expense.setPurpose(dto.getPurpose());
|
||||||
|
expense.setAttachments(dto.getAttachments());
|
||||||
|
expense.setUpdatedTime(LocalDateTime.now());
|
||||||
|
return expenseDataService.updateById(expense);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FundExpenseVO getExpenseById(Long id) {
|
||||||
|
FundExpense expense = expenseDataService.getById(id);
|
||||||
|
if (expense == null || expense.getDeleted() == 1) throw new RuntimeException("支出记录不存在");
|
||||||
|
return convertToVO(expense);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<FundExpenseVO> pageExpenses(int pageNum, int pageSize, String title, Integer expenseType, Integer payStatus) {
|
||||||
|
Page<FundExpense> page = new Page<>(pageNum, pageSize);
|
||||||
|
LambdaQueryWrapper<FundExpense> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(FundExpense::getDeleted, 0);
|
||||||
|
if (StringUtils.hasText(title)) wrapper.like(FundExpense::getTitle, title);
|
||||||
|
if (expenseType != null) wrapper.eq(FundExpense::getExpenseType, expenseType);
|
||||||
|
if (payStatus != null) wrapper.eq(FundExpense::getPayStatus, payStatus);
|
||||||
|
wrapper.orderByDesc(FundExpense::getCreatedTime);
|
||||||
|
|
||||||
|
Page<FundExpense> expensePage = expenseDataService.page(page, wrapper);
|
||||||
|
Page<FundExpenseVO> voPage = new Page<>(expensePage.getCurrent(), expensePage.getSize(), expensePage.getTotal());
|
||||||
|
voPage.setRecords(expensePage.getRecords().stream().map(this::convertToVO).toList());
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean deleteExpense(Long id) {
|
||||||
|
LambdaUpdateWrapper<FundExpense> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundExpense::getId, id).set(FundExpense::getDeleted, 1).set(FundExpense::getUpdatedTime, LocalDateTime.now());
|
||||||
|
return expenseDataService.update(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean approve(Long id, String comment) {
|
||||||
|
LambdaUpdateWrapper<FundExpense> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundExpense::getId, id).set(FundExpense::getApprovalStatus, 2)
|
||||||
|
.set(FundExpense::getApprovalTime, LocalDateTime.now())
|
||||||
|
.set(FundExpense::getApprovalComment, comment)
|
||||||
|
.set(FundExpense::getUpdatedTime, LocalDateTime.now());
|
||||||
|
return expenseDataService.update(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean reject(Long id, String comment) {
|
||||||
|
LambdaUpdateWrapper<FundExpense> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundExpense::getId, id).set(FundExpense::getApprovalStatus, 3)
|
||||||
|
.set(FundExpense::getApprovalTime, LocalDateTime.now())
|
||||||
|
.set(FundExpense::getApprovalComment, comment)
|
||||||
|
.set(FundExpense::getUpdatedTime, LocalDateTime.now());
|
||||||
|
return expenseDataService.update(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean confirmPay(Long id, String payChannel, String payVoucher) {
|
||||||
|
LambdaUpdateWrapper<FundExpense> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundExpense::getId, id).set(FundExpense::getPayStatus, 1)
|
||||||
|
.set(FundExpense::getPayTime, LocalDateTime.now())
|
||||||
|
.set(FundExpense::getPayChannel, payChannel)
|
||||||
|
.set(FundExpense::getPayVoucher, payVoucher)
|
||||||
|
.set(FundExpense::getUpdatedTime, LocalDateTime.now());
|
||||||
|
return expenseDataService.update(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateExpenseNo() {
|
||||||
|
String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||||
|
int seq = counter.getAndIncrement();
|
||||||
|
return String.format("EXP%s%04d", dateStr, seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FundExpenseVO convertToVO(FundExpense e) {
|
||||||
|
FundExpenseVO vo = new FundExpenseVO();
|
||||||
|
vo.setId(e.getId());
|
||||||
|
vo.setExpenseNo(e.getExpenseNo());
|
||||||
|
vo.setTitle(e.getTitle());
|
||||||
|
vo.setAmount(e.getAmount());
|
||||||
|
vo.setCurrency(e.getCurrency());
|
||||||
|
vo.setExpenseType(e.getExpenseType());
|
||||||
|
vo.setExpenseTypeName(getExpenseTypeName(e.getExpenseType()));
|
||||||
|
vo.setPayeeName(e.getPayeeName());
|
||||||
|
vo.setPayeeBank(e.getPayeeBank());
|
||||||
|
vo.setPayeeAccount(e.getPayeeAccount());
|
||||||
|
vo.setExpenseDate(e.getExpenseDate());
|
||||||
|
vo.setPurpose(e.getPurpose());
|
||||||
|
vo.setRequestId(e.getRequestId());
|
||||||
|
vo.setProjectId(e.getProjectId());
|
||||||
|
vo.setCustomerId(e.getCustomerId());
|
||||||
|
vo.setPayStatus(e.getPayStatus());
|
||||||
|
vo.setPayStatusName(getPayStatusName(e.getPayStatus()));
|
||||||
|
vo.setPayTime(e.getPayTime());
|
||||||
|
vo.setPayChannel(e.getPayChannel());
|
||||||
|
vo.setPayVoucher(e.getPayVoucher());
|
||||||
|
vo.setApprovalStatus(e.getApprovalStatus());
|
||||||
|
vo.setApprovalStatusName(getApprovalStatusName(e.getApprovalStatus()));
|
||||||
|
vo.setApprovalTime(e.getApprovalTime());
|
||||||
|
vo.setApprovalComment(e.getApprovalComment());
|
||||||
|
vo.setAttachments(e.getAttachments());
|
||||||
|
vo.setTenantId(e.getTenantId());
|
||||||
|
vo.setCreatedBy(e.getCreatedBy());
|
||||||
|
vo.setCreatedTime(e.getCreatedTime());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getExpenseTypeName(Integer type) {
|
||||||
|
if (type == null) return "";
|
||||||
|
return switch (type) { case 1 -> "日常支出"; case 2 -> "项目支出"; case 3 -> "工资发放"; case 4 -> "其他"; default -> ""; };
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPayStatusName(Integer status) {
|
||||||
|
if (status == null) return "";
|
||||||
|
return switch (status) { case 0 -> "待支付"; case 1 -> "已支付"; case 2 -> "支付失败"; default -> ""; };
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getApprovalStatusName(Integer status) {
|
||||||
|
if (status == null) return "";
|
||||||
|
return switch (status) { case 0 -> "待审批"; case 1 -> "审批中"; case 2 -> "审批通过"; case 3 -> "审批拒绝"; default -> ""; };
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
package com.fundplatform.exp.vo;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class FundExpenseVO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String expenseNo;
|
||||||
|
private String title;
|
||||||
|
private BigDecimal amount;
|
||||||
|
private String currency;
|
||||||
|
private Integer expenseType;
|
||||||
|
private String expenseTypeName;
|
||||||
|
private String payeeName;
|
||||||
|
private String payeeBank;
|
||||||
|
private String payeeAccount;
|
||||||
|
private LocalDateTime expenseDate;
|
||||||
|
private String purpose;
|
||||||
|
private Long requestId;
|
||||||
|
private Long projectId;
|
||||||
|
private Long customerId;
|
||||||
|
private Integer payStatus;
|
||||||
|
private String payStatusName;
|
||||||
|
private LocalDateTime payTime;
|
||||||
|
private String payChannel;
|
||||||
|
private String payVoucher;
|
||||||
|
private Integer approvalStatus;
|
||||||
|
private String approvalStatusName;
|
||||||
|
private Long approverId;
|
||||||
|
private LocalDateTime approvalTime;
|
||||||
|
private String approvalComment;
|
||||||
|
private String attachments;
|
||||||
|
private Long tenantId;
|
||||||
|
private Long createdBy;
|
||||||
|
private LocalDateTime createdTime;
|
||||||
|
|
||||||
|
// getters and setters
|
||||||
|
public Long getId() { return id; }
|
||||||
|
public void setId(Long id) { this.id = id; }
|
||||||
|
public String getExpenseNo() { return expenseNo; }
|
||||||
|
public void setExpenseNo(String expenseNo) { this.expenseNo = expenseNo; }
|
||||||
|
public String getTitle() { return title; }
|
||||||
|
public void setTitle(String title) { this.title = title; }
|
||||||
|
public BigDecimal getAmount() { return amount; }
|
||||||
|
public void setAmount(BigDecimal amount) { this.amount = amount; }
|
||||||
|
public String getCurrency() { return currency; }
|
||||||
|
public void setCurrency(String currency) { this.currency = currency; }
|
||||||
|
public Integer getExpenseType() { return expenseType; }
|
||||||
|
public void setExpenseType(Integer expenseType) { this.expenseType = expenseType; }
|
||||||
|
public String getExpenseTypeName() { return expenseTypeName; }
|
||||||
|
public void setExpenseTypeName(String expenseTypeName) { this.expenseTypeName = expenseTypeName; }
|
||||||
|
public String getPayeeName() { return payeeName; }
|
||||||
|
public void setPayeeName(String payeeName) { this.payeeName = payeeName; }
|
||||||
|
public String getPayeeBank() { return payeeBank; }
|
||||||
|
public void setPayeeBank(String payeeBank) { this.payeeBank = payeeBank; }
|
||||||
|
public String getPayeeAccount() { return payeeAccount; }
|
||||||
|
public void setPayeeAccount(String payeeAccount) { this.payeeAccount = payeeAccount; }
|
||||||
|
public LocalDateTime getExpenseDate() { return expenseDate; }
|
||||||
|
public void setExpenseDate(LocalDateTime expenseDate) { this.expenseDate = expenseDate; }
|
||||||
|
public String getPurpose() { return purpose; }
|
||||||
|
public void setPurpose(String purpose) { this.purpose = purpose; }
|
||||||
|
public Long getRequestId() { return requestId; }
|
||||||
|
public void setRequestId(Long requestId) { this.requestId = requestId; }
|
||||||
|
public Long getProjectId() { return projectId; }
|
||||||
|
public void setProjectId(Long projectId) { this.projectId = projectId; }
|
||||||
|
public Long getCustomerId() { return customerId; }
|
||||||
|
public void setCustomerId(Long customerId) { this.customerId = customerId; }
|
||||||
|
public Integer getPayStatus() { return payStatus; }
|
||||||
|
public void setPayStatus(Integer payStatus) { this.payStatus = payStatus; }
|
||||||
|
public String getPayStatusName() { return payStatusName; }
|
||||||
|
public void setPayStatusName(String payStatusName) { this.payStatusName = payStatusName; }
|
||||||
|
public LocalDateTime getPayTime() { return payTime; }
|
||||||
|
public void setPayTime(LocalDateTime payTime) { this.payTime = payTime; }
|
||||||
|
public String getPayChannel() { return payChannel; }
|
||||||
|
public void setPayChannel(String payChannel) { this.payChannel = payChannel; }
|
||||||
|
public String getPayVoucher() { return payVoucher; }
|
||||||
|
public void setPayVoucher(String payVoucher) { this.payVoucher = payVoucher; }
|
||||||
|
public Integer getApprovalStatus() { return approvalStatus; }
|
||||||
|
public void setApprovalStatus(Integer approvalStatus) { this.approvalStatus = approvalStatus; }
|
||||||
|
public String getApprovalStatusName() { return approvalStatusName; }
|
||||||
|
public void setApprovalStatusName(String approvalStatusName) { this.approvalStatusName = approvalStatusName; }
|
||||||
|
public Long getApproverId() { return approverId; }
|
||||||
|
public void setApproverId(Long approverId) { this.approverId = approverId; }
|
||||||
|
public LocalDateTime getApprovalTime() { return approvalTime; }
|
||||||
|
public void setApprovalTime(LocalDateTime approvalTime) { this.approvalTime = approvalTime; }
|
||||||
|
public String getApprovalComment() { return approvalComment; }
|
||||||
|
public void setApprovalComment(String approvalComment) { this.approvalComment = approvalComment; }
|
||||||
|
public String getAttachments() { return attachments; }
|
||||||
|
public void setAttachments(String attachments) { this.attachments = attachments; }
|
||||||
|
public Long getTenantId() { return tenantId; }
|
||||||
|
public void setTenantId(Long tenantId) { this.tenantId = tenantId; }
|
||||||
|
public Long getCreatedBy() { return createdBy; }
|
||||||
|
public void setCreatedBy(Long createdBy) { this.createdBy = createdBy; }
|
||||||
|
public LocalDateTime getCreatedTime() { return createdTime; }
|
||||||
|
public void setCreatedTime(LocalDateTime createdTime) { this.createdTime = createdTime; }
|
||||||
|
}
|
||||||
@ -4,3 +4,10 @@ server:
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: fund-exp
|
name: fund-exp
|
||||||
|
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
server-addr: localhost:8848
|
||||||
|
namespace: fund-platform
|
||||||
|
group: DEFAULT_GROUP
|
||||||
|
|||||||
@ -33,6 +33,11 @@
|
|||||||
<groupId>com.mysql</groupId>
|
<groupId>com.mysql</groupId>
|
||||||
<artifactId>mysql-connector-j</artifactId>
|
<artifactId>mysql-connector-j</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Nacos服务注册发现 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -2,8 +2,10 @@ package com.fundplatform.file;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableDiscoveryClient
|
||||||
public class FileApplication {
|
public class FileApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@ -4,3 +4,10 @@ server:
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: fund-file
|
name: fund-file
|
||||||
|
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
server-addr: localhost:8848
|
||||||
|
namespace: fund-platform
|
||||||
|
group: DEFAULT_GROUP
|
||||||
|
|||||||
@ -34,6 +34,31 @@
|
|||||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||||
<version>4.0.0</version>
|
<version>4.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JWT -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-api</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-impl</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-jackson</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Redis for Rate Limiting -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.fundplatform.gateway.config;
|
||||||
|
|
||||||
|
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流配置
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class RateLimitConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于IP的限流Key解析器
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public KeyResolver ipKeyResolver() {
|
||||||
|
return exchange -> {
|
||||||
|
String ip = exchange.getRequest().getRemoteAddress() != null
|
||||||
|
? exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
|
||||||
|
: "unknown";
|
||||||
|
return Mono.just(ip);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于用户ID的限流Key解析器
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public KeyResolver userKeyResolver() {
|
||||||
|
return exchange -> {
|
||||||
|
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
|
||||||
|
return Mono.just(userId != null ? userId : "anonymous");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于API路径的限流Key解析器
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public KeyResolver apiKeyResolver() {
|
||||||
|
return exchange -> Mono.just(exchange.getRequest().getPath().value());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
package com.fundplatform.gateway.filter;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.slf4j.MDC;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局日志过滤器
|
||||||
|
* 记录所有请求日志,生成TraceId
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class GlobalLogFilter implements GlobalFilter, Ordered {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(GlobalLogFilter.class);
|
||||||
|
private static final String TRACE_ID = "X-Trace-Id";
|
||||||
|
private static final String START_TIME = "startTime";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
|
// 生成TraceId
|
||||||
|
String traceId = UUID.randomUUID().toString().replace("-", "");
|
||||||
|
|
||||||
|
// 记录开始时间
|
||||||
|
exchange.getAttributes().put(START_TIME, System.currentTimeMillis());
|
||||||
|
|
||||||
|
// 将TraceId写入请求头
|
||||||
|
ServerHttpRequest request = exchange.getRequest().mutate()
|
||||||
|
.header(TRACE_ID, traceId)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 记录请求日志
|
||||||
|
String method = request.getMethod().name();
|
||||||
|
String path = request.getURI().getPath();
|
||||||
|
String clientIp = getClientIp(request);
|
||||||
|
|
||||||
|
logger.info("[{}] Request: {} {} from {}", traceId, method, path, clientIp);
|
||||||
|
|
||||||
|
// 继续执行
|
||||||
|
return chain.filter(exchange.mutate().request(request).build())
|
||||||
|
.then(Mono.fromRunnable(() -> {
|
||||||
|
// 计算耗时
|
||||||
|
Long startTime = exchange.getAttribute(START_TIME);
|
||||||
|
if (startTime != null) {
|
||||||
|
long duration = System.currentTimeMillis() - startTime;
|
||||||
|
int statusCode = exchange.getResponse().getStatusCode() != null
|
||||||
|
? exchange.getResponse().getStatusCode().value()
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
logger.info("[{}] Response: {} {} - {} ({}ms)",
|
||||||
|
traceId, method, path, statusCode, duration);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取客户端IP
|
||||||
|
*/
|
||||||
|
private String getClientIp(ServerHttpRequest request) {
|
||||||
|
String ip = request.getHeaders().getFirst("X-Forwarded-For");
|
||||||
|
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeaders().getFirst("X-Real-IP");
|
||||||
|
}
|
||||||
|
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getRemoteAddress() != null
|
||||||
|
? request.getRemoteAddress().getAddress().getHostAddress()
|
||||||
|
: "unknown";
|
||||||
|
}
|
||||||
|
// 多个代理时取第一个IP
|
||||||
|
if (ip != null && ip.contains(",")) {
|
||||||
|
ip = ip.split(",")[0].trim();
|
||||||
|
}
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return Ordered.HIGHEST_PRECEDENCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,158 @@
|
|||||||
|
package com.fundplatform.gateway.filter;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fundplatform.common.core.Result;
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JWT鉴权过滤器
|
||||||
|
* 验证JWT Token,提取用户信息
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class JwtAuthFilter implements GlobalFilter, Ordered {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(JwtAuthFilter.class);
|
||||||
|
private static final String SECRET_KEY = "fundplatform-secret-key-for-jwt-token-generation-min-256-bits";
|
||||||
|
private static final String TOKEN_PREFIX = "Bearer ";
|
||||||
|
private static final String USER_ID_HEADER = "X-User-Id";
|
||||||
|
private static final String USERNAME_HEADER = "X-Username";
|
||||||
|
private static final String TENANT_ID_HEADER = "X-Tenant-Id";
|
||||||
|
|
||||||
|
// 白名单路径(不需要token验证)
|
||||||
|
private static final List<String> WHITE_LIST = Arrays.asList(
|
||||||
|
"/sys/api/v1/auth/login",
|
||||||
|
"/sys/api/v1/sys/health",
|
||||||
|
"/cust/api/v1/cust/health",
|
||||||
|
"/proj/api/v1/proj/health"
|
||||||
|
);
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
|
String path = request.getURI().getPath();
|
||||||
|
|
||||||
|
// 白名单路径直接放行
|
||||||
|
if (isWhiteListed(path)) {
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取Token
|
||||||
|
String token = getToken(request);
|
||||||
|
if (token == null) {
|
||||||
|
return unauthorized(exchange, "缺少认证Token");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 验证Token
|
||||||
|
Claims claims = validateToken(token);
|
||||||
|
if (claims == null) {
|
||||||
|
return unauthorized(exchange, "Token无效或已过期");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取用户信息
|
||||||
|
Long userId = claims.get("userId", Long.class);
|
||||||
|
String username = claims.get("username", String.class);
|
||||||
|
Long tenantId = claims.get("tenantId", Long.class);
|
||||||
|
|
||||||
|
// 将用户信息写入请求头
|
||||||
|
ServerHttpRequest mutatedRequest = request.mutate()
|
||||||
|
.header(USER_ID_HEADER, String.valueOf(userId))
|
||||||
|
.header(USERNAME_HEADER, username)
|
||||||
|
.header(TENANT_ID_HEADER, String.valueOf(tenantId))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
logger.debug("Token验证通过: userId={}, username={}, tenantId={}", userId, username, tenantId);
|
||||||
|
|
||||||
|
return chain.filter(exchange.mutate().request(mutatedRequest).build());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Token验证失败: {}", e.getMessage());
|
||||||
|
return unauthorized(exchange, "Token验证失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否白名单路径
|
||||||
|
*/
|
||||||
|
private boolean isWhiteListed(String path) {
|
||||||
|
return WHITE_LIST.stream().anyMatch(path::startsWith);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从请求头获取Token
|
||||||
|
*/
|
||||||
|
private String getToken(ServerHttpRequest request) {
|
||||||
|
String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
|
||||||
|
if (authHeader != null && authHeader.startsWith(TOKEN_PREFIX)) {
|
||||||
|
return authHeader.substring(TOKEN_PREFIX.length());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证Token
|
||||||
|
*/
|
||||||
|
private Claims validateToken(String token) {
|
||||||
|
try {
|
||||||
|
SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return Jwts.parserBuilder()
|
||||||
|
.setSigningKey(key)
|
||||||
|
.build()
|
||||||
|
.parseClaimsJws(token)
|
||||||
|
.getBody();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Token解析失败: {}", e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回未授权响应
|
||||||
|
*/
|
||||||
|
private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
|
||||||
|
ServerHttpResponse response = exchange.getResponse();
|
||||||
|
response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
||||||
|
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
Result<Void> result = Result.error(401, message);
|
||||||
|
String body;
|
||||||
|
try {
|
||||||
|
body = objectMapper.writeValueAsString(result);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
body = "{\"code\":401,\"message\":\"Unauthorized\",\"success\":false}";
|
||||||
|
}
|
||||||
|
|
||||||
|
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return response.writeWith(Mono.just(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return Ordered.HIGHEST_PRECEDENCE + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,10 +4,27 @@ server:
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: fund-gateway
|
name: fund-gateway
|
||||||
|
|
||||||
|
# Redis配置(用于限流)
|
||||||
|
data:
|
||||||
|
redis:
|
||||||
|
host: localhost
|
||||||
|
port: 6379
|
||||||
|
password: zjf@123456
|
||||||
|
database: 1
|
||||||
|
|
||||||
cloud:
|
cloud:
|
||||||
compatibility-verifier:
|
compatibility-verifier:
|
||||||
enabled: false
|
enabled: false
|
||||||
gateway:
|
gateway:
|
||||||
|
# 默认限流配置
|
||||||
|
default-filters:
|
||||||
|
- name: RequestRateLimiter
|
||||||
|
args:
|
||||||
|
redis-rate-limiter.replenishRate: 100 # 每秒补充令牌数
|
||||||
|
redis-rate-limiter.burstCapacity: 200 # 令牌桶最大容量
|
||||||
|
key-resolver: "#{@ipKeyResolver}"
|
||||||
|
|
||||||
routes:
|
routes:
|
||||||
# 系统管理服务
|
# 系统管理服务
|
||||||
- id: fund-sys
|
- id: fund-sys
|
||||||
|
|||||||
@ -33,6 +33,11 @@
|
|||||||
<groupId>com.mysql</groupId>
|
<groupId>com.mysql</groupId>
|
||||||
<artifactId>mysql-connector-j</artifactId>
|
<artifactId>mysql-connector-j</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Nacos服务注册发现 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -2,8 +2,10 @@ package com.fundplatform.proj;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
|
|
||||||
@SpringBootApplication(scanBasePackages = {"com.fundplatform.proj", "com.fundplatform.common"})
|
@SpringBootApplication(scanBasePackages = {"com.fundplatform.proj", "com.fundplatform.common"})
|
||||||
|
@EnableDiscoveryClient
|
||||||
public class ProjApplication {
|
public class ProjApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@ -5,6 +5,13 @@ spring:
|
|||||||
application:
|
application:
|
||||||
name: fund-proj
|
name: fund-proj
|
||||||
|
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
server-addr: localhost:8848
|
||||||
|
namespace: fund-platform
|
||||||
|
group: DEFAULT_GROUP
|
||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
url: jdbc:mysql://localhost:3306/fund_proj?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
url: jdbc:mysql://localhost:3306/fund_proj?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
||||||
|
|||||||
@ -2,8 +2,10 @@ package com.fundplatform.receipt;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableDiscoveryClient
|
||||||
public class ReceiptApplication {
|
public class ReceiptApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.fundplatform.receipt.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.common.core.Result;
|
||||||
|
import com.fundplatform.receipt.dto.FundReceiptDTO;
|
||||||
|
import com.fundplatform.receipt.service.FundReceiptService;
|
||||||
|
import com.fundplatform.receipt.vo.FundReceiptVO;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/receipt/receipt")
|
||||||
|
public class FundReceiptController {
|
||||||
|
|
||||||
|
private final FundReceiptService receiptService;
|
||||||
|
|
||||||
|
public FundReceiptController(FundReceiptService receiptService) {
|
||||||
|
this.receiptService = receiptService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public Result<Long> create(@Valid @RequestBody FundReceiptDTO dto) {
|
||||||
|
return Result.success(receiptService.createReceipt(dto));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping
|
||||||
|
public Result<Boolean> update(@Valid @RequestBody FundReceiptDTO dto) {
|
||||||
|
return Result.success(receiptService.updateReceipt(dto));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Result<FundReceiptVO> getById(@PathVariable Long id) {
|
||||||
|
return Result.success(receiptService.getReceiptById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
public Result<Page<FundReceiptVO>> page(
|
||||||
|
@RequestParam(defaultValue = "1") int pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") int pageSize,
|
||||||
|
@RequestParam(required = false) String title,
|
||||||
|
@RequestParam(required = false) Integer receiptType,
|
||||||
|
@RequestParam(required = false) Integer receiptStatus) {
|
||||||
|
return Result.success(receiptService.pageReceipts(pageNum, pageSize, title, receiptType, receiptStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public Result<Boolean> delete(@PathVariable Long id) {
|
||||||
|
return Result.success(receiptService.deleteReceipt(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/confirm")
|
||||||
|
public Result<Boolean> confirm(@PathVariable Long id) {
|
||||||
|
return Result.success(receiptService.confirm(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/write-off")
|
||||||
|
public Result<Boolean> writeOff(@PathVariable Long id) {
|
||||||
|
return Result.success(receiptService.writeOff(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
package com.fundplatform.receipt.data.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fundplatform.common.core.BaseEntity;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收款管理实体
|
||||||
|
*/
|
||||||
|
@TableName("fund_receipt")
|
||||||
|
public class FundReceipt extends BaseEntity {
|
||||||
|
|
||||||
|
/** 收款单号 */
|
||||||
|
private String receiptNo;
|
||||||
|
|
||||||
|
/** 收款标题 */
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/** 收款金额 */
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
/** 币种 */
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
/** 收款类型(1-项目收款 2-服务费 3-利息收入 4-其他) */
|
||||||
|
private Integer receiptType;
|
||||||
|
|
||||||
|
/** 付款单位 */
|
||||||
|
private String payerName;
|
||||||
|
|
||||||
|
/** 付款银行 */
|
||||||
|
private String payerBank;
|
||||||
|
|
||||||
|
/** 付款账号 */
|
||||||
|
private String payerAccount;
|
||||||
|
|
||||||
|
/** 收款日期 */
|
||||||
|
private LocalDateTime receiptDate;
|
||||||
|
|
||||||
|
/** 用途说明 */
|
||||||
|
private String purpose;
|
||||||
|
|
||||||
|
/** 关联项目ID */
|
||||||
|
private Long projectId;
|
||||||
|
|
||||||
|
/** 关联客户ID */
|
||||||
|
private Long customerId;
|
||||||
|
|
||||||
|
/** 收款状态(0-待确认 1-已确认 2-已核销) */
|
||||||
|
private Integer receiptStatus;
|
||||||
|
|
||||||
|
/** 确认时间 */
|
||||||
|
private LocalDateTime confirmTime;
|
||||||
|
|
||||||
|
/** 确认人ID */
|
||||||
|
private Long confirmBy;
|
||||||
|
|
||||||
|
/** 核销时间 */
|
||||||
|
private LocalDateTime writeOffTime;
|
||||||
|
|
||||||
|
/** 核销人ID */
|
||||||
|
private Long writeOffBy;
|
||||||
|
|
||||||
|
/** 收款凭证 */
|
||||||
|
private String voucher;
|
||||||
|
|
||||||
|
/** 发票号 */
|
||||||
|
private String invoiceNo;
|
||||||
|
|
||||||
|
/** 附件URL */
|
||||||
|
private String attachments;
|
||||||
|
|
||||||
|
public String getReceiptNo() { return receiptNo; }
|
||||||
|
public void setReceiptNo(String receiptNo) { this.receiptNo = receiptNo; }
|
||||||
|
public String getTitle() { return title; }
|
||||||
|
public void setTitle(String title) { this.title = title; }
|
||||||
|
public BigDecimal getAmount() { return amount; }
|
||||||
|
public void setAmount(BigDecimal amount) { this.amount = amount; }
|
||||||
|
public String getCurrency() { return currency; }
|
||||||
|
public void setCurrency(String currency) { this.currency = currency; }
|
||||||
|
public Integer getReceiptType() { return receiptType; }
|
||||||
|
public void setReceiptType(Integer receiptType) { this.receiptType = receiptType; }
|
||||||
|
public String getPayerName() { return payerName; }
|
||||||
|
public void setPayerName(String payerName) { this.payerName = payerName; }
|
||||||
|
public String getPayerBank() { return payerBank; }
|
||||||
|
public void setPayerBank(String payerBank) { this.payerBank = payerBank; }
|
||||||
|
public String getPayerAccount() { return payerAccount; }
|
||||||
|
public void setPayerAccount(String payerAccount) { this.payerAccount = payerAccount; }
|
||||||
|
public LocalDateTime getReceiptDate() { return receiptDate; }
|
||||||
|
public void setReceiptDate(LocalDateTime receiptDate) { this.receiptDate = receiptDate; }
|
||||||
|
public String getPurpose() { return purpose; }
|
||||||
|
public void setPurpose(String purpose) { this.purpose = purpose; }
|
||||||
|
public Long getProjectId() { return projectId; }
|
||||||
|
public void setProjectId(Long projectId) { this.projectId = projectId; }
|
||||||
|
public Long getCustomerId() { return customerId; }
|
||||||
|
public void setCustomerId(Long customerId) { this.customerId = customerId; }
|
||||||
|
public Integer getReceiptStatus() { return receiptStatus; }
|
||||||
|
public void setReceiptStatus(Integer receiptStatus) { this.receiptStatus = receiptStatus; }
|
||||||
|
public LocalDateTime getConfirmTime() { return confirmTime; }
|
||||||
|
public void setConfirmTime(LocalDateTime confirmTime) { this.confirmTime = confirmTime; }
|
||||||
|
public Long getConfirmBy() { return confirmBy; }
|
||||||
|
public void setConfirmBy(Long confirmBy) { this.confirmBy = confirmBy; }
|
||||||
|
public LocalDateTime getWriteOffTime() { return writeOffTime; }
|
||||||
|
public void setWriteOffTime(LocalDateTime writeOffTime) { this.writeOffTime = writeOffTime; }
|
||||||
|
public Long getWriteOffBy() { return writeOffBy; }
|
||||||
|
public void setWriteOffBy(Long writeOffBy) { this.writeOffBy = writeOffBy; }
|
||||||
|
public String getVoucher() { return voucher; }
|
||||||
|
public void setVoucher(String voucher) { this.voucher = voucher; }
|
||||||
|
public String getInvoiceNo() { return invoiceNo; }
|
||||||
|
public void setInvoiceNo(String invoiceNo) { this.invoiceNo = invoiceNo; }
|
||||||
|
public String getAttachments() { return attachments; }
|
||||||
|
public void setAttachments(String attachments) { this.attachments = attachments; }
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.fundplatform.receipt.data.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.fundplatform.receipt.data.entity.FundReceipt;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface FundReceiptMapper extends BaseMapper<FundReceipt> {
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.fundplatform.receipt.data.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.fundplatform.receipt.data.entity.FundReceipt;
|
||||||
|
import com.fundplatform.receipt.data.mapper.FundReceiptMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FundReceiptDataService extends ServiceImpl<FundReceiptMapper, FundReceipt> implements IService<FundReceipt> {
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
package com.fundplatform.receipt.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class FundReceiptDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@NotBlank(message = "收款标题不能为空")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@NotNull(message = "收款金额不能为空")
|
||||||
|
@Positive(message = "收款金额必须大于0")
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
private String currency = "CNY";
|
||||||
|
|
||||||
|
@NotNull(message = "收款类型不能为空")
|
||||||
|
private Integer receiptType;
|
||||||
|
|
||||||
|
@NotBlank(message = "付款单位不能为空")
|
||||||
|
private String payerName;
|
||||||
|
|
||||||
|
private String payerBank;
|
||||||
|
private String payerAccount;
|
||||||
|
private LocalDateTime receiptDate;
|
||||||
|
private String purpose;
|
||||||
|
private Long projectId;
|
||||||
|
private Long customerId;
|
||||||
|
private String invoiceNo;
|
||||||
|
private String voucher;
|
||||||
|
private String attachments;
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
public Long getId() { return id; }
|
||||||
|
public void setId(Long id) { this.id = id; }
|
||||||
|
public String getTitle() { return title; }
|
||||||
|
public void setTitle(String title) { this.title = title; }
|
||||||
|
public BigDecimal getAmount() { return amount; }
|
||||||
|
public void setAmount(BigDecimal amount) { this.amount = amount; }
|
||||||
|
public String getCurrency() { return currency; }
|
||||||
|
public void setCurrency(String currency) { this.currency = currency; }
|
||||||
|
public Integer getReceiptType() { return receiptType; }
|
||||||
|
public void setReceiptType(Integer receiptType) { this.receiptType = receiptType; }
|
||||||
|
public String getPayerName() { return payerName; }
|
||||||
|
public void setPayerName(String payerName) { this.payerName = payerName; }
|
||||||
|
public String getPayerBank() { return payerBank; }
|
||||||
|
public void setPayerBank(String payerBank) { this.payerBank = payerBank; }
|
||||||
|
public String getPayerAccount() { return payerAccount; }
|
||||||
|
public void setPayerAccount(String payerAccount) { this.payerAccount = payerAccount; }
|
||||||
|
public LocalDateTime getReceiptDate() { return receiptDate; }
|
||||||
|
public void setReceiptDate(LocalDateTime receiptDate) { this.receiptDate = receiptDate; }
|
||||||
|
public String getPurpose() { return purpose; }
|
||||||
|
public void setPurpose(String purpose) { this.purpose = purpose; }
|
||||||
|
public Long getProjectId() { return projectId; }
|
||||||
|
public void setProjectId(Long projectId) { this.projectId = projectId; }
|
||||||
|
public Long getCustomerId() { return customerId; }
|
||||||
|
public void setCustomerId(Long customerId) { this.customerId = customerId; }
|
||||||
|
public String getInvoiceNo() { return invoiceNo; }
|
||||||
|
public void setInvoiceNo(String invoiceNo) { this.invoiceNo = invoiceNo; }
|
||||||
|
public String getVoucher() { return voucher; }
|
||||||
|
public void setVoucher(String voucher) { this.voucher = voucher; }
|
||||||
|
public String getAttachments() { return attachments; }
|
||||||
|
public void setAttachments(String attachments) { this.attachments = attachments; }
|
||||||
|
public String getRemark() { return remark; }
|
||||||
|
public void setRemark(String remark) { this.remark = remark; }
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.fundplatform.receipt.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.receipt.dto.FundReceiptDTO;
|
||||||
|
import com.fundplatform.receipt.vo.FundReceiptVO;
|
||||||
|
|
||||||
|
public interface FundReceiptService {
|
||||||
|
|
||||||
|
Long createReceipt(FundReceiptDTO dto);
|
||||||
|
|
||||||
|
boolean updateReceipt(FundReceiptDTO dto);
|
||||||
|
|
||||||
|
FundReceiptVO getReceiptById(Long id);
|
||||||
|
|
||||||
|
Page<FundReceiptVO> pageReceipts(int pageNum, int pageSize, String title, Integer receiptType, Integer receiptStatus);
|
||||||
|
|
||||||
|
boolean deleteReceipt(Long id);
|
||||||
|
|
||||||
|
boolean confirm(Long id);
|
||||||
|
|
||||||
|
boolean writeOff(Long id);
|
||||||
|
}
|
||||||
@ -0,0 +1,178 @@
|
|||||||
|
package com.fundplatform.receipt.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.receipt.data.entity.FundReceipt;
|
||||||
|
import com.fundplatform.receipt.data.service.FundReceiptDataService;
|
||||||
|
import com.fundplatform.receipt.dto.FundReceiptDTO;
|
||||||
|
import com.fundplatform.receipt.service.FundReceiptService;
|
||||||
|
import com.fundplatform.receipt.vo.FundReceiptVO;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FundReceiptServiceImpl implements FundReceiptService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FundReceiptServiceImpl.class);
|
||||||
|
private static final AtomicInteger counter = new AtomicInteger(1);
|
||||||
|
|
||||||
|
private final FundReceiptDataService receiptDataService;
|
||||||
|
|
||||||
|
public FundReceiptServiceImpl(FundReceiptDataService receiptDataService) {
|
||||||
|
this.receiptDataService = receiptDataService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createReceipt(FundReceiptDTO dto) {
|
||||||
|
FundReceipt receipt = new FundReceipt();
|
||||||
|
receipt.setReceiptNo(generateReceiptNo());
|
||||||
|
receipt.setTitle(dto.getTitle());
|
||||||
|
receipt.setAmount(dto.getAmount());
|
||||||
|
receipt.setCurrency(dto.getCurrency() != null ? dto.getCurrency() : "CNY");
|
||||||
|
receipt.setReceiptType(dto.getReceiptType());
|
||||||
|
receipt.setPayerName(dto.getPayerName());
|
||||||
|
receipt.setPayerBank(dto.getPayerBank());
|
||||||
|
receipt.setPayerAccount(dto.getPayerAccount());
|
||||||
|
receipt.setReceiptDate(dto.getReceiptDate() != null ? dto.getReceiptDate() : LocalDateTime.now());
|
||||||
|
receipt.setPurpose(dto.getPurpose());
|
||||||
|
receipt.setProjectId(dto.getProjectId());
|
||||||
|
receipt.setCustomerId(dto.getCustomerId());
|
||||||
|
receipt.setReceiptStatus(0);
|
||||||
|
receipt.setInvoiceNo(dto.getInvoiceNo());
|
||||||
|
receipt.setVoucher(dto.getVoucher());
|
||||||
|
receipt.setAttachments(dto.getAttachments());
|
||||||
|
receipt.setDeleted(0);
|
||||||
|
receipt.setCreatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
receiptDataService.save(receipt);
|
||||||
|
log.info("创建收款记录成功: id={}, receiptNo={}", receipt.getId(), receipt.getReceiptNo());
|
||||||
|
return receipt.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateReceipt(FundReceiptDTO dto) {
|
||||||
|
if (dto.getId() == null) throw new RuntimeException("收款ID不能为空");
|
||||||
|
FundReceipt existing = receiptDataService.getById(dto.getId());
|
||||||
|
if (existing == null || existing.getDeleted() == 1) throw new RuntimeException("收款记录不存在");
|
||||||
|
if (existing.getReceiptStatus() == 2) throw new RuntimeException("已核销记录不允许修改");
|
||||||
|
|
||||||
|
FundReceipt receipt = new FundReceipt();
|
||||||
|
receipt.setId(dto.getId());
|
||||||
|
receipt.setTitle(dto.getTitle());
|
||||||
|
receipt.setAmount(dto.getAmount());
|
||||||
|
receipt.setPurpose(dto.getPurpose());
|
||||||
|
receipt.setVoucher(dto.getVoucher());
|
||||||
|
receipt.setAttachments(dto.getAttachments());
|
||||||
|
receipt.setUpdatedTime(LocalDateTime.now());
|
||||||
|
return receiptDataService.updateById(receipt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FundReceiptVO getReceiptById(Long id) {
|
||||||
|
FundReceipt receipt = receiptDataService.getById(id);
|
||||||
|
if (receipt == null || receipt.getDeleted() == 1) throw new RuntimeException("收款记录不存在");
|
||||||
|
return convertToVO(receipt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<FundReceiptVO> pageReceipts(int pageNum, int pageSize, String title, Integer receiptType, Integer receiptStatus) {
|
||||||
|
Page<FundReceipt> page = new Page<>(pageNum, pageSize);
|
||||||
|
LambdaQueryWrapper<FundReceipt> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(FundReceipt::getDeleted, 0);
|
||||||
|
if (StringUtils.hasText(title)) wrapper.like(FundReceipt::getTitle, title);
|
||||||
|
if (receiptType != null) wrapper.eq(FundReceipt::getReceiptType, receiptType);
|
||||||
|
if (receiptStatus != null) wrapper.eq(FundReceipt::getReceiptStatus, receiptStatus);
|
||||||
|
wrapper.orderByDesc(FundReceipt::getCreatedTime);
|
||||||
|
|
||||||
|
Page<FundReceipt> receiptPage = receiptDataService.page(page, wrapper);
|
||||||
|
Page<FundReceiptVO> voPage = new Page<>(receiptPage.getCurrent(), receiptPage.getSize(), receiptPage.getTotal());
|
||||||
|
voPage.setRecords(receiptPage.getRecords().stream().map(this::convertToVO).toList());
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean deleteReceipt(Long id) {
|
||||||
|
LambdaUpdateWrapper<FundReceipt> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundReceipt::getId, id).set(FundReceipt::getDeleted, 1).set(FundReceipt::getUpdatedTime, LocalDateTime.now());
|
||||||
|
return receiptDataService.update(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean confirm(Long id) {
|
||||||
|
LambdaUpdateWrapper<FundReceipt> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundReceipt::getId, id).set(FundReceipt::getReceiptStatus, 1)
|
||||||
|
.set(FundReceipt::getConfirmTime, LocalDateTime.now())
|
||||||
|
.set(FundReceipt::getUpdatedTime, LocalDateTime.now());
|
||||||
|
return receiptDataService.update(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean writeOff(Long id) {
|
||||||
|
LambdaUpdateWrapper<FundReceipt> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundReceipt::getId, id).set(FundReceipt::getReceiptStatus, 2)
|
||||||
|
.set(FundReceipt::getWriteOffTime, LocalDateTime.now())
|
||||||
|
.set(FundReceipt::getUpdatedTime, LocalDateTime.now());
|
||||||
|
return receiptDataService.update(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateReceiptNo() {
|
||||||
|
String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||||
|
int seq = counter.getAndIncrement();
|
||||||
|
return String.format("REC%s%04d", dateStr, seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FundReceiptVO convertToVO(FundReceipt r) {
|
||||||
|
FundReceiptVO vo = new FundReceiptVO();
|
||||||
|
vo.setId(r.getId());
|
||||||
|
vo.setReceiptNo(r.getReceiptNo());
|
||||||
|
vo.setTitle(r.getTitle());
|
||||||
|
vo.setAmount(r.getAmount());
|
||||||
|
vo.setCurrency(r.getCurrency());
|
||||||
|
vo.setReceiptType(r.getReceiptType());
|
||||||
|
vo.setReceiptTypeName(getReceiptTypeName(r.getReceiptType()));
|
||||||
|
vo.setPayerName(r.getPayerName());
|
||||||
|
vo.setPayerBank(r.getPayerBank());
|
||||||
|
vo.setPayerAccount(r.getPayerAccount());
|
||||||
|
vo.setReceiptDate(r.getReceiptDate());
|
||||||
|
vo.setPurpose(r.getPurpose());
|
||||||
|
vo.setProjectId(r.getProjectId());
|
||||||
|
vo.setCustomerId(r.getCustomerId());
|
||||||
|
vo.setReceiptStatus(r.getReceiptStatus());
|
||||||
|
vo.setReceiptStatusName(getReceiptStatusName(r.getReceiptStatus()));
|
||||||
|
vo.setConfirmTime(r.getConfirmTime());
|
||||||
|
vo.setConfirmBy(r.getConfirmBy());
|
||||||
|
vo.setWriteOffTime(r.getWriteOffTime());
|
||||||
|
vo.setWriteOffBy(r.getWriteOffBy());
|
||||||
|
vo.setVoucher(r.getVoucher());
|
||||||
|
vo.setInvoiceNo(r.getInvoiceNo());
|
||||||
|
vo.setAttachments(r.getAttachments());
|
||||||
|
vo.setTenantId(r.getTenantId());
|
||||||
|
vo.setCreatedBy(r.getCreatedBy());
|
||||||
|
vo.setCreatedTime(r.getCreatedTime());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getReceiptTypeName(Integer type) {
|
||||||
|
if (type == null) return "";
|
||||||
|
return switch (type) { case 1 -> "项目收款"; case 2 -> "服务费"; case 3 -> "利息收入"; case 4 -> "其他"; default -> ""; };
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getReceiptStatusName(Integer status) {
|
||||||
|
if (status == null) return "";
|
||||||
|
return switch (status) { case 0 -> "待确认"; case 1 -> "已确认"; case 2 -> "已核销"; default -> ""; };
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
package com.fundplatform.receipt.vo;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class FundReceiptVO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String receiptNo;
|
||||||
|
private String title;
|
||||||
|
private BigDecimal amount;
|
||||||
|
private String currency;
|
||||||
|
private Integer receiptType;
|
||||||
|
private String receiptTypeName;
|
||||||
|
private String payerName;
|
||||||
|
private String payerBank;
|
||||||
|
private String payerAccount;
|
||||||
|
private LocalDateTime receiptDate;
|
||||||
|
private String purpose;
|
||||||
|
private Long projectId;
|
||||||
|
private Long customerId;
|
||||||
|
private Integer receiptStatus;
|
||||||
|
private String receiptStatusName;
|
||||||
|
private LocalDateTime confirmTime;
|
||||||
|
private Long confirmBy;
|
||||||
|
private LocalDateTime writeOffTime;
|
||||||
|
private Long writeOffBy;
|
||||||
|
private String voucher;
|
||||||
|
private String invoiceNo;
|
||||||
|
private String attachments;
|
||||||
|
private Long tenantId;
|
||||||
|
private Long createdBy;
|
||||||
|
private LocalDateTime createdTime;
|
||||||
|
|
||||||
|
public Long getId() { return id; }
|
||||||
|
public void setId(Long id) { this.id = id; }
|
||||||
|
public String getReceiptNo() { return receiptNo; }
|
||||||
|
public void setReceiptNo(String receiptNo) { this.receiptNo = receiptNo; }
|
||||||
|
public String getTitle() { return title; }
|
||||||
|
public void setTitle(String title) { this.title = title; }
|
||||||
|
public BigDecimal getAmount() { return amount; }
|
||||||
|
public void setAmount(BigDecimal amount) { this.amount = amount; }
|
||||||
|
public String getCurrency() { return currency; }
|
||||||
|
public void setCurrency(String currency) { this.currency = currency; }
|
||||||
|
public Integer getReceiptType() { return receiptType; }
|
||||||
|
public void setReceiptType(Integer receiptType) { this.receiptType = receiptType; }
|
||||||
|
public String getReceiptTypeName() { return receiptTypeName; }
|
||||||
|
public void setReceiptTypeName(String receiptTypeName) { this.receiptTypeName = receiptTypeName; }
|
||||||
|
public String getPayerName() { return payerName; }
|
||||||
|
public void setPayerName(String payerName) { this.payerName = payerName; }
|
||||||
|
public String getPayerBank() { return payerBank; }
|
||||||
|
public void setPayerBank(String payerBank) { this.payerBank = payerBank; }
|
||||||
|
public String getPayerAccount() { return payerAccount; }
|
||||||
|
public void setPayerAccount(String payerAccount) { this.payerAccount = payerAccount; }
|
||||||
|
public LocalDateTime getReceiptDate() { return receiptDate; }
|
||||||
|
public void setReceiptDate(LocalDateTime receiptDate) { this.receiptDate = receiptDate; }
|
||||||
|
public String getPurpose() { return purpose; }
|
||||||
|
public void setPurpose(String purpose) { this.purpose = purpose; }
|
||||||
|
public Long getProjectId() { return projectId; }
|
||||||
|
public void setProjectId(Long projectId) { this.projectId = projectId; }
|
||||||
|
public Long getCustomerId() { return customerId; }
|
||||||
|
public void setCustomerId(Long customerId) { this.customerId = customerId; }
|
||||||
|
public Integer getReceiptStatus() { return receiptStatus; }
|
||||||
|
public void setReceiptStatus(Integer receiptStatus) { this.receiptStatus = receiptStatus; }
|
||||||
|
public String getReceiptStatusName() { return receiptStatusName; }
|
||||||
|
public void setReceiptStatusName(String receiptStatusName) { this.receiptStatusName = receiptStatusName; }
|
||||||
|
public LocalDateTime getConfirmTime() { return confirmTime; }
|
||||||
|
public void setConfirmTime(LocalDateTime confirmTime) { this.confirmTime = confirmTime; }
|
||||||
|
public Long getConfirmBy() { return confirmBy; }
|
||||||
|
public void setConfirmBy(Long confirmBy) { this.confirmBy = confirmBy; }
|
||||||
|
public LocalDateTime getWriteOffTime() { return writeOffTime; }
|
||||||
|
public void setWriteOffTime(LocalDateTime writeOffTime) { this.writeOffTime = writeOffTime; }
|
||||||
|
public Long getWriteOffBy() { return writeOffBy; }
|
||||||
|
public void setWriteOffBy(Long writeOffBy) { this.writeOffBy = writeOffBy; }
|
||||||
|
public String getVoucher() { return voucher; }
|
||||||
|
public void setVoucher(String voucher) { this.voucher = voucher; }
|
||||||
|
public String getInvoiceNo() { return invoiceNo; }
|
||||||
|
public void setInvoiceNo(String invoiceNo) { this.invoiceNo = invoiceNo; }
|
||||||
|
public String getAttachments() { return attachments; }
|
||||||
|
public void setAttachments(String attachments) { this.attachments = attachments; }
|
||||||
|
public Long getTenantId() { return tenantId; }
|
||||||
|
public void setTenantId(Long tenantId) { this.tenantId = tenantId; }
|
||||||
|
public Long getCreatedBy() { return createdBy; }
|
||||||
|
public void setCreatedBy(Long createdBy) { this.createdBy = createdBy; }
|
||||||
|
public LocalDateTime getCreatedTime() { return createdTime; }
|
||||||
|
public void setCreatedTime(LocalDateTime createdTime) { this.createdTime = createdTime; }
|
||||||
|
}
|
||||||
@ -4,3 +4,10 @@ server:
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: fund-receipt
|
name: fund-receipt
|
||||||
|
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
server-addr: localhost:8848
|
||||||
|
namespace: fund-platform
|
||||||
|
group: DEFAULT_GROUP
|
||||||
|
|||||||
@ -2,8 +2,10 @@ package com.fundplatform.report;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableDiscoveryClient
|
||||||
public class ReportApplication {
|
public class ReportApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@ -4,3 +4,10 @@ server:
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: fund-report
|
name: fund-report
|
||||||
|
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
server-addr: localhost:8848
|
||||||
|
namespace: fund-platform
|
||||||
|
group: DEFAULT_GROUP
|
||||||
|
|||||||
@ -2,8 +2,10 @@ package com.fundplatform.req;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableDiscoveryClient
|
||||||
public class ReqApplication {
|
public class ReqApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@ -0,0 +1,109 @@
|
|||||||
|
package com.fundplatform.req.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.common.core.Result;
|
||||||
|
import com.fundplatform.req.dto.FundRequestDTO;
|
||||||
|
import com.fundplatform.req.service.FundRequestService;
|
||||||
|
import com.fundplatform.req.vo.FundRequestVO;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用款申请Controller
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/req/fund-request")
|
||||||
|
public class FundRequestController {
|
||||||
|
|
||||||
|
private final FundRequestService fundRequestService;
|
||||||
|
|
||||||
|
public FundRequestController(FundRequestService fundRequestService) {
|
||||||
|
this.fundRequestService = fundRequestService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建用款申请
|
||||||
|
*/
|
||||||
|
@PostMapping
|
||||||
|
public Result<Long> create(@Valid @RequestBody FundRequestDTO dto) {
|
||||||
|
Long id = fundRequestService.createRequest(dto);
|
||||||
|
return Result.success(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用款申请
|
||||||
|
*/
|
||||||
|
@PutMapping
|
||||||
|
public Result<Boolean> update(@Valid @RequestBody FundRequestDTO dto) {
|
||||||
|
boolean result = fundRequestService.updateRequest(dto);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询用款申请
|
||||||
|
*/
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Result<FundRequestVO> getById(@PathVariable Long id) {
|
||||||
|
FundRequestVO vo = fundRequestService.getRequestById(id);
|
||||||
|
return Result.success(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询用款申请
|
||||||
|
*/
|
||||||
|
@GetMapping("/page")
|
||||||
|
public Result<Page<FundRequestVO>> page(
|
||||||
|
@RequestParam(defaultValue = "1") int pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") int pageSize,
|
||||||
|
@RequestParam(required = false) String title,
|
||||||
|
@RequestParam(required = false) Integer requestType,
|
||||||
|
@RequestParam(required = false) Integer approvalStatus) {
|
||||||
|
Page<FundRequestVO> page = fundRequestService.pageRequests(pageNum, pageSize, title, requestType, approvalStatus);
|
||||||
|
return Result.success(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用款申请
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public Result<Boolean> delete(@PathVariable Long id) {
|
||||||
|
boolean result = fundRequestService.deleteRequest(id);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交审批
|
||||||
|
*/
|
||||||
|
@PostMapping("/{id}/submit")
|
||||||
|
public Result<Boolean> submit(@PathVariable Long id) {
|
||||||
|
boolean result = fundRequestService.submitApproval(id);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批通过
|
||||||
|
*/
|
||||||
|
@PutMapping("/{id}/approve")
|
||||||
|
public Result<Boolean> approve(@PathVariable Long id, @RequestParam(required = false) String comment) {
|
||||||
|
boolean result = fundRequestService.approve(id, comment);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批拒绝
|
||||||
|
*/
|
||||||
|
@PutMapping("/{id}/reject")
|
||||||
|
public Result<Boolean> reject(@PathVariable Long id, @RequestParam(required = false) String comment) {
|
||||||
|
boolean result = fundRequestService.reject(id, comment);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤回申请
|
||||||
|
*/
|
||||||
|
@PutMapping("/{id}/withdraw")
|
||||||
|
public Result<Boolean> withdraw(@PathVariable Long id) {
|
||||||
|
boolean result = fundRequestService.withdraw(id);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,223 @@
|
|||||||
|
package com.fundplatform.req.data.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fundplatform.common.core.BaseEntity;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用款申请实体
|
||||||
|
*/
|
||||||
|
@TableName("fund_request")
|
||||||
|
public class FundRequest extends BaseEntity {
|
||||||
|
|
||||||
|
/** 申请单号 */
|
||||||
|
private String requestNo;
|
||||||
|
|
||||||
|
/** 申请标题 */
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/** 申请金额 */
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
/** 币种 */
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
/** 用款类型(1-日常报销 2-项目付款 3-预付款 4-其他) */
|
||||||
|
private Integer requestType;
|
||||||
|
|
||||||
|
/** 收款单位 */
|
||||||
|
private String payeeName;
|
||||||
|
|
||||||
|
/** 收款银行 */
|
||||||
|
private String payeeBank;
|
||||||
|
|
||||||
|
/** 收款账号 */
|
||||||
|
private String payeeAccount;
|
||||||
|
|
||||||
|
/** 用途说明 */
|
||||||
|
private String purpose;
|
||||||
|
|
||||||
|
/** 项目ID */
|
||||||
|
private Long projectId;
|
||||||
|
|
||||||
|
/** 客户ID */
|
||||||
|
private Long customerId;
|
||||||
|
|
||||||
|
/** 申请日期 */
|
||||||
|
private LocalDateTime requestDate;
|
||||||
|
|
||||||
|
/** 期望付款日期 */
|
||||||
|
private LocalDateTime expectedPayDate;
|
||||||
|
|
||||||
|
/** 审批状态(0-待审批 1-审批中 2-审批通过 3-审批拒绝 4-已撤回) */
|
||||||
|
private Integer approvalStatus;
|
||||||
|
|
||||||
|
/** 当前审批节点 */
|
||||||
|
private Integer currentNode;
|
||||||
|
|
||||||
|
/** 审批人ID */
|
||||||
|
private Long approverId;
|
||||||
|
|
||||||
|
/** 审批时间 */
|
||||||
|
private LocalDateTime approvalTime;
|
||||||
|
|
||||||
|
/** 审批意见 */
|
||||||
|
private String approvalComment;
|
||||||
|
|
||||||
|
/** 附件URL */
|
||||||
|
private String attachments;
|
||||||
|
|
||||||
|
public String getRequestNo() {
|
||||||
|
return requestNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestNo(String requestNo) {
|
||||||
|
this.requestNo = requestNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(BigDecimal amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrency() {
|
||||||
|
return currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrency(String currency) {
|
||||||
|
this.currency = currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRequestType() {
|
||||||
|
return requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestType(Integer requestType) {
|
||||||
|
this.requestType = requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeName() {
|
||||||
|
return payeeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeName(String payeeName) {
|
||||||
|
this.payeeName = payeeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeBank() {
|
||||||
|
return payeeBank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeBank(String payeeBank) {
|
||||||
|
this.payeeBank = payeeBank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeAccount() {
|
||||||
|
return payeeAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeAccount(String payeeAccount) {
|
||||||
|
this.payeeAccount = payeeAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPurpose() {
|
||||||
|
return purpose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPurpose(String purpose) {
|
||||||
|
this.purpose = purpose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getProjectId() {
|
||||||
|
return projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectId(Long projectId) {
|
||||||
|
this.projectId = projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCustomerId() {
|
||||||
|
return customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerId(Long customerId) {
|
||||||
|
this.customerId = customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getRequestDate() {
|
||||||
|
return requestDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestDate(LocalDateTime requestDate) {
|
||||||
|
this.requestDate = requestDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getExpectedPayDate() {
|
||||||
|
return expectedPayDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpectedPayDate(LocalDateTime expectedPayDate) {
|
||||||
|
this.expectedPayDate = expectedPayDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getApprovalStatus() {
|
||||||
|
return approvalStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovalStatus(Integer approvalStatus) {
|
||||||
|
this.approvalStatus = approvalStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCurrentNode() {
|
||||||
|
return currentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentNode(Integer currentNode) {
|
||||||
|
this.currentNode = currentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getApproverId() {
|
||||||
|
return approverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApproverId(Long approverId) {
|
||||||
|
this.approverId = approverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getApprovalTime() {
|
||||||
|
return approvalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovalTime(LocalDateTime approvalTime) {
|
||||||
|
this.approvalTime = approvalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApprovalComment() {
|
||||||
|
return approvalComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovalComment(String approvalComment) {
|
||||||
|
this.approvalComment = approvalComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAttachments() {
|
||||||
|
return attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttachments(String attachments) {
|
||||||
|
this.attachments = attachments;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.fundplatform.req.data.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.fundplatform.req.data.entity.FundRequest;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用款申请Mapper
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface FundRequestMapper extends BaseMapper<FundRequest> {
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.fundplatform.req.data.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.fundplatform.req.data.entity.FundRequest;
|
||||||
|
import com.fundplatform.req.data.mapper.FundRequestMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用款申请数据服务
|
||||||
|
* 职责:仅负责数据访问、数据封装和转换,不承载业务逻辑
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class FundRequestDataService extends ServiceImpl<FundRequestMapper, FundRequest> implements IService<FundRequest> {
|
||||||
|
}
|
||||||
@ -0,0 +1,165 @@
|
|||||||
|
package com.fundplatform.req.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用款申请DTO
|
||||||
|
*/
|
||||||
|
public class FundRequestDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@NotBlank(message = "申请标题不能为空")
|
||||||
|
@Size(max = 200, message = "申请标题不能超过200个字符")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@NotNull(message = "申请金额不能为空")
|
||||||
|
@Positive(message = "申请金额必须大于0")
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
private String currency = "CNY";
|
||||||
|
|
||||||
|
@NotNull(message = "用款类型不能为空")
|
||||||
|
private Integer requestType;
|
||||||
|
|
||||||
|
@NotBlank(message = "收款单位不能为空")
|
||||||
|
@Size(max = 100, message = "收款单位不能超过100个字符")
|
||||||
|
private String payeeName;
|
||||||
|
|
||||||
|
@Size(max = 100, message = "收款银行不能超过100个字符")
|
||||||
|
private String payeeBank;
|
||||||
|
|
||||||
|
@Size(max = 50, message = "收款账号不能超过50个字符")
|
||||||
|
private String payeeAccount;
|
||||||
|
|
||||||
|
@Size(max = 500, message = "用途说明不能超过500个字符")
|
||||||
|
private String purpose;
|
||||||
|
|
||||||
|
private Long projectId;
|
||||||
|
|
||||||
|
private Long customerId;
|
||||||
|
|
||||||
|
private LocalDateTime expectedPayDate;
|
||||||
|
|
||||||
|
private String attachments;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(BigDecimal amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrency() {
|
||||||
|
return currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrency(String currency) {
|
||||||
|
this.currency = currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRequestType() {
|
||||||
|
return requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestType(Integer requestType) {
|
||||||
|
this.requestType = requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeName() {
|
||||||
|
return payeeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeName(String payeeName) {
|
||||||
|
this.payeeName = payeeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeBank() {
|
||||||
|
return payeeBank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeBank(String payeeBank) {
|
||||||
|
this.payeeBank = payeeBank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeAccount() {
|
||||||
|
return payeeAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeAccount(String payeeAccount) {
|
||||||
|
this.payeeAccount = payeeAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPurpose() {
|
||||||
|
return purpose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPurpose(String purpose) {
|
||||||
|
this.purpose = purpose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getProjectId() {
|
||||||
|
return projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectId(Long projectId) {
|
||||||
|
this.projectId = projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCustomerId() {
|
||||||
|
return customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerId(Long customerId) {
|
||||||
|
this.customerId = customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getExpectedPayDate() {
|
||||||
|
return expectedPayDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpectedPayDate(LocalDateTime expectedPayDate) {
|
||||||
|
this.expectedPayDate = expectedPayDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAttachments() {
|
||||||
|
return attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttachments(String attachments) {
|
||||||
|
this.attachments = attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemark() {
|
||||||
|
return remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemark(String remark) {
|
||||||
|
this.remark = remark;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
package com.fundplatform.req.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.req.dto.FundRequestDTO;
|
||||||
|
import com.fundplatform.req.vo.FundRequestVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用款申请服务接口
|
||||||
|
*/
|
||||||
|
public interface FundRequestService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建用款申请
|
||||||
|
*
|
||||||
|
* @param dto 用款申请DTO
|
||||||
|
* @return 申请ID
|
||||||
|
*/
|
||||||
|
Long createRequest(FundRequestDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用款申请
|
||||||
|
*
|
||||||
|
* @param dto 用款申请DTO
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean updateRequest(FundRequestDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询用款申请
|
||||||
|
*
|
||||||
|
* @param id 申请ID
|
||||||
|
* @return 用款申请VO
|
||||||
|
*/
|
||||||
|
FundRequestVO getRequestById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询用款申请
|
||||||
|
*
|
||||||
|
* @param pageNum 页码
|
||||||
|
* @param pageSize 每页大小
|
||||||
|
* @param title 标题(模糊查询)
|
||||||
|
* @param requestType 用款类型
|
||||||
|
* @param approvalStatus 审批状态
|
||||||
|
* @return 分页数据
|
||||||
|
*/
|
||||||
|
Page<FundRequestVO> pageRequests(int pageNum, int pageSize, String title, Integer requestType, Integer approvalStatus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用款申请
|
||||||
|
*
|
||||||
|
* @param id 申请ID
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean deleteRequest(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交审批
|
||||||
|
*
|
||||||
|
* @param id 申请ID
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean submitApproval(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批通过
|
||||||
|
*
|
||||||
|
* @param id 申请ID
|
||||||
|
* @param comment 审批意见
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean approve(Long id, String comment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批拒绝
|
||||||
|
*
|
||||||
|
* @param id 申请ID
|
||||||
|
* @param comment 审批意见
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean reject(Long id, String comment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤回申请
|
||||||
|
*
|
||||||
|
* @param id 申请ID
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean withdraw(Long id);
|
||||||
|
}
|
||||||
@ -0,0 +1,301 @@
|
|||||||
|
package com.fundplatform.req.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.req.data.entity.FundRequest;
|
||||||
|
import com.fundplatform.req.data.service.FundRequestDataService;
|
||||||
|
import com.fundplatform.req.dto.FundRequestDTO;
|
||||||
|
import com.fundplatform.req.service.FundRequestService;
|
||||||
|
import com.fundplatform.req.vo.FundRequestVO;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用款申请服务实现
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class FundRequestServiceImpl implements FundRequestService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FundRequestServiceImpl.class);
|
||||||
|
private static final AtomicInteger counter = new AtomicInteger(1);
|
||||||
|
|
||||||
|
private final FundRequestDataService requestDataService;
|
||||||
|
|
||||||
|
public FundRequestServiceImpl(FundRequestDataService requestDataService) {
|
||||||
|
this.requestDataService = requestDataService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createRequest(FundRequestDTO dto) {
|
||||||
|
FundRequest request = new FundRequest();
|
||||||
|
request.setRequestNo(generateRequestNo());
|
||||||
|
request.setTitle(dto.getTitle());
|
||||||
|
request.setAmount(dto.getAmount());
|
||||||
|
request.setCurrency(dto.getCurrency() != null ? dto.getCurrency() : "CNY");
|
||||||
|
request.setRequestType(dto.getRequestType());
|
||||||
|
request.setPayeeName(dto.getPayeeName());
|
||||||
|
request.setPayeeBank(dto.getPayeeBank());
|
||||||
|
request.setPayeeAccount(dto.getPayeeAccount());
|
||||||
|
request.setPurpose(dto.getPurpose());
|
||||||
|
request.setProjectId(dto.getProjectId());
|
||||||
|
request.setCustomerId(dto.getCustomerId());
|
||||||
|
request.setRequestDate(LocalDateTime.now());
|
||||||
|
request.setExpectedPayDate(dto.getExpectedPayDate());
|
||||||
|
request.setApprovalStatus(0); // 待审批
|
||||||
|
request.setCurrentNode(1);
|
||||||
|
request.setAttachments(dto.getAttachments());
|
||||||
|
request.setDeleted(0);
|
||||||
|
request.setCreatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
requestDataService.save(request);
|
||||||
|
log.info("创建用款申请成功: id={}, requestNo={}", request.getId(), request.getRequestNo());
|
||||||
|
return request.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateRequest(FundRequestDTO dto) {
|
||||||
|
if (dto.getId() == null) {
|
||||||
|
throw new RuntimeException("申请ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
FundRequest existing = requestDataService.getById(dto.getId());
|
||||||
|
if (existing == null || existing.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("用款申请不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只有待审批状态才能修改
|
||||||
|
if (existing.getApprovalStatus() != 0) {
|
||||||
|
throw new RuntimeException("当前状态不允许修改");
|
||||||
|
}
|
||||||
|
|
||||||
|
FundRequest request = new FundRequest();
|
||||||
|
request.setId(dto.getId());
|
||||||
|
request.setTitle(dto.getTitle());
|
||||||
|
request.setAmount(dto.getAmount());
|
||||||
|
request.setCurrency(dto.getCurrency());
|
||||||
|
request.setRequestType(dto.getRequestType());
|
||||||
|
request.setPayeeName(dto.getPayeeName());
|
||||||
|
request.setPayeeBank(dto.getPayeeBank());
|
||||||
|
request.setPayeeAccount(dto.getPayeeAccount());
|
||||||
|
request.setPurpose(dto.getPurpose());
|
||||||
|
request.setProjectId(dto.getProjectId());
|
||||||
|
request.setCustomerId(dto.getCustomerId());
|
||||||
|
request.setExpectedPayDate(dto.getExpectedPayDate());
|
||||||
|
request.setAttachments(dto.getAttachments());
|
||||||
|
request.setUpdatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
boolean result = requestDataService.updateById(request);
|
||||||
|
log.info("更新用款申请: id={}, result={}", dto.getId(), result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FundRequestVO getRequestById(Long id) {
|
||||||
|
FundRequest request = requestDataService.getById(id);
|
||||||
|
if (request == null || request.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("用款申请不存在");
|
||||||
|
}
|
||||||
|
return convertToVO(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<FundRequestVO> pageRequests(int pageNum, int pageSize, String title, Integer requestType, Integer approvalStatus) {
|
||||||
|
Page<FundRequest> page = new Page<>(pageNum, pageSize);
|
||||||
|
LambdaQueryWrapper<FundRequest> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(FundRequest::getDeleted, 0);
|
||||||
|
|
||||||
|
if (StringUtils.hasText(title)) {
|
||||||
|
wrapper.like(FundRequest::getTitle, title);
|
||||||
|
}
|
||||||
|
if (requestType != null) {
|
||||||
|
wrapper.eq(FundRequest::getRequestType, requestType);
|
||||||
|
}
|
||||||
|
if (approvalStatus != null) {
|
||||||
|
wrapper.eq(FundRequest::getApprovalStatus, approvalStatus);
|
||||||
|
}
|
||||||
|
wrapper.orderByDesc(FundRequest::getCreatedTime);
|
||||||
|
|
||||||
|
Page<FundRequest> requestPage = requestDataService.page(page, wrapper);
|
||||||
|
|
||||||
|
Page<FundRequestVO> voPage = new Page<>(requestPage.getCurrent(), requestPage.getSize(), requestPage.getTotal());
|
||||||
|
voPage.setRecords(requestPage.getRecords().stream().map(this::convertToVO).toList());
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean deleteRequest(Long id) {
|
||||||
|
LambdaUpdateWrapper<FundRequest> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundRequest::getId, id);
|
||||||
|
wrapper.set(FundRequest::getDeleted, 1);
|
||||||
|
wrapper.set(FundRequest::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = requestDataService.update(wrapper);
|
||||||
|
log.info("删除用款申请: id={}", id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean submitApproval(Long id) {
|
||||||
|
FundRequest request = requestDataService.getById(id);
|
||||||
|
if (request == null || request.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("用款申请不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getApprovalStatus() != 0) {
|
||||||
|
throw new RuntimeException("当前状态不允许提交审批");
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaUpdateWrapper<FundRequest> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundRequest::getId, id);
|
||||||
|
wrapper.set(FundRequest::getApprovalStatus, 1); // 审批中
|
||||||
|
wrapper.set(FundRequest::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = requestDataService.update(wrapper);
|
||||||
|
log.info("提交用款申请审批: id={}", id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean approve(Long id, String comment) {
|
||||||
|
FundRequest request = requestDataService.getById(id);
|
||||||
|
if (request == null || request.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("用款申请不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getApprovalStatus() != 1) {
|
||||||
|
throw new RuntimeException("当前状态不允许审批");
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaUpdateWrapper<FundRequest> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundRequest::getId, id);
|
||||||
|
wrapper.set(FundRequest::getApprovalStatus, 2); // 审批通过
|
||||||
|
wrapper.set(FundRequest::getApprovalTime, LocalDateTime.now());
|
||||||
|
wrapper.set(FundRequest::getApprovalComment, comment);
|
||||||
|
wrapper.set(FundRequest::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = requestDataService.update(wrapper);
|
||||||
|
log.info("审批通过用款申请: id={}", id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean reject(Long id, String comment) {
|
||||||
|
FundRequest request = requestDataService.getById(id);
|
||||||
|
if (request == null || request.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("用款申请不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getApprovalStatus() != 1) {
|
||||||
|
throw new RuntimeException("当前状态不允许审批");
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaUpdateWrapper<FundRequest> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundRequest::getId, id);
|
||||||
|
wrapper.set(FundRequest::getApprovalStatus, 3); // 审批拒绝
|
||||||
|
wrapper.set(FundRequest::getApprovalTime, LocalDateTime.now());
|
||||||
|
wrapper.set(FundRequest::getApprovalComment, comment);
|
||||||
|
wrapper.set(FundRequest::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = requestDataService.update(wrapper);
|
||||||
|
log.info("审批拒绝用款申请: id={}", id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean withdraw(Long id) {
|
||||||
|
FundRequest request = requestDataService.getById(id);
|
||||||
|
if (request == null || request.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("用款申请不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getApprovalStatus() != 1) {
|
||||||
|
throw new RuntimeException("当前状态不允许撤回");
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaUpdateWrapper<FundRequest> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(FundRequest::getId, id);
|
||||||
|
wrapper.set(FundRequest::getApprovalStatus, 4); // 已撤回
|
||||||
|
wrapper.set(FundRequest::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = requestDataService.update(wrapper);
|
||||||
|
log.info("撤回用款申请: id={}", id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成申请单号
|
||||||
|
*/
|
||||||
|
private String generateRequestNo() {
|
||||||
|
String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||||
|
int seq = counter.getAndIncrement();
|
||||||
|
return String.format("REQ%s%04d", dateStr, seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为VO
|
||||||
|
*/
|
||||||
|
private FundRequestVO convertToVO(FundRequest request) {
|
||||||
|
FundRequestVO vo = new FundRequestVO();
|
||||||
|
vo.setId(request.getId());
|
||||||
|
vo.setRequestNo(request.getRequestNo());
|
||||||
|
vo.setTitle(request.getTitle());
|
||||||
|
vo.setAmount(request.getAmount());
|
||||||
|
vo.setCurrency(request.getCurrency());
|
||||||
|
vo.setRequestType(request.getRequestType());
|
||||||
|
vo.setRequestTypeName(getRequestTypeName(request.getRequestType()));
|
||||||
|
vo.setPayeeName(request.getPayeeName());
|
||||||
|
vo.setPayeeBank(request.getPayeeBank());
|
||||||
|
vo.setPayeeAccount(request.getPayeeAccount());
|
||||||
|
vo.setPurpose(request.getPurpose());
|
||||||
|
vo.setProjectId(request.getProjectId());
|
||||||
|
vo.setCustomerId(request.getCustomerId());
|
||||||
|
vo.setRequestDate(request.getRequestDate());
|
||||||
|
vo.setExpectedPayDate(request.getExpectedPayDate());
|
||||||
|
vo.setApprovalStatus(request.getApprovalStatus());
|
||||||
|
vo.setApprovalStatusName(getApprovalStatusName(request.getApprovalStatus()));
|
||||||
|
vo.setCurrentNode(request.getCurrentNode());
|
||||||
|
vo.setApproverId(request.getApproverId());
|
||||||
|
vo.setApprovalTime(request.getApprovalTime());
|
||||||
|
vo.setApprovalComment(request.getApprovalComment());
|
||||||
|
vo.setAttachments(request.getAttachments());
|
||||||
|
vo.setTenantId(request.getTenantId());
|
||||||
|
vo.setCreatedBy(request.getCreatedBy());
|
||||||
|
vo.setCreatedTime(request.getCreatedTime());
|
||||||
|
vo.setUpdatedTime(request.getUpdatedTime());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRequestTypeName(Integer type) {
|
||||||
|
if (type == null) return "";
|
||||||
|
switch (type) {
|
||||||
|
case 1: return "日常报销";
|
||||||
|
case 2: return "项目付款";
|
||||||
|
case 3: return "预付款";
|
||||||
|
case 4: return "其他";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getApprovalStatusName(Integer status) {
|
||||||
|
if (status == null) return "";
|
||||||
|
switch (status) {
|
||||||
|
case 0: return "待审批";
|
||||||
|
case 1: return "审批中";
|
||||||
|
case 2: return "审批通过";
|
||||||
|
case 3: return "审批拒绝";
|
||||||
|
case 4: return "已撤回";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,281 @@
|
|||||||
|
package com.fundplatform.req.vo;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用款申请VO
|
||||||
|
*/
|
||||||
|
public class FundRequestVO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String requestNo;
|
||||||
|
private String title;
|
||||||
|
private BigDecimal amount;
|
||||||
|
private String currency;
|
||||||
|
private Integer requestType;
|
||||||
|
private String requestTypeName;
|
||||||
|
private String payeeName;
|
||||||
|
private String payeeBank;
|
||||||
|
private String payeeAccount;
|
||||||
|
private String purpose;
|
||||||
|
private Long projectId;
|
||||||
|
private String projectName;
|
||||||
|
private Long customerId;
|
||||||
|
private String customerName;
|
||||||
|
private LocalDateTime requestDate;
|
||||||
|
private LocalDateTime expectedPayDate;
|
||||||
|
private Integer approvalStatus;
|
||||||
|
private String approvalStatusName;
|
||||||
|
private Integer currentNode;
|
||||||
|
private Long approverId;
|
||||||
|
private String approverName;
|
||||||
|
private LocalDateTime approvalTime;
|
||||||
|
private String approvalComment;
|
||||||
|
private String attachments;
|
||||||
|
private Long tenantId;
|
||||||
|
private Long createdBy;
|
||||||
|
private String createdByName;
|
||||||
|
private LocalDateTime createdTime;
|
||||||
|
private LocalDateTime updatedTime;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRequestNo() {
|
||||||
|
return requestNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestNo(String requestNo) {
|
||||||
|
this.requestNo = requestNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(BigDecimal amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrency() {
|
||||||
|
return currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrency(String currency) {
|
||||||
|
this.currency = currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRequestType() {
|
||||||
|
return requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestType(Integer requestType) {
|
||||||
|
this.requestType = requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRequestTypeName() {
|
||||||
|
return requestTypeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestTypeName(String requestTypeName) {
|
||||||
|
this.requestTypeName = requestTypeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeName() {
|
||||||
|
return payeeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeName(String payeeName) {
|
||||||
|
this.payeeName = payeeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeBank() {
|
||||||
|
return payeeBank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeBank(String payeeBank) {
|
||||||
|
this.payeeBank = payeeBank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayeeAccount() {
|
||||||
|
return payeeAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayeeAccount(String payeeAccount) {
|
||||||
|
this.payeeAccount = payeeAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPurpose() {
|
||||||
|
return purpose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPurpose(String purpose) {
|
||||||
|
this.purpose = purpose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getProjectId() {
|
||||||
|
return projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectId(Long projectId) {
|
||||||
|
this.projectId = projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProjectName() {
|
||||||
|
return projectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectName(String projectName) {
|
||||||
|
this.projectName = projectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCustomerId() {
|
||||||
|
return customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerId(Long customerId) {
|
||||||
|
this.customerId = customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomerName() {
|
||||||
|
return customerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerName(String customerName) {
|
||||||
|
this.customerName = customerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getRequestDate() {
|
||||||
|
return requestDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestDate(LocalDateTime requestDate) {
|
||||||
|
this.requestDate = requestDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getExpectedPayDate() {
|
||||||
|
return expectedPayDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpectedPayDate(LocalDateTime expectedPayDate) {
|
||||||
|
this.expectedPayDate = expectedPayDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getApprovalStatus() {
|
||||||
|
return approvalStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovalStatus(Integer approvalStatus) {
|
||||||
|
this.approvalStatus = approvalStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApprovalStatusName() {
|
||||||
|
return approvalStatusName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovalStatusName(String approvalStatusName) {
|
||||||
|
this.approvalStatusName = approvalStatusName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCurrentNode() {
|
||||||
|
return currentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentNode(Integer currentNode) {
|
||||||
|
this.currentNode = currentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getApproverId() {
|
||||||
|
return approverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApproverId(Long approverId) {
|
||||||
|
this.approverId = approverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApproverName() {
|
||||||
|
return approverName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApproverName(String approverName) {
|
||||||
|
this.approverName = approverName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getApprovalTime() {
|
||||||
|
return approvalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovalTime(LocalDateTime approvalTime) {
|
||||||
|
this.approvalTime = approvalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApprovalComment() {
|
||||||
|
return approvalComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApprovalComment(String approvalComment) {
|
||||||
|
this.approvalComment = approvalComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAttachments() {
|
||||||
|
return attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttachments(String attachments) {
|
||||||
|
this.attachments = attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(Long tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCreatedBy() {
|
||||||
|
return createdBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedBy(Long createdBy) {
|
||||||
|
this.createdBy = createdBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreatedByName() {
|
||||||
|
return createdByName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedByName(String createdByName) {
|
||||||
|
this.createdByName = createdByName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedTime() {
|
||||||
|
return createdTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedTime(LocalDateTime createdTime) {
|
||||||
|
this.createdTime = createdTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedTime() {
|
||||||
|
return updatedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedTime(LocalDateTime updatedTime) {
|
||||||
|
this.updatedTime = updatedTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,3 +4,10 @@ server:
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: fund-req
|
name: fund-req
|
||||||
|
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
server-addr: localhost:8848
|
||||||
|
namespace: fund-platform
|
||||||
|
group: DEFAULT_GROUP
|
||||||
|
|||||||
@ -3,11 +3,13 @@ package com.fundplatform.sys;
|
|||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统服务启动类
|
* 系统服务启动类
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableDiscoveryClient
|
||||||
@MapperScan("com.fundplatform.sys.data.mapper")
|
@MapperScan("com.fundplatform.sys.data.mapper")
|
||||||
public class SysApplication {
|
public class SysApplication {
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,66 @@
|
|||||||
|
package com.fundplatform.sys.controller;
|
||||||
|
|
||||||
|
import com.fundplatform.common.core.Result;
|
||||||
|
import com.fundplatform.sys.dto.DeptDTO;
|
||||||
|
import com.fundplatform.sys.service.DeptService;
|
||||||
|
import com.fundplatform.sys.vo.DeptVO;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门管理Controller
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/sys/dept")
|
||||||
|
public class DeptController {
|
||||||
|
|
||||||
|
private final DeptService deptService;
|
||||||
|
|
||||||
|
public DeptController(DeptService deptService) {
|
||||||
|
this.deptService = deptService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public Result<Long> create(@Valid @RequestBody DeptDTO dto) {
|
||||||
|
Long deptId = deptService.createDept(dto);
|
||||||
|
return Result.success(deptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping
|
||||||
|
public Result<Boolean> update(@Valid @RequestBody DeptDTO dto) {
|
||||||
|
boolean result = deptService.updateDept(dto);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Result<DeptVO> getById(@PathVariable Long id) {
|
||||||
|
DeptVO vo = deptService.getDeptById(id);
|
||||||
|
return Result.success(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/tree")
|
||||||
|
public Result<List<DeptVO>> getTree() {
|
||||||
|
List<DeptVO> tree = deptService.getDeptTree();
|
||||||
|
return Result.success(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
public Result<List<DeptVO>> listAll() {
|
||||||
|
List<DeptVO> list = deptService.listAllDepts();
|
||||||
|
return Result.success(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public Result<Boolean> delete(@PathVariable Long id) {
|
||||||
|
boolean result = deptService.deleteDept(id);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/status")
|
||||||
|
public Result<Boolean> updateStatus(@PathVariable Long id, @RequestParam Integer status) {
|
||||||
|
boolean result = deptService.updateStatus(id, status);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.fundplatform.sys.controller;
|
||||||
|
|
||||||
|
import com.fundplatform.common.core.Result;
|
||||||
|
import com.fundplatform.sys.dto.MenuDTO;
|
||||||
|
import com.fundplatform.sys.service.MenuService;
|
||||||
|
import com.fundplatform.sys.vo.MenuVO;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单管理Controller
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/sys/menu")
|
||||||
|
public class MenuController {
|
||||||
|
|
||||||
|
private final MenuService menuService;
|
||||||
|
|
||||||
|
public MenuController(MenuService menuService) {
|
||||||
|
this.menuService = menuService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public Result<Long> create(@Valid @RequestBody MenuDTO dto) {
|
||||||
|
Long menuId = menuService.createMenu(dto);
|
||||||
|
return Result.success(menuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping
|
||||||
|
public Result<Boolean> update(@Valid @RequestBody MenuDTO dto) {
|
||||||
|
boolean result = menuService.updateMenu(dto);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Result<MenuVO> getById(@PathVariable Long id) {
|
||||||
|
MenuVO vo = menuService.getMenuById(id);
|
||||||
|
return Result.success(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/tree")
|
||||||
|
public Result<List<MenuVO>> getTree() {
|
||||||
|
List<MenuVO> tree = menuService.getMenuTree();
|
||||||
|
return Result.success(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/user/{userId}")
|
||||||
|
public Result<List<MenuVO>> getUserTree(@PathVariable Long userId) {
|
||||||
|
List<MenuVO> tree = menuService.getUserMenuTree(userId);
|
||||||
|
return Result.success(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public Result<Boolean> delete(@PathVariable Long id) {
|
||||||
|
boolean result = menuService.deleteMenu(id);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
package com.fundplatform.sys.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.common.core.Result;
|
||||||
|
import com.fundplatform.sys.dto.RoleDTO;
|
||||||
|
import com.fundplatform.sys.service.RoleService;
|
||||||
|
import com.fundplatform.sys.vo.RoleVO;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色管理Controller
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/sys/role")
|
||||||
|
public class RoleController {
|
||||||
|
|
||||||
|
private final RoleService roleService;
|
||||||
|
|
||||||
|
public RoleController(RoleService roleService) {
|
||||||
|
this.roleService = roleService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public Result<Long> create(@Valid @RequestBody RoleDTO dto) {
|
||||||
|
Long roleId = roleService.createRole(dto);
|
||||||
|
return Result.success(roleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping
|
||||||
|
public Result<Boolean> update(@Valid @RequestBody RoleDTO dto) {
|
||||||
|
boolean result = roleService.updateRole(dto);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Result<RoleVO> getById(@PathVariable Long id) {
|
||||||
|
RoleVO vo = roleService.getRoleById(id);
|
||||||
|
return Result.success(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
public Result<Page<RoleVO>> page(
|
||||||
|
@RequestParam(defaultValue = "1") int pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") int pageSize,
|
||||||
|
@RequestParam(required = false) String roleName,
|
||||||
|
@RequestParam(required = false) Integer status) {
|
||||||
|
Page<RoleVO> page = roleService.pageRoles(pageNum, pageSize, roleName, status);
|
||||||
|
return Result.success(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
public Result<List<RoleVO>> listAll() {
|
||||||
|
List<RoleVO> list = roleService.listAllRoles();
|
||||||
|
return Result.success(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public Result<Boolean> delete(@PathVariable Long id) {
|
||||||
|
boolean result = roleService.deleteRole(id);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/status")
|
||||||
|
public Result<Boolean> updateStatus(@PathVariable Long id, @RequestParam Integer status) {
|
||||||
|
boolean result = roleService.updateStatus(id, status);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{id}/menus")
|
||||||
|
public Result<Boolean> assignMenus(@PathVariable Long id, @RequestBody List<Long> menuIds) {
|
||||||
|
boolean result = roleService.assignMenus(id, menuIds);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,100 @@
|
|||||||
|
package com.fundplatform.sys.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.common.core.Result;
|
||||||
|
import com.fundplatform.sys.dto.UserDTO;
|
||||||
|
import com.fundplatform.sys.service.UserService;
|
||||||
|
import com.fundplatform.sys.vo.UserVO;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户管理Controller
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/sys/user")
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
public UserController(UserService userService) {
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建用户
|
||||||
|
*/
|
||||||
|
@PostMapping
|
||||||
|
public Result<Long> create(@Valid @RequestBody UserDTO dto) {
|
||||||
|
Long userId = userService.createUser(dto);
|
||||||
|
return Result.success(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户
|
||||||
|
*/
|
||||||
|
@PutMapping
|
||||||
|
public Result<Boolean> update(@Valid @RequestBody UserDTO dto) {
|
||||||
|
boolean result = userService.updateUser(dto);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询用户
|
||||||
|
*/
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Result<UserVO> getById(@PathVariable Long id) {
|
||||||
|
UserVO vo = userService.getUserById(id);
|
||||||
|
return Result.success(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询用户
|
||||||
|
*/
|
||||||
|
@GetMapping("/page")
|
||||||
|
public Result<Page<UserVO>> page(
|
||||||
|
@RequestParam(defaultValue = "1") int pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") int pageSize,
|
||||||
|
@RequestParam(required = false) String username,
|
||||||
|
@RequestParam(required = false) Integer status,
|
||||||
|
@RequestParam(required = false) Long deptId) {
|
||||||
|
Page<UserVO> page = userService.pageUsers(pageNum, pageSize, username, status, deptId);
|
||||||
|
return Result.success(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用户
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public Result<Boolean> delete(@PathVariable Long id) {
|
||||||
|
boolean result = userService.deleteUser(id);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除用户
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/batch")
|
||||||
|
public Result<Boolean> batchDelete(@RequestBody Long[] ids) {
|
||||||
|
boolean result = userService.batchDeleteUsers(ids);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置密码
|
||||||
|
*/
|
||||||
|
@PutMapping("/{id}/reset-password")
|
||||||
|
public Result<Boolean> resetPassword(@PathVariable Long id) {
|
||||||
|
boolean result = userService.resetPassword(id);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户状态
|
||||||
|
*/
|
||||||
|
@PutMapping("/{id}/status")
|
||||||
|
public Result<Boolean> updateStatus(@PathVariable Long id, @RequestParam Integer status) {
|
||||||
|
boolean result = userService.updateStatus(id, status);
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
115
fund-sys/src/main/java/com/fundplatform/sys/dto/DeptDTO.java
Normal file
115
fund-sys/src/main/java/com/fundplatform/sys/dto/DeptDTO.java
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package com.fundplatform.sys.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门DTO
|
||||||
|
*/
|
||||||
|
public class DeptDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private Long parentId;
|
||||||
|
|
||||||
|
@NotBlank(message = "部门编码不能为空")
|
||||||
|
@Size(max = 50, message = "部门编码不能超过50个字符")
|
||||||
|
private String deptCode;
|
||||||
|
|
||||||
|
@NotBlank(message = "部门名称不能为空")
|
||||||
|
@Size(max = 50, message = "部门名称不能超过50个字符")
|
||||||
|
private String deptName;
|
||||||
|
|
||||||
|
@Size(max = 50, message = "部门负责人不能超过50个字符")
|
||||||
|
private String deptLeader;
|
||||||
|
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private Integer sortOrder;
|
||||||
|
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getParentId() {
|
||||||
|
return parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentId(Long parentId) {
|
||||||
|
this.parentId = parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeptCode() {
|
||||||
|
return deptCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeptCode(String deptCode) {
|
||||||
|
this.deptCode = deptCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeptName() {
|
||||||
|
return deptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeptName(String deptName) {
|
||||||
|
this.deptName = deptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeptLeader() {
|
||||||
|
return deptLeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeptLeader(String deptLeader) {
|
||||||
|
this.deptLeader = deptLeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhone() {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhone(String phone) {
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSortOrder() {
|
||||||
|
return sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortOrder(Integer sortOrder) {
|
||||||
|
this.sortOrder = sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Integer status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemark() {
|
||||||
|
return remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemark(String remark) {
|
||||||
|
this.remark = remark;
|
||||||
|
}
|
||||||
|
}
|
||||||
136
fund-sys/src/main/java/com/fundplatform/sys/dto/MenuDTO.java
Normal file
136
fund-sys/src/main/java/com/fundplatform/sys/dto/MenuDTO.java
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package com.fundplatform.sys.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单DTO
|
||||||
|
*/
|
||||||
|
public class MenuDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private Long parentId;
|
||||||
|
|
||||||
|
@NotBlank(message = "菜单名称不能为空")
|
||||||
|
@Size(max = 50, message = "菜单名称不能超过50个字符")
|
||||||
|
private String menuName;
|
||||||
|
|
||||||
|
private Integer menuType;
|
||||||
|
|
||||||
|
@Size(max = 200, message = "菜单路径不能超过200个字符")
|
||||||
|
private String menuPath;
|
||||||
|
|
||||||
|
@Size(max = 100, message = "菜单图标不能超过100个字符")
|
||||||
|
private String menuIcon;
|
||||||
|
|
||||||
|
@Size(max = 200, message = "组件路径不能超过200个字符")
|
||||||
|
private String component;
|
||||||
|
|
||||||
|
@Size(max = 100, message = "权限标识不能超过100个字符")
|
||||||
|
private String permission;
|
||||||
|
|
||||||
|
private Integer sortOrder;
|
||||||
|
|
||||||
|
private Integer visible;
|
||||||
|
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getParentId() {
|
||||||
|
return parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentId(Long parentId) {
|
||||||
|
this.parentId = parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuName() {
|
||||||
|
return menuName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuName(String menuName) {
|
||||||
|
this.menuName = menuName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMenuType() {
|
||||||
|
return menuType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuType(Integer menuType) {
|
||||||
|
this.menuType = menuType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuPath() {
|
||||||
|
return menuPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuPath(String menuPath) {
|
||||||
|
this.menuPath = menuPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuIcon() {
|
||||||
|
return menuIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuIcon(String menuIcon) {
|
||||||
|
this.menuIcon = menuIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getComponent() {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComponent(String component) {
|
||||||
|
this.component = component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPermission() {
|
||||||
|
return permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermission(String permission) {
|
||||||
|
this.permission = permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSortOrder() {
|
||||||
|
return sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortOrder(Integer sortOrder) {
|
||||||
|
this.sortOrder = sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVisible() {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(Integer visible) {
|
||||||
|
this.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Integer status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemark() {
|
||||||
|
return remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemark(String remark) {
|
||||||
|
this.remark = remark;
|
||||||
|
}
|
||||||
|
}
|
||||||
84
fund-sys/src/main/java/com/fundplatform/sys/dto/RoleDTO.java
Normal file
84
fund-sys/src/main/java/com/fundplatform/sys/dto/RoleDTO.java
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package com.fundplatform.sys.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色DTO
|
||||||
|
*/
|
||||||
|
public class RoleDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@NotBlank(message = "角色编码不能为空")
|
||||||
|
@Size(max = 50, message = "角色编码不能超过50个字符")
|
||||||
|
private String roleCode;
|
||||||
|
|
||||||
|
@NotBlank(message = "角色名称不能为空")
|
||||||
|
@Size(max = 50, message = "角色名称不能超过50个字符")
|
||||||
|
private String roleName;
|
||||||
|
|
||||||
|
private Integer dataScope;
|
||||||
|
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
private Integer sortOrder;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoleCode() {
|
||||||
|
return roleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoleCode(String roleCode) {
|
||||||
|
this.roleCode = roleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoleName() {
|
||||||
|
return roleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoleName(String roleName) {
|
||||||
|
this.roleName = roleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDataScope() {
|
||||||
|
return dataScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataScope(Integer dataScope) {
|
||||||
|
this.dataScope = dataScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Integer status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSortOrder() {
|
||||||
|
return sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortOrder(Integer sortOrder) {
|
||||||
|
this.sortOrder = sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemark() {
|
||||||
|
return remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemark(String remark) {
|
||||||
|
this.remark = remark;
|
||||||
|
}
|
||||||
|
}
|
||||||
118
fund-sys/src/main/java/com/fundplatform/sys/dto/UserDTO.java
Normal file
118
fund-sys/src/main/java/com/fundplatform/sys/dto/UserDTO.java
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package com.fundplatform.sys.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户DTO(创建/更新)
|
||||||
|
*/
|
||||||
|
public class UserDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@NotBlank(message = "用户名不能为空")
|
||||||
|
@Size(min = 3, max = 50, message = "用户名长度必须在3-50个字符之间")
|
||||||
|
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母、数字和下划线")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Size(min = 6, max = 100, message = "密码长度必须在6-100个字符之间")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Size(max = 50, message = "真实姓名不能超过50个字符")
|
||||||
|
private String realName;
|
||||||
|
|
||||||
|
@Pattern(regexp = "^$|^1[3-9]\\d{9}$", message = "手机号格式不正确")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
@Pattern(regexp = "^$|^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", message = "邮箱格式不正确")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private Long deptId;
|
||||||
|
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRealName() {
|
||||||
|
return realName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRealName(String realName) {
|
||||||
|
this.realName = realName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhone() {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhone(String phone) {
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDeptId() {
|
||||||
|
return deptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeptId(Long deptId) {
|
||||||
|
this.deptId = deptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Integer status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAvatar() {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvatar(String avatar) {
|
||||||
|
this.avatar = avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemark() {
|
||||||
|
return remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemark(String remark) {
|
||||||
|
this.remark = remark;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package com.fundplatform.sys.service;
|
||||||
|
|
||||||
|
import com.fundplatform.sys.dto.DeptDTO;
|
||||||
|
import com.fundplatform.sys.vo.DeptVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门服务接口
|
||||||
|
*/
|
||||||
|
public interface DeptService {
|
||||||
|
|
||||||
|
Long createDept(DeptDTO dto);
|
||||||
|
|
||||||
|
boolean updateDept(DeptDTO dto);
|
||||||
|
|
||||||
|
DeptVO getDeptById(Long id);
|
||||||
|
|
||||||
|
List<DeptVO> getDeptTree();
|
||||||
|
|
||||||
|
List<DeptVO> listAllDepts();
|
||||||
|
|
||||||
|
boolean deleteDept(Long id);
|
||||||
|
|
||||||
|
boolean updateStatus(Long id, Integer status);
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package com.fundplatform.sys.service;
|
||||||
|
|
||||||
|
import com.fundplatform.sys.dto.MenuDTO;
|
||||||
|
import com.fundplatform.sys.vo.MenuVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单服务接口
|
||||||
|
*/
|
||||||
|
public interface MenuService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建菜单
|
||||||
|
*/
|
||||||
|
Long createMenu(MenuDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新菜单
|
||||||
|
*/
|
||||||
|
boolean updateMenu(MenuDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询菜单
|
||||||
|
*/
|
||||||
|
MenuVO getMenuById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询菜单树
|
||||||
|
*/
|
||||||
|
List<MenuVO> getMenuTree();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户菜单树
|
||||||
|
*/
|
||||||
|
List<MenuVO> getUserMenuTree(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除菜单
|
||||||
|
*/
|
||||||
|
boolean deleteMenu(Long id);
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
package com.fundplatform.sys.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.sys.dto.RoleDTO;
|
||||||
|
import com.fundplatform.sys.vo.RoleVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色服务接口
|
||||||
|
*/
|
||||||
|
public interface RoleService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建角色
|
||||||
|
*/
|
||||||
|
Long createRole(RoleDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新角色
|
||||||
|
*/
|
||||||
|
boolean updateRole(RoleDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询角色
|
||||||
|
*/
|
||||||
|
RoleVO getRoleById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询角色
|
||||||
|
*/
|
||||||
|
Page<RoleVO> pageRoles(int pageNum, int pageSize, String roleName, Integer status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有角色
|
||||||
|
*/
|
||||||
|
List<RoleVO> listAllRoles();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除角色
|
||||||
|
*/
|
||||||
|
boolean deleteRole(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新角色状态
|
||||||
|
*/
|
||||||
|
boolean updateStatus(Long id, Integer status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分配菜单权限
|
||||||
|
*/
|
||||||
|
boolean assignMenus(Long roleId, List<Long> menuIds);
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
package com.fundplatform.sys.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.sys.dto.UserDTO;
|
||||||
|
import com.fundplatform.sys.vo.UserVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户服务接口
|
||||||
|
*/
|
||||||
|
public interface UserService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建用户
|
||||||
|
*
|
||||||
|
* @param dto 用户DTO
|
||||||
|
* @return 用户ID
|
||||||
|
*/
|
||||||
|
Long createUser(UserDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户
|
||||||
|
*
|
||||||
|
* @param dto 用户DTO
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean updateUser(UserDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询用户
|
||||||
|
*
|
||||||
|
* @param id 用户ID
|
||||||
|
* @return 用户VO
|
||||||
|
*/
|
||||||
|
UserVO getUserById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询用户
|
||||||
|
*
|
||||||
|
* @param pageNum 页码
|
||||||
|
* @param pageSize 每页大小
|
||||||
|
* @param username 用户名(模糊查询)
|
||||||
|
* @param status 状态
|
||||||
|
* @param deptId 部门ID
|
||||||
|
* @return 分页数据
|
||||||
|
*/
|
||||||
|
Page<UserVO> pageUsers(int pageNum, int pageSize, String username, Integer status, Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用户
|
||||||
|
*
|
||||||
|
* @param id 用户ID
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean deleteUser(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除用户
|
||||||
|
*
|
||||||
|
* @param ids 用户ID列表
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean batchDeleteUsers(Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置密码
|
||||||
|
*
|
||||||
|
* @param id 用户ID
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean resetPassword(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户状态
|
||||||
|
*
|
||||||
|
* @param id 用户ID
|
||||||
|
* @param status 状态
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean updateStatus(Long id, Integer status);
|
||||||
|
}
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
package com.fundplatform.sys.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.fundplatform.sys.data.entity.SysDept;
|
||||||
|
import com.fundplatform.sys.data.service.SysDeptDataService;
|
||||||
|
import com.fundplatform.sys.dto.DeptDTO;
|
||||||
|
import com.fundplatform.sys.service.DeptService;
|
||||||
|
import com.fundplatform.sys.vo.DeptVO;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门服务实现
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class DeptServiceImpl implements DeptService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(DeptServiceImpl.class);
|
||||||
|
|
||||||
|
private final SysDeptDataService deptDataService;
|
||||||
|
|
||||||
|
public DeptServiceImpl(SysDeptDataService deptDataService) {
|
||||||
|
this.deptDataService = deptDataService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createDept(DeptDTO dto) {
|
||||||
|
LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysDept::getDeptCode, dto.getDeptCode());
|
||||||
|
wrapper.eq(SysDept::getDeleted, 0);
|
||||||
|
if (deptDataService.count(wrapper) > 0) {
|
||||||
|
throw new RuntimeException("部门编码已存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
SysDept dept = new SysDept();
|
||||||
|
dept.setParentId(dto.getParentId() != null ? dto.getParentId() : 0L);
|
||||||
|
dept.setDeptCode(dto.getDeptCode());
|
||||||
|
dept.setDeptName(dto.getDeptName());
|
||||||
|
dept.setDeptLeader(dto.getDeptLeader());
|
||||||
|
dept.setPhone(dto.getPhone());
|
||||||
|
dept.setEmail(dto.getEmail());
|
||||||
|
dept.setSortOrder(dto.getSortOrder() != null ? dto.getSortOrder() : 0);
|
||||||
|
dept.setStatus(dto.getStatus() != null ? dto.getStatus() : 1);
|
||||||
|
dept.setDeleted(0);
|
||||||
|
dept.setCreatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
deptDataService.save(dept);
|
||||||
|
log.info("创建部门成功: deptId={}, deptName={}", dept.getId(), dept.getDeptName());
|
||||||
|
return dept.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateDept(DeptDTO dto) {
|
||||||
|
if (dto.getId() == null) {
|
||||||
|
throw new RuntimeException("部门ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
SysDept existing = deptDataService.getById(dto.getId());
|
||||||
|
if (existing == null || existing.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("部门不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
SysDept dept = new SysDept();
|
||||||
|
dept.setId(dto.getId());
|
||||||
|
dept.setParentId(dto.getParentId());
|
||||||
|
dept.setDeptName(dto.getDeptName());
|
||||||
|
dept.setDeptLeader(dto.getDeptLeader());
|
||||||
|
dept.setPhone(dto.getPhone());
|
||||||
|
dept.setEmail(dto.getEmail());
|
||||||
|
dept.setSortOrder(dto.getSortOrder());
|
||||||
|
dept.setStatus(dto.getStatus());
|
||||||
|
dept.setUpdatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
boolean result = deptDataService.updateById(dept);
|
||||||
|
log.info("更新部门: deptId={}", dto.getId());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeptVO getDeptById(Long id) {
|
||||||
|
SysDept dept = deptDataService.getById(id);
|
||||||
|
if (dept == null || dept.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("部门不存在");
|
||||||
|
}
|
||||||
|
return convertToVO(dept);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DeptVO> getDeptTree() {
|
||||||
|
LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysDept::getDeleted, 0);
|
||||||
|
wrapper.eq(SysDept::getStatus, 1);
|
||||||
|
wrapper.orderByAsc(SysDept::getSortOrder);
|
||||||
|
|
||||||
|
List<SysDept> depts = deptDataService.list(wrapper);
|
||||||
|
return buildDeptTree(depts, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DeptVO> listAllDepts() {
|
||||||
|
LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysDept::getDeleted, 0);
|
||||||
|
wrapper.orderByAsc(SysDept::getSortOrder);
|
||||||
|
return deptDataService.list(wrapper).stream().map(this::convertToVO).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean deleteDept(Long id) {
|
||||||
|
LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysDept::getParentId, id);
|
||||||
|
wrapper.eq(SysDept::getDeleted, 0);
|
||||||
|
if (deptDataService.count(wrapper) > 0) {
|
||||||
|
throw new RuntimeException("存在子部门,不能删除");
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaUpdateWrapper<SysDept> updateWrapper = new LambdaUpdateWrapper<>();
|
||||||
|
updateWrapper.eq(SysDept::getId, id);
|
||||||
|
updateWrapper.set(SysDept::getDeleted, 1);
|
||||||
|
updateWrapper.set(SysDept::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = deptDataService.update(updateWrapper);
|
||||||
|
log.info("删除部门: deptId={}", id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateStatus(Long id, Integer status) {
|
||||||
|
LambdaUpdateWrapper<SysDept> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(SysDept::getId, id);
|
||||||
|
wrapper.set(SysDept::getStatus, status);
|
||||||
|
wrapper.set(SysDept::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = deptDataService.update(wrapper);
|
||||||
|
log.info("更新部门状态: deptId={}, status={}", id, status);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DeptVO> buildDeptTree(List<SysDept> depts, Long parentId) {
|
||||||
|
List<DeptVO> tree = new ArrayList<>();
|
||||||
|
|
||||||
|
Map<Long, List<SysDept>> deptMap = depts.stream()
|
||||||
|
.collect(Collectors.groupingBy(SysDept::getParentId));
|
||||||
|
|
||||||
|
List<SysDept> rootDepts = deptMap.getOrDefault(parentId, new ArrayList<>());
|
||||||
|
for (SysDept dept : rootDepts) {
|
||||||
|
DeptVO vo = convertToVO(dept);
|
||||||
|
vo.setChildren(buildDeptTree(depts, dept.getId()));
|
||||||
|
tree.add(vo);
|
||||||
|
}
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeptVO convertToVO(SysDept dept) {
|
||||||
|
DeptVO vo = new DeptVO();
|
||||||
|
vo.setId(dept.getId());
|
||||||
|
vo.setParentId(dept.getParentId());
|
||||||
|
vo.setDeptCode(dept.getDeptCode());
|
||||||
|
vo.setDeptName(dept.getDeptName());
|
||||||
|
vo.setDeptLeader(dept.getDeptLeader());
|
||||||
|
vo.setPhone(dept.getPhone());
|
||||||
|
vo.setEmail(dept.getEmail());
|
||||||
|
vo.setSortOrder(dept.getSortOrder());
|
||||||
|
vo.setStatus(dept.getStatus());
|
||||||
|
vo.setTenantId(dept.getTenantId());
|
||||||
|
vo.setCreatedTime(dept.getCreatedTime());
|
||||||
|
vo.setUpdatedTime(dept.getUpdatedTime());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,178 @@
|
|||||||
|
package com.fundplatform.sys.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.fundplatform.sys.data.entity.SysMenu;
|
||||||
|
import com.fundplatform.sys.data.service.SysMenuDataService;
|
||||||
|
import com.fundplatform.sys.dto.MenuDTO;
|
||||||
|
import com.fundplatform.sys.service.MenuService;
|
||||||
|
import com.fundplatform.sys.vo.MenuVO;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单服务实现
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class MenuServiceImpl implements MenuService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MenuServiceImpl.class);
|
||||||
|
|
||||||
|
private final SysMenuDataService menuDataService;
|
||||||
|
|
||||||
|
public MenuServiceImpl(SysMenuDataService menuDataService) {
|
||||||
|
this.menuDataService = menuDataService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createMenu(MenuDTO dto) {
|
||||||
|
SysMenu menu = new SysMenu();
|
||||||
|
menu.setParentId(dto.getParentId() != null ? dto.getParentId() : 0L);
|
||||||
|
menu.setMenuName(dto.getMenuName());
|
||||||
|
menu.setMenuType(dto.getMenuType() != null ? dto.getMenuType() : 1);
|
||||||
|
menu.setMenuPath(dto.getMenuPath());
|
||||||
|
menu.setMenuIcon(dto.getMenuIcon());
|
||||||
|
menu.setComponent(dto.getComponent());
|
||||||
|
menu.setPermission(dto.getPermission());
|
||||||
|
menu.setSortOrder(dto.getSortOrder() != null ? dto.getSortOrder() : 0);
|
||||||
|
menu.setVisible(dto.getVisible() != null ? dto.getVisible() : 1);
|
||||||
|
menu.setStatus(dto.getStatus() != null ? dto.getStatus() : 1);
|
||||||
|
menu.setDeleted(0);
|
||||||
|
menu.setCreatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
menuDataService.save(menu);
|
||||||
|
log.info("创建菜单成功: menuId={}, menuName={}", menu.getId(), menu.getMenuName());
|
||||||
|
return menu.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateMenu(MenuDTO dto) {
|
||||||
|
if (dto.getId() == null) {
|
||||||
|
throw new RuntimeException("菜单ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
SysMenu existing = menuDataService.getById(dto.getId());
|
||||||
|
if (existing == null || existing.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("菜单不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
SysMenu menu = new SysMenu();
|
||||||
|
menu.setId(dto.getId());
|
||||||
|
menu.setParentId(dto.getParentId());
|
||||||
|
menu.setMenuName(dto.getMenuName());
|
||||||
|
menu.setMenuType(dto.getMenuType());
|
||||||
|
menu.setMenuPath(dto.getMenuPath());
|
||||||
|
menu.setMenuIcon(dto.getMenuIcon());
|
||||||
|
menu.setComponent(dto.getComponent());
|
||||||
|
menu.setPermission(dto.getPermission());
|
||||||
|
menu.setSortOrder(dto.getSortOrder());
|
||||||
|
menu.setVisible(dto.getVisible());
|
||||||
|
menu.setStatus(dto.getStatus());
|
||||||
|
menu.setUpdatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
boolean result = menuDataService.updateById(menu);
|
||||||
|
log.info("更新菜单: menuId={}", dto.getId());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MenuVO getMenuById(Long id) {
|
||||||
|
SysMenu menu = menuDataService.getById(id);
|
||||||
|
if (menu == null || menu.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("菜单不存在");
|
||||||
|
}
|
||||||
|
return convertToVO(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MenuVO> getMenuTree() {
|
||||||
|
LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysMenu::getDeleted, 0);
|
||||||
|
wrapper.eq(SysMenu::getStatus, 1);
|
||||||
|
wrapper.orderByAsc(SysMenu::getSortOrder);
|
||||||
|
|
||||||
|
List<SysMenu> menus = menuDataService.list(wrapper);
|
||||||
|
return buildMenuTree(menus, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MenuVO> getUserMenuTree(Long userId) {
|
||||||
|
// TODO: 根据用户角色查询菜单
|
||||||
|
return getMenuTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean deleteMenu(Long id) {
|
||||||
|
// 检查是否有子菜单
|
||||||
|
LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysMenu::getParentId, id);
|
||||||
|
wrapper.eq(SysMenu::getDeleted, 0);
|
||||||
|
if (menuDataService.count(wrapper) > 0) {
|
||||||
|
throw new RuntimeException("存在子菜单,不能删除");
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaUpdateWrapper<SysMenu> updateWrapper = new LambdaUpdateWrapper<>();
|
||||||
|
updateWrapper.eq(SysMenu::getId, id);
|
||||||
|
updateWrapper.set(SysMenu::getDeleted, 1);
|
||||||
|
updateWrapper.set(SysMenu::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = menuDataService.update(updateWrapper);
|
||||||
|
log.info("删除菜单: menuId={}", id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MenuVO> buildMenuTree(List<SysMenu> menus, Long parentId) {
|
||||||
|
List<MenuVO> tree = new ArrayList<>();
|
||||||
|
|
||||||
|
Map<Long, List<SysMenu>> menuMap = menus.stream()
|
||||||
|
.collect(Collectors.groupingBy(SysMenu::getParentId));
|
||||||
|
|
||||||
|
List<SysMenu> rootMenus = menuMap.getOrDefault(parentId, new ArrayList<>());
|
||||||
|
for (SysMenu menu : rootMenus) {
|
||||||
|
MenuVO vo = convertToVO(menu);
|
||||||
|
vo.setChildren(buildMenuTree(menus, menu.getId()));
|
||||||
|
tree.add(vo);
|
||||||
|
}
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MenuVO convertToVO(SysMenu menu) {
|
||||||
|
MenuVO vo = new MenuVO();
|
||||||
|
vo.setId(menu.getId());
|
||||||
|
vo.setParentId(menu.getParentId());
|
||||||
|
vo.setMenuName(menu.getMenuName());
|
||||||
|
vo.setMenuType(menu.getMenuType());
|
||||||
|
vo.setMenuTypeName(getMenuTypeName(menu.getMenuType()));
|
||||||
|
vo.setMenuPath(menu.getMenuPath());
|
||||||
|
vo.setMenuIcon(menu.getMenuIcon());
|
||||||
|
vo.setComponent(menu.getComponent());
|
||||||
|
vo.setPermission(menu.getPermission());
|
||||||
|
vo.setSortOrder(menu.getSortOrder());
|
||||||
|
vo.setVisible(menu.getVisible());
|
||||||
|
vo.setStatus(menu.getStatus());
|
||||||
|
vo.setTenantId(menu.getTenantId());
|
||||||
|
vo.setCreatedTime(menu.getCreatedTime());
|
||||||
|
vo.setUpdatedTime(menu.getUpdatedTime());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMenuTypeName(Integer menuType) {
|
||||||
|
if (menuType == null) return "";
|
||||||
|
switch (menuType) {
|
||||||
|
case 1: return "目录";
|
||||||
|
case 2: return "菜单";
|
||||||
|
case 3: return "按钮";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
package com.fundplatform.sys.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.sys.data.entity.SysRole;
|
||||||
|
import com.fundplatform.sys.data.service.SysRoleDataService;
|
||||||
|
import com.fundplatform.sys.dto.RoleDTO;
|
||||||
|
import com.fundplatform.sys.service.RoleService;
|
||||||
|
import com.fundplatform.sys.vo.RoleVO;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色服务实现
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class RoleServiceImpl implements RoleService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(RoleServiceImpl.class);
|
||||||
|
|
||||||
|
private final SysRoleDataService roleDataService;
|
||||||
|
|
||||||
|
public RoleServiceImpl(SysRoleDataService roleDataService) {
|
||||||
|
this.roleDataService = roleDataService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createRole(RoleDTO dto) {
|
||||||
|
// 检查角色编码是否存在
|
||||||
|
LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysRole::getRoleCode, dto.getRoleCode());
|
||||||
|
wrapper.eq(SysRole::getDeleted, 0);
|
||||||
|
if (roleDataService.count(wrapper) > 0) {
|
||||||
|
throw new RuntimeException("角色编码已存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
SysRole role = new SysRole();
|
||||||
|
role.setRoleCode(dto.getRoleCode());
|
||||||
|
role.setRoleName(dto.getRoleName());
|
||||||
|
role.setDataScope(dto.getDataScope() != null ? dto.getDataScope() : 1);
|
||||||
|
role.setStatus(dto.getStatus() != null ? dto.getStatus() : 1);
|
||||||
|
role.setSortOrder(dto.getSortOrder());
|
||||||
|
role.setDeleted(0);
|
||||||
|
role.setCreatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
roleDataService.save(role);
|
||||||
|
log.info("创建角色成功: roleId={}, roleCode={}", role.getId(), role.getRoleCode());
|
||||||
|
return role.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateRole(RoleDTO dto) {
|
||||||
|
if (dto.getId() == null) {
|
||||||
|
throw new RuntimeException("角色ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
SysRole existing = roleDataService.getById(dto.getId());
|
||||||
|
if (existing == null || existing.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("角色不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
SysRole role = new SysRole();
|
||||||
|
role.setId(dto.getId());
|
||||||
|
role.setRoleName(dto.getRoleName());
|
||||||
|
role.setDataScope(dto.getDataScope());
|
||||||
|
role.setStatus(dto.getStatus());
|
||||||
|
role.setSortOrder(dto.getSortOrder());
|
||||||
|
role.setUpdatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
boolean result = roleDataService.updateById(role);
|
||||||
|
log.info("更新角色: roleId={}, result={}", dto.getId(), result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RoleVO getRoleById(Long id) {
|
||||||
|
SysRole role = roleDataService.getById(id);
|
||||||
|
if (role == null || role.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("角色不存在");
|
||||||
|
}
|
||||||
|
return convertToVO(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<RoleVO> pageRoles(int pageNum, int pageSize, String roleName, Integer status) {
|
||||||
|
Page<SysRole> page = new Page<>(pageNum, pageSize);
|
||||||
|
LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysRole::getDeleted, 0);
|
||||||
|
|
||||||
|
if (StringUtils.hasText(roleName)) {
|
||||||
|
wrapper.like(SysRole::getRoleName, roleName);
|
||||||
|
}
|
||||||
|
if (status != null) {
|
||||||
|
wrapper.eq(SysRole::getStatus, status);
|
||||||
|
}
|
||||||
|
wrapper.orderByAsc(SysRole::getSortOrder);
|
||||||
|
|
||||||
|
Page<SysRole> rolePage = roleDataService.page(page, wrapper);
|
||||||
|
|
||||||
|
Page<RoleVO> voPage = new Page<>(rolePage.getCurrent(), rolePage.getSize(), rolePage.getTotal());
|
||||||
|
voPage.setRecords(rolePage.getRecords().stream().map(this::convertToVO).toList());
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RoleVO> listAllRoles() {
|
||||||
|
LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysRole::getDeleted, 0);
|
||||||
|
wrapper.eq(SysRole::getStatus, 1);
|
||||||
|
wrapper.orderByAsc(SysRole::getSortOrder);
|
||||||
|
return roleDataService.list(wrapper).stream().map(this::convertToVO).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean deleteRole(Long id) {
|
||||||
|
LambdaUpdateWrapper<SysRole> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(SysRole::getId, id);
|
||||||
|
wrapper.set(SysRole::getDeleted, 1);
|
||||||
|
wrapper.set(SysRole::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = roleDataService.update(wrapper);
|
||||||
|
log.info("删除角色: roleId={}", id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateStatus(Long id, Integer status) {
|
||||||
|
LambdaUpdateWrapper<SysRole> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(SysRole::getId, id);
|
||||||
|
wrapper.set(SysRole::getStatus, status);
|
||||||
|
wrapper.set(SysRole::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = roleDataService.update(wrapper);
|
||||||
|
log.info("更新角色状态: roleId={}, status={}", id, status);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean assignMenus(Long roleId, List<Long> menuIds) {
|
||||||
|
// TODO: 实现角色菜单关联
|
||||||
|
log.info("分配角色菜单: roleId={}, menuIds={}", roleId, menuIds);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RoleVO convertToVO(SysRole role) {
|
||||||
|
RoleVO vo = new RoleVO();
|
||||||
|
vo.setId(role.getId());
|
||||||
|
vo.setRoleCode(role.getRoleCode());
|
||||||
|
vo.setRoleName(role.getRoleName());
|
||||||
|
vo.setDataScope(role.getDataScope());
|
||||||
|
vo.setDataScopeName(getDataScopeName(role.getDataScope()));
|
||||||
|
vo.setStatus(role.getStatus());
|
||||||
|
vo.setSortOrder(role.getSortOrder());
|
||||||
|
vo.setTenantId(role.getTenantId());
|
||||||
|
vo.setCreatedTime(role.getCreatedTime());
|
||||||
|
vo.setUpdatedTime(role.getUpdatedTime());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDataScopeName(Integer dataScope) {
|
||||||
|
if (dataScope == null) return "";
|
||||||
|
switch (dataScope) {
|
||||||
|
case 1: return "全部数据";
|
||||||
|
case 2: return "本部门数据";
|
||||||
|
case 3: return "本部门及下级数据";
|
||||||
|
case 4: return "仅本人数据";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,230 @@
|
|||||||
|
package com.fundplatform.sys.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.sys.data.entity.SysDept;
|
||||||
|
import com.fundplatform.sys.data.entity.SysUser;
|
||||||
|
import com.fundplatform.sys.data.service.SysDeptDataService;
|
||||||
|
import com.fundplatform.sys.data.service.SysUserDataService;
|
||||||
|
import com.fundplatform.sys.dto.UserDTO;
|
||||||
|
import com.fundplatform.sys.service.UserService;
|
||||||
|
import com.fundplatform.sys.vo.UserVO;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户服务实现
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class UserServiceImpl implements UserService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
|
||||||
|
|
||||||
|
private final SysUserDataService userDataService;
|
||||||
|
private final SysDeptDataService deptDataService;
|
||||||
|
private final BCryptPasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
public UserServiceImpl(SysUserDataService userDataService, SysDeptDataService deptDataService) {
|
||||||
|
this.userDataService = userDataService;
|
||||||
|
this.deptDataService = deptDataService;
|
||||||
|
this.passwordEncoder = new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createUser(UserDTO dto) {
|
||||||
|
// 检查用户名是否存在
|
||||||
|
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysUser::getUsername, dto.getUsername());
|
||||||
|
wrapper.eq(SysUser::getDeleted, 0);
|
||||||
|
if (userDataService.count(wrapper) > 0) {
|
||||||
|
throw new RuntimeException("用户名已存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建用户
|
||||||
|
SysUser user = new SysUser();
|
||||||
|
user.setUsername(dto.getUsername());
|
||||||
|
user.setPassword(passwordEncoder.encode(dto.getPassword()));
|
||||||
|
user.setRealName(dto.getRealName());
|
||||||
|
user.setPhone(dto.getPhone());
|
||||||
|
user.setEmail(dto.getEmail());
|
||||||
|
user.setDeptId(dto.getDeptId());
|
||||||
|
user.setStatus(dto.getStatus() != null ? dto.getStatus() : 1);
|
||||||
|
user.setAvatar(dto.getAvatar());
|
||||||
|
user.setRemark(dto.getRemark());
|
||||||
|
user.setDeleted(0);
|
||||||
|
user.setCreatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
userDataService.save(user);
|
||||||
|
log.info("创建用户成功: userId={}, username={}", user.getId(), user.getUsername());
|
||||||
|
return user.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateUser(UserDTO dto) {
|
||||||
|
if (dto.getId() == null) {
|
||||||
|
throw new RuntimeException("用户ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查用户是否存在
|
||||||
|
SysUser existingUser = userDataService.getById(dto.getId());
|
||||||
|
if (existingUser == null || existingUser.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("用户不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果修改了用户名,检查是否重复
|
||||||
|
if (StringUtils.hasText(dto.getUsername()) && !dto.getUsername().equals(existingUser.getUsername())) {
|
||||||
|
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysUser::getUsername, dto.getUsername());
|
||||||
|
wrapper.eq(SysUser::getDeleted, 0);
|
||||||
|
wrapper.ne(SysUser::getId, dto.getId());
|
||||||
|
if (userDataService.count(wrapper) > 0) {
|
||||||
|
throw new RuntimeException("用户名已存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新用户
|
||||||
|
SysUser user = new SysUser();
|
||||||
|
user.setId(dto.getId());
|
||||||
|
if (StringUtils.hasText(dto.getUsername())) {
|
||||||
|
user.setUsername(dto.getUsername());
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(dto.getPassword())) {
|
||||||
|
user.setPassword(passwordEncoder.encode(dto.getPassword()));
|
||||||
|
}
|
||||||
|
user.setRealName(dto.getRealName());
|
||||||
|
user.setPhone(dto.getPhone());
|
||||||
|
user.setEmail(dto.getEmail());
|
||||||
|
user.setDeptId(dto.getDeptId());
|
||||||
|
user.setStatus(dto.getStatus());
|
||||||
|
user.setAvatar(dto.getAvatar());
|
||||||
|
user.setRemark(dto.getRemark());
|
||||||
|
user.setUpdatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
boolean result = userDataService.updateById(user);
|
||||||
|
log.info("更新用户: userId={}, result={}", dto.getId(), result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserVO getUserById(Long id) {
|
||||||
|
SysUser user = userDataService.getById(id);
|
||||||
|
if (user == null || user.getDeleted() == 1) {
|
||||||
|
throw new RuntimeException("用户不存在");
|
||||||
|
}
|
||||||
|
return convertToVO(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<UserVO> pageUsers(int pageNum, int pageSize, String username, Integer status, Long deptId) {
|
||||||
|
Page<SysUser> page = new Page<>(pageNum, pageSize);
|
||||||
|
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(SysUser::getDeleted, 0);
|
||||||
|
|
||||||
|
if (StringUtils.hasText(username)) {
|
||||||
|
wrapper.like(SysUser::getUsername, username);
|
||||||
|
}
|
||||||
|
if (status != null) {
|
||||||
|
wrapper.eq(SysUser::getStatus, status);
|
||||||
|
}
|
||||||
|
if (deptId != null) {
|
||||||
|
wrapper.eq(SysUser::getDeptId, deptId);
|
||||||
|
}
|
||||||
|
wrapper.orderByDesc(SysUser::getCreatedTime);
|
||||||
|
|
||||||
|
Page<SysUser> userPage = userDataService.page(page, wrapper);
|
||||||
|
|
||||||
|
// 转换为VO
|
||||||
|
Page<UserVO> voPage = new Page<>(userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
|
||||||
|
voPage.setRecords(userPage.getRecords().stream().map(this::convertToVO).toList());
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean deleteUser(Long id) {
|
||||||
|
LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(SysUser::getId, id);
|
||||||
|
wrapper.set(SysUser::getDeleted, 1);
|
||||||
|
wrapper.set(SysUser::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = userDataService.update(wrapper);
|
||||||
|
log.info("删除用户: userId={}, result={}", id, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean batchDeleteUsers(Long[] ids) {
|
||||||
|
if (ids == null || ids.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.in(SysUser::getId, Arrays.asList(ids));
|
||||||
|
wrapper.set(SysUser::getDeleted, 1);
|
||||||
|
wrapper.set(SysUser::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = userDataService.update(wrapper);
|
||||||
|
log.info("批量删除用户: ids={}, result={}", Arrays.toString(ids), result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean resetPassword(Long id) {
|
||||||
|
String defaultPassword = "123456";
|
||||||
|
LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(SysUser::getId, id);
|
||||||
|
wrapper.set(SysUser::getPassword, passwordEncoder.encode(defaultPassword));
|
||||||
|
wrapper.set(SysUser::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = userDataService.update(wrapper);
|
||||||
|
log.info("重置用户密码: userId={}", id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateStatus(Long id, Integer status) {
|
||||||
|
LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(SysUser::getId, id);
|
||||||
|
wrapper.set(SysUser::getStatus, status);
|
||||||
|
wrapper.set(SysUser::getUpdatedTime, LocalDateTime.now());
|
||||||
|
boolean result = userDataService.update(wrapper);
|
||||||
|
log.info("更新用户状态: userId={}, status={}", id, status);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为VO
|
||||||
|
*/
|
||||||
|
private UserVO convertToVO(SysUser user) {
|
||||||
|
UserVO vo = new UserVO();
|
||||||
|
vo.setId(user.getId());
|
||||||
|
vo.setUsername(user.getUsername());
|
||||||
|
vo.setRealName(user.getRealName());
|
||||||
|
vo.setPhone(user.getPhone());
|
||||||
|
vo.setEmail(user.getEmail());
|
||||||
|
vo.setDeptId(user.getDeptId());
|
||||||
|
vo.setStatus(user.getStatus());
|
||||||
|
vo.setAvatar(user.getAvatar());
|
||||||
|
vo.setTenantId(user.getTenantId());
|
||||||
|
vo.setCreatedTime(user.getCreatedTime());
|
||||||
|
vo.setUpdatedTime(user.getUpdatedTime());
|
||||||
|
|
||||||
|
// 查询部门名称
|
||||||
|
if (user.getDeptId() != null) {
|
||||||
|
SysDept dept = deptDataService.getById(user.getDeptId());
|
||||||
|
if (dept != null) {
|
||||||
|
vo.setDeptName(dept.getDeptName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
}
|
||||||
139
fund-sys/src/main/java/com/fundplatform/sys/vo/DeptVO.java
Normal file
139
fund-sys/src/main/java/com/fundplatform/sys/vo/DeptVO.java
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
package com.fundplatform.sys.vo;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门VO
|
||||||
|
*/
|
||||||
|
public class DeptVO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private Long parentId;
|
||||||
|
private String parentName;
|
||||||
|
private String deptCode;
|
||||||
|
private String deptName;
|
||||||
|
private String deptLeader;
|
||||||
|
private String phone;
|
||||||
|
private String email;
|
||||||
|
private Integer sortOrder;
|
||||||
|
private Integer status;
|
||||||
|
private Long tenantId;
|
||||||
|
private LocalDateTime createdTime;
|
||||||
|
private LocalDateTime updatedTime;
|
||||||
|
|
||||||
|
// 子部门
|
||||||
|
private List<DeptVO> children;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getParentId() {
|
||||||
|
return parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentId(Long parentId) {
|
||||||
|
this.parentId = parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParentName() {
|
||||||
|
return parentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentName(String parentName) {
|
||||||
|
this.parentName = parentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeptCode() {
|
||||||
|
return deptCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeptCode(String deptCode) {
|
||||||
|
this.deptCode = deptCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeptName() {
|
||||||
|
return deptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeptName(String deptName) {
|
||||||
|
this.deptName = deptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeptLeader() {
|
||||||
|
return deptLeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeptLeader(String deptLeader) {
|
||||||
|
this.deptLeader = deptLeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhone() {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhone(String phone) {
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSortOrder() {
|
||||||
|
return sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortOrder(Integer sortOrder) {
|
||||||
|
this.sortOrder = sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Integer status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(Long tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedTime() {
|
||||||
|
return createdTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedTime(LocalDateTime createdTime) {
|
||||||
|
this.createdTime = createdTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedTime() {
|
||||||
|
return updatedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedTime(LocalDateTime updatedTime) {
|
||||||
|
this.updatedTime = updatedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DeptVO> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildren(List<DeptVO> children) {
|
||||||
|
this.children = children;
|
||||||
|
}
|
||||||
|
}
|
||||||
157
fund-sys/src/main/java/com/fundplatform/sys/vo/MenuVO.java
Normal file
157
fund-sys/src/main/java/com/fundplatform/sys/vo/MenuVO.java
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
package com.fundplatform.sys.vo;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单VO
|
||||||
|
*/
|
||||||
|
public class MenuVO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private Long parentId;
|
||||||
|
private String menuName;
|
||||||
|
private Integer menuType;
|
||||||
|
private String menuTypeName;
|
||||||
|
private String menuPath;
|
||||||
|
private String menuIcon;
|
||||||
|
private String component;
|
||||||
|
private String permission;
|
||||||
|
private Integer sortOrder;
|
||||||
|
private Integer visible;
|
||||||
|
private Integer status;
|
||||||
|
private Long tenantId;
|
||||||
|
private LocalDateTime createdTime;
|
||||||
|
private LocalDateTime updatedTime;
|
||||||
|
|
||||||
|
// 子菜单
|
||||||
|
private List<MenuVO> children;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getParentId() {
|
||||||
|
return parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentId(Long parentId) {
|
||||||
|
this.parentId = parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuName() {
|
||||||
|
return menuName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuName(String menuName) {
|
||||||
|
this.menuName = menuName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMenuType() {
|
||||||
|
return menuType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuType(Integer menuType) {
|
||||||
|
this.menuType = menuType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuTypeName() {
|
||||||
|
return menuTypeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuTypeName(String menuTypeName) {
|
||||||
|
this.menuTypeName = menuTypeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuPath() {
|
||||||
|
return menuPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuPath(String menuPath) {
|
||||||
|
this.menuPath = menuPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuIcon() {
|
||||||
|
return menuIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuIcon(String menuIcon) {
|
||||||
|
this.menuIcon = menuIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getComponent() {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComponent(String component) {
|
||||||
|
this.component = component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPermission() {
|
||||||
|
return permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermission(String permission) {
|
||||||
|
this.permission = permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSortOrder() {
|
||||||
|
return sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortOrder(Integer sortOrder) {
|
||||||
|
this.sortOrder = sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVisible() {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(Integer visible) {
|
||||||
|
this.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Integer status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(Long tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedTime() {
|
||||||
|
return createdTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedTime(LocalDateTime createdTime) {
|
||||||
|
this.createdTime = createdTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedTime() {
|
||||||
|
return updatedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedTime(LocalDateTime updatedTime) {
|
||||||
|
this.updatedTime = updatedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MenuVO> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildren(List<MenuVO> children) {
|
||||||
|
this.children = children;
|
||||||
|
}
|
||||||
|
}
|
||||||
100
fund-sys/src/main/java/com/fundplatform/sys/vo/RoleVO.java
Normal file
100
fund-sys/src/main/java/com/fundplatform/sys/vo/RoleVO.java
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package com.fundplatform.sys.vo;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色VO
|
||||||
|
*/
|
||||||
|
public class RoleVO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String roleCode;
|
||||||
|
private String roleName;
|
||||||
|
private Integer dataScope;
|
||||||
|
private String dataScopeName;
|
||||||
|
private Integer status;
|
||||||
|
private Integer sortOrder;
|
||||||
|
private Long tenantId;
|
||||||
|
private LocalDateTime createdTime;
|
||||||
|
private LocalDateTime updatedTime;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoleCode() {
|
||||||
|
return roleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoleCode(String roleCode) {
|
||||||
|
this.roleCode = roleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoleName() {
|
||||||
|
return roleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoleName(String roleName) {
|
||||||
|
this.roleName = roleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDataScope() {
|
||||||
|
return dataScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataScope(Integer dataScope) {
|
||||||
|
this.dataScope = dataScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataScopeName() {
|
||||||
|
return dataScopeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataScopeName(String dataScopeName) {
|
||||||
|
this.dataScopeName = dataScopeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Integer status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSortOrder() {
|
||||||
|
return sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortOrder(Integer sortOrder) {
|
||||||
|
this.sortOrder = sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(Long tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedTime() {
|
||||||
|
return createdTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedTime(LocalDateTime createdTime) {
|
||||||
|
this.createdTime = createdTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedTime() {
|
||||||
|
return updatedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedTime(LocalDateTime updatedTime) {
|
||||||
|
this.updatedTime = updatedTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
118
fund-sys/src/main/java/com/fundplatform/sys/vo/UserVO.java
Normal file
118
fund-sys/src/main/java/com/fundplatform/sys/vo/UserVO.java
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package com.fundplatform.sys.vo;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户VO(返回视图)
|
||||||
|
*/
|
||||||
|
public class UserVO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String username;
|
||||||
|
private String realName;
|
||||||
|
private String phone;
|
||||||
|
private String email;
|
||||||
|
private Long deptId;
|
||||||
|
private String deptName;
|
||||||
|
private Integer status;
|
||||||
|
private String avatar;
|
||||||
|
private Long tenantId;
|
||||||
|
private LocalDateTime createdTime;
|
||||||
|
private LocalDateTime updatedTime;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRealName() {
|
||||||
|
return realName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRealName(String realName) {
|
||||||
|
this.realName = realName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhone() {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhone(String phone) {
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDeptId() {
|
||||||
|
return deptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeptId(Long deptId) {
|
||||||
|
this.deptId = deptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeptName() {
|
||||||
|
return deptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeptName(String deptName) {
|
||||||
|
this.deptName = deptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Integer status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAvatar() {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvatar(String avatar) {
|
||||||
|
this.avatar = avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(Long tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedTime() {
|
||||||
|
return createdTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedTime(LocalDateTime createdTime) {
|
||||||
|
this.createdTime = createdTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedTime() {
|
||||||
|
return updatedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedTime(LocalDateTime updatedTime) {
|
||||||
|
this.updatedTime = updatedTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,13 @@ spring:
|
|||||||
application:
|
application:
|
||||||
name: fund-sys
|
name: fund-sys
|
||||||
|
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
server-addr: localhost:8848
|
||||||
|
namespace: fund-platform
|
||||||
|
group: DEFAULT_GROUP
|
||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
url: jdbc:mysql://localhost:3306/fund_sys?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
url: jdbc:mysql://localhost:3306/fund_sys?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
||||||
@ -15,6 +22,21 @@ spring:
|
|||||||
minimum-idle: 5
|
minimum-idle: 5
|
||||||
connection-timeout: 30000
|
connection-timeout: 30000
|
||||||
|
|
||||||
|
# Redis配置
|
||||||
|
data:
|
||||||
|
redis:
|
||||||
|
host: localhost
|
||||||
|
port: 6379
|
||||||
|
password: zjf@123456
|
||||||
|
database: 0
|
||||||
|
timeout: 10000
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
max-active: 8
|
||||||
|
max-wait: -1
|
||||||
|
max-idle: 8
|
||||||
|
min-idle: 0
|
||||||
|
|
||||||
mybatis-plus:
|
mybatis-plus:
|
||||||
mapper-locations: classpath*:/mapper/**/*.xml
|
mapper-locations: classpath*:/mapper/**/*.xml
|
||||||
type-aliases-package: com.fundplatform.sys.data.entity
|
type-aliases-package: com.fundplatform.sys.data.entity
|
||||||
|
|||||||
100
fund-sys/src/main/resources/logback-spring.xml
Normal file
100
fund-sys/src/main/resources/logback-spring.xml
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||||
|
|
||||||
|
<!-- 定义日志文件路径 -->
|
||||||
|
<property name="LOG_PATH" value="./logs"/>
|
||||||
|
<property name="APP_NAME" value="fund-sys"/>
|
||||||
|
|
||||||
|
<!-- 控制台输出 -->
|
||||||
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId:-}] %-5level %logger{50} - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- INFO级别日志文件 -->
|
||||||
|
<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_PATH}/${APP_NAME}/info.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId:-}] %-5level %logger{50} - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_PATH}/${APP_NAME}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>INFO</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- ERROR级别日志文件 -->
|
||||||
|
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_PATH}/${APP_NAME}/error.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId:-}] %-5level %logger{50} - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_PATH}/${APP_NAME}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- JSON格式日志(用于ELK采集) -->
|
||||||
|
<appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_PATH}/${APP_NAME}/json.log</file>
|
||||||
|
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
|
||||||
|
<customFields>{"app_name":"${APP_NAME}"}</customFields>
|
||||||
|
<includeMdcKeyName>traceId</includeMdcKeyName>
|
||||||
|
<includeMdcKeyName>userId</includeMdcKeyName>
|
||||||
|
<includeMdcKeyName>tenantId</includeMdcKeyName>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_PATH}/${APP_NAME}/json-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 开发环境 -->
|
||||||
|
<springProfile name="dev">
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="CONSOLE"/>
|
||||||
|
</root>
|
||||||
|
</springProfile>
|
||||||
|
|
||||||
|
<!-- 生产环境 -->
|
||||||
|
<springProfile name="prod">
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="CONSOLE"/>
|
||||||
|
<appender-ref ref="FILE_INFO"/>
|
||||||
|
<appender-ref ref="FILE_ERROR"/>
|
||||||
|
<appender-ref ref="JSON_FILE"/>
|
||||||
|
</root>
|
||||||
|
</springProfile>
|
||||||
|
|
||||||
|
<!-- 默认配置 -->
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="CONSOLE"/>
|
||||||
|
<appender-ref ref="FILE_INFO"/>
|
||||||
|
<appender-ref ref="FILE_ERROR"/>
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
23
pom.xml
23
pom.xml
@ -35,8 +35,31 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>21</java.version>
|
<java.version>21</java.version>
|
||||||
|
<spring-cloud.version>2023.0.0</spring-cloud.version>
|
||||||
|
<spring-cloud-alibaba.version>2023.0.0.0-RC1</spring-cloud-alibaba.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<!-- Spring Cloud -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-dependencies</artifactId>
|
||||||
|
<version>${spring-cloud.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- Spring Cloud Alibaba -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||||
|
<version>${spring-cloud-alibaba.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
<!-- 项目内自定义 Maven 仓库配置,避免依赖外部 settings.xml 中的私服配置 -->
|
<!-- 项目内自定义 Maven 仓库配置,避免依赖外部 settings.xml 中的私服配置 -->
|
||||||
<repositories>
|
<repositories>
|
||||||
<!-- 官方中央仓库 -->
|
<!-- 官方中央仓库 -->
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user