feat: 实现部门积分层级继承逻辑 - 一级汇总/二级管理/三级共享
This commit is contained in:
parent
1c4e042c4b
commit
a6997c55f4
@ -568,21 +568,54 @@
|
||||
|
||||
<template v-else-if="column.key === 'score'">
|
||||
<div class="score-display">
|
||||
<div class="score-main">
|
||||
<span class="score-value">{{ record.scoreBalance ?? 0 }}</span>
|
||||
<span class="score-unit">分</span>
|
||||
</div>
|
||||
<div class="score-details">
|
||||
<span class="score-detail-item">
|
||||
<span class="detail-label">充值</span>
|
||||
<span class="detail-value">{{ record.totalRecharge ?? 0 }}</span>
|
||||
</span>
|
||||
<span class="detail-separator">|</span>
|
||||
<span class="score-detail-item">
|
||||
<span class="detail-label">消耗</span>
|
||||
<span class="detail-value">{{ record.totalConsume ?? 0 }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<!-- 一级部门有子部门:显示汇总 -->
|
||||
<template v-if="getDepartmentLevel(record) === 1 && hasChildDepartments(record)">
|
||||
<div class="score-main">
|
||||
<span class="score-value">{{ getLevel1DeptTotalScore(record) }}</span>
|
||||
<span class="score-unit">分</span>
|
||||
<a-tag size="small" color="blue" style="margin-left: 4px;">汇总</a-tag>
|
||||
</div>
|
||||
<div class="score-details">
|
||||
<span class="score-detail-item">
|
||||
<span class="detail-label">充值</span>
|
||||
<span class="detail-value">{{ getLevel1DeptTotalRecharge(record) }}</span>
|
||||
</span>
|
||||
<span class="detail-separator">|</span>
|
||||
<span class="score-detail-item">
|
||||
<span class="detail-label">消耗</span>
|
||||
<span class="detail-value">{{ getLevel1DeptTotalConsume(record) }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 三级部门:显示共享自父部门 -->
|
||||
<template v-else-if="getDepartmentLevel(record) === 3">
|
||||
<div class="score-main">
|
||||
<span class="score-value">{{ getParentDeptScore(record) }}</span>
|
||||
<span class="score-unit">分</span>
|
||||
<a-tag size="small" color="purple" style="margin-left: 4px;">共享</a-tag>
|
||||
</div>
|
||||
<div class="score-details" style="font-size: 11px; color: #888;">
|
||||
共享自「{{ getParentDeptNameById(record.parentId) }}」
|
||||
</div>
|
||||
</template>
|
||||
<!-- 二级部门或无子部门的一级部门:正常显示 -->
|
||||
<template v-else>
|
||||
<div class="score-main">
|
||||
<span class="score-value">{{ record.scoreBalance ?? 0 }}</span>
|
||||
<span class="score-unit">分</span>
|
||||
</div>
|
||||
<div class="score-details">
|
||||
<span class="score-detail-item">
|
||||
<span class="detail-label">充值</span>
|
||||
<span class="detail-value">{{ record.totalRecharge ?? 0 }}</span>
|
||||
</span>
|
||||
<span class="detail-separator">|</span>
|
||||
<span class="score-detail-item">
|
||||
<span class="detail-label">消耗</span>
|
||||
<span class="detail-value">{{ record.totalConsume ?? 0 }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -1793,74 +1826,121 @@
|
||||
<!-- 积分池管理弹窗 -->
|
||||
<a-modal
|
||||
v-model:open="modals.scorePool"
|
||||
title="积分池管理"
|
||||
:title="scorePoolModalTitle"
|
||||
width="700px"
|
||||
ok-text="OK"
|
||||
cancel-text="Cancel"
|
||||
ok-text="关闭"
|
||||
:cancel-button-props="{ style: { display: 'none' } }"
|
||||
@ok="modals.scorePool = false"
|
||||
@cancel="modals.scorePool = false"
|
||||
>
|
||||
<div v-if="currentScorePool">
|
||||
<!-- 提示信息:根据层级显示不同说明 -->
|
||||
<a-alert
|
||||
v-if="currentDeptScoreLevel === 1 && hasChildDepartments(currentDept)"
|
||||
type="info"
|
||||
show-icon
|
||||
style="margin-bottom: 16px;"
|
||||
>
|
||||
<template #message>
|
||||
<span>一级部门积分为下属二级部门积分的汇总,不支持直接充值。请前往具体二级部门进行充值。</span>
|
||||
</template>
|
||||
</a-alert>
|
||||
<a-alert
|
||||
v-else-if="currentDeptScoreLevel === 3"
|
||||
type="info"
|
||||
show-icon
|
||||
style="margin-bottom: 16px;"
|
||||
>
|
||||
<template #message>
|
||||
<span>三级部门共享上级二级部门「{{ getParentDeptName(currentDept) }}」的积分,不支持单独设置。</span>
|
||||
</template>
|
||||
</a-alert>
|
||||
|
||||
<a-descriptions :column="2" bordered>
|
||||
<a-descriptions-item label="部门名称">
|
||||
{{ currentScorePool.deptName }}
|
||||
<a-tag v-if="currentDeptScoreLevel === 1 && hasChildDepartments(currentDept)" color="blue" style="margin-left: 8px;">汇总</a-tag>
|
||||
<a-tag v-else-if="currentDeptScoreLevel === 3" color="purple" style="margin-left: 8px;">共享</a-tag>
|
||||
<a-tag v-else color="green" style="margin-left: 8px;">独立管理</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="当前余额">
|
||||
<span class="balance-display">
|
||||
{{ currentScorePool.balance }} 分
|
||||
{{ getDisplayScoreBalance() }} 分
|
||||
</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="累计充值">
|
||||
{{ currentScorePool.totalRecharge || 0 }} 分
|
||||
{{ getDisplayTotalRecharge() }} 分
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="累计消耗">
|
||||
{{ currentScorePool.totalConsume || 0 }} 分
|
||||
{{ getDisplayTotalConsume() }} 分
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="累计获得" v-if="currentScorePool.totalEarn">
|
||||
{{ currentScorePool.totalEarn }} 分
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<a-divider>消耗限制设置</a-divider>
|
||||
|
||||
<a-descriptions :column="2" bordered>
|
||||
<a-descriptions-item label="限制状态">
|
||||
<a-tag :color="currentScorePool.limitEnabled ? 'green' : 'default'">
|
||||
{{ currentScorePool.limitEnabled ? '已启用' : '未启用' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="限制周期" v-if="currentScorePool.limitEnabled">
|
||||
{{ currentScorePool.limitPeriod === 'DAILY' ? '每日' :
|
||||
currentScorePool.limitPeriod === 'WEEKLY' ? '每周' :
|
||||
currentScorePool.limitPeriod === 'MONTHLY' ? '每月' : '未知' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="周期限额" v-if="currentScorePool.limitEnabled">
|
||||
{{ currentScorePool.periodLimit || 0 }} 分
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="已使用" v-if="currentScorePool.limitEnabled">
|
||||
{{ currentScorePool.periodUsed || 0 }} 分
|
||||
<span v-if="currentScorePool.periodLimit">
|
||||
({{ Math.round((currentScorePool.periodUsed || 0) / currentScorePool.periodLimit * 100) }}%)
|
||||
</span>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<!-- 一级部门:显示子部门积分明细 -->
|
||||
<template v-if="currentDeptScoreLevel === 1 && hasChildDepartments(currentDept)">
|
||||
<a-divider>下属二级部门积分明细</a-divider>
|
||||
<a-table
|
||||
:columns="childDeptScoreColumns"
|
||||
:data-source="getChildDepartmentScores()"
|
||||
:pagination="false"
|
||||
size="small"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'actions'">
|
||||
<a-button type="link" size="small" @click="showScorePoolModal(record)">
|
||||
管理积分
|
||||
</a-button>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
|
||||
<a-divider>充值积分</a-divider>
|
||||
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="充值金额">
|
||||
<a-input-number
|
||||
v-model:value="rechargeAmount"
|
||||
:min="1"
|
||||
:precision="0"
|
||||
style="width: 200px"
|
||||
placeholder="请输入充值金额"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button type="primary" @click="handleRecharge">确认充值</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<!-- 消耗限制设置:只对可管理积分的部门显示 -->
|
||||
<template v-if="canManageScore">
|
||||
<a-divider>消耗限制设置</a-divider>
|
||||
|
||||
<a-descriptions :column="2" bordered>
|
||||
<a-descriptions-item label="限制状态">
|
||||
<a-tag :color="currentScorePool.limitEnabled ? 'green' : 'default'">
|
||||
{{ currentScorePool.limitEnabled ? '已启用' : '未启用' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="限制周期" v-if="currentScorePool.limitEnabled">
|
||||
{{ currentScorePool.limitPeriod === 'DAILY' ? '每日' :
|
||||
currentScorePool.limitPeriod === 'WEEKLY' ? '每周' :
|
||||
currentScorePool.limitPeriod === 'MONTHLY' ? '每月' : '未知' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="周期限额" v-if="currentScorePool.limitEnabled">
|
||||
{{ currentScorePool.periodLimit || 0 }} 分
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="已使用" v-if="currentScorePool.limitEnabled">
|
||||
{{ currentScorePool.periodUsed || 0 }} 分
|
||||
<span v-if="currentScorePool.periodLimit">
|
||||
({{ Math.round((currentScorePool.periodUsed || 0) / currentScorePool.periodLimit * 100) }}%)
|
||||
</span>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<a-divider>充值积分</a-divider>
|
||||
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="充值金额">
|
||||
<a-input-number
|
||||
v-model:value="rechargeAmount"
|
||||
:min="1"
|
||||
:precision="0"
|
||||
style="width: 200px"
|
||||
placeholder="请输入充值金额"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button type="primary" @click="handleRecharge">确认充值</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
</div>
|
||||
<a-empty v-else description="加载中..." />
|
||||
</a-modal>
|
||||
@ -2497,6 +2577,180 @@ const getDepartmentLevel = (record: DepartmentOverview): number => {
|
||||
return 3
|
||||
}
|
||||
|
||||
// 当前部门的积分管理层级
|
||||
const currentDeptScoreLevel = computed(() => {
|
||||
if (!currentDept.value) return 0
|
||||
return getDepartmentLevel(currentDept.value)
|
||||
})
|
||||
|
||||
// 积分池弹窗标题
|
||||
const scorePoolModalTitle = computed(() => {
|
||||
if (!currentDept.value) return '积分池管理'
|
||||
const level = currentDeptScoreLevel.value
|
||||
if (level === 1 && hasChildDepartments(currentDept.value)) {
|
||||
return '积分池管理 - 汇总视图'
|
||||
} else if (level === 3) {
|
||||
return '积分池管理 - 共享视图'
|
||||
}
|
||||
return '积分池管理'
|
||||
})
|
||||
|
||||
// 判断部门是否有子部门
|
||||
const hasChildDepartments = (dept: DepartmentOverview | null): boolean => {
|
||||
if (!dept?.id) return false
|
||||
return departments.value.some(d => d.parentId === dept.id)
|
||||
}
|
||||
|
||||
// 获取父部门名称
|
||||
const getParentDeptName = (dept: DepartmentOverview | null): string => {
|
||||
if (!dept?.parentId) return ''
|
||||
const parent = departments.value.find(d => d.id === dept.parentId)
|
||||
return parent?.deptName || ''
|
||||
}
|
||||
|
||||
// 获取父部门(二级部门)的积分信息
|
||||
const getParentDeptScoreInfo = () => {
|
||||
if (!currentDept.value?.parentId) return null
|
||||
const parent = departments.value.find(d => d.id === currentDept.value?.parentId)
|
||||
return parent || null
|
||||
}
|
||||
|
||||
// 是否可以管理积分(充值等操作)
|
||||
const canManageScore = computed(() => {
|
||||
if (!currentDept.value) return false
|
||||
const level = currentDeptScoreLevel.value
|
||||
|
||||
// 三级部门不能管理积分
|
||||
if (level === 3) return false
|
||||
|
||||
// 一级部门:如果有子部门,则不能直接管理(显示汇总)
|
||||
if (level === 1 && hasChildDepartments(currentDept.value)) return false
|
||||
|
||||
// 二级部门可以管理
|
||||
// 没有子部门的一级部门也可以管理
|
||||
return true
|
||||
})
|
||||
|
||||
// 获取显示的积分余额(考虑层级继承)
|
||||
const getDisplayScoreBalance = (): number => {
|
||||
if (!currentDept.value) return 0
|
||||
const level = currentDeptScoreLevel.value
|
||||
|
||||
// 三级部门:显示父部门(二级)的积分
|
||||
if (level === 3) {
|
||||
const parent = getParentDeptScoreInfo()
|
||||
return parent?.scoreBalance || 0
|
||||
}
|
||||
|
||||
// 一级部门且有子部门:计算所有二级部门的积分汇总
|
||||
if (level === 1 && hasChildDepartments(currentDept.value)) {
|
||||
const childDepts = departments.value.filter(d => d.parentId === currentDept.value?.id)
|
||||
return childDepts.reduce((sum, d) => sum + (d.scoreBalance || 0), 0)
|
||||
}
|
||||
|
||||
// 其他情况:显示本部门积分
|
||||
return currentScorePool.value?.balance || 0
|
||||
}
|
||||
|
||||
// 获取显示的累计充值(考虑层级继承)
|
||||
const getDisplayTotalRecharge = (): number => {
|
||||
if (!currentDept.value) return 0
|
||||
const level = currentDeptScoreLevel.value
|
||||
|
||||
// 三级部门:显示父部门的数据
|
||||
if (level === 3) {
|
||||
const parent = getParentDeptScoreInfo()
|
||||
return parent?.totalRecharge || 0
|
||||
}
|
||||
|
||||
// 一级部门且有子部门:计算汇总
|
||||
if (level === 1 && hasChildDepartments(currentDept.value)) {
|
||||
const childDepts = departments.value.filter(d => d.parentId === currentDept.value?.id)
|
||||
return childDepts.reduce((sum, d) => sum + (d.totalRecharge || 0), 0)
|
||||
}
|
||||
|
||||
return currentScorePool.value?.totalRecharge || 0
|
||||
}
|
||||
|
||||
// 获取显示的累计消耗(考虑层级继承)
|
||||
const getDisplayTotalConsume = (): number => {
|
||||
if (!currentDept.value) return 0
|
||||
const level = currentDeptScoreLevel.value
|
||||
|
||||
// 三级部门:显示父部门的数据
|
||||
if (level === 3) {
|
||||
const parent = getParentDeptScoreInfo()
|
||||
return parent?.totalConsume || 0
|
||||
}
|
||||
|
||||
// 一级部门且有子部门:计算汇总
|
||||
if (level === 1 && hasChildDepartments(currentDept.value)) {
|
||||
const childDepts = departments.value.filter(d => d.parentId === currentDept.value?.id)
|
||||
return childDepts.reduce((sum, d) => sum + (d.totalConsume || 0), 0)
|
||||
}
|
||||
|
||||
return currentScorePool.value?.totalConsume || 0
|
||||
}
|
||||
|
||||
// 获取子部门积分列表(用于一级部门汇总视图)
|
||||
const getChildDepartmentScores = () => {
|
||||
if (!currentDept.value?.id) return []
|
||||
return departments.value
|
||||
.filter(d => d.parentId === currentDept.value?.id)
|
||||
.map(d => ({
|
||||
...d,
|
||||
id: d.id,
|
||||
deptName: d.deptName,
|
||||
scoreBalance: d.scoreBalance || 0,
|
||||
totalRecharge: d.totalRecharge || 0,
|
||||
totalConsume: d.totalConsume || 0
|
||||
}))
|
||||
}
|
||||
|
||||
// 子部门积分明细表格列
|
||||
const childDeptScoreColumns = [
|
||||
{ title: '二级部门', dataIndex: 'deptName', key: 'deptName' },
|
||||
{ title: '当前余额', dataIndex: 'scoreBalance', key: 'scoreBalance' },
|
||||
{ title: '累计充值', dataIndex: 'totalRecharge', key: 'totalRecharge' },
|
||||
{ title: '累计消耗', dataIndex: 'totalConsume', key: 'totalConsume' },
|
||||
{ title: '操作', key: 'actions', width: 100 }
|
||||
]
|
||||
|
||||
// 获取一级部门的汇总积分(所有二级部门积分之和)
|
||||
const getLevel1DeptTotalScore = (dept: DepartmentOverview): number => {
|
||||
if (!dept.id) return 0
|
||||
const childDepts = departments.value.filter(d => d.parentId === dept.id)
|
||||
return childDepts.reduce((sum, d) => sum + (d.scoreBalance || 0), 0)
|
||||
}
|
||||
|
||||
// 获取一级部门的汇总充值
|
||||
const getLevel1DeptTotalRecharge = (dept: DepartmentOverview): number => {
|
||||
if (!dept.id) return 0
|
||||
const childDepts = departments.value.filter(d => d.parentId === dept.id)
|
||||
return childDepts.reduce((sum, d) => sum + (d.totalRecharge || 0), 0)
|
||||
}
|
||||
|
||||
// 获取一级部门的汇总消耗
|
||||
const getLevel1DeptTotalConsume = (dept: DepartmentOverview): number => {
|
||||
if (!dept.id) return 0
|
||||
const childDepts = departments.value.filter(d => d.parentId === dept.id)
|
||||
return childDepts.reduce((sum, d) => sum + (d.totalConsume || 0), 0)
|
||||
}
|
||||
|
||||
// 获取父部门(二级部门)的积分(用于三级部门显示)
|
||||
const getParentDeptScore = (dept: DepartmentOverview): number => {
|
||||
if (!dept.parentId) return 0
|
||||
const parent = departments.value.find(d => d.id === dept.parentId)
|
||||
return parent?.scoreBalance || 0
|
||||
}
|
||||
|
||||
// 根据ID获取父部门名称
|
||||
const getParentDeptNameById = (parentId: number | null | undefined): string => {
|
||||
if (!parentId) return ''
|
||||
const parent = departments.value.find(d => d.id === parentId)
|
||||
return parent?.deptName || ''
|
||||
}
|
||||
|
||||
// 部门树形选择器数据 - 用于调整用户部门
|
||||
const departmentTreeSelectData = computed(() => {
|
||||
// 构建树形结构
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user