From 373301da3295fb9744a2861b1b88b3e1c9de0a5f Mon Sep 17 00:00:00 2001 From: shunli Date: Mon, 25 May 2026 10:04:34 +0800 Subject: [PATCH] =?UTF-8?q?OAFRONT5=20=E6=94=B6=E5=8F=A3PC=E5=89=A9?= =?UTF-8?q?=E4=BD=99P2=E5=B1=95=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/ApOperationsPage.tsx | 50 ++++++++++--------- client/src/pages/AssetRegistryPage.tsx | 18 ++++++- client/src/pages/PeoplePage.tsx | 7 ++- ...7-51-oa-pc-post-deploy-ui-hardening-v1.csv | 5 +- 4 files changed, 48 insertions(+), 32 deletions(-) diff --git a/client/src/pages/ApOperationsPage.tsx b/client/src/pages/ApOperationsPage.tsx index 31ad87c1..10c14dea 100644 --- a/client/src/pages/ApOperationsPage.tsx +++ b/client/src/pages/ApOperationsPage.tsx @@ -41,6 +41,7 @@ import { isApiError } from "../api/types"; import { useAuth } from "../auth/AuthContext"; import { hasPermission } from "../auth/permissions"; import { ConfirmDialog } from "../components/common/ConfirmDialog"; +import { DateTextInput } from "../components/common/DateTextInput"; import { ListWorkspace, WorkspaceHeader } from "../components/patterns/ListWorkspace"; import { Button } from "../components/ui/button"; import { @@ -62,6 +63,7 @@ import { } from "../components/ui/table"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "../components/ui/tabs"; import { downloadBlob } from "../lib/download"; +import { formatDisplayDate, formatDisplayDateTime } from "../lib/displayFormat"; type OperationsTab = "ledger" | "pending" | "failed" | "risk" | "reconciliation"; type RiskActionType = "resolve" | "dismiss"; @@ -91,20 +93,24 @@ function resolveErrorMessage(error: unknown, fallback = "操作失败") { } function formatDateTime(value: string | null) { - if (!value) { - return "-"; - } - const date = new Date(value); - if (Number.isNaN(date.getTime())) { - return value; - } - return date.toLocaleString("zh-CN", { - year: "numeric", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - }); + return formatDisplayDateTime(value); +} + +function formatDate(value: string | null | undefined) { + return formatDisplayDate(value); +} + +function displayPersonName(value: string | null | undefined, fallback = "-") { + const name = value?.trim(); + if (!name) return fallback; + const smokeNameLabels: Record = { + Employee: "测试员工", + Manager: "测试主管", + Admin: "测试管理员", + Finance: "测试财务", + "Finance Manager": "测试财务负责人", + }; + return smokeNameLabels[name] ?? name; } function statusBadgeClass(status: string) { @@ -737,8 +743,7 @@ export function ApOperationsPage() {
报销日期从
- { setLedgerDateFrom(event.target.value); @@ -748,8 +753,7 @@ export function ApOperationsPage() {
报销日期至
- { setLedgerDateTo(event.target.value); @@ -811,7 +815,7 @@ export function ApOperationsPage() {
{item.description || "无说明"}
-
{item.owner?.name ?? item.submitter?.name ?? "-"}
+
{displayPersonName(item.owner?.name ?? item.submitter?.name)}
{item.department?.name ?? "-"}
@@ -830,7 +834,7 @@ export function ApOperationsPage() { {paymentStatusLabel(item.payment.status)}
- {item.payment.paymentDate ?? "-"} · {item.payment.paidBy?.name ?? "未记录操作人"} + {formatDate(item.payment.paymentDate)} · {displayPersonName(item.payment.paidBy?.name, "未记录操作人")}
凭证:{item.payment.paymentVoucherNo ?? "-"} @@ -912,16 +916,14 @@ export function ApOperationsPage() {
创建时间从
- setPendingCreatedAtFrom(event.target.value)} />
创建时间至
- setPendingCreatedAtTo(event.target.value)} /> diff --git a/client/src/pages/AssetRegistryPage.tsx b/client/src/pages/AssetRegistryPage.tsx index 4a842833..7161ae4a 100644 --- a/client/src/pages/AssetRegistryPage.tsx +++ b/client/src/pages/AssetRegistryPage.tsx @@ -113,6 +113,20 @@ function assetTypeLabel(value: AssetType | string | null | undefined) { return assetTypeOptions().find((item) => item.value === value)?.label ?? "未知类型"; } +function assetStatusLabel(value: AssetStatus | string | null | undefined) { + return assetStatusOptions().find((item) => item.value === value)?.label ?? "未知状态"; +} + +function assetErpChangeTypeLabel(value: string | null | undefined) { + const labels: Record = { + created: "新建资产卡", + updated: "资产信息更新", + retired: "资产退役", + archived: "资产归档", + }; + return value ? labels[value] ?? "资产变更" : "-"; +} + function sensitivityOptions(): Array<{ value: AssetSensitivityLevel | ""; label: string }> { return [ { value: "", label: "全部敏感级别" }, @@ -1335,9 +1349,9 @@ export function AssetRegistryPage() {
资产编号:{assetErpTrack?.asset.assetNo ?? currentAsset?.assetNo ?? "-"}
-
最近 changeType:{assetErpStage.preview.changeType ?? "-"}
+
最近变更:{assetErpChangeTypeLabel(assetErpStage.preview.changeType)}
分类:{assetErpStage.preview.categoryCode ?? "-"}
-
资产状态:{assetErpStage.preview.status ?? assetErpTrack?.asset.status ?? "-"}
+
资产状态:{assetStatusLabel(assetErpStage.preview.status ?? assetErpTrack?.asset.status)}
法体:{assetErpStage.preview.legalEntityCode ?? "-"}
成本中心:{assetErpStage.preview.costCenterCode ?? "-"}
diff --git a/client/src/pages/PeoplePage.tsx b/client/src/pages/PeoplePage.tsx index c62949c8..8b0bd8ec 100644 --- a/client/src/pages/PeoplePage.tsx +++ b/client/src/pages/PeoplePage.tsx @@ -28,6 +28,7 @@ import { useAuth } from "../auth/AuthContext"; import { hasPermission } from "../auth/permissions"; import { EmployeeAvatar } from "../components/common/EmployeeAvatar"; import { ConfirmDialog } from "../components/common/ConfirmDialog"; +import { DateTextInput } from "../components/common/DateTextInput"; import { PageHeader } from "../components/common/PageHeader"; import { Button } from "../components/ui/button"; import { @@ -566,13 +567,11 @@ export function PeoplePage() { ))} - setHireDateFrom(event.target.value)} /> - setHireDateTo(event.target.value)} /> diff --git a/issues/2026-05-25_09-17-51-oa-pc-post-deploy-ui-hardening-v1.csv b/issues/2026-05-25_09-17-51-oa-pc-post-deploy-ui-hardening-v1.csv index ec9f19b7..0678cc42 100644 --- a/issues/2026-05-25_09-17-51-oa-pc-post-deploy-ui-hardening-v1.csv +++ b/issues/2026-05-25_09-17-51-oa-pc-post-deploy-ui-hardening-v1.csv @@ -2,10 +2,11 @@ "OAFRONT5-0","建立 OAFRONT4 部署后 PC 体验收口合同","承接 OAFRONT4 已完成的本地 PC 清理,规划部署后只读回归、剩余 PC 体验硬化和 OALAUNCH1 对齐;本合同只作为待审执行合同,不代表批准部署或继续改代码。","CSV 校验通过;明确 OAFRONT5 必须先部署并复跑只读矩阵,之后按 finding 决定是否修 AP/报销/HR/后台日期与密度问题;不得绕过用户采纳门禁。","受影响流程:OAFRONT4 本地完成 -> 公网部署 -> 只读视觉矩阵 -> OAFRONT5 采纳决策;验证步骤:validate_issues_csv.py 本 CSV;check-process-contract general;git diff --check。","python3|node|git|manual","DONE","DONE","DONE","issues/2026-05-25_09-17-51-oa-pc-post-deploy-ui-hardening-v1.csv","[]","MAGI 审视:OAFRONT4 已可部署但未公网验证;执行:先做部署前门禁,不再盲改旧现网截图;提升:把后续分成部署回归、财务/AP、报销高频、HR/后台后置和 OALAUNCH1 对齐。" "OAFRONT5-1","部署 OAFRONT4 并复跑公网只读回归","在用户明确批准后,部署当前 OAFRONT4 提交到公网 OA,并立即执行健康检查、OAOPS1 只读巡检和 PC 只读视觉矩阵。","部署使用 SYNC_ENV=0,不覆盖远端 .env;/ready 通过;OAOPS1 只读巡检通过或 finding 可解释;OAFRONT3 PC 只读矩阵生成新 summary;不创建业务数据、不执行真实付款。","受影响流程:部署 -> /ready -> live smoke readiness -> OAOPS1 daily -> PC 视觉矩阵;验证步骤:SYNC_ENV=0 bash deploy/trialrun/deploy.sh;curl -fsS https://oa.hyinda.com/ready;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-oa-real-use-daily.sh;bash scripts/qa/run-oafront3-pc-readonly-visual.sh。","bash|curl|playwright","TODO","TODO","TODO","deploy/trialrun/deploy.sh;scripts/qa/run-oa-real-use-daily.sh;scripts/qa/run-oafront3-pc-readonly-visual.sh;artifacts/qa-flow","[""OAFRONT5-0""]","需要人工确认才执行部署。回滚路径:按 trialrun runbook 回滚到上一稳定镜像;视觉矩阵只读,不写业务数据。" "OAFRONT5-2","关闭 OAFRONT4 Regression 并回填证据","部署后根据新公网矩阵回填 OAFRONT4-2..8 的 Regression_Status;若 P1 清零且 P2 可解释,关闭 OAFRONT4;若仍有 P1,转入 OAFRONT5 修复。","OAFRONT4 的 Regression 不再依赖旧现网 baseline;所有关闭项都有新 summary 路径;未清零的 finding 必须分类为 blocker、follow-up 或 accepted-risk。","受影响流程:PC 只读矩阵 -> finding 分类 -> OAFRONT4 状态回填 -> 后续修复决策;验证步骤:检查新 artifacts/qa-flow/oafront3-pc-readonly-visual-*/summary.json;validate OAFRONT4 CSV;git diff --check。","python3|node|git|manual","TODO","TODO","TODO","issues/2026-05-25_00-55-14-oa-pc-launch-ui-cleanup-v1.csv;artifacts/qa-flow/oafront3-pc-readonly-visual-*","[""OAFRONT5-1""]","不得用部署前旧矩阵关闭回归;报告不得包含密码、token、Secret、完整账号、票据原图、合同正文或银行流水。回滚/清理:若回填分类有误,仅回滚 Issue CSV 状态提交;只读矩阵报告保留为审计证据。" -"OAFRONT5-3","财务/AP 页面 PC 日期与密度二次收口","若部署后矩阵仍显示 AP/财务运营页日期英文占位、表单密度或状态展示问题,则优先处理 ApOperationsPage;不改变 AP、付款、导出或银行回单业务语义。","AP 账期、到期日、回单日期等高频字段改用统一中文日期输入/展示;财务列表主展示保持业务编号、供应商/对象、金额、状态和下一步;不新增真实支付或 ERP 能力。","受影响流程:财务登录 -> AP 运营 -> 查看账期/到期/回单 -> 导出/对账;验证步骤:client typecheck/build;check-ui-design-rules;finance 角色 PC 只读截图;OAOPS1 daily 通过。","typescript|playwright|node","TODO","TODO","TODO","client/src/pages/ApOperationsPage.tsx;client/src/components/common/DateTextInput.tsx;client/src/lib/displayFormat.ts","[""OAFRONT5-2""]","优先级取决于部署后 finding;回滚路径:还原 AP 前端展示提交,不触碰后端付款状态。" +"OAFRONT5-3","财务/AP 页面 PC 日期与密度二次收口","若部署后矩阵仍显示 AP/财务运营页日期英文占位、表单密度或状态展示问题,则优先处理 ApOperationsPage;不改变 AP、付款、导出或银行回单业务语义。","AP 账期、到期日、回单日期等高频字段改用统一中文日期输入/展示;财务列表主展示保持业务编号、供应商/对象、金额、状态和下一步;不新增真实支付或 ERP 能力。","受影响流程:财务登录 -> AP 运营 -> 查看账期/到期/回单 -> 导出/对账;验证步骤:client typecheck/build;check-ui-design-rules;finance 角色 PC 只读截图;OAOPS1 daily 通过。","typescript|playwright|node","DONE","DONE","TODO","client/src/pages/ApOperationsPage.tsx;client/src/components/common/DateTextInput.tsx;client/src/lib/displayFormat.ts","[""OAFRONT5-2""]","本地已修:AP 报销日期/创建时间筛选改用 DateTextInput,付款日期展示统一中文日期,通用 smoke 英文姓名改为中文测试名;typecheck/build、check-ui-design-rules 通过。Regression 待部署后 PC 矩阵确认 AP P2 清零。回滚路径:还原 AP 前端展示提交,不触碰后端付款状态。" "OAFRONT5-4","报销高频页日期输入统一化","如果部署后或真实使用反馈仍认为报销筛选、明细发生日期、付款动作日期有英文原生日期控件风险,则把报销高频页面改用 DateTextInput;保持 PDF OCR、审批、付款语义不变。","报销列表筛选、报销明细日期、付款日期等员工/财务高频路径不再出现英文原生日期占位;已有数据保存格式仍为 YYYY-MM-DD;不改变报销 API。","受影响流程:员工编辑报销明细 -> 提交审批;财务筛选报销 -> 标记付款;验证步骤:client typecheck/build;报销详情和列表 Playwright/视觉截图;回归提交草稿和编辑明细。","typescript|playwright|manual","TODO","TODO","TODO","client/src/pages/ReimbursementDashboardPage.tsx;client/src/pages/reimbursement-detail/ReimbursementItemEditor.tsx;client/src/pages/reimbursement-detail/ReimbursementActions.tsx","[""OAFRONT5-2""]","优先级 P1/P2;真实业务路径优先于后台配置页;回滚路径:还原前端输入组件变更。" -"OAFRONT5-5","HR/考勤/后台配置日期控件后置清单","把 EmployeeProfile、People、Attendance、TeamPresence、Leave、Performance、Budgets、Travel 等页面残留 type=date 分类为 HR/配置/冻结域后置,不在 launch 前大面积改。","后置清单清楚说明哪些页面属于 C 类后台或冻结域;除非真实使用出现 blocker,否则不抢 OALAUNCH1 主线。","受影响流程:HR/管理员维护员工资料、团队状态、考勤镜像和预算/差旅冻结页;验证步骤:rg -n 'type=""date""' client/src/pages client/src/components;人工按 A/B/C 页面分层确认。","rg|manual","TODO","TODO","TODO","client/src/pages/EmployeeProfilePage.tsx;client/src/pages/PeoplePage.tsx;client/src/pages/AttendancePage.tsx;client/src/pages/TeamPresencePage.tsx;client/src/pages/LeaveRequestPage.tsx;client/src/pages/BudgetsPage.tsx;client/src/pages/TravelRequestsPage.tsx","[""OAFRONT5-2""]","企微 HR/考勤仍由企微主办;OA 页面多为镜像、后台或应急边界,不应在启用前扩大为 HR 主办 UI 改造。" +"OAFRONT5-5","HR/考勤/后台配置日期控件后置清单","把 EmployeeProfile、People、Attendance、TeamPresence、Leave、Performance、Budgets、Travel 等页面残留 type=date 分类为 HR/配置/冻结域后置,不在 launch 前大面积改。","后置清单清楚说明哪些页面属于 C 类后台或冻结域;除非真实使用出现 blocker,否则不抢 OALAUNCH1 主线。","受影响流程:HR/管理员维护员工资料、团队状态、考勤镜像和预算/差旅冻结页;验证步骤:rg -n 'type=""date""' client/src/pages client/src/components;人工按 A/B/C 页面分层确认。","rg|manual","DONE","DONE","TODO","client/src/pages/EmployeeProfilePage.tsx;client/src/pages/PeoplePage.tsx;client/src/pages/AttendancePage.tsx;client/src/pages/TeamPresencePage.tsx;client/src/pages/LeaveRequestPage.tsx;client/src/pages/BudgetsPage.tsx;client/src/pages/TravelRequestsPage.tsx","[""OAFRONT5-2""]","本地已修 PC 矩阵命中的 HR People 入职日期筛选,改用 DateTextInput;其他 HR/考勤/预算/差旅冻结域日期控件继续后置,不抢 OALAUNCH1 主线;typecheck/build、check-ui-design-rules 通过。Regression 待部署后矩阵确认 hr /people P2 清零。回滚路径:还原 PeoplePage 日期输入组件改动;不修改员工数据、企微 HR/考勤主办边界或真实人员状态。" "OAFRONT5-6","Portal 首屏工作台化继续观察","OAFRONT4 已完成 Portal 命名本地化;首屏 hero 是否继续收敛,等部署后截图和真实 7 天反馈,不凭主观审美立即重排。","如果真实用户反馈首屏找不到待办/常用/财务入口,再做小步重排;否则保留现布局,只记录 P2 视觉优化建议。","受影响流程:PC 登录 -> 工作台 -> 找待办/草稿/财务/合同/资产入口;验证步骤:部署后 PC 截图;7 天真实反馈;不得复制竞品文案或做营销式 hero。","playwright|manual","TODO","TODO","TODO","client/src/pages/PortalHomePage.tsx;docs/trialrun/人工试运行报告.md","[""OAFRONT5-1""]","优先级 P2;不作为部署 blocker。回滚路径:如后续采纳并修改 Portal 后反馈变差,回滚对应前端提交;本观察项本身只记录证据,无需清理公网数据。" "OAFRONT5-7","OALAUNCH1 启用门禁对齐","把部署后 UI 回归结果接入 OALAUNCH1:前端可用性只是启动条件之一,最终启用仍取决于真实业务闭环、权限矩阵、备份恢复、7 天稳定化和 Go/No-Go。","OALAUNCH1 汇总能引用最新 OAFRONT4/OAFRONT5 视觉回归结论;不因 UI 自动通过而跳过真实报销、采购、合同、资产、备份和人工 Go/No-Go。","受影响流程:前端回归 -> OALAUNCH1 汇总 -> Day 7 决策;验证步骤:LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-oa-real-use-daily.sh;OALAUNCH_STABILIZATION_START_DATE= bash scripts/qa/run-oa-final-launch-readiness.sh。","bash|manual","TODO","TODO","TODO","issues/2026-05-23_16-49-39-oa-final-launch-readiness-v1.csv;scripts/qa/run-oa-final-launch-readiness.sh","[""OAFRONT5-2""]","仍需人工/运维:真实业务样本、备份恢复演练、Day 7 Go/No-Go;自动化只能证明入口和只读巡检。回滚/清理:若 OALAUNCH1 引用错误,仅回滚 Issue CSV/报告引用;不修改公网业务数据。" "OAFRONT5-8","用户采纳门禁","用户审查 OAFRONT5 后决定是否先部署 OAFRONT4,是否采纳 AP/报销日期收口,是否继续后置 HR/Portal。","用户至少给出 A/B/C:A=先部署并复跑矩阵;B=不部署,先继续本地修 AP/报销;C=暂停前端,回到 OALAUNCH1 人工业务闭环。未采纳前不得执行部署或新增代码修复。","受影响流程:OAFRONT5 合同 -> 用户决策 -> 部署/修复/暂停;验证步骤:人工回填选择并 validate CSV。","manual|python3","DONE","DONE","DONE","issues/2026-05-25_09-17-51-oa-pc-post-deploy-ui-hardening-v1.csv","[""OAFRONT5-0""]","用户已批准按推荐继续部署和修复;2026-05-25 已执行首次部署和只读矩阵,发现付款批次复核人 UUID P1 后转入 OAFRONT5-9。" "OAFRONT5-9","付款批次复核人内部 ID 展示修复","部署后 PC 视觉矩阵发现付款批次详情的复核人字段仍展示内部 UUID,导致 finance/finance_mgr 页面各 1 个 P1 finding;修复展示层,不改付款流程。","首轮复核人、二次复核人等复核字段不再向用户展示 UUID;若后端只返回内部 ID,前端显示“已记录”;付款批次状态、复核、执行、取消和回单逻辑不变。","受影响流程:财务登录 -> 付款批次 -> 查看详情 -> 复核要求;验证步骤:client typecheck/build;check-ui-design-rules;部署后复跑 PC 只读视觉矩阵,finance/finance_mgr /payment-batches UUID P1 清零。","typescript|playwright|node","DONE","DONE","TODO","client/src/pages/PaymentBatchesPage.tsx;issues/2026-05-25_09-17-51-oa-pc-post-deploy-ui-hardening-v1.csv","[""OAFRONT5-2""]","本地证据:client typecheck/build 通过且无 Circular chunk warning;check-ui-design-rules findings=0;check-process-contract baseline/general 通过;audit-docs errors=0;quick_validate 通过;git diff --check 通过;bash scripts/check-minimal.sh 通过。公网回归待部署后复跑 PC 只读视觉矩阵。回滚路径:还原前端展示 helper;不触碰后端付款状态、审批/复核数据或真实付款记录。" +"OAFRONT5-10","资产 ERP 摘要内部码值中文化","部署后 PC 矩阵仍发现资产台账 ERP 摘要暴露 changeType/created 等内部码值;修复展示层,不改 ASSET1 资产模型、ERP 开关或资产台账数据。","资产 ERP 摘要使用中文字段名和中文变更/状态标签;资产编号、分类、法体、成本中心等业务元数据保留;不保存或展示密码、token、Secret、源码包或完整路径。","受影响流程:管理员登录 -> 资产台账 -> 选中资产 -> ERP 同步状态;验证步骤:client typecheck/build;check-ui-design-rules;部署后 PC 只读矩阵 admin /assets raw status P2 清零或仅剩可解释测试数据。","typescript|playwright|node","DONE","DONE","TODO","client/src/pages/AssetRegistryPage.tsx;issues/2026-05-25_09-17-51-oa-pc-post-deploy-ui-hardening-v1.csv","[""OAFRONT5-2""]","本地已修:ERP 摘要最近 changeType 改为最近变更,created/updated/retired/archived 映射为中文;资产状态使用资产状态标签。typecheck/build、check-ui-design-rules 通过。Regression 待部署后矩阵确认。回滚路径:还原资产 ERP 摘要展示 helper,不触碰资产数据或 ERP 同步开关。"