修复商品分类树名称展示

This commit is contained in:
czl231
2026-08-15 23:47:33 +08:00
parent cc14cb9f62
commit 0b6e7b0598
5 changed files with 160 additions and 17 deletions

View File

@@ -1,6 +1,6 @@
/**
* 功能描述校验平台48类资源均具备中文展示字段并防止列表、详情退回数据库ID或动态英文列。
* 版本v1.0.0
* 版本v1.2.1
*/
import fs from 'node:fs';
import path from 'node:path';
@@ -23,6 +23,8 @@ const display = read('src/api/resource-display.ts');
const detailContract = read('src/api/resource-detail-contract.ts');
const detailPage = read('src/views/resource/ResourceDetailContent.vue');
const listPage = read('src/views/shared/CrudListPage.vue');
const treePage = read('src/views/shared/TreePage.vue');
const identityText = read('src/components/IdentityText.vue');
const resourceNames = [...resources.matchAll(/\bdefine\('([^']+)'/g)].map(
(match) => match[1],
@@ -81,6 +83,37 @@ if (/title="ID"|data-index="id"/.test(listPage)) {
throw new Error('标准资源列表不得把数据库ID作为业务列展示');
}
assertIncludes(listPage, 'title="系统唯一标识"', '列表必须中文标注系统唯一标识');
assertIncludes(
treePage,
'<a-table',
'树形资源必须使用带明确列标题的树形表格',
);
assertIncludes(
treePage,
'<template #columns>',
'Arco 树形表格列必须放入 columns 插槽,避免运行时渲染为空白',
);
for (const columnTitle of ['分类名称', '排序', '状态', '系统标识', '操作']) {
assertIncludes(treePage, columnTitle, `树形表格缺少必要列:${columnTitle}`);
}
assertIncludes(
treePage,
'{{ record.name }}',
'树形表格必须以接口返回的中文业务名称作为主标题',
);
assertIncludes(
treePage,
'display-text="复制标识"',
'树形表格不得把截断唯一标识作为高优先级正文',
);
assertIncludes(
identityText,
'displayText?: string',
'唯一标识组件必须保留可选的低优先级复制文案能力',
);
if (treePage.includes('node.title')) {
throw new Error('树节点不得读取标题插槽中不存在的 title 字段');
}
assertIncludes(
listPage,
'class="resource-table-shell"',

View File

@@ -1,8 +1,8 @@
<!-- 功能描述紧凑展示资源唯一标识并支持点击复制完整值版本v1.1.0 -->
<!-- 功能描述紧凑展示资源唯一标识或复制入口并支持点击复制完整值版本v1.2.0 -->
<template>
<a-tooltip :content="`${value}\n点击复制完整唯一标识`">
<button class="identity-text" type="button" :aria-label="`复制完整唯一标识 ${value}`" @click="copyIdentity">
{{ shortValue }}
{{ displayText ?? shortValue }}
</button>
</a-tooltip>
</template>
@@ -11,7 +11,7 @@
import { Message } from '@arco-design/web-vue';
import { computed } from 'vue';
const props = defineProps<{ value: string }>();
const props = defineProps<{ value: string; displayText?: string }>();
const shortValue = computed(() => props.value.slice(-12));
async function copyIdentity() {

View File

@@ -1,3 +1,4 @@
<!-- 功能描述使用树形表格展示和维护层级资源中文业务名称优先系统唯一标识次要展示版本v1.2.1 -->
<template>
<a-card :title="definition.title" :bordered="false">
<template #extra>
@@ -6,20 +7,54 @@
<a-button v-if="canCreate" type="primary" @click="openCreate">新增</a-button>
</a-space>
</template>
<a-tree :data="tree" :loading="loading" :field-names="{ key: 'identity', title: 'name', children: 'children' }">
<template #title="node">
<a-space>
<span>{{ node.title }}</span>
<span v-if="node.group_code || node.path" class="tree-business-key">
{{ node.group_code || node.path }}
</span>
<IdentityText :value="String(node.identity)" />
<a-button v-if="canEdit" size="mini" @click.stop="openEdit(node)">编辑</a-button>
<a-button v-if="canChangeStatus" size="mini" @click.stop="confirmStatus(node)">{{ node.status === 1 ? '停用' : '启用' }}</a-button>
<a-button v-if="canArchive" size="mini" status="danger" @click.stop="confirmArchive(node)">归档</a-button>
</a-space>
<a-table
class="tree-table"
:data="tree"
:loading="loading"
:pagination="false"
row-key="identity"
default-expand-all-rows
hide-expand-button-on-empty
>
<template #columns>
<a-table-column :title="nameColumnTitle" data-index="name" :width="360">
<template #cell="{ record }">
<div class="tree-name-cell">
<span class="tree-name">{{ record.name }}</span>
<span v-if="record.group_code || record.path" class="tree-business-key">
{{ record.group_code || record.path }}
</span>
</div>
</template>
</a-table-column>
<a-table-column title="排序" data-index="sort_no" :width="90" align="center">
<template #cell="{ record }">{{ record.sort_no ?? '-' }}</template>
</a-table-column>
<a-table-column title="状态" data-index="status" :width="100">
<template #cell="{ record }">
<a-tag :color="statusColor(Number(record.status))">
{{ recordStatusLabel(Number(record.status)) }}
</a-tag>
</template>
</a-table-column>
<a-table-column title="系统标识" :width="120">
<template #cell="{ record }">
<IdentityText :value="String(record.identity)" display-text="复制标识" />
</template>
</a-table-column>
<a-table-column v-if="canEdit || canChangeStatus || canArchive" title="操作" :width="230" fixed="right">
<template #cell="{ record }">
<a-space>
<a-button v-if="canEdit" size="mini" @click="openEdit(record)">编辑</a-button>
<a-button v-if="canChangeStatus" size="mini" @click="confirmStatus(record)">
{{ record.status === 1 ? '停用' : '启用' }}
</a-button>
<a-button v-if="canArchive" size="mini" status="danger" @click="confirmArchive(record)">归档</a-button>
</a-space>
</template>
</a-table-column>
</template>
</a-tree>
</a-table>
</a-card>
<a-drawer :visible="formVisible" :title="editingIdentity ? `编辑${definition.title}` : `新增${definition.title}`" :width="480" @cancel="formVisible = false" @ok="save">
<a-form :model="form" layout="vertical">
@@ -41,6 +76,7 @@
import { Message, Modal } from '@arco-design/web-vue';
import { computed, onMounted, reactive, ref } from 'vue';
import { resourceApi } from '@/api/resource';
import { recordStatusLabel } from '@/api/resource-display';
import { buildResourcePayload, isMissingField } from '@/api/resource-form';
import type { ResourceUiDefinition } from '@/api/resources';
import { useUserStore } from '@/store';
@@ -71,6 +107,9 @@ const canChangeStatus = computed(
const canArchive = computed(
() => props.definition.canArchive && rootAllowed.value,
);
const nameColumnTitle = computed(() =>
props.definition.name === 'ec_category' ? '分类名称' : '菜单名称',
);
const tree = computed(() => {
const byIdentity = new Map<string, Node>();
const roots: Node[] = [];
@@ -94,6 +133,13 @@ const tree = computed(() => {
return roots;
});
/** 返回树形表格状态标签颜色,名称仍由统一状态字典提供。 */
function statusColor(status: number) {
if (status === 1) return 'green';
if (status === 2) return 'orange';
return 'gray';
}
function reset(data?: Node) {
for (const field of props.definition.fields) {
const value = data?.[field.key];
@@ -192,7 +238,23 @@ onMounted(load);
</script>
<style scoped>
.tree-table {
width: 100%;
}
.tree-name-cell {
display: flex;
gap: 10px;
align-items: center;
min-width: 0;
}
.tree-name {
overflow: hidden;
font-weight: 500;
text-overflow: ellipsis;
white-space: nowrap;
}
.tree-business-key {
flex: none;
color: var(--color-text-3);
font-size: 12px;
}