feat: 补充后端缺失接口并修复API路径不一致问题

新增接口:
- fund-sys: 登出、刷新Token、获取角色菜单
- fund-cust: 联系人管理完整CRUD
- fund-receipt: 获取应收款收款记录列表

修复问题:
- 支出类型更新接口路径改为 PUT /{id}
- 支出更新接口路径改为 PUT /{id}
- 应收款更新接口路径改为 PUT /{id}
- FundReceipt实体添加receivableId字段
This commit is contained in:
zhangjf 2026-02-18 08:19:13 +08:00
parent b3ef6d89f1
commit 88291b1d46
24 changed files with 853 additions and 8 deletions

View File

@ -0,0 +1,82 @@
package com.fundplatform.cust.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fundplatform.common.core.Result;
import com.fundplatform.cust.dto.ContactDTO;
import com.fundplatform.cust.service.ContactService;
import com.fundplatform.cust.vo.ContactVO;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
/**
* 联系人管理Controller
*/
@RestController
@RequestMapping("/api/v1/customer/contact")
public class ContactController {
private final ContactService contactService;
public ContactController(ContactService contactService) {
this.contactService = contactService;
}
/**
* 创建联系人
*/
@PostMapping
public Result<Long> create(@Valid @RequestBody ContactDTO dto) {
Long id = contactService.createContact(dto);
return Result.success(id);
}
/**
* 更新联系人
*/
@PutMapping("/{id}")
public Result<Boolean> update(@PathVariable Long id, @Valid @RequestBody ContactDTO dto) {
boolean result = contactService.updateContact(id, dto);
return Result.success(result);
}
/**
* 根据ID查询联系人
*/
@GetMapping("/{id}")
public Result<ContactVO> getById(@PathVariable Long id) {
ContactVO vo = contactService.getContactById(id);
return Result.success(vo);
}
/**
* 分页查询联系人
*/
@GetMapping("/page")
public Result<Page<ContactVO>> page(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
@RequestParam(required = false) Long customerId) {
Page<ContactVO> page = contactService.pageContacts(pageNum, pageSize, customerId);
return Result.success(page);
}
/**
* 删除联系人
*/
@DeleteMapping("/{id}")
public Result<Boolean> delete(@PathVariable Long id) {
boolean result = contactService.deleteContact(id);
return Result.success(result);
}
/**
* 设置主要联系人
*/
@PutMapping("/{customerId}/contact/{contactId}/primary")
public Result<Boolean> setPrimary(
@PathVariable Long customerId,
@PathVariable Long contactId) {
boolean result = contactService.setPrimaryContact(customerId, contactId);
return Result.success(result);
}
}

View File

@ -0,0 +1,117 @@
package com.fundplatform.cust.data.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fundplatform.common.core.BaseEntity;
import java.time.LocalDateTime;
/**
* 联系人实体
*/
@TableName("customer_contact")
public class CustomerContact extends BaseEntity {
/**
* 客户ID
*/
private Long customerId;
/**
* 联系人姓名
*/
private String contactName;
/**
* 职位
*/
private String position;
/**
* 手机号
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 是否主要联系人(0- 1-)
*/
private Integer isPrimary;
/**
* 状态(0-禁用 1-启用)
*/
private Integer status;
/**
* 备注
*/
private String remark;
public Long getCustomerId() {
return customerId;
}
public void setCustomerId(Long customerId) {
this.customerId = customerId;
}
public String getContactName() {
return contactName;
}
public void setContactName(String contactName) {
this.contactName = contactName;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
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 getIsPrimary() {
return isPrimary;
}
public void setIsPrimary(Integer isPrimary) {
this.isPrimary = isPrimary;
}
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;
}
}

View File

@ -0,0 +1,12 @@
package com.fundplatform.cust.data.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fundplatform.cust.data.entity.CustomerContact;
import org.apache.ibatis.annotations.Mapper;
/**
* 联系人Mapper
*/
@Mapper
public interface CustomerContactMapper extends BaseMapper<CustomerContact> {
}

View File

@ -0,0 +1,10 @@
package com.fundplatform.cust.data.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fundplatform.cust.data.entity.CustomerContact;
/**
* 联系人数据服务
*/
public interface CustomerContactDataService extends IService<CustomerContact> {
}

View File

@ -0,0 +1,14 @@
package com.fundplatform.cust.data.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fundplatform.cust.data.entity.CustomerContact;
import com.fundplatform.cust.data.mapper.CustomerContactMapper;
import com.fundplatform.cust.data.service.CustomerContactDataService;
import org.springframework.stereotype.Service;
/**
* 联系人数据服务实现
*/
@Service
public class CustomerContactDataServiceImpl extends ServiceImpl<CustomerContactMapper, CustomerContact> implements CustomerContactDataService {
}

View File

@ -0,0 +1,126 @@
package com.fundplatform.cust.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
/**
* 联系人DTO
*/
public class ContactDTO {
private Long id;
/**
* 客户ID
*/
@NotNull(message = "客户ID不能为空")
private Long customerId;
/**
* 联系人姓名
*/
@NotBlank(message = "联系人姓名不能为空")
private String contactName;
/**
* 职位
*/
private String position;
/**
* 手机号
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 是否主要联系人
*/
private Integer isPrimary;
/**
* 状态
*/
private Integer status;
/**
* 备注
*/
private String remark;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getCustomerId() {
return customerId;
}
public void setCustomerId(Long customerId) {
this.customerId = customerId;
}
public String getContactName() {
return contactName;
}
public void setContactName(String contactName) {
this.contactName = contactName;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
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 getIsPrimary() {
return isPrimary;
}
public void setIsPrimary(Integer isPrimary) {
this.isPrimary = isPrimary;
}
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;
}
}

View File

@ -0,0 +1,41 @@
package com.fundplatform.cust.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fundplatform.cust.dto.ContactDTO;
import com.fundplatform.cust.vo.ContactVO;
/**
* 联系人服务接口
*/
public interface ContactService {
/**
* 创建联系人
*/
Long createContact(ContactDTO dto);
/**
* 更新联系人
*/
boolean updateContact(Long id, ContactDTO dto);
/**
* 根据ID查询联系人
*/
ContactVO getContactById(Long id);
/**
* 分页查询联系人
*/
Page<ContactVO> pageContacts(int pageNum, int pageSize, Long customerId);
/**
* 删除联系人
*/
boolean deleteContact(Long id);
/**
* 设置主要联系人
*/
boolean setPrimaryContact(Long customerId, Long contactId);
}

View File

@ -0,0 +1,148 @@
package com.fundplatform.cust.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.cust.data.entity.CustomerContact;
import com.fundplatform.cust.data.service.CustomerContactDataService;
import com.fundplatform.cust.dto.ContactDTO;
import com.fundplatform.cust.service.ContactService;
import com.fundplatform.cust.vo.ContactVO;
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.List;
/**
* 联系人服务实现
*/
@Service
public class ContactServiceImpl implements ContactService {
private static final Logger log = LoggerFactory.getLogger(ContactServiceImpl.class);
private final CustomerContactDataService contactDataService;
public ContactServiceImpl(CustomerContactDataService contactDataService) {
this.contactDataService = contactDataService;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long createContact(ContactDTO dto) {
CustomerContact contact = new CustomerContact();
contact.setCustomerId(dto.getCustomerId());
contact.setContactName(dto.getContactName());
contact.setPosition(dto.getPosition());
contact.setPhone(dto.getPhone());
contact.setEmail(dto.getEmail());
contact.setIsPrimary(dto.getIsPrimary() != null ? dto.getIsPrimary() : 0);
contact.setStatus(dto.getStatus() != null ? dto.getStatus() : 1);
contact.setRemark(dto.getRemark());
contact.setDeleted(0);
contact.setCreatedTime(LocalDateTime.now());
contactDataService.save(contact);
log.info("创建联系人成功: contactId={}, customerId={}", contact.getId(), contact.getCustomerId());
return contact.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateContact(Long id, ContactDTO dto) {
CustomerContact contact = contactDataService.getById(id);
if (contact == null || contact.getDeleted() == 1) {
throw new RuntimeException("联系人不存在");
}
contact.setContactName(dto.getContactName());
contact.setPosition(dto.getPosition());
contact.setPhone(dto.getPhone());
contact.setEmail(dto.getEmail());
contact.setIsPrimary(dto.getIsPrimary());
contact.setStatus(dto.getStatus());
contact.setRemark(dto.getRemark());
contact.setUpdatedTime(LocalDateTime.now());
boolean result = contactDataService.updateById(contact);
log.info("更新联系人: contactId={}", id);
return result;
}
@Override
public ContactVO getContactById(Long id) {
CustomerContact contact = contactDataService.getById(id);
if (contact == null || contact.getDeleted() == 1) {
throw new RuntimeException("联系人不存在");
}
return convertToVO(contact);
}
@Override
public Page<ContactVO> pageContacts(int pageNum, int pageSize, Long customerId) {
Page<CustomerContact> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<CustomerContact> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CustomerContact::getDeleted, 0);
if (customerId != null) {
wrapper.eq(CustomerContact::getCustomerId, customerId);
}
wrapper.orderByDesc(CustomerContact::getIsPrimary);
wrapper.orderByDesc(CustomerContact::getCreatedTime);
Page<CustomerContact> contactPage = contactDataService.page(page, wrapper);
Page<ContactVO> voPage = new Page<>(contactPage.getCurrent(), contactPage.getSize(), contactPage.getTotal());
voPage.setRecords(contactPage.getRecords().stream().map(this::convertToVO).toList());
return voPage;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteContact(Long id) {
LambdaUpdateWrapper<CustomerContact> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(CustomerContact::getId, id);
wrapper.set(CustomerContact::getDeleted, 1);
wrapper.set(CustomerContact::getUpdatedTime, LocalDateTime.now());
boolean result = contactDataService.update(wrapper);
log.info("删除联系人: contactId={}", id);
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean setPrimaryContact(Long customerId, Long contactId) {
// 先清除该客户的所有主要联系人标记
LambdaUpdateWrapper<CustomerContact> clearWrapper = new LambdaUpdateWrapper<>();
clearWrapper.eq(CustomerContact::getCustomerId, customerId);
clearWrapper.set(CustomerContact::getIsPrimary, 0);
contactDataService.update(clearWrapper);
// 设置新的主要联系人
LambdaUpdateWrapper<CustomerContact> setWrapper = new LambdaUpdateWrapper<>();
setWrapper.eq(CustomerContact::getId, contactId);
setWrapper.set(CustomerContact::getIsPrimary, 1);
setWrapper.set(CustomerContact::getUpdatedTime, LocalDateTime.now());
boolean result = contactDataService.update(setWrapper);
log.info("设置主要联系人: customerId={}, contactId={}", customerId, contactId);
return result;
}
private ContactVO convertToVO(CustomerContact contact) {
ContactVO vo = new ContactVO();
vo.setId(contact.getId());
vo.setCustomerId(contact.getCustomerId());
vo.setContactName(contact.getContactName());
vo.setPosition(contact.getPosition());
vo.setPhone(contact.getPhone());
vo.setEmail(contact.getEmail());
vo.setIsPrimary(contact.getIsPrimary());
vo.setStatus(contact.getStatus());
vo.setRemark(contact.getRemark());
vo.setCreatedTime(contact.getCreatedTime());
vo.setUpdatedTime(contact.getUpdatedTime());
return vo;
}
}

View File

@ -0,0 +1,162 @@
package com.fundplatform.cust.vo;
import java.time.LocalDateTime;
/**
* 联系人VO
*/
public class ContactVO {
private Long id;
/**
* 客户ID
*/
private Long customerId;
/**
* 客户名称
*/
private String customerName;
/**
* 联系人姓名
*/
private String contactName;
/**
* 职位
*/
private String position;
/**
* 手机号
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 是否主要联系人
*/
private Integer isPrimary;
/**
* 状态
*/
private Integer status;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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 String getContactName() {
return contactName;
}
public void setContactName(String contactName) {
this.contactName = contactName;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
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 getIsPrimary() {
return isPrimary;
}
public void setIsPrimary(Integer isPrimary) {
this.isPrimary = isPrimary;
}
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;
}
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;
}
}

View File

@ -35,8 +35,9 @@ public class ExpenseTypeController {
/** /**
* 更新支出类型 * 更新支出类型
*/ */
@PutMapping @PutMapping("/{id}")
public Result<Boolean> update(@Valid @RequestBody ExpenseTypeDTO dto) { public Result<Boolean> update(@PathVariable Long id, @Valid @RequestBody ExpenseTypeDTO dto) {
dto.setId(id);
return Result.success(typeService.updateType(dto)); return Result.success(typeService.updateType(dto));
} }

View File

@ -38,8 +38,9 @@ public class FundExpenseController {
/** /**
* 更新支出申请仅待审批状态可修改 * 更新支出申请仅待审批状态可修改
*/ */
@PutMapping @PutMapping("/{id}")
public Result<Boolean> update(@Valid @RequestBody FundExpenseDTO dto) { public Result<Boolean> update(@PathVariable Long id, @Valid @RequestBody FundExpenseDTO dto) {
dto.setId(id);
return Result.success(expenseService.updateExpense(dto)); return Result.success(expenseService.updateExpense(dto));
} }

View File

@ -4,11 +4,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fundplatform.common.core.Result; import com.fundplatform.common.core.Result;
import com.fundplatform.receipt.dto.ReceivableDTO; import com.fundplatform.receipt.dto.ReceivableDTO;
import com.fundplatform.receipt.service.ReceivableService; import com.fundplatform.receipt.service.ReceivableService;
import com.fundplatform.receipt.vo.FundReceiptVO;
import com.fundplatform.receipt.vo.ReceivableVO; import com.fundplatform.receipt.vo.ReceivableVO;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List;
/** /**
* 应收款管理Controller * 应收款管理Controller
@ -40,8 +42,9 @@ public class ReceivableController {
/** /**
* 更新应收款仅待确认状态可修改 * 更新应收款仅待确认状态可修改
*/ */
@PutMapping @PutMapping("/{id}")
public Result<Boolean> update(@Valid @RequestBody ReceivableDTO dto) { public Result<Boolean> update(@PathVariable Long id, @Valid @RequestBody ReceivableDTO dto) {
dto.setId(id);
return Result.success(receivableService.updateReceivable(dto)); return Result.success(receivableService.updateReceivable(dto));
} }
@ -93,6 +96,14 @@ public class ReceivableController {
return Result.success(receivableService.recordReceipt(id, amount)); return Result.success(receivableService.recordReceipt(id, amount));
} }
/**
* 获取应收款的收款记录列表
*/
@GetMapping("/{id}/receipts")
public Result<List<FundReceiptVO>> getReceipts(@PathVariable Long id) {
return Result.success(receivableService.getReceiptsByReceivableId(id));
}
/** /**
* 更新逾期状态 * 更新逾期状态
*/ */

View File

@ -48,6 +48,9 @@ public class FundReceipt extends BaseEntity {
/** 关联客户ID */ /** 关联客户ID */
private Long customerId; private Long customerId;
/** 关联应收款ID */
private Long receivableId;
/** 收款状态(0-待确认 1-已确认 2-已核销) */ /** 收款状态(0-待确认 1-已确认 2-已核销) */
private Integer receiptStatus; private Integer receiptStatus;
@ -96,6 +99,8 @@ public class FundReceipt extends BaseEntity {
public void setProjectId(Long projectId) { this.projectId = projectId; } public void setProjectId(Long projectId) { this.projectId = projectId; }
public Long getCustomerId() { return customerId; } public Long getCustomerId() { return customerId; }
public void setCustomerId(Long customerId) { this.customerId = customerId; } public void setCustomerId(Long customerId) { this.customerId = customerId; }
public Long getReceivableId() { return receivableId; }
public void setReceivableId(Long receivableId) { this.receivableId = receivableId; }
public Integer getReceiptStatus() { return receiptStatus; } public Integer getReceiptStatus() { return receiptStatus; }
public void setReceiptStatus(Integer receiptStatus) { this.receiptStatus = receiptStatus; } public void setReceiptStatus(Integer receiptStatus) { this.receiptStatus = receiptStatus; }
public LocalDateTime getConfirmTime() { return confirmTime; } public LocalDateTime getConfirmTime() { return confirmTime; }

View File

@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fundplatform.receipt.dto.FundReceiptDTO; import com.fundplatform.receipt.dto.FundReceiptDTO;
import com.fundplatform.receipt.vo.FundReceiptVO; import com.fundplatform.receipt.vo.FundReceiptVO;
import java.util.List;
public interface FundReceiptService { public interface FundReceiptService {
Long createReceipt(FundReceiptDTO dto); Long createReceipt(FundReceiptDTO dto);
@ -14,6 +16,11 @@ public interface FundReceiptService {
Page<FundReceiptVO> pageReceipts(int pageNum, int pageSize, String title, Integer receiptType, Integer receiptStatus); Page<FundReceiptVO> pageReceipts(int pageNum, int pageSize, String title, Integer receiptType, Integer receiptStatus);
/**
* 根据应收款ID查询收款记录
*/
List<FundReceiptVO> getReceiptsByReceivableId(Long receivableId);
boolean deleteReceipt(Long id); boolean deleteReceipt(Long id);
boolean confirm(Long id); boolean confirm(Long id);

View File

@ -2,9 +2,11 @@ package com.fundplatform.receipt.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fundplatform.receipt.dto.ReceivableDTO; import com.fundplatform.receipt.dto.ReceivableDTO;
import com.fundplatform.receipt.vo.FundReceiptVO;
import com.fundplatform.receipt.vo.ReceivableVO; import com.fundplatform.receipt.vo.ReceivableVO;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List;
/** /**
* 应收款服务接口 * 应收款服务接口
@ -46,6 +48,11 @@ public interface ReceivableService {
*/ */
boolean recordReceipt(Long id, BigDecimal amount); boolean recordReceipt(Long id, BigDecimal amount);
/**
* 获取应收款的收款记录
*/
List<FundReceiptVO> getReceiptsByReceivableId(Long receivableId);
/** /**
* 更新逾期状态 * 更新逾期状态
*/ */

View File

@ -17,6 +17,7 @@ import org.springframework.util.StringUtils;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@Service @Service
@ -101,6 +102,15 @@ public class FundReceiptServiceImpl implements FundReceiptService {
return voPage; return voPage;
} }
@Override
public List<FundReceiptVO> getReceiptsByReceivableId(Long receivableId) {
LambdaQueryWrapper<FundReceipt> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(FundReceipt::getDeleted, 0);
wrapper.eq(FundReceipt::getReceivableId, receivableId);
wrapper.orderByDesc(FundReceipt::getCreatedTime);
return receiptDataService.list(wrapper).stream().map(this::convertToVO).toList();
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public boolean deleteReceipt(Long id) { public boolean deleteReceipt(Long id) {
@ -151,6 +161,7 @@ public class FundReceiptServiceImpl implements FundReceiptService {
vo.setPurpose(r.getPurpose()); vo.setPurpose(r.getPurpose());
vo.setProjectId(r.getProjectId()); vo.setProjectId(r.getProjectId());
vo.setCustomerId(r.getCustomerId()); vo.setCustomerId(r.getCustomerId());
vo.setReceivableId(r.getReceivableId());
vo.setReceiptStatus(r.getReceiptStatus()); vo.setReceiptStatus(r.getReceiptStatus());
vo.setReceiptStatusName(getReceiptStatusName(r.getReceiptStatus())); vo.setReceiptStatusName(getReceiptStatusName(r.getReceiptStatus()));
vo.setConfirmTime(r.getConfirmTime()); vo.setConfirmTime(r.getConfirmTime());

View File

@ -8,7 +8,9 @@ import com.fundplatform.common.context.UserContextHolder;
import com.fundplatform.receipt.data.entity.Receivable; import com.fundplatform.receipt.data.entity.Receivable;
import com.fundplatform.receipt.data.service.ReceivableDataService; import com.fundplatform.receipt.data.service.ReceivableDataService;
import com.fundplatform.receipt.dto.ReceivableDTO; import com.fundplatform.receipt.dto.ReceivableDTO;
import com.fundplatform.receipt.service.FundReceiptService;
import com.fundplatform.receipt.service.ReceivableService; import com.fundplatform.receipt.service.ReceivableService;
import com.fundplatform.receipt.vo.FundReceiptVO;
import com.fundplatform.receipt.vo.ReceivableVO; import com.fundplatform.receipt.vo.ReceivableVO;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -19,6 +21,7 @@ import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@Service @Service
@ -42,9 +45,11 @@ public class ReceivableServiceImpl implements ReceivableService {
private static final int CONFIRM_CONFIRMED = 1; private static final int CONFIRM_CONFIRMED = 1;
private final ReceivableDataService receivableDataService; private final ReceivableDataService receivableDataService;
private final FundReceiptService receiptService;
public ReceivableServiceImpl(ReceivableDataService receivableDataService) { public ReceivableServiceImpl(ReceivableDataService receivableDataService, FundReceiptService receiptService) {
this.receivableDataService = receivableDataService; this.receivableDataService = receivableDataService;
this.receiptService = receiptService;
} }
@Override @Override
@ -229,6 +234,11 @@ public class ReceivableServiceImpl implements ReceivableService {
return result; return result;
} }
@Override
public List<FundReceiptVO> getReceiptsByReceivableId(Long receivableId) {
return receiptService.getReceiptsByReceivableId(receivableId);
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateOverdueStatus() { public void updateOverdueStatus() {

View File

@ -19,6 +19,7 @@ public class FundReceiptVO {
private String purpose; private String purpose;
private Long projectId; private Long projectId;
private Long customerId; private Long customerId;
private Long receivableId;
private Integer receiptStatus; private Integer receiptStatus;
private String receiptStatusName; private String receiptStatusName;
private LocalDateTime confirmTime; private LocalDateTime confirmTime;
@ -60,6 +61,8 @@ public class FundReceiptVO {
public void setProjectId(Long projectId) { this.projectId = projectId; } public void setProjectId(Long projectId) { this.projectId = projectId; }
public Long getCustomerId() { return customerId; } public Long getCustomerId() { return customerId; }
public void setCustomerId(Long customerId) { this.customerId = customerId; } public void setCustomerId(Long customerId) { this.customerId = customerId; }
public Long getReceivableId() { return receivableId; }
public void setReceivableId(Long receivableId) { this.receivableId = receivableId; }
public Integer getReceiptStatus() { return receiptStatus; } public Integer getReceiptStatus() { return receiptStatus; }
public void setReceiptStatus(Integer receiptStatus) { this.receiptStatus = receiptStatus; } public void setReceiptStatus(Integer receiptStatus) { this.receiptStatus = receiptStatus; }
public String getReceiptStatusName() { return receiptStatusName; } public String getReceiptStatusName() { return receiptStatusName; }

View File

@ -35,6 +35,24 @@ public class AuthController {
return Result.success(vo); return Result.success(vo);
} }
/**
* 用户登出
*/
@PostMapping("/logout")
public Result<Void> logout(@RequestHeader(value = "X-User-Id", required = false) Long userId) {
authService.logout(userId);
return Result.success();
}
/**
* 刷新Token
*/
@PostMapping("/refresh")
public Result<LoginVO> refreshToken(@RequestHeader("X-User-Id") Long userId) {
LoginVO vo = authService.refreshToken(userId);
return Result.success(vo);
}
/** /**
* 获取当前用户信息 * 获取当前用户信息
*/ */

View File

@ -69,7 +69,19 @@ public class RoleController {
return Result.success(result); return Result.success(result);
} }
@PostMapping("/{id}/menus") /**
* 获取角色菜单ID列表
*/
@GetMapping("/{id}/menus")
public Result<List<Long>> getRoleMenus(@PathVariable Long id) {
List<Long> menuIds = roleService.getRoleMenus(id);
return Result.success(menuIds);
}
/**
* 分配菜单给角色
*/
@PutMapping("/{id}/menus")
public Result<Boolean> assignMenus(@PathVariable Long id, @RequestBody List<Long> menuIds) { public Result<Boolean> assignMenus(@PathVariable Long id, @RequestBody List<Long> menuIds) {
boolean result = roleService.assignMenus(id, menuIds); boolean result = roleService.assignMenus(id, menuIds);
return Result.success(result); return Result.success(result);

View File

@ -14,6 +14,16 @@ public interface AuthService {
*/ */
LoginVO login(LoginRequestDTO request); LoginVO login(LoginRequestDTO request);
/**
* 用户登出
*/
void logout(Long userId);
/**
* 刷新Token
*/
LoginVO refreshToken(Long userId);
/** /**
* 获取当前用户信息 * 获取当前用户信息
*/ */

View File

@ -46,6 +46,11 @@ public interface RoleService {
*/ */
boolean updateStatus(Long id, Integer status); boolean updateStatus(Long id, Integer status);
/**
* 获取角色菜单ID列表
*/
List<Long> getRoleMenus(Long roleId);
/** /**
* 分配菜单权限 * 分配菜单权限
*/ */

View File

@ -58,6 +58,30 @@ public class AuthServiceImpl implements AuthService {
return new LoginVO(user.getId(), user.getUsername(), token, user.getTenantId()); return new LoginVO(user.getId(), user.getUsername(), token, user.getTenantId());
} }
@Override
public void logout(Long userId) {
// TODO: 可以在此处清除用户的Token缓存或记录登出日志
// 目前JWT是无状态的登出只需前端清除Token即可
}
@Override
public LoginVO refreshToken(Long userId) {
SysUser user = userDataService.getById(userId);
if (user == null) {
throw new RuntimeException("用户不存在");
}
// 检查用户状态
if (user.getStatus() != 1) {
throw new RuntimeException("用户已被禁用");
}
// 生成新Token
String token = JwtUtil.generateToken(user.getId(), user.getUsername(), user.getTenantId());
return new LoginVO(user.getId(), user.getUsername(), token, user.getTenantId());
}
@Override @Override
public UserVO getUserInfo(Long userId) { public UserVO getUserInfo(Long userId) {
SysUser user = userDataService.getById(userId); SysUser user = userDataService.getById(userId);

View File

@ -144,6 +144,14 @@ public class RoleServiceImpl implements RoleService {
return result; return result;
} }
@Override
public List<Long> getRoleMenus(Long roleId) {
// TODO: 从sys_role_menu表查询角色关联的菜单ID
// 目前返回空列表
log.info("获取角色菜单: roleId={}", roleId);
return List.of();
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public boolean assignMenus(Long roleId, List<Long> menuIds) { public boolean assignMenus(Long roleId, List<Long> menuIds) {