From 962e83597f99438ef73497e6dfa304a75a20aed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=86=95?= Date: Mon, 13 Jul 2026 09:31:28 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=AD=E4=BB=A3=20ONE-OS=20=E5=A4=9A?= =?UTF-8?q?=E5=8E=9F=E5=9E=8B=EF=BC=9A=E6=8F=90=E8=BD=A6=E5=BA=94=E6=94=B6?= =?UTF-8?q?=E6=AC=BE=E6=94=B6=E6=AC=BE/=E5=90=88=E5=90=8C=E9=A1=B5?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=EF=BC=8C=E7=A7=9F=E8=B5=81=E6=98=8E=E7=BB=86?= =?UTF-8?q?=E6=A0=87=E6=B3=A8=E5=90=8C=E6=AD=A5=EF=BC=8C=E5=AF=BC=E8=88=AA?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E8=A1=A8=E6=9B=B4=E6=96=B0=EF=BC=9B=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20Git=20=E5=8D=8F=E4=BD=9C=E6=8A=80=E8=83=BD=E5=B9=B6?= =?UTF-8?q?=E5=BF=BD=E7=95=A5=20.local=20=E4=B8=B4=E6=97=B6=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- .axhub/make/axhub.config.json | 5 +- .axhub/make/sidebar-tree.json | 156 +- .../skills/git-repo-beginner-guide/SKILL.md | 162 + .../agents/openai.yaml | 4 + .../skills/git-repo-beginner-guide/SKILL.md | 162 + .gitignore | 1 + package-lock.json | 1 + package.json | 2 + scripts/apply-release-changelog.mjs | 293 + scripts/publish-all-to-s3.mjs | 12 +- scripts/sync-project-prototype-directory.mjs | 9 +- scripts/sync-prototype-nav-registry.mjs | 19 + .../contract-template-docx-fidelity.js | 7 +- .../contract-template-word-import.js | 2 +- .../.spec/requirements-prd.md | 64 +- .../annotation-source.json | 72 +- .../scripts/sync-annotation-directory.mjs | 148 + .../oneos-prototype-nav/nav-data.ts | 27 +- .../oneos-prototype-nav/nav-menu.json | 78 - .../prototype-registry.json | 6567 ++++------------- .../7abbf7d8-3099-47e5-a969-e12082edb3d3.png | Bin 0 -> 12437 bytes .../8b7434c4-e7a7-4473-8404-5864f615811f.png | Bin 0 -> 17943 bytes .../bd98fc92-babb-4cba-8cfe-cecea7354f99.png | Bin 0 -> 19907 bytes .../e590591d-67bb-4a69-9536-5bf15921cf29.png | Bin 0 -> 37097 bytes .../VehiclePickupReceivableApp.jsx | 84 +- .../VehiclePickupReceivableCollectPage.jsx | 814 ++ .../VehiclePickupReceivableContractView.jsx | 342 + .../VehiclePickupReceivableList.jsx | 419 +- .../annotation-source.json | 56 +- .../data/pickup-receivable-list-data.js | 109 +- .../pickup-receivable-bridge.js | 421 ++ .../styles/index.css | 1152 ++- vite.config.ts | 3 + 33 files changed, 5328 insertions(+), 5863 deletions(-) create mode 100644 .claude/skills/git-repo-beginner-guide/SKILL.md create mode 100644 .claude/skills/git-repo-beginner-guide/agents/openai.yaml create mode 100644 .cursor/skills/git-repo-beginner-guide/SKILL.md create mode 100644 scripts/apply-release-changelog.mjs create mode 100644 src/prototypes/lease-business-detail/scripts/sync-annotation-directory.mjs create mode 100644 src/prototypes/vehicle-pickup-receivable/.spec/prototype-comment-assets/7abbf7d8-3099-47e5-a969-e12082edb3d3.png create mode 100644 src/prototypes/vehicle-pickup-receivable/.spec/prototype-comment-assets/8b7434c4-e7a7-4473-8404-5864f615811f.png create mode 100644 src/prototypes/vehicle-pickup-receivable/.spec/prototype-comment-assets/bd98fc92-babb-4cba-8cfe-cecea7354f99.png create mode 100644 src/prototypes/vehicle-pickup-receivable/.spec/prototype-comment-assets/e590591d-67bb-4a69-9536-5bf15921cf29.png create mode 100644 src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableCollectPage.jsx create mode 100644 src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableContractView.jsx diff --git a/.axhub/make/axhub.config.json b/.axhub/make/axhub.config.json index 952115b..cbcd4b5 100644 --- a/.axhub/make/axhub.config.json +++ b/.axhub/make/axhub.config.json @@ -34,7 +34,10 @@ "bucket": "model-lnoneos", "prefix": "", "baseUrl": "https://prototype.lnoneos.com", - "endpoint": "https://model-lnoneos.oss-cn-hangzhou.aliyuncs.com" + "endpoint": "https://model-lnoneos.oss-cn-hangzhou.aliyuncs.com", + "pathAliases": { + "oneos-prototype-nav": "oneos-prototype-nav" + } }, "githubPages": { "repository": "", diff --git a/.axhub/make/sidebar-tree.json b/.axhub/make/sidebar-tree.json index da03d89..b933e97 100644 --- a/.axhub/make/sidebar-tree.json +++ b/.axhub/make/sidebar-tree.json @@ -1,78 +1,73 @@ { "version": 1, - "updatedAt": "2026-07-11T03:51:46.250Z", + "updatedAt": "2026-07-12T17:06:54.186Z", "prototypes": [ { - "id": "item-prototypes-task-work-order", - "kind": "item", - "title": "task work order", - "itemKey": "prototypes/task-work-order" - }, - { - "id": "item-prototypes-lease-business-line-overview", - "kind": "item", - "title": "lease business line overview", - "itemKey": "prototypes/lease-business-line-overview" - }, - { - "id": "item-prototypes-oneos-web-business", - "kind": "item", - "title": "oneos web business", - "itemKey": "prototypes/oneos-web-business" - }, - { - "id": "item-prototypes-oneos-web-contract-template", - "kind": "item", - "title": "oneos web contract template", - "itemKey": "prototypes/oneos-web-contract-template" - }, - { - "id": "item-prototypes-oneos-web-data-analysis", - "kind": "item", - "title": "oneos web data analysis", - "itemKey": "prototypes/oneos-web-data-analysis" - }, - { - "id": "item-prototypes-oneos-web-finance", - "kind": "item", - "title": "oneos web finance", - "itemKey": "prototypes/oneos-web-finance" - }, - { - "id": "item-prototypes-oneos-web-h2-station", - "kind": "item", - "title": "oneos web h2 station", - "itemKey": "prototypes/oneos-web-h2-station" - }, - { - "id": "item-prototypes-oneos-web-help-center", - "kind": "item", - "title": "oneos web help center", - "itemKey": "prototypes/oneos-web-help-center" - }, - { - "id": "item-prototypes-oneos-web-lease-contract", - "kind": "item", - "title": "oneos web lease contract", - "itemKey": "prototypes/oneos-web-lease-contract" - }, - { - "id": "item-prototypes-oneos-web-ledger-data", - "kind": "item", - "title": "oneos web ledger data", - "itemKey": "prototypes/oneos-web-ledger-data" - }, - { - "id": "item-prototypes-oneos-web-ops", - "kind": "item", - "title": "oneos web ops", - "itemKey": "prototypes/oneos-web-ops" - }, - { - "id": "item-prototypes-oneos-web-procurement", - "kind": "item", - "title": "oneos web procurement", - "itemKey": "prototypes/oneos-web-procurement" + "id": "folder-1783875936186-27raza", + "kind": "folder", + "title": "旧ONEOS", + "children": [ + { + "id": "item:prototypes:oneos-web-business", + "kind": "item", + "title": "业务管理", + "itemKey": "prototypes/oneos-web-business" + }, + { + "id": "item:prototypes:oneos-web-contract-template", + "kind": "item", + "title": "合同模板管理", + "itemKey": "prototypes/oneos-web-contract-template" + }, + { + "id": "item:prototypes:oneos-web-data-analysis", + "kind": "item", + "title": "数据分析", + "itemKey": "prototypes/oneos-web-data-analysis" + }, + { + "id": "item:prototypes:oneos-web-finance", + "kind": "item", + "title": "财务管理(合包)", + "itemKey": "prototypes/oneos-web-finance" + }, + { + "id": "item:prototypes:oneos-web-h2-station", + "kind": "item", + "title": "加氢站管理", + "itemKey": "prototypes/oneos-web-h2-station" + }, + { + "id": "item:prototypes:oneos-web-help-center", + "kind": "item", + "title": "帮助中心", + "itemKey": "prototypes/oneos-web-help-center" + }, + { + "id": "item:prototypes:oneos-web-lease-contract", + "kind": "item", + "title": "车辆租赁合同", + "itemKey": "prototypes/oneos-web-lease-contract" + }, + { + "id": "item:prototypes:oneos-web-ledger-data", + "kind": "item", + "title": "台账数据", + "itemKey": "prototypes/oneos-web-ledger-data" + }, + { + "id": "item:prototypes:oneos-web-ops", + "kind": "item", + "title": "运维管理", + "itemKey": "prototypes/oneos-web-ops" + }, + { + "id": "item:prototypes:oneos-web-procurement", + "kind": "item", + "title": "采购管理", + "itemKey": "prototypes/oneos-web-procurement" + } + ] }, { "id": "item:prototypes:oneos-prototype-nav", @@ -241,6 +236,25 @@ "itemKey": "prototypes/vehicle-return-settlement-v2" } ] + }, + { + "id": "folder-1783875880945-4r6tq1", + "kind": "folder", + "title": "任务工单", + "children": [ + { + "id": "item:prototypes:task-work-order", + "kind": "item", + "title": "任务工单", + "itemKey": "prototypes/task-work-order" + } + ] + }, + { + "id": "item:prototypes:lease-business-line-overview", + "kind": "item", + "title": "业务条线说明", + "itemKey": "prototypes/lease-business-line-overview" } ] } diff --git a/.claude/skills/git-repo-beginner-guide/SKILL.md b/.claude/skills/git-repo-beginner-guide/SKILL.md new file mode 100644 index 0000000..7238faa --- /dev/null +++ b/.claude/skills/git-repo-beginner-guide/SKILL.md @@ -0,0 +1,162 @@ +--- +name: git-repo-beginner-guide +description: "面向不熟悉 Git 的产品经理、设计师、运营、文档作者等非技术用户,引导 GitHub/GitLab/Gitee/Bitbucket/自建 Git 平台的仓库初始化、授权、克隆、提交同步、冲突处理、版本恢复和协作交接。" +--- + +# Git 仓库新手引导 + +## Overview + +帮助非技术用户安全、低焦虑地使用 Git 仓库协作。默认由 AI 代做可执行操作,并把必要概念翻译成用户能理解的决策点。 + +## 核心原则 + +- 先问目标,不先教术语。用户通常要的是“保存一版”“发给团队”“拿到项目”“回到昨天”,不是学习 Git。 +- 先保护现场。任何会丢弃、覆盖、重写历史、删除远程内容的动作,都先解释影响并确认。 +- 默认代办。能由 AI 检查、执行、验证的,不要让用户自己照抄命令;用户只负责授权、选择平台、确认风险。 +- 渐进解释。只有当概念会影响用户决策时才解释,例如远程仓库、提交、同步、冲突。分支、rebase、stash 等先不主动引入。 +- 平台中立。不要默认 GitHub;先识别或询问 GitHub、GitLab、Gitee、Bitbucket、自建 Git、公司内网平台等。 +- 用生活化比喻,但保留必要名词。第一次出现可写“提交 commit:给当前文件拍一张可回退的快照”。 +- 先小步闭环。每次只完成一个可验证状态:已登录、已连接远程、已保存本地版本、已同步到远程、已恢复文件。 + +## 交互流程 + +### 1. 先识别用户处境 + +先用自然语言复述用户目标,然后做最少量澄清。 + +常见处境: + +- “我有一个本地文件夹,想放到代码平台上” → 初始化/连接远程/首次同步 +- “别人给我一个链接,我要拿下来” → 克隆/权限/打开项目 +- “我改完了,想保存并发给别人” → 查看改动/提交/推送 +- “我怕改坏,想留个版本” → 本地提交或备份分支,按复杂度选择 +- “提示要登录/没有权限” → 平台授权引导 +- “提示冲突/推不上去” → 解释有人也改了同一处,先保护本地改动再合并 +- “我要回到之前” → 明确是恢复文件、撤销未提交改动、还是回到某个历史版本 + +如果上下文已经足够,不要继续追问。直接说“我先帮你检查当前状态”。 + +### 2. 明确 AI 能帮什么 + +在开始前用一句话降低用户负担: + +> 我可以帮你检查当前文件状态、创建版本记录、连接远程仓库、同步到平台;你只需要在需要网页登录授权时确认账号,或者告诉我目标仓库链接。 + +避免说“你运行以下命令”。除非当前环境无法代办,才给用户步骤。 + +### 3. 检查当前状态并翻译结果 + +检查本地是否是仓库、是否有远程地址、当前有无未保存改动、是否已登录相关平台。回复用户时不要直接堆 `git status` 原文,先给可行动摘要: + +- “这个文件夹还不是仓库,我可以把它变成一个可记录版本的文件夹。” +- “它已经连接到远程平台,地址是 X。” +- “现在有 6 个文件改动了,还没有保存成版本。” +- “远程平台需要登录授权,接下来会打开/提供平台自己的登录流程。” + +需要展示命令输出时,只摘关键含义。 + +### 4. 授权引导要平台灵活 + +先识别远程 URL 或用户指定平台,再选择授权方式: + +- GitHub:优先 `gh auth status` / `gh auth login`;必要时解释浏览器 OAuth、SSH、token 的差异。 +- GitLab:优先平台 CLI 或 HTTPS token/SSH;自建 GitLab 注意域名和公司 SSO。 +- Gitee:常见为 HTTPS 凭证、私人令牌或 SSH key;不要套用 GitHub 文案。 +- Bitbucket:注意 workspace、app password、SSH。 +- 自建平台:先问/识别平台地址,按 HTTPS token、SSH key、公司 SSO 三类引导。 + +授权沟通规范: + +- 不要求用户把密码、token、私钥粘贴到聊天里。 +- 需要 token 时,引导用户在平台页面生成,并说明只保存到系统凭据/CLI,不在聊天中泄露。 +- 需要 SSH key 时,先检查是否已有可用 key;没有再创建,并指导用户把公钥加到平台。 +- 遇到 SSO/组织权限时,告诉用户“这是账号权限问题,不是你的文件坏了”。 + +## 复杂度控制 + +### 不主动引入分支 + +如果用户只想把个人文件夹放到远程、保存一版、拉取项目或同步改动,不主动讲分支。 + +只有在以下情况才引入分支: + +- 用户明确要多人协作或不想影响主版本 +- 当前仓库已有分支策略或保护规则 +- 需要在不动主线的情况下尝试修改 +- 提交到主分支被拒绝,需要通过 PR/MR + +第一次解释分支时保持短句: + +> 分支可以理解成一份独立草稿。你可以在草稿里改,确认没问题后再合到正式版本。 + +不要一开始讲 rebase、cherry-pick、worktree、detached HEAD。 + +### 冲突处理面向结果 + +冲突不是“报错”,而是“同一处内容有两份修改,系统不知道该选哪份”。 + +处理前先说明: + +- 你的本地改动还在 +- 远程也有别人/另一台设备的改动 +- 我会先帮你看冲突位置,再让你决定保留哪部分或合并两边 + +如果用户不懂代码,优先生成“冲突内容对照摘要”,不要让用户读冲突标记。 + +### 版本恢复先问恢复粒度 + +用户说“还原/回退/恢复”时,先判断是哪一种: + +- 只撤销还没保存成版本的本地修改 +- 找回某个被删文件 +- 查看之前某个版本 +- 把整个项目回到某个历史版本 +- 远程也要同步回退 + +远程回退、强推、删除历史前必须明确风险并取得确认。对非技术用户可说: + +> 这会改变团队平台上看到的历史版本,可能影响别人。我先给你一个不改远程历史的恢复方案。 + +## 推荐话术 + +### 初始化/首次同步 + +> 我先帮你确认这个文件夹是不是已经有版本记录。如果没有,我会把它变成一个仓库,然后再连接你选择的平台。这个过程不会改变文件内容,只是增加一套版本记录。 + +### 提交/保存版本 + +> 现在可以把这次改动保存成一个版本记录。提交信息我会写成人能看懂的一句话,方便以后知道这一版改了什么。 + +### 推送/同步 + +> 本地版本已经保存好了。下一步是同步到远程平台,这样团队或另一台电脑才能看到。 + +### 授权 + +> 这里需要你用平台账号授权。我不会让你把密码发给我;我们走平台自己的登录流程,完成后我再继续。 + +### 不确定平台 + +> 你用的是 GitHub、GitLab、Gitee、Bitbucket,还是公司自己的代码平台?如果你有仓库链接,直接发链接最省事。 + +## 操作规范 + +- 执行前先看 `git status`、远程地址和当前分支/默认线索;不要盲目提交或推送。 +- 提交前给用户一个简短变更摘要,确认是否包含敏感文件、临时文件、大文件、设计源文件。 +- 提交信息用用户能理解的语言,但保留常见规范。示例:`docs: update product requirements draft`、`feat: add onboarding flow mockup`。 +- 不把 `.env`、密钥、token、账号导出文件、个人隐私文件提交到仓库;发现时先提醒并处理忽略规则。 +- 不擅自执行 `git reset --hard`、`git clean -fd`、`git push --force`、删除远程分支、覆盖远程历史。 +- 如果工作区已有别人未说明的改动,不要回滚;先说明发现了哪些现有改动,并只处理用户当前目标相关内容。 +- 对新手用户优先给“下一步我来做什么”和“你需要确认什么”,少给完整命令列表。 + +## 交付要求 + +完成后用简短摘要告诉用户: + +- 当前状态:本地已保存/已连接远程/已同步/仍需授权/遇到冲突 +- 做了什么:初始化、克隆、提交、推送、恢复、创建 issue/PR/MR 等 +- 远程位置:仓库链接或远程地址(如果可用) +- 用户下一步:打开链接确认、邀请协作者、继续修改、等待权限、选择冲突保留内容 + +如果没有完成,说明卡在“权限、网络、平台限制、冲突选择、缺少仓库链接”中的哪一类,并给一个最短可继续步骤。 diff --git a/.claude/skills/git-repo-beginner-guide/agents/openai.yaml b/.claude/skills/git-repo-beginner-guide/agents/openai.yaml new file mode 100644 index 0000000..56d6215 --- /dev/null +++ b/.claude/skills/git-repo-beginner-guide/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Git 仓库新手引导" + short_description: "用非技术用户听得懂的方式引导 Git/GitHub/GitLab/Gitee 仓库协作。" + default_prompt: "帮我用面向非技术用户的方式完成仓库初始化、授权、提交、同步或版本恢复。" diff --git a/.cursor/skills/git-repo-beginner-guide/SKILL.md b/.cursor/skills/git-repo-beginner-guide/SKILL.md new file mode 100644 index 0000000..7238faa --- /dev/null +++ b/.cursor/skills/git-repo-beginner-guide/SKILL.md @@ -0,0 +1,162 @@ +--- +name: git-repo-beginner-guide +description: "面向不熟悉 Git 的产品经理、设计师、运营、文档作者等非技术用户,引导 GitHub/GitLab/Gitee/Bitbucket/自建 Git 平台的仓库初始化、授权、克隆、提交同步、冲突处理、版本恢复和协作交接。" +--- + +# Git 仓库新手引导 + +## Overview + +帮助非技术用户安全、低焦虑地使用 Git 仓库协作。默认由 AI 代做可执行操作,并把必要概念翻译成用户能理解的决策点。 + +## 核心原则 + +- 先问目标,不先教术语。用户通常要的是“保存一版”“发给团队”“拿到项目”“回到昨天”,不是学习 Git。 +- 先保护现场。任何会丢弃、覆盖、重写历史、删除远程内容的动作,都先解释影响并确认。 +- 默认代办。能由 AI 检查、执行、验证的,不要让用户自己照抄命令;用户只负责授权、选择平台、确认风险。 +- 渐进解释。只有当概念会影响用户决策时才解释,例如远程仓库、提交、同步、冲突。分支、rebase、stash 等先不主动引入。 +- 平台中立。不要默认 GitHub;先识别或询问 GitHub、GitLab、Gitee、Bitbucket、自建 Git、公司内网平台等。 +- 用生活化比喻,但保留必要名词。第一次出现可写“提交 commit:给当前文件拍一张可回退的快照”。 +- 先小步闭环。每次只完成一个可验证状态:已登录、已连接远程、已保存本地版本、已同步到远程、已恢复文件。 + +## 交互流程 + +### 1. 先识别用户处境 + +先用自然语言复述用户目标,然后做最少量澄清。 + +常见处境: + +- “我有一个本地文件夹,想放到代码平台上” → 初始化/连接远程/首次同步 +- “别人给我一个链接,我要拿下来” → 克隆/权限/打开项目 +- “我改完了,想保存并发给别人” → 查看改动/提交/推送 +- “我怕改坏,想留个版本” → 本地提交或备份分支,按复杂度选择 +- “提示要登录/没有权限” → 平台授权引导 +- “提示冲突/推不上去” → 解释有人也改了同一处,先保护本地改动再合并 +- “我要回到之前” → 明确是恢复文件、撤销未提交改动、还是回到某个历史版本 + +如果上下文已经足够,不要继续追问。直接说“我先帮你检查当前状态”。 + +### 2. 明确 AI 能帮什么 + +在开始前用一句话降低用户负担: + +> 我可以帮你检查当前文件状态、创建版本记录、连接远程仓库、同步到平台;你只需要在需要网页登录授权时确认账号,或者告诉我目标仓库链接。 + +避免说“你运行以下命令”。除非当前环境无法代办,才给用户步骤。 + +### 3. 检查当前状态并翻译结果 + +检查本地是否是仓库、是否有远程地址、当前有无未保存改动、是否已登录相关平台。回复用户时不要直接堆 `git status` 原文,先给可行动摘要: + +- “这个文件夹还不是仓库,我可以把它变成一个可记录版本的文件夹。” +- “它已经连接到远程平台,地址是 X。” +- “现在有 6 个文件改动了,还没有保存成版本。” +- “远程平台需要登录授权,接下来会打开/提供平台自己的登录流程。” + +需要展示命令输出时,只摘关键含义。 + +### 4. 授权引导要平台灵活 + +先识别远程 URL 或用户指定平台,再选择授权方式: + +- GitHub:优先 `gh auth status` / `gh auth login`;必要时解释浏览器 OAuth、SSH、token 的差异。 +- GitLab:优先平台 CLI 或 HTTPS token/SSH;自建 GitLab 注意域名和公司 SSO。 +- Gitee:常见为 HTTPS 凭证、私人令牌或 SSH key;不要套用 GitHub 文案。 +- Bitbucket:注意 workspace、app password、SSH。 +- 自建平台:先问/识别平台地址,按 HTTPS token、SSH key、公司 SSO 三类引导。 + +授权沟通规范: + +- 不要求用户把密码、token、私钥粘贴到聊天里。 +- 需要 token 时,引导用户在平台页面生成,并说明只保存到系统凭据/CLI,不在聊天中泄露。 +- 需要 SSH key 时,先检查是否已有可用 key;没有再创建,并指导用户把公钥加到平台。 +- 遇到 SSO/组织权限时,告诉用户“这是账号权限问题,不是你的文件坏了”。 + +## 复杂度控制 + +### 不主动引入分支 + +如果用户只想把个人文件夹放到远程、保存一版、拉取项目或同步改动,不主动讲分支。 + +只有在以下情况才引入分支: + +- 用户明确要多人协作或不想影响主版本 +- 当前仓库已有分支策略或保护规则 +- 需要在不动主线的情况下尝试修改 +- 提交到主分支被拒绝,需要通过 PR/MR + +第一次解释分支时保持短句: + +> 分支可以理解成一份独立草稿。你可以在草稿里改,确认没问题后再合到正式版本。 + +不要一开始讲 rebase、cherry-pick、worktree、detached HEAD。 + +### 冲突处理面向结果 + +冲突不是“报错”,而是“同一处内容有两份修改,系统不知道该选哪份”。 + +处理前先说明: + +- 你的本地改动还在 +- 远程也有别人/另一台设备的改动 +- 我会先帮你看冲突位置,再让你决定保留哪部分或合并两边 + +如果用户不懂代码,优先生成“冲突内容对照摘要”,不要让用户读冲突标记。 + +### 版本恢复先问恢复粒度 + +用户说“还原/回退/恢复”时,先判断是哪一种: + +- 只撤销还没保存成版本的本地修改 +- 找回某个被删文件 +- 查看之前某个版本 +- 把整个项目回到某个历史版本 +- 远程也要同步回退 + +远程回退、强推、删除历史前必须明确风险并取得确认。对非技术用户可说: + +> 这会改变团队平台上看到的历史版本,可能影响别人。我先给你一个不改远程历史的恢复方案。 + +## 推荐话术 + +### 初始化/首次同步 + +> 我先帮你确认这个文件夹是不是已经有版本记录。如果没有,我会把它变成一个仓库,然后再连接你选择的平台。这个过程不会改变文件内容,只是增加一套版本记录。 + +### 提交/保存版本 + +> 现在可以把这次改动保存成一个版本记录。提交信息我会写成人能看懂的一句话,方便以后知道这一版改了什么。 + +### 推送/同步 + +> 本地版本已经保存好了。下一步是同步到远程平台,这样团队或另一台电脑才能看到。 + +### 授权 + +> 这里需要你用平台账号授权。我不会让你把密码发给我;我们走平台自己的登录流程,完成后我再继续。 + +### 不确定平台 + +> 你用的是 GitHub、GitLab、Gitee、Bitbucket,还是公司自己的代码平台?如果你有仓库链接,直接发链接最省事。 + +## 操作规范 + +- 执行前先看 `git status`、远程地址和当前分支/默认线索;不要盲目提交或推送。 +- 提交前给用户一个简短变更摘要,确认是否包含敏感文件、临时文件、大文件、设计源文件。 +- 提交信息用用户能理解的语言,但保留常见规范。示例:`docs: update product requirements draft`、`feat: add onboarding flow mockup`。 +- 不把 `.env`、密钥、token、账号导出文件、个人隐私文件提交到仓库;发现时先提醒并处理忽略规则。 +- 不擅自执行 `git reset --hard`、`git clean -fd`、`git push --force`、删除远程分支、覆盖远程历史。 +- 如果工作区已有别人未说明的改动,不要回滚;先说明发现了哪些现有改动,并只处理用户当前目标相关内容。 +- 对新手用户优先给“下一步我来做什么”和“你需要确认什么”,少给完整命令列表。 + +## 交付要求 + +完成后用简短摘要告诉用户: + +- 当前状态:本地已保存/已连接远程/已同步/仍需授权/遇到冲突 +- 做了什么:初始化、克隆、提交、推送、恢复、创建 issue/PR/MR 等 +- 远程位置:仓库链接或远程地址(如果可用) +- 用户下一步:打开链接确认、邀请协作者、继续修改、等待权限、选择冲突保留内容 + +如果没有完成,说明卡在“权限、网络、平台限制、冲突选择、缺少仓库链接”中的哪一类,并给一个最短可继续步骤。 diff --git a/.gitignore b/.gitignore index 882f52b..3c2d4f5 100644 --- a/.gitignore +++ b/.gitignore @@ -133,6 +133,7 @@ storybook-static/ # Temporary folders tmp/ temp/ +.local/ # Git version management temporary files .git-versions/ diff --git a/package-lock.json b/package-lock.json index 14af0ad..d157858 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@axhub/annotation": "^1.0.10", "docx-preview": "^0.3.7", + "jszip": "^3.10.1", "lucide-react": "^0.562.0", "mammoth": "^1.12.0", "mermaid": "^11.16.0", diff --git a/package.json b/package.json index 5fea9eb..1146428 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "project-nav:sync": "node scripts/sync-project-prototype-directory.mjs", "nav:sync": "node scripts/sync-prototype-nav-registry.mjs", "nav:enrich-git": "node scripts/enrich-prototype-registry-from-git.mjs", + "release:changelog": "node scripts/apply-release-changelog.mjs", "nav:xll-sync": "node scripts/sync-xll-nav-menu.mjs", "oneos-web:sync": "node scripts/sync-oneos-web-prototypes.mjs && node scripts/scan-entries.js && npm run metadata:sync", "build": "node scripts/sync-vendor-if-present.mjs && node scripts/scan-entries.js && node scripts/build-all.js", @@ -50,6 +51,7 @@ "dependencies": { "@axhub/annotation": "^1.0.10", "docx-preview": "^0.3.7", + "jszip": "^3.10.1", "lucide-react": "^0.562.0", "mammoth": "^1.12.0", "mermaid": "^11.16.0", diff --git a/scripts/apply-release-changelog.mjs b/scripts/apply-release-changelog.mjs new file mode 100644 index 0000000..7c10d7e --- /dev/null +++ b/scripts/apply-release-changelog.mjs @@ -0,0 +1,293 @@ +/** + * 将版本发布的功能变更说明写入 prototype-registry.json(覆盖 commit 131b963 对应条目)。 + * + * 用法:node scripts/apply-release-changelog.mjs + */ +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const projectRoot = path.resolve(__dirname, '..'); +const REGISTRY_PATH = path.join(projectRoot, 'src/prototypes/oneos-prototype-nav/prototype-registry.json'); +const RELEASE_COMMIT = '131b963'; +const RELEASE_DATE = '2026-07-12'; +const RELEASE_TIME = '22:45'; +const MAX_RECENT = 40; + +/** @type {Record} */ +const RELEASE_NOTES = { + 'oneos-prototype-nav': { + summary: '统一标注壳与操作规范,租赁明细/合同/提车应收款增强,新增任务工单,同步合包页面', + details: [ + '【平台】全项目接入 PrototypeAnnotationHost,PRD 迁入右侧标注目录;列表统一 OperationActions 与工具栏图标规范', + '【租赁业务明细】收款状态列、47 列宽表、氢费钻取、字段校验、变更记录、导入导出与主管解锁', + '【租赁合同】KPI/状态收敛、查看页、线上/线下签署、交付变更、附加费用与提车应收联动', + '【提车应收款】独立原型上线;finance 合包仅保留租赁账单;工作台快捷入口改跳独立原型', + '【任务工单】新增业管发起端:合同/独立双入口、六类任务类型与督办催办', + '【合包】business/ops/finance/ledger-data/lease-contract/h2-station 等移除面包屑并标准化操作区', + '【下线】移除 login/requirements/vehicle-asset 合包;侧栏新增任务工单与提车应收款', + '【发布】导航页固定发布至 /oneos-prototype-nav/index.html', + ], + }, + 'lease-business-detail': { + summary: '租赁业务明细大改版:收款状态、47 列宽表、字段校验与变更记录', + details: [ + '新增收款状态列(未收款/部分收款/已结清);月份、部门+业务员合并展示;表尾 23 项金额汇总', + '氢费可钻取 Popover;编辑/删除/变更记录;公式列(应收合计、未收、盈亏、氢费等)自动重算', + '客户/提车日期/租金等与车辆/客户/合同交叉校验,支持一键替换建议值', + '批量导入 36 列手工字段、导出 47 列;部分成功 + 错误日志;已对账锁定与主管解锁', + ], + }, + 'lease-contract-management': { + summary: '租赁合同增强:KPI/状态收敛、查看页、签署方式与提车应收联动', + details: [ + '列表 KPI:全部/草稿/进行中/审批中/已终止;合同状态收敛;在租车队 KPI 迁至车辆管理', + '筛选:合同模板类型 + 标准合同名称二级联动;统一流程入口(新增/续签/转正式/增车等)', + '新增只读查看页;线上电子签章 / 线下人工上传;主动终止与交付安排变更(Cascader/TBD)', + '附加费用拆分已有/新增服务项;红线条款 + 新增条款检测;先付后用/先用后付', + '提交审批与交付计划变更同步提车应收 bridge', + ], + }, + 'lease-business-ledger': { + summary: '租赁业务台账:操作区统一为 OperationActions,标注壳切换', + details: [ + '行操作:编辑 / 操作记录 / 保存(编辑态)', + '关联收款、事故/维保/收据链接弹窗保留', + '接入 PrototypeAnnotationHost,移除内嵌原型导航目录', + ], + }, + 'self-operated-business-ledger': { + summary: '物流业务明细:更名、列对齐 Excel、批量导入与自动计算', + details: [ + '模块更名:物流业务台账 → 物流业务明细', + '列对齐 Excel 1.2:薪资、电费、日社保/挂车/停车/轮胎、线路计价等;系统车型列', + '新增批量导入:模板下载、错误日志、导入后自动计算金额/总成本/盈亏', + '移除行勾选与批量删除', + ], + }, + 'business-dept-ledger': { + summary: '业务部台账:分组表头与表格可读性增强', + details: [ + '统一边框 token、分组表头双层样式(业务板块 + 业绩/成本/盈亏)', + '冻结列滚动修复;金额列防裁切;盈亏钻取链接样式调整', + ], + }, + 'vehicle-management': { + summary: '车辆管理:在租车队 KPI 迁入、车型分布弹窗与列表样式优化', + details: [ + '在租车队 KPI 从租赁合同列表迁入;按品牌型号统计在租数量', + '车型分布弹窗:品牌筛选、车型卡片、占比进度条、车辆明细', + '详情 Tab 与列表筛选/导入/KPI 操作区统一;表格样式优化', + ], + }, + 'customer-management': { + summary: '客户管理:OperationActions 统一操作列,移除面包屑', + details: [ + '列表操作:详情 / 编辑 / 管理标签 / 删除', + '风险标签、批量打标等业务逻辑不变', + ], + }, + 'contract-template-management': { + summary: '合同模板:启用/停用、先付后用/先用后付变量与操作区重构', + details: [ + '行操作:编辑 + 更多(启用/停用、版本日志、删除);启用中不可编辑/删除', + '模板变量新增 paymentMethod;付款周期与氢费结算文案更新', + ], + }, + 'insurance-procurement': { + summary: '保险采购:OperationActions 统一操作列', + details: [ + '保单列表:编辑 / 预览 / 下载 / 更多', + '标注壳切换', + ], + }, + 'vehicle-pickup-receivable': { + summary: '提车应收款独立原型上线:自动生成/手动办理与合同双向联动', + details: [ + '收款情况列:租车数 / 已提车(Popover 钻取)', + '合同提交审批即生成主表;有交付时间则提前 2 天生成应收', + '手动办理勾选品牌型号与交付时间;15 日前/后分档计费规则', + '与租赁合同 bridge 联动;finance 合包剥离;工作台入口改跳本原型', + ], + }, + 'task-work-order': { + summary: '任务工单新原型:业管发起端(合同/独立双入口)', + details: [ + '任务类型:里程履约、维保履约、政策兑现、付款/交付节点、条款跟进、通用临时', + '列表 KPI:全部/我发布的/我督办的 + 状态视角;详情含进度、反馈、催办', + '执行人不可见合同原文与金额(第一版仅业管端)', + ], + }, + 'payment-records': { + summary: '收款记录:OperationActions 与关联账单操作', + details: [ + '操作列标准化;表格新增「关联账单」', + '标注壳切换', + ], + }, + 'supplier-management': { + summary: '供应商管理:工具栏与操作区图标标准化', + details: [ + '新增供应商按钮图标统一;删除收入 OperationActions', + ], + }, + 'oneos-web-business': { + summary: '业务管理合包:18 页移除面包屑,OperationActions 统一', + details: [ + '保险采购、交车任务、客户/供应商、租赁账单、ETC 管理等页操作区标准化', + ], + }, + 'oneos-web-ops': { + summary: '运维管理合包:45 页操作列与工具栏按钮标准化', + details: [ + '备件/调拨/交还车/故障/异动/证件/型号参数等页 OperationActions 与 data-vm-icon 图标', + ], + }, + 'oneos-web-finance': { + summary: '财务管理合包:提车应收款剥离,仅保留租赁账单', + details: [ + '提车应收款 6 页移除;合包默认页改为租赁账单', + '提车流程由 vehicle-pickup-receivable 独立原型承接', + ], + }, + 'oneos-web-ledger-data': { + summary: '台账数据合包:5 页操作区标准化', + details: [ + '保险分摊、氢费、维修明细、氢费采购端汇总、租赁业务台账等页 OperationActions', + ], + }, + 'oneos-web-lease-contract': { + summary: '租赁合同合包:8 子页同步签署/流程字段与 OperationActions', + details: [ + '新增、续签、转正式、三方变更、附加费用等子页操作区标准化', + '修复移除面包屑后的 JSX 括号语法', + ], + }, + 'oneos-web-data-analysis': { + summary: '数据分析合包:业务部台账列宽与盈亏着色优化', + details: [ + '9 页操作区标准化;业务部台账列宽加大;盈亏负值着色', + ], + }, + 'oneos-web-h2-station': { + summary: '加氢站合包:站点信息编辑提升为主操作', + details: [ + '加氢订单/记录/站点信息 3 页 OperationActions;站点编辑不再藏在「更多」', + ], + }, + 'oneos-web-workbench': { + summary: '工作台:提车应收款快捷入口改跳独立原型', + details: [ + '快捷入口指向 /prototypes/vehicle-pickup-receivable', + 'protoNav 支持直接 location 跳转原型 URL', + ], + }, + 'oneos-web-contract-template': { + summary: '合同模板合包:操作区与独立原型对齐', + details: ['模板管理页 OperationActions 统一'], + }, + 'oneos-web-procurement': { + summary: '采购管理合包:三方退租车页操作区标准化', + details: ['退租申请与管理页 OperationActions'], + }, + 'oneos-web-h2-station-site': { + summary: '站点信息:标注目录清理', + details: ['移除内嵌原型导航节点;标注壳切换'], + }, + 'lease-business-line-overview': { + summary: '业务条线说明:标注目录微调', + details: ['条线数据更新;移除内嵌导航节点'], + }, + 'vehicle-h2-fee-ledger': { + summary: '车辆氢费明细:标注壳与操作区统一', + details: ['OperationActions;标注目录规范化'], + }, + 'vehicle-maintenance-ledger': { + summary: '车辆维修明细:标注壳与操作区统一', + details: ['OperationActions;标注目录规范化'], + }, + 'vehicle-return-settlement-v2': { + summary: '还车应结算 V2:OperationActions 统一为详情主操作', + details: ['列表操作列标准化'], + }, +}; + +function readJson(filePath) { + return JSON.parse(fs.readFileSync(filePath, 'utf8')); +} + +function writeJson(filePath, value) { + fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8'); +} + +function applyReleaseNotes(registry) { + let updated = 0; + for (const [prototypeId, notes] of Object.entries(RELEASE_NOTES)) { + const record = registry.prototypes?.[prototypeId]; + if (!record) continue; + + const changelog = Array.isArray(record.changelog) ? [...record.changelog] : []; + let targetIndex = changelog.findIndex((entry) => entry.commit === RELEASE_COMMIT); + if (targetIndex < 0 && changelog.length > 0) targetIndex = 0; + + const base = targetIndex >= 0 ? changelog[targetIndex] : { + version: record.version, + date: RELEASE_DATE, + time: RELEASE_TIME, + files: record.trackedFiles?.slice(0, 12) || [], + }; + + const nextEntry = { + ...base, + date: RELEASE_DATE, + time: RELEASE_TIME, + summary: notes.summary, + details: notes.details, + commit: RELEASE_COMMIT, + }; + + if (targetIndex >= 0) { + changelog[targetIndex] = nextEntry; + } else { + changelog.unshift(nextEntry); + } + + record.changelog = changelog.slice(0, 30); + record.lastUpdated = `${RELEASE_DATE}T14:45:00.000Z`; + updated += 1; + } + + const recent = []; + for (const [prototypeId, notes] of Object.entries(RELEASE_NOTES)) { + const record = registry.prototypes?.[prototypeId]; + if (!record) continue; + const entry = record.changelog?.[0]; + if (!entry) continue; + recent.push({ + prototypeId, + title: record.title || prototypeId, + version: entry.version || record.version, + date: entry.date || RELEASE_DATE, + time: entry.time || RELEASE_TIME, + summary: notes.summary, + details: notes.details, + files: entry.files || [], + }); + } + + recent.sort((a, b) => { + const ta = new Date(`${a.date}T${a.time}:00+08:00`).getTime(); + const tb = new Date(`${b.date}T${b.time}:00+08:00`).getTime(); + return tb - ta; + }); + + registry.recentUpdates = recent.slice(0, MAX_RECENT); + registry.updatedAt = `${RELEASE_DATE}T14:45:00.000Z`; + return updated; +} + +const registry = readJson(REGISTRY_PATH); +const count = applyReleaseNotes(registry); +writeJson(REGISTRY_PATH, registry); +console.log(`完成:已写入 ${count} 个原型的版本发布变更说明(commit ${RELEASE_COMMIT})`); diff --git a/scripts/publish-all-to-s3.mjs b/scripts/publish-all-to-s3.mjs index bbc30fa..57dcddd 100644 --- a/scripts/publish-all-to-s3.mjs +++ b/scripts/publish-all-to-s3.mjs @@ -54,6 +54,7 @@ function readS3Config() { } return { ...s3, + pathAliases: s3.pathAliases && typeof s3.pathAliases === 'object' ? s3.pathAliases : {}, includeSource: raw?.cloudPublishing?.publishSettings?.includeSource !== false, }; } @@ -63,7 +64,10 @@ function toPublishPath(resource) { return String(raw).replace(/\\/gu, '/').replace(/\/index\.tsx?$/iu, ''); } -function resolveObjectPrefix(entry) { +function resolveObjectPrefix(entry, pathAliases = {}) { + const alias = pathAliases[entry.id]; + if (alias) return String(alias).replace(/^\/+|\/+$/gu, ''); + const normalized = entry.path.replace(/^\/+|\/+$/gu, ''); const prototypeMatch = normalized.match(/^(?:src\/)?prototypes\/(.+)$/u); if (prototypeMatch?.[1]) return `prototypes/${prototypeMatch[1]}`; @@ -97,7 +101,7 @@ function guessContentType(filePath) { return map[ext] || 'application/octet-stream'; } -async function collectPublishEntries(adminOrigin, projectId, groupFilter) { +async function collectPublishEntries(adminOrigin, projectId, groupFilter, pathAliases = {}) { const res = await fetch(`${adminOrigin}/api/projects/${encodeURIComponent(projectId)}/resources`); if (!res.ok) { throw new Error(`GET /api/projects/${projectId}/resources failed: ${res.status}`); @@ -114,7 +118,7 @@ async function collectPublishEntries(adminOrigin, projectId, groupFilter) { id: item.id, title: item.title || item.id, path: publishPath, - prefix: resolveObjectPrefix({ path: publishPath, id: item.id }), + prefix: resolveObjectPrefix({ path: publishPath, id: item.id }, pathAliases), }); } } @@ -223,7 +227,7 @@ async function main() { const adminOrigin = resolveAdminOrigin(args.adminOrigin); const s3Config = readS3Config(); const includeSource = args.includeSource && s3Config.includeSource; - const entries = await collectPublishEntries(adminOrigin, args.projectId, args.group); + const entries = await collectPublishEntries(adminOrigin, args.projectId, args.group, s3Config.pathAliases); console.log(`Admin: ${adminOrigin}`); console.log(`Bucket: ${s3Config.bucket}`); diff --git a/scripts/sync-project-prototype-directory.mjs b/scripts/sync-project-prototype-directory.mjs index 27fc9a5..72bab96 100644 --- a/scripts/sync-project-prototype-directory.mjs +++ b/scripts/sync-project-prototype-directory.mjs @@ -117,11 +117,16 @@ function cleanupPrototypeDirectory(prototypeId, projectRoot) { return true; } +function filterNavMenuPrototypes(sidebarItems) { + return sidebarItems.filter((node) => node?.kind === 'folder' && node?.title === 'OneOS'); +} + function syncPrototypeNavMenu(projectRoot, sidebarItems) { const navMenuPath = path.join(projectRoot, 'src/prototypes/oneos-prototype-nav/nav-menu.json'); if (!fs.existsSync(path.dirname(navMenuPath))) return false; - writeJson(navMenuPath, { prototypes: sidebarItems }); - console.log('[sync] oneos-prototype-nav: 已更新 nav-menu.json'); + const filtered = filterNavMenuPrototypes(sidebarItems); + writeJson(navMenuPath, { prototypes: filtered }); + console.log(`[sync] oneos-prototype-nav: 已更新 nav-menu.json(${filtered.length} 个分区)`); return true; } diff --git a/scripts/sync-prototype-nav-registry.mjs b/scripts/sync-prototype-nav-registry.mjs index 584b917..e8e28e9 100644 --- a/scripts/sync-prototype-nav-registry.mjs +++ b/scripts/sync-prototype-nav-registry.mjs @@ -167,6 +167,17 @@ function diffChangedFiles(previousFiles, currentFiles) { return currentFiles.filter((file) => !prevSet.has(file)); } +/** 仅标注/批注文件变动时不自动递增版本(避免 dev 保存刷屏) */ +function isAnnotationOnlyChange(changedFiles) { + if (!changedFiles.length) return false; + return changedFiles.every((file) => ( + file === 'annotation-source.json' + || file.endsWith('/annotation-source.json') + || file.includes('prototype-comments') + || (file.includes('.spec/') && file.endsWith('.md') && !file.includes('requirements-prd')) + )); +} + function bumpVersion(revision) { return `v1.${revision}`; } @@ -211,6 +222,14 @@ function upsertPrototypeRecord(registry, prototypeId, title, contentHash, files, } const changedFiles = diffChangedFiles(existing.trackedFiles, files); + if (!options.note && isAnnotationOnlyChange(changedFiles.length ? changedFiles : files)) { + existing.title = title; + existing.contentHash = contentHash; + existing.trackedFiles = files; + registry.prototypes[prototypeId] = existing; + return { changed: false, entry: null }; + } + const summary = summarizeChange(changedFiles.length ? changedFiles : files, options.note); const nextRevision = (existing.revision || 0) + 1; const version = bumpVersion(nextRevision); diff --git a/src/prototypes/contract-template-management/contract-template-docx-fidelity.js b/src/prototypes/contract-template-management/contract-template-docx-fidelity.js index f046c50..4b24e4c 100644 --- a/src/prototypes/contract-template-management/contract-template-docx-fidelity.js +++ b/src/prototypes/contract-template-management/contract-template-docx-fidelity.js @@ -1,7 +1,7 @@ /** * docx-preview 高保真 Word 渲染(预览区) + * 使用动态 import,避免阻塞原型入口模块加载。 */ -import { renderAsync } from 'docx-preview'; var DEFAULT_RENDER_OPTIONS = { className: 'ct-docx-preview', @@ -18,6 +18,11 @@ var DEFAULT_RENDER_OPTIONS = { export async function renderDocxPreview(container, arrayBuffer, options) { if (!container || !arrayBuffer) return; container.innerHTML = ''; + var mod = await import('docx-preview'); + var renderAsync = mod.renderAsync; + if (typeof renderAsync !== 'function') { + throw new Error('docx-preview 模块未正确加载'); + } await renderAsync( arrayBuffer, container, diff --git a/src/prototypes/contract-template-management/contract-template-word-import.js b/src/prototypes/contract-template-management/contract-template-word-import.js index d07d509..e39e8e3 100644 --- a/src/prototypes/contract-template-management/contract-template-word-import.js +++ b/src/prototypes/contract-template-management/contract-template-word-import.js @@ -2,6 +2,7 @@ * Word (.doc / .docx) → HTML 导入 */ import mammoth from 'mammoth'; +import JSZip from 'jszip'; var MAMMOTH_STYLE_MAP = [ "p[style-name='Title'] => h1.ct-word-doc-title:fresh", @@ -94,7 +95,6 @@ export function extractInlineStylesFromImportedHtml(html) { export async function extractDocxThemeStyles(arrayBuffer) { try { - var JSZip = (await import('jszip')).default; var zip = await JSZip.loadAsync(arrayBuffer); var stylesFile = zip.file('word/styles.xml'); if (!stylesFile) return ''; diff --git a/src/prototypes/lease-business-detail/.spec/requirements-prd.md b/src/prototypes/lease-business-detail/.spec/requirements-prd.md index 70660f5..089fb39 100644 --- a/src/prototypes/lease-business-detail/.spec/requirements-prd.md +++ b/src/prototypes/lease-business-detail/.spec/requirements-prd.md @@ -13,14 +13,14 @@ | 预览地址 | `/prototypes/lease-business-detail` | | 目标用户 | 业务二部业管 / 运营人员 | | 核心任务 | 按 Excel 样表维护租赁车辆收入明细、查询汇总、批量导入导出 | -| 页面结构 | 筛选区 + 7 项 KPI + 工具栏 + 47 列宽表(表尾 23 项汇总)+ 分页 | +| 页面结构 | 筛选区 + 7 项 KPI + 工具栏 + 48 列宽表(表尾 23 项汇总)+ 分页 | | 设计基底 | `vm-page` + `ldb-page` + `lc-page`(见 `ledger-shared/DESIGN.md`) | ### 与「租赁业务台账」的分工 | 模块 | 定位 | |---|---| -| **租赁业务明细**(本模块) | 对齐业管 Excel 运营台账宽表;手工列导入维护;6 个公式列自动计算;**不**做收款关联与账单状态 | +| **租赁业务明细**(本模块) | 对齐业管 Excel 运营台账宽表;手工列导入维护;6 个公式列自动计算;收款状态按实收/应收展示 | | **租赁业务台账** | 账单维度维护、关联收款记录、收款状态(未收/部分/已收)、归档与角色数据范围 | 下游 **业务部台账 / 业务汇总分析** 中「租赁业绩」数据来源为本模块明细(见 `oneos-web-data-analysis/05-业务部台账`)。 @@ -28,15 +28,14 @@ ### 不做范围(当前原型) - 「租赁业务盈亏月度汇总」独立 Tab(Legacy 数据分析页有,本原型待规划) -- 行内编辑、删除、服务端持久化 +- 服务端持久化、员工/主管数据权限隔离(主管预览:`?role=supervisor`) - 关联收款记录自动回写实收 -- 员工/主管数据权限隔离 --- ## 2. 筛选区 -默认展示 4 项(一行),「更多筛选」展开车牌多选。 +默认展示 5 项(一行),「更多筛选」展开车牌多选。 | 筛选项 | 说明 | |---|---| @@ -44,6 +43,7 @@ | 业务部门 | 精确匹配 | | 业务员 | 精确匹配 | | 客户名称 | 模糊包含 | +| 状态 | 已结清 / 部分收款 / 未收款(按实收与应收合计计算) | | 车牌号码 | 多选精确匹配(更多筛选) | 查询按钮触发筛选;KPI 与表尾汇总基于**全量筛选结果**(非当前页)。 @@ -70,28 +70,36 @@ | 按钮 | 行为 | |---|---| -| 批量导入 | 下载模板(仅手工录入列)→ 上传 Excel → 公式列自动计算 | -| 批量导出 | 导出当前筛选结果(完整 47 列,含公式列结果) | +| 批量导入 | 下载模板(36 列手工录入)→ 上传 Excel → 公式列自动计算 | +| 批量导出 | 导出当前筛选结果(完整 48 列,含公式列结果) | -导入必填:**年份、月份、车牌号码**。 +### 行内操作 + +编辑、删除、变更日志(操作列);已锁定记录仅主管可改(`?role=supervisor`)。 --- -## 5. 明细列表(47 列) +## 5. 明细列表(48 列) -表头顺序严格对齐 Excel「2.租赁车辆收入明细表」: - -年份、月份、业务部门、业务员、付款日期、车牌号码、车型、客户名称、增值服务、享免政策、提车日期、合同生效日期、合同到期日期、起始日期、退车日期、平均天数、押金、合同标的租金、应收合计、应收租金、月度收入、月度租金、维保包干收入、保险上浮费、运维费(收入)、其他收入、里程减免金额、其他减免金额、实收金额、未收、开票日期、实际付款日期、付款方式、车辆标准成本、车辆实际成本、保险费、氢费、运维费(成本)、居间费、其他、总成本、盈亏、GPS里程、其他减免金额明细内容、资产归属、签约公司、备注。 +表头顺序对齐 Excel「2.租赁车辆收入明细表」,并在月份列左侧增加「状态」列。 ### 交互 -- 横向滚动;左冻结:**年份 + 车牌号码** +- 横向滚动;左冻结:**状态 + 月份 + 车牌号码** - 仅**日期类列**表头支持正序/倒序排序 -- 公式列(`calculated`)浅灰底色,表示系统计算、导入模板不含 -- 表尾**汇总行**:23 个金额列 SUBTOTAL,首列显示「汇总」 +- 公式列(`calculated`)浅灰底色,导入模板不含 +- 表尾**汇总行**:23 个金额列 SUBTOTAL,月份列显示「汇总」 - 未收 > 0 单元格标红;盈亏正负着色 - 底部分页:10 / 20 / 50 / 100 +### 收款状态(状态列) + +| 状态 | 判定规则 | +|---|---| +| 未收款 | 实收金额 = 0 或未录入 | +| 部分收款 | 实收金额 > 0 且 < 应收合计 | +| 已结清 | 实收金额 ≥ 应收合计 | + ### 表尾汇总(23 项) 押金、合同标的租金、应收合计、应收租金、月度收入、月度租金、维保包干收入、保险上浮费、运维费(收入)、其他收入、里程减免金额、其他减免金额、实收金额、未收、车辆标准成本、车辆实际成本、保险费、氢费、运维费(成本)、居间费、其他、总成本、盈亏。 @@ -104,21 +112,15 @@ | 字段 | 计算方式 | |---|---| -| **应收合计** | 应收租金 + 维保包干收入 + 保险上浮费 + 运维费(收入) + 其他收入 + 里程减免 + 其他减免 | -| **月度收入** | 月度租金 + 同上调整项 | +| **应收合计** | 维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免 + 其他减免 | +| **月度收入** | 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免 + 其他减免 | | **未收** | 应收合计 − 实收金额 | | **车辆实际成本** | 车辆标准成本 × 平均天数 | -| **总成本** | 车辆实际成本 + 保险费 + 氢费 + 运维费(成本) + 居间费 + 其他 | +| **总成本** | 车辆实际成本 + 保险费 + 氢费 + 运维费(成本)+ 居间费 + 其他 | | **盈亏** | 月度收入 − 总成本 | 减免金额在 Excel 中以负数录入;导入时填负数即可。 -### 导入模板 - -- **含**:41 列手工录入字段(不含上述 6 列) -- **不含**:应收合计、月度收入、未收、车辆实际成本、总成本、盈亏 -- 导入后调用 `applyDetailCalculations` 统一重算 - --- ## 7. 样例数据 @@ -137,21 +139,22 @@ | 标注源 | `annotation-source.json` | | 列定义 | `components/tableColumns.ts` | | 筛选 / KPI 汇总 | `utils/detail.ts` | +| 收款状态 | `utils/payment-status.ts` | | 公式计算 | `utils/calc-detail.ts` | | 导入导出 | `utils/batch-io.ts` | +| 变更日志 | `utils/change-log.ts` | | 类型 | `types.ts` | -| 组件 | `components/FilterPanel.tsx`、`DetailKpiRow.tsx`、`DetailTable.tsx`、`DetailImportModal.tsx` | +| 组件 | `FilterPanel.tsx`、`DetailKpiRow.tsx`、`DetailTable.tsx`、`DetailImportModal.tsx`、`DetailEditModal.tsx`、`DetailChangeLogModal.tsx` | --- ## 9. 验收重点 -1. 表头 47 列顺序与 Excel 样表一致;双「运维费」列位置正确 +1. 筛选区含「状态」;状态列展示未收款 / 部分收款 / 已结清 2. 筛选后 KPI、表尾汇总与明细行合计一致 -3. 下载导入模板无 6 个公式列;导入后公式列自动计算且与 Excel 同口径 -4. 导出为完整 47 列 -5. 横向滚动与左冻结(年份、车牌)正常 -6. 未收 > 0 标红;盈亏正负着色 +3. 左冻结:状态 + 月份 + 车牌号码 +4. 氢费非零可点击明细;编辑/删除/变更日志可用 +5. 未收 > 0 标红;盈亏正负着色 --- @@ -162,4 +165,3 @@ - P1:盈亏月度汇总 Tab - P1:与租赁业务台账 / 收款模块集成口径 - P2:导入重复键(年+月+车牌)处理策略 -- P2:导入行级校验与实收 ≤ 应收校验 diff --git a/src/prototypes/lease-business-detail/annotation-source.json b/src/prototypes/lease-business-detail/annotation-source.json index d465132..d0ada91 100644 --- a/src/prototypes/lease-business-detail/annotation-source.json +++ b/src/prototypes/lease-business-detail/annotation-source.json @@ -5,7 +5,7 @@ "version": 2, "prototypeName": "lease-business-detail", "pageId": "list", - "updatedAt": 1783800844965, + "updatedAt": 1783906281870, "nodes": [ { "id": "lbd-filter", @@ -219,7 +219,7 @@ }, { "id": "lbd-col-status", - "index": 12, + "index": 11, "title": "状态", "pageId": "list", "locator": { @@ -240,7 +240,7 @@ }, { "id": "lbd-changelog-modal", - "index": 13, + "index": 12, "title": "变更日志", "pageId": "list", "locator": { @@ -284,7 +284,7 @@ "lbd-table": "## 5. 明细列表(48 列)\n\n表头顺序严格对齐 Excel「2.租赁车辆收入明细表」,并在月份列左侧增加「状态」列。\n\n### 交互\n\n- 横向滚动;左冻结:**状态 + 月份 + 车牌号码**\n- 仅**日期类列**表头支持正序/倒序排序\n- 公式列(calculated)浅灰底色,导入模板不含\n- 表尾**汇总行**:23 个金额列 SUBTOTAL,月份列显示「汇总」\n- 未收 > 0 单元格标红;盈亏正负着色\n- 底部分页:10 / 20 / 50 / 100\n\n### 收款状态(状态列)\n\n| 状态 | 判定规则 |\n|---|---|\n| 未收款 | 实收金额 = 0 或未录入 |\n| 部分收款 | 实收金额 > 0 且 < 应收合计 |\n| 已结清 | 实收金额 ≥ 应收合计 |\n\n### 表尾汇总(23 项)\n\n押金、合同标的租金、应收合计、应收租金、月度收入、月度租金、维保包干收入、保险上浮费、运维费(收入)、其他收入、里程减免金额、其他减免金额、实收金额、未收、车辆标准成本、车辆实际成本、保险费、氢费、运维费(成本)、居间费、其他、总成本、盈亏。\n\n---", "lbd-doc-formulas": "## 6. 公式列(系统自动计算)\n\n对齐 Excel 表内公式;实现见 `utils/calc-detail.ts`。\n\n| 字段 | 计算方式 |\n|---|---|\n| **应收合计** | 维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免金额(负数)+ 其他减免金额(负数) |\n| **月度收入** | 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免 + 其他减免 |\n| **未收** | 应收合计 − 实收金额 |\n| **车辆实际成本** | 车辆标准成本 × 平均天数 |\n| **总成本** | 车辆实际成本 + 保险费 + 氢费 + 运维费(成本)+ 居间费 + 其他 |\n| **盈亏** | 月度收入 − 总成本 |\n\n减免金额在 Excel 中以负数录入;导入时填负数即可。\n\n---", "lbd-doc-boundary": "## 模块边界\n\n### 与「租赁业务台账」的分工\n\n| 模块 | 定位 |\n|---|---|\n| **租赁业务明细**(本模块) | 对齐业管 Excel 运营台账宽表;手工列导入维护;6 个公式列自动计算;**不**做收款关联与账单状态 |\n| **租赁业务台账** | 账单维度维护、关联收款记录、收款状态(未收/部分/已收)、归档与角色数据范围 |\n\n下游 **业务部台账 / 业务汇总分析** 中「租赁业绩」数据来源为本模块明细。\n\n### 不做范围(当前原型)\n\n- 「租赁业务盈亏月度汇总」独立 Tab\n- 行内编辑、删除、服务端持久化\n- 关联收款记录自动回写实收\n- 员工/主管数据权限隔离\n\n---", - "lbd-doc-overview": "## 1. 模块定位\n\n| 项 | 说明 |\n|---|---|\n| 模块名称 | 台账数据 — 租赁业务明细 |\n| 目标用户 | 业务二部业管 / 运营人员 |\n| 核心任务 | 按 Excel 样表维护租赁车辆收入明细、查询汇总、批量导入导出 |\n| 页面结构 | 筛选区 + 7 项 KPI + 工具栏 + 47 列宽表(表尾 23 项汇总)+ 分页 |\n| 设计基底 | vm-page + ldb-page + lc-page |\n\n对齐 Excel《2026年业务二部运营台账总表》「2.租赁车辆收入明细表」。\n\n---", + "lbd-doc-overview": "## 1. 模块定位\n\n| 项 | 说明 |\n|---|---|\n| 模块名称 | 台账数据 — 租赁业务明细 |\n| 目标用户 | 业务二部业管 / 运营人员 |\n| 核心任务 | 按 Excel 样表维护租赁车辆收入明细、查询汇总、批量导入导出 |\n| 页面结构 | 筛选区 + 7 项 KPI + 工具栏 + 48 列宽表(表尾 23 项汇总)+ 分页 |\n| 设计基底 | vm-page + ldb-page + lc-page |\n\n对齐 Excel《2026年业务二部运营台账总表》「2.租赁车辆收入明细表」。\n\n---", "lbd-col-receivable-total": "## 应收合计\n\n**计算方式**:维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免金额(负数)+ 其他减免金额(负数)。\n**录入方式**:系统自动计算,只读。\n\n---", "lbd-col-outstanding": "## 未收\n\n**计算方式**:应收合计 − 实收金额。\n**录入方式**:系统自动计算,只读。\n\n---", "lbd-col-vehicle-actual-cost": "## 车辆实际成本\n\n**计算方式**:车辆实际成本 = 车辆标准成本 × 平均天数。\n**录入方式**:系统自动计算,只读。\n\n---", @@ -307,20 +307,20 @@ "type": "markdown", "id": "lbd-doc-overview", "title": "模块总览", - "markdown": "## 1. 模块定位\n\n| 项 | 说明 |\n|---|---|\n| 模块名称 | 台账数据 — 租赁业务明细 |\n| 目标用户 | 业务二部业管 / 运营人员 |\n| 核心任务 | 按 Excel 样表维护租赁车辆收入明细、查询汇总、批量导入导出 |\n| 页面结构 | 筛选区 + 7 项 KPI + 工具栏 + 47 列宽表(表尾 23 项汇总)+ 分页 |\n| 设计基底 | vm-page + ldb-page + lc-page |\n\n对齐 Excel《2026年业务二部运营台账总表》「2.租赁车辆收入明细表」。\n\n---" + "markdown": "## 1. 模块定位\n\n| 项 | 说明 |\n|---|---|\n| 模块名称 | 台账数据 — 租赁业务明细 |\n| 目标用户 | 业务二部业管 / 运营人员 |\n| 核心任务 | 按 Excel 样表维护租赁车辆收入明细、查询汇总、批量导入导出 |\n| 页面结构 | 筛选区 + 7 项 KPI + 工具栏 + 48 列宽表(表尾 23 项汇总)+ 分页 |\n| 设计基底 | vm-page + ldb-page + lc-page |\n\n对齐 Excel《2026年业务二部运营台账总表》「2.租赁车辆收入明细表」。\n\n---" }, { "type": "link", "id": "lbd-link-self", "title": "租赁业务明细原型", - "href": "./index.html", + "href": "/prototypes/lease-business-detail", "target": "self" }, { "type": "markdown", "id": "lbd-doc-prd", "title": "PRD 全文", - "markdown": "# 租赁业务明细 · 产品需求说明(PRD)\n\n> 对齐 Excel《2026年业务二部运营台账总表》「2.租赁车辆收入明细表」;业管人员按月份维护运营明细,公式列系统自动计算。\n\n---\n\n## 1. 模块定位\n\n| 项 | 说明 |\n|---|---|\n| 模块名称 | 台账数据 — 租赁业务明细 |\n| 原型路径 | `src/prototypes/lease-business-detail` |\n| 预览地址 | `/prototypes/lease-business-detail` |\n| 目标用户 | 业务二部业管 / 运营人员 |\n| 核心任务 | 按 Excel 样表维护租赁车辆收入明细、查询汇总、批量导入导出 |\n| 页面结构 | 筛选区 + 7 项 KPI + 工具栏 + 47 列宽表(表尾 23 项汇总)+ 分页 |\n| 设计基底 | `vm-page` + `ldb-page` + `lc-page`(见 `ledger-shared/DESIGN.md`) |\n\n### 与「租赁业务台账」的分工\n\n| 模块 | 定位 |\n|---|---|\n| **租赁业务明细**(本模块) | 对齐业管 Excel 运营台账宽表;手工列导入维护;6 个公式列自动计算;**不**做收款关联与账单状态 |\n| **租赁业务台账** | 账单维度维护、关联收款记录、收款状态(未收/部分/已收)、归档与角色数据范围 |\n\n下游 **业务部台账 / 业务汇总分析** 中「租赁业绩」数据来源为本模块明细(见 `oneos-web-data-analysis/05-业务部台账`)。\n\n### 不做范围(当前原型)\n\n- 「租赁业务盈亏月度汇总」独立 Tab(Legacy 数据分析页有,本原型待规划)\n- 行内编辑、删除、服务端持久化\n- 关联收款记录自动回写实收\n- 员工/主管数据权限隔离\n\n---\n\n## 2. 筛选区\n\n默认展示 4 项(一行),「更多筛选」展开车牌多选。\n\n| 筛选项 | 说明 |\n|---|---|\n| 统计月份 | `YYYY-MM` 格式,精确匹配年份+月份 |\n| 业务部门 | 精确匹配 |\n| 业务员 | 精确匹配 |\n| 客户名称 | 模糊包含 |\n| 车牌号码 | 多选精确匹配(更多筛选) |\n\n查询按钮触发筛选;KPI 与表尾汇总基于**全量筛选结果**(非当前页)。\n\n---\n\n## 3. KPI 统计卡片(7 张)\n\n顶部展示关键指标;完整 23 项金额合计见列表底部汇总行。\n\n| KPI | 汇总字段 |\n|---|---|\n| 应收总计 | `receivableTotal` |\n| 押金总计 | `deposit`(仅数值型) |\n| 实收总计 | `receivedAmount` |\n| 里程减免总计 | `mileageDeduction` |\n| 其他减免总计 | `otherDeduction` |\n| 未收总计 | `outstanding`(>0 标红) |\n| 盈亏总计 | `profitLoss`(正负着色) |\n\n---\n\n## 4. 列表工具栏\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板(仅手工录入列)→ 上传 Excel → 公式列自动计算 |\n| 批量导出 | 导出当前筛选结果(完整 47 列,含公式列结果) |\n\n导入必填:**年份、月份、车牌号码**。\n\n---\n\n## 5. 明细列表(47 列)\n\n表头顺序严格对齐 Excel「2.租赁车辆收入明细表」:\n\n年份、月份、业务部门、业务员、付款日期、车牌号码、车型、客户名称、增值服务、享免政策、提车日期、合同生效日期、合同到期日期、起始日期、退车日期、平均天数、押金、合同标的租金、应收合计、应收租金、月度收入、月度租金、维保包干收入、保险上浮费、运维费(收入)、其他收入、里程减免金额、其他减免金额、实收金额、未收、开票日期、实际付款日期、付款方式、车辆标准成本、车辆实际成本、保险费、氢费、运维费(成本)、居间费、其他、总成本、盈亏、GPS里程、其他减免金额明细内容、资产归属、签约公司、备注。\n\n### 交互\n\n- 横向滚动;左冻结:**年份 + 车牌号码**\n- 仅**日期类列**表头支持正序/倒序排序\n- 公式列(`calculated`)浅灰底色,表示系统计算、导入模板不含\n- 表尾**汇总行**:23 个金额列 SUBTOTAL,首列显示「汇总」\n- 未收 > 0 单元格标红;盈亏正负着色\n- 底部分页:10 / 20 / 50 / 100\n\n### 表尾汇总(23 项)\n\n押金、合同标的租金、应收合计、应收租金、月度收入、月度租金、维保包干收入、保险上浮费、运维费(收入)、其他收入、里程减免金额、其他减免金额、实收金额、未收、车辆标准成本、车辆实际成本、保险费、氢费、运维费(成本)、居间费、其他、总成本、盈亏。\n\n---\n\n## 6. 公式列(系统自动计算)\n\n对齐 Excel 表内公式;实现见 `utils/calc-detail.ts`。\n\n| 字段 | 计算方式 |\n|---|---|\n| **应收合计** | 应收租金 + 维保包干收入 + 保险上浮费 + 运维费(收入) + 其他收入 + 里程减免 + 其他减免 |\n| **月度收入** | 月度租金 + 同上调整项 |\n| **未收** | 应收合计 − 实收金额 |\n| **车辆实际成本** | 车辆标准成本 × 平均天数 |\n| **总成本** | 车辆实际成本 + 保险费 + 氢费 + 运维费(成本) + 居间费 + 其他 |\n| **盈亏** | 月度收入 − 总成本 |\n\n减免金额在 Excel 中以负数录入;导入时填负数即可。\n\n### 导入模板\n\n- **含**:41 列手工录入字段(不含上述 6 列)\n- **不含**:应收合计、月度收入、未收、车辆实际成本、总成本、盈亏\n- 导入后调用 `applyDetailCalculations` 统一重算\n\n---\n\n## 7. 样例数据\n\n- 文件:`data/rows.json`\n- 来源:Excel《2026年业务二部运营台账总表6.17 - 新版》2026 年 1–6 月明细\n- 条数:553 条;汇总与 Excel SUBTOTAL 行一致\n\n---\n\n## 8. 源码入口\n\n| 类型 | 路径 |\n|---|---|\n| 主入口 | `index.tsx` |\n| 标注源 | `annotation-source.json` |\n| 列定义 | `components/tableColumns.ts` |\n| 筛选 / KPI 汇总 | `utils/detail.ts` |\n| 公式计算 | `utils/calc-detail.ts` |\n| 导入导出 | `utils/batch-io.ts` |\n| 类型 | `types.ts` |\n| 组件 | `components/FilterPanel.tsx`、`DetailKpiRow.tsx`、`DetailTable.tsx`、`DetailImportModal.tsx` |\n\n---\n\n## 9. 验收重点\n\n1. 表头 47 列顺序与 Excel 样表一致;双「运维费」列位置正确\n2. 筛选后 KPI、表尾汇总与明细行合计一致\n3. 下载导入模板无 6 个公式列;导入后公式列自动计算且与 Excel 同口径\n4. 导出为完整 47 列\n5. 横向滚动与左冻结(年份、车牌)正常\n6. 未收 > 0 标红;盈亏正负着色\n\n---\n\n## 10. 待规划项(评审记录)\n\n详见 `.spec/prototype-review.md`:\n\n- P1:盈亏月度汇总 Tab\n- P1:与租赁业务台账 / 收款模块集成口径\n- P2:导入重复键(年+月+车牌)处理策略\n- P2:导入行级校验与实收 ≤ 应收校验\n", + "markdown": "# 租赁业务明细 · 产品需求说明(PRD)\n\n> 对齐 Excel《2026年业务二部运营台账总表》「2.租赁车辆收入明细表」;业管人员按月份维护运营明细,公式列系统自动计算。\n\n---\n\n## 1. 模块定位\n\n| 项 | 说明 |\n|---|---|\n| 模块名称 | 台账数据 — 租赁业务明细 |\n| 原型路径 | `src/prototypes/lease-business-detail` |\n| 预览地址 | `/prototypes/lease-business-detail` |\n| 目标用户 | 业务二部业管 / 运营人员 |\n| 核心任务 | 按 Excel 样表维护租赁车辆收入明细、查询汇总、批量导入导出 |\n| 页面结构 | 筛选区 + 7 项 KPI + 工具栏 + 48 列宽表(表尾 23 项汇总)+ 分页 |\n| 设计基底 | `vm-page` + `ldb-page` + `lc-page`(见 `ledger-shared/DESIGN.md`) |\n\n### 与「租赁业务台账」的分工\n\n| 模块 | 定位 |\n|---|---|\n| **租赁业务明细**(本模块) | 对齐业管 Excel 运营台账宽表;手工列导入维护;6 个公式列自动计算;收款状态按实收/应收展示 |\n| **租赁业务台账** | 账单维度维护、关联收款记录、收款状态(未收/部分/已收)、归档与角色数据范围 |\n\n下游 **业务部台账 / 业务汇总分析** 中「租赁业绩」数据来源为本模块明细(见 `oneos-web-data-analysis/05-业务部台账`)。\n\n### 不做范围(当前原型)\n\n- 「租赁业务盈亏月度汇总」独立 Tab(Legacy 数据分析页有,本原型待规划)\n- 服务端持久化、员工/主管数据权限隔离(主管预览:`?role=supervisor`)\n- 关联收款记录自动回写实收\n\n---\n\n## 2. 筛选区\n\n默认展示 5 项(一行),「更多筛选」展开车牌多选。\n\n| 筛选项 | 说明 |\n|---|---|\n| 统计月份 | `YYYY-MM` 格式,精确匹配年份+月份 |\n| 业务部门 | 精确匹配 |\n| 业务员 | 精确匹配 |\n| 客户名称 | 模糊包含 |\n| 状态 | 已结清 / 部分收款 / 未收款(按实收与应收合计计算) |\n| 车牌号码 | 多选精确匹配(更多筛选) |\n\n查询按钮触发筛选;KPI 与表尾汇总基于**全量筛选结果**(非当前页)。\n\n---\n\n## 3. KPI 统计卡片(7 张)\n\n顶部展示关键指标;完整 23 项金额合计见列表底部汇总行。\n\n| KPI | 汇总字段 |\n|---|---|\n| 应收总计 | `receivableTotal` |\n| 押金总计 | `deposit`(仅数值型) |\n| 实收总计 | `receivedAmount` |\n| 里程减免总计 | `mileageDeduction` |\n| 其他减免总计 | `otherDeduction` |\n| 未收总计 | `outstanding`(>0 标红) |\n| 盈亏总计 | `profitLoss`(正负着色) |\n\n---\n\n## 4. 列表工具栏\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板(36 列手工录入)→ 上传 Excel → 公式列自动计算 |\n| 批量导出 | 导出当前筛选结果(完整 48 列,含公式列结果) |\n\n### 行内操作\n\n编辑、删除、变更日志(操作列);已锁定记录仅主管可改(`?role=supervisor`)。\n\n---\n\n## 5. 明细列表(48 列)\n\n表头顺序对齐 Excel「2.租赁车辆收入明细表」,并在月份列左侧增加「状态」列。\n\n### 交互\n\n- 横向滚动;左冻结:**状态 + 月份 + 车牌号码**\n- 仅**日期类列**表头支持正序/倒序排序\n- 公式列(`calculated`)浅灰底色,导入模板不含\n- 表尾**汇总行**:23 个金额列 SUBTOTAL,月份列显示「汇总」\n- 未收 > 0 单元格标红;盈亏正负着色\n- 底部分页:10 / 20 / 50 / 100\n\n### 收款状态(状态列)\n\n| 状态 | 判定规则 |\n|---|---|\n| 未收款 | 实收金额 = 0 或未录入 |\n| 部分收款 | 实收金额 > 0 且 < 应收合计 |\n| 已结清 | 实收金额 ≥ 应收合计 |\n\n### 表尾汇总(23 项)\n\n押金、合同标的租金、应收合计、应收租金、月度收入、月度租金、维保包干收入、保险上浮费、运维费(收入)、其他收入、里程减免金额、其他减免金额、实收金额、未收、车辆标准成本、车辆实际成本、保险费、氢费、运维费(成本)、居间费、其他、总成本、盈亏。\n\n---\n\n## 6. 公式列(系统自动计算)\n\n对齐 Excel 表内公式;实现见 `utils/calc-detail.ts`。\n\n| 字段 | 计算方式 |\n|---|---|\n| **应收合计** | 维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免 + 其他减免 |\n| **月度收入** | 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免 + 其他减免 |\n| **未收** | 应收合计 − 实收金额 |\n| **车辆实际成本** | 车辆标准成本 × 平均天数 |\n| **总成本** | 车辆实际成本 + 保险费 + 氢费 + 运维费(成本)+ 居间费 + 其他 |\n| **盈亏** | 月度收入 − 总成本 |\n\n减免金额在 Excel 中以负数录入;导入时填负数即可。\n\n---\n\n## 7. 样例数据\n\n- 文件:`data/rows.json`\n- 来源:Excel《2026年业务二部运营台账总表6.17 - 新版》2026 年 1–6 月明细\n- 条数:553 条;汇总与 Excel SUBTOTAL 行一致\n\n---\n\n## 8. 源码入口\n\n| 类型 | 路径 |\n|---|---|\n| 主入口 | `index.tsx` |\n| 标注源 | `annotation-source.json` |\n| 列定义 | `components/tableColumns.ts` |\n| 筛选 / KPI 汇总 | `utils/detail.ts` |\n| 收款状态 | `utils/payment-status.ts` |\n| 公式计算 | `utils/calc-detail.ts` |\n| 导入导出 | `utils/batch-io.ts` |\n| 变更日志 | `utils/change-log.ts` |\n| 类型 | `types.ts` |\n| 组件 | `FilterPanel.tsx`、`DetailKpiRow.tsx`、`DetailTable.tsx`、`DetailImportModal.tsx`、`DetailEditModal.tsx`、`DetailChangeLogModal.tsx` |\n\n---\n\n## 9. 验收重点\n\n1. 筛选区含「状态」;状态列展示未收款 / 部分收款 / 已结清\n2. 筛选后 KPI、表尾汇总与明细行合计一致\n3. 左冻结:状态 + 月份 + 车牌号码\n4. 氢费非零可点击明细;编辑/删除/变更日志可用\n5. 未收 > 0 标红;盈亏正负着色\n\n---\n\n## 10. 待规划项(评审记录)\n\n详见 `.spec/prototype-review.md`:\n\n- P1:盈亏月度汇总 Tab\n- P1:与租赁业务台账 / 收款模块集成口径\n- P2:导入重复键(年+月+车牌)处理策略\n", "markdownPath": "src/prototypes/lease-business-detail/.spec/requirements-prd.md" }, { @@ -345,33 +345,33 @@ "type": "markdown", "id": "lbd-doc-lbd-toolbar", "title": "批量导入导出", - "markdown": "## 4. 列表工具栏\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板(仅 41 列手工录入)→ 上传 Excel → 公式列自动计算 |\n| 批量导出 | 导出当前筛选结果(完整 47 列,含公式列结果) |\n\n导入必填:**年份、月份、车牌号码**。\n\n### 导入模板列范围\n\n- **含**:41 列手工录入字段\n- **不含**:应收合计、月度收入、未收、车辆实际成本、总成本、盈亏(6 个公式列)\n- 导入后调用 `applyDetailCalculations` 统一重算\n\n---" + "markdown": "## 4. 列表工具栏\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板(36 列手工录入)→ 上传 Excel → 公式列自动计算 |\n| 批量导出 | 导出当前筛选结果(完整 47 列,含公式列结果) |\n\n导入必填见模板说明。\n\n### 权限\n\n- 默认业管人员可编辑、删除明细记录\n- 主管预览:URL 追加 `?role=supervisor`(可修改已锁定记录)\n\n---" }, { "type": "markdown", "id": "lbd-doc-lbd-table", "title": "明细列表", - "markdown": "## 5. 明细列表(47 列)\n\n表头顺序严格对齐 Excel「2.租赁车辆收入明细表」。\n\n### 交互\n\n- 横向滚动;左冻结:**年份 + 车牌号码**\n- 仅**日期类列**表头支持正序/倒序排序\n- 公式列(calculated)浅灰底色,导入模板不含\n- 表尾**汇总行**:23 个金额列 SUBTOTAL,首列显示「汇总」\n- 未收 > 0 单元格标红;盈亏正负着色\n- 底部分页:10 / 20 / 50 / 100\n\n### 表尾汇总(23 项)\n\n押金、合同标的租金、应收合计、应收租金、月度收入、月度租金、维保包干收入、保险上浮费、运维费(收入)、其他收入、里程减免金额、其他减免金额、实收金额、未收、车辆标准成本、车辆实际成本、保险费、氢费、运维费(成本)、居间费、其他、总成本、盈亏。\n\n---" + "markdown": "## 5. 明细列表(48 列)\n\n表头顺序严格对齐 Excel「2.租赁车辆收入明细表」,并在月份列左侧增加「状态」列。\n\n### 交互\n\n- 横向滚动;左冻结:**状态 + 月份 + 车牌号码**\n- 仅**日期类列**表头支持正序/倒序排序\n- 公式列(calculated)浅灰底色,导入模板不含\n- 表尾**汇总行**:23 个金额列 SUBTOTAL,月份列显示「汇总」\n- 未收 > 0 单元格标红;盈亏正负着色\n- 底部分页:10 / 20 / 50 / 100\n\n### 收款状态(状态列)\n\n| 状态 | 判定规则 |\n|---|---|\n| 未收款 | 实收金额 = 0 或未录入 |\n| 部分收款 | 实收金额 > 0 且 < 应收合计 |\n| 已结清 | 实收金额 ≥ 应收合计 |\n\n### 表尾汇总(23 项)\n\n押金、合同标的租金、应收合计、应收租金、月度收入、月度租金、维保包干收入、保险上浮费、运维费(收入)、其他收入、里程减免金额、其他减免金额、实收金额、未收、车辆标准成本、车辆实际成本、保险费、氢费、运维费(成本)、居间费、其他、总成本、盈亏。\n\n---" + }, + { + "type": "markdown", + "id": "lbd-doc-lbd-changelog-modal", + "title": "变更日志", + "markdown": "## 变更日志\n\n弹窗标题仅显示「变更日志」;表格上方展示记录条数,列表字段为操作时间、操作人、字段、修改前、修改后。\n\n---" } ] }, { "type": "folder", - "id": "lbd-doc-specs", - "title": "规格说明", + "id": "lbd-doc-field-annotations", + "title": "字段标注", "defaultExpanded": false, "children": [ { "type": "markdown", - "id": "lbd-doc-formulas", - "title": "公式列", - "markdown": "## 6. 公式列(系统自动计算)\n\n对齐 Excel 表内公式;实现见 `utils/calc-detail.ts`。\n\n| 字段 | 计算方式 |\n|---|---|\n| **应收合计** | 维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免金额(负数)+ 其他减免金额(负数) |\n| **月度收入** | 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免 + 其他减免 |\n| **未收** | 应收合计 − 实收金额 |\n| **车辆实际成本** | 车辆标准成本 × 平均天数 |\n| **总成本** | 车辆实际成本 + 保险费 + 氢费 + 运维费(成本)+ 居间费 + 其他 |\n| **盈亏** | 月度收入 − 总成本 |\n\n减免金额在 Excel 中以负数录入;导入时填负数即可。\n\n---" - }, - { - "type": "markdown", - "id": "lbd-doc-boundary", - "title": "模块边界", - "markdown": "## 模块边界\n\n### 与「租赁业务台账」的分工\n\n| 模块 | 定位 |\n|---|---|\n| **租赁业务明细**(本模块) | 对齐业管 Excel 运营台账宽表;手工列导入维护;6 个公式列自动计算;**不**做收款关联与账单状态 |\n| **租赁业务台账** | 账单维度维护、关联收款记录、收款状态(未收/部分/已收)、归档与角色数据范围 |\n\n下游 **业务部台账 / 业务汇总分析** 中「租赁业绩」数据来源为本模块明细。\n\n### 不做范围(当前原型)\n\n- 「租赁业务盈亏月度汇总」独立 Tab\n- 行内编辑、删除、服务端持久化\n- 关联收款记录自动回写实收\n- 员工/主管数据权限隔离\n\n---" + "id": "lbd-doc-lbd-col-status", + "title": "状态", + "markdown": "## 状态\n\n按**实收金额**与**应收合计**自动计算,只读展示。\n\n| 状态 | 判定规则 |\n|---|---|\n| **未收款** | 实收金额 = 0 或未录入 |\n| **部分收款** | 实收金额 > 0 且 < 应收合计 |\n| **已结清** | 实收金额 ≥ 应收合计 |\n\n列位置:月份列左侧;左冻结。\n\n---" }, { "type": "markdown", @@ -405,15 +405,35 @@ }, { "type": "markdown", - "id": "lbd-doc-lbd-col-status", - "title": "状态", - "markdown": "## 状态\n\n按**实收金额**与**应收合计**自动计算,只读展示。\n\n| 状态 | 判定规则 |\n|---|---|\n| **未收款** | 实收金额 = 0 或未录入 |\n| **部分收款** | 实收金额 > 0 且 < 应收合计 |\n| **已结清** | 实收金额 ≥ 应收合计 |\n\n列位置:月份列左侧;左冻结。\n\n---" + "id": "lbd-doc-lbd-col-hydrogen-fee", + "title": "氢费", + "markdown": "## 氢费\n\n**计算方式**:车辆氢费明细中,该车牌在「提车日期」与「退车日期」之间、承担方式为「我司承担」的加氢记录「加氢总价(元)」求和。\n**表头提示**:显示该车牌号码对应客户名称,所有加氢记录,承担方式为我司承担的记录「加氢总价(元)」总和。\n**交互**:金额不为零时可点击,弹出加氢明细列表(加氢时间、加氢站名称、客户名称、车牌号码、加氢量、加氢单价、加氢总价)。\n**录入方式**:系统自动汇总,只读。\n\n---" + } + ] + }, + { + "type": "folder", + "id": "lbd-doc-specs", + "title": "规格说明", + "defaultExpanded": false, + "children": [ + { + "type": "markdown", + "id": "lbd-doc-formulas", + "title": "公式列", + "markdown": "## 6. 公式列(系统自动计算)\n\n对齐 Excel 表内公式;实现见 `utils/calc-detail.ts`。\n\n| 字段 | 计算方式 |\n|---|---|\n| **应收合计** | 维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免金额(负数)+ 其他减免金额(负数) |\n| **月度收入** | 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入)+ 其他收入 + 里程减免 + 其他减免 |\n| **未收** | 应收合计 − 实收金额 |\n| **车辆实际成本** | 车辆标准成本 × 平均天数 |\n| **总成本** | 车辆实际成本 + 保险费 + 氢费 + 运维费(成本)+ 居间费 + 其他 |\n| **盈亏** | 月度收入 − 总成本 |\n\n减免金额在 Excel 中以负数录入;导入时填负数即可。\n\n---" }, { "type": "markdown", - "id": "lbd-doc-lbd-col-hydrogen-fee", - "title": "氢费", - "markdown": "## 氢费\n\n**计算方式**:车辆氢费明细中,该车牌在「提车日期」与「退车日期」(未退车取账单月末)之间、承担方式为「我司承担」的加氢记录「加氢总价(元)」求和。\n**交互**:金额不为零时可点击,弹出加氢明细列表。\n**录入方式**:系统自动汇总,只读。\n\n---" + "id": "lbd-doc-boundary", + "title": "模块边界", + "markdown": "## 模块边界\n\n### 与「租赁业务台账」的分工\n\n| 模块 | 定位 |\n|---|---|\n| **租赁业务明细**(本模块) | 对齐业管 Excel 运营台账宽表;手工列导入维护;6 个公式列自动计算;**不**做收款关联与账单状态 |\n| **租赁业务台账** | 账单维度维护、关联收款记录、收款状态(未收/部分/已收)、归档与角色数据范围 |\n\n下游 **业务部台账 / 业务汇总分析** 中「租赁业绩」数据来源为本模块明细。\n\n### 不做范围(当前原型)\n\n- 「租赁业务盈亏月度汇总」独立 Tab\n- 行内编辑、删除、服务端持久化\n- 关联收款记录自动回写实收\n- 员工/主管数据权限隔离\n\n---" + }, + { + "type": "markdown", + "id": "lbd-doc-source", + "title": "源码入口", + "markdown": "## 8. 源码入口\n\n| 类型 | 路径 |\n|---|---|\n| 主入口 | `index.tsx` |\n| 标注源 | `annotation-source.json` |\n| 列定义 | `components/tableColumns.ts` |\n| 筛选 / KPI 汇总 | `utils/detail.ts` |\n| 收款状态 | `utils/payment-status.ts` |\n| 公式计算 | `utils/calc-detail.ts` |\n| 导入导出 | `utils/batch-io.ts` |\n| 变更日志 | `utils/change-log.ts` |\n| 类型 | `types.ts` |\n| 组件 | `FilterPanel.tsx`、`DetailKpiRow.tsx`、`DetailTable.tsx`、`DetailImportModal.tsx`、`DetailEditModal.tsx`、`DetailChangeLogModal.tsx` |\n\n---" } ] } diff --git a/src/prototypes/lease-business-detail/scripts/sync-annotation-directory.mjs b/src/prototypes/lease-business-detail/scripts/sync-annotation-directory.mjs new file mode 100644 index 0000000..29e5b57 --- /dev/null +++ b/src/prototypes/lease-business-detail/scripts/sync-annotation-directory.mjs @@ -0,0 +1,148 @@ +/** + * 将 PRD、markdownMap 与标注节点说明同步到 annotation-source.json 的 directory.nodes + */ +import { readFileSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const root = join(__dirname, '..'); +const jsonPath = join(root, 'annotation-source.json'); +const prdPath = join(root, '.spec/requirements-prd.md'); + +const doc = JSON.parse(readFileSync(jsonPath, 'utf8')); +const prd = readFileSync(prdPath, 'utf8'); +const mm = doc.markdownMap; + +doc.markdownMap['lbd-doc-overview'] = `## 1. 模块定位 + +| 项 | 说明 | +|---|---| +| 模块名称 | 台账数据 — 租赁业务明细 | +| 目标用户 | 业务二部业管 / 运营人员 | +| 核心任务 | 按 Excel 样表维护租赁车辆收入明细、查询汇总、批量导入导出 | +| 页面结构 | 筛选区 + 7 项 KPI + 工具栏 + 48 列宽表(表尾 23 项汇总)+ 分页 | +| 设计基底 | vm-page + ldb-page + lc-page | + +对齐 Excel《2026年业务二部运营台账总表》「2.租赁车辆收入明细表」。 + +---`; + +function markdownDoc(id, title) { + return { + type: 'markdown', + id, + title, + markdown: mm[id.replace('lbd-doc-', '')] ?? mm[id] ?? doc.data.nodes.find((n) => n.id === id.replace('lbd-doc-', ''))?.annotationText ?? '', + }; +} + +/** 目录 markdown 节点:优先 markdownMap 中带 lbd-doc- 前缀的键,否则用标注节点 id */ +function nodeDoc(nodeId, title, docId = `lbd-doc-${nodeId}`) { + const markdown = mm[nodeId] ?? mm[docId] ?? ''; + return { type: 'markdown', id: docId, title, markdown }; +} + +doc.directory.nodes = [ + { + type: 'folder', + id: 'lbd-doc-root', + title: '租赁业务明细说明', + defaultExpanded: true, + children: [ + { + type: 'markdown', + id: 'lbd-doc-overview', + title: '模块总览', + markdown: doc.markdownMap['lbd-doc-overview'], + }, + { + type: 'link', + id: 'lbd-link-self', + title: '租赁业务明细原型', + href: '/prototypes/lease-business-detail', + target: 'self', + }, + { + type: 'markdown', + id: 'lbd-doc-prd', + title: 'PRD 全文', + markdown: prd, + markdownPath: 'src/prototypes/lease-business-detail/.spec/requirements-prd.md', + }, + { + type: 'folder', + id: 'lbd-doc-page-annotations', + title: '页面标注', + defaultExpanded: true, + children: [ + nodeDoc('lbd-filter', '筛选条件'), + nodeDoc('lbd-kpi', 'KPI 汇总'), + nodeDoc('lbd-toolbar', '批量导入导出'), + nodeDoc('lbd-table', '明细列表'), + nodeDoc('lbd-changelog-modal', '变更日志'), + ], + }, + { + type: 'folder', + id: 'lbd-doc-field-annotations', + title: '字段标注', + defaultExpanded: false, + children: [ + nodeDoc('lbd-col-status', '状态'), + nodeDoc('lbd-col-receivable-total', '应收合计'), + nodeDoc('lbd-col-outstanding', '未收'), + nodeDoc('lbd-col-vehicle-actual-cost', '车辆实际成本'), + nodeDoc('lbd-col-total-cost', '总成本'), + nodeDoc('lbd-col-profit-loss', '盈亏'), + nodeDoc('lbd-col-hydrogen-fee', '氢费'), + ], + }, + { + type: 'folder', + id: 'lbd-doc-specs', + title: '规格说明', + defaultExpanded: false, + children: [ + { + type: 'markdown', + id: 'lbd-doc-formulas', + title: '公式列', + markdown: mm['lbd-doc-formulas'], + }, + { + type: 'markdown', + id: 'lbd-doc-boundary', + title: '模块边界', + markdown: mm['lbd-doc-boundary'], + }, + { + type: 'markdown', + id: 'lbd-doc-source', + title: '源码入口', + markdown: `## 8. 源码入口 + +| 类型 | 路径 | +|---|---| +| 主入口 | \`index.tsx\` | +| 标注源 | \`annotation-source.json\` | +| 列定义 | \`components/tableColumns.ts\` | +| 筛选 / KPI 汇总 | \`utils/detail.ts\` | +| 收款状态 | \`utils/payment-status.ts\` | +| 公式计算 | \`utils/calc-detail.ts\` | +| 导入导出 | \`utils/batch-io.ts\` | +| 变更日志 | \`utils/change-log.ts\` | +| 类型 | \`types.ts\` | +| 组件 | \`FilterPanel.tsx\`、\`DetailKpiRow.tsx\`、\`DetailTable.tsx\`、\`DetailImportModal.tsx\`、\`DetailEditModal.tsx\`、\`DetailChangeLogModal.tsx\` | + +---`, + }, + ], + }, + ], + }, +]; + +doc.data.updatedAt = Date.now(); +writeFileSync(jsonPath, `${JSON.stringify(doc, null, 2)}\n`, 'utf8'); +console.log('Synced directory.nodes with PRD and', doc.data.nodes.length, 'annotation nodes'); diff --git a/src/prototypes/oneos-prototype-nav/nav-data.ts b/src/prototypes/oneos-prototype-nav/nav-data.ts index 65a6a00..cd142de 100644 --- a/src/prototypes/oneos-prototype-nav/nav-data.ts +++ b/src/prototypes/oneos-prototype-nav/nav-data.ts @@ -23,27 +23,45 @@ import { const CURRENT_PROTOTYPE_ID = 'oneos-prototype-nav'; const PUBLISHED_CLOUD_HOSTS = new Set(['prototype.lnoneos.com']); +/** 导航页左侧 DIRECTORY 仅展示这些一级分区(小羚羚由 xll-nav-menu.json 单独注入) */ +const NAV_SIDEBAR_SECTION_TITLES = new Set(['OneOS']); + +/** 与 axhub.config.json cloudPublishing.s3.pathAliases 保持一致 */ +const CLOUD_PUBLISH_PATH_ALIASES: Record = { + 'oneos-prototype-nav': 'oneos-prototype-nav', +}; + +function cloudPrototypeSegment(prototypeId: string): string { + return CLOUD_PUBLISH_PATH_ALIASES[prototypeId] || `prototypes/${prototypeId}`; +} /** 对象存储静态发布站点(无 Make 本地 dev server 路由) */ export function isPublishedCloudHost(): boolean { if (typeof window === 'undefined') return false; const { hostname, pathname } = window.location; if (PUBLISHED_CLOUD_HOSTS.has(hostname)) return true; - // export-html 发布页:/{prototype}/index.html - return /\/index\.html$/u.test(pathname) && !pathname.startsWith('/prototypes/'); + // export-html 发布页:/{prototype}/index.html 或 /prototypes/{prototype}/index.html + return /\/index\.html$/u.test(pathname); } export function resolvePrototypeHref(prototypeId: string): string { if (typeof window === 'undefined') return `/prototypes/${prototypeId}`; if (isPublishedCloudHost()) { - return `${window.location.origin}/prototypes/${prototypeId}/index.html`; + return `${window.location.origin}/${cloudPrototypeSegment(prototypeId)}/index.html`; } return `/prototypes/${prototypeId}`; } +function normalizeAbsoluteHref(href: string): string { + const matches = href.match(/https?:\/\/[^\s"']+/gu); + if (matches && matches.length > 1) return matches[0]; + return href; +} + /** 卡片/弹窗打开时按当前环境解析链接,避免静态包内 href 写死 */ export function linkHref(link: NavLinkItem): string { - if (link.external || /^https?:\/\//u.test(link.href)) return link.href; + if (link.external) return normalizeAbsoluteHref(link.href); + if (/^https?:\/\//u.test(link.href)) return normalizeAbsoluteHref(link.href); if (link.href.includes('#page=')) return link.href; return resolvePrototypeHref(link.prototypeId); } @@ -242,6 +260,7 @@ function transformSection(node: SidebarNode): NavSection | null { export function loadNavSections(): NavSection[] { const prototypes = (navMenu as { prototypes?: SidebarNode[] }).prototypes || []; const oneosSections = prototypes + .filter((node) => node.kind === 'folder' && NAV_SIDEBAR_SECTION_TITLES.has(String(node.title || ''))) .map((node) => transformSection(node)) .filter((section): section is NavSection => Boolean(section)); const xllSection = loadXllNavSection(); diff --git a/src/prototypes/oneos-prototype-nav/nav-menu.json b/src/prototypes/oneos-prototype-nav/nav-menu.json index ee0e8f0..f114a66 100644 --- a/src/prototypes/oneos-prototype-nav/nav-menu.json +++ b/src/prototypes/oneos-prototype-nav/nav-menu.json @@ -1,83 +1,5 @@ { "prototypes": [ - { - "id": "item-prototypes-task-work-order", - "kind": "item", - "title": "task work order", - "itemKey": "prototypes/task-work-order" - }, - { - "id": "item-prototypes-lease-business-line-overview", - "kind": "item", - "title": "lease business line overview", - "itemKey": "prototypes/lease-business-line-overview" - }, - { - "id": "item-prototypes-oneos-web-business", - "kind": "item", - "title": "oneos web business", - "itemKey": "prototypes/oneos-web-business" - }, - { - "id": "item-prototypes-oneos-web-contract-template", - "kind": "item", - "title": "oneos web contract template", - "itemKey": "prototypes/oneos-web-contract-template" - }, - { - "id": "item-prototypes-oneos-web-data-analysis", - "kind": "item", - "title": "oneos web data analysis", - "itemKey": "prototypes/oneos-web-data-analysis" - }, - { - "id": "item-prototypes-oneos-web-finance", - "kind": "item", - "title": "oneos web finance", - "itemKey": "prototypes/oneos-web-finance" - }, - { - "id": "item-prototypes-oneos-web-h2-station", - "kind": "item", - "title": "oneos web h2 station", - "itemKey": "prototypes/oneos-web-h2-station" - }, - { - "id": "item-prototypes-oneos-web-help-center", - "kind": "item", - "title": "oneos web help center", - "itemKey": "prototypes/oneos-web-help-center" - }, - { - "id": "item-prototypes-oneos-web-lease-contract", - "kind": "item", - "title": "oneos web lease contract", - "itemKey": "prototypes/oneos-web-lease-contract" - }, - { - "id": "item-prototypes-oneos-web-ledger-data", - "kind": "item", - "title": "oneos web ledger data", - "itemKey": "prototypes/oneos-web-ledger-data" - }, - { - "id": "item-prototypes-oneos-web-ops", - "kind": "item", - "title": "oneos web ops", - "itemKey": "prototypes/oneos-web-ops" - }, - { - "id": "item-prototypes-oneos-web-procurement", - "kind": "item", - "title": "oneos web procurement", - "itemKey": "prototypes/oneos-web-procurement" - }, - { - "id": "item:prototypes:oneos-prototype-nav", - "kind": "item", - "title": "原型导航", - "itemKey": "prototypes/oneos-prototype-nav" - }, { "id": "folder-1782874576229-r8atbu", "kind": "folder", diff --git a/src/prototypes/oneos-prototype-nav/prototype-registry.json b/src/prototypes/oneos-prototype-nav/prototype-registry.json index aa5c9de..5f7022c 100644 --- a/src/prototypes/oneos-prototype-nav/prototype-registry.json +++ b/src/prototypes/oneos-prototype-nav/prototype-registry.json @@ -1,65 +1,28 @@ { "version": 1, - "updatedAt": "2026-07-12T14:50:59.959Z", + "updatedAt": "2026-07-13T01:31:23.010Z", "prototypes": { "oneos-web-workbench": { "title": "工作台", - "version": "v1.8", - "revision": 8, - "lastUpdated": "2026-07-11T21:02:25.326Z", + "version": "v1.4", + "revision": 4, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "3d7954b2ad60057932b8a0b25e645a83ef0ff1b5fe3db37d1a25382810e29126", "trackedFiles": [ "index.tsx", "pages/01-工作台.jsx" ], "changelog": [ - { - "version": "v1.8", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-工作台.jsx" - ] - }, - { - "version": "v1.7", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-工作台.jsx" - ] - }, - { - "version": "v1.6", - "date": "2026-07-11", - "time": "11:49", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-工作台.jsx" - ] - }, - { - "version": "v1.5", - "date": "2026-07-11", - "time": "11:49", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-工作台.jsx" - ] - }, { "version": "v1.4", - "date": "2026-07-09", - "time": "17:52", - "summary": "多业务台账/财务/工作台页面迭代与标注目录同步。", - "details": [], - "commit": "6ccbbef", + "date": "2026-07-12", + "time": "22:45", + "summary": "工作台:提车应收款快捷入口改跳独立原型", + "details": [ + "快捷入口指向 /prototypes/vehicle-pickup-receivable", + "protoNav 支持直接 location 跳转原型 URL" + ], + "commit": "131b963", "files": [] }, { @@ -97,9 +60,9 @@ }, "vehicle-management": { "title": "车辆资产", - "version": "v1.27", - "revision": 27, - "lastUpdated": "2026-07-11T20:59:58.930Z", + "version": "v1.5", + "revision": 5, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "9b780aa62650c093877ad900ad113bf83841eb63416c5bb93fe931f6c444d9f8", "trackedFiles": [ ".spec/prototype-comments.json", @@ -185,453 +148,30 @@ "utils/violationRecords.ts" ], "changelog": [ - { - "version": "v1.27", - "date": "2026-07-12", - "time": "04:59", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.26", - "date": "2026-07-12", - "time": "04:14", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.25", - "date": "2026-07-12", - "time": "00:16", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.24", - "date": "2026-07-12", - "time": "00:14", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.23", - "date": "2026-07-12", - "time": "00:14", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.22", - "date": "2026-07-11", - "time": "17:54", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.21", - "date": "2026-07-11", - "time": "17:50", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.20", - "date": "2026-07-11", - "time": "17:50", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.19", - "date": "2026-07-11", - "time": "17:50", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.18", - "date": "2026-07-11", - "time": "17:50", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.17", - "date": "2026-07-11", - "time": "17:50", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.16", - "date": "2026-07-11", - "time": "17:50", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.15", - "date": "2026-07-11", - "time": "17:50", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.14", - "date": "2026-07-11", - "time": "17:50", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.13", - "date": "2026-07-11", - "time": "17:39", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.12", - "date": "2026-07-11", - "time": "17:39", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.11", - "date": "2026-07-11", - "time": "17:38", - "summary": "更新页面逻辑与交互", - "files": [ - "components/OnLeaseFleetSection.tsx" - ] - }, - { - "version": "v1.10", - "date": "2026-07-11", - "time": "17:15", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.9", - "date": "2026-07-11", - "time": "16:49", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.8", - "date": "2026-07-11", - "time": "16:42", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.7", - "date": "2026-07-11", - "time": "16:41", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, - { - "version": "v1.6", - "date": "2026-07-11", - "time": "16:41", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", - "components/DetailAccidentRecordsTab.tsx", - "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" - ] - }, { "version": "v1.5", - "date": "2026-07-10", - "time": "23:10", - "summary": "更新需求说明与标注", + "date": "2026-07-12", + "time": "22:45", + "summary": "车辆管理:在租车队 KPI 迁入、车型分布弹窗与列表样式优化", + "details": [ + "在租车队 KPI 从租赁合同列表迁入;按品牌型号统计在租数量", + "车型分布弹窗:品牌筛选、车型卡片、占比进度条、车辆明细", + "详情 Tab 与列表筛选/导入/KPI 操作区统一;表格样式优化" + ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd-detail.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/DateRangeCalendarPanel.tsx", - "components/DateRangeFilterField.tsx", "components/DetailAccidentRecordsTab.tsx", "components/DetailAnnualReviewRecordsTab.tsx", - "components/DetailBasicInfoTab.tsx", - "components/DetailExpireField.tsx", - "components/DetailFaultRecordsTab.tsx" + "components/DetailFaultRecordsTab.tsx", + "components/DetailInsuranceRecordsTab.tsx", + "components/DetailLeaseRecordsTab.tsx", + "components/DetailMovementRecordsTab.tsx", + "components/DetailTransferRecordsTab.tsx", + "components/DetailViolationRecordsTab.tsx", + "components/FilterPanel.tsx", + "components/ImportModal.tsx", + "components/KpiCards.tsx", + "components/MultiPlateFilterField.tsx" ] }, { @@ -728,9 +268,9 @@ }, "customer-management": { "title": "客户管理", - "version": "v1.5", - "revision": 5, - "lastUpdated": "2026-07-11T16:16:51.651Z", + "version": "v1.4", + "revision": 4, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "d1b57a768182b120855143480ed45e1b0c3be9ef18d73fe928538b1059f0daa2", "trackedFiles": [ ".spec/requirements-prd-create.md", @@ -760,44 +300,23 @@ "utils/riskTagStore.ts" ], "changelog": [ - { - "version": "v1.5", - "date": "2026-07-12", - "time": "00:16", - "summary": "更新需求说明与标注", - "files": [ - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", - "components/BatchRiskTagModal.tsx", - "components/CustomerTable.tsx", - "components/FilterPanel.tsx", - "components/LabelTags.tsx", - "components/MultiSelectField.tsx", - "components/RiskLabelTags.tsx", - "components/RiskTagDrawer.tsx", - "components/RiskTagForm.tsx", - "components/StatusBadge.tsx" - ] - }, { "version": "v1.4", - "date": "2026-07-11", - "time": "16:47", - "summary": "更新需求说明与标注", + "date": "2026-07-12", + "time": "22:45", + "summary": "客户管理:OperationActions 统一操作列,移除面包屑", + "details": [ + "列表操作:详情 / 编辑 / 管理标签 / 删除", + "风险标签、批量打标等业务逻辑不变" + ], + "commit": "131b963", "files": [ - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - ".spec/ui-review.md", "components/BatchRiskTagModal.tsx", "components/CustomerTable.tsx", "components/FilterPanel.tsx", - "components/LabelTags.tsx", - "components/MultiSelectField.tsx", - "components/RiskLabelTags.tsx", "components/RiskTagDrawer.tsx", - "components/RiskTagForm.tsx", - "components/StatusBadge.tsx" + "index.tsx", + "pages/CreatePage.tsx" ] }, { @@ -873,7 +392,7 @@ "title": "供应商管理", "version": "v1.3", "revision": 3, - "lastUpdated": "2026-07-11T16:17:07.633Z", + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "1ed87c36f3bb872a07efd3eb46a7bfd871b00e08c71f7758db8819af6e0318e7", "trackedFiles": [ "components/CoopStatusBadge.tsx", @@ -893,21 +412,17 @@ { "version": "v1.3", "date": "2026-07-12", - "time": "00:17", - "summary": "更新页面样式", + "time": "22:45", + "summary": "供应商管理:工具栏与操作区图标标准化", + "details": [ + "新增供应商按钮图标统一;删除收入 OperationActions" + ], + "commit": "131b963", "files": [ - "components/CoopStatusBadge.tsx", "components/FilterPanel.tsx", - "components/KpiCards.tsx", "components/SupplierTable.tsx", - "data/suppliers.json", "index.tsx", - "pages/CreatePage.tsx", - "styles/index.css", - "types.ts", - "utils/address.ts", - "utils/constants.ts", - "utils/filters.ts" + "pages/CreatePage.tsx" ] }, { @@ -954,9 +469,9 @@ }, "lease-contract-management": { "title": "租赁合同", - "version": "v1.787", - "revision": 787, - "lastUpdated": "2026-07-12T13:45:58.363Z", + "version": "v1.9", + "revision": 9, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "384ec56941b0af20408dcfb531f0eaaff12a95b52f1b5f352162486ae653edc0", "trackedFiles": [ ".spec/prototype-comments.json", @@ -992,602 +507,223 @@ ], "changelog": [ { - "version": "v1.787", + "version": "v1.9", "date": "2026-07-12", - "time": "21:45", - "summary": "更新需求说明与标注", + "time": "22:45", + "summary": "租赁合同增强:KPI/状态收敛、查看页、签署方式与提车应收联动", + "details": [ + "列表 KPI:全部/草稿/进行中/审批中/已终止;合同状态收敛;在租车队 KPI 迁至车辆管理", + "筛选:合同模板类型 + 标准合同名称二级联动;统一流程入口(新增/续签/转正式/增车等)", + "新增只读查看页;线上电子签章 / 线下人工上传;主动终止与交付安排变更(Cascader/TBD)", + "附加费用拆分已有/新增服务项;红线条款 + 新增条款检测;先付后用/先用后付", + "提交审批与交付计划变更同步提车应收 bridge" + ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", ".spec/requirements-annotation-context.md", ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", ".spec/requirements-prd-list.md", - "contract-word-preview.js", + "LeaseContractCreate.jsx", + "LeaseContractEditorForm.jsx", + "LeaseContractFleetSummary.jsx", + "LeaseContractManagement.jsx", + "LeaseContractPreviewPanel.jsx", + "LeaseContractView.jsx", "index.tsx", - "lease-business-org-data.js", "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" + "lease-contract-edit-bridge.js" ] }, { - "version": "v1.786", - "date": "2026-07-12", - "time": "21:12", - "summary": "更新需求说明与标注", + "version": "v1.8", + "date": "2026-07-08", + "time": "11:44", + "summary": "页面逻辑与交互:LeaseContractManagement.jsx、lease-contract-vehicle-clause.js、lease-order-vars.js", + "details": [ + "样式与布局:index.css、lease-contract.css" + ], + "commit": "6d14c58", "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" + "LeaseContractManagement.jsx", + "lease-contract-vehicle-clause.js", + "lease-order-vars.js", + "styles/index.css", + "styles/lease-contract.css" ] }, { - "version": "v1.785", - "date": "2026-07-12", - "time": "21:12", - "summary": "更新需求说明与标注", + "version": "v1.7", + "date": "2026-07-06", + "time": "17:18", + "summary": "租赁合同:列表/表单增强、客户资质与审批规则", + "details": [ + "租赁/自营台账增强", + "租赁合同与条线说明", + "统一台账壳层与侧栏导航", + "页面逻辑与交互:LeaseContractCreate.jsx、LeaseContractEditorForm.jsx、LeaseContractFleetSummary.jsx、LeaseContractManagement.jsx 等", + "样式与布局:lease-contract-create.css、lease-contract.css", + "需求说明与 PRD:requirements-prd-create.md、requirements-prd-list.md" + ], + "commit": "d0d7458", "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", ".spec/requirements-prd-create.md", ".spec/requirements-prd-list.md", - "contract-word-preview.js", + "LeaseContractCreate.jsx", + "LeaseContractEditorForm.jsx", + "LeaseContractFleetSummary.jsx", + "LeaseContractManagement.jsx", "index.tsx", - "lease-business-org-data.js", "lease-contract-approval-rules.js", "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.784", - "date": "2026-07-12", - "time": "21:12", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.783", - "date": "2026-07-12", - "time": "21:12", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.782", - "date": "2026-07-12", - "time": "21:12", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.781", - "date": "2026-07-12", - "time": "21:12", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.780", - "date": "2026-07-12", - "time": "21:12", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.779", - "date": "2026-07-12", - "time": "21:12", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.778", - "date": "2026-07-12", - "time": "21:12", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.777", - "date": "2026-07-12", - "time": "21:11", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.776", - "date": "2026-07-12", - "time": "21:11", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.775", - "date": "2026-07-12", - "time": "21:11", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js" - ] - }, - { - "version": "v1.774", - "date": "2026-07-12", - "time": "20:49", - "summary": "更新需求说明与标注", - "files": [ - ".spec/requirements-annotation-context.md", - ".spec/requirements-flow-operations.md" - ] - }, - { - "version": "v1.773", - "date": "2026-07-12", - "time": "20:42", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", "lease-contract-form-validation.js", "lease-contract-list-data.js", "lease-contract-preview-build.js" ] }, { - "version": "v1.772", - "date": "2026-07-12", - "time": "20:42", - "summary": "更新需求说明与标注", + "version": "v1.6", + "date": "2026-07-02", + "time": "03:35", + "summary": "租赁合同:列表展开列合并、在租明细弹窗、编辑回填与样式修复", + "details": [ + "租赁台账与租赁合同增强", + "加氢站站点独立原型与氢费数据桥接", + "页面逻辑与交互:LeaseContractCreate.jsx、LeaseContractFleetSummary.jsx、LeaseContractManagement.jsx、lease-contract-edit-bridge.js 等", + "样式与布局:lease-contract.css" + ], + "commit": "f5e3126", "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", + "LeaseContractCreate.jsx", + "LeaseContractFleetSummary.jsx", + "LeaseContractManagement.jsx", "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", "lease-contract-list-data.js", - "lease-contract-preview-build.js" + "styles/lease-contract.css" ] }, { - "version": "v1.771", - "date": "2026-07-12", - "time": "20:42", - "summary": "更新需求说明与标注", + "version": "v1.5", + "date": "2026-07-01", + "time": "16:28", + "summary": "租赁合同增强", + "details": [ + "Clay 车辆备份", + "侧边栏分组", + "移除周报与安全培训原型。", + "页面逻辑与交互:LeaseContractCreate.jsx、LeaseContractEditorForm.jsx、LeaseContractFleetSummary.jsx、LeaseContractManagement.jsx 等", + "样式与布局:lease-contract.css" + ], + "commit": "b9dee3a", "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", + "LeaseContractCreate.jsx", + "LeaseContractEditorForm.jsx", + "LeaseContractFleetSummary.jsx", + "LeaseContractManagement.jsx", "lease-contract-list-data.js", - "lease-contract-preview-build.js" + "lease-contract-preview-build.js", + "styles/lease-contract.css" ] }, { - "version": "v1.770", - "date": "2026-07-12", - "time": "20:42", - "summary": "更新需求说明与标注", + "version": "v1.4", + "date": "2026-07-01", + "time": "09:11", + "summary": "租赁合同管理:列表子表、交车安排、里程汇总及新建/编辑表单优化", + "details": [ + "合同模板重构与租赁合同列表/表单增强", + "页面逻辑与交互:LeaseContractCreate.jsx、LeaseContractEditorForm.jsx、LeaseContractManagement.jsx、LeaseContractPreviewPanel.jsx 等", + "样式与布局:lease-contract-create.css、lease-contract.css", + "需求说明与 PRD:requirements-prd-create.md、requirements-prd-list.md" + ], + "commit": "2e0a3d7", "files": [ - ".spec/prototype-comments.json", ".spec/requirements-prd-create.md", ".spec/requirements-prd-list.md", - "contract-word-preview.js", + "LeaseContractCreate.jsx", + "LeaseContractEditorForm.jsx", + "LeaseContractManagement.jsx", + "LeaseContractPreviewPanel.jsx", "index.tsx", "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", "lease-contract-form-validation.js", "lease-contract-list-data.js", - "lease-contract-preview-build.js" + "lease-contract-preview-build.js", + "lease-contract-risk-detect.js" ] }, { - "version": "v1.769", - "date": "2026-07-12", - "time": "20:42", - "summary": "更新需求说明与标注", + "version": "v1.3", + "date": "2026-06-30", + "time": "15:27", + "summary": "页面逻辑与交互:LeaseContractCreate.jsx、LeaseContractEditorForm.jsx、LeaseContractManagement.jsx、LeaseContractPreviewPanel.jsx 等", + "details": [ + "样式与布局:lease-contract-create.css、lease-contract.css", + "需求说明与 PRD:requirements-prd-create.md、requirements-prd-list.md" + ], + "commit": "af29b26", "files": [ - ".spec/prototype-comments.json", ".spec/requirements-prd-create.md", ".spec/requirements-prd-list.md", - "contract-word-preview.js", + "LeaseContractCreate.jsx", + "LeaseContractEditorForm.jsx", + "LeaseContractManagement.jsx", + "LeaseContractPreviewPanel.jsx", "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", "lease-contract-form-validation.js", "lease-contract-list-data.js", - "lease-contract-preview-build.js" + "lease-contract-preview-build.js", + "lease-contract-risk-detect.js", + "lease-contract-vehicle-clause.js" ] }, { - "version": "v1.768", - "date": "2026-07-12", - "time": "20:42", - "summary": "更新需求说明与标注", + "version": "v1.2", + "date": "2026-06-26", + "time": "17:56", + "summary": "页面逻辑与交互:LeaseContractEditorForm.jsx、LeaseContractManagement.jsx、lease-contract-preview-build.js、lease-order-vars.js", + "details": [ + "样式与布局:lease-contract-create.css" + ], + "commit": "00ca184", "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" + "LeaseContractEditorForm.jsx", + "LeaseContractManagement.jsx", + "lease-contract-preview-build.js", + "lease-order-vars.js", + "styles/lease-contract-create.css" ] }, { - "version": "v1.767", - "date": "2026-07-12", - "time": "20:42", - "summary": "更新需求说明与标注", + "version": "v1.1", + "date": "2026-06-26", + "time": "15:36", + "summary": "页面逻辑与交互:LeaseContractCreate.jsx、LeaseContractEditorForm.jsx、LeaseContractManagement.jsx、LeaseContractPreviewPanel.jsx 等", + "details": [ + "样式与布局:index.css、lease-contract-create.css、lease-contract.css" + ], + "commit": "7ef8852", "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", + "LeaseContractCreate.jsx", + "LeaseContractEditorForm.jsx", + "LeaseContractManagement.jsx", + "LeaseContractPreviewPanel.jsx", "contract-word-preview.js", "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" - ] - }, - { - "version": "v1.766", - "date": "2026-07-12", - "time": "20:42", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" - ] - }, - { - "version": "v1.765", - "date": "2026-07-12", - "time": "20:42", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" - ] - }, - { - "version": "v1.764", - "date": "2026-07-12", - "time": "20:42", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" - ] - }, - { - "version": "v1.763", - "date": "2026-07-12", - "time": "20:41", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" - ] - }, - { - "version": "v1.762", - "date": "2026-07-12", - "time": "20:37", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" - ] - }, - { - "version": "v1.761", - "date": "2026-07-12", - "time": "20:37", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" - ] - }, - { - "version": "v1.760", - "date": "2026-07-12", - "time": "20:37", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" - ] - }, - { - "version": "v1.759", - "date": "2026-07-12", - "time": "20:37", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" - ] - }, - { - "version": "v1.758", - "date": "2026-07-12", - "time": "20:17", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd-create.md", - ".spec/requirements-prd-list.md", - "contract-word-preview.js", - "index.tsx", - "lease-business-org-data.js", - "lease-contract-approval-rules.js", - "lease-contract-edit-bridge.js", - "lease-contract-flow-bridge.js", - "lease-contract-form-validation.js", - "lease-contract-list-data.js", - "lease-contract-preview-build.js" + "lease-contract-preview-build.js", + "lease-order-vars.js", + "styles/index.css", + "styles/lease-contract-create.css", + "styles/lease-contract.css" ] } ] }, "insurance-procurement": { "title": "保险采购", - "version": "v1.7", - "revision": 7, - "lastUpdated": "2026-07-11T21:03:06.031Z", + "version": "v1.4", + "revision": 4, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "0394aa51c3f0da383c8f1afb99537ac5c7d9f04941e488f87cb30fcd2607f872", "trackedFiles": [ ".spec/prototype-comments.json", @@ -1596,52 +732,19 @@ "styles/index.css" ], "changelog": [ - { - "version": "v1.7", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "index.tsx", - "InsuranceProcurement.jsx", - "styles/index.css" - ] - }, - { - "version": "v1.6", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "index.tsx", - "InsuranceProcurement.jsx", - "styles/index.css" - ] - }, - { - "version": "v1.5", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "index.tsx", - "InsuranceProcurement.jsx", - "styles/index.css" - ] - }, { "version": "v1.4", "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面样式", + "time": "22:45", + "summary": "保险采购:OperationActions 统一操作列", + "details": [ + "保单列表:编辑 / 预览 / 下载 / 更多", + "标注壳切换" + ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", - "index.tsx", "InsuranceProcurement.jsx", - "styles/index.css" + "index.tsx" ] }, { @@ -1687,10 +790,10 @@ }, "contract-template-management": { "title": "合同模板管理", - "version": "v1.19", - "revision": 19, - "lastUpdated": "2026-07-11T21:01:32.488Z", - "contentHash": "229d085b020d1a3286d362a604aece6ce84fa5e5509652172f1fae977030a0c7", + "version": "v1.11", + "revision": 11, + "lastUpdated": "2026-07-12T16:26:54.909Z", + "contentHash": "d73aaafeba82194211c48a9012a786753c1f9e76a23d7148f5fbae6ee592d1d6", "trackedFiles": [ ".spec/acp/conversations.json", ".spec/prototype-comments.json", @@ -1720,88 +823,8 @@ ], "changelog": [ { - "version": "v1.19", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新需求说明与标注", - "files": [ - ".spec/acp/conversations.json", - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/ui-review.md", - "contract-template-catalog.js", - "contract-template-docx-fidelity.js", - "contract-template-section-filter.js", - "contract-template-section-headings.js", - "contract-template-section-html.js", - "contract-template-seed.js", - "contract-template-store.js", - "contract-template-types.js" - ] - }, - { - "version": "v1.18", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新需求说明与标注", - "files": [ - ".spec/acp/conversations.json", - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/ui-review.md", - "contract-template-catalog.js", - "contract-template-docx-fidelity.js", - "contract-template-section-filter.js", - "contract-template-section-headings.js", - "contract-template-section-html.js", - "contract-template-seed.js", - "contract-template-store.js", - "contract-template-types.js" - ] - }, - { - "version": "v1.17", - "date": "2026-07-12", - "time": "04:22", - "summary": "更新需求说明与标注", - "files": [ - ".spec/acp/conversations.json", - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/ui-review.md", - "contract-template-catalog.js", - "contract-template-docx-fidelity.js", - "contract-template-section-filter.js", - "contract-template-section-headings.js", - "contract-template-section-html.js", - "contract-template-seed.js", - "contract-template-store.js", - "contract-template-types.js" - ] - }, - { - "version": "v1.16", - "date": "2026-07-12", - "time": "03:15", - "summary": "更新需求说明与标注", - "files": [ - ".spec/acp/conversations.json", - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/ui-review.md", - "contract-template-catalog.js", - "contract-template-docx-fidelity.js", - "contract-template-section-filter.js", - "contract-template-section-headings.js", - "contract-template-section-html.js", - "contract-template-seed.js", - "contract-template-store.js", - "contract-template-types.js" - ] - }, - { - "version": "v1.15", - "date": "2026-07-12", + "version": "v1.11", + "date": "2026-07-13", "time": "00:26", "summary": "更新需求说明与标注", "files": [ @@ -1819,90 +842,10 @@ "contract-template-types.js" ] }, - { - "version": "v1.14", - "date": "2026-07-12", - "time": "00:19", - "summary": "更新需求说明与标注", - "files": [ - ".spec/acp/conversations.json", - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/ui-review.md", - "contract-template-catalog.js", - "contract-template-docx-fidelity.js", - "contract-template-section-filter.js", - "contract-template-section-headings.js", - "contract-template-section-html.js", - "contract-template-seed.js", - "contract-template-store.js", - "contract-template-types.js" - ] - }, - { - "version": "v1.13", - "date": "2026-07-12", - "time": "00:17", - "summary": "更新需求说明与标注", - "files": [ - ".spec/acp/conversations.json", - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/ui-review.md", - "contract-template-catalog.js", - "contract-template-docx-fidelity.js", - "contract-template-section-filter.js", - "contract-template-section-headings.js", - "contract-template-section-html.js", - "contract-template-seed.js", - "contract-template-store.js", - "contract-template-types.js" - ] - }, - { - "version": "v1.12", - "date": "2026-07-11", - "time": "19:03", - "summary": "更新需求说明与标注", - "files": [ - ".spec/acp/conversations.json", - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/ui-review.md", - "contract-template-catalog.js", - "contract-template-docx-fidelity.js", - "contract-template-section-filter.js", - "contract-template-section-headings.js", - "contract-template-section-html.js", - "contract-template-seed.js", - "contract-template-store.js", - "contract-template-types.js" - ] - }, - { - "version": "v1.11", - "date": "2026-07-11", - "time": "17:21", - "summary": "更新需求说明与标注", - "files": [ - ".spec/acp/conversations.json", - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/ui-review.md", - "contract-template-catalog.js", - "contract-template-docx-fidelity.js", - "contract-template-section-filter.js", - "contract-template-section-headings.js", - "contract-template-section-html.js", - "contract-template-seed.js", - "contract-template-store.js", - "contract-template-types.js" - ] - }, { "version": "v1.10", - "date": "2026-07-11", - "time": "16:47", + "date": "2026-07-13", + "time": "00:26", "summary": "更新需求说明与标注", "files": [ ".spec/acp/conversations.json", @@ -1921,22 +864,20 @@ }, { "version": "v1.9", - "date": "2026-07-11", - "time": "16:47", - "summary": "更新需求说明与标注", + "date": "2026-07-12", + "time": "22:45", + "summary": "合同模板:启用/停用、先付后用/先用后付变量与操作区重构", + "details": [ + "行操作:编辑 + 更多(启用/停用、版本日志、删除);启用中不可编辑/删除", + "模板变量新增 paymentMethod;付款周期与氢费结算文案更新" + ], + "commit": "131b963", "files": [ - ".spec/acp/conversations.json", - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/ui-review.md", + "ContractTemplate.jsx", "contract-template-catalog.js", - "contract-template-docx-fidelity.js", - "contract-template-section-filter.js", - "contract-template-section-headings.js", - "contract-template-section-html.js", - "contract-template-seed.js", - "contract-template-store.js", - "contract-template-types.js" + "contract-template-vars.js", + "index.tsx", + "styles/contract-template.css" ] }, { @@ -2078,9 +1019,9 @@ }, "oneos-web-h2-station-site": { "title": "站点信息", - "version": "v1.3", - "revision": 3, - "lastUpdated": "2026-07-09T09:52:00.000Z", + "version": "v1.4", + "revision": 4, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "f77326526aa62f234abdaa573a67c752f71e0874b1930daf3fb27baf0478258d", "trackedFiles": [ ".spec/prototype-comments.json", @@ -2093,6 +1034,19 @@ "index.tsx" ], "changelog": [ + { + "version": "v1.4", + "date": "2026-07-12", + "time": "22:45", + "summary": "站点信息:标注目录清理", + "details": [ + "移除内嵌原型导航节点;标注壳切换" + ], + "commit": "131b963", + "files": [ + "index.tsx" + ] + }, { "version": "v1.3", "date": "2026-07-09", @@ -2142,9 +1096,9 @@ }, "business-dept-ledger": { "title": "业务部台账", - "version": "v1.27", - "revision": 27, - "lastUpdated": "2026-07-09T15:43:55.730Z", + "version": "v1.3", + "revision": 3, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "5264ccedcb133f7d49eafcf572a3f384ae819e4fcc59f89014913c14e9ccaed3", "trackedFiles": [ ".spec/prototype-comments.json", @@ -2153,303 +1107,17 @@ "styles/index.css" ], "changelog": [ - { - "version": "v1.27", - "date": "2026-07-09", - "time": "23:43", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.26", - "date": "2026-07-09", - "time": "23:42", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.25", - "date": "2026-07-09", - "time": "23:41", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.24", - "date": "2026-07-09", - "time": "23:29", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.23", - "date": "2026-07-09", - "time": "23:29", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.22", - "date": "2026-07-09", - "time": "23:26", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.21", - "date": "2026-07-09", - "time": "23:14", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.20", - "date": "2026-07-09", - "time": "23:14", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.19", - "date": "2026-07-09", - "time": "23:14", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.18", - "date": "2026-07-09", - "time": "23:14", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.17", - "date": "2026-07-09", - "time": "23:14", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.16", - "date": "2026-07-09", - "time": "23:14", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.15", - "date": "2026-07-09", - "time": "23:14", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.14", - "date": "2026-07-09", - "time": "22:59", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.13", - "date": "2026-07-09", - "time": "22:59", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.12", - "date": "2026-07-09", - "time": "22:59", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.11", - "date": "2026-07-09", - "time": "22:58", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.10", - "date": "2026-07-09", - "time": "22:58", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.9", - "date": "2026-07-09", - "time": "22:58", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.8", - "date": "2026-07-09", - "time": "22:54", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.7", - "date": "2026-07-09", - "time": "22:45", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.6", - "date": "2026-07-09", - "time": "22:45", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.5", - "date": "2026-07-09", - "time": "22:44", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.4", - "date": "2026-07-09", - "time": "22:44", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", - "styles/index.css" - ] - }, { "version": "v1.3", - "date": "2026-07-09", - "time": "22:44", - "summary": "更新页面样式", + "date": "2026-07-12", + "time": "22:45", + "summary": "业务部台账:分组表头与表格可读性增强", + "details": [ + "统一边框 token、分组表头双层样式(业务板块 + 业绩/成本/盈亏)", + "冻结列滚动修复;金额列防裁切;盈亏钻取链接样式调整" + ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", - "data/excel-2026-seed.json", - "index.tsx", "styles/index.css" ] }, @@ -2486,9 +1154,9 @@ }, "lease-business-ledger": { "title": "租赁业务台账", - "version": "v1.8", - "revision": 8, - "lastUpdated": "2026-07-11T16:20:27.717Z", + "version": "v1.6", + "revision": 6, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "773015ea35fa4f62c2b330e5bb7dcb099f5fac660a61c8831ea03bf00edc8d2f", "trackedFiles": [ ".spec/prototype-comments.json", @@ -2523,64 +1191,29 @@ "utils/ledger.ts" ], "changelog": [ - { - "version": "v1.8", - "date": "2026-07-12", - "time": "00:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/AccidentLinkModal.tsx", - "components/ConfirmMarkModal.tsx", - "components/DeleteConfirmModal.tsx", - "components/FilterPanel.tsx", - "components/LeaseLedgerImportModal.tsx", - "components/LeaseLedgerTable.tsx", - "components/LedgerDetailPopover.tsx", - "components/LedgerKpiRow.tsx", - "components/LedgerLineItemsCell.tsx" - ] - }, - { - "version": "v1.7", - "date": "2026-07-12", - "time": "00:17", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/AccidentLinkModal.tsx", - "components/ConfirmMarkModal.tsx", - "components/DeleteConfirmModal.tsx", - "components/FilterPanel.tsx", - "components/LeaseLedgerImportModal.tsx", - "components/LeaseLedgerTable.tsx", - "components/LedgerDetailPopover.tsx", - "components/LedgerKpiRow.tsx", - "components/LedgerLineItemsCell.tsx" - ] - }, { "version": "v1.6", "date": "2026-07-12", - "time": "00:17", - "summary": "更新需求说明与标注", + "time": "22:45", + "summary": "租赁业务台账:操作区统一为 OperationActions,标注壳切换", + "details": [ + "行操作:编辑 / 操作记录 / 保存(编辑态)", + "关联收款、事故/维保/收据链接弹窗保留", + "接入 PrototypeAnnotationHost,移除内嵌原型导航目录" + ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", "components/AccidentLinkModal.tsx", "components/ConfirmMarkModal.tsx", "components/DeleteConfirmModal.tsx", "components/FilterPanel.tsx", "components/LeaseLedgerImportModal.tsx", "components/LeaseLedgerTable.tsx", - "components/LedgerDetailPopover.tsx", - "components/LedgerKpiRow.tsx", - "components/LedgerLineItemsCell.tsx" + "components/LedgerLineItemsCell.tsx", + "components/MaintenanceLinkModal.tsx", + "components/OperationHistoryModal.tsx", + "components/ReceiptLinkModal.tsx", + "index.tsx" ] }, { @@ -2697,10 +1330,10 @@ }, "lease-business-detail": { "title": "租赁业务明细", - "version": "v1.108", - "revision": 108, - "lastUpdated": "2026-07-10T09:49:25.059Z", - "contentHash": "0f7be74931eda02bc0e3ccaeb47ac65130053fdfc2ea68d334380b8e2c30dcce", + "version": "v1.3", + "revision": 3, + "lastUpdated": "2026-07-13T01:26:44.092Z", + "contentHash": "f1ec8e7d93bc9621988474fcf264d3edd798b987bee5527cfddb9ed607c641ec", "trackedFiles": [ ".spec/prototype-comments.json", ".spec/prototype-review.md", @@ -2735,9 +1368,9 @@ ], "changelog": [ { - "version": "v1.108", - "date": "2026-07-10", - "time": "17:49", + "version": "v1.3", + "date": "2026-07-13", + "time": "09:26", "summary": "更新需求说明与标注", "files": [ ".spec/prototype-comments.json", @@ -2755,581 +1388,65 @@ ] }, { - "version": "v1.107", - "date": "2026-07-10", - "time": "17:49", - "summary": "更新需求说明与标注", + "version": "v1.2", + "date": "2026-07-12", + "time": "22:45", + "summary": "租赁业务明细大改版:收款状态、47 列宽表、字段校验与变更记录", + "details": [ + "新增收款状态列(未收款/部分收款/已结清);月份、部门+业务员合并展示;表尾 23 项金额汇总", + "氢费可钻取 Popover;编辑/删除/变更记录;公式列(应收合计、未收、盈亏、氢费等)自动重算", + "客户/提车日期/租金等与车辆/客户/合同交叉校验,支持一键替换建议值", + "批量导入 36 列手工字段、导出 47 列;部分成功 + 错误日志;已对账锁定与主管解锁" + ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", ".spec/requirements-prd.md", "columnHeaderTips.ts", "components/DetailChangeLogModal.tsx", "components/DetailDeleteConfirmModal.tsx", "components/DetailEditModal.tsx", "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", "components/DetailTable.tsx", "components/FieldCheckIcon.tsx", - "components/FilterPanel.tsx" + "components/FilterPanel.tsx", + "components/TableHeaderTip.tsx", + "components/tableColumns.ts", + "data/change-log-seed.json" ] }, { - "version": "v1.106", - "date": "2026-07-10", - "time": "17:49", - "summary": "更新需求说明与标注", + "version": "v1.1", + "date": "2026-07-09", + "time": "17:52", + "summary": "页面逻辑与交互:DetailImportModal.tsx、DetailKpiRow.tsx、DetailTable.tsx、FilterPanel.tsx 等", + "details": [ + "样式与布局:index.css", + "需求说明与 PRD:prototype-review.md", + "演示数据与配置:rows.json" + ], + "commit": "6ccbbef", "files": [ - ".spec/prototype-comments.json", ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", "components/DetailImportModal.tsx", "components/DetailKpiRow.tsx", "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx", - "components/FilterPanel.tsx" - ] - }, - { - "version": "v1.105", - "date": "2026-07-10", - "time": "17:49", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx", - "components/FilterPanel.tsx" - ] - }, - { - "version": "v1.104", - "date": "2026-07-10", - "time": "12:21", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx", - "components/FilterPanel.tsx" - ] - }, - { - "version": "v1.103", - "date": "2026-07-10", - "time": "12:21", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.102", - "date": "2026-07-10", - "time": "12:21", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.101", - "date": "2026-07-10", - "time": "12:21", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.100", - "date": "2026-07-10", - "time": "12:21", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.99", - "date": "2026-07-10", - "time": "12:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.98", - "date": "2026-07-10", - "time": "12:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.97", - "date": "2026-07-10", - "time": "12:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.96", - "date": "2026-07-10", - "time": "12:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.95", - "date": "2026-07-10", - "time": "12:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.94", - "date": "2026-07-10", - "time": "12:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.93", - "date": "2026-07-10", - "time": "12:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.92", - "date": "2026-07-10", - "time": "12:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.91", - "date": "2026-07-10", - "time": "12:20", - "summary": "更新 payment-status.ts", - "files": [ - "utils/payment-status.ts" - ] - }, - { - "version": "v1.90", - "date": "2026-07-10", - "time": "12:13", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.89", - "date": "2026-07-10", - "time": "12:13", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.88", - "date": "2026-07-10", - "time": "12:13", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.87", - "date": "2026-07-10", - "time": "12:13", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.86", - "date": "2026-07-10", - "time": "12:13", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.85", - "date": "2026-07-10", - "time": "11:25", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.84", - "date": "2026-07-10", - "time": "11:24", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.83", - "date": "2026-07-10", - "time": "11:22", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.82", - "date": "2026-07-10", - "time": "11:21", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.81", - "date": "2026-07-10", - "time": "11:21", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.80", - "date": "2026-07-10", - "time": "11:21", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" - ] - }, - { - "version": "v1.79", - "date": "2026-07-10", - "time": "11:21", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/prototype-review.md", - ".spec/requirements-prd.md", - "columnHeaderTips.ts", - "components/DetailChangeLogModal.tsx", - "components/DetailConfirmModal.tsx", - "components/DetailDeleteConfirmModal.tsx", - "components/DetailEditModal.tsx", - "components/DetailImportModal.tsx", - "components/DetailKpiRow.tsx", - "components/DetailTable.tsx", - "components/FieldCheckIcon.tsx" + "components/FilterPanel.tsx", + "components/tableColumns.ts", + "data/rows.json", + "index.tsx", + "styles/index.css", + "types.ts", + "utils/batch-io.ts", + "utils/calc-detail.ts" ] } ] }, "self-operated-business-ledger": { "title": "物流业务明细", - "version": "v1.72", - "revision": 72, - "lastUpdated": "2026-07-11T16:20:46.376Z", + "version": "v1.5", + "revision": 5, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "d4e29b38f9458eeb0d10dd3e97668af63ead0084891129cf1085af48f2ef55bc", "trackedFiles": [ ".spec/prototype-comments.json", @@ -3350,13 +1467,18 @@ ], "changelog": [ { - "version": "v1.72", + "version": "v1.5", "date": "2026-07-12", - "time": "00:20", - "summary": "更新需求说明与标注", + "time": "22:45", + "summary": "物流业务明细:更名、列对齐 Excel、批量导入与自动计算", + "details": [ + "模块更名:物流业务台账 → 物流业务明细", + "列对齐 Excel 1.2:薪资、电费、日社保/挂车/停车/轮胎、线路计价等;系统车型列", + "新增批量导入:模板下载、错误日志、导入后自动计算金额/总成本/盈亏", + "移除行勾选与批量删除" + ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", "components/FilterPanel.tsx", "components/LedgerKpiRow.tsx", "components/SelfImportModal.tsx", @@ -3366,585 +1488,85 @@ "index.tsx", "styles/index.css", "types.ts", - "utils/batch-io.ts" + "utils/batch-io.ts", + "utils/calc-row.ts", + "utils/ledger.ts" ] }, { - "version": "v1.71", - "date": "2026-07-12", - "time": "00:19", - "summary": "更新需求说明与标注", + "version": "v1.4", + "date": "2026-07-09", + "time": "17:52", + "summary": "页面逻辑与交互:index.tsx", + "details": [], + "commit": "6ccbbef", + "files": [ + "index.tsx" + ] + }, + { + "version": "v1.3", + "date": "2026-07-08", + "time": "11:44", + "summary": "页面逻辑与交互:FilterPanel.tsx、SelfLedgerTable.tsx、index.tsx", + "details": [], + "commit": "6d14c58", + "files": [ + "components/FilterPanel.tsx", + "components/SelfLedgerTable.tsx", + "index.tsx" + ] + }, + { + "version": "v1.2", + "date": "2026-07-06", + "time": "17:18", + "summary": "页面逻辑与交互:FilterPanel.tsx、SelfLedgerTable.tsx、tableColumns.ts、index.tsx 等", + "details": [ + "样式与布局:index.css", + "需求说明与 PRD:requirements-prd.md" + ], + "commit": "d0d7458", + "files": [ + ".spec/requirements-prd.md", + "components/FilterPanel.tsx", + "components/SelfLedgerTable.tsx", + "components/tableColumns.ts", + "index.tsx", + "styles/index.css", + "utils/ledger.ts" + ] + }, + { + "version": "v1.1", + "date": "2026-06-30", + "time": "15:27", + "summary": "页面逻辑与交互:FilterPanel.tsx、LedgerKpiRow.tsx、SelfLedgerTable.tsx、index.tsx 等", + "details": [ + "样式与布局:index.css", + "需求说明与 PRD:requirements-prd.md", + "演示数据与配置:rows.json" + ], + "commit": "af29b26", "files": [ - ".spec/prototype-comments.json", ".spec/requirements-prd.md", "components/FilterPanel.tsx", "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", "data/rows.json", "index.tsx", "styles/index.css", "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.70", - "date": "2026-07-12", - "time": "00:16", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.69", - "date": "2026-07-10", - "time": "15:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.68", - "date": "2026-07-10", - "time": "15:20", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.67", - "date": "2026-07-10", - "time": "15:19", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.66", - "date": "2026-07-10", - "time": "15:19", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.65", - "date": "2026-07-10", - "time": "15:19", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.64", - "date": "2026-07-10", - "time": "15:19", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.63", - "date": "2026-07-10", - "time": "15:19", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.62", - "date": "2026-07-10", - "time": "15:19", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.61", - "date": "2026-07-10", - "time": "15:19", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.60", - "date": "2026-07-10", - "time": "14:54", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.59", - "date": "2026-07-10", - "time": "14:54", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.58", - "date": "2026-07-10", - "time": "14:54", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.57", - "date": "2026-07-10", - "time": "14:54", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.56", - "date": "2026-07-10", - "time": "14:54", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.55", - "date": "2026-07-10", - "time": "14:53", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.54", - "date": "2026-07-10", - "time": "14:53", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.53", - "date": "2026-07-10", - "time": "14:53", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.52", - "date": "2026-07-10", - "time": "14:53", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.51", - "date": "2026-07-10", - "time": "14:53", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.50", - "date": "2026-07-10", - "time": "14:53", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.49", - "date": "2026-07-10", - "time": "14:53", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.48", - "date": "2026-07-10", - "time": "14:53", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.47", - "date": "2026-07-10", - "time": "14:53", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.46", - "date": "2026-07-10", - "time": "14:53", - "summary": "更新 vehicle-ref.ts", - "files": [ - "utils/vehicle-ref.ts" - ] - }, - { - "version": "v1.45", - "date": "2026-07-10", - "time": "14:51", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.44", - "date": "2026-07-10", - "time": "14:51", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" - ] - }, - { - "version": "v1.43", - "date": "2026-07-10", - "time": "14:50", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "components/FilterPanel.tsx", - "components/LedgerKpiRow.tsx", - "components/SelfImportModal.tsx", - "components/SelfLedgerTable.tsx", - "components/tableColumns.ts", - "data/rows.json", - "index.tsx", - "styles/index.css", - "types.ts", - "utils/batch-io.ts" + "utils/ledger.ts" ] } ] }, "vehicle-h2-fee-ledger": { "title": "车辆氢费明细", - "version": "v1.7", - "revision": 7, - "lastUpdated": "2026-07-11T21:04:17.350Z", + "version": "v1.5", + "revision": 5, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "ee0d8d6dfc26c9116c41f5928dcd8c7c6b0cde7909859862024ed7a99f6e1985", "trackedFiles": [ ".spec/PRD.md", @@ -3954,41 +1576,16 @@ "index.tsx" ], "changelog": [ - { - "version": "v1.7", - "date": "2026-07-12", - "time": "05:04", - "summary": "更新需求说明与标注", - "files": [ - ".spec/PRD.md", - ".spec/prototype-comments.json", - "globals.ts", - "H2LedgerPage.jsx", - "index.tsx" - ] - }, - { - "version": "v1.6", - "date": "2026-07-12", - "time": "05:04", - "summary": "更新需求说明与标注", - "files": [ - ".spec/PRD.md", - ".spec/prototype-comments.json", - "globals.ts", - "H2LedgerPage.jsx", - "index.tsx" - ] - }, { "version": "v1.5", "date": "2026-07-12", - "time": "05:04", - "summary": "更新需求说明与标注", + "time": "22:45", + "summary": "车辆氢费明细:标注壳与操作区统一", + "details": [ + "OperationActions;标注目录规范化" + ], + "commit": "131b963", "files": [ - ".spec/PRD.md", - ".spec/prototype-comments.json", - "globals.ts", "H2LedgerPage.jsx", "index.tsx" ] @@ -4050,9 +1647,9 @@ }, "vehicle-maintenance-ledger": { "title": "维修保养台账", - "version": "v1.5", - "revision": 5, - "lastUpdated": "2026-07-11T21:03:55.548Z", + "version": "v1.2", + "revision": 2, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "d5e11ebaf8e2df28936bdd8e9a21f43af079a0f8db562d983c1144f43bfcd404", "trackedFiles": [ ".spec/prototype-comments.json", @@ -4063,60 +1660,18 @@ "styles/index.css" ], "changelog": [ - { - "version": "v1.5", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "globals.ts", - "index.tsx", - "MaintenanceLedgerPage.jsx", - "styles/index.css" - ] - }, - { - "version": "v1.4", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "globals.ts", - "index.tsx", - "MaintenanceLedgerPage.jsx", - "styles/index.css" - ] - }, - { - "version": "v1.3", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新需求说明与标注", - "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "globals.ts", - "index.tsx", - "MaintenanceLedgerPage.jsx", - "styles/index.css" - ] - }, { "version": "v1.2", "date": "2026-07-12", - "time": "00:17", - "summary": "更新需求说明与标注", + "time": "22:45", + "summary": "车辆维修明细:标注壳与操作区统一", + "details": [ + "OperationActions;标注目录规范化" + ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", - ".spec/requirements-prd.md", - "globals.ts", - "index.tsx", "MaintenanceLedgerPage.jsx", - "styles/index.css" + "index.tsx" ] }, { @@ -4141,9 +1696,9 @@ }, "payment-records": { "title": "收款记录", - "version": "v1.7", - "revision": 7, - "lastUpdated": "2026-07-11T21:00:51.384Z", + "version": "v1.3", + "revision": 3, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "fb2974cbf5518761021be442e2e9bd949eb32fc947dd2ddd8572a153af452150", "trackedFiles": [ ".spec/prototype-comments.json", @@ -4162,104 +1717,23 @@ "utils/payment.ts" ], "changelog": [ - { - "version": "v1.7", - "date": "2026-07-12", - "time": "05:00", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "components/AddPaymentModal.tsx", - "components/BillLinkModal.tsx", - "components/FilterPanel.tsx", - "components/LinkedBillsNestedTable.tsx", - "components/PaymentKpiDetailFilterBar.tsx", - "components/PaymentKpiDetailModal.tsx", - "components/PaymentRecordsTable.tsx", - "data/bills.json", - "data/records.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.6", - "date": "2026-07-12", - "time": "00:19", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "components/AddPaymentModal.tsx", - "components/BillLinkModal.tsx", - "components/FilterPanel.tsx", - "components/LinkedBillsNestedTable.tsx", - "components/PaymentKpiDetailFilterBar.tsx", - "components/PaymentKpiDetailModal.tsx", - "components/PaymentRecordsTable.tsx", - "data/bills.json", - "data/records.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.5", - "date": "2026-07-12", - "time": "00:19", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "components/AddPaymentModal.tsx", - "components/BillLinkModal.tsx", - "components/FilterPanel.tsx", - "components/LinkedBillsNestedTable.tsx", - "components/PaymentKpiDetailFilterBar.tsx", - "components/PaymentKpiDetailModal.tsx", - "components/PaymentRecordsTable.tsx", - "data/bills.json", - "data/records.json", - "index.tsx", - "styles/index.css" - ] - }, - { - "version": "v1.4", - "date": "2026-07-11", - "time": "17:17", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "components/AddPaymentModal.tsx", - "components/BillLinkModal.tsx", - "components/FilterPanel.tsx", - "components/LinkedBillsNestedTable.tsx", - "components/PaymentKpiDetailFilterBar.tsx", - "components/PaymentKpiDetailModal.tsx", - "components/PaymentRecordsTable.tsx", - "data/bills.json", - "data/records.json", - "index.tsx", - "styles/index.css" - ] - }, { "version": "v1.3", - "date": "2026-07-11", - "time": "17:17", - "summary": "更新页面样式", + "date": "2026-07-12", + "time": "22:45", + "summary": "收款记录:OperationActions 与关联账单操作", + "details": [ + "操作列标准化;表格新增「关联账单」", + "标注壳切换" + ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", - "components/AddPaymentModal.tsx", - "components/BillLinkModal.tsx", "components/FilterPanel.tsx", - "components/LinkedBillsNestedTable.tsx", "components/PaymentKpiDetailFilterBar.tsx", "components/PaymentKpiDetailModal.tsx", "components/PaymentRecordsTable.tsx", - "data/bills.json", - "data/records.json", "index.tsx", - "styles/index.css" + "utils/payment.ts" ] }, { @@ -4316,9 +1790,9 @@ }, "vehicle-return-settlement": { "title": "还车应结款", - "version": "v1.2", - "revision": 2, - "lastUpdated": "2026-07-09T09:52:00.000Z", + "version": "v1.3", + "revision": 3, + "lastUpdated": "2026-07-12T14:44:00.000Z", "contentHash": "76326ecfbf6eb1d0c27018862e6ae071efb56d674ad6e763146b5b2a0d09c86a", "trackedFiles": [ ".spec/prototype-comments.json", @@ -4328,6 +1802,17 @@ "VehicleReturnSettlementHandle.jsx" ], "changelog": [ + { + "version": "v1.3", + "date": "2026-07-12", + "time": "22:44", + "summary": "页面逻辑与交互:VehicleReturnSettlementHandle.jsx", + "details": [], + "commit": "131b963", + "files": [ + "VehicleReturnSettlementHandle.jsx" + ] + }, { "version": "v1.2", "date": "2026-07-09", @@ -4361,9 +1846,9 @@ }, "vehicle-return-settlement-v2": { "title": "还车应结款-新", - "version": "v1.4", - "revision": 4, - "lastUpdated": "2026-07-12T08:06:00.871Z", + "version": "v1.2", + "revision": 2, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "a581b2271b6687a81a82ae72e0f6e8523991596cad86c30080f79354b65b9a63", "trackedFiles": [ ".spec/prototype-comments.json", @@ -4375,46 +1860,16 @@ "vrsV2Data.js" ], "changelog": [ - { - "version": "v1.4", - "date": "2026-07-12", - "time": "16:06", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "index.tsx", - "styles/index.css", - "VehicleReturnSettlementV2App.jsx", - "VehicleReturnSettlementV2Detail.jsx", - "VehicleReturnSettlementV2List.jsx", - "vrsV2Data.js" - ] - }, - { - "version": "v1.3", - "date": "2026-07-12", - "time": "00:20", - "summary": "更新页面样式", - "files": [ - ".spec/prototype-comments.json", - "index.tsx", - "styles/index.css", - "VehicleReturnSettlementV2App.jsx", - "VehicleReturnSettlementV2Detail.jsx", - "VehicleReturnSettlementV2List.jsx", - "vrsV2Data.js" - ] - }, { "version": "v1.2", - "date": "2026-07-11", - "time": "16:41", - "summary": "更新页面样式", + "date": "2026-07-12", + "time": "22:45", + "summary": "还车应结算 V2:OperationActions 统一为详情主操作", + "details": [ + "列表操作列标准化" + ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", - "index.tsx", - "styles/index.css", - "VehicleReturnSettlementV2App.jsx", "VehicleReturnSettlementV2Detail.jsx", "VehicleReturnSettlementV2List.jsx", "vrsV2Data.js" @@ -4462,23 +1917,20 @@ "summary": "统一标注壳与操作规范,租赁明细/合同/提车应收款增强,新增任务工单,同步合包页面", "details": [ "【平台】全项目接入 PrototypeAnnotationHost,PRD 迁入右侧标注目录;列表统一 OperationActions 与工具栏图标规范", - "【租赁业务明细】新增收款状态列、47 列宽表与 23 项汇总;氢费钻取、字段交叉校验、变更记录、批量导入导出与主管解锁", - "【租赁合同】KPI/状态收敛;新增查看页、线上/线下签署、交付变更、附加费用拆分、风控条款检测;与提车应收联动", - "【提车应收款】独立原型上线:自动生成/手动办理、15 日前后分档计费、与合同双向 bridge;finance 合包仅保留租赁账单", - "【任务工单】新增业管发起端:合同/独立双入口、六类任务类型、KPI 视角与督办催办(执行端后续)", - "【物流业务明细】原物流业务台账更名;列对齐 Excel、系统车型列、批量导入与自动计算", - "【车辆管理】在租车队 KPI 迁入;车型分布弹窗;详情 Tab 与列表样式优化", - "【客户/模板/保险】OperationActions 统一;模板新增先付后用/先用后付;业务部台账表格视觉增强", - "【合包】business/ops/finance/ledger-data/lease-contract/h2-station 等移除面包屑并标准化操作区;workbench 提车入口改跳独立原型", - "【下线】移除 oneos-web-login、requirements、vehicle-asset 合包;侧栏新增任务工单与提车应收款" + "【租赁业务明细】收款状态列、47 列宽表、氢费钻取、字段校验、变更记录、导入导出与主管解锁", + "【租赁合同】KPI/状态收敛、查看页、线上/线下签署、交付变更、附加费用与提车应收联动", + "【提车应收款】独立原型上线;finance 合包仅保留租赁账单;工作台快捷入口改跳独立原型", + "【任务工单】新增业管发起端:合同/独立双入口、六类任务类型与督办催办", + "【合包】business/ops/finance/ledger-data/lease-contract/h2-station 等移除面包屑并标准化操作区", + "【下线】移除 login/requirements/vehicle-asset 合包;侧栏新增任务工单与提车应收款", + "【发布】导航页固定发布至 /oneos-prototype-nav/index.html" ], + "commit": "131b963", "files": [ - ".spec/prototype-comments.json", "index.tsx", "nav-data.ts", "style.css", - "xll-nav-menu.json", - "xll-nav-source.json" + "xll-nav-menu.json" ] }, { @@ -4521,9 +1973,9 @@ }, "oneos-web-data-analysis": { "title": "oneos web data analysis", - "version": "v1.36", - "revision": 36, - "lastUpdated": "2026-07-11T21:02:03.958Z", + "version": "v1.3", + "revision": 3, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "5c6df8bcc6e82ed8de7e02a3c7dba3ef7f67ccb3b65e006107169eba5e4ad228", "trackedFiles": [ "index.tsx", @@ -4539,552 +1991,49 @@ ], "changelog": [ { - "version": "v1.36", + "version": "v1.3", "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", + "time": "22:45", + "summary": "数据分析合包:业务部台账列宽与盈亏着色优化", + "details": [ + "9 页操作区标准化;业务部台账列宽加大;盈亏负值着色" + ], + "commit": "131b963", "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" + "index.tsx" ] }, { - "version": "v1.35", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", + "version": "v1.2", + "date": "2026-06-30", + "time": "16:54", + "summary": "页面逻辑与交互:index.tsx", + "details": [], + "commit": "0982837", "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" + "index.tsx" ] }, { - "version": "v1.34", - "date": "2026-07-12", - "time": "00:20", - "summary": "更新页面逻辑与交互", + "version": "v1.1", + "date": "2026-06-30", + "time": "16:36", + "summary": "Import desktop web originals into dedicated prototypes with a shared legacy shell, sync script, and a new「ONE-OS Web 端」sidebar section for review alongside existing refactored pages.", + "details": [ + "页面逻辑与交互:index.tsx" + ], + "commit": "d71ebc5", "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.33", - "date": "2026-07-12", - "time": "00:20", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.32", - "date": "2026-07-11", - "time": "16:57", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.31", - "date": "2026-07-09", - "time": "23:47", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.30", - "date": "2026-07-09", - "time": "23:47", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.29", - "date": "2026-07-09", - "time": "23:43", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.28", - "date": "2026-07-09", - "time": "23:26", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.27", - "date": "2026-07-09", - "time": "23:24", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.26", - "date": "2026-07-09", - "time": "23:24", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.25", - "date": "2026-07-09", - "time": "23:24", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.24", - "date": "2026-07-09", - "time": "23:23", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.23", - "date": "2026-07-09", - "time": "23:23", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.22", - "date": "2026-07-09", - "time": "23:23", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.21", - "date": "2026-07-09", - "time": "23:23", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.20", - "date": "2026-07-09", - "time": "23:23", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.19", - "date": "2026-07-09", - "time": "23:22", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.18", - "date": "2026-07-09", - "time": "23:22", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.17", - "date": "2026-07-09", - "time": "23:22", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.16", - "date": "2026-07-09", - "time": "23:22", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.15", - "date": "2026-07-09", - "time": "23:22", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.14", - "date": "2026-07-09", - "time": "23:14", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.13", - "date": "2026-07-09", - "time": "23:12", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.12", - "date": "2026-07-09", - "time": "23:12", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.11", - "date": "2026-07-09", - "time": "23:12", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.10", - "date": "2026-07-09", - "time": "23:12", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.9", - "date": "2026-07-09", - "time": "22:59", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.8", - "date": "2026-07-09", - "time": "22:58", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" - ] - }, - { - "version": "v1.7", - "date": "2026-07-09", - "time": "22:58", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-客户服务部业务统计报表.jsx", - "pages/02-物流业务台账.jsx", - "pages/03-物流业务月度统计.jsx", - "pages/04-业务部汇总台账.jsx", - "pages/05-业务部台账.jsx", - "pages/06-业务部业绩明细.jsx", - "pages/07-业务台账.jsx", - "pages/08-租赁车辆收入明细.jsx", - "pages/09-租赁客户氢费台账.jsx" + "index.tsx" ] } ] }, "task-work-order": { "title": "task work order", - "version": "v1.18", - "revision": 18, - "lastUpdated": "2026-07-11T16:24:15.965Z", + "version": "v1.1", + "revision": 1, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "15f17a2d566dbe11036326fbc3727d43f23bdf8a67e3400e68052f1f0eda57e0", "trackedFiles": [ ".spec/2026-07-10-requirements.md", @@ -5095,233 +2044,23 @@ "TaskWorkOrderPage.jsx" ], "changelog": [ - { - "version": "v1.18", - "date": "2026-07-12", - "time": "00:24", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.17", - "date": "2026-07-12", - "time": "00:17", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.16", - "date": "2026-07-11", - "time": "11:03", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.15", - "date": "2026-07-11", - "time": "10:31", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.14", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.13", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.12", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.11", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.10", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.9", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.8", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.7", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "components/task-work-order-kpi.jsx", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.6", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新页面逻辑与交互", - "files": [ - "components/task-work-order-kpi.jsx" - ] - }, - { - "version": "v1.5", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.4", - "date": "2026-07-11", - "time": "10:30", - "summary": "更新需求说明与标注", - "files": [ - ".spec/2026-07-10-requirements.md", - "data/task-work-order-seed.js", - "index.tsx", - "styles/index.css", - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.3", - "date": "2026-07-10", - "time": "23:10", - "summary": "更新页面逻辑与交互", - "files": [ - "TaskWorkOrderPage.jsx" - ] - }, - { - "version": "v1.2", - "date": "2026-07-10", - "time": "23:09", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx" - ] - }, { "version": "v1.1", - "date": "2026-07-10", - "time": "23:09", - "summary": "更新页面样式", + "date": "2026-07-12", + "time": "22:45", + "summary": "任务工单新原型:业管发起端(合同/独立双入口)", + "details": [ + "任务类型:里程履约、维保履约、政策兑现、付款/交付节点、条款跟进、通用临时", + "列表 KPI:全部/我发布的/我督办的 + 状态视角;详情含进度、反馈、催办", + "执行人不可见合同原文与金额(第一版仅业管端)" + ], + "commit": "131b963", "files": [ + ".spec/2026-07-10-requirements.md", + "TaskWorkOrderPage.jsx", + "components/task-work-order-kpi.jsx", + "data/task-work-order-seed.js", + "index.tsx", "styles/index.css" ] } @@ -5329,10 +2068,10 @@ }, "vehicle-pickup-receivable": { "title": "提车应收款", - "version": "v1.227", - "revision": 227, - "lastUpdated": "2026-07-12T14:34:09.897Z", - "contentHash": "cf81a91cd3cba609253f27abc6094c2c8ab63b9ab9542cec13aace0fe5db5a3e", + "version": "v1.167", + "revision": 167, + "lastUpdated": "2026-07-12T17:21:58.954Z", + "contentHash": "266723009574aadd9d2ee8dd0fc7a6bb36f086bd146a17fbf4c61b1746e7353f", "trackedFiles": [ ".spec/PRD.md", ".spec/prototype-comments.json", @@ -5342,13 +2081,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ], "changelog": [ { - "version": "v1.227", - "date": "2026-07-12", - "time": "22:34", + "version": "v1.167", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5359,13 +2100,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.226", - "date": "2026-07-12", - "time": "22:34", + "version": "v1.166", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5376,13 +2119,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.225", - "date": "2026-07-12", - "time": "22:34", + "version": "v1.165", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5393,13 +2138,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.224", - "date": "2026-07-12", - "time": "22:33", + "version": "v1.164", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5410,13 +2157,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.223", - "date": "2026-07-12", - "time": "22:33", + "version": "v1.163", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5427,13 +2176,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.222", - "date": "2026-07-12", - "time": "22:33", + "version": "v1.162", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5444,13 +2195,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.221", - "date": "2026-07-12", - "time": "22:33", + "version": "v1.161", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5461,13 +2214,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.220", - "date": "2026-07-12", - "time": "22:28", + "version": "v1.160", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5478,13 +2233,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.219", - "date": "2026-07-12", - "time": "22:28", + "version": "v1.159", + "date": "2026-07-13", + "time": "01:16", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5495,13 +2252,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.218", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.158", + "date": "2026-07-13", + "time": "01:16", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5512,13 +2271,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.217", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.157", + "date": "2026-07-13", + "time": "01:16", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5529,13 +2290,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.216", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.156", + "date": "2026-07-13", + "time": "01:16", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5546,13 +2309,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.215", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.155", + "date": "2026-07-13", + "time": "01:16", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5563,13 +2328,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.214", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.154", + "date": "2026-07-13", + "time": "01:04", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5580,13 +2347,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.213", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.153", + "date": "2026-07-13", + "time": "01:03", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5597,13 +2366,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.212", - "date": "2026-07-12", - "time": "22:24", + "version": "v1.152", + "date": "2026-07-13", + "time": "01:03", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5614,13 +2385,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.211", - "date": "2026-07-12", - "time": "22:24", + "version": "v1.151", + "date": "2026-07-13", + "time": "01:03", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5631,13 +2404,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.210", - "date": "2026-07-12", - "time": "22:24", + "version": "v1.150", + "date": "2026-07-13", + "time": "01:03", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5648,13 +2423,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.209", - "date": "2026-07-12", - "time": "22:24", + "version": "v1.149", + "date": "2026-07-13", + "time": "00:54", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5665,13 +2442,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.208", - "date": "2026-07-12", - "time": "22:24", + "version": "v1.148", + "date": "2026-07-13", + "time": "00:54", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5682,13 +2461,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.207", - "date": "2026-07-12", - "time": "22:18", + "version": "v1.147", + "date": "2026-07-13", + "time": "00:54", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5699,13 +2480,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.206", - "date": "2026-07-12", - "time": "22:18", + "version": "v1.146", + "date": "2026-07-13", + "time": "00:54", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5716,13 +2499,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.205", - "date": "2026-07-12", - "time": "22:18", + "version": "v1.145", + "date": "2026-07-13", + "time": "00:54", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5733,13 +2518,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.204", - "date": "2026-07-12", - "time": "22:18", + "version": "v1.144", + "date": "2026-07-13", + "time": "00:50", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5750,13 +2537,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.203", - "date": "2026-07-12", - "time": "22:17", + "version": "v1.143", + "date": "2026-07-13", + "time": "00:50", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5767,13 +2556,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.202", - "date": "2026-07-12", - "time": "22:17", + "version": "v1.142", + "date": "2026-07-13", + "time": "00:49", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5784,13 +2575,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.201", - "date": "2026-07-12", - "time": "22:17", + "version": "v1.141", + "date": "2026-07-13", + "time": "00:49", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5801,13 +2594,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.200", - "date": "2026-07-12", - "time": "22:16", + "version": "v1.140", + "date": "2026-07-13", + "time": "00:49", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5818,13 +2613,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.199", - "date": "2026-07-12", - "time": "22:16", + "version": "v1.139", + "date": "2026-07-13", + "time": "00:45", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5835,13 +2632,15 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { - "version": "v1.198", - "date": "2026-07-12", - "time": "22:16", + "version": "v1.138", + "date": "2026-07-13", + "time": "00:45", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -5852,6 +2651,8 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] } @@ -5859,9 +2660,9 @@ }, "oneos-web-finance": { "title": "oneos web finance", - "version": "v1.66", - "revision": 66, - "lastUpdated": "2026-07-12T13:30:10.471Z", + "version": "v1.4", + "revision": 4, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "fbfde8aca3da5329961b52f23fb2f304ce1c83c7d01c9801390201f7c22e8466", "trackedFiles": [ "index.tsx", @@ -5878,582 +2679,61 @@ ], "changelog": [ { - "version": "v1.66", + "version": "v1.4", "date": "2026-07-12", - "time": "21:30", - "summary": "更新页面逻辑与交互", + "time": "22:45", + "summary": "财务管理合包:提车应收款剥离,仅保留租赁账单", + "details": [ + "提车应收款 6 页移除;合包默认页改为租赁账单", + "提车流程由 vehicle-pickup-receivable 独立原型承接" + ], + "commit": "131b963", "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" + "index.tsx" ] }, { - "version": "v1.65", - "date": "2026-07-12", - "time": "21:30", - "summary": "更新页面逻辑与交互", + "version": "v1.3", + "date": "2026-07-08", + "time": "11:44", + "summary": "页面逻辑与交互:index.tsx", + "details": [], + "commit": "6d14c58", "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" + "index.tsx" ] }, { - "version": "v1.64", - "date": "2026-07-12", - "time": "21:30", - "summary": "更新页面逻辑与交互", + "version": "v1.2", + "date": "2026-06-30", + "time": "16:54", + "summary": "页面逻辑与交互:index.tsx", + "details": [], + "commit": "0982837", "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" + "index.tsx" ] }, { - "version": "v1.63", - "date": "2026-07-12", - "time": "21:30", - "summary": "更新页面逻辑与交互", + "version": "v1.1", + "date": "2026-06-30", + "time": "16:36", + "summary": "Import desktop web originals into dedicated prototypes with a shared legacy shell, sync script, and a new「ONE-OS Web 端」sidebar section for review alongside existing refactored pages.", + "details": [ + "页面逻辑与交互:index.tsx" + ], + "commit": "d71ebc5", "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.62", - "date": "2026-07-12", - "time": "21:29", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.61", - "date": "2026-07-12", - "time": "21:29", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.60", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.59", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.58", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.57", - "date": "2026-07-12", - "time": "00:18", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.56", - "date": "2026-07-11", - "time": "17:16", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.55", - "date": "2026-07-11", - "time": "17:16", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.54", - "date": "2026-07-11", - "time": "17:16", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.53", - "date": "2026-07-11", - "time": "17:16", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.52", - "date": "2026-07-11", - "time": "17:16", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.51", - "date": "2026-07-11", - "time": "17:15", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.50", - "date": "2026-07-11", - "time": "17:15", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.49", - "date": "2026-07-11", - "time": "17:15", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.48", - "date": "2026-07-11", - "time": "17:15", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.47", - "date": "2026-07-11", - "time": "17:15", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.46", - "date": "2026-07-11", - "time": "17:15", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.45", - "date": "2026-07-11", - "time": "17:15", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.44", - "date": "2026-07-11", - "time": "17:10", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.43", - "date": "2026-07-11", - "time": "17:09", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.42", - "date": "2026-07-11", - "time": "17:09", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.41", - "date": "2026-07-11", - "time": "17:09", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.40", - "date": "2026-07-11", - "time": "17:09", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.39", - "date": "2026-07-11", - "time": "17:09", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.38", - "date": "2026-07-11", - "time": "17:08", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" - ] - }, - { - "version": "v1.37", - "date": "2026-07-11", - "time": "17:08", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-还车应结款-查看.jsx", - "pages/02-还车应结款-费用明细.jsx", - "pages/03-还车应结款.jsx", - "pages/04-提车收款单-编辑.jsx", - "pages/05-提车应收款-查看.jsx", - "pages/06-提车应收款-开票信息.jsx", - "pages/07-提车应收款-审核.jsx", - "pages/08-提车应收款-提车收款单.jsx", - "pages/09-提车应收款.jsx", - "pages/10-租赁账单.jsx" + "index.tsx" ] } ] }, "lease-business-line-overview": { "title": "lease business line overview", - "version": "v1.0", - "revision": 0, - "lastUpdated": "2026-07-11T03:48:35.931Z", + "version": "v1.3", + "revision": 3, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "5301b410eb837abfdb8fd933ed4099e33938ff422c9fb0e9a78846b97e6283ca", "trackedFiles": [ ".spec/prototype-comments.json", @@ -6463,13 +2743,55 @@ "lines.ts", "style.css" ], - "changelog": [] + "changelog": [ + { + "version": "v1.3", + "date": "2026-07-12", + "time": "22:45", + "summary": "业务条线说明:标注目录微调", + "details": [ + "条线数据更新;移除内嵌导航节点" + ], + "commit": "131b963", + "files": [ + "lines.ts" + ] + }, + { + "version": "v1.2", + "date": "2026-07-08", + "time": "11:44", + "summary": "页面逻辑与交互:lines.ts", + "details": [], + "commit": "6d14c58", + "files": [ + "lines.ts" + ] + }, + { + "version": "v1.1", + "date": "2026-07-06", + "time": "17:18", + "summary": "页面逻辑与交互:data-foundations.ts、hooks.ts、index.tsx、lines.ts", + "details": [ + "样式与布局:style.css" + ], + "commit": "d0d7458", + "files": [ + "data-foundations.ts", + "hooks.ts", + "index.tsx", + "lines.ts", + "style.css" + ] + } + ] }, "oneos-web-contract-template": { "title": "oneos web contract template", "version": "v1.3", "revision": 3, - "lastUpdated": "2026-07-11T21:02:22.370Z", + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "a3330ed07315a1fb54c5bc063eee96b8e4fe9e9a692654ebbfc7e1be1f6c9aab", "trackedFiles": [ "index.tsx", @@ -6479,40 +2801,47 @@ { "version": "v1.3", "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", + "time": "22:45", + "summary": "合同模板合包:操作区与独立原型对齐", + "details": [ + "模板管理页 OperationActions 统一" + ], + "commit": "131b963", "files": [ - "index.tsx", - "pages/01-合同模板管理.jsx" + "index.tsx" ] }, { "version": "v1.2", - "date": "2026-07-11", - "time": "16:47", - "summary": "更新页面逻辑与交互", + "date": "2026-06-30", + "time": "16:54", + "summary": "页面逻辑与交互:index.tsx", + "details": [], + "commit": "0982837", "files": [ - "index.tsx", - "pages/01-合同模板管理.jsx" + "index.tsx" ] }, { "version": "v1.1", - "date": "2026-07-11", - "time": "16:44", - "summary": "更新页面逻辑与交互", + "date": "2026-06-30", + "time": "16:36", + "summary": "Import desktop web originals into dedicated prototypes with a shared legacy shell, sync script, and a new「ONE-OS Web 端」sidebar section for review alongside existing refactored pages.", + "details": [ + "页面逻辑与交互:index.tsx" + ], + "commit": "d71ebc5", "files": [ - "index.tsx", - "pages/01-合同模板管理.jsx" + "index.tsx" ] } ] }, "oneos-web-h2-station": { "title": "oneos web h2 station", - "version": "v1.12", - "revision": 12, - "lastUpdated": "2026-07-11T21:02:00.181Z", + "version": "v1.5", + "revision": 5, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "ef1dc5bf2f93f80d38273976fa63752796cd9f39bddb1dced1cf779960d68ff3", "trackedFiles": [ "index.tsx", @@ -6522,169 +2851,75 @@ "styles/h2-station-vm-filter.css" ], "changelog": [ - { - "version": "v1.12", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面样式", - "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", - "styles/h2-station-vm-filter.css" - ] - }, - { - "version": "v1.11", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新页面样式", - "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", - "styles/h2-station-vm-filter.css" - ] - }, - { - "version": "v1.10", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新页面样式", - "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", - "styles/h2-station-vm-filter.css" - ] - }, - { - "version": "v1.9", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新页面样式", - "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", - "styles/h2-station-vm-filter.css" - ] - }, - { - "version": "v1.8", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新页面样式", - "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", - "styles/h2-station-vm-filter.css" - ] - }, - { - "version": "v1.7", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新页面样式", - "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", - "styles/h2-station-vm-filter.css" - ] - }, - { - "version": "v1.6", - "date": "2026-07-12", - "time": "00:26", - "summary": "更新页面样式", - "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", - "styles/h2-station-vm-filter.css" - ] - }, { "version": "v1.5", "date": "2026-07-12", - "time": "00:23", - "summary": "更新页面样式", + "time": "22:45", + "summary": "加氢站合包:站点信息编辑提升为主操作", + "details": [ + "加氢订单/记录/站点信息 3 页 OperationActions;站点编辑不再藏在「更多」" + ], + "commit": "131b963", "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", - "styles/h2-station-vm-filter.css" + "index.tsx" ] }, { "version": "v1.4", - "date": "2026-07-12", - "time": "00:20", - "summary": "更新页面样式", + "date": "2026-07-08", + "time": "11:44", + "summary": "样式与布局:h2-station-vm-filter.css", + "details": [], + "commit": "6d14c58", "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", "styles/h2-station-vm-filter.css" ] }, { "version": "v1.3", - "date": "2026-07-12", - "time": "00:20", - "summary": "更新页面样式", + "date": "2026-07-02", + "time": "03:35", + "summary": "页面逻辑与交互:index.tsx", + "details": [ + "样式与布局:h2-station-vm-filter.css" + ], + "commit": "f5e3126", "files": [ "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", "styles/h2-station-vm-filter.css" ] }, { "version": "v1.2", - "date": "2026-07-11", - "time": "16:45", - "summary": "更新页面样式", + "date": "2026-06-30", + "time": "16:54", + "summary": "页面逻辑与交互:index.tsx", + "details": [], + "commit": "0982837", "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", - "styles/h2-station-vm-filter.css" + "index.tsx" ] }, { "version": "v1.1", - "date": "2026-07-11", - "time": "16:44", - "summary": "更新页面样式", + "date": "2026-06-30", + "time": "16:36", + "summary": "Import desktop web originals into dedicated prototypes with a shared legacy shell, sync script, and a new「ONE-OS Web 端」sidebar section for review alongside existing refactored pages.", + "details": [ + "页面逻辑与交互:index.tsx" + ], + "commit": "d71ebc5", "files": [ - "index.tsx", - "pages/01-加氢订单.jsx", - "pages/02-加氢记录.jsx", - "pages/03-站点信息.jsx", - "styles/h2-station-vm-filter.css" + "index.tsx" ] } ] }, "oneos-web-procurement": { "title": "oneos web procurement", - "version": "v1.2", - "revision": 2, - "lastUpdated": "2026-07-11T21:03:08.589Z", + "version": "v1.3", + "revision": 3, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "f66bafe345eda150da4047f5ef28064454d87dccdd68b01a62d58f95bc656960", "trackedFiles": [ "index.tsx", @@ -6693,34 +2928,49 @@ ], "changelog": [ { - "version": "v1.2", + "version": "v1.3", "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面逻辑与交互", + "time": "22:45", + "summary": "采购管理合包:三方退租车页操作区标准化", + "details": [ + "退租申请与管理页 OperationActions" + ], + "commit": "131b963", "files": [ - "index.tsx", - "pages/01-三方退租车管理.jsx", - "pages/02-三方退租申请-新增.jsx" + "index.tsx" + ] + }, + { + "version": "v1.2", + "date": "2026-06-30", + "time": "16:54", + "summary": "页面逻辑与交互:index.tsx", + "details": [], + "commit": "0982837", + "files": [ + "index.tsx" ] }, { "version": "v1.1", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面逻辑与交互", + "date": "2026-06-30", + "time": "16:36", + "summary": "Import desktop web originals into dedicated prototypes with a shared legacy shell, sync script, and a new「ONE-OS Web 端」sidebar section for review alongside existing refactored pages.", + "details": [ + "页面逻辑与交互:index.tsx" + ], + "commit": "d71ebc5", "files": [ - "index.tsx", - "pages/01-三方退租车管理.jsx", - "pages/02-三方退租申请-新增.jsx" + "index.tsx" ] } ] }, "oneos-web-ops": { "title": "oneos web ops", - "version": "v1.14", - "revision": 14, - "lastUpdated": "2026-07-11T21:02:30.579Z", + "version": "v1.2", + "revision": 2, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "a58a00246936f10fd91012d54ac6b7031fcb04a1d8f432ab301ffd6fbc8b9e74", "trackedFiles": [ "index.tsx", @@ -6775,293 +3025,39 @@ "pages/49-型号参数.jsx" ], "changelog": [ - { - "version": "v1.14", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.13", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.12", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.11", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.10", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.9", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.8", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.7", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.6", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.5", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.4", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, - { - "version": "v1.3", - "date": "2026-07-11", - "time": "16:57", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" - ] - }, { "version": "v1.2", - "date": "2026-07-11", - "time": "16:57", - "summary": "更新页面逻辑与交互", + "date": "2026-07-12", + "time": "22:45", + "summary": "运维管理合包:45 页操作列与工具栏按钮标准化", + "details": [ + "备件/调拨/交还车/故障/异动/证件/型号参数等页 OperationActions 与 data-vm-icon 图标" + ], + "commit": "131b963", "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" + "index.tsx" ] }, { "version": "v1.1", - "date": "2026-07-11", - "time": "16:57", - "summary": "更新页面逻辑与交互", + "date": "2026-06-30", + "time": "16:36", + "summary": "Import desktop web originals into dedicated prototypes with a shared legacy shell, sync script, and a new「ONE-OS Web 端」sidebar section for review alongside existing refactored pages.", + "details": [ + "页面逻辑与交互:index.tsx" + ], + "commit": "d71ebc5", "files": [ - "index.tsx", - "pages/01-备件库存.jsx", - "pages/02-仓库管理.jsx", - "pages/03-备车-编辑.jsx", - "pages/04-备车-查看.jsx", - "pages/05-备车-新增.jsx", - "pages/06-备车管理.jsx", - "pages/07-查看故障.jsx", - "pages/08-调拨管理-查看.jsx", - "pages/09-调拨管理-调拨信息.jsx", - "pages/10-调拨管理-接收信息-第三方运输.jsx", - "pages/11-调拨管理-接收信息-司机运输.jsx" + "index.tsx" ] } ] }, "oneos-web-lease-contract": { "title": "oneos web lease contract", - "version": "v1.3", - "revision": 3, - "lastUpdated": "2026-07-12T14:50:59.958Z", + "version": "v1.2", + "revision": 2, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "330315de025466bd4d99fab62d28f381c1f26dc1f2cb695e998c64ec49748cea", "trackedFiles": [ "index.tsx", @@ -7075,64 +3071,40 @@ "pages/08-车辆租赁合同.jsx" ], "changelog": [ - { - "version": "v1.3", - "date": "2026-07-12", - "time": "22:50", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-车辆租赁合同-变更为三方合同.jsx", - "pages/02-车辆租赁合同-查看.jsx", - "pages/03-车辆租赁合同-附加费用.jsx", - "pages/04-车辆租赁合同-新增.jsx", - "pages/05-车辆租赁合同-新增车辆.jsx", - "pages/06-车辆租赁合同-续签合同.jsx", - "pages/07-车辆租赁合同-转正式合同.jsx", - "pages/08-车辆租赁合同.jsx" - ] - }, { "version": "v1.2", "date": "2026-07-12", - "time": "22:47", - "summary": "更新页面逻辑与交互", + "time": "22:45", + "summary": "租赁合同合包:8 子页同步签署/流程字段与 OperationActions", + "details": [ + "新增、续签、转正式、三方变更、附加费用等子页操作区标准化", + "修复移除面包屑后的 JSX 括号语法" + ], + "commit": "131b963", "files": [ - "index.tsx", - "pages/01-车辆租赁合同-变更为三方合同.jsx", - "pages/02-车辆租赁合同-查看.jsx", - "pages/03-车辆租赁合同-附加费用.jsx", - "pages/04-车辆租赁合同-新增.jsx", - "pages/05-车辆租赁合同-新增车辆.jsx", - "pages/06-车辆租赁合同-续签合同.jsx", - "pages/07-车辆租赁合同-转正式合同.jsx", - "pages/08-车辆租赁合同.jsx" + "index.tsx" ] }, { "version": "v1.1", - "date": "2026-07-12", - "time": "05:01", - "summary": "更新页面逻辑与交互", + "date": "2026-06-30", + "time": "16:36", + "summary": "Import desktop web originals into dedicated prototypes with a shared legacy shell, sync script, and a new「ONE-OS Web 端」sidebar section for review alongside existing refactored pages.", + "details": [ + "页面逻辑与交互:index.tsx" + ], + "commit": "d71ebc5", "files": [ - "index.tsx", - "pages/01-车辆租赁合同-变更为三方合同.jsx", - "pages/02-车辆租赁合同-查看.jsx", - "pages/03-车辆租赁合同-附加费用.jsx", - "pages/04-车辆租赁合同-新增.jsx", - "pages/05-车辆租赁合同-新增车辆.jsx", - "pages/06-车辆租赁合同-续签合同.jsx", - "pages/07-车辆租赁合同-转正式合同.jsx", - "pages/08-车辆租赁合同.jsx" + "index.tsx" ] } ] }, "oneos-web-business": { "title": "oneos web business", - "version": "v1.10", - "revision": 10, - "lastUpdated": "2026-07-11T21:03:38.838Z", + "version": "v1.2", + "revision": 2, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "81527424b7c28091f51aeaa1c530e0517eca0025fa5a79711a907e2f52edb127", "trackedFiles": [ "index.tsx", @@ -7156,213 +3128,39 @@ "pages/18-ETC管理.jsx" ], "changelog": [ - { - "version": "v1.10", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险采购.jsx", - "pages/02-编辑交车任务.jsx", - "pages/03-查看交车任务.jsx", - "pages/04-车辆成本维护.jsx", - "pages/05-供应商管理-编辑.jsx", - "pages/06-供应商管理-查看.jsx", - "pages/07-供应商管理-新增.jsx", - "pages/08-供应商管理.jsx", - "pages/09-交车任务.jsx", - "pages/10-客户管理-编辑.jsx", - "pages/11-客户管理-查看.jsx" - ] - }, - { - "version": "v1.9", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险采购.jsx", - "pages/02-编辑交车任务.jsx", - "pages/03-查看交车任务.jsx", - "pages/04-车辆成本维护.jsx", - "pages/05-供应商管理-编辑.jsx", - "pages/06-供应商管理-查看.jsx", - "pages/07-供应商管理-新增.jsx", - "pages/08-供应商管理.jsx", - "pages/09-交车任务.jsx", - "pages/10-客户管理-编辑.jsx", - "pages/11-客户管理-查看.jsx" - ] - }, - { - "version": "v1.8", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险采购.jsx", - "pages/02-编辑交车任务.jsx", - "pages/03-查看交车任务.jsx", - "pages/04-车辆成本维护.jsx", - "pages/05-供应商管理-编辑.jsx", - "pages/06-供应商管理-查看.jsx", - "pages/07-供应商管理-新增.jsx", - "pages/08-供应商管理.jsx", - "pages/09-交车任务.jsx", - "pages/10-客户管理-编辑.jsx", - "pages/11-客户管理-查看.jsx" - ] - }, - { - "version": "v1.7", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险采购.jsx", - "pages/02-编辑交车任务.jsx", - "pages/03-查看交车任务.jsx", - "pages/04-车辆成本维护.jsx", - "pages/05-供应商管理-编辑.jsx", - "pages/06-供应商管理-查看.jsx", - "pages/07-供应商管理-新增.jsx", - "pages/08-供应商管理.jsx", - "pages/09-交车任务.jsx", - "pages/10-客户管理-编辑.jsx", - "pages/11-客户管理-查看.jsx" - ] - }, - { - "version": "v1.6", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险采购.jsx", - "pages/02-编辑交车任务.jsx", - "pages/03-查看交车任务.jsx", - "pages/04-车辆成本维护.jsx", - "pages/05-供应商管理-编辑.jsx", - "pages/06-供应商管理-查看.jsx", - "pages/07-供应商管理-新增.jsx", - "pages/08-供应商管理.jsx", - "pages/09-交车任务.jsx", - "pages/10-客户管理-编辑.jsx", - "pages/11-客户管理-查看.jsx" - ] - }, - { - "version": "v1.5", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险采购.jsx", - "pages/02-编辑交车任务.jsx", - "pages/03-查看交车任务.jsx", - "pages/04-车辆成本维护.jsx", - "pages/05-供应商管理-编辑.jsx", - "pages/06-供应商管理-查看.jsx", - "pages/07-供应商管理-新增.jsx", - "pages/08-供应商管理.jsx", - "pages/09-交车任务.jsx", - "pages/10-客户管理-编辑.jsx", - "pages/11-客户管理-查看.jsx" - ] - }, - { - "version": "v1.4", - "date": "2026-07-12", - "time": "05:03", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险采购.jsx", - "pages/02-编辑交车任务.jsx", - "pages/03-查看交车任务.jsx", - "pages/04-车辆成本维护.jsx", - "pages/05-供应商管理-编辑.jsx", - "pages/06-供应商管理-查看.jsx", - "pages/07-供应商管理-新增.jsx", - "pages/08-供应商管理.jsx", - "pages/09-交车任务.jsx", - "pages/10-客户管理-编辑.jsx", - "pages/11-客户管理-查看.jsx" - ] - }, - { - "version": "v1.3", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险采购.jsx", - "pages/02-编辑交车任务.jsx", - "pages/03-查看交车任务.jsx", - "pages/04-车辆成本维护.jsx", - "pages/05-供应商管理-编辑.jsx", - "pages/06-供应商管理-查看.jsx", - "pages/07-供应商管理-新增.jsx", - "pages/08-供应商管理.jsx", - "pages/09-交车任务.jsx", - "pages/10-客户管理-编辑.jsx", - "pages/11-客户管理-查看.jsx" - ] - }, { "version": "v1.2", "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", + "time": "22:45", + "summary": "业务管理合包:18 页移除面包屑,OperationActions 统一", + "details": [ + "保险采购、交车任务、客户/供应商、租赁账单、ETC 管理等页操作区标准化" + ], + "commit": "131b963", "files": [ - "index.tsx", - "pages/01-保险采购.jsx", - "pages/02-编辑交车任务.jsx", - "pages/03-查看交车任务.jsx", - "pages/04-车辆成本维护.jsx", - "pages/05-供应商管理-编辑.jsx", - "pages/06-供应商管理-查看.jsx", - "pages/07-供应商管理-新增.jsx", - "pages/08-供应商管理.jsx", - "pages/09-交车任务.jsx", - "pages/10-客户管理-编辑.jsx", - "pages/11-客户管理-查看.jsx" + "index.tsx" ] }, { "version": "v1.1", - "date": "2026-07-12", - "time": "05:02", - "summary": "更新页面逻辑与交互", + "date": "2026-06-30", + "time": "16:36", + "summary": "Import desktop web originals into dedicated prototypes with a shared legacy shell, sync script, and a new「ONE-OS Web 端」sidebar section for review alongside existing refactored pages.", + "details": [ + "页面逻辑与交互:index.tsx" + ], + "commit": "d71ebc5", "files": [ - "index.tsx", - "pages/01-保险采购.jsx", - "pages/02-编辑交车任务.jsx", - "pages/03-查看交车任务.jsx", - "pages/04-车辆成本维护.jsx", - "pages/05-供应商管理-编辑.jsx", - "pages/06-供应商管理-查看.jsx", - "pages/07-供应商管理-新增.jsx", - "pages/08-供应商管理.jsx", - "pages/09-交车任务.jsx", - "pages/10-客户管理-编辑.jsx", - "pages/11-客户管理-查看.jsx" + "index.tsx" ] } ] }, "oneos-web-ledger-data": { "title": "oneos web ledger data", - "version": "v1.6", - "revision": 6, - "lastUpdated": "2026-07-11T21:04:46.084Z", + "version": "v1.3", + "revision": 3, + "lastUpdated": "2026-07-12T14:45:00.000Z", "contentHash": "68be711a6da9e583a1ac610fac01a778716c02028a62b1fcf4a164cc22a33172", "trackedFiles": [ "index.tsx", @@ -7373,97 +3171,50 @@ "pages/05-租赁业务台账.jsx" ], "changelog": [ - { - "version": "v1.6", - "date": "2026-07-12", - "time": "05:04", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险分摊明细.jsx", - "pages/02-车辆氢费明细.jsx", - "pages/03-车辆维修明细.jsx", - "pages/04-氢费采购端汇总报表.jsx", - "pages/05-租赁业务台账.jsx" - ] - }, - { - "version": "v1.5", - "date": "2026-07-12", - "time": "05:04", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险分摊明细.jsx", - "pages/02-车辆氢费明细.jsx", - "pages/03-车辆维修明细.jsx", - "pages/04-氢费采购端汇总报表.jsx", - "pages/05-租赁业务台账.jsx" - ] - }, - { - "version": "v1.4", - "date": "2026-07-12", - "time": "05:04", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-保险分摊明细.jsx", - "pages/02-车辆氢费明细.jsx", - "pages/03-车辆维修明细.jsx", - "pages/04-氢费采购端汇总报表.jsx", - "pages/05-租赁业务台账.jsx" - ] - }, { "version": "v1.3", "date": "2026-07-12", - "time": "05:04", - "summary": "更新页面逻辑与交互", + "time": "22:45", + "summary": "台账数据合包:5 页操作区标准化", + "details": [ + "保险分摊、氢费、维修明细、氢费采购端汇总、租赁业务台账等页 OperationActions" + ], + "commit": "131b963", "files": [ - "index.tsx", - "pages/01-保险分摊明细.jsx", - "pages/02-车辆氢费明细.jsx", - "pages/03-车辆维修明细.jsx", - "pages/04-氢费采购端汇总报表.jsx", - "pages/05-租赁业务台账.jsx" + "index.tsx" ] }, { "version": "v1.2", - "date": "2026-07-12", - "time": "05:04", - "summary": "更新页面逻辑与交互", + "date": "2026-06-30", + "time": "16:54", + "summary": "页面逻辑与交互:index.tsx", + "details": [], + "commit": "0982837", "files": [ - "index.tsx", - "pages/01-保险分摊明细.jsx", - "pages/02-车辆氢费明细.jsx", - "pages/03-车辆维修明细.jsx", - "pages/04-氢费采购端汇总报表.jsx", - "pages/05-租赁业务台账.jsx" + "index.tsx" ] }, { "version": "v1.1", - "date": "2026-07-12", - "time": "05:04", - "summary": "更新页面逻辑与交互", + "date": "2026-06-30", + "time": "16:36", + "summary": "Import desktop web originals into dedicated prototypes with a shared legacy shell, sync script, and a new「ONE-OS Web 端」sidebar section for review alongside existing refactored pages.", + "details": [ + "页面逻辑与交互:index.tsx" + ], + "commit": "d71ebc5", "files": [ - "index.tsx", - "pages/01-保险分摊明细.jsx", - "pages/02-车辆氢费明细.jsx", - "pages/03-车辆维修明细.jsx", - "pages/04-氢费采购端汇总报表.jsx", - "pages/05-租赁业务台账.jsx" + "index.tsx" ] } ] }, "ledger-shared": { "title": "ledger-shared", - "version": "v1.1", - "revision": 1, - "lastUpdated": "2026-07-12T08:08:00.906Z", + "version": "v1.4", + "revision": 4, + "lastUpdated": "2026-07-12T14:44:00.000Z", "contentHash": "cfa97e916eb8480e2d3c62d5b7a785ae02638dfdd9ace32883a56aa66982b531", "trackedFiles": [ "DESIGN.md", @@ -7471,10 +3222,52 @@ ], "changelog": [ { - "version": "v1.1", + "version": "v1.4", "date": "2026-07-12", - "time": "16:08", - "summary": "更新页面样式", + "time": "22:44", + "summary": "迭代 ONE-OS 多原型:统一标注壳与操作规范,租赁明细/合同/提车应收款增强,新增任务工单,同步导航与合包页面。", + "details": [ + "变更 1 个文件" + ], + "commit": "131b963", + "files": [ + "DESIGN.md" + ] + }, + { + "version": "v1.3", + "date": "2026-07-09", + "time": "17:52", + "summary": "迭代 ONE-OS 多原型:原型导航与版本追踪上线;车辆氢费明细成本单价校验增强;多业务台账/财务/工作台页面迭代与标注目录同步。", + "details": [ + "变更 1 个文件" + ], + "commit": "6ccbbef", + "files": [ + "DESIGN.md" + ] + }, + { + "version": "v1.2", + "date": "2026-07-08", + "time": "11:44", + "summary": "样式与布局:ledger-page.css", + "details": [], + "commit": "6d14c58", + "files": [ + "DESIGN.md", + "styles/ledger-page.css" + ] + }, + { + "version": "v1.1", + "date": "2026-07-06", + "time": "17:18", + "summary": "新增业务部台账、收款记录、业务条线说明及 ledger-shared / vm-shared 公共壳层", + "details": [ + "样式与布局:ledger-page.css" + ], + "commit": "d0d7458", "files": [ "DESIGN.md", "styles/ledger-page.css" @@ -7484,28 +3277,60 @@ }, "vm-shared": { "title": "vm-shared", - "version": "v1.2", - "revision": 2, - "lastUpdated": "2026-07-12T08:05:34.337Z", + "version": "v1.4", + "revision": 4, + "lastUpdated": "2026-07-12T14:44:00.000Z", "contentHash": "4a8d78c8ffaa1ffbf48164c0a77651919681b3e89b7b5ed700a2acf9c7f00e91", "trackedFiles": [ "DESIGN.md" ], "changelog": [ { - "version": "v1.2", + "version": "v1.4", "date": "2026-07-12", - "time": "16:05", - "summary": "更新 DESIGN.md", + "time": "22:44", + "summary": "迭代 ONE-OS 多原型:统一标注壳与操作规范,租赁明细/合同/提车应收款增强,新增任务工单,同步导航与合包页面。", + "details": [ + "变更 1 个文件" + ], + "commit": "131b963", + "files": [ + "DESIGN.md" + ] + }, + { + "version": "v1.3", + "date": "2026-07-09", + "time": "17:52", + "summary": "迭代 ONE-OS 多原型:原型导航与版本追踪上线;车辆氢费明细成本单价校验增强;多业务台账/财务/工作台页面迭代与标注目录同步。", + "details": [ + "变更 1 个文件" + ], + "commit": "6ccbbef", + "files": [ + "DESIGN.md" + ] + }, + { + "version": "v1.2", + "date": "2026-07-08", + "time": "11:44", + "summary": "迭代 ONE-OS 多原型:租赁台账增强、合同模板 Word 导入,统一全局分页与筛选规范。", + "details": [ + "变更 1 个文件" + ], + "commit": "6d14c58", "files": [ "DESIGN.md" ] }, { "version": "v1.1", - "date": "2026-07-12", - "time": "16:05", - "summary": "更新 DESIGN.md", + "date": "2026-07-06", + "time": "17:18", + "summary": "新增业务部台账、收款记录、业务条线说明及 ledger-shared / vm-shared 公共壳层", + "details": [], + "commit": "d0d7458", "files": [ "DESIGN.md" ] @@ -7515,77 +3340,33 @@ }, "recentUpdates": [ { - "prototypeId": "oneos-web-lease-contract", - "title": "oneos web lease contract", + "prototypeId": "lease-business-detail", + "title": "租赁业务明细", "version": "v1.3", - "date": "2026-07-12", - "time": "22:50", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-车辆租赁合同-变更为三方合同.jsx", - "pages/02-车辆租赁合同-查看.jsx", - "pages/03-车辆租赁合同-附加费用.jsx", - "pages/04-车辆租赁合同-新增.jsx", - "pages/05-车辆租赁合同-新增车辆.jsx", - "pages/06-车辆租赁合同-续签合同.jsx", - "pages/07-车辆租赁合同-转正式合同.jsx", - "pages/08-车辆租赁合同.jsx" - ] - }, - { - "prototypeId": "oneos-web-lease-contract", - "title": "oneos web lease contract", - "version": "v1.2", - "date": "2026-07-12", - "time": "22:47", - "summary": "更新页面逻辑与交互", - "files": [ - "index.tsx", - "pages/01-车辆租赁合同-变更为三方合同.jsx", - "pages/02-车辆租赁合同-查看.jsx", - "pages/03-车辆租赁合同-附加费用.jsx", - "pages/04-车辆租赁合同-新增.jsx", - "pages/05-车辆租赁合同-新增车辆.jsx", - "pages/06-车辆租赁合同-续签合同.jsx", - "pages/07-车辆租赁合同-转正式合同.jsx", - "pages/08-车辆租赁合同.jsx" - ] - }, - { - "prototypeId": "oneos-prototype-nav", - "title": "原型导航", - "version": "v1.3", - "date": "2026-07-12", - "time": "22:45", - "summary": "统一标注壳与操作规范,租赁明细/合同/提车应收款增强,新增任务工单,同步合包页面", - "details": [ - "【平台】全项目接入 PrototypeAnnotationHost,PRD 迁入右侧标注目录;列表统一 OperationActions 与工具栏图标规范", - "【租赁业务明细】新增收款状态列、47 列宽表与 23 项汇总;氢费钻取、字段交叉校验、变更记录、批量导入导出与主管解锁", - "【租赁合同】KPI/状态收敛;新增查看页、线上/线下签署、交付变更、附加费用拆分、风控条款检测;与提车应收联动", - "【提车应收款】独立原型上线:自动生成/手动办理、15 日前后分档计费、与合同双向 bridge;finance 合包仅保留租赁账单", - "【任务工单】新增业管发起端:合同/独立双入口、六类任务类型、KPI 视角与督办催办(执行端后续)", - "【物流业务明细】原物流业务台账更名;列对齐 Excel、系统车型列、批量导入与自动计算", - "【车辆管理】在租车队 KPI 迁入;车型分布弹窗;详情 Tab 与列表样式优化", - "【客户/模板/保险】OperationActions 统一;模板新增先付后用/先用后付;业务部台账表格视觉增强", - "【合包】business/ops/finance/ledger-data/lease-contract/h2-station 等移除面包屑并标准化操作区;workbench 提车入口改跳独立原型", - "【下线】移除 oneos-web-login、requirements、vehicle-asset 合包;侧栏新增任务工单与提车应收款" - ], + "date": "2026-07-13", + "time": "09:26", + "summary": "更新需求说明与标注", "files": [ ".spec/prototype-comments.json", - "index.tsx", - "nav-data.ts", - "style.css", - "xll-nav-menu.json", - "xll-nav-source.json" + ".spec/prototype-review.md", + ".spec/requirements-prd.md", + "columnHeaderTips.ts", + "components/DetailChangeLogModal.tsx", + "components/DetailDeleteConfirmModal.tsx", + "components/DetailEditModal.tsx", + "components/DetailImportModal.tsx", + "components/DetailKpiRow.tsx", + "components/DetailTable.tsx", + "components/FieldCheckIcon.tsx", + "components/FilterPanel.tsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.227", - "date": "2026-07-12", - "time": "22:34", + "version": "v1.167", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7596,15 +3377,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.226", - "date": "2026-07-12", - "time": "22:34", + "version": "v1.166", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7615,15 +3398,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.225", - "date": "2026-07-12", - "time": "22:34", + "version": "v1.165", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7634,15 +3419,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.224", - "date": "2026-07-12", - "time": "22:33", + "version": "v1.164", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7653,15 +3440,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.223", - "date": "2026-07-12", - "time": "22:33", + "version": "v1.163", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7672,15 +3461,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.222", - "date": "2026-07-12", - "time": "22:33", + "version": "v1.162", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7691,15 +3482,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.221", - "date": "2026-07-12", - "time": "22:33", + "version": "v1.161", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7710,15 +3503,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.220", - "date": "2026-07-12", - "time": "22:28", + "version": "v1.160", + "date": "2026-07-13", + "time": "01:21", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7729,15 +3524,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.219", - "date": "2026-07-12", - "time": "22:28", + "version": "v1.159", + "date": "2026-07-13", + "time": "01:16", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7748,15 +3545,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.218", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.158", + "date": "2026-07-13", + "time": "01:16", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7767,15 +3566,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.217", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.157", + "date": "2026-07-13", + "time": "01:16", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7786,15 +3587,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.216", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.156", + "date": "2026-07-13", + "time": "01:16", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7805,15 +3608,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.215", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.155", + "date": "2026-07-13", + "time": "01:16", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7824,15 +3629,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.214", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.154", + "date": "2026-07-13", + "time": "01:04", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7843,15 +3650,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.213", - "date": "2026-07-12", - "time": "22:25", + "version": "v1.153", + "date": "2026-07-13", + "time": "01:03", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7862,15 +3671,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.212", - "date": "2026-07-12", - "time": "22:24", + "version": "v1.152", + "date": "2026-07-13", + "time": "01:03", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7881,15 +3692,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.211", - "date": "2026-07-12", - "time": "22:24", + "version": "v1.151", + "date": "2026-07-13", + "time": "01:03", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7900,15 +3713,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.210", - "date": "2026-07-12", - "time": "22:24", + "version": "v1.150", + "date": "2026-07-13", + "time": "01:03", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7919,15 +3734,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.209", - "date": "2026-07-12", - "time": "22:24", + "version": "v1.149", + "date": "2026-07-13", + "time": "00:54", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7938,15 +3755,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.208", - "date": "2026-07-12", - "time": "22:24", + "version": "v1.148", + "date": "2026-07-13", + "time": "00:54", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7957,15 +3776,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.207", - "date": "2026-07-12", - "time": "22:18", + "version": "v1.147", + "date": "2026-07-13", + "time": "00:54", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7976,15 +3797,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.206", - "date": "2026-07-12", - "time": "22:18", + "version": "v1.146", + "date": "2026-07-13", + "time": "00:54", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -7995,15 +3818,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.205", - "date": "2026-07-12", - "time": "22:18", + "version": "v1.145", + "date": "2026-07-13", + "time": "00:54", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8014,15 +3839,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.204", - "date": "2026-07-12", - "time": "22:18", + "version": "v1.144", + "date": "2026-07-13", + "time": "00:50", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8033,15 +3860,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.203", - "date": "2026-07-12", - "time": "22:17", + "version": "v1.143", + "date": "2026-07-13", + "time": "00:50", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8052,15 +3881,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.202", - "date": "2026-07-12", - "time": "22:17", + "version": "v1.142", + "date": "2026-07-13", + "time": "00:49", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8071,15 +3902,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.201", - "date": "2026-07-12", - "time": "22:17", + "version": "v1.141", + "date": "2026-07-13", + "time": "00:49", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8090,15 +3923,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.200", - "date": "2026-07-12", - "time": "22:16", + "version": "v1.140", + "date": "2026-07-13", + "time": "00:49", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8109,15 +3944,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.199", - "date": "2026-07-12", - "time": "22:16", + "version": "v1.139", + "date": "2026-07-13", + "time": "00:45", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8128,15 +3965,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.198", - "date": "2026-07-12", - "time": "22:16", + "version": "v1.138", + "date": "2026-07-13", + "time": "00:45", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8147,15 +3986,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.197", - "date": "2026-07-12", - "time": "22:16", + "version": "v1.137", + "date": "2026-07-13", + "time": "00:45", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8166,15 +4007,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.196", - "date": "2026-07-12", - "time": "22:14", + "version": "v1.136", + "date": "2026-07-13", + "time": "00:45", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8185,15 +4028,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.195", - "date": "2026-07-12", - "time": "22:14", + "version": "v1.135", + "date": "2026-07-13", + "time": "00:45", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8204,15 +4049,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.194", - "date": "2026-07-12", - "time": "22:14", + "version": "v1.134", + "date": "2026-07-13", + "time": "00:45", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8223,15 +4070,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.193", - "date": "2026-07-12", - "time": "22:14", + "version": "v1.133", + "date": "2026-07-13", + "time": "00:38", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8242,15 +4091,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.192", - "date": "2026-07-12", - "time": "22:14", + "version": "v1.132", + "date": "2026-07-13", + "time": "00:38", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8261,15 +4112,17 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] }, { "prototypeId": "vehicle-pickup-receivable", "title": "提车应收款", - "version": "v1.191", - "date": "2026-07-12", - "time": "22:14", + "version": "v1.131", + "date": "2026-07-13", + "time": "00:38", "summary": "更新需求说明与标注", "files": [ ".spec/PRD.md", @@ -8280,6 +4133,50 @@ "pickup-receivable-calc.js", "styles/index.css", "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", + "VehiclePickupReceivableList.jsx" + ] + }, + { + "prototypeId": "vehicle-pickup-receivable", + "title": "提车应收款", + "version": "v1.130", + "date": "2026-07-13", + "time": "00:38", + "summary": "更新需求说明与标注", + "files": [ + ".spec/PRD.md", + ".spec/prototype-comments.json", + "data/pickup-receivable-list-data.js", + "index.tsx", + "pickup-receivable-bridge.js", + "pickup-receivable-calc.js", + "styles/index.css", + "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", + "VehiclePickupReceivableList.jsx" + ] + }, + { + "prototypeId": "vehicle-pickup-receivable", + "title": "提车应收款", + "version": "v1.129", + "date": "2026-07-13", + "time": "00:38", + "summary": "更新需求说明与标注", + "files": [ + ".spec/PRD.md", + ".spec/prototype-comments.json", + "data/pickup-receivable-list-data.js", + "index.tsx", + "pickup-receivable-bridge.js", + "pickup-receivable-calc.js", + "styles/index.css", + "VehiclePickupReceivableApp.jsx", + "VehiclePickupReceivableCollectPage.jsx", + "VehiclePickupReceivableContractView.jsx", "VehiclePickupReceivableList.jsx" ] } diff --git a/src/prototypes/vehicle-pickup-receivable/.spec/prototype-comment-assets/7abbf7d8-3099-47e5-a969-e12082edb3d3.png b/src/prototypes/vehicle-pickup-receivable/.spec/prototype-comment-assets/7abbf7d8-3099-47e5-a969-e12082edb3d3.png new file mode 100644 index 0000000000000000000000000000000000000000..005daba88a0145d68fa43e7ab09914d60b68840c GIT binary patch literal 12437 zcmd6OWn5HU_$>oSD2+;YDInb)5<>~d(4CSZ-3(IFFr?B50z-pzx3toTz!1{i%{}A$ zzxQ{)-0%0pFo(lF`|Pv#v)8kpwGI*LY6`fI$sePjpx}ZPUu&YEfWmAv1ug4YJhIlgj&LO;1nv;T-vv@J6S`5T~@Jyv@8BJznH!~FMc>Yl1W){-ds0HNzL{w_>jQjl6_YQ&TKz8J|9V68f+Le7UO4t>k7? zx}o0s{M4x&dESq|Gk!>1+q|n=fze*(j*XoDimRsQKmrP|9Lcand2ezz)j)i+e z0ws-s`(aHlp=~G?Dm;BfL<x^D>;`|WsZeki8~LQp5XWo^9z!0^V?s1W` z5QPF6Fv`aCl|^Ngf~+hdC!-llJ^BBSW>S-D1BnY$U*EPCmzM{uM6eiq|M70ImAD+|kKh;$kGj1ziOMD~oS=`rSjC!HjV-Ic~OF59qz1o;7Tk&Jq;mJm|)%%p> zpug|upN*-=EQp=n7e{)+n{jPINe;n{|_pH_DYPa$6S7}s60+b*O^@8n| zuPlRX%90PIUVC4ni{C)@mq-@cf*W@@NAKP$DQzE?gr(OcZA|Grc${ul4Guo`TJ+h; zwx0>`+iz@@t27S0b64?09L!WKK|v&n3CrE#l9vdf*@6PAL}t~dqrP7oS-u=F^%6`P zKSgu-m?ltP?aaL)Oi1!-Z9*uHoPT?!z0H3orL6tx!Lyj190(|BmY*nat<(Maa2D|_ zu1(k=8s@oiU`(OakT&Q2oU<8C;O&v`LA#(?*QMip-Pq@okAuChp6=RC+(XlABZ&JY zk9zo2ij|a8yR2c+n|PUVOez#>`uMnBF8Q65Rad*b z&@eQ-B{A`vYxTX@-F2Ai*_|6(^1qnvr%oSl^A|{R>W#bzJV_Uoyx#m85_0+cmHyhg zPsv|k7S#jM$)%EEfgdJ>HL|*inOEVk^7{{cZ^y_v@Sn)mFZzgP6c-nl8Pqr3Ur$V= zEHryo=+$6&I%kS{s;Q~y0A8rxx2BSLW=b|5a|(3{k0fTBPVxpvh#U9-gs0J{wmK?3H{b5A58W zEG#}K>$8?NEZEcedK)Vzr-7z7`1c+TLvx(lse%Ewm$$cKM|}3vrEjuno;`aO#b^2p z^ZsN^5})lSm(RuiS!#O=qo=c?yqtHAIf;>*M!#An*A%&!B|!!T#OHi&1CLrvT~9BR zon5)iq@B92BM9xobljsS#(n5^%UyC$NI0HLYNrO=?TB)DHt&=-pDF$ZR<@G~SlJ}! zEvvo7E1S9Xm|mK4H5$oA^O=h<<;d7ry@td0Ulo>K+yn92$MbXkeS2}++o(^U)aAso zUg${@jkR7Zx(>ba=DFCKE}K6HxR{TQ#u*R^XyFqP5qR~gEH95T%fP8oucYV4GJc>J zxyi}i?^@+vggi0ZA6+FKYGiPoNp}d5?|j9T&CJqvL~^%oCSF`G9Bp38W6 zQL4JjYH!9A6%Y3{VDFDeI0MSwWJ?g4=;=i?%dqPl%vKRYVko_9FRQZr$HXl-+b+$) z<~tL<2W24(wf3pgWd^c8fFBpj;r6aBE(pW+`>4D;`iQm9{{>7M>y^7Wz8II&YF`XC zc7*13PXw{~AI~Lm&jtST+;D0r>#}`7sbl+5pJWbuMeDhUcCksoRk8xLH)+%gR!YU% z7k=gL=SqwlBchEke)Ar(`7g25;*ldtSYEqT#pCFsi7b*~yln>*0=t71?f2HRT+Jho z;ZJda^wohC($A^(g%7M>y>_5`o)V?Cqr}M)K=h!OBTD45EQJ}okLoSdpl=3Qw zOZ;l>ttR?J#+Nj9aGl+h{JsCx-_(@^UJnhYg(l#()}yzp$A1sZl{z)zZ++JGhpwiP59P0Y#qV;CK z*`j|jG~(Gg-?C^ku%VZ4gx)Q624ntJmV#tp0J-208{zaL6f-4Azs@11Y##oem|5&` z+%4OS7X*@R4BbWsGv(rlr8a-jbGFXQsS2my5IU5ow-<{y^G`Ti8uIeY4-vWXT#$4g zV{faV$p|I&?Zf46MTwJPH|#XYhcW+~^YD$b`b8NgqKKMpC_Ef_&q}P^UV&#*I(zf={q@$)0l+SA_!Si)e3eOF z=P&!Ny1KfuT+7HG)wdZU&F$jq+J1XnQdFd1Kv-f{Dl7S{r1?hoK98!_~}mmp@5P?7 z-51zm-wmT~VCYL{i00(^f#j!+K5J{A>_56YK@|00`&;qVhUOXt={U*_W;kk}n*o$d zN{DE-+T8$bYg>Z1h>2U!%Oc#K{G`j%8Aw1K6$bd!Zl{~NrA)a|X-pchuA_r!e`a9f zxi&huBwG#$B7byv>Iz`NLsDo}uC7A8V#@qWF8gqY=5>|3Vkm6D=cQ@Ns5T%F&Pkrd z73neQCFwn0#S0;LNMGe{3_tUYb`>@XNO!SMALh^K3arg29xCZB>2bqzvU@cS)_3rb z@Y(0jl4k`Y{J~fqf=;@Nb#ay)*zp~6(kQ`HveYy5-Ae;^4pSpq(rF76vj+=mt_i8v_STp$vyy<|=jH?WVPgdT}i2!Uf0U)4?A+|uIgfSuP zAYJKrhx(wQZYkXNxU=nn?VX>qv*YU3$TN`e+mIoJCdu28h4+0u{e4?ibmL}Tl$)fn za&bGlVfEp;qeCuF3%VhvTspA2q3DKXN?kj*Cu1|603%ziO=!Ygx}y?tE7IXSNKZvF z_z=;c3HW!7kEXLJg*a-AZ)s^#r8uMN%rj*MHWQSKslJGgpq`%B zJ&3*JYh}SBRHr|k(r-p&tl!er0DA-nU8WSL5Q6=c1l2O_IbFm(KjJku>qLc#WG3Na zb1M*E8Z^Vvb&m5XU%os>qZT_Z{{H>x33Eg^sae%a4h}r9QQ7J5cR+nHOZ;x)8*ZD> z?;4x9a6Z%@CJ`o$Hh!4l0zW;ZrGvCUV3~0--{TTc`^Q|WFtpwyE#bRQv9a3j zGSOcI-0-2NCwL<$Qd3hz!{aLM`lz51p-^C+Fk+4nK4hslpx zxNnEVp!yIZlZHDBK_$6R4IUB;`1MY=`TH88IqjT=RZ3%fwlrZXFDRO~!|19( zk|+YIsLP5S>}1mIkI5Q+WIMH(j7YX;-L*oE&C&9WZ7eMrLk0|McCE+n+_NpWYkx5Z z$tz3IKvM|Z_^WW7HTA?AfP{gO#VTAj(Yp7JAB zLr(WKnLGe!KB#tvn6z&+>&oHzK8TrKOzpu6W>OVk?3L)K)a&k=Os!J@|GpKP4nzHz zn>ob-UtO^{Vs;5Mam}l@ns|(i@9j7#lnELf4;*iY+}P;DM*M-FW`!TZ%oWKk^C~M} zynNY7$(%q$N&GC-QYNv7K_OOG9&Xx0foF1b3aorcG}KHBp0A3@HOsw52wmnp66l0I z%VEv+ke%v}U0*(H#9)E>SUMzm@+5yrsPkMJuyH6U(F|+E@B!{^s3sL-VpW7^QEBmm z;bk`shPhUG0ilL{NMl;#kNZ1J@vI-w(Qe|ilwp5ld%YVXL|ZP@-Ck?WaAcldHqE9u zP8G19g*~|8gEH80CA*LNaSI2+u%);y=T4s*pQ8qJ%0>I=? z;-4&{gB%$ic!;0JD(i(;9+$ezp#D=iaO~Nr8q4e#$le>aoZO~Fh1b6AC;vB zLab_28dvyi^z0IacP&5MByhGC^Y>Ajp69R{!L(4CqR?6s@bru&Gl5v&XMsw`pmiI@ zxcRGFq@{C8ug+-t7NysaMI5+`4Jc?E4v!pE`bA~r zkCVtOu3Y}xTn(Z?i2)u@to)n9I7P@4l?c7THvJux5McK+yNxAS;h=>sqBKXGSLzEl zA1#%p9<14Z1|QHhrkj%!eYpf5-hHr**w0t}HzJ}{qA!K{wRVd#?(@y^Z(RjhEKI)1 zHN8qW+~obHzmLdovFkP^br}Kw4WbhmZOBzt6l%O{DQ$6>&&r%+K+|Og)B0gcr8il6 ze2NinRK=F1evd-08Fp*=m&{2ETpW2Xd1>IHG!P&ee}~`F&giGf*PC1 zGleYv8r*{5Fwp05+DmtXCi+hE5(5PxVGSNrOBnhnIqLOhipG0wv_@Sc?w<2vC7+_8 zB-NBgGA{xXdqP=aWMF0ZqYrDE7UM`j280P)jeQNq+>IrX)UzuS8trcca@eIUf^izd zX)wBV#O{!b#|HWYmBwVW^==I~$m5$VV1bmp17DfFFlev(z8e#BA~o8%J*ec0Ld~5# z{pY6C#hv};W?bO2;~0f=*0JgQ%}xc!{$hzj`^oi77G!l4PuMZre~-e)Vn@rST4}av zvlUm%`jQIUyl_W%;~?;4ekG6IH4wu@*mAeQH~B$vKcRi}Zs^g2dv3Xsm*2#aiT_=g zN$fY)m+E|qv_0sr{WJLN%9PZUe)r^fQ(_ejt^F_zJdoIkZP_nudWgV&d&an%Jhaq* zRXB4ujIaS1IUoe);LLK+vgQVIa*Ch6NzQ-n?&zag4}tQ;+tcLGJ4Po>PLA5#Lq`cR zY9wurOh~Nj$M$C%SChh-SNmTPsT=*}Uwqhz99eQAzn>sPhR~*oZ~L#CMpei#eVE2m%%^DB8b3!JI9QN9)bU3MKe<4u$yG-dT;t%;uCD#Y38s zd4li8`2pirL}Zf}BGA8nuep4osUw)AXgEuv#&t$56|YIF7ul6FOAw-nXmWJ@SgV}J z;iF@;oqXBav4ZNut{A zcB>~cySl>cbCuvNjnVs6IB$pMQyP6f1UmYG!ka5~9$KV0ivrmM5wItm%`3;@eG;^w z?f@Q2`04KI*zJc!c8bS7j^B|L4p@p0>($^&z1?q_WG!O?T)sF4#A9WpNR4yT(V#%~ zYZH@XM%xqSo_w49rMnwn>o?ht=$g0c(*2Y3vVm%f5B)WIh6>@WI#Zxk?~)eS$!VoQIoVeh-18i^@Y0*jL?`iPvRh=-^9g}AgE>QwWs|qP$lM8wGv_^X z&SEn~mmhhJHV4fJtEP#7j{J-oT;D}A2Kmq<3_%}rlmudm*{#r>JH3kcDWV>NKF(29 z7YNzi1Z-Sb^$(r8GYx%-ii}i>OWmJu#&2v3nX9HnLaHdlXyu(s)u*;X2vmJ@-t4Y_D{%K$rA@LGdu|qS9 zeUTX|G-OPE%UVofJ|y^|k|}~$Ovp6<+c)^2e}DGW~a+K%tDr=E9@9zSZ~1f#8~0v^Cg3#V-li z1Gms#^?!}AGFh)`EojkoMwx-EECcRnL=90(mhrxGhyr5R4_iIC>!QYD42;-iL_``T z;r-Iq)=rtB3=Nf2h+U%=^V$R?NI<;Zo~g(-?jB5LTU}YEys|>{H(Ub(;s3Cb59l~Lo?XV( zmbMNK?2rLyD458Z4pd)4q_qynEj2b{sG@N!A|k&}`XxuBqobQPvYMZ%4yTPzOnlAD zL+G{oj8s{8Gbk9Bx!58LL=xaqO+CH2w{OH5R4xEX+GFpxc9}li6`JV=hebw4-W<>r1`_SeRP@_->Xcmzy4+ky-fce;4+AU(Cg{IKC{GHKZvU+2K60LqIl9dFAUmUAh5sTJCzJI~%ZFTzK>+xTKtXF;A}V zYn)oZTEbENQouZ}VD#^5D>i1OU<{*J#kl^&goF>fvsD6)zp;+;^Va~K(ZZ(q@BJzwW|vhiR$ z@lCbM=T}~DMN75m)v@Qw>Z*})HWjc*xQLx^0t%v|Px-khN`3$M$Y4;bt3Dov}hg_0Jp!%`or#;#C zr!3|N^YsVo=?_a*sYX2B$BciHicz{Vux?PS$FhXI4xcp?^6naG${{anh?gQQB68|E zTxd712dY>=;WPIB`%}l{E?ua~ev72NLHf~)uf7-ifc^2i{(bxLPh>ig1da8@ELMD< zT;3sZvkp{IaWglU(bupoZwmgOKDF~v$DjS zx2gC`;?~G-6;o1^NuEBxJM3;-TVpJ}-%LiIq2}NAX_ax%yPj#+HoG(M{5?P0mXw%i zLDOvrOnoW=)-4_fv%oiR2mOr&)4 z0lX-Bk4oAyYyGMBc?P#kfiO2hBm6S>t5T8u&G`W@uYp-i@x4}YTW3`O01!ZiNo9TH z*seM8Z2*wcrY4xG^nufTvb68ullkDpm6g>POv;L+e@ZsGYO=Y7#o*B3c5!NH3UKO( z0P71YKec6xCbBCgDF|Grr8EQJHSYoYvOS>+shqVE<*-h%8EdPdG9m;4#<=uD7tr={ zi~;1?e#Xhh0>D^$hb^S5=K9Iw$LwrUDFxYTzyuRvi2&M92>jKQg1D=|relo^@+23r zP??hByiZ_@9RV{~DW#DMnWY#B+)x3X1|sW!n6KbYg9(=hViv3Uy9Z5qfTrm~3WMp#b- z(XvD=%n~j3Up4-^Lr4c^U73=vow{9YrmYMZvZyKO?CVNI;i5uAsJJUhg*!?UUdbH* zO!oG!QzM*;v#4=Yiey;-~)q1eRCTl@&$?w4=BNtGQM6Q5}4=@oy>bt7icZ+Yc304osn z*wr#amRm9^9oKjqJ(-p7@!}{05kVhjjBifv?`}Nz|9~H@-Z8~VN;poz6Hk~g>EvD4 zheNrohgDfs1TpX^8@!HWj!KPN*JrC*5*R9`(U6K2pHL8&IulpZniiFu^mLV)pz)`)cofpU#li{+VqJD$^vc#ORLd0c*sV10^_{PO zk4ZxM;6E}3*i)o{(O|5v{~JKYX6NOV0_BH=yNO5%$D$%xZVu59{J+FGtDdca5}Foad%o1K}?g304x$xF2qOo9f{7@wm)-* zmQTIJ;#pgse*-{@C^0GNPm}u&;BJDC0sV!*9MvpGslng(X0QHfYGIZS`FSwDM2^@X zlriFN(U+~s^8mwlI4xZv?!FhIgGrxS2n9q(@?i%qCF^}k;x>pW*SxmWY^Yk>pY zC|*jI5bL+6vz66f?y4$Wcd{^#uV1+_kEsu3BYOJCDmFtf*;E1|`*#ZsW8{j>vBd`s?4M^JFnN!!i-z~JDxxImqm+EWS& zQQ!07&ftm;@dc(-L-V)s$bhG#CE$aIc$A{NKgIKj%cTX<{Y=S1tFNcKdvYhX)m)`n zxBE1xR!T_9(-1BnOZj2WDwVZee@dI0 z8wuUP;mB=+K}UcN`N(K?<1Q~Bm7@$Zc@6kmNPd#5=;L!Tnkkxo7si#`b6${k#mtypi z30`p(J4ZuIoSBvupOQjOOw6!HCr@=~ipmr~dN{=CkS^f3-Qt>(VB&uUdHvclTSBsW zm|qC6>AOoyJyM=5&wh?rsy^LcP>xJWNf{LJ`46MReA18@{RHHI-6M#&l%ceV7A;o7 z@tUN&$Jz{COrtBV#t9HFb|BrB>h#fMnqorQtIIMSoRG)A0}7mTy955|>;UuoOGD7C zfEp8v0xACGzt&<(yRX^M;tmi6~G6--u&?HWJI_CV4NB#wM&i7CxWU~Ab*i? z@)6we7chf39-y=0MDN^y!)XqR2r6MtdTDK~8PD5G;3fC<()2(RjOgrOiq#88G-Ow0CQvGwgY zmCjYqBRryikoRt73xUMEImiDS^9+?~4?QzNc44$gNRxB5==)sj4S#luylnT`?> zry2p^T>AAzZ^*~Bfli8%bg{lR;O-g*Gyj7|Umy5z@AKRdh(rPcD5{VHlN)@kQZ}p- zh+~iCu3qKTd$fwaGm6hv)fpvKTDP%&}Cysm4>WR72F5GuDVbWnp1qRxtA2s}b}JxTdp>6dgk~fb`)s)Y;i4m9`Uo97atcrA7j;0leS> ztp?bq@6Gt66yO$K_Qv!2Xd4;f8jKbfFNWrdP}BGwnrUk{mzJ`-ikk%9sajfE0ujqt z0=PdntY$XWbwk4r_OXTGKz)Udetdk)Rns|}#H$~Yi;83WsmEv~=}^=&src zDh>WtU*Ht|1et2(Ee!%541$hB4>8tD$kqv2df(IkS*tkfy6ov=`$gR&c%ioLD}V_- z!8V;#uE0^sZ_?K?)YR3A)YFvlE4}EqWMwdweHqJVD>>EW%3xt`j_MTk2w1zWSm^zC z-6?NB-Z)5pWaQv#!QZN18pQ+HX)mNVi#)0rWF2?s-qsF3gQ<(@X(9rnx zD?ycL)!aNUfeDjYFzee(usl7+m2k47S8To}(^?4`dBzF}L`Jo+TFvyOvdfVd*lkm* z>=v-NgK9pb^!fG(vy5xPXazMi;u#MFkNLwqhlujAebbVt2kx{(yj_^8&DSjtcLv^$ zuV%i8Fv+y1TukgiP*PE4W@I>&XHz5liIb9+2JKJeh&J$L~iOj7hD zF3;}>4UEnP6uuRIca?pru!5W1712k4(jF2)Cr}-!9LZf4sVuY_p*Wgu4d`}&@SK!F z$tht>4?}-M0FkLTTP5f|W@T>+mIWDoV2=XFtaCxM$$UO+Jy!A#-SPs)?!Fw7)XJfTl zyXA2R!B&m5dm&qkiQmMw&2ZNZlw2Je=z2n{>PO~9UcuS_C3a}8-8&Ll14%|H@Awc$ z4ti?Wlt6gMag*I9*hGLlMH?aw?&9QOv>E8t!&~c$SKIOQ7<{RRe1$V43`$<-4p?VI5!0(V9Ck4l--SpE&C6A=08uwXF<&fc~lz49@WP05;c*13MQ?BycAa+kxZgHf?Mx2!UoHuf&xB$%5fxQ z-pUgyNL>k6fVI6=xGD&1I*qgfcIUQChYQZ&WwISpM~)CY>6k69kykp6EmyOE+}fbp z`8gWMZkw_7S0d3@dZv!}rz~T@{cz); zc4wPMDZlf5Y|E86OTz!jjUbSb(9aCIVo#~+QxucBq;c0){uzd0kM{#@w>f5N-*MVvJas41YL*lA3C zyT5#$K9^*uL9qF!;UsOSephG4+jVq{@skYyRxt|-!?*n%Us@~KwvxPr50SA@L+{dw z<_s*G=|I|?HGr{5)%}ES3kU!A=u!ZN>%|t(W>}F!9+|NSrtN z#Qp1&A5^osnQHNQr=B%eKKzTOy>1!E=iuL;NI=THzc@Q}q-fzGKABG<6BSvwuX_Pu z5h>rA=zsN`mFTMh5)Sp=9}f6Xle~785965IX5JPp*)qA`HNr6El1W@sM z72W5F$*laW8U|hMNKH@?4H+i&9%}Yhl)$91VO_Gx!zZ$U7v0;<4ZQDo?O26A#4fG4 zHBAJNoK*xzBlT#iAdwf5KQw+WYDR3M5`0U{A5N9de7rzIXh0t%LcoQ;D8=@cH$SJC z$VZdKjK>gMmZ~(zLtp^|Y+9)@25!X|Ri~-j%wOL4?Ooit?4ww*31J)=3T;F@tA-P@?QeLa%!*3WlTT*FJR##yZ`_I literal 0 HcmV?d00001 diff --git a/src/prototypes/vehicle-pickup-receivable/.spec/prototype-comment-assets/8b7434c4-e7a7-4473-8404-5864f615811f.png b/src/prototypes/vehicle-pickup-receivable/.spec/prototype-comment-assets/8b7434c4-e7a7-4473-8404-5864f615811f.png new file mode 100644 index 0000000000000000000000000000000000000000..f655592e04363461131b1b8a59ad0e218de1d286 GIT binary patch literal 17943 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 literal 0 HcmV?d00001 diff --git a/src/prototypes/vehicle-pickup-receivable/.spec/prototype-comment-assets/e590591d-67bb-4a69-9536-5bf15921cf29.png b/src/prototypes/vehicle-pickup-receivable/.spec/prototype-comment-assets/e590591d-67bb-4a69-9536-5bf15921cf29.png new file mode 100644 index 0000000000000000000000000000000000000000..021afe7014edb047056157c454ffc5cfb62f5494 GIT binary patch literal 37097 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 OfR8iD&5=tyNdFs1#>II6 literal 0 HcmV?d00001 diff --git a/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableApp.jsx b/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableApp.jsx index 29ba0f7..7701791 100644 --- a/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableApp.jsx +++ b/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableApp.jsx @@ -1,21 +1,19 @@ import PickupReceivableViewPage from '../oneos-web-finance/pages/05-提车应收款-查看.jsx'; import PickupReceivableInvoicePage from '../oneos-web-finance/pages/06-提车应收款-开票信息.jsx'; import PickupReceivableAuditPage from '../oneos-web-finance/pages/07-提车应收款-审核.jsx'; -import PickupReceivableCollectPage from '../oneos-web-finance/pages/08-提车应收款-提车收款单.jsx'; import PickupCollectEditPage from '../oneos-web-finance/pages/04-提车收款单-编辑.jsx'; import VehiclePickupReceivableList from './VehiclePickupReceivableList.jsx'; +import VehiclePickupReceivableCollectPage from './VehiclePickupReceivableCollectPage.jsx'; +import VehiclePickupReceivableContractView from './VehiclePickupReceivableContractView.jsx'; import { - toCollectPageVehicles, appendPickupCollectChild, buildPickupSubmitCcMessage, - applyPickupDateToVehicles, - buildBatchPickupScheduleSummary, - describePickupRule, + buildCollectHandleContext, + buildContractViewContext, + canShowHandle, } from './pickup-receivable-bridge.js'; -var DEFAULT_PICKUP_DATE = '2026-03-12'; - -/** @typedef {'list' | 'collect' | 'view' | 'edit' | 'invoice' | 'audit'} PickupView */ +/** @typedef {'list' | 'collect' | 'contractView' | 'view' | 'edit' | 'invoice' | 'audit'} PickupView */ const Component = function (props) { var useState = React.useState; @@ -26,7 +24,11 @@ const Component = function (props) { useEffect(function () { if (props && props.onPageViewChange) { - var pageId = view === 'collect' ? 'collect' : 'list'; + var pageId = view === 'collect' + ? 'collect' + : view === 'contractView' + ? 'contractView' + : 'list'; props.onPageViewChange(pageId); } }, [view, props]); @@ -39,6 +41,14 @@ const Component = function (props) { var handleContext = handleContextState[0]; var setHandleContext = handleContextState[1]; + var viewContextState = useState(null); + var viewContext = viewContextState[0]; + var setViewContext = viewContextState[1]; + + var contractViewRecordState = useState(null); + var contractViewRecord = contractViewRecordState[0]; + var setContractViewRecord = contractViewRecordState[1]; + useEffect(function () { window.__receivableBack = function () { setView('list'); @@ -65,11 +75,6 @@ const Component = function (props) { if (window.__receivableBack) window.__receivableBack(); }; window.__pickupBuildSubmitCcMessage = buildPickupSubmitCcMessage; - window.__pickupCalc = { - applyPickupDateToVehicles: applyPickupDateToVehicles, - buildBatchPickupScheduleSummary: buildBatchPickupScheduleSummary, - describePickupRule: describePickupRule, - }; window.__pickupHandleSubmit = function (payload) { var ctx = window.__pickupHandleContext; if (ctx && ctx.contractCode) { @@ -85,9 +90,9 @@ const Component = function (props) { delete window.__receivableToAudit; delete window.__receivableSubmit; delete window.__pickupHandleContext; + delete window.__pickupViewContext; delete window.__pickupHandleSubmit; delete window.__pickupBuildSubmitCcMessage; - delete window.__pickupCalc; }; }, [setView, bumpListRefresh]); @@ -96,11 +101,26 @@ const Component = function (props) { if (view === 'collect' && handleContext) { window.__pickupHandleContext = handleContext; } + if (view === 'contractView' && viewContext) { + window.__pickupViewContext = viewContext; + } }, - [view, handleContext], + [view, handleContext, viewContext], ); - if (view === 'collect') return React.createElement(PickupReceivableCollectPage); + if (view === 'collect') return React.createElement(VehiclePickupReceivableCollectPage); + if (view === 'contractView') { + return React.createElement(VehiclePickupReceivableContractView, { + canHandle: contractViewRecord ? canShowHandle(contractViewRecord) : false, + onGoHandle: function () { + if (!contractViewRecord) return; + var ctx = buildCollectHandleContext(contractViewRecord); + setHandleContext(ctx); + window.__pickupHandleContext = ctx; + setView('collect'); + }, + }); + } if (view === 'view') return React.createElement(PickupReceivableViewPage); if (view === 'edit') return React.createElement(PickupCollectEditPage); if (view === 'invoice') return React.createElement(PickupReceivableInvoicePage); @@ -109,28 +129,22 @@ const Component = function (props) { return React.createElement(VehiclePickupReceivableList, { refreshToken: listRefreshToken, onGoHandle: function (record) { - var months = record.paymentCycleMonths || 1; - var pickupDate = record.lastPickupDate || DEFAULT_PICKUP_DATE; - var ctx = { - contractCode: record.contractCode, - contractType: record.contractType, - projectName: record.projectName, - customerName: record.customerName, - paymentMethod: record.paymentMethod || '预付', - paymentCycle: months + '个月', - paymentCycleMonths: months, - contractStart: record.contractEffectiveDate, - contractEnd: record.contractEndDate || '', - businessDept: record.businessDept, - businessPerson: record.businessPerson, - pickupDate: pickupDate, - vehicles: toCollectPageVehicles(record, pickupDate), - }; + var ctx = buildCollectHandleContext(record); setHandleContext(ctx); window.__pickupHandleContext = ctx; setView('collect'); }, - onGoView: function () { + onGoContractView: function (record) { + setContractViewRecord(record); + var ctx = buildContractViewContext(record); + setViewContext(ctx); + window.__pickupViewContext = ctx; + setView('contractView'); + }, + onGoView: function (record, parent) { + if (parent) { + window.__pickupViewContext = { mode: 'batch', batch: record, parent: parent }; + } setView('view'); }, onGoEdit: function () { diff --git a/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableCollectPage.jsx b/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableCollectPage.jsx new file mode 100644 index 0000000..0b5de46 --- /dev/null +++ b/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableCollectPage.jsx @@ -0,0 +1,814 @@ +import { + fmtMoneyYuan, +} from './data/pickup-receivable-list-data.js'; +import { + buildBatchPickupScheduleSummary, + describePickupRule, + buildCollectLinePreview, + buildCollectSubmitPayload, + buildCollectOrderTableRows, + resolveCollectPlateLabel, + PLATE_ACTUAL_DELIVERY_LABEL, +} from './pickup-receivable-bridge.js'; + +function displayText(value) { + var text = value == null ? '' : String(value).trim(); + return text || '—'; +} + +function initLineQuantities(lines) { + var map = {}; + (lines || []).forEach(function (line) { + map[line.lineKey] = 0; + }); + return map; +} + +function formatBrandModelLabel(brand, model) { + return [brand, model] + .filter(function (part) { + return part && String(part).trim() && part !== '-'; + }) + .join(' · ') || '—'; +} + +function DeliveryFieldIconLocation() { + return React.createElement( + 'svg', + { + className: 'vpr-collect-delivery-field__icon', + width: 16, + height: 16, + viewBox: '0 0 24 24', + fill: 'none', + stroke: 'currentColor', + strokeWidth: 2, + strokeLinecap: 'round', + strokeLinejoin: 'round', + 'aria-hidden': true, + }, + React.createElement('path', { d: 'M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z' }), + React.createElement('circle', { cx: '12', cy: '10', r: '3' }), + ); +} + +function DeliveryFieldIconCalendar() { + return React.createElement( + 'svg', + { + className: 'vpr-collect-delivery-field__icon', + width: 16, + height: 16, + viewBox: '0 0 24 24', + fill: 'none', + stroke: 'currentColor', + strokeWidth: 2, + strokeLinecap: 'round', + strokeLinejoin: 'round', + 'aria-hidden': true, + }, + React.createElement('rect', { x: '3', y: '4', width: '18', height: '18', rx: '2' }), + React.createElement('line', { x1: '16', y1: '2', x2: '16', y2: '6' }), + React.createElement('line', { x1: '8', y1: '2', x2: '8', y2: '6' }), + React.createElement('line', { x1: '3', y1: '10', x2: '21', y2: '10' }), + ); +} + +const Component = function () { + var useState = React.useState; + var useMemo = React.useMemo; + var useEffect = React.useEffect; + + var antd = window.antd; + var Card = antd.Card; + var Button = antd.Button; + var Input = antd.Input; + var InputNumber = antd.InputNumber; + var DatePicker = antd.DatePicker; + var Modal = antd.Modal; + var message = antd.message; + var dayjs = window.dayjs; + + var handleCtx = typeof window !== 'undefined' ? window.__pickupHandleContext : null; + var project = handleCtx || {}; + var orderLines = project.leaseOrderLines || []; + var paymentCycleMonths = project.paymentCycleMonths || 1; + + var deliveryLocationState = useState(project.defaultDeliveryLocation || ''); + var deliveryLocation = deliveryLocationState[0]; + var setDeliveryLocation = deliveryLocationState[1]; + + var deliveryDateState = useState(project.defaultPickupDate || ''); + var deliveryDate = deliveryDateState[0]; + var setDeliveryDate = deliveryDateState[1]; + + var lineQuantitiesState = useState(function () { + return initLineQuantities(orderLines); + }); + var lineQuantities = lineQuantitiesState[0]; + var setLineQuantities = lineQuantitiesState[1]; + + var dirtyState = useState(false); + var dirty = dirtyState[0]; + var setDirty = dirtyState[1]; + + var submitAttemptState = useState(false); + var submitAttempted = submitAttemptState[0]; + var setSubmitAttempted = submitAttemptState[1]; + + var submitConfirmState = useState(false); + var submitConfirmVisible = submitConfirmState[0]; + var setSubmitConfirmVisible = submitConfirmState[1]; + + useEffect(function () { + setLineQuantities(initLineQuantities(orderLines)); + }, [project.contractCode]); + + var selectedCount = useMemo(function () { + return (orderLines || []).reduce(function (sum, line) { + var qty = Math.min( + line.availableCount, + Math.max(0, parseInt(lineQuantities[line.lineKey], 10) || 0), + ); + return sum + qty; + }, 0); + }, [orderLines, lineQuantities]); + + var calcRows = useMemo(function () { + var rows = []; + (orderLines || []).forEach(function (line) { + var qty = Math.min( + line.availableCount, + Math.max(0, parseInt(lineQuantities[line.lineKey], 10) || 0), + ); + for (var i = 0; i < qty; i += 1) { + rows.push({ + selected: true, + receivableCompleted: false, + monthRent: line.monthRent, + serviceFeeTotal: line.serviceFeeTotal, + deposit: line.deposit, + receivableDeposit: line.deposit, + receivableService: line.serviceFeeTotal, + }); + } + }); + return rows; + }, [orderLines, lineQuantities]); + + var batchSummary = useMemo(function () { + if (!deliveryDate || !calcRows.length) return null; + return buildBatchPickupScheduleSummary(calcRows, deliveryDate, paymentCycleMonths); + }, [calcRows, deliveryDate, paymentCycleMonths]); + + var amountBreakdown = useMemo(function () { + if (!batchSummary) { + return { rent: 0, deposit: 0, service: 0, total: 0 }; + } + return { + rent: (batchSummary.beforePickup.rent || 0) + (batchSummary.month25.rent || 0), + deposit: batchSummary.beforePickup.deposit || 0, + service: (batchSummary.beforePickup.service || 0) + (batchSummary.month25.service || 0), + total: batchSummary.totalReceivable || 0, + }; + }, [batchSummary]); + + var orderTableRows = useMemo(function () { + return buildCollectOrderTableRows(orderLines); + }, [orderLines]); + + var ruleText = useMemo(function () { + return describePickupRule(batchSummary && batchSummary.rule); + }, [batchSummary]); + + var formReady = Boolean(deliveryDate && String(deliveryLocation || '').trim() && selectedCount > 0); + + var submitHint = useMemo(function () { + if (!deliveryDate) return '请先设置车辆交付时间'; + if (!String(deliveryLocation || '').trim()) return '请先填写车辆交付地点'; + if (!selectedCount) return '请至少选择 1 辆本次交车数量'; + return ''; + }, [deliveryDate, deliveryLocation, selectedCount]); + + function markDirty() { + setDirty(true); + } + + function handleBack() { + if (dirty) { + Modal.confirm({ + title: '确认离开', + content: '当前办理信息尚未提交,确定返回列表吗?', + okText: '返回列表', + cancelText: '继续编辑', + onOk: function () { + if (window.__receivableBack) window.__receivableBack(); + }, + }); + return; + } + if (window.__receivableBack) window.__receivableBack(); + } + + function fillLineQuantity(lineKey, quantity) { + setLineQuantities(function (prev) { + var next = Object.assign({}, prev); + next[lineKey] = quantity; + return next; + }); + markDirty(); + } + + function fillAllPending() { + setLineQuantities(function () { + var next = {}; + (orderLines || []).forEach(function (line) { + next[line.lineKey] = line.availableCount; + }); + return next; + }); + markDirty(); + } + + function clearAllQuantities() { + setLineQuantities(initLineQuantities(orderLines)); + markDirty(); + } + + function handleSubmit() { + setSubmitAttempted(true); + if (!deliveryDate) { + message.warning('请设置车辆交付时间'); + return; + } + if (!String(deliveryLocation || '').trim()) { + message.warning('请填写车辆交付(交还)地点'); + return; + } + if (!selectedCount) { + message.warning('请至少选择 1 辆本次交车数量'); + return; + } + setSubmitConfirmVisible(true); + } + + function confirmSubmit() { + var payload = buildCollectSubmitPayload(project, { + deliveryDate: deliveryDate, + deliveryLocation: deliveryLocation, + lineQuantities: lineQuantities, + }); + if (window.__pickupHandleSubmit) window.__pickupHandleSubmit(payload); + if (window.__pickupBuildSubmitCcMessage) { + message.success(window.__pickupBuildSubmitCcMessage()); + } else { + message.success('已提交办理并生成提车应收款单据'); + } + setSubmitConfirmVisible(false); + setDirty(false); + if (window.__receivableBack) window.__receivableBack(); + } + + function renderContractStat(label, value, options) { + var opts = options || {}; + var valueClass = 'vm-detail-stat-value'; + if (opts.mono) valueClass += ' mono tabular-nums'; + + return React.createElement( + 'div', + { className: 'vm-detail-stat', key: label }, + React.createElement( + 'div', + { className: 'vm-detail-stat-main' }, + React.createElement('span', { className: 'vm-detail-stat-label' }, label), + React.createElement( + 'span', + { className: valueClass, title: displayText(value) }, + displayText(value), + ), + ), + ); + } + + function renderCollectPlateCell(vehicle) { + var label = resolveCollectPlateLabel(vehicle); + var isPending = label === PLATE_ACTUAL_DELIVERY_LABEL; + return React.createElement( + 'span', + { + className: 'vpr-pickup-subtable__plate-no tabular-nums' + + (isPending ? ' vpr-pickup-subtable__plate-no--pending' : ''), + title: label, + }, + label, + ); + } + + function renderCollectModelGroupCell(line) { + var label = formatBrandModelLabel(line.brand, line.model); + return React.createElement( + 'div', + { className: 'vpr-collect-td--model', title: label }, + label, + ); + } + + function renderKpiStat(label, value, highlight) { + return React.createElement( + 'div', + { + className: 'vm-detail-stat vpr-collect-kpi-stat' + + (highlight ? ' vpr-collect-kpi-stat--active' : ''), + key: label, + }, + React.createElement( + 'div', + { className: 'vm-detail-stat-main' }, + React.createElement('span', { className: 'vm-detail-stat-label' }, label), + React.createElement( + 'div', + { className: 'vm-detail-stat-value vpr-collect-kpi-stat__value tabular-nums' }, + value, + ), + ), + ); + } + + var businessMeta = [project.businessDept, project.businessPerson] + .filter(function (part) { + return part && String(part).trim(); + }) + .join(' · '); + + var contractStats = [ + renderContractStat('签约公司', project.signingCompany), + renderContractStat('付款方式', project.paymentMethodLabel || project.paymentMethod), + renderContractStat('付款周期', project.paymentCycleLabel || project.paymentCycle), + renderContractStat('氢费支付方式', project.hydrogenPaymentMethodLabel || project.hydrogenPaymentMethod), + ]; + if (project.hydrogenPrepayAmount != null) { + contractStats.push(renderContractStat('预付款金额', fmtMoneyYuan(project.hydrogenPrepayAmount), { mono: true })); + } + + return React.createElement( + 'div', + { className: 'vm-page lc-page vpr-page vpr-collect-page' }, + React.createElement( + 'header', + { + className: 'vm-detail-topbar vpr-collect-topbar', + 'data-annotation-id': 'vpr-collect-topbar', + }, + React.createElement( + 'button', + { + type: 'button', + className: 'vm-btn vm-btn-back', + onClick: handleBack, + }, + '返回列表', + ), + ), + React.createElement( + 'main', + { className: 'vpr-collect-main' }, + React.createElement( + 'section', + { + className: 'vm-detail-card vpr-collect-contract-card', + 'data-annotation-id': 'vpr-collect-project', + }, + React.createElement( + 'div', + { className: 'vm-detail-hero vpr-collect-contract-hero' }, + React.createElement( + 'div', + null, + React.createElement( + 'div', + { className: 'vm-detail-plate', title: displayText(project.customerName) }, + displayText(project.customerName), + ), + React.createElement( + 'p', + { className: 'vm-detail-meta mono tabular-nums' }, + displayText(project.contractCode), + ), + React.createElement( + 'p', + { className: 'vm-detail-meta', title: displayText(project.projectName) }, + displayText(project.projectName), + ), + ), + React.createElement( + 'div', + { className: 'vm-detail-aside' }, + React.createElement( + 'p', + { className: 'vpr-collect-contract-hero__aside-main', title: displayText(project.signingCompany) }, + displayText(project.signingCompany), + ), + businessMeta + ? React.createElement('p', { className: 'vm-detail-meta' }, businessMeta) + : null, + React.createElement( + 'p', + { className: 'vm-detail-meta' }, + displayText(project.contractType || '正式合同'), + ), + ), + ), + React.createElement( + 'div', + { className: 'vm-detail-stats vpr-collect-contract-stats' }, + contractStats, + ), + ), + React.createElement( + 'div', + { + className: 'vm-detail-stats vpr-collect-summary-stats', + 'data-annotation-id': 'vpr-collect-kpi', + }, + renderKpiStat('已选车辆数', selectedCount + ' 辆', selectedCount > 0), + renderKpiStat('应收总额', fmtMoneyYuan(amountBreakdown.total), amountBreakdown.total > 0), + renderKpiStat('租金总额', fmtMoneyYuan(amountBreakdown.rent), amountBreakdown.rent > 0), + renderKpiStat('保证金总额', fmtMoneyYuan(amountBreakdown.deposit), amountBreakdown.deposit > 0), + renderKpiStat('服务项总额', fmtMoneyYuan(amountBreakdown.service), amountBreakdown.service > 0), + ), + React.createElement( + Card, + { + className: 'vpr-collect-card vpr-collect-card--order', + title: '提车应收款', + 'data-annotation-id': 'vpr-collect-form', + extra: orderLines.length + ? React.createElement( + 'span', + { className: 'vpr-collect-card__extra tabular-nums' }, + orderLines.length, + ' 个待办型号', + ) + : null, + }, + React.createElement( + 'div', + { className: 'vpr-collect-order-section' }, + React.createElement( + 'section', + { className: 'vpr-collect-delivery-panel', 'aria-label': '交付信息' }, + React.createElement( + 'div', + { className: 'vpr-collect-delivery-panel__head' }, + React.createElement('h3', { className: 'vpr-collect-delivery-panel__title' }, '交付信息'), + React.createElement( + 'span', + { className: 'vpr-collect-delivery-panel__hint' }, + '根据交付时间,自动计算提车应收款金额', + ), + ), + React.createElement( + 'div', + { className: 'vpr-collect-delivery-panel__grid' }, + React.createElement( + 'label', + { + className: + 'vpr-collect-delivery-field' + + (submitAttempted && !String(deliveryLocation || '').trim() ? ' vpr-collect-delivery-field--invalid' : ''), + }, + React.createElement( + 'span', + { className: 'vpr-collect-delivery-field__label' }, + React.createElement(DeliveryFieldIconLocation), + '车辆交付(交还)地点', + React.createElement('span', { className: 'vpr-collect-form-item__required', 'aria-hidden': true }, ' *'), + ), + React.createElement(Input, { + value: deliveryLocation, + placeholder: '请输入本次交车地点', + className: 'vpr-collect-delivery-field__control', + status: submitAttempted && !String(deliveryLocation || '').trim() ? 'error' : undefined, + onChange: function (e) { + setDeliveryLocation(e.target.value); + markDirty(); + }, + }), + submitAttempted && !String(deliveryLocation || '').trim() + ? React.createElement('span', { className: 'vpr-collect-form-item__error', role: 'alert' }, '请填写交付地点') + : null, + ), + React.createElement( + 'label', + { + className: + 'vpr-collect-delivery-field' + + (submitAttempted && !deliveryDate ? ' vpr-collect-delivery-field--invalid' : ''), + }, + React.createElement( + 'span', + { className: 'vpr-collect-delivery-field__label' }, + React.createElement(DeliveryFieldIconCalendar), + '车辆交付时间', + React.createElement('span', { className: 'vpr-collect-form-item__required', 'aria-hidden': true }, ' *'), + ), + React.createElement(DatePicker, { + className: 'vpr-collect-delivery-field__control vpr-collect-date-picker', + style: { width: '100%' }, + placeholder: '请选择交付日期', + status: submitAttempted && !deliveryDate ? 'error' : undefined, + value: deliveryDate && dayjs ? dayjs(deliveryDate) : null, + onChange: function (_date, dateString) { + setDeliveryDate(dateString || ''); + markDirty(); + }, + }), + submitAttempted && !deliveryDate + ? React.createElement('span', { className: 'vpr-collect-form-item__error', role: 'alert' }, '请选择交付时间') + : null, + ), + ), + ), + React.createElement( + 'div', + { className: 'vpr-page-callout vpr-page-callout--rule vpr-collect-order-callout', role: 'note' }, + ruleText, + ), + React.createElement( + 'div', + { className: 'vpr-collect-table-toolbar' }, + React.createElement( + 'div', + { className: 'vpr-collect-table-toolbar__left' }, + React.createElement( + 'span', + { className: 'vpr-collect-table-toolbar__badge tabular-nums' }, + '待办 ', + orderLines.length, + ' 行', + ), + React.createElement('span', { className: 'vpr-collect-table-toolbar__hint' }, '填写本次交车数后自动计算应收'), + ), + orderLines.length + ? React.createElement( + 'div', + { className: 'vpr-collect-table-toolbar__actions' }, + React.createElement(Button, { size: 'small', type: 'primary', ghost: true, onClick: fillAllPending }, '填入全部待办'), + React.createElement(Button, { size: 'small', onClick: clearAllQuantities }, '清空数量'), + ) + : null, + ), + React.createElement( + 'div', + { className: 'vpr-collect-table-wrap', 'data-annotation-id': 'vpr-collect-table' }, + orderLines.length + ? React.createElement( + 'table', + { className: 'vpr-collect-table' }, + React.createElement( + 'thead', + null, + React.createElement( + 'tr', + null, + React.createElement('th', null, '品牌型号'), + React.createElement('th', { className: 'vpr-collect-th--plate' }, '车牌号'), + React.createElement('th', { className: 'vpr-collect-th--num' }, '未交车辆数'), + React.createElement('th', { className: 'vpr-collect-th--num' }, '本次交车数'), + React.createElement('th', { className: 'vpr-collect-th--num' }, '租金总额'), + React.createElement('th', { className: 'vpr-collect-th--num' }, '保证金总额'), + React.createElement('th', { className: 'vpr-collect-th--num' }, '服务项总额'), + React.createElement('th', { className: 'vpr-collect-th--num' }, '应收总额'), + ), + ), + React.createElement( + 'tbody', + null, + orderTableRows.map(function (row) { + var line = row.line; + var preview = buildCollectLinePreview( + line, + lineQuantities[line.lineKey], + deliveryDate, + paymentCycleMonths, + ); + var rowClass = preview.quantity ? 'vpr-collect-row--selected' : 'vpr-collect-row--idle'; + var cells = []; + + if (row.isFirstInModelGroup) { + cells.push( + React.createElement( + 'td', + { + key: 'model', + rowSpan: row.modelGroupRowSpan, + className: 'vpr-collect-td--model-cell', + }, + renderCollectModelGroupCell(line), + ), + ); + } + + cells.push( + React.createElement( + 'td', + { key: 'plateNo', className: 'vpr-pickup-subtable__plate-cell' }, + renderCollectPlateCell(row.vehicle), + ), + ); + + if (row.isFirstInModelGroup) { + cells.push( + React.createElement( + 'td', + { + key: 'pendingCount', + rowSpan: row.modelGroupRowSpan, + className: 'vpr-collect-td--num vpr-collect-td--action tabular-nums', + title: '点击填入该行全部未交车辆', + onClick: function () { + fillLineQuantity(line.lineKey, line.availableCount); + }, + }, + line.availableCount, + ), + React.createElement( + 'td', + { + key: 'pickupQty', + rowSpan: row.modelGroupRowSpan, + className: 'vpr-collect-td--num', + }, + React.createElement(InputNumber, { + min: 0, + max: line.availableCount, + value: lineQuantities[line.lineKey] || 0, + className: 'vpr-collect-qty-input', + onChange: function (value) { + setLineQuantities(function (prev) { + var next = Object.assign({}, prev); + next[line.lineKey] = value == null ? 0 : value; + return next; + }); + markDirty(); + }, + }), + ), + React.createElement( + 'td', + { + key: 'rentTotal', + rowSpan: row.modelGroupRowSpan, + className: 'vpr-collect-td--num tabular-nums', + }, + fmtMoneyYuan(preview.rentTotal), + ), + React.createElement( + 'td', + { + key: 'depositTotal', + rowSpan: row.modelGroupRowSpan, + className: 'vpr-collect-td--num tabular-nums', + }, + fmtMoneyYuan(preview.depositTotal), + ), + React.createElement( + 'td', + { + key: 'serviceTotal', + rowSpan: row.modelGroupRowSpan, + className: 'vpr-collect-td--num tabular-nums', + }, + fmtMoneyYuan(preview.serviceTotal), + ), + React.createElement( + 'td', + { + key: 'lineTotal', + rowSpan: row.modelGroupRowSpan, + className: 'vpr-collect-td--num tabular-nums', + }, + fmtMoneyYuan(preview.lineTotal), + ), + ); + } + + return React.createElement( + 'tr', + { key: row.rowKey, className: rowClass }, + cells, + ); + }), + ), + ) + : React.createElement( + 'div', + { className: 'vpr-collect-table-toolbar vpr-collect-table-toolbar--warn vpr-page-empty' }, + React.createElement('p', { className: 'vpr-page-empty__title' }, '暂无可办理的租赁订单明细'), + React.createElement('p', { className: 'vpr-page-empty__desc' }, '本合同车辆可能已全部办理,请返回列表确认。'), + ), + ), + batchSummary && batchSummary.rule === 'on-or-before-15' && batchSummary.month25.amount > 0 + ? React.createElement( + 'div', + { className: 'vpr-collect-batch-panel' }, + React.createElement('div', { className: 'vpr-collect-batch-panel__title' }, '当月 25 日应付(下周期租金及服务费)'), + React.createElement( + 'div', + { className: 'vpr-collect-batch-panel__amount tabular-nums' }, + fmtMoneyYuan(batchSummary.month25.amount), + ), + ) + : null, + ), + ), + ), + React.createElement( + 'footer', + { className: 'vpr-collect-footer', 'data-annotation-id': 'vpr-collect-footer' }, + React.createElement( + 'div', + { className: 'vpr-collect-footer__left' }, + dirty + ? React.createElement('span', { className: 'vpr-collect-draft-badge' }, '未提交') + : null, + React.createElement( + 'div', + { className: 'vpr-collect-footer__summary' + (formReady ? '' : ' vpr-collect-footer__summary--warn') }, + formReady + ? React.createElement( + React.Fragment, + null, + '已选 ', + React.createElement('strong', { className: 'tabular-nums' }, String(selectedCount)), + ' 辆 · 应收合计 ', + React.createElement( + 'strong', + { className: 'tabular-nums' }, + fmtMoneyYuan(amountBreakdown.total), + ), + ) + : React.createElement('span', null, submitHint || '请完善交付信息与交车数量'), + ), + ), + React.createElement( + 'div', + { className: 'vpr-collect-footer__actions' }, + React.createElement(Button, { onClick: handleBack }, '取消'), + React.createElement( + Button, + { + type: 'primary', + className: 'vm-btn-primary', + disabled: !formReady, + onClick: handleSubmit, + title: formReady ? '提交并生成提车应收款' : submitHint, + }, + '提交生成', + ), + ), + ), + React.createElement( + Modal, + { + title: '确认提交办理', + open: submitConfirmVisible, + okText: '确认提交', + cancelText: '再检查一下', + onOk: confirmSubmit, + onCancel: function () { + setSubmitConfirmVisible(false); + }, + }, + React.createElement( + 'div', + { className: 'vpr-submit-confirm' }, + React.createElement( + 'p', + null, + '将为 ', + React.createElement('strong', null, String(selectedCount)), + ' 辆车生成本次提车应收款。', + ), + React.createElement( + 'ul', + { className: 'vpr-submit-confirm__list' }, + React.createElement('li', null, '交付时间:', React.createElement('strong', null, deliveryDate || '—')), + React.createElement('li', null, '交付地点:', React.createElement('strong', null, deliveryLocation || '—')), + React.createElement( + 'li', + null, + '应收合计:', + React.createElement( + 'strong', + { className: 'tabular-nums' }, + fmtMoneyYuan(amountBreakdown.total), + ), + ), + ), + ), + ), + ); +}; + +export default Component; diff --git a/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableContractView.jsx b/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableContractView.jsx new file mode 100644 index 0000000..5da12d6 --- /dev/null +++ b/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableContractView.jsx @@ -0,0 +1,342 @@ +import { StatusTag } from '../vehicle-management/components/StatusTag'; +import { + fmtMoneyYuan, + normalizeAuditStatus, + auditStatusTone, +} from './data/pickup-receivable-list-data.js'; + +function displayText(value) { + var text = value == null ? '' : String(value).trim(); + return text || '—'; +} + +function renderInfoField(label, value) { + return React.createElement( + 'div', + { className: 'vpr-collect-field', key: label }, + React.createElement('div', { className: 'vpr-collect-field__label' }, label), + React.createElement( + 'div', + { className: 'vpr-collect-field__value', title: displayText(value) }, + displayText(value), + ), + ); +} + +const Component = function (props) { + var useMemo = React.useMemo; + var antd = window.antd; + var Button = antd.Button; + var Card = antd.Card; + + var ctx = typeof window !== 'undefined' ? window.__pickupViewContext : null; + var project = ctx || {}; + var publishedRecords = project.publishedRecords || []; + var pendingVehicles = project.pendingVehicles || []; + var onGoHandle = props && props.onGoHandle; + var canHandle = props && props.canHandle; + + var summary = useMemo(function () { + var receivableTotal = 0; + var receivedTotal = 0; + publishedRecords.forEach(function (row) { + receivableTotal += parseFloat(row.receivableTotal) || 0; + receivedTotal += parseFloat(row.receivedTotal) || 0; + }); + return { + publishedCount: publishedRecords.length, + pendingCount: pendingVehicles.length, + receivableTotal: receivableTotal, + receivedTotal: receivedTotal, + }; + }, [publishedRecords, pendingVehicles]); + + var showHandle = canHandle && pendingVehicles.length > 0 && onGoHandle; + + function handleBack() { + if (window.__receivableBack) window.__receivableBack(); + } + + function handleGoHandle() { + if (onGoHandle) onGoHandle(); + } + + return React.createElement( + 'div', + { className: 'vm-page lc-page vpr-page vpr-collect-page vpr-contract-view-page' }, + React.createElement( + 'header', + { className: 'vpr-collect-topbar', 'data-annotation-id': 'vpr-contract-view-topbar' }, + React.createElement( + 'button', + { + type: 'button', + className: 'vm-btn vm-btn-back', + onClick: handleBack, + }, + '返回列表', + ), + ), + showHandle + ? React.createElement( + 'div', + { className: 'vpr-contract-view-actions' }, + React.createElement( + Button, + { + type: 'primary', + className: 'vm-btn-primary', + onClick: handleGoHandle, + }, + '办理未发布车辆', + ), + ) + : null, + React.createElement( + 'div', + { className: 'vpr-page-kpi-row', 'data-annotation-id': 'vpr-contract-view-kpi' }, + React.createElement( + 'div', + { className: 'vpr-collect-kpi-card' }, + React.createElement('div', { className: 'vpr-collect-kpi-card__label' }, '已发布单据'), + React.createElement( + 'div', + { className: 'vpr-collect-kpi-card__value tabular-nums' }, + String(summary.publishedCount), + React.createElement('span', { className: 'vpr-page-kpi-unit' }, ' 条'), + ), + ), + React.createElement( + 'div', + { className: 'vpr-collect-kpi-card' }, + React.createElement('div', { className: 'vpr-collect-kpi-card__label' }, '未发布车辆'), + React.createElement( + 'div', + { + className: + 'vpr-collect-kpi-card__value tabular-nums' + + (summary.pendingCount ? ' vpr-page-kpi-value--warn' : ''), + }, + String(summary.pendingCount), + React.createElement('span', { className: 'vpr-page-kpi-unit' }, ' 辆'), + ), + ), + React.createElement( + 'div', + { className: 'vpr-collect-kpi-card' }, + React.createElement('div', { className: 'vpr-collect-kpi-card__label' }, '已发布合计应收'), + React.createElement( + 'div', + { className: 'vpr-collect-kpi-card__value tabular-nums' }, + fmtMoneyYuan(summary.receivableTotal), + ), + ), + React.createElement( + 'div', + { className: 'vpr-collect-kpi-card vpr-collect-kpi-card--primary' }, + React.createElement('div', { className: 'vpr-collect-kpi-card__label' }, '已发布合计实收'), + React.createElement( + 'div', + { className: 'vpr-collect-kpi-card__value tabular-nums' }, + fmtMoneyYuan(summary.receivedTotal), + ), + React.createElement('div', { className: 'vpr-collect-kpi-card__hint' }, '由收款记录导入反写'), + ), + ), + React.createElement( + Card, + { + className: 'vpr-collect-card vpr-collect-card--primary', + title: '合同项目信息', + }, + React.createElement( + 'div', + { className: 'vpr-collect-info-grid' }, + renderInfoField('客户名称', project.customerName), + renderInfoField('合同编码', project.contractCode), + renderInfoField('项目名称', project.projectName), + renderInfoField('付款周期', project.paymentCycle), + renderInfoField('业务部门', project.businessDept), + renderInfoField('业务负责人', project.businessPerson), + renderInfoField('租车数', project.contractVehicleCount), + renderInfoField('已提车数', project.pickedUpVehicleCount), + ), + React.createElement( + 'div', + { className: 'vpr-page-callout', role: 'note' }, + React.createElement('strong', null, '说明:'), + '本页汇总本合同全部已发布与未发布提车应收款。未发布车辆可点击上方「办理未发布车辆」进入办理流程。', + ), + ), + React.createElement( + 'section', + { className: 'vpr-contract-view-section' }, + React.createElement( + 'div', + { className: 'vpr-contract-view-section__head' }, + React.createElement('h2', { className: 'vpr-contract-view-section__title' }, '已发布提车应收款'), + React.createElement( + 'span', + { className: 'vpr-contract-view-section__count tabular-nums' }, + summary.publishedCount + ' 条', + ), + ), + publishedRecords.length + ? React.createElement( + 'div', + { className: 'vpr-pickup-table-wrap vpr-page-table-wrap' }, + React.createElement( + 'table', + { className: 'vpr-pickup-native-table vpr-contract-view-table' }, + React.createElement( + 'thead', + null, + React.createElement( + 'tr', + null, + React.createElement('th', null, '提车收款单编码'), + React.createElement('th', null, '发布状态'), + React.createElement('th', null, '单据状态'), + React.createElement('th', null, '交付时间'), + React.createElement('th', { className: 'vpr-th--num' }, '车辆数'), + React.createElement('th', { className: 'vpr-th--num' }, '合计应收'), + React.createElement('th', { className: 'vpr-th--num' }, '合计实收'), + React.createElement('th', null, '生成时间'), + ), + ), + React.createElement( + 'tbody', + null, + publishedRecords.map(function (row) { + var auditLabel = normalizeAuditStatus(row.auditStatus); + return React.createElement( + 'tr', + { key: row.collectCode || row.seq, className: 'vpr-page-table-row' }, + React.createElement('td', { className: 'tabular-nums' }, displayText(row.collectCode)), + React.createElement( + 'td', + null, + React.createElement(StatusTag, { + label: row.publishStatus, + tone: 'green', + title: row.publishStatus, + }), + ), + React.createElement( + 'td', + null, + React.createElement(StatusTag, { + label: auditLabel === '已驳回' ? '审批驳回' : auditLabel, + tone: auditStatusTone(row.auditStatus), + title: auditLabel, + }), + ), + React.createElement('td', { className: 'tabular-nums' }, displayText(row.pickupDate)), + React.createElement('td', { className: 'vpr-td--num tabular-nums' }, String(row.vehicleCount || 0)), + React.createElement('td', { className: 'vpr-money vpr-td--num tabular-nums' }, fmtMoneyYuan(row.receivableTotal)), + React.createElement('td', { className: 'vpr-money vpr-td--num tabular-nums' }, fmtMoneyYuan(row.receivedTotal)), + React.createElement('td', { className: 'tabular-nums' }, displayText(row.chargeTime)), + ); + }), + ), + ), + ) + : React.createElement( + 'div', + { className: 'vpr-contract-view-empty vpr-page-empty' }, + React.createElement('p', { className: 'vpr-page-empty__title' }, '暂无已发布记录'), + React.createElement('p', { className: 'vpr-page-empty__desc' }, '办理提交后将在此展示已生成的提车应收款单据。'), + ), + ), + React.createElement( + 'section', + { className: 'vpr-contract-view-section' }, + React.createElement( + 'div', + { className: 'vpr-contract-view-section__head' }, + React.createElement('h2', { className: 'vpr-contract-view-section__title' }, '未发布提车应收款'), + React.createElement( + 'span', + { className: 'vpr-contract-view-section__count tabular-nums' }, + summary.pendingCount + ' 辆', + ), + ), + pendingVehicles.length + ? React.createElement( + 'div', + { className: 'vpr-pickup-table-wrap vpr-page-table-wrap' }, + React.createElement( + 'table', + { className: 'vpr-pickup-native-table vpr-contract-view-table' }, + React.createElement( + 'thead', + null, + React.createElement( + 'tr', + null, + React.createElement('th', { className: 'vpr-th--num' }, '序号'), + React.createElement('th', null, '发布状态'), + React.createElement('th', null, '品牌'), + React.createElement('th', null, '型号'), + React.createElement('th', null, '车牌号'), + React.createElement('th', null, '说明'), + ), + ), + React.createElement( + 'tbody', + null, + pendingVehicles.map(function (vehicle) { + return React.createElement( + 'tr', + { + key: (vehicle.seq || '') + '-' + (vehicle.plateNo || '') + '-' + (vehicle.model || ''), + className: 'vpr-page-table-row', + }, + React.createElement('td', { className: 'vpr-td--num tabular-nums' }, vehicle.seq), + React.createElement( + 'td', + null, + React.createElement(StatusTag, { + label: vehicle.publishStatus, + tone: 'amber', + title: vehicle.publishStatus, + }), + ), + React.createElement('td', null, displayText(vehicle.brand)), + React.createElement('td', null, displayText(vehicle.model)), + React.createElement('td', { className: 'tabular-nums' }, displayText(vehicle.plateNo)), + React.createElement('td', { className: 'vpr-page-table-muted' }, '尚未办理,可发起提车应收款办理'), + ); + }), + ), + ), + ) + : React.createElement( + 'div', + { className: 'vpr-contract-view-empty vpr-page-empty vpr-page-empty--success' }, + React.createElement('p', { className: 'vpr-page-empty__title' }, '本合同车辆均已发布'), + React.createElement('p', { className: 'vpr-page-empty__desc' }, '所有车辆均已生成提车应收款,无需再次办理。'), + ), + ), + showHandle + ? React.createElement( + 'div', + { className: 'vpr-contract-view-footer-cta' }, + React.createElement( + Button, + { + type: 'primary', + size: 'large', + className: 'vm-btn-primary', + onClick: handleGoHandle, + }, + '办理 ', + summary.pendingCount, + ' 辆未发布车辆', + ), + ) + : null, + ); +}; + +export default Component; diff --git a/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableList.jsx b/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableList.jsx index ffb2fde..f463584 100644 --- a/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableList.jsx +++ b/src/prototypes/vehicle-pickup-receivable/VehiclePickupReceivableList.jsx @@ -32,23 +32,12 @@ var ONEOS_ANT_TABLE_GLOBAL_FIX = [ var VPR_LIST_CHROME_OFFSET = 420; -var VPR_MAIN_TABLE_COL_RATIOS = [13, 7, 9.5, 6, 6, 6, 7.5, 6, 6, 6, 7.5, 6]; -var VPR_MAIN_TABLE_COL_RATIO_SUM = VPR_MAIN_TABLE_COL_RATIOS.reduce(function (sum, ratio) { - return sum + ratio; -}, 0); +/** 主表列宽(px);scroll.x 为各列之和,表头/表体横向同步滚动 */ +var VPR_MAIN_TABLE_COLUMN_WIDTHS = [240, 120, 160, 100, 100, 100, 120, 100, 100, 100, 120, 140]; -function buildVprMainTableColumnWidths(containerWidth) { - var safeWidth = Math.max(960, Math.floor(containerWidth) || 960); - var widths = VPR_MAIN_TABLE_COL_RATIOS.map(function (ratio) { - return Math.max(52, Math.floor(safeWidth * ratio / VPR_MAIN_TABLE_COL_RATIO_SUM)); - }); - var sum = widths.reduce(function (acc, width) { - return acc + width; - }, 0); - var delta = safeWidth - sum; - if (delta) widths[widths.length - 1] += delta; - return { widths: widths, scrollX: safeWidth }; -} +var VPR_MAIN_TABLE_SCROLL_X = VPR_MAIN_TABLE_COLUMN_WIDTHS.reduce(function (sum, width) { + return sum + width; +}, 0); var KPI_ICONS = { all: React.createElement( @@ -68,7 +57,7 @@ var KPI_ICONS = { React.createElement('path', { d: 'M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z' }), React.createElement('path', { d: 'M14 2v4a2 2 0 0 0 2 2h4' }), ), - pending: React.createElement( + notPickedUp: React.createElement( 'svg', { xmlns: 'http://www.w3.org/2000/svg', @@ -85,7 +74,7 @@ var KPI_ICONS = { React.createElement('circle', { cx: 12, cy: 12, r: 10 }), React.createElement('polyline', { points: '12 6 12 12 16 14' }), ), - inReview: React.createElement( + partialPickedUp: React.createElement( 'svg', { xmlns: 'http://www.w3.org/2000/svg', @@ -102,7 +91,7 @@ var KPI_ICONS = { React.createElement('path', { d: 'M21 12a9 9 0 1 1-3-6.7' }), React.createElement('polyline', { points: '21 3 21 9 15 9' }), ), - approved: React.createElement( + completed: React.createElement( 'svg', { xmlns: 'http://www.w3.org/2000/svg', @@ -118,7 +107,7 @@ var KPI_ICONS = { }, React.createElement('path', { d: 'M20 6 9 17l-5-5' }), ), - rejected: React.createElement( + refunded: React.createElement( 'svg', { xmlns: 'http://www.w3.org/2000/svg', @@ -132,28 +121,8 @@ var KPI_ICONS = { strokeLinejoin: 'round', 'aria-hidden': true, }, - React.createElement('circle', { cx: 12, cy: 12, r: 10 }), - React.createElement('path', { d: 'm15 9-6 6' }), - React.createElement('path', { d: 'm9 9 6 6' }), - ), - generated: React.createElement( - 'svg', - { - xmlns: 'http://www.w3.org/2000/svg', - width: 18, - height: 18, - viewBox: '0 0 24 24', - fill: 'none', - stroke: 'currentColor', - strokeWidth: 2, - strokeLinecap: 'round', - strokeLinejoin: 'round', - 'aria-hidden': true, - }, - React.createElement('path', { d: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z' }), - React.createElement('polyline', { points: '14 2 14 8 20 8' }), - React.createElement('line', { x1: 12, x2: 12, y1: 18, y2: 12 }), - React.createElement('line', { x1: 9, x2: 15, y1: 15, y2: 15 }), + React.createElement('path', { d: 'M3 7v6h6' }), + React.createElement('path', { d: 'M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13' }), ), }; @@ -262,6 +231,7 @@ const Component = function (props) { contractCode: undefined, projectName: undefined, customerName: undefined, + plateNo: undefined, businessDept: undefined, businessPerson: undefined, }); @@ -272,6 +242,7 @@ const Component = function (props) { contractCode: undefined, projectName: undefined, customerName: undefined, + plateNo: undefined, businessDept: undefined, businessPerson: undefined, }); @@ -291,31 +262,9 @@ const Component = function (props) { [props && props.refreshToken], ); + var tableColumnWidths = VPR_MAIN_TABLE_COLUMN_WIDTHS; + var tableScrollX = VPR_MAIN_TABLE_SCROLL_X; var tableWrapRef = React.useRef(null); - var tableLayoutState = React.useState(function () { - return buildVprMainTableColumnWidths(1200); - }); - var tableColumnWidths = tableLayoutState[0].widths; - var tableScrollX = tableLayoutState[0].scrollX; - var setTableLayout = tableLayoutState[1]; - - useEffect(function () { - var el = tableWrapRef.current; - if (!el || typeof ResizeObserver === 'undefined') return undefined; - var syncWidth = function () { - var nextWidth = el.clientWidth; - if (!nextWidth) return; - setTableLayout(buildVprMainTableColumnWidths(nextWidth)); - }; - syncWidth(); - var observer = new ResizeObserver(function () { - syncWidth(); - }); - observer.observe(el); - return function () { - observer.disconnect(); - }; - }, []); var contractPopoverKeyState = useState(null); var contractPopoverKey = contractPopoverKeyState[0]; @@ -346,8 +295,8 @@ const Component = function (props) { }, [mainList, appliedFilters]); var kpiCounts = useMemo(function () { - return countKpiFromList(filteredByQuery, kpiTab); - }, [filteredByQuery, kpiTab]); + return countKpiFromList(filteredByQuery); + }, [filteredByQuery]); var filteredData = useMemo(function () { return filterByKpiTab(filteredByQuery, kpiTab); @@ -364,6 +313,45 @@ const Component = function (props) { .slice(start, start + pageSize); }, [filteredData, safePage, pageSize]); + useEffect( + function () { + var root = tableWrapRef.current; + if (!root) return undefined; + var body = root.querySelector('.ant-table-body'); + var header = root.querySelector('.ant-table-header'); + if (!body || !header) return undefined; + + function applyLayoutSync() { + var scrollbarWidth = Math.max(0, body.offsetWidth - body.clientWidth); + header.style.paddingRight = scrollbarWidth ? scrollbarWidth + 'px' : ''; + header.style.boxSizing = 'border-box'; + header.scrollLeft = body.scrollLeft; + } + + function onBodyScroll() { + header.scrollLeft = body.scrollLeft; + } + + applyLayoutSync(); + body.addEventListener('scroll', onBodyScroll, { passive: true }); + var resizeObserver = + typeof ResizeObserver !== 'undefined' + ? new ResizeObserver(function () { + applyLayoutSync(); + }) + : null; + if (resizeObserver) resizeObserver.observe(body); + + return function () { + body.removeEventListener('scroll', onBodyScroll); + if (resizeObserver) resizeObserver.disconnect(); + header.style.paddingRight = ''; + header.style.boxSizing = ''; + }; + }, + [pagedList, safePage, pageSize, tableScrollX], + ); + function handleQuery() { setAppliedFilters(Object.assign({}, filters)); setPage(1); @@ -374,6 +362,7 @@ const Component = function (props) { contractCode: undefined, projectName: undefined, customerName: undefined, + plateNo: undefined, businessDept: undefined, businessPerson: undefined, }; @@ -388,6 +377,11 @@ const Component = function (props) { else message.info('跳转至办理页(原型)'); } + function goContractView(record) { + if (props && typeof props.onGoContractView === 'function') props.onGoContractView(record); + else message.info('查看合同提车应收款(原型):' + (record.contractCode || '')); + } + function goRefund(record) { message.success( '已发起退款流程(原型):' + (record.contractCode || '') + ' · 抄送财务复核', @@ -422,7 +416,49 @@ const Component = function (props) { if (!vehicle) return ''; return [String(vehicle.brand || '').trim(), String(vehicle.model || '').trim()] .filter(Boolean) - .join(' '); + .join('::'); + } + + var PLATE_ACTUAL_DELIVERY_LABEL = '以实际交付为准'; + + function formatBrandModelLabel(brand, model) { + return [brand, model] + .filter(function (part) { + return part && String(part).trim() && part !== '-'; + }) + .join(' · ') || '—'; + } + + function findLeaseOrderVehicle(parent, deliveryVehicle) { + if (!parent || !deliveryVehicle) return null; + return (parent.leaseOrderVehicles || []).find(function (lv) { + if (deliveryVehicle.seq != null && lv.seq === deliveryVehicle.seq) return true; + var deliveryPlate = String(deliveryVehicle.plateNo || '').trim(); + var leasePlate = String(lv.plateNo || '').trim(); + return deliveryPlate && leasePlate && deliveryPlate === leasePlate; + }) || null; + } + + function isLeaseSpecificVehicle(leaseVehicle) { + if (!leaseVehicle) return false; + if (leaseVehicle.plateMode === 'specific') return true; + if (leaseVehicle.plateMode === 'actual') return false; + var leasePlate = String(leaseVehicle.plateNo || '').trim(); + return Boolean(leasePlate && leasePlate !== PLATE_ACTUAL_DELIVERY_LABEL && leasePlate !== '-'); + } + + function resolveSubTablePlateLabel(deliveryVehicle, parent) { + if (!deliveryVehicle) return '—'; + var leaseVehicle = findLeaseOrderVehicle(parent, deliveryVehicle); + var deliveryPlate = String(deliveryVehicle.plateNo || '').trim(); + if (isLeaseSpecificVehicle(leaseVehicle)) { + var contractPlate = leaseVehicle ? String(leaseVehicle.plateNo || '').trim() : ''; + return contractPlate || deliveryPlate || '—'; + } + if (deliveryPlate && deliveryPlate !== PLATE_ACTUAL_DELIVERY_LABEL) { + return deliveryPlate; + } + return PLATE_ACTUAL_DELIVERY_LABEL; } function buildPickupSubModelGroupRows(parent) { @@ -434,9 +470,12 @@ const Component = function (props) { batch: batch, parent: parent, modelGroup: null, + vehicle: null, batchSeq: batch.seq, isFirstInBatch: true, batchRowSpan: 1, + isFirstInModelGroup: true, + modelGroupRowSpan: 1, }); return; } @@ -455,14 +494,24 @@ const Component = function (props) { } groupMap[key].vehicles.push(vehicle); }); - groupOrder.forEach(function (key, idx) { - rows.push({ - batch: batch, - parent: parent, - modelGroup: groupMap[key], - batchSeq: batch.seq, - isFirstInBatch: idx === 0, - batchRowSpan: groupOrder.length, + var batchVehicleCount = vehicles.length; + var vehicleRowIndex = 0; + groupOrder.forEach(function (key) { + var modelGroup = groupMap[key]; + var groupVehicles = modelGroup.vehicles; + groupVehicles.forEach(function (vehicle, vehicleIndex) { + rows.push({ + batch: batch, + parent: parent, + modelGroup: modelGroup, + vehicle: vehicle, + batchSeq: batch.seq, + isFirstInBatch: vehicleRowIndex === 0, + batchRowSpan: batchVehicleCount, + isFirstInModelGroup: vehicleIndex === 0, + modelGroupRowSpan: groupVehicles.length, + }); + vehicleRowIndex += 1; }); }); }); @@ -471,34 +520,25 @@ const Component = function (props) { function renderModelGroupCell(modelGroup) { if (!modelGroup) return '—'; - var label = [modelGroup.brand, modelGroup.model].filter(Boolean).join(' '); - var plates = (modelGroup.vehicles || []) - .map(function (vehicle) { - return String(vehicle.plateNo || '').trim(); - }) - .filter(Boolean); + var label = formatBrandModelLabel(modelGroup.brand, modelGroup.model); return React.createElement( 'div', - { className: 'vpr-pickup-subtable__model-group' }, - React.createElement( - 'div', - { className: 'vpr-pickup-subtable__model-group-name', title: label || '—' }, - label || '—', - ), - plates.length - ? React.createElement( - 'div', - { - className: 'vpr-pickup-subtable__model-group-plates tabular-nums', - title: plates.join('、'), - }, - plates.join('、'), - ) - : React.createElement( - 'div', - { className: 'vpr-pickup-subtable__model-group-plates is-empty' }, - '—', - ), + { className: 'vpr-pickup-subtable__model-group-name', title: label }, + label, + ); + } + + function renderPlateNoCell(vehicle, parent) { + var label = resolveSubTablePlateLabel(vehicle, parent); + var isPending = label === PLATE_ACTUAL_DELIVERY_LABEL; + return React.createElement( + 'span', + { + className: 'vpr-pickup-subtable__plate-no tabular-nums' + + (isPending ? ' vpr-pickup-subtable__plate-no--pending' : ''), + title: label, + }, + label, ); } @@ -592,60 +632,55 @@ const Component = function (props) { }); } - function handleProjectInfoClick(record, e) { - if (e) e.stopPropagation(); - if (canShowHandle(record)) { - goHandle(record); - return; - } - message.info('当前合同暂无可办理的提车应收款'); - } - function renderProjectInfoCell(_, record) { var clickable = canShowHandle(record); var hasSubRows = Boolean(record && record.children && record.children.length); + var stackContent = React.createElement( + 'div', + { className: 'vm-stack' }, + React.createElement( + 'span', + { className: 'primary', title: displayText(record.customerName) }, + displayText(record.customerName), + ), + React.createElement( + 'span', + { className: 'code', title: displayText(record.contractCode) }, + displayText(record.contractCode), + ), + React.createElement( + 'span', + { className: 'sub', title: displayText(record.projectName) }, + displayText(record.projectName), + ), + ); + return React.createElement( 'div', { className: 'lc-project-info-merged-cell' }, hasSubRows ? renderRowExpandIcon(record) : React.createElement('span', { className: 'vpr-row-expand-spacer', 'aria-hidden': true }), React.createElement( 'div', - { - className: 'lc-project-info-cell' + (clickable ? ' vpr-project-info-cell--clickable' : ''), - role: clickable ? 'button' : undefined, - tabIndex: clickable ? 0 : undefined, - title: clickable ? '点击进入办理' : displayText(record.customerName), - onClick: function (e) { - handleProjectInfoClick(record, e); - }, - onKeyDown: clickable - ? function (e) { - if (e.key === 'Enter' || e.key === ' ') { - e.preventDefault(); - handleProjectInfoClick(record, e); - } - } - : undefined, - }, - React.createElement( - 'div', - { className: 'vm-stack' }, - React.createElement( - 'span', - { className: 'primary', title: displayText(record.customerName) }, - displayText(record.customerName), - ), - React.createElement( - 'span', - { className: 'code', title: displayText(record.contractCode) }, - displayText(record.contractCode), - ), - React.createElement( - 'span', - { className: 'sub', title: displayText(record.projectName) }, - displayText(record.projectName), - ), - ), + { className: 'lc-project-info-cell' }, + clickable + ? React.createElement( + 'button', + { + type: 'button', + className: 'lc-project-info-btn', + title: '点击进入办理', + onClick: function (e) { + e.stopPropagation(); + goHandle(record); + }, + }, + stackContent, + ) + : React.createElement( + 'div', + { className: 'lc-project-info-cell__static' }, + stackContent, + ), ), ); } @@ -1124,35 +1159,22 @@ const Component = function (props) { function renderMainActionCell(_, record) { var showHandle = canShowHandle(record); - if (!showHandle) { - return React.createElement('span', { className: 'vm-operation-actions vm-operation-actions--empty' }, '—'); - } return React.createElement( 'div', { - className: 'vm-row-actions vm-operation-actions', + className: 'vm-row-actions vm-operation-actions vpr-main-action-cell', onClick: function (e) { e.stopPropagation(); }, }, - React.createElement( - 'button', - { - type: 'button', - className: 'vm-op-action', - 'aria-label': '办理', - onClick: function (e) { - e.stopPropagation(); - goHandle(record); - }, - }, - React.createElement(ClipboardCheck, { - className: 'vm-op-action__icon', - 'aria-hidden': true, - strokeWidth: 1.75, - }), - React.createElement('span', { className: 'vm-op-action__label' }, '办理'), - ), + renderPrimaryOpButton('查看', Eye, function () { + goContractView(record); + }), + showHandle + ? renderPrimaryOpButton('办理', ClipboardCheck, function () { + goHandle(record); + }) + : null, ); } @@ -1194,7 +1216,8 @@ const Component = function (props) { React.createElement('th', { style: { width: 88 } }, '单据状态'), React.createElement('th', { style: { width: 108 } }, '交付时间'), React.createElement('th', { style: { width: 120 } }, '交付地点'), - React.createElement('th', { style: { width: 180 } }, '品牌型号'), + React.createElement('th', { style: { width: 160 } }, '品牌型号'), + React.createElement('th', { style: { width: 120 } }, '车牌号'), React.createElement('th', { style: { width: 64 } }, '数量'), React.createElement('th', { style: { width: 104 } }, '合计应收'), React.createElement('th', { style: { width: 104 } }, '合计实收'), @@ -1207,11 +1230,14 @@ const Component = function (props) { modelGroupRows.map(function (row) { var batch = row.batch; var modelGroup = row.modelGroup; - var sampleVehicle = modelGroup && modelGroup.vehicles.length ? modelGroup.vehicles[0] : null; + var vehicle = row.vehicle; + var sampleVehicle = vehicle || (modelGroup && modelGroup.vehicles.length ? modelGroup.vehicles[0] : null); var auditStatus = normalizeAuditStatus(batch.auditStatus); var auditLabel = auditStatus === '已驳回' ? '审批驳回' : (auditStatus || '—'); var batchTotals = getBatchAmountTotals(batch); - var rowKey = (parent.contractCode || '') + '-' + batch.seq + '-' + (modelGroup ? modelGroup.key : 'empty'); + var rowKey = (parent.contractCode || '') + '-' + batch.seq + '-' + + (vehicle ? (vehicle.seq != null ? vehicle.seq : buildVehicleModelKey(vehicle)) : 'empty') + + '-' + (row.isFirstInModelGroup ? '0' : '1'); var cells = []; if (row.isFirstInBatch) { @@ -1265,8 +1291,26 @@ const Component = function (props) { ); } + if (row.isFirstInModelGroup) { + cells.push( + React.createElement( + 'td', + { + key: 'vehicleInfo', + rowSpan: row.modelGroupRowSpan, + className: 'vpr-pickup-subtable__model-group-cell', + }, + renderModelGroupCell(modelGroup), + ), + ); + } + cells.push( - React.createElement('td', { key: 'vehicleInfo' }, renderModelGroupCell(modelGroup)), + React.createElement( + 'td', + { key: 'plateNo', className: 'vpr-pickup-subtable__plate-cell' }, + vehicle ? renderPlateNoCell(vehicle, parent) : '—', + ), ); if (row.isFirstInBatch) { @@ -1361,6 +1405,7 @@ const Component = function (props) { title: '项目信息', key: 'projectInfo', width: colWidths[0], + fixed: 'left', ellipsis: true, className: 'lc-project-info-col vpr-col-project', onHeaderCell: function () { @@ -1505,12 +1550,13 @@ const Component = function (props) { title: '操作', key: 'action', width: colWidths[11], + fixed: 'right', className: 'vpr-col-action', render: renderMainActionCell, }, ]; }, - [expandedRowKeys, contractPopoverKey, mainList, tableColumnWidths], + [expandedRowKeys, contractPopoverKey, mainList], ); var filterItems = [ @@ -1571,6 +1617,25 @@ const Component = function (props) { }, }), ), + React.createElement( + 'label', + { key: 'plateNo', className: 'vm-filter-field' }, + React.createElement('span', null, '车牌号'), + React.createElement(Select, { + value: filters.plateNo, + options: filterOptions.plateNo, + allowClear: true, + placeholder: '请选择或输入车牌号', + showSearch: true, + filterOption: filterOption, + className: 'lc-filter-select', + onChange: function (v) { + setFilters(function (p) { + return Object.assign({}, p, { plateNo: v }); + }); + }, + }), + ), React.createElement( 'label', { key: 'businessDept', className: 'vm-filter-field' }, @@ -1580,6 +1645,8 @@ const Component = function (props) { options: filterOptions.businessDept, allowClear: true, placeholder: '请选择业务部门', + showSearch: true, + filterOption: filterOption, className: 'lc-filter-select', onChange: function (v) { setFilters(function (p) { @@ -1672,7 +1739,7 @@ const Component = function (props) { { className: 'vm-kpi-row', role: 'group', - 'aria-label': '提车收款单统计', + 'aria-label': '提车应收款统计', 'data-annotation-id': 'vpr-kpi', }, PICKUP_KPI_CARDS.map(function (card) { diff --git a/src/prototypes/vehicle-pickup-receivable/annotation-source.json b/src/prototypes/vehicle-pickup-receivable/annotation-source.json index d078586..b231ecf 100644 --- a/src/prototypes/vehicle-pickup-receivable/annotation-source.json +++ b/src/prototypes/vehicle-pickup-receivable/annotation-source.json @@ -17,8 +17,8 @@ "fingerprint": "vpr-filter", "path": [] }, - "aiPrompt": "合同编码、项目名称、客户名称、业务部门、业务负责人筛选。", - "annotationText": "默认首行 4 项;超过 1 行时其余项收入「更多筛选」。支持重置与查询,交互对齐租赁合同列表页。", + "aiPrompt": "合同编码、项目名称、客户名称、车牌号、业务部门、业务负责人筛选。", + "annotationText": "默认首行 4 项:合同编码、项目名称、客户名称、车牌号(可输入模糊搜索);业务部门、业务负责人收入「更多筛选」。", "hasMarkdown": true, "color": "#2563eb", "images": [], @@ -28,15 +28,15 @@ { "id": "vpr-kpi", "index": 2, - "title": "提车收款单 KPI", + "title": "提车应收款 KPI", "pageId": "list", "locator": { "selectors": ["[data-annotation-id=\"vpr-kpi\"]"], "fingerprint": "vpr-kpi", "path": [] }, - "aiPrompt": "全部 / 待审批 / 审批中 / 审批通过 / 已驳回统计卡片。", - "annotationText": "点击 KPI 卡片筛选子表提车收款单;计数基于当前筛选结果内的明细条数。", + "aiPrompt": "全部 / 未提车 / 部分提车 / 已完成 / 已退款统计卡片。", + "annotationText": "点击 KPI 卡片按合同提车与收款闭环进度筛选列表;计数为当前筛选结果内的合同条数。", "hasMarkdown": true, "color": "#0f766e", "images": [], @@ -90,7 +90,7 @@ "path": [] }, "aiPrompt": "主表按合同聚合;展开子表为提车收款单明细。", - "annotationText": "主表操作列外显「办理」;租车数等于已提车数时不显示办理。退款仅在子表操作。展开子表按提车批次展示车辆清单,子表操作外显查看、关联收款记录,合同审批驳回时可退款。", + "annotationText": "主表操作列外显「查看」「办理」:查看可浏览本合同全部已发布与未发布提车应收款;办理仅针对尚未操作的车辆。租车数等于已提车数时不显示办理。退款仅在子表操作。", "hasMarkdown": true, "color": "#32a06e", "images": [], @@ -107,8 +107,8 @@ "fingerprint": "vpr-collect-topbar", "path": [] }, - "aiPrompt": "办理提车收款单的返回与标题区。", - "annotationText": "返回列表;展示合同编码、项目名称;有未保存修改时显示「未保存」徽章。", + "aiPrompt": "办理页顶栏,仅返回列表。", + "annotationText": "仅保留「返回列表」;与表单页一致。未保存修改时底栏显示「未提交」。", "hasMarkdown": true, "color": "#334155", "images": [], @@ -118,15 +118,15 @@ { "id": "vpr-collect-project", "index": 7, - "title": "项目信息", + "title": "合同信息", "pageId": "collect", "locator": { "selectors": ["[data-annotation-id=\"vpr-collect-project\"]"], "fingerprint": "vpr-collect-project", "path": [] }, - "aiPrompt": "合同与项目只读信息卡片。", - "annotationText": "从办理上下文带出合同编码、客户、付款方式/周期、业务部门等;默认展开,可收起。", + "aiPrompt": "合同只读信息卡片,字段与租赁合同模块关联。", + "annotationText": "参照车辆资产详情页 hero:客户名称主标题,合同编码与项目名称;右侧签约公司、业务部门·负责人、合同类型;下方 stats 展示付款方式、周期、氢费等。", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -136,15 +136,15 @@ { "id": "vpr-collect-form", "index": 8, - "title": "提车日期与计费规则", + "title": "提车应收款表单", "pageId": "collect", "locator": { "selectors": ["[data-annotation-id=\"vpr-collect-form\"]"], "fingerprint": "vpr-collect-form", "path": [] }, - "aiPrompt": "提车日期、计费规则说明与应收付款节点。", - "annotationText": "提车日期必填,变更后重算各车应收;展示提车前 2 日内应付与当月 25 日应付节点摘要。", + "aiPrompt": "交付信息、计费规则与租赁订单明细表。", + "annotationText": "交付信息提示「根据交付时间,自动计算提车应收款金额」;明细表含租赁车辆数、未交车辆数及租金/保证金/服务项/应收总额列。", "hasMarkdown": true, "color": "#2563eb", "images": [], @@ -161,8 +161,8 @@ "fingerprint": "vpr-collect-kpi", "path": [] }, - "aiPrompt": "应收款总额、提车前应付、应开票总额。", - "annotationText": "基于已勾选车辆汇总;前两项卡片可点击查看明细 Popover。", + "aiPrompt": "已选车辆数、应收/租金/保证金/服务项总额。", + "annotationText": "五列 vm-detail-stats:已选车辆数、应收总额、租金总额、保证金总额、服务项总额;填写交车数与交付时间后联动更新。", "hasMarkdown": true, "color": "#0f766e", "images": [], @@ -179,8 +179,8 @@ "fingerprint": "vpr-collect-table", "path": [] }, - "aiPrompt": "勾选车辆、应收/实收金额与氢费预付款。", - "annotationText": "点击行切换勾选;已完成车辆不可再选。支持全选/取消全选;实收由收款记录导入反写。", + "aiPrompt": "租赁车辆数、未交车辆数、交车数及租金/保证金/服务项/应收总额。", + "annotationText": "按品牌型号汇总;车牌号与列表子表规则一致;未交车辆数可点击填入;金额列按交付时间与本次交车数自动拆分。", "hasMarkdown": true, "color": "#32a06e", "images": [], @@ -208,17 +208,17 @@ ] }, "markdownMap": { - "vpr-filter": "# 筛选条件\n\n合同编码、项目名称、客户名称、业务部门、业务负责人等。\n\n| 操作 | 行为 |\n|---|---|\n| 查询 | 应用筛选并重算 KPI |\n| 重置 | 清空条件 |\n| 更多筛选 | 展开其余筛选项 |\n\n交互对齐租赁合同列表页。", - "vpr-kpi": "# 提车收款单 KPI\n\n全部 / 待审批 / 审批中 / 审批通过 / 已驳回。\n\n点击卡片筛选子表提车收款单明细;计数基于当前筛选结果内的条数。", + "vpr-filter": "# 筛选条件\n\n| 字段 | 说明 |\n|---|---|\n| 合同编码 | 可输入模糊搜索的下拉选择 |\n| 项目名称 | 可输入模糊搜索的下拉选择 |\n| 客户名称 | 可输入模糊搜索的下拉选择 |\n| 车牌号 | 首行第 4 项;可输入模糊搜索,匹配租赁订单或已提车明细中的车牌 |\n| 业务部门 | 「更多筛选」中展示 |\n| 业务负责人 | 「更多筛选」中展示 |\n\n| 操作 | 行为 |\n|---|---|\n| 查询 | 应用筛选并重算 KPI |\n| 重置 | 清空条件 |\n| 更多筛选 | 展开业务部门、业务负责人 |\n\n交互对齐租赁合同列表页。", + "vpr-kpi": "# 提车应收款 KPI\n\n| 卡片 | 说明 |\n|---|---|\n| 全部 | 显示全部租赁合同对应的提车应收款信息 |\n| 未提车 | 没有任何车辆完成「提车应收款 + 收款记录关联」闭环 |\n| 部分提车 | 仅部分车辆完成闭环 |\n| 已完成 | 全部车辆均完成闭环 |\n| 已退款 | 合同审批终止且已完成退款与付款记录关联 |\n\n点击卡片筛选主表合同;计数基于当前筛选结果内的合同条数。", "vpr-col-pickup": "# 收款情况\n\n展示 **租车数** 与 **已提车**,交互对齐租赁合同列表。\n\n| 操作 | 行为 |\n|---|---|\n| 点击 **租车数** | Popover 展示品牌、型号及对应车辆数汇总表 |\n| 点击 **已提车** | 展开/收起本合同提车应收款子表(已提车 ≥ 0 均可点击) |\n\n## 提车应收款生成逻辑\n\n### A. 自动生成\n\n1. 租赁合同 **提交审批** 时立即生成主表任务。\n2. 合同标注 **交付时间** 时,在交付日 **前 2 天** 自动生成应收数据。\n\n### B. 手动办理\n\n未约定交付时间时,点击操作列 **办理**,勾选车辆并设置交付信息。\n\n## 计算规则\n\n以 **车辆交付时间** 为依据;当月 ≤15 日与 >15 日应付节点不同。详见目录「收款情况与生成规则」。", "vpr-toolbar": "# 列表工具栏\n\n| 按钮 | 说明 |\n|---|---|\n| 导出 | 导出当前筛选结果 |\n\n总条数由底部分页展示,不在工具栏重复计数。", - "vpr-table": "# 主从嵌套列表\n\n**主表**:按合同聚合,展示收款情况、应收/实收金额等;操作列外显 **办理**(租车数 = 已提车数时不显示)。\n\n**子表**:按 **提车批次 + 品牌型号分组** 展示。\n\n- **序号**:一个序号对应一次提车办理批次\n- **同一批次多辆车**:交付时间、交付地点、数量、合计应收/实收与操作列按批次合并\n- **品牌型号**:同批次内相同品牌型号合并为一行,并在该单元格内列出全部车牌号;多个品牌型号各占一行\n- **子表操作**(外显):查看、关联收款记录;合同 **审批驳回** 时显示退款\n\n**数据来源**:租赁合同提交审核时同步生成主记录;办理提交后追加子表;实收由收款记录导入反写。", - "vpr-collect-topbar": "# 办理页顶栏\n\n- **返回**:回到列表(有未保存修改时二次确认)\n- **标题**:办理提车收款单\n- **副标题**:合同编码 · 项目名称\n- **未保存**:表单有改动且未保存时显示徽章", - "vpr-collect-project": "# 项目信息\n\n只读卡片,默认展开:\n\n提车收款单编码、合同编码/类型、项目名称、客户名称、付款方式与周期、合同起止时间、业务部门与负责人。", - "vpr-collect-form": "# 提车日期与计费\n\n- **提车日期**(必填):变更后重算各车应收与 KPI\n- **计费规则**:按合同付款周期自动生成说明文案\n- **应收付款节点**:展示提车前 2 日内应付、当月 25 日应付(如有)\n\n实收金额由「收款记录」导入后反写,办理页只录应收。", - "vpr-collect-kpi": "# 办理页 KPI\n\n| 指标 | 说明 |\n|---|---|\n| 应收款总额 | 已选车辆应收合计;可点击查看明细 |\n| 提车前应付 | 提车前须到账金额;可点击查看明细 |\n| 应开票总额 | 按实收租金与服务费计算 |", - "vpr-collect-table": "# 提车车辆明细\n\n- 勾选列:点击行或复选框切换;已完成车辆标记「已完成」且不可选\n- 工具栏:全选/取消全选;未选时警告提示\n- 列:车牌、应收租金/保证金/服务费、实收、氢费应收等\n- **氢费预付款**:合同氢费支付方式相关只读/录入区\n\n金额展示使用等宽数字与千分位格式。", - "vpr-collect-footer": "# 底栏操作\n\n| 按钮 | 行为 |\n|---|---|\n| 取消 | 返回列表,未保存时确认 |\n| 保存 | 保存草稿,清除「未保存」状态 |\n| 提交审核 | 至少勾选 1 辆车;确认后生成子表单据并抄送财务 |\n\n底栏汇总展示提车前应付与已选车辆数。" + "vpr-table": "# 主从嵌套列表\n\n**主表**:按合同聚合,展示收款情况、应收/实收金额等。\n\n**主表操作列**:\n- **查看**:浏览本合同全部 **已发布** 与 **未发布** 提车应收款记录(只读)\n- **办理**:仅对 **尚未操作** 的未发布车辆发起办理;租车数 = 已提车数时不显示\n\n**项目信息列**:可点击进入办理的客户/合同/项目文案使用 **主题色** 链接样式;左侧展开图标同样使用主题色,提示可展开查看子表。\n\n**子表**:按 **提车批次 + 品牌型号分组** 展示。\n\n- **序号**:一个序号对应一次提车办理批次\n- **同一批次多辆车**:交付时间、交付地点、数量、合计应收/实收与操作列按批次合并\n- **品牌型号**:格式为「品牌·型号」;同批次内相同品牌型号合并单元格\n- **车牌号**:独立列;合同为「以实际交付为准」时先显示该文案,交车后显示实际车牌;「选择特定车辆」时显示合同车牌\n- **同一品牌型号多辆车**:品牌型号合并,车牌号各占一行\n- **子表操作**(外显):查看、关联收款记录;合同 **审批驳回** 时显示退款\n\n**数据来源**:租赁合同提交审核时同步生成主记录;办理提交后追加子表;实收由收款记录导入反写。", + "vpr-collect-topbar": "# 办理页顶栏\n\n- **返回列表**:回到列表(有未提交修改时二次确认)\n- 与租赁合同等表单页一致,顶栏仅保留返回按钮\n- 合同编码、项目名称见下方「合同信息」模块;有未保存修改时在底栏显示「未提交」", + "vpr-collect-project": "# 合同信息\n\n参照车辆资产详情页上方展示(`vm-detail-card` + `vm-detail-hero` + `vm-detail-stats`):\n\n- **Hero 左侧**:客户名称(主标题)、合同编码、项目名称\n- **Hero 右侧**:签约公司、业务部门·负责人、合同类型\n- **Stats 行**:签约公司、付款方式、付款周期、氢费支付方式;氢费为「预付款」时追加预付款金额", + "vpr-collect-form": "# 提车应收款\n\n## 交付信息\n\n两列对齐面板(地点 + 时间,均必填);提示文案:**根据交付时间,自动计算提车应收款金额**。\n\n## 租赁订单明细表\n\n| 列 | 说明 |\n|---|---|\n| 品牌型号 | 格式「品牌·型号」;同型号多车合并单元格 |\n| 车牌号 | 与列表子表一致:「选择特定车辆」显示合同车牌;「以实际交付为准」显示对应文案 |\n| 未交车辆数 | 尚未办理提车的数量;点击可填入本次交车数 |\n| 本次交车数 | 本次办理数量,不超过未交车辆数 |\n| 租金总额 | 按交付时间与本次交车数计算的租金合计 |\n| 保证金总额 | 按交付时间与本次交车数计算的保证金合计 |\n| 服务项总额 | 按交付时间与本次交车数计算的服务费合计 |\n| 应收总额 | 租金总额 + 保证金总额 + 服务项总额 |\n\n## 计算规则\n\n- 提车日 ≤15 日:提车前 2 日内付保证金+当月剩余租金及服务费;当月 25 日付下周期\n- 提车日 >15 日:提车前 2 日内付保证金+当月剩余+下周期", + "vpr-collect-kpi": "# 办理汇总\n\n五列 `vm-detail-stats` 统计条:\n\n| 指标 | 说明 |\n|---|---|\n| 已选车辆数 | 各品牌型号交车数合计 |\n| 应收总额 | 按交付时间自动计算并求和 |\n| 租金总额 | 提车前 + 当月 25 日节点租金合计 |\n| 保证金总额 | 提车前应付保证金 |\n| 服务项总额 | 提车前 + 当月 25 日节点服务费合计 |", + "vpr-collect-table": "# 租赁订单明细表\n\n按品牌/型号汇总;车牌号列与列表子表一致(特定车辆显示车牌、以实际交付为准显示对应文案,同型号多车合并品牌型号单元格);含未交车辆数、本次交车数及租金/保证金/服务项/应收总额。", + "vpr-collect-footer": "# 底栏操作\n\n| 按钮 | 行为 |\n|---|---|\n| 取消 | 返回列表,未提交时确认 |\n| 提交生成 | 至少 1 辆车且填写交付时间/地点;确认后生成子表并抄送财务 |" }, "assetMap": {}, "directory": { @@ -283,7 +283,7 @@ "type": "markdown", "id": "vpr-doc-collect-flow", "title": "办理流程", - "markdown": "## 办理流程\n\n1. 从列表点击「办理」进入\n2. 确认项目信息与提车日期\n3. 勾选本次提车车辆(默认预选未完成车辆)\n4. 核对 KPI 与明细表应收金额\n5. **保存** 草稿或 **提交审核**\n\n提交后生成子表单据,抄送财务;返回列表可看到新子表记录。" + "markdown": "## 办理流程\n\n1. 列表点击 **办理** 进入办理页\n2. 确认顶部 **合同信息**(参照车辆资产详情页样式)\n3. 查看 **办理汇总** KPI(已选车辆数、应收/租金/保证金/服务项总额)\n4. 在 **提车应收款** 卡片填写交付地点与时间,并设置各品牌型号本次交车数量\n5. 系统自动按提车应收款规则计算应收\n6. **提交生成** 后写入子表并抄送财务" }, { "type": "markdown", diff --git a/src/prototypes/vehicle-pickup-receivable/data/pickup-receivable-list-data.js b/src/prototypes/vehicle-pickup-receivable/data/pickup-receivable-list-data.js index 2b87306..5334406 100644 --- a/src/prototypes/vehicle-pickup-receivable/data/pickup-receivable-list-data.js +++ b/src/prototypes/vehicle-pickup-receivable/data/pickup-receivable-list-data.js @@ -10,7 +10,9 @@ import { formatDeliveryLocation, dedupePickupListByContractCode, pickSeedIdentityFields, + kpiKeyFromPickupProgress, } from '../pickup-receivable-bridge.js'; +import { formatMoneyYuan as formatMoneyYuanCore } from '../../../common/format-number.js'; /** * 模拟「租赁合同提交 / 交付日前 2 天」自动生成的提车应收款子单 @@ -194,13 +196,17 @@ export const PICKUP_RECEIVABLE_LIST_SEED = [ contractType: '正式合同', projectName: '嘉兴氢能示范项目', customerName: '嘉兴某某物流有限公司', + signingCompany: '嘉兴羚牛氢能科技有限公司', businessDept: '业务1部', businessPerson: '张经理', contractEffectiveDate: '2025-01-15', contractApprovalStatus: '审批通过', contractStatus: '合同进行中', paymentCycleMonths: 6, - paymentMethod: '预付', + paymentMethod: 'advance', + hydrogenBearer: '客户', + hydrogenPaymentMethod: 'prepay', + hydrogenPrepay: 5000, createdFromLeaseSubmit: true, leaseSubmitAt: '2025-01-08 11:20', deliveryDate: '2025-03-01', @@ -245,13 +251,18 @@ export const PICKUP_RECEIVABLE_LIST_SEED = [ contractType: '正式合同', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', + signingCompany: '上海羚牛氢能科技有限公司', businessDept: '业务3部', businessPerson: '王专员', contractEffectiveDate: '2025-02-10', contractApprovalStatus: '审批驳回', contractStatus: '已结束', + pickupRefundCompleted: true, + refundPaymentLinked: true, paymentCycleMonths: 1, - paymentMethod: '后付', + paymentMethod: 'postpay', + hydrogenBearer: '客户', + hydrogenPaymentMethod: 'month', createdFromLeaseSubmit: true, leaseSubmitAt: '2025-02-11 09:30', allVehiclesReceivableCompleted: false, @@ -376,16 +387,33 @@ export const PICKUP_RECEIVABLE_LIST_SEED = [ ]; export const PICKUP_KPI_CARDS = [ - { key: 'all', title: '全部', desc: '当前筛选范围内全部提车应收款单据' }, - { key: 'generated', title: '已生成', desc: '办理提交后已生成、待财务跟进的提车应收款单据' }, - { key: 'pending', title: '待审批', desc: '已保存但未提交审批的提车应收款单据' }, - { key: 'inReview', title: '审批中', desc: '审批流程进行中的提车应收款单据' }, - { key: 'approved', title: '审批通过', desc: '已完成最终审批的提车应收款单据' }, - { key: 'rejected', title: '已驳回', desc: '审批被驳回、可重新编辑提交的提车应收款单据' }, + { + key: 'all', + title: '全部', + desc: '显示全部租赁合同对应的提车应收款信息', + }, + { + key: 'notPickedUp', + title: '未提车', + desc: '显示租赁合同中没有完成任何车辆提车应收款并关联收款记录闭环的数据', + }, + { + key: 'partialPickedUp', + title: '部分提车', + desc: '显示租赁合同中只完成部分车辆提车应收款并关联收款记录闭环的数据', + }, + { + key: 'completed', + title: '已完成', + desc: '显示租赁合同中全部车辆都已完成提车应收款并关联收款记录闭环的数据', + }, + { + key: 'refunded', + title: '已退款', + desc: '显示租赁合同已被审批终止,且点击退款并完成付款记录关联的数据', + }, ]; -import { formatMoneyYuan as formatMoneyYuanCore } from '../../../common/format-number.js'; - export function buildCollectCode(contractCode, seq) { const suffix = `TC${String(seq != null ? seq : '').padStart(4, '0')}`; return `${String(contractCode || '')}${suffix}`; @@ -455,6 +483,7 @@ export function buildFilterOptions(list) { const codes = []; const projects = []; const customers = []; + const plateNos = []; const depts = []; const persons = []; (list || []).forEach((r) => { @@ -463,50 +492,74 @@ export function buildFilterOptions(list) { if (r.customerName && !customers.includes(r.customerName)) customers.push(r.customerName); if (r.businessDept && !depts.includes(r.businessDept)) depts.push(r.businessDept); if (r.businessPerson && !persons.includes(r.businessPerson)) persons.push(r.businessPerson); + (r.leaseOrderVehicles || []).forEach((v) => { + var plate = String(v.plateNo || '').trim(); + if (plate && !plateNos.includes(plate)) plateNos.push(plate); + }); + (r.children || []).forEach((child) => { + (child.deliveryVehicles || []).forEach((v) => { + var childPlate = String(v.plateNo || '').trim(); + if (childPlate && !plateNos.includes(childPlate)) plateNos.push(childPlate); + }); + }); }); + plateNos.sort(); return { contractCode: codes.map((v) => ({ value: v, label: v })), projectName: projects.map((v) => ({ value: v, label: v })), customerName: customers.map((v) => ({ value: v, label: v })), + plateNo: plateNos.map((v) => ({ value: v, label: v })), businessDept: depts.map((v) => ({ value: v, label: v })), businessPerson: persons.map((v) => ({ value: v, label: v })), }; } +function recordMatchesPlateNo(record, plateNo) { + var target = String(plateNo || '').trim(); + if (!target) return true; + var matched = (record.leaseOrderVehicles || []).some(function (v) { + return String(v.plateNo || '').trim() === target; + }); + if (matched) return true; + return (record.children || []).some(function (child) { + return (child.deliveryVehicles || []).some(function (v) { + return String(v.plateNo || '').trim() === target; + }); + }); +} + export function filterMainList(list, filters) { let rows = (list || []).filter(isValidPickupMainRecord); if (filters.contractCode) rows = rows.filter((r) => r.contractCode === filters.contractCode); if (filters.projectName) rows = rows.filter((r) => r.projectName === filters.projectName); if (filters.customerName) rows = rows.filter((r) => r.customerName === filters.customerName); + if (filters.plateNo) rows = rows.filter((r) => recordMatchesPlateNo(r, filters.plateNo)); if (filters.businessDept) rows = rows.filter((r) => r.businessDept === filters.businessDept); if (filters.businessPerson) rows = rows.filter((r) => r.businessPerson === filters.businessPerson); return rows; } -export function countKpiFromList(list, kpiTab) { - const counts = { all: 0, generated: 0, pending: 0, inReview: 0, approved: 0, rejected: 0 }; - (list || []).forEach((parent) => { - (parent.children || []).forEach((child) => { - counts.all += 1; - const key = kpiKeyFromAuditStatus(child.auditStatus); - if (key) counts[key] += 1; - }); +export function countKpiFromList(list) { + const counts = { + all: 0, + notPickedUp: 0, + partialPickedUp: 0, + completed: 0, + refunded: 0, + }; + (list || []).forEach(function (parent) { + counts.all += 1; + const key = kpiKeyFromPickupProgress(parent); + if (key && counts[key] != null) counts[key] += 1; }); return counts; } export function filterByKpiTab(list, kpiTab) { if (!kpiTab || kpiTab === 'all') return list; - return (list || []) - .map((parent) => { - const children = (parent.children || []).filter((child) => { - const key = kpiKeyFromAuditStatus(child.auditStatus); - return key === kpiTab; - }); - if (!children.length) return null; - return { ...parent, children }; - }) - .filter(Boolean); + return (list || []).filter(function (parent) { + return kpiKeyFromPickupProgress(parent) === kpiTab; + }); } function mergeSeedWithStored(seed, stored) { diff --git a/src/prototypes/vehicle-pickup-receivable/pickup-receivable-bridge.js b/src/prototypes/vehicle-pickup-receivable/pickup-receivable-bridge.js index 490c9ff..04d5b5e 100644 --- a/src/prototypes/vehicle-pickup-receivable/pickup-receivable-bridge.js +++ b/src/prototypes/vehicle-pickup-receivable/pickup-receivable-bridge.js @@ -8,6 +8,11 @@ import { buildBatchPickupScheduleSummary, describePickupRule, } from './pickup-receivable-calc.js'; +import { + formatHydrogenPaymentLabel, + formatPaymentMethodLabel, + formatPaymentPeriodLabel, +} from '../lease-contract-management/lease-contract-list-data.js'; export { buildVehiclePickupSchedule, @@ -85,6 +90,10 @@ export function pickSeedIdentityFields(seedRow) { contractStatus: seedRow.contractStatus, paymentCycleMonths: seedRow.paymentCycleMonths, paymentMethod: seedRow.paymentMethod, + signingCompany: seedRow.signingCompany, + hydrogenBearer: seedRow.hydrogenBearer, + hydrogenPaymentMethod: seedRow.hydrogenPaymentMethod, + hydrogenPrepay: seedRow.hydrogenPrepay, deliveryDate: seedRow.deliveryDate, deliveryDateTbd: seedRow.deliveryDateTbd, deliveryRegion: seedRow.deliveryRegion, @@ -327,6 +336,61 @@ export function countPickedUpVehicles(record) { return collectPickedVehicleKeys(record.children).size; } +/** 子单是否已完成收款闭环(实收 ≥ 应收) */ +export function isBatchPaymentClosed(child) { + var status = String(child && child.auditStatus || ''); + if (status === '已驳回' || status === '审批驳回') return false; + var received = parseFloat( + child && child.financeReceived != null ? child.financeReceived : child && child.actualTotal, + ) || 0; + var receivable = parseFloat(child && child.receivableTotal) || 0; + if (receivable <= 0) return false; + return received + 0.009 >= receivable; +} + +/** 已完成提车应收款并关联收款记录闭环的车辆 */ +export function collectClosedLoopVehicleKeys(children) { + var keys = new Set(); + (children || []).forEach(function (child) { + if (!isBatchPaymentClosed(child)) return; + (child.deliveryVehicles || []).forEach(function (v) { + keys.add(vehicleMatchKey(v)); + }); + }); + return keys; +} + +export function countClosedLoopVehicles(record) { + return collectClosedLoopVehicleKeys(record && record.children).size; +} + +export function isContractApprovalTerminated(record) { + var approval = String(record && record.contractApprovalStatus || record && record.leaseApprovalStatus || '').trim(); + var status = String(record && record.contractStatus || '').trim(); + return approval === '审批驳回' + || approval === '已驳回' + || approval === '审批终止' + || status === '已终止' + || status === '已结束'; +} + +export function isPickupRefundCompleted(record) { + return Boolean(record && (record.pickupRefundCompleted || record.refundPaymentLinked)); +} + +/** 列表 KPI:按合同提车与收款闭环进度分类 */ +export function kpiKeyFromPickupProgress(record) { + if (isContractApprovalTerminated(record) && isPickupRefundCompleted(record)) { + return 'refunded'; + } + var total = record.contractVehicleCount || (record.leaseOrderVehicles || []).length; + if (!total) return 'notPickedUp'; + var closed = countClosedLoopVehicles(record); + if (closed <= 0) return 'notPickedUp'; + if (closed >= total) return 'completed'; + return 'partialPickedUp'; +} + export function calcReceivedTotal(children) { return (children || []).reduce(function (sum, child) { var status = String(child.auditStatus || ''); @@ -727,6 +791,363 @@ export function toCollectPageVehicles(record, pickupDate) { }); } +export function buildVehicleModelKey(vehicle) { + if (!vehicle) return ''; + return [String(vehicle.brand || '').trim(), String(vehicle.model || '').trim()] + .filter(Boolean) + .join(' '); +} + +export var PLATE_ACTUAL_DELIVERY_LABEL = '以实际交付为准'; + +export function isLeaseSpecificVehicle(leaseVehicle) { + if (!leaseVehicle) return false; + if (leaseVehicle.plateMode === 'specific') return true; + if (leaseVehicle.plateMode === 'actual') return false; + var leasePlate = String(leaseVehicle.plateNo || '').trim(); + return Boolean(leasePlate && leasePlate !== PLATE_ACTUAL_DELIVERY_LABEL && leasePlate !== '-'); +} + +/** 办理页表格:按租赁合同规则解析车牌展示文案 */ +export function resolveCollectPlateLabel(leaseVehicle) { + if (!leaseVehicle) return '—'; + if (isLeaseSpecificVehicle(leaseVehicle)) { + var contractPlate = String(leaseVehicle.plateNo || '').trim(); + return contractPlate || '—'; + } + return PLATE_ACTUAL_DELIVERY_LABEL; +} + +export function buildCollectOrderTableRows(orderLines) { + var rows = []; + (orderLines || []).forEach(function (line) { + var displayVehicles = (line.leaseVehicles && line.leaseVehicles.length) + ? line.leaseVehicles + : (line.vehicles && line.vehicles.length) + ? line.vehicles + : [{ seq: 0, brand: line.brand, model: line.model, plateNo: '' }]; + var rowSpan = displayVehicles.length; + displayVehicles.forEach(function (vehicle, index) { + rows.push({ + line: line, + vehicle: vehicle, + rowKey: line.lineKey + '::' + (vehicle.seq != null ? vehicle.seq : index), + isFirstInModelGroup: index === 0, + modelGroupRowSpan: rowSpan, + }); + }); + }); + return rows; +} + +export function buildLeaseOrderLinesForCollect(record) { + var enriched = enrichPickupRecord(Object.assign({}, record)); + var pending = getPendingPickupVehicles(enriched); + var totalCountMap = {}; + var leaseVehiclesByKey = {}; + (enriched.leaseOrderVehicles || []).forEach(function (vehicle, index) { + var totalKey = buildVehicleModelKey(vehicle) || '__line-' + index; + totalCountMap[totalKey] = (totalCountMap[totalKey] || 0) + 1; + if (!leaseVehiclesByKey[totalKey]) leaseVehiclesByKey[totalKey] = []; + leaseVehiclesByKey[totalKey].push(vehicle); + }); + var groupMap = {}; + var order = []; + pending.forEach(function (vehicle, index) { + var key = buildVehicleModelKey(vehicle) || '__line-' + index; + if (!groupMap[key]) { + groupMap[key] = { + lineKey: key, + brand: vehicle.brand || '', + model: vehicle.model || '', + monthRent: vehicle.monthRent || 0, + deposit: vehicle.deposit || 0, + serviceFeeTotal: vehicle.serviceFeeTotal || 0, + vehicles: [], + leaseVehicles: leaseVehiclesByKey[key] || [], + leasedCount: totalCountMap[key] || 0, + availableCount: 0, + }; + order.push(key); + } + groupMap[key].vehicles.push(vehicle); + groupMap[key].availableCount += 1; + }); + return order.map(function (key) { + var line = groupMap[key]; + if (!line.leasedCount) line.leasedCount = line.availableCount; + return line; + }); +} + +function normalizePaymentMethodCode(method) { + var text = String(method || '').trim(); + if (text === '预付' || text === '先付后用') return 'advance'; + if (text === '后付' || text === '先用后付') return 'postpay'; + return text; +} + +function normalizeHydrogenPaymentCode(method) { + var text = String(method || '').trim(); + if (text === '预付' || text === '预付款') return 'prepay'; + if (text === '月付款' || text === '按月结算') return 'month'; + if (text === '自行结算' || text === '自行解决') return 'self'; + return text; +} + +function isHydrogenPrepayMethod(method) { + var code = normalizeHydrogenPaymentCode(method); + return code === 'prepay'; +} + +/** 氢费支付方式展示(与租赁合同选项对齐) */ +export function resolveHydrogenPaymentLabel(record) { + var code = normalizeHydrogenPaymentCode(record && record.hydrogenPaymentMethod); + if (code) return formatHydrogenPaymentLabel(code); + var bearer = String((record && record.hydrogenBearer) || '').trim(); + if (bearer === '我方') return '我方承担'; + return '—'; +} + +/** 氢气预付款金额;仅氢费支付方式为「预付款」时有值 */ +export function resolveHydrogenPrepayAmount(record) { + if (!isHydrogenPrepayMethod(record && record.hydrogenPaymentMethod)) return null; + var raw = record.hydrogenPrepay != null ? record.hydrogenPrepay : record.hydrogenPrepayAmount; + if (raw == null || raw === '') return null; + var amount = parseFloat(raw); + return Number.isFinite(amount) ? amount : null; +} + +function applyLeaseContractFieldDefaults(record) { + var next = Object.assign({}, record); + if (!next.signingCompany) next.signingCompany = '嘉兴羚牛氢能科技有限公司'; + if (!next.hydrogenBearer) next.hydrogenBearer = '客户'; + next.paymentMethod = normalizePaymentMethodCode(next.paymentMethod || 'advance'); + next.hydrogenPaymentMethod = normalizeHydrogenPaymentCode( + next.hydrogenPaymentMethod || (next.hydrogenBearer === '客户' ? 'prepay' : ''), + ); + if (next.hydrogenPrepay == null && isHydrogenPrepayMethod(next.hydrogenPaymentMethod)) { + next.hydrogenPrepay = 5000; + } + return next; +} + +/** 列表「办理」页上下文:合同主信息 + 附件1 租赁订单可办明细 */ +export function buildCollectHandleContext(record) { + var enriched = applyLeaseContractFieldDefaults(enrichPickupRecord(Object.assign({}, record))); + var months = enriched.paymentCycleMonths || 1; + var paymentMethodCode = normalizePaymentMethodCode(enriched.paymentMethod); + var hydrogenMethodCode = normalizeHydrogenPaymentCode(enriched.hydrogenPaymentMethod); + return { + contractCode: enriched.contractCode, + contractType: enriched.contractType || '正式合同', + projectName: enriched.projectName, + customerName: enriched.customerName, + signingCompany: enriched.signingCompany || '', + paymentMethod: paymentMethodCode, + paymentMethodLabel: formatPaymentMethodLabel(paymentMethodCode), + paymentCycleMonths: months, + paymentCycle: formatPaymentPeriodLabel(months), + paymentCycleLabel: formatPaymentPeriodLabel(months), + hydrogenBearer: enriched.hydrogenBearer || '', + hydrogenPaymentMethod: hydrogenMethodCode, + hydrogenPaymentMethodLabel: formatHydrogenPaymentLabel(hydrogenMethodCode), + hydrogenPrepayAmount: resolveHydrogenPrepayAmount(enriched), + contractStart: enriched.contractEffectiveDate || '', + contractEnd: enriched.contractEndDate || '', + businessDept: enriched.businessDept || '', + businessPerson: enriched.businessPerson || '', + contractStatus: enriched.contractStatus || '', + contractApprovalStatus: enriched.contractApprovalStatus || '', + defaultDeliveryLocation: formatDeliveryLocation(enriched), + defaultPickupDate: enriched.lastPickupDate || enriched.deliveryDate || '', + leaseOrderLines: buildLeaseOrderLinesForCollect(enriched), + }; +} + +function vehicleScheduleParts(schedule) { + if (!schedule) return { rent: 0, deposit: 0, service: 0, total: 0 }; + var before = schedule.items && schedule.items[0] ? schedule.items[0] : {}; + var month25 = schedule.items && schedule.items[1] ? schedule.items[1] : {}; + var rent = (before.rent || 0) + (month25.rent || 0); + var service = (before.service || 0) + (month25.service || 0); + var deposit = before.deposit || 0; + return { + rent: rent, + deposit: deposit, + service: service, + total: schedule.totalReceivable || rent + deposit + service, + }; +} + +export function buildCollectLinePreview(line, quantity, pickupDate, paymentCycleMonths) { + var qty = Math.min(line.availableCount, Math.max(0, parseInt(quantity, 10) || 0)); + if (!qty || !pickupDate) { + return { + quantity: qty, + unitTotal: 0, + lineTotal: 0, + rentTotal: 0, + depositTotal: 0, + serviceTotal: 0, + schedule: null, + }; + } + var schedule = buildVehiclePickupSchedule({ + monthRent: line.monthRent, + monthServiceFee: line.serviceFeeTotal, + deposit: line.deposit, + pickupDate: pickupDate, + paymentCycleMonths: paymentCycleMonths, + }); + var parts = vehicleScheduleParts(schedule); + return { + quantity: qty, + unitTotal: parts.total, + lineTotal: parts.total * qty, + rentTotal: parts.rent * qty, + depositTotal: parts.deposit * qty, + serviceTotal: parts.service * qty, + schedule: schedule, + }; +} + +export function buildCollectSubmitPayload(handleContext, form) { + var months = handleContext.paymentCycleMonths || 1; + var pickupDate = form.deliveryDate; + var deliveryLocation = form.deliveryLocation; + var deliveryVehicles = []; + var calcRows = []; + + (handleContext.leaseOrderLines || []).forEach(function (line) { + var qty = Math.min( + line.availableCount, + Math.max(0, parseInt(form.lineQuantities[line.lineKey], 10) || 0), + ); + line.vehicles.slice(0, qty).forEach(function (vehicle) { + var schedule = buildVehiclePickupSchedule({ + monthRent: line.monthRent, + monthServiceFee: line.serviceFeeTotal, + deposit: line.deposit, + pickupDate: pickupDate, + paymentCycleMonths: months, + }); + var parts = vehicleScheduleParts(schedule); + var nextVehicle = Object.assign({}, vehicle, { + deliveryTime: pickupDate, + deliveryLocation: deliveryLocation, + receivableSchedule: schedule, + receivableTotal: parts.total, + receivableRent: parts.rent, + receivableDeposit: parts.deposit, + receivableService: parts.service, + receivedTotal: 0, + }); + deliveryVehicles.push(nextVehicle); + calcRows.push({ + selected: true, + receivableCompleted: false, + monthRent: line.monthRent, + serviceFeeTotal: line.serviceFeeTotal, + deposit: line.deposit, + receivableDeposit: line.deposit, + receivableService: line.serviceFeeTotal, + receivableSchedule: schedule, + }); + }); + }); + + var batchSchedule = buildBatchPickupScheduleSummary(calcRows, pickupDate, months); + var breakdown = breakdownFromBatchSummary(batchSchedule); + + return { + pickupDate: pickupDate, + deliveryLocation: deliveryLocation, + deliveryVehicles: deliveryVehicles, + receivableSchedule: batchSchedule, + receivableRent: breakdown.rent, + receivableDeposit: breakdown.deposit, + receivableService: breakdown.service, + receivableTotal: batchSchedule.totalReceivable, + actualTotal: 0, + receivedRent: 0, + receivedDeposit: 0, + receivedService: 0, + creator: '当前用户', + }; +} + +export function getPendingPickupVehicles(record) { + if (!record) return []; + var pickedKeys = collectPickedVehicleKeys(record.children); + return (record.leaseOrderVehicles || []).filter(function (vehicle) { + return !pickedKeys.has(vehicleMatchKey(vehicle)); + }); +} + +function buildPickupCollectCode(contractCode, seq) { + return String(contractCode || '') + 'TC' + String(seq != null ? seq : '').padStart(4, '0'); +} + +function summarizePublishedPickupRecord(child, contractCode) { + if (!child) return null; + var receivableTotal = parseFloat(child.receivableTotal); + if (Number.isNaN(receivableTotal)) { + receivableTotal = (child.deliveryVehicles || []).reduce(function (sum, vehicle) { + return sum + (parseFloat(vehicle.receivableTotal) || 0); + }, 0); + } + var receivedTotal = parseFloat( + child.financeReceived != null ? child.financeReceived : child.actualTotal, + ) || 0; + return { + seq: child.seq, + collectCode: buildPickupCollectCode(contractCode, child.seq), + auditStatus: child.auditStatus || '已生成', + publishStatus: '已发布', + pickupDate: child.pickupDate || '—', + deliveryLocation: child.deliveryLocation || '—', + vehicleCount: (child.deliveryVehicles || []).length || child.deliveryCount || 0, + receivableTotal: receivableTotal, + receivedTotal: receivedTotal, + chargeTime: child.chargeTime || '—', + creator: child.creator || '—', + }; +} + +/** 列表「查看」页上下文:已发布子单 + 未发布待办理车辆 */ +export function buildContractViewContext(record) { + var enriched = enrichPickupRecord(Object.assign({}, record)); + return { + mode: 'contract', + contractCode: enriched.contractCode, + contractType: enriched.contractType, + projectName: enriched.projectName, + customerName: enriched.customerName, + paymentMethod: enriched.paymentMethod, + paymentCycleMonths: enriched.paymentCycleMonths, + paymentCycle: (enriched.paymentCycleMonths || 1) + '个月', + contractStart: enriched.contractEffectiveDate, + contractEnd: enriched.contractEndDate || '', + businessDept: enriched.businessDept, + businessPerson: enriched.businessPerson, + contractVehicleCount: enriched.contractVehicleCount, + pickedUpVehicleCount: enriched.pickedUpVehicleCount, + publishedRecords: (enriched.children || []).map(function (child) { + return summarizePublishedPickupRecord(child, enriched.contractCode); + }).filter(Boolean), + pendingVehicles: getPendingPickupVehicles(enriched).map(function (vehicle, index) { + return { + seq: vehicle.seq != null ? vehicle.seq : index + 1, + brand: vehicle.brand, + model: vehicle.model, + plateNo: vehicle.plateNo || '—', + publishStatus: '未发布', + }; + }), + }; +} + export function applyPickupDateToVehicles(vehicles, pickupDate, paymentCycleMonths) { return (vehicles || []).map(function (row) { if (row.receivableCompleted) return row; diff --git a/src/prototypes/vehicle-pickup-receivable/styles/index.css b/src/prototypes/vehicle-pickup-receivable/styles/index.css index 351b1a2..a98fb04 100644 --- a/src/prototypes/vehicle-pickup-receivable/styles/index.css +++ b/src/prototypes/vehicle-pickup-receivable/styles/index.css @@ -27,18 +27,41 @@ line-height: 1.4; } -.vm-page.vpr-page .vpr-project-info-cell--clickable { +.vm-page.vpr-page .vpr-main-list-table .lc-project-info-merged-cell { + display: flex; + align-items: center; + gap: 8px; + width: 100%; + min-width: 0; +} + +.vm-page.vpr-page .vpr-main-list-table .lc-project-info-merged-cell .lc-project-info-cell { + flex: 1; + min-width: 0; +} + +.vm-page.vpr-page .vpr-main-list-table .lc-project-info-merged-cell .ant-table-row-expand-icon { + flex-shrink: 0; + margin: 0; cursor: pointer; + color: var(--ln-primary, #32a06e); + border-color: color-mix(in srgb, var(--ln-primary, #32a06e) 45%, transparent); + transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease; } -.vm-page.vpr-page .vpr-project-info-cell--clickable:hover .primary { - color: var(--vm-link, #1677ff); +.vm-page.vpr-page .vpr-main-list-table .lc-project-info-merged-cell .ant-table-row-expand-icon:hover { + color: var(--ln-primary-hover, #15803d); + border-color: var(--ln-primary-hover, #15803d); + background: color-mix(in srgb, var(--ln-primary, #32a06e) 8%, transparent); } -.vm-page.vpr-page .vpr-project-info-cell--clickable:focus-visible { - outline: 2px solid var(--vm-focus, #1677ff); +.vm-page.vpr-page .vpr-main-list-table .lc-project-info-merged-cell .ant-table-row-expand-icon:focus-visible { + outline: 2px solid var(--ln-primary, #32a06e); outline-offset: 2px; - border-radius: 4px; +} + +.vm-page.vpr-page .lc-project-info-cell__static { + min-width: 0; } .vm-page.vpr-page .vpr-delivery-btn { @@ -64,7 +87,7 @@ } .vm-page.vpr-page .vpr-pickup-native-table--vehicles { - min-width: 980px; + min-width: 1060px; } .vm-page.vpr-page .vpr-pickup-subtable__batch-cell { @@ -180,14 +203,22 @@ line-height: 1.4; } -.vm-page.vpr-page .vpr-pickup-subtable__model-group-plates { - font-size: 12px; - color: var(--ln-muted, #71717a); +.vm-page.vpr-page .vpr-pickup-subtable__model-group-cell { + vertical-align: middle; + background: var(--ln-surface-card, #fff); +} + +.vm-page.vpr-page .vpr-pickup-subtable__plate-cell { + vertical-align: middle; +} + +.vm-page.vpr-page .vpr-pickup-subtable__plate-no { + color: var(--ln-fg, #18181b); line-height: 1.4; word-break: break-all; } -.vm-page.vpr-page .vpr-pickup-subtable__model-group-plates.is-empty { +.vm-page.vpr-page .vpr-pickup-subtable__plate-no--pending { color: var(--ln-muted, #71717a); } @@ -213,28 +244,45 @@ border-bottom: 1px solid var(--ln-hairline, #e2e8f0); } -/* 主表一屏展示:scroll.x 与容器同宽,表头/表体共用 colgroup */ +/* 主表横向滚动:表头/表体同步(对齐 lc-list-table--nested,勿单独禁用 body overflow-x) */ .vm-page.vpr-page .vm-table-wrap { width: 100%; overflow: hidden; } .vm-page.vpr-page .vpr-main-list-table .ant-table-container { - overflow: hidden !important; -} - -.vm-page.vpr-page .vpr-main-list-table .ant-table-content { - overflow: hidden !important; + overflow: hidden; } .vm-page.vpr-page .vpr-main-list-table .ant-table-body { - overflow-y: auto !important; - overflow-x: hidden !important; + container-type: inline-size; + container-name: vpr-main-table-scroll; } -.vm-page.vpr-page .vpr-main-list-table .ant-table-sticky-scroll, -.vm-page.vpr-page .vpr-main-list-table .ant-table-sticky-scroll-bar { - display: none !important; +/* 纵向滚动条占位:防止表头/表体右侧冻结列错位 */ +.vm-page.vpr-page .vpr-main-list-table .ant-table-thead > tr > th.ant-table-cell-fix-end:not(.ant-table-cell-scrollbar)::before, +.vm-page.vpr-page .vpr-main-list-table .ant-table-tbody > tr > td.ant-table-cell-fix-end:not(.ant-table-cell-scrollbar)::before, +.vm-page.vpr-page .vpr-main-list-table .ant-table-thead > tr > th.ant-table-cell-fix-right:not(.ant-table-cell-scrollbar)::before, +.vm-page.vpr-page .vpr-main-list-table .ant-table-tbody > tr > td.ant-table-cell-fix-right:not(.ant-table-cell-scrollbar)::before { + content: ''; + position: absolute; + top: 0; + bottom: 0; + right: -17px; + width: 17px; + background: inherit; + pointer-events: none; +} + +/* 保留滚动条占位列,避免表头/表体 clientWidth 不一致导致横向错位(覆盖 lc-list-table--nested 的隐藏规则) */ +.vm-page.vpr-page .vpr-main-list-table .ant-table-cell-scrollbar { + width: 17px !important; + min-width: 17px !important; + max-width: 17px !important; + padding: 0 !important; + border: none !important; + visibility: visible !important; + background: var(--ln-surface, #fff); } .vm-page.vpr-page .vpr-main-list-table .ant-table-thead > tr > th, @@ -280,6 +328,105 @@ white-space: nowrap; } +.vm-page.vpr-page .vpr-main-action-cell { + flex-wrap: wrap; + justify-content: flex-start; + gap: 2px 4px; +} + +.vm-page.vpr-page .vpr-main-action-cell .vm-op-action { + flex: 0 1 auto; +} + +.vm-page.vpr-page .vpr-contract-view-page { + padding: 16px 20px 32px; + min-height: 100vh; + background: var(--ln-canvas-parchment, #f5f6f6); + box-sizing: border-box; +} + +.vm-page.vpr-page .vpr-contract-view-actions { + display: flex; + justify-content: flex-end; + max-width: 1280px; + margin: 0 auto 12px; +} + +.vm-page.vpr-page .vpr-contract-view-section { + margin-top: 16px; + padding: 16px; + border: 1px solid var(--ln-hairline, #e2e8f0); + border-radius: var(--ln-radius-md, 12px); + background: var(--ln-surface, #fff); +} + +.vm-page.vpr-page .vpr-contract-view-section__head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: 12px; +} + +.vm-page.vpr-page .vpr-contract-view-section__title { + margin: 0; + font-size: 15px; + font-weight: 600; + color: var(--ln-fg, #18181b); +} + +.vm-page.vpr-page .vpr-contract-view-section__count { + font-size: 12px; + color: var(--ln-muted, #71717a); +} + +.vm-page.vpr-page .vpr-contract-view-section__hint { + margin: 12px 0 0; + font-size: 13px; + line-height: 1.5; + color: var(--ln-muted, #71717a); +} + +.vm-page.vpr-page .vpr-contract-view-info-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px 20px; +} + +.vm-page.vpr-page .vpr-contract-view-info-item { + display: flex; + flex-direction: column; + gap: 4px; + min-width: 0; +} + +.vm-page.vpr-page .vpr-contract-view-info-item__label { + font-size: 12px; + color: var(--ln-muted, #71717a); +} + +.vm-page.vpr-page .vpr-contract-view-info-item__value { + font-size: 14px; + color: var(--ln-fg, #18181b); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.vm-page.vpr-page .vpr-contract-view-empty { + padding: 20px; + text-align: center; + font-size: 13px; + color: var(--ln-muted, #71717a); + background: var(--ln-canvas-soft, #f8fafc); + border-radius: var(--ln-radius-control, 8px); +} + +.vm-page.vpr-page .vpr-contract-view-table th, +.vm-page.vpr-page .vpr-contract-view-table td { + white-space: nowrap; +} + /* 金额列 */ .vm-page.vpr-page .vpr-money-col-th, .vm-page.vpr-page .vpr-money-col-td { @@ -307,16 +454,158 @@ } } -/* 办理页顶栏:返回 + 操作 */ +/* 办理页顶栏:仅返回列表 */ .vm-page.vpr-collect-page .vpr-collect-topbar { + max-width: 1280px; + margin-left: auto; + margin-right: auto; + margin-bottom: 12px; +} + +.vm-page.vpr-collect-page .vpr-collect-contract-card { + padding: 20px 24px; + margin-bottom: 0; +} + +.vm-page.vpr-collect-page .vpr-collect-contract-hero { + margin-bottom: 16px; + padding-bottom: 16px; +} + +.vm-page.vpr-collect-page .vpr-collect-contract-hero__aside-main { + margin: 0; + font-size: 0.875rem; + font-weight: 600; + color: var(--ln-ink, #18181b); + line-height: 1.45; +} + +.vm-page.vpr-collect-page .vpr-collect-contract-stats { + margin-bottom: 0; + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + +@media (max-width: 900px) { + .vm-page.vpr-collect-page .vpr-collect-contract-stats { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +.vm-page.vpr-collect-page .vpr-collect-summary-stats { + grid-template-columns: repeat(5, minmax(0, 1fr)); + margin-bottom: 0; + gap: 12px; +} + +.vm-page.vpr-collect-page .vpr-collect-kpi-stat__value { + font-size: 1rem; + font-weight: 700; + font-variant-numeric: tabular-nums; +} + +.vm-page.vpr-collect-page .vpr-collect-kpi-stat--active { + border-color: color-mix(in srgb, var(--ln-primary, #32a06e) 35%, var(--ln-hairline)); + background: color-mix(in srgb, var(--ln-primary, #32a06e) 4%, #fff); +} + +.vm-page.vpr-collect-page .vpr-collect-kpi-stat--active .vpr-collect-kpi-stat__value { + color: var(--ln-primary-focus, #27885a); +} + +@media (max-width: 1100px) { + .vm-page.vpr-collect-page .vpr-collect-summary-stats { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +@media (max-width: 720px) { + .vm-page.vpr-collect-page .vpr-collect-summary-stats { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-panel { + display: flex; + flex-direction: column; + gap: 12px; + padding: 14px 16px; + margin-bottom: 12px; + border: 1px solid var(--ln-hairline, #e2e8f0); + border-radius: var(--ln-radius-control, 8px); + background: var(--ln-surface-card, #fff); + box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04); +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-panel__head { display: flex; align-items: center; justify-content: space-between; - gap: 16px; - margin-bottom: 16px; + gap: 12px; flex-wrap: wrap; } +.vm-page.vpr-collect-page .vpr-collect-delivery-panel__title { + margin: 0; + font-size: 0.875rem; + font-weight: 600; + color: var(--ln-ink, #18181b); + line-height: 1.35; +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-panel__hint { + font-size: 0.75rem; + color: var(--ln-muted, #71717a); + line-height: 1.35; +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-panel__grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px 16px; +} + +@media (max-width: 768px) { + .vm-page.vpr-collect-page .vpr-collect-delivery-panel__grid { + grid-template-columns: 1fr; + } +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-field { + display: flex; + flex-direction: column; + gap: 8px; + min-width: 0; +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-field__label { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 0.8125rem; + font-weight: 500; + color: var(--ln-body, #3f3f46); + line-height: 1.35; +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-field__icon { + flex-shrink: 0; + color: var(--ln-primary-focus, #27885a); +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-field__control, +.vm-page.vpr-collect-page .vpr-collect-delivery-field__control.ant-picker { + width: 100%; + min-height: 36px; +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-field:focus-within .vpr-collect-delivery-field__label { + color: var(--ln-primary-focus, #27885a); +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-field--invalid .vpr-collect-delivery-field__label { + color: var(--ln-danger, #dc2626); +} + .vm-page.vpr-collect-page .vpr-collect-topbar__link { padding: 0; @@ -325,12 +614,115 @@ /* —— 办理页 —— */ .vm-page.vpr-collect-page { - padding: 16px 24px 96px; + --vpr-collect-footer-height: 68px; + padding: 16px 24px calc(var(--vpr-collect-footer-height) + 16px); min-height: 100vh; background: var(--ln-canvas-parchment, #f5f6f6); box-sizing: border-box; } +.vm-page.vpr-collect-page .vpr-collect-main { + display: flex; + flex-direction: column; + gap: 12px; + max-width: 1280px; + margin: 0 auto; +} + +.vm-page.vpr-collect-page .vpr-collect-panel { + background: var(--ln-surface-card, #fff); + border: 1px solid var(--ln-hairline, #e2e8f0); + border-radius: var(--ln-radius-card, 12px); + box-shadow: var(--ln-shadow-soft); + overflow: hidden; +} + +.vm-page.vpr-collect-page .vpr-collect-panel__head { + padding: 12px 16px; + border-bottom: 1px solid var(--ln-hairline, #e2e8f0); + background: color-mix(in srgb, var(--ln-primary, #32a06e) 4%, #fff); +} + +.vm-page.vpr-collect-page .vpr-collect-panel__title { + margin: 0; + font-size: 0.9375rem; + font-weight: 600; + color: var(--ln-ink, #18181b); + line-height: 1.35; +} + +.vm-page.vpr-collect-page .vpr-collect-info-grid--flat { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 0; +} + +.vm-page.vpr-collect-page .vpr-collect-field--flat { + padding: 12px 14px; + border-right: 1px solid var(--ln-hairline, #e2e8f0); + border-bottom: 1px solid var(--ln-hairline, #e2e8f0); + min-height: 0; + background: var(--ln-surface-card, #fff); +} + +.vm-page.vpr-collect-page .vpr-collect-info-grid--flat .vpr-collect-field--flat:nth-child(4n) { + border-right: none; +} + +.vm-page.vpr-collect-page .vpr-collect-field--flat .vpr-collect-field__label { + margin-bottom: 6px; + font-size: 0.75rem; + font-weight: 500; + color: var(--ln-muted, #71717a); + line-height: 1.2; +} + +.vm-page.vpr-collect-page .vpr-collect-field--flat .vpr-collect-field__value { + font-size: 0.875rem; + font-weight: 600; + line-height: 1.4; + color: var(--ln-ink, #18181b); +} + +.vm-page.vpr-collect-page .vpr-collect-topbar--shell { + max-width: 1280px; + margin: 0 auto 16px; + padding: 14px 16px; + background: var(--ln-surface-card, #fff); + border: 1px solid var(--ln-hairline); + border-radius: var(--ln-radius-card); + box-shadow: var(--ln-shadow-soft); +} + +.vm-page.vpr-collect-page .vpr-collect-topbar--shell.vpr-collect-topbar { + margin-bottom: 16px; +} + +.vm-page.vpr-collect-page .vpr-collect-topbar__chip { + display: inline-flex; + align-items: center; + padding: 0 8px; + height: 22px; + border-radius: 6px; + font-size: 0.75rem; + font-weight: 600; + color: var(--ln-primary-focus, #27885a); + background: color-mix(in srgb, var(--ln-primary, #32a06e) 10%, #fff); + border: 1px solid color-mix(in srgb, var(--ln-primary, #32a06e) 20%, transparent); +} + +.vm-page.vpr-collect-page .vpr-collect-topbar__meta-text { + color: var(--ln-muted); + font-size: 0.8125rem; +} + +@media (max-width: 900px) { + .vm-page.vpr-collect-page { + padding-left: 16px; + padding-right: 16px; + } +} + .vm-page.vpr-collect-page .vpr-collect-topbar__left { display: flex; align-items: flex-start; @@ -376,23 +768,199 @@ } .vm-page.vpr-collect-page .vpr-collect-card { - margin-bottom: 16px; + margin-bottom: 0; border: 1px solid var(--ln-hairline); border-radius: var(--ln-radius-card); box-shadow: var(--ln-shadow-soft); + overflow: hidden; } .vm-page.vpr-collect-page .vpr-collect-card .ant-card-head { min-height: 48px; border-bottom: 1px solid var(--ln-hairline); + background: color-mix(in srgb, var(--ln-primary, #32a06e) 3%, #fff); } .vm-page.vpr-collect-page .vpr-collect-card .ant-card-head-title { + display: inline-flex; + align-items: center; + gap: 8px; font-size: 0.9375rem; font-weight: 600; color: var(--ln-ink); } +.vm-page.vpr-collect-page .vpr-collect-card .ant-card-head-title::before { + content: ''; + flex-shrink: 0; + width: 3px; + height: 14px; + border-radius: 999px; + background: var(--ln-primary, #32a06e); +} + +.vm-page.vpr-collect-page .vpr-collect-card--primary { + border-color: color-mix(in srgb, var(--ln-primary, #32a06e) 24%, var(--ln-hairline)); +} + +.vm-page.vpr-collect-page .vpr-collect-card--primary .ant-card-head { + background: color-mix(in srgb, var(--ln-primary, #32a06e) 5%, #fff); + border-bottom-color: color-mix(in srgb, var(--ln-primary, #32a06e) 14%, var(--ln-hairline)); +} + +.vm-page.vpr-collect-page .vpr-collect-card--primary .ant-card-body { + padding: 16px; + background: var(--ln-canvas-soft, #f8fafc); +} + +.vm-page.vpr-collect-page .vpr-collect-info-grid--contract { + gap: 12px; +} + +.vm-page.vpr-collect-page .vpr-collect-info-grid--contract .vpr-collect-field { + display: flex; + flex-direction: column; + justify-content: flex-start; + min-height: 72px; + padding: 12px 14px; + background: var(--ln-surface, #fff); + border: 1px solid var(--ln-hairline, #e5e7eb); + border-radius: var(--ln-radius-control, 8px); + box-shadow: none; + transition: border-color 0.2s ease; +} + +.vm-page.vpr-collect-page .vpr-collect-info-grid--contract .vpr-collect-field__label { + margin-bottom: 10px; + font-size: 12px; + font-weight: 400; + color: var(--ln-muted, #9ca3af); + line-height: 1.2; +} + +.vm-page.vpr-collect-page .vpr-collect-info-grid--contract .vpr-collect-field__value { + font-size: 14px; + font-weight: 600; + line-height: 1.45; + color: var(--ln-ink, #1f2937); + min-height: auto; +} + +.vm-page.vpr-collect-page .vpr-collect-info-grid--contract .vpr-collect-field__value--mono { + font-size: 14px; + font-weight: 600; + letter-spacing: 0; +} + +.vm-page.vpr-collect-page .vpr-collect-section-lead { + margin: 0 0 16px; + font-size: 13px; + line-height: 1.5; + color: var(--ln-muted, #71717a); +} + +.vm-page.vpr-collect-page .vpr-collect-rule-text { + margin: 12px 0 16px; + padding: 10px 12px; + border-radius: var(--ln-radius-control, 8px); + background: color-mix(in srgb, var(--ln-primary, #32a06e) 6%, #fff); + border: 1px solid color-mix(in srgb, var(--ln-primary, #32a06e) 14%, transparent); + font-size: 13px; + line-height: 1.55; + color: var(--ln-body, #334155); +} + +.vm-page.vpr-collect-page .vpr-collect-card--order .ant-card-head { + border-bottom: 1px solid var(--ln-hairline); +} + +.vm-page.vpr-collect-page .vpr-collect-card__extra { + font-size: 0.8125rem; + font-weight: 500; + color: var(--ln-muted); +} + +.vm-page.vpr-collect-page .vpr-collect-order-section { + display: flex; + flex-direction: column; + gap: 12px; +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-row { + display: grid; + grid-template-columns: minmax(0, 1.35fr) minmax(220px, 0.65fr); + gap: 16px; + padding: 14px 16px; + border: 1px solid var(--ln-hairline); + border-radius: var(--ln-radius-control, 8px); + background: var(--ln-canvas-soft, #f8fafc); + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.vm-page.vpr-collect-page .vpr-collect-delivery-row:focus-within { + border-color: color-mix(in srgb, var(--ln-primary, #32a06e) 35%, var(--ln-hairline)); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--ln-primary, #32a06e) 12%, transparent); +} + +@media (max-width: 768px) { + .vm-page.vpr-collect-page .vpr-collect-delivery-row { + grid-template-columns: minmax(0, 1fr); + } +} + +.vm-page.vpr-collect-page .vpr-collect-order-callout { + margin: 0; +} + +.vm-page.vpr-collect-page .vpr-collect-table-toolbar__badge { + display: inline-flex; + align-items: center; + height: 24px; + padding: 0 10px; + border-radius: 999px; + font-size: 0.75rem; + font-weight: 600; + color: var(--ln-primary-focus, #27885a); + background: color-mix(in srgb, var(--ln-primary, #32a06e) 10%, #fff); + border: 1px solid color-mix(in srgb, var(--ln-primary, #32a06e) 18%, transparent); +} + +.vm-page.vpr-collect-page .vpr-collect-table-toolbar { + margin-bottom: 0; +} + +.vm-page.vpr-collect-page .vpr-collect-card--order .vpr-collect-table-wrap { + margin-bottom: 0; +} + +.vm-page.vpr-collect-page .vpr-collect-form-item__label { + display: block; + margin-bottom: 6px; + font-size: 13px; + font-weight: 500; + color: var(--ln-body, #334155); +} + +.vm-page.vpr-collect-page .vpr-collect-date-picker, +.vm-page.vpr-collect-page .vpr-collect-qty-input { + width: 100%; +} + +.vm-page.vpr-collect-page .vpr-collect-kpi-card--primary { + border-color: color-mix(in srgb, var(--ln-primary, #32a06e) 28%, var(--ln-hairline)); + background: color-mix(in srgb, var(--ln-primary, #32a06e) 4%, #fff); +} + +.vm-page.vpr-collect-page .vpr-collect-kpi-card--primary .vpr-collect-kpi-card__value { + color: var(--ln-primary, #32a06e); +} + +@media (max-width: 768px) { + .vm-page.vpr-collect-page .vpr-collect-kpi-row { + grid-template-columns: minmax(0, 1fr); + } +} + .vm-page.vpr-collect-page .vpr-collect-card-toggle.ant-btn { padding: 0; height: auto; @@ -401,7 +969,7 @@ .vm-page.vpr-collect-page .vpr-collect-info-grid { display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px 24px; } @@ -417,9 +985,24 @@ } } +.vm-page.vpr-collect-page .vpr-collect-field { + min-width: 0; +} + +.vm-page.vpr-collect-page .vpr-collect-field--span-2 { + grid-column: span 2; +} + +@media (max-width: 640px) { + .vm-page.vpr-collect-page .vpr-collect-field--span-2 { + grid-column: span 1; + } +} + .vm-page.vpr-collect-page .vpr-collect-field__label { - margin-bottom: 6px; - font-size: 0.8125rem; + margin-bottom: 4px; + font-size: 0.75rem; + font-weight: 500; color: var(--ln-muted); } @@ -428,19 +1011,20 @@ font-size: 0.875rem; line-height: 1.5; min-height: 22px; + word-break: break-word; +} + +.vm-page.vpr-collect-page .vpr-collect-field__value--mono { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace; + font-size: 0.8125rem; + letter-spacing: 0.01em; } .vm-page.vpr-collect-page .vpr-collect-kpi-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; - margin-bottom: 16px; -} - -@media (max-width: 768px) { - .vm-page.vpr-collect-page .vpr-collect-kpi-row { - grid-template-columns: minmax(0, 1fr); - } + margin-bottom: 0; } .vm-page.vpr-collect-page .vpr-collect-kpi-card { @@ -448,7 +1032,21 @@ border: 1px solid var(--ln-hairline); border-radius: var(--ln-radius-card); padding: 14px 16px; - transition: border-color 0.2s, box-shadow 0.2s; + min-height: 88px; + display: flex; + flex-direction: column; + justify-content: center; + box-shadow: var(--ln-shadow-soft); + transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease; +} + +.vm-page.vpr-collect-page .vpr-collect-kpi-card--active { + border-color: color-mix(in srgb, var(--ln-primary, #32a06e) 28%, var(--ln-hairline)); + box-shadow: 0 2px 8px color-mix(in srgb, var(--ln-primary, #32a06e) 10%, transparent); +} + +.vm-page.vpr-collect-page .vpr-collect-kpi-card__value { + transition: color 0.2s ease; } .vm-page.vpr-collect-page .vpr-collect-kpi-card--clickable { @@ -481,7 +1079,7 @@ } .vm-page.vpr-collect-page .vpr-collect-batch-panel { - margin-bottom: 16px; + margin-bottom: 0; padding: 12px 16px; background: color-mix(in srgb, var(--ln-primary) 6%, #fff); border: 1px solid color-mix(in srgb, var(--ln-primary) 18%, var(--ln-hairline)); @@ -599,10 +1197,10 @@ .vm-page.vpr-collect-page .vpr-collect-table { width: 100%; - min-width: 1600px; + min-width: 640px; border-collapse: collapse; font-size: 0.8125rem; - table-layout: fixed; + table-layout: auto; } .vm-page.vpr-collect-page .vpr-collect-table thead th { @@ -632,6 +1230,7 @@ .vm-page.vpr-collect-page .vpr-collect-row--selected { background: color-mix(in srgb, var(--ln-primary) 5%, #fff); + box-shadow: inset 3px 0 0 var(--ln-primary, #32a06e); } .vm-page.vpr-collect-page .vpr-collect-row--idle { @@ -655,6 +1254,19 @@ background: color-mix(in srgb, var(--ln-primary) 3%, #fff); } +.vm-page.vpr-collect-page .vpr-collect-td--action { + cursor: pointer; + color: var(--ln-primary-focus, #27885a); + font-weight: 600; + transition: background-color 0.15s ease, color 0.15s ease; +} + +.vm-page.vpr-collect-page .vpr-collect-td--action:hover { + background: color-mix(in srgb, var(--ln-primary, #32a06e) 8%, #fff); + text-decoration: underline; + text-underline-offset: 2px; +} + .vm-page.vpr-collect-page .vpr-collect-row--done { cursor: default; } @@ -664,6 +1276,28 @@ font-variant-numeric: tabular-nums; } +.vm-page.vpr-collect-page .vpr-collect-td--model { + font-weight: 500; + color: var(--ln-ink, #18181b); + max-width: 280px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.vm-page.vpr-collect-page .vpr-collect-th--plate { + width: 120px; + min-width: 120px; +} + +.vm-page.vpr-collect-page .vpr-collect-td--model-cell { + vertical-align: middle; +} + +.vm-page.vpr-collect-page .vpr-collect-table .vpr-pickup-subtable__plate-cell { + vertical-align: middle; +} + .vm-page.vpr-collect-page .vpr-collect-row-badge { display: inline-flex; align-items: center; @@ -711,13 +1345,48 @@ justify-content: space-between; gap: 16px; flex-wrap: wrap; + min-height: var(--vpr-collect-footer-height, 68px); padding: 12px 24px; - background: color-mix(in srgb, var(--ln-surface-card) 92%, transparent); + background: color-mix(in srgb, var(--ln-surface-card) 94%, transparent); backdrop-filter: blur(8px); border-top: 1px solid var(--ln-hairline); box-shadow: 0 -4px 16px rgba(24, 24, 27, 0.06); } +.vm-page.vpr-collect-page .vpr-collect-footer__left { + display: flex; + align-items: center; + gap: 10px; + min-width: 0; + flex-wrap: wrap; +} + +.vm-page.vpr-collect-page .vpr-collect-footer__step { + display: inline-flex; + align-items: center; + gap: 8px; +} + +.vm-page.vpr-collect-page .vpr-collect-footer__step-dot { + width: 8px; + height: 8px; + border-radius: 999px; + background: var(--ln-hairline, #e2e8f0); + border: 1px solid color-mix(in srgb, var(--ln-muted, #71717a) 30%, transparent); +} + +.vm-page.vpr-collect-page .vpr-collect-footer__step-dot--active { + background: var(--ln-primary, #32a06e); + border-color: var(--ln-primary, #32a06e); + box-shadow: 0 0 0 2px color-mix(in srgb, var(--ln-primary, #32a06e) 25%, transparent); +} + +.vm-page.vpr-collect-page .vpr-collect-footer__step-label { + margin-left: 4px; + font-size: 0.75rem; + color: var(--ln-muted); +} + .vm-page.vpr-collect-page .vpr-collect-footer__summary { font-size: 0.875rem; color: var(--ln-body); @@ -743,3 +1412,402 @@ transition: none; } } + +/* —— 查看 / 办理页共享 —— */ +.vm-page.vpr-collect-page .vpr-page-topbar, +.vm-page.vpr-page .vpr-page-topbar { + align-items: flex-start; +} + +.vm-page.vpr-collect-page .vpr-page-topbar__back, +.vm-page.vpr-page .vpr-page-topbar__back { + display: inline-flex; + align-items: center; + gap: 4px; + min-height: 44px; + padding: 0 8px 0 0; + cursor: pointer; + transition: color 0.2s ease, background-color 0.2s ease; + border-radius: var(--ln-radius-control, 8px); +} + +.vm-page.vpr-collect-page .vpr-page-topbar__back:hover, +.vm-page.vpr-page .vpr-page-topbar__back:hover { + color: var(--ln-primary, #32a06e); +} + +.vm-page.vpr-collect-page .vpr-page-topbar__back:focus-visible, +.vm-page.vpr-page .vpr-page-topbar__back:focus-visible { + outline: 2px solid var(--ln-primary, #32a06e); + outline-offset: 2px; +} + +.vm-page.vpr-collect-page .vpr-page-topbar__back-icon, +.vm-page.vpr-page .vpr-page-topbar__back-icon { + flex-shrink: 0; +} + +.vm-page.vpr-collect-page .vpr-page-topbar__actions, +.vm-page.vpr-page .vpr-page-topbar__actions { + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; +} + +.vm-page.vpr-collect-page .vpr-page-kpi-row, +.vm-page.vpr-page .vpr-page-kpi-row { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 12px; + margin-bottom: 16px; +} + +@media (max-width: 960px) { + .vm-page.vpr-collect-page .vpr-page-kpi-row, + .vm-page.vpr-page .vpr-page-kpi-row { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 520px) { + .vm-page.vpr-collect-page .vpr-page-kpi-row, + .vm-page.vpr-page .vpr-page-kpi-row { + grid-template-columns: 1fr; + } +} + +.vm-page.vpr-collect-page .vpr-page-kpi-unit, +.vm-page.vpr-page .vpr-page-kpi-unit { + font-size: 0.875rem; + font-weight: 500; + color: var(--ln-muted, #71717a); +} + +.vm-page.vpr-collect-page .vpr-page-kpi-value--warn, +.vm-page.vpr-page .vpr-page-kpi-value--warn { + color: #b45309; +} + +.vm-page.vpr-collect-page .vpr-page-kpi-value--muted, +.vm-page.vpr-page .vpr-page-kpi-value--muted { + color: var(--ln-muted, #71717a); +} + +.vm-page.vpr-collect-page .vpr-page-callout, +.vm-page.vpr-page .vpr-page-callout { + margin-top: 12px; + padding: 12px 14px; + font-size: 13px; + line-height: 1.55; + color: var(--ln-body, #334155); + background: color-mix(in srgb, var(--ln-primary, #32a06e) 8%, #fff); + border: 1px solid color-mix(in srgb, var(--ln-primary, #32a06e) 20%, var(--ln-hairline)); + border-radius: var(--ln-radius-control, 8px); +} + +.vm-page.vpr-collect-page .vpr-page-callout--rule, +.vm-page.vpr-page .vpr-page-callout--rule { + margin: 0 0 12px; +} + +.vm-page.vpr-collect-page .vpr-page-steps-flow, +.vm-page.vpr-page .vpr-page-steps-flow { + display: block; + width: 100%; + margin: 0 0 10px; + padding: 8px 12px; + border: 1px solid var(--ln-hairline, #e2e8f0); + border-radius: var(--ln-radius-control, 8px); + background: color-mix(in srgb, var(--ln-surface, #fff) 94%, var(--ln-primary, #32a06e) 6%); + box-sizing: border-box; +} + +.vm-page.vpr-collect-page .vpr-page-steps-flow__track, +.vm-page.vpr-page .vpr-page-steps-flow__track { + margin: 0; + padding: 0; + list-style: none; + display: flex; + align-items: center; + justify-content: space-between; + gap: 4px; + min-height: 28px; +} + +.vm-page.vpr-collect-page .vpr-page-steps-flow__node, +.vm-page.vpr-page .vpr-page-steps-flow__node { + flex: 0 1 auto; + display: inline-flex; + align-items: center; + gap: 6px; + min-width: 0; + max-width: 100%; +} + +.vm-page.vpr-collect-page .vpr-page-steps-flow__dot, +.vm-page.vpr-page .vpr-page-steps-flow__dot { + flex-shrink: 0; + display: inline-flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + border-radius: 999px; + font-size: 11px; + font-weight: 700; + line-height: 1; + font-variant-numeric: tabular-nums; + color: var(--ln-muted, #71717a); + background: var(--ln-surface, #fff); + border: 1.5px solid var(--ln-hairline, #e2e8f0); +} + +.vm-page.vpr-collect-page .vpr-page-steps-flow__node--current .vpr-page-steps-flow__dot, +.vm-page.vpr-page .vpr-page-steps-flow__node--current .vpr-page-steps-flow__dot { + color: #fff; + background: var(--ln-primary, #32a06e); + border-color: var(--ln-primary, #32a06e); +} + +.vm-page.vpr-collect-page .vpr-page-steps-flow__name, +.vm-page.vpr-page .vpr-page-steps-flow__name { + font-size: 0.8125rem; + font-weight: 500; + line-height: 1.25; + color: var(--ln-muted, #71717a); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.vm-page.vpr-collect-page .vpr-page-steps-flow__node--current .vpr-page-steps-flow__name, +.vm-page.vpr-page .vpr-page-steps-flow__node--current .vpr-page-steps-flow__name { + color: var(--ln-primary-focus, #27885a); + font-weight: 600; +} + +.vm-page.vpr-collect-page .vpr-page-steps-flow__connector, +.vm-page.vpr-page .vpr-page-steps-flow__connector { + flex: 1 1 12px; + min-width: 8px; + max-width: 40px; + height: 1px; + margin: 0 2px; + background: var(--ln-hairline, #e2e8f0); + list-style: none; +} + +.vm-page.vpr-collect-page .vpr-page-steps-flow__hint, +.vm-page.vpr-page .vpr-page-steps-flow__hint { + margin: 4px 0 0; + padding: 0; + font-size: 0.75rem; + line-height: 1.4; + color: var(--ln-muted, #71717a); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +@media (max-width: 900px) { + .vm-page.vpr-collect-page .vpr-page-steps-flow__track, + .vm-page.vpr-page .vpr-page-steps-flow__track { + flex-wrap: wrap; + row-gap: 6px; + justify-content: flex-start; + } + + .vm-page.vpr-collect-page .vpr-page-steps-flow__connector, + .vm-page.vpr-page .vpr-page-steps-flow__connector { + display: none; + } + + .vm-page.vpr-collect-page .vpr-page-steps-flow__node, + .vm-page.vpr-page .vpr-page-steps-flow__node { + flex: 1 1 calc(33.333% - 8px); + min-width: 0; + } + + .vm-page.vpr-collect-page .vpr-page-steps-flow__hint, + .vm-page.vpr-page .vpr-page-steps-flow__hint { + white-space: normal; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + } +} + +@media (prefers-reduced-motion: reduce) { + .vm-page.vpr-collect-page .vpr-page-steps-flow__dot, + .vm-page.vpr-page .vpr-page-steps-flow__dot { + transition: none; + } +} + +/* legacy hint styles kept for contract view if needed */ +.vm-page.vpr-collect-page .vpr-page-steps-hint, +.vm-page.vpr-page .vpr-page-steps-hint { + display: block; + padding: 16px 18px; +} + +.vm-page.vpr-collect-page .vpr-page-steps, +.vm-page.vpr-page .vpr-page-steps { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 8px 4px; + margin: -4px 0 16px; + padding: 10px 12px; + background: var(--ln-surface, #fff); + border: 1px solid var(--ln-hairline, #e2e8f0); + border-radius: var(--ln-radius-md, 12px); +} + +.vm-page.vpr-collect-page .vpr-page-step, +.vm-page.vpr-page .vpr-page-step { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: 13px; + color: var(--ln-muted, #71717a); +} + +.vm-page.vpr-collect-page .vpr-page-step__dot, +.vm-page.vpr-page .vpr-page-step__dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--ln-hairline, #e2e8f0); + transition: background-color 0.2s ease, transform 0.2s ease; +} + +.vm-page.vpr-collect-page .vpr-page-step--active, +.vm-page.vpr-page .vpr-page-step--active { + color: var(--ln-fg, #18181b); + font-weight: 600; +} + +.vm-page.vpr-collect-page .vpr-page-step--active .vpr-page-step__dot, +.vm-page.vpr-page .vpr-page-step--active .vpr-page-step__dot { + background: var(--ln-primary, #32a06e); + transform: scale(1.15); +} + +.vm-page.vpr-collect-page .vpr-page-step--done, +.vm-page.vpr-page .vpr-page-step--done { + color: var(--ln-body, #334155); +} + +.vm-page.vpr-collect-page .vpr-page-step--done .vpr-page-step__dot, +.vm-page.vpr-page .vpr-page-step--done .vpr-page-step__dot { + background: color-mix(in srgb, var(--ln-primary, #32a06e) 55%, #fff); +} + +.vm-page.vpr-collect-page .vpr-page-steps__sep, +.vm-page.vpr-page .vpr-page-steps__sep { + width: 20px; + height: 1px; + background: var(--ln-hairline, #e2e8f0); + flex-shrink: 0; +} + +.vm-page.vpr-collect-page .vpr-collect-form-item__required, +.vm-page.vpr-page .vpr-collect-form-item__required { + margin-left: 2px; + color: #dc2626; +} + +.vm-page.vpr-collect-page .vpr-collect-form-item__error, +.vm-page.vpr-page .vpr-collect-form-item__error { + display: block; + margin-top: 4px; + font-size: 12px; + color: #dc2626; +} + +.vm-page.vpr-collect-page .vpr-collect-form-item--invalid .vpr-collect-form-item__label, +.vm-page.vpr-page .vpr-collect-form-item--invalid .vpr-collect-form-item__label { + color: #b91c1c; +} + +.vm-page.vpr-page .vpr-page-table-wrap { + overflow: auto; + border-radius: var(--ln-radius-control, 8px); + border: 1px solid var(--ln-hairline, #e2e8f0); +} + +.vm-page.vpr-page .vpr-page-table-wrap thead th { + position: sticky; + top: 0; + z-index: 1; + background: var(--ln-canvas-soft, #f8fafc); +} + +.vm-page.vpr-page .vpr-page-table-row { + transition: background-color 0.15s ease; +} + +.vm-page.vpr-page .vpr-page-table-row:hover { + background: color-mix(in srgb, var(--ln-primary, #32a06e) 4%, #fff); +} + +.vm-page.vpr-page .vpr-th--num, +.vm-page.vpr-page .vpr-td--num { + text-align: right !important; + font-variant-numeric: tabular-nums; +} + +.vm-page.vpr-page .vpr-page-table-muted { + color: var(--ln-muted, #71717a); + font-size: 13px; +} + +.vm-page.vpr-page .vpr-page-empty { + padding: 24px 16px; + text-align: center; +} + +.vm-page.vpr-page .vpr-page-empty__title { + margin: 0 0 6px; + font-size: 14px; + font-weight: 600; + color: var(--ln-fg, #18181b); +} + +.vm-page.vpr-page .vpr-page-empty__desc { + margin: 0; + font-size: 13px; + line-height: 1.5; + color: var(--ln-muted, #71717a); +} + +.vm-page.vpr-page .vpr-page-empty--success { + background: color-mix(in srgb, var(--ln-primary, #32a06e) 6%, var(--ln-canvas-soft, #f8fafc)); +} + +.vm-page.vpr-page .vpr-contract-view-footer-cta { + display: flex; + justify-content: center; + margin-top: 8px; + padding: 8px 0 16px; +} + +.vm-page.vpr-collect-page .vpr-submit-confirm__list { + margin: 12px 0 0; + padding-left: 18px; + color: var(--ln-body, #334155); + line-height: 1.7; +} + +@media (prefers-reduced-motion: reduce) { + .vm-page.vpr-collect-page .vpr-page-topbar__back, + .vm-page.vpr-page .vpr-page-topbar__back, + .vm-page.vpr-page .vpr-page-table-row, + .vm-page.vpr-collect-page .vpr-page-step__dot, + .vm-page.vpr-page .vpr-page-step__dot { + transition: none; + } +} diff --git a/vite.config.ts b/vite.config.ts index 56fa10d..179d739 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -100,6 +100,9 @@ export default defineConfig(({ command }) => { optimizeDeps: { include: [ 'lucide-react', + 'mammoth', + 'docx-preview', + 'jszip', ], },