feat(web-admin): gate archive actions and price columns by menu codes

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-09-03 16:34:49 +08:00
1 parent af0ae031a5
commit b92418fa4a
1 file changed
+48 -7
+48 -7
View File
@@ -88,6 +88,7 @@
@clear="handleQuickSearchClear"
/>
<el-button
v-if="canArchive"
class="btn-main"
type="primary"
:disabled="!selectedPlan || selectedPlan.followStatus === 'cancelled'"
@@ -503,7 +504,7 @@
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('productUnitPrice')"
v-if="isArchiveColumnVisible('productUnitPrice')"
label="单价(元)"
min-width="100"
align="right"
@@ -522,7 +523,7 @@
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('productAmount')"
v-if="isArchiveColumnVisible('productAmount')"
label="金额(元)"
min-width="100"
align="right"
@@ -576,10 +577,11 @@
v-model:visible="viewVisible"
:plan-id="viewPlanId"
show-archive-io-fields
:show-archive-price-fields="canViewPrice"
>
<template v-if="viewingPlan" #hero-actions>
<el-button
v-if="viewingPlan.followStatus !== 'cancelled'"
v-if="canArchive && viewingPlan.followStatus !== 'cancelled'"
class="btn-main"
type="primary"
@click="handleArchive(viewingPlan)"
@@ -617,6 +619,7 @@ import {
Search
} from '@element-plus/icons-vue'
import { planApi, type Plan } from '@/api/pl'
import { fetchGetMenuCodes } from '@/api/auth'
import { pickBxData } from '@/utils/http/bx'
import PlPlanContractCell from '@/components/business/pl-plan-contract-cell/index.vue'
import PlPlanArchiveDialog from '@/components/business/pl-plan-archive-dialog/index.vue'
@@ -677,6 +680,8 @@ const PLAN_MERGE_COLUMN_PROPS = [
] as const
const loading = ref(false)
const canArchive = ref(false)
const canViewPrice = ref(false)
const viewVisible = ref(false)
const viewPlanId = ref('')
const viewDialogRef = ref<InstanceType<typeof PlPlanViewDialog>>()
@@ -685,7 +690,9 @@ const archivePlanId = ref('')
const erpBatchLoading = ref(false)
const planList = ref<Plan[]>([])
const listColumnDefs = [
const PRICE_COLUMN_PROPS = new Set(['productUnitPrice', 'productAmount'])
const allListColumnDefs = [
{ prop: 'planDate', label: '计划日期' },
{ prop: 'archiveStatus', label: '归档状态' },
{ prop: 'followStatus', label: '跟进状态' },
@@ -712,13 +719,42 @@ const listColumnDefs = [
{ prop: 'productAmount', label: '金额(元)' }
]
const listColumnDefs = computed(() =>
canViewPrice.value
? allListColumnDefs
: allListColumnDefs.filter((def) => !PRICE_COLUMN_PROPS.has(def.prop))
)
const {
visibleColumns,
checkAll,
isIndeterminate,
isColumnVisible,
resetToDefault
} = usePersistedListColumns('pl-plan-archive-list-columns-v5', listColumnDefs)
} = usePersistedListColumns('pl-plan-archive-list-columns-v6', allListColumnDefs)
function isArchiveColumnVisible(prop: string) {
if (PRICE_COLUMN_PROPS.has(prop) && !canViewPrice.value) return false
return isColumnVisible(prop)
}
watch(canViewPrice, (ok) => {
if (ok) return
visibleColumns.value = visibleColumns.value.filter((prop) => !PRICE_COLUMN_PROPS.has(prop))
})
async function loadArchivePermissions() {
try {
const perm = await fetchGetMenuCodes()
const all = !!perm?.all || !!perm?.isSuperAdmin
const codes = perm?.menuCodes || []
canArchive.value = all || codes.includes('pl:plan-archive:archive')
canViewPrice.value = all || codes.includes('pl:plan-archive:price')
} catch {
canArchive.value = false
canViewPrice.value = false
}
}
const selectedRows = ref<Plan[]>([])
@@ -754,8 +790,8 @@ const archiveStatsRowColumns = computed((): StatsRowColumn[] => {
{ key: '__index', interactive: false },
{ key: 'planNo', interactive: true, prop: 'planNo' }
]
for (const def of listColumnDefs) {
if (!isColumnVisible(def.prop)) continue
for (const def of listColumnDefs.value) {
if (!isArchiveColumnVisible(def.prop)) continue
cols.push({
key: def.prop,
interactive: def.prop !== 'stopKind',
@@ -975,6 +1011,10 @@ function archiveButtonLabel(row: Plan) {
}
async function handleArchive(row: Plan) {
if (!canArchive.value) {
ElMessage.warning('无运输计划归档操作权限')
return
}
// 打开归档弹窗:已归档走调整;未归档/已暂存可直接打开(证书齐备仅在「确认归档」时校验,以便支持暂存)
archivePlanId.value = row.id
archiveDialogVisible.value = true
@@ -1048,6 +1088,7 @@ useDbInstantSearch(
)
onMounted(() => {
loadArchivePermissions()
fetchData()
nextTick(() => recalcTableHeight())