From 98eae634352c801b9ec4afad1218aefb63d1f9a1 Mon Sep 17 00:00:00 2001 From: gin Date: Wed, 27 May 2026 20:29:27 +0800 Subject: [PATCH] feat: show collaboration record creators --- .../CollaborationRecordController.java | 5 +- ...CollaborationRecordApplicationService.java | 75 ++++++++++++++----- .../record/dto/CollaborationRecordDTO.java | 4 + .../query/CollaborationRecordQuery.java | 3 + frontend/web/src/api/collaboration/record.ts | 14 +++- .../src/views/collaboration/record/index.vue | 19 +++++ .../views/collaboration/record/utils/hook.tsx | 30 +++++++- .../views/collaboration/statistics/index.vue | 59 +++++++++++---- .../collaboration/statistics/utils/hook.ts | 37 +++++++-- 9 files changed, 203 insertions(+), 43 deletions(-) diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/collaboration/CollaborationRecordController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/collaboration/CollaborationRecordController.java index 44127c0..b0b4ee3 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/collaboration/CollaborationRecordController.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/collaboration/CollaborationRecordController.java @@ -70,8 +70,9 @@ public class CollaborationRecordController extends BaseController { @Operation(summary = "合作记录月度统计") @PreAuthorize("@permission.has('collaboration:record:statistics')") @GetMapping("/monthly-statistics") - public ResponseDTO> monthlyStatistics(@RequestParam Integer year) { - return ResponseDTO.ok(recordApplicationService.getMonthlyStatistics(year)); + public ResponseDTO> monthlyStatistics( + @RequestParam Integer year, @RequestParam(required = false) Long creatorId) { + return ResponseDTO.ok(recordApplicationService.getMonthlyStatistics(year, creatorId)); } @Operation(summary = "新增合作记录") diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/CollaborationRecordApplicationService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/CollaborationRecordApplicationService.java index 36b435c..4246acc 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/CollaborationRecordApplicationService.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/CollaborationRecordApplicationService.java @@ -34,7 +34,9 @@ import com.agileboot.domain.collaboration.record.enumtype.SettlementStatusEnum; import com.agileboot.domain.collaboration.record.model.CollaborationRecordModel; import com.agileboot.domain.collaboration.record.model.CollaborationRecordModelFactory; import com.agileboot.domain.collaboration.record.query.CollaborationRecordQuery; +import com.agileboot.domain.common.cache.CacheCenter; import com.agileboot.domain.common.command.BulkOperationCommand; +import com.agileboot.domain.system.user.db.SysUserEntity; import com.agileboot.infrastructure.user.AuthenticationUtils; import com.agileboot.infrastructure.user.web.SystemLoginUser; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -130,17 +132,21 @@ public class CollaborationRecordApplicationService { .collect(Collectors.toList()); } - public List getMonthlyStatistics(Integer year) { + public List getMonthlyStatistics(Integer year, Long creatorId) { List statistics = new ArrayList<>(); for (int month = 1; month <= 12; month++) { - statistics.add(buildMonthlyStatistics(year, month)); + statistics.add(buildMonthlyStatistics(year, month, creatorId)); } return statistics; } + public List getMonthlyStatistics(Integer year) { + return getMonthlyStatistics(year, null); + } + private QueryWrapper getScopedRecordWrapper(CollaborationRecordQuery query) { + applyQueryCreatorScope(query); QueryWrapper wrapper = query.toQueryWrapper(); - applyCurrentCreatorScope(wrapper); return wrapper; } @@ -235,6 +241,13 @@ public class CollaborationRecordApplicationService { } } + private void applyQueryCreatorScope(CollaborationRecordQuery query) { + Long creatorId = getCurrentCreatorScope(); + if (creatorId != null) { + query.setCreatorId(creatorId); + } + } + private Long getCurrentCreatorScope() { SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser(); return loginUser.isAdmin() ? null : loginUser.getUserId(); @@ -242,10 +255,22 @@ public class CollaborationRecordApplicationService { private CollaborationRecordDTO buildRecordDTO(CollaborationRecordEntity entity) { CollaborationRecordDTO dto = new CollaborationRecordDTO(entity); + dto.setCreatorName(getCreatorName(entity.getCreatorId())); fillRecordStats(dto, entity.getRecordId()); return dto; } + private String getCreatorName(Long creatorId) { + if (creatorId == null) { + return ""; + } + SysUserEntity user = CacheCenter.userCache.getObjectById(creatorId); + if (user == null) { + return ""; + } + return StrUtil.blankToDefault(user.getNickname(), user.getUsername()); + } + private void fillDetailChildren(CollaborationRecordDetailDTO dto, Long recordId) { dto.setTasks(taskService.listByRecordId(recordId).stream() .map(CollaborationTaskDTO::new) @@ -454,21 +479,21 @@ public class CollaborationRecordApplicationService { return entity; } - private CollaborationMonthlyStatisticsDTO buildMonthlyStatistics(Integer year, Integer month) { + private CollaborationMonthlyStatisticsDTO buildMonthlyStatistics(Integer year, Integer month, Long creatorId) { Date[] range = getMonthRange(year, month); - BigDecimal purchasePrice = sumPurchasePrice(range); - BigDecimal expenditureAmount = sumExpenditure(range); - BigDecimal settledRemuneration = sumSettlement(range, REMUNERATION_FEE); - BigDecimal settledTotal = sumSettlement(range, null); + BigDecimal purchasePrice = sumPurchasePrice(range, creatorId); + BigDecimal expenditureAmount = sumExpenditure(range, creatorId); + BigDecimal settledRemuneration = sumSettlement(range, REMUNERATION_FEE, creatorId); + BigDecimal settledTotal = sumSettlement(range, null, creatorId); return new CollaborationMonthlyStatisticsDTO(month, purchasePrice, expenditureAmount, settledRemuneration, settledTotal); } - private BigDecimal sumPurchasePrice(Date[] range) { + private BigDecimal sumPurchasePrice(Date[] range, Long creatorId) { QueryWrapper wrapper = new QueryWrapper() .ge("purchase_date", range[0]) .le("purchase_date", range[1]); - applyCurrentCreatorScope(wrapper); + applyCreatorScope(wrapper, creatorId); List records = recordService.list(wrapper); return records.stream() .map(CollaborationRecordEntity::getPurchasePrice) @@ -476,11 +501,11 @@ public class CollaborationRecordApplicationService { .reduce(BigDecimal.ZERO, BigDecimal::add); } - private BigDecimal sumExpenditure(Date[] range) { + private BigDecimal sumExpenditure(Date[] range, Long creatorId) { QueryWrapper wrapper = new QueryWrapper() .ge("spend_date", range[0]) .le("spend_date", range[1]); - applyChildRecordScope(wrapper); + applyChildRecordScope(wrapper, creatorId); List expenditures = expenditureService.list(wrapper); return expenditures.stream() .map(CollaborationExpenditureEntity::getAmount) @@ -488,20 +513,34 @@ public class CollaborationRecordApplicationService { .reduce(BigDecimal.ZERO, BigDecimal::add); } - private BigDecimal sumSettlement(Date[] range, String purpose) { + private BigDecimal sumSettlement(Date[] range, String purpose, Long creatorId) { QueryWrapper wrapper = new QueryWrapper() .ge("settle_date", range[0]) .le("settle_date", range[1]) .eq(purpose != null, "purpose", purpose); - applyChildRecordScope(wrapper); + applyChildRecordScope(wrapper, creatorId); return sumSettlement(settlementService.list(wrapper)); } - private void applyChildRecordScope(QueryWrapper wrapper) { - Long creatorId = getCurrentCreatorScope(); - if (creatorId != null) { - wrapper.inSql("record_id", buildCreatorRecordSubQuery(creatorId)); + private void applyChildRecordScope(QueryWrapper wrapper, Long requestedCreatorId) { + Long creatorId = getEffectiveCreatorScope(requestedCreatorId); + if (creatorId == null) { + return; } + wrapper.inSql("record_id", buildCreatorRecordSubQuery(creatorId)); + } + + private void applyCreatorScope(QueryWrapper wrapper, Long requestedCreatorId) { + Long creatorId = getEffectiveCreatorScope(requestedCreatorId); + if (creatorId == null) { + return; + } + wrapper.eq("creator_id", creatorId); + } + + private Long getEffectiveCreatorScope(Long requestedCreatorId) { + Long currentCreatorScope = getCurrentCreatorScope(); + return currentCreatorScope == null ? requestedCreatorId : currentCreatorScope; } private String buildCreatorRecordSubQuery(Long creatorId) { diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/dto/CollaborationRecordDTO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/dto/CollaborationRecordDTO.java index 59db750..a15b087 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/dto/CollaborationRecordDTO.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/dto/CollaborationRecordDTO.java @@ -56,6 +56,10 @@ public class CollaborationRecordDTO { private String remark; + private Long creatorId; + + private String creatorName; + private Integer tasksNum; private Integer completedTasksNum; diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/query/CollaborationRecordQuery.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/query/CollaborationRecordQuery.java index d93e510..7fe23eb 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/query/CollaborationRecordQuery.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/query/CollaborationRecordQuery.java @@ -27,6 +27,8 @@ public class CollaborationRecordQuery extends AbstractPageQuery { ); }; -export const getCollaborationMonthlyStatisticsApi = (year: number) => { +export interface CollaborationMonthlyStatisticsCommand { + year: number; + creatorId?: number; +} + +export const getCollaborationMonthlyStatisticsApi = ( + params: CollaborationMonthlyStatisticsCommand +) => { return http.request>( "get", "/collaboration/record/monthly-statistics", { - params: { year } + params } ); }; diff --git a/frontend/web/src/views/collaboration/record/index.vue b/frontend/web/src/views/collaboration/record/index.vue index 5454c4d..da2727c 100644 --- a/frontend/web/src/views/collaboration/record/index.vue +++ b/frontend/web/src/views/collaboration/record/index.vue @@ -30,6 +30,9 @@ const { deadlineRange, purchaseRange, optionMap, + creatorOptions, + isAdmin, + getUserDisplayName, multipleSelection, onSearch, onSortChanged, @@ -93,6 +96,22 @@ function openDialog( class="!w-[180px]" /> + + + + + userStore.roles?.includes("admin")); + const defaultSort: Sort = { prop: "deadline", order: "descending" @@ -36,6 +45,7 @@ export function useCollaborationRecordHook() { const searchFormParams = reactive({ brand: "", goods: "", + creatorId: undefined, cooperationPlatform: undefined }); @@ -55,6 +65,7 @@ export function useCollaborationRecordHook() { const dataList = ref([]); const optionMap = ref>({}); + const creatorOptions = ref([]); const pageLoading = ref(true); const multipleSelection = ref([]); const sortState = ref(defaultSort); @@ -63,6 +74,12 @@ export function useCollaborationRecordHook() { { type: "selection", align: "left" }, { label: "品牌", prop: "brand", minWidth: 120 }, { label: "物品", prop: "goods", minWidth: 120 }, + { + label: "创建者", + prop: "creatorName", + minWidth: 110, + hide: !isAdmin.value + }, { label: "合作平台", prop: "cooperationPlatform", minWidth: 110 }, { label: "留存方式", prop: "retainedMethod", minWidth: 100 }, { label: "购入方式", prop: "purchaseMethod", minWidth: 100 }, @@ -126,8 +143,9 @@ export function useCollaborationRecordHook() { function renderStatus(status, size) { if (!status) return ""; + const type = statusTypeMap[status.status] || "info"; return ( - + {status.label} ); @@ -195,6 +213,12 @@ export function useCollaborationRecordHook() { ); } + async function getCreatorOptions() { + if (!isAdmin.value) return; + const { data } = await getUserListApi({ pageNum: 1, pageSize: 1000 }); + creatorOptions.value = data.rows; + } + async function handleDelete(row: CollaborationRecordPageResponse) { await deleteCollaborationRecordApi([row.recordId]); message(`您删除了编号为${row.recordId}的合作记录`, { type: "success" }); @@ -237,6 +261,7 @@ export function useCollaborationRecordHook() { onMounted(() => { getOptions(); + getCreatorOptions(); getRecordList(); }); @@ -250,6 +275,9 @@ export function useCollaborationRecordHook() { deadlineRange, purchaseRange, optionMap, + creatorOptions, + isAdmin, + getUserDisplayName, multipleSelection, onSearch, onSortChanged, diff --git a/frontend/web/src/views/collaboration/statistics/index.vue b/frontend/web/src/views/collaboration/statistics/index.vue index 37e7264..1384d53 100644 --- a/frontend/web/src/views/collaboration/statistics/index.vue +++ b/frontend/web/src/views/collaboration/statistics/index.vue @@ -5,8 +5,16 @@ defineOptions({ name: "CollaborationStatistics" }); -const { chartRef, selectedYear, yearOptions, getStatistics } = - useCollaborationStatisticsHook(); +const { + chartRef, + selectedYear, + selectedCreatorId, + yearOptions, + creatorOptions, + isAdmin, + getUserDisplayName, + getStatistics +} = useCollaborationStatisticsHook();