From 877b184de1d8660b34e824c7d3f4661484397844 Mon Sep 17 00:00:00 2001 From: czl231 <3286836406@qq.com> Date: Mon, 17 Aug 2026 19:48:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=AE=A2=E6=9C=8D=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=E8=AF=A6=E6=83=85=E7=A9=BA=E7=8A=B6=E6=80=81=E4=B8=8E?= =?UTF-8?q?=E5=85=B3=E8=81=94=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ..._客服工单详情空状态与关联展示修复_20260817.md | 47 +++++++++++++++++++ docs/项目文档_平台资源中文展示统一_v1.0.md | 1 + .../check-resource-display-contracts.mjs | 13 +++++ .../src/api/resource-page-rules.ts | 13 +++++ frontend/platform_admin/src/api/resources.ts | 24 ++++++++++ .../shared/resource-list-field-display.ts | 7 ++- 6 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 docs/操作日志_客服工单详情空状态与关联展示修复_20260817.md diff --git a/docs/操作日志_客服工单详情空状态与关联展示修复_20260817.md b/docs/操作日志_客服工单详情空状态与关联展示修复_20260817.md new file mode 100644 index 0000000..b9e91fb --- /dev/null +++ b/docs/操作日志_客服工单详情空状态与关联展示修复_20260817.md @@ -0,0 +1,47 @@ +# 客服工单详情空状态与关联展示修复操作日志 + +操作时间:2026-08-17 +操作类型:修改 +影响模块:平台总后台 / 客服管理 / 客服工单详情 + +## 操作前状态 + +- 待受理工单的配送点、处理人员、服务气站、开始时间、完成时间和处理结果统一显示 `-`,无法区分未分派、未开始和未完成等业务阶段。 +- 配送点、气站和工作人员使用技术标识字段名,存在值时不能优先展示业务名称。 +- 问题描述、请求流水号和最近操作记录缺失时缺少明确说明。 + +## 具体操作 + +- 配送点、处理人员和服务气站改为只在详情使用的关系字段,优先展示关联名称并保留唯一标识复制。 +- 处理人员关系显式允许安装、配送和运维三类工单执行人员,满足工作人员关系加载器的安全过滤要求。 +- 为未分派、未关联、未预约、未开始、未完成及未提交处理结果设置独立中文空状态。 +- 增加 `listHidden` 字段能力,详情辅助字段不扩张原有客服工单列表列数。 +- 新增详情字段从客服工单新建页面隐藏,编辑协议仍只提交原有四个允许字段。 +- 增加静态展示契约,防止空状态重新退化为裸占位符。 + +## 操作后状态 + +- 待受理工单详情能准确表达当前处理阶段。 +- 原列表结构、新建字段、编辑字段及后端接口保持不变。 + +## 代码变更 + +- `frontend/platform_admin/src/api/resources.ts`:补充客服工单详情关系字段及业务空状态。 +- `frontend/platform_admin/src/views/shared/resource-list-field-display.ts`:支持详情专用字段从列表隐藏。 +- `frontend/platform_admin/src/api/resource-page-rules.ts`:隐藏新建页面中的流程只读字段。 +- `frontend/platform_admin/scripts/check-resource-display-contracts.mjs`:增加客服工单详情空状态契约。 +- `docs/项目文档_平台资源中文展示统一_v1.0.md`:增加 v1.19 变更记录。 + +## 验证结果 + +- 资源展示契约检查通过:`pnpm resource-display-contracts:check`。 +- 后端接口契约检查通过:`pnpm contract:check`。 +- Biome 代码检查通过:`pnpm exec biome lint src/api/resources.ts src/api/resource-page-rules.ts src/views/shared/resource-list-field-display.ts scripts/check-resource-display-contracts.mjs`。 +- TypeScript 类型检查通过:`pnpm type:check`。 +- 前端生产构建通过:`pnpm build`。 +- 本地浏览器已确认应用可访问且无启动错误;独立测试浏览器未复用用户外部浏览器登录态,因此详情真实数据渲染仍需在已登录页面刷新确认。 + +## 风险评估 + +- 不修改数据库、接口字段或工单状态流转,仅调整前端展示元数据。 +- 关系失效时仍保留唯一标识复制能力,便于排障。 diff --git a/docs/项目文档_平台资源中文展示统一_v1.0.md b/docs/项目文档_平台资源中文展示统一_v1.0.md index 8dd1062..0c8d71e 100644 --- a/docs/项目文档_平台资源中文展示统一_v1.0.md +++ b/docs/项目文档_平台资源中文展示统一_v1.0.md @@ -81,3 +81,4 @@ frontend/platform_admin/ - v1.16:财务对账渠道统一显示余额支付、支付宝、微信支付;账单日期按 `YYYY-MM-DD` 展示,不再回显时间和时区。 - v1.17:内容类型统一显示公告、协议,发布状态统一显示草稿、已发布;新建和编辑改用中文下拉并保留未知值提示。 - v1.18:客服工单用户统一展示可读名称并保留标识复制;分类与优先级统一显示中文,新建和编辑改用中文下拉并保留未知值提示。 +- v1.19:客服工单详情的气站、配送点和处理人员统一展示关系名称;未分派、未开始、未完成及未提交结果等空值改用明确业务状态,不再显示裸 `-`。 diff --git a/frontend/platform_admin/scripts/check-resource-display-contracts.mjs b/frontend/platform_admin/scripts/check-resource-display-contracts.mjs index 3263fb2..063ed7b 100644 --- a/frontend/platform_admin/scripts/check-resource-display-contracts.mjs +++ b/frontend/platform_admin/scripts/check-resource-display-contracts.mjs @@ -23,6 +23,7 @@ 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 listFieldDisplay = read('src/views/shared/resource-list-field-display.ts'); const treePage = read('src/views/shared/TreePage.vue'); const identityText = read('src/components/IdentityText.vue'); @@ -363,6 +364,13 @@ for (const ticketContract of [ "unknownValueLabel: '未知工单分类'", "{ label: '普通', value: 'normal' }", "unknownValueLabel: '未知优先级'", + "emptyText: '尚未分配配送点'", + "emptyText: '尚未分配处理人员'", + "staffRelation: { roles: ['installer', 'delivery', 'operations'] }", + "emptyText: '尚未关联服务气站'", + "emptyText: '尚未开始处理'", + "emptyText: '尚未完成'", + "emptyText: '尚未提交处理结果'", ]) { assertIncludes( resources, @@ -370,6 +378,11 @@ for (const ticketContract of [ `客服工单缺少用户关系或中文枚举契约:${ticketContract}`, ); } +assertIncludes( + listFieldDisplay, + '!field.listHidden', + '仅用于详情的辅助字段不得扩张标准资源列表', +); assertIncludes( detailPage, '!hasResourceFieldLabel(props.definition, actualKey)', diff --git a/frontend/platform_admin/src/api/resource-page-rules.ts b/frontend/platform_admin/src/api/resource-page-rules.ts index 79f5bf5..f299f9a 100644 --- a/frontend/platform_admin/src/api/resource-page-rules.ts +++ b/frontend/platform_admin/src/api/resource-page-rules.ts @@ -157,6 +157,19 @@ const pageRules: Record = { editKeys: ['content_type', 'title', 'body', 'version_no', 'publish_status'], }, cs_ticket: { + createHiddenKeys: [ + 'delivery_basic_identity', + 'staff_account_identity', + 'gas_basic_identity', + 'operator_identity', + 'description', + 'request_no', + 'address', + 'appointment_at', + 'started_at', + 'completed_at', + 'result', + ], editKeys: ['user_account_identity', 'ticket_no', 'category', 'priority'], }, platform_account: { diff --git a/frontend/platform_admin/src/api/resources.ts b/frontend/platform_admin/src/api/resources.ts index d1c8088..d0d6ff1 100644 --- a/frontend/platform_admin/src/api/resources.ts +++ b/frontend/platform_admin/src/api/resources.ts @@ -86,6 +86,8 @@ export type ResourceField = { listDetailLink?: boolean; /** 列表以可读展示字段为主文案,同时保留原关系唯一标识复制入口。 */ listDisplayIdentityCopy?: boolean; + /** 仅用于详情或表单的辅助字段,不进入标准资源列表。 */ + listHidden?: boolean; options?: Array<{ label: string; value: string | number }>; defaultValue?: string | number | boolean; readonlyOnCreate?: boolean; @@ -186,6 +188,7 @@ const fieldLabels: Record = { repair_type: '检修类型', started_at: '开始时间', completed_at: '完成时间', + appointment_at: '预约时间', result: '检修结果', target_product_status: '目标产品状态', content: '内容', @@ -922,6 +925,27 @@ export const resources: ResourceUiDefinition[] = [ { label: '高', value: 'high' }, { label: '紧急', value: 'urgent' }, ], unknownValueLabel: '未知优先级' }), + relation('delivery_basic_identity', '/delivery_basic', false, { + label: '配送点', listHidden: true, displayRelationLabel: true, + showIdentityCopy: true, emptyText: '尚未分配配送点', + }), + relation('staff_account_identity', '/staff_account', false, { + label: '处理人员', listHidden: true, displayRelationLabel: true, + showIdentityCopy: true, emptyText: '尚未分配处理人员', + staffRelation: { roles: ['installer', 'delivery', 'operations'] }, + }), + relation('gas_basic_identity', '/gas_basic', false, { + label: '服务气站', listHidden: true, displayRelationLabel: true, + showIdentityCopy: true, emptyText: '尚未关联服务气站', + }), + f('operator_identity', { label: '最近操作人标识', listHidden: true, listCopyable: true, emptyText: '暂无操作记录' }), + f('description', { label: '问题描述', type: 'textarea', listHidden: true, emptyText: '未填写问题描述' }), + f('request_no', { label: '请求流水号', listHidden: true, listCopyable: true, emptyText: '未记录请求流水号' }), + f('address', { label: '上门地址', type: 'textarea', listHidden: true, emptyText: '未填写上门地址' }), + f('appointment_at', { label: '预约时间', type: 'datetime', listHidden: true, emptyText: '未预约' }), + f('started_at', { label: '开始时间', type: 'datetime', listHidden: true, emptyText: '尚未开始处理' }), + f('completed_at', { label: '完成时间', type: 'datetime', listHidden: true, emptyText: '尚未完成' }), + f('result', { label: '处理结果', type: 'textarea', listHidden: true, emptyText: '尚未提交处理结果' }), ]), define('platform_account', '平台账户', 'writable', [f('username', { required: true }), f('password', { required: true }), f('display_name'), f('avatar'), f('platform_role_code', { required: true, unknownValueLabel: '未知角色' }), f('phone')]), define('platform_role', '平台角色', 'writable', [f('role_code', { required: true }), f('name', { required: true }), f('location_scope', { required: true, type: 'select', options: resourceSearchEnumOptions('platform_role', 'location_scope') })], 'list', [ diff --git a/frontend/platform_admin/src/views/shared/resource-list-field-display.ts b/frontend/platform_admin/src/views/shared/resource-list-field-display.ts index d67518a..931da5f 100644 --- a/frontend/platform_admin/src/views/shared/resource-list-field-display.ts +++ b/frontend/platform_admin/src/views/shared/resource-list-field-display.ts @@ -77,7 +77,12 @@ export function resourceListDisplayFields( ...definition.fields.filter((field) => !priority.includes(field.key)), ]; return ordered - .filter((field) => field.key !== 'identity' && field.type !== 'password') + .filter( + (field) => + field.key !== 'identity' && + field.type !== 'password' && + !field.listHidden, + ) .filter( (field) => !(