From 6baff9ab7f7a5453164c25092cf7e01576f973ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=86=95?= Date: Wed, 10 Jun 2026 14:05:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(miniapp):=20=E5=AE=8C=E5=96=84=E5=B0=8F?= =?UTF-8?q?=E7=BE=9A=E7=BE=9A=E5=AE=A1=E6=89=B9=E4=B8=AD=E5=BF=83=E4=B8=8E?= =?UTF-8?q?=E5=90=84=E6=B5=81=E7=A8=8B=20PRD=20=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增审批中心及提车/还车/租赁账单/调拨/替换车等流程需求文档,优化底部抽屉确认样式,并精简还车应结款审批页车辆租金展示。 Co-authored-by: Cursor --- ONE-OS小程序/小羚羚.jsx | 262 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 236 insertions(+), 26 deletions(-) diff --git a/ONE-OS小程序/小羚羚.jsx b/ONE-OS小程序/小羚羚.jsx index fb14905..4dc2e23 100644 --- a/ONE-OS小程序/小羚羚.jsx +++ b/ONE-OS小程序/小羚羚.jsx @@ -634,6 +634,9 @@ const PAGE_STYLE = ` .tc-mini-sheet-title { font-size:16px; font-weight:700; color:${COLOR_TEXT}; } .tc-mini-sheet-close { width:32px; height:32px; border:none; background:${COLOR_PAGE}; border-radius:999px; font-size:20px; line-height:1; color:${COLOR_MUTED}; cursor:pointer; flex-shrink:0; } .tc-mini-sheet-body { flex:1; min-height:0; overflow-y:auto; -webkit-overflow-scrolling:touch; padding:4px 20px calc(16px + env(safe-area-inset-bottom,0px)); } +.tc-mini-sheet-foot { flex-shrink:0; padding:10px 16px calc(10px + env(safe-area-inset-bottom,0px)); border-top:1px solid ${COLOR_LINE}; } +.tc-mini-sheet-ok { width:100%; min-height:44px; border:none; border-radius:10px; font-size:15px; font-weight:600; cursor:pointer; background:${XLL_GREEN_DEEP}; color:#fff; touch-action:manipulation; } +.tc-mini-sheet-ok:active { opacity:.88; } @keyframes tc-sheet-up { from { transform:translateY(100%); } to { transform:translateY(0); } } @media (prefers-reduced-motion: reduce) { .tc-mini-sheet-panel { animation:none; } @@ -1785,14 +1788,6 @@ const ReturnSettlementApprovePage = ({ task, mode, onBack }) => { -
-
车辆租金
-
- - - -
-
@@ -2454,6 +2449,16 @@ const VrReplaceVehicleCard = ({ pair, index }) => ( ); +const getAuditPrdKey = (task) => { + if (!task) return 'audit'; + if (task.flowType === '提车应收款') return 'audit-pickup'; + if (task.flowType === '还车应结款') return 'audit-return'; + if (task.flowType === '租赁账单') return 'audit-lease-bill'; + if (task.flowType === '替换车申请') return 'audit-replace'; + if (task.flowType === '车辆调拨') return task.transferStage === 'ops' ? 'audit-transfer-ops' : 'audit-transfer-create'; + return 'audit'; +}; + const ReplaceVehicleApprovePage = ({ task, mode, onBack }) => { const detail = useMemo(() => buildReplaceVehicleDetail(task), [task]); const { pairs, projectInfo, approvalSteps } = detail; @@ -2519,13 +2524,18 @@ const ReplaceVehicleApprovePage = ({ task, mode, onBack }) => { ); }; -const ApprovalCenterModule = ({ onRegisterBack }) => { +const ApprovalCenterModule = ({ onRegisterBack, onPrdKeyChange }) => { const [mainTab, setMainTab] = useState('todo'); const [flowFilter, setFlowFilter] = useState(''); const [searchKey, setSearchKey] = useState(''); const [filterDrawerOpen, setFilterDrawerOpen] = useState(false); const [detailTask, setDetailTask] = useState(null); + useEffect(() => { + onPrdKeyChange?.(getAuditPrdKey(detailTask)); + return () => onPrdKeyChange?.(null); + }, [detailTask, onPrdKeyChange]); + const tabCounts = useMemo(() => { const counts = { initiated: 0, todo: 0, done: 0, cc: 0 }; AC_MOCK_TASKS.forEach((t) => { @@ -4927,6 +4937,199 @@ const PRD_DOCS = { ), }, + audit: { + title: '审批中心 · 产品需求说明', + body: ( +
+ 审批管理 / 审批中心 +
版本 V1.0 · 对接 ONE-OS 审批中心 · 适用:有审批权限的业务/财务/管理人员
+
一、目标
+

在小程序内聚合「我发起的 / 我的待办 / 我的已办 / 抄送我的」四类审批任务,支持按流程类型筛选与搜索,点击进入对应流程的办理或查看页。

+
二、列表 Tab
+
    +
  • 我发起的:当前用户作为发起人的流程。
  • +
  • 我的待办:待当前用户审批,卡片展示当前节点与处理人。
  • +
  • 我的已办:当前用户已处理过的历史记录。
  • +
  • 抄送我的:仅知会、无需操作的任务。
  • +
+
三、列表卡片字段
+
    +
  • 流程类型色条 + 类型名称(合同审批、提车应收款、租赁账单、还车应结款、车辆调拨、替换车申请等)。
  • +
  • 单据号、摘要、发起人、到达/完成时间。
  • +
  • 客户类流程额外展示客户名称、项目名称;还车展示应退/应补金额。
  • +
  • 状态 Tag:审批中 / 已通过 / 已驳回 / 已终止。
  • +
+
四、筛选与搜索
+
    +
  • 快捷 Chip:全部、合同审批、提车应收款、租赁账单、车辆调拨;「更多类型」抽屉展示全部流程类型。
  • +
  • 搜索范围:单据号、摘要、流程类型、发起人、客户名、项目名、车牌号。
  • +
+
五、跳转规则
+
    +
  • 已接入详情页:提车应收款、还车应结款、租赁账单、车辆调拨(申请/运维)、替换车申请。
  • +
  • 待办 Tab 进入办理态(底部展示通过/驳回/终止/评论);其余 Tab 为只读查看态。
  • +
  • 左上返回:详情页先退回列表,再退回业务入口。
  • +
+
+ ), + }, + 'audit-pickup': { + title: '提车应收款审批 · 产品需求说明', + body: ( +
+ 审批中心 / 提车应收款 +
版本 V1.0 · 数据源自提车应收款业务单 · 审批节点:业管 → 财务
+
一、页面目标
+

审批人核对本次提车实收金额是否与合同约定一致,确认车辆明细、氢费预付款(如有)及开票信息后方可通过。

+
二、Hero 区
+
    +
  • 主金额:实收款总额(大字号,橙色主题)。
  • +
  • 副信息:客户名称、合同编码、项目名称、提车台数。
  • +
  • 对比行:应收款总额、较应收减免差额。
  • +
  • 「实收明细」底部抽屉:分项展示月租金、保证金、服务费、减免及氢费预收(如有)。
  • +
+
三、正文区块
+
    +
  • 车辆明细:逐车展示品牌型号、车牌、应收/实收租金、保证金、服务费及减免凭证。
  • +
  • 氢费预付款(首期有):应收、实收、减免金额与备注。
  • +
  • 开票信息:开票方式、开票备注。
  • +
  • 审批情况:时间轴展示各部门审批状态、审批人、时间。
  • +
+
四、底部操作(待办态)
+
    +
  • 评论:填写意见,不改变流程状态。
  • +
  • 终止 / 驳回:需填写原因,流程结束并通知发起人。
  • +
  • 通过:确认后流转下一节点;末节点通过后单据完结。
  • +
+
+ ), + }, + 'audit-return': { + title: '还车应结款审批 · 产品需求说明', + body: ( +
+ 审批中心 / 还车应结款 +
版本 V1.0 · 数据源自还车结算单 · 多部门分组提交后汇总审批
+
一、页面目标
+

还车完成后,客户服务组、能源采购组、运维部、安全部分别填报费用,审批人核对分组明细与汇总金额,判定保证金抵扣后应退或应补。

+
当保证金 ≥ 待结算总额时,Hero 展示「应退还总额」;否则展示「应补缴总额」。
+
二、Hero 区(紫色主题)
+
    +
  • 主金额:应退还总额 / 应补缴总额。
  • +
  • 车辆信息:车牌、合同编码、项目名称、三项保险状态(易损/轮胎/养护)。
  • +
  • 租期:交车时间、还车时间。
  • +
  • 摘要:保证金、待结算总额、车辆实际租金;「结算明细」抽屉展示分项汇总。
  • +
+
三、分组结算卡片
+
    +
  • 客户服务组:固定费项表格(违章违约金、保险上浮、ETC 费用、停车费等),底部应结算总额。
  • +
  • 能源采购组:氢量差补缴、交/还车氢量、退还单价、预付款退费。
  • +
  • 运维部:清洗、保养、维修、车损、工具/证件/广告丢失、送接车服务、轮胎磨损等费项。
  • +
  • 安全部:违章次数、已缴/未缴金额统计。
  • +
+
四、审批与操作
+

审批时间轴 + 底部评论/终止/驳回/通过,规则同提车应收款。查看态隐藏操作栏,仅浏览。

+
+ ), + }, + 'audit-lease-bill': { + title: '租赁账单审批 · 产品需求说明', + body: ( +
+ 审批中心 / 租赁账单 +
版本 V1.0 · 数据源自月度租赁账单 · 审批节点:业务服务组 → 业管主管 → 财务
+
一、页面目标
+

审批人核对本期账单实收金额、逐车租金与服务费减免是否合理,首期账单需额外核对氢费预付款。

+
二、Hero 区(蓝色主题)
+
    +
  • 主金额:实收款总额。
  • +
  • 客户、合同编码、项目名称。
  • +
  • 账单周期起止日期、期数 Tag(第 N 期)。
  • +
  • 应收款总额、开票总额;「应收明细」「实收明细」两个底部抽屉。
  • +
+
三、正文区块
+
    +
  • 车辆列表:逐车展示应收/实收租金、减免金额与凭证、服务费明细。
  • +
  • 氢费预付款(仅第 1 期展示):应收、实收、减免及备注。
  • +
  • 审批情况:各部门节点时间轴。
  • +
+
四、金额计算口径(开发)
+
    +
  • 应收总额 = 月租金 + 保证金(首期)+ 服务费 + 氢费预收(首期)。
  • +
  • 实收总额 = 实收租金 + 保证金 + 实收服务费 − 租金减免 − 服务费减免 + 氢费实收 − 氢费减免。
  • +
  • 开票总额不含保证金。
  • +
+
+ ), + }, + 'audit-transfer-create': { + title: '车辆调拨审批(申请方) · 产品需求说明', + body: ( +
+ 审批中心 / 车辆调拨 · 申请方 +
版本 V1.0 · transferStage=create · 区域间车辆调配申请
+
一、页面目标
+

发起区域申请将车辆调拨至目标区域,审批人核对路线、运输方式、车辆清单及出发时车况数据。

+
二、Hero 区(绿色主题)
+
    +
  • 调拨车辆台数、出发区域 → 接收区域路线展示。
  • +
  • 调拨日期;Tag 标识「调拨申请」。
  • +
+
三、正文区块
+
    +
  • 调拨情况:日期、出发/接收区域、调拨原因。
  • +
  • 运输信息:运输方式(司机运输/板车运输等)、承运人、预计到达。
  • +
  • 车辆清单:逐车车牌、品牌型号、出发里程/氢量/电量。
  • +
  • 审批情况:节点时间轴。
  • +
+
四、与运维方审批的差异
+

申请方侧重「为何调拨、调哪些车」;运维方(ops)侧重接收区域验收与到达车况,Hero Tag 为「运维调拨方」。

+
+ ), + }, + 'audit-transfer-ops': { + title: '车辆调拨审批(运维方) · 产品需求说明', + body: ( +
+ 审批中心 / 车辆调拨 · 运维方 +
版本 V1.0 · transferStage=ops · 接收区域运维确认调拨到达
+
一、页面目标
+

接收区域运维负责人在车辆到达后审批确认,核对运输过程信息与车辆到达时里程、氢量、电量是否与申请一致。

+
二、页面结构
+

布局与申请方审批页一致,Hero Tag 改为「运维调拨方」。车辆卡片除出发数据外,需展示到达里程/氢量/电量(如有)。

+
三、审批要点
+
    +
  • 确认车辆已全部到达接收区域。
  • +
  • 核对车况数据异常是否已在备注中说明。
  • +
  • 通过后更新车辆归属区域,流程完结。
  • +
+
+ ), + }, + 'audit-replace': { + title: '替换车申请审批 · 产品需求说明', + body: ( +
+ 审批中心 / 替换车申请 +
版本 V1.0 · 数据源自替换车业务单 · 审批节点:业务主管 → 事业部主管 → 运维主管
+
一、页面目标
+

客户用车期间需更换车辆时,审批人核对替换类型、原/替换车辆信息及替换原因,客户原因替换需确认费用。

+
二、Hero 区(玫红主题)
+
    +
  • 替换车辆台数、客户名称。
  • +
  • 合同编码、项目名称、交车区域、项目类型 Tag。
  • +
+
三、替换对卡片
+
    +
  • 左右对照:被替换车(原车牌/品牌型号)→ 替换为(新车牌/品牌型号)。
  • +
  • 替换类型 Tag:永久替换 / 临时替换。
  • +
  • 替换原因、原因说明;原因为「客户原因」时展示替换费用。
  • +
+
四、审批与操作
+

支持多组替换对逐条展示;底部操作栏规则与其他审批页一致。通过后由运维安排交/还车衔接。

+
+ ), + }, }; const IphoneStatusBar = () => ( @@ -4950,21 +5153,22 @@ const MpCapsule = () => ( const PrdModal = ({ prdKey, onClose }) => { const doc = PRD_DOCS[prdKey]; - if (!doc || !Modal) return null; + if (!doc || !prdKey) return null; return ( - 知道了, - ] : null} - styles={{ body: { maxHeight: '72vh', overflowY: 'auto', paddingTop: 8 } }} - > - {doc.body} - +
+ +
+
{doc.body}
+
+ +
+ + ); }; @@ -5157,6 +5361,11 @@ const Component = function XiaoLingLingMiniApp() { const [todoDetail, setTodoDetail] = useState(null); const [bizModule, setBizModule] = useState(null); const [prdKey, setPrdKey] = useState(null); + const [auditPrdKey, setAuditPrdKey] = useState(null); + + const handleAuditPrdKeyChange = useCallback((key) => { + setAuditPrdKey(key || null); + }, []); const navTitle = useMemo(() => { if (!loggedIn) return '登录'; @@ -5174,14 +5383,15 @@ const Component = function XiaoLingLingMiniApp() { if (!loggedIn) return 'login'; if (bizModule === 'delivery') return 'delivery'; if (bizModule === 'replace') return 'replace'; - if (bizModule === 'audit' || bizModule === 'inspection' || bizModule === 'vehicle') return 'business'; + if (bizModule === 'audit') return auditPrdKey || 'audit'; + if (bizModule === 'inspection' || bizModule === 'vehicle') return 'business'; if (todoDetail) return 'todo-detail'; if (mainTab === 'todo') return 'todo'; if (mainTab === 'business') return 'business'; if (mainTab === 'map') return 'map'; if (mainTab === 'mine') return 'mine'; return 'todo'; - }, [loggedIn, mainTab, todoDetail, bizModule]); + }, [loggedIn, mainTab, todoDetail, bizModule, auditPrdKey]); const handleOpenPrd = useCallback((key) => setPrdKey(key || currentPrdKey), [currentPrdKey]); @@ -5296,7 +5506,7 @@ const Component = function XiaoLingLingMiniApp() { { setLoggedIn(true); message.success('登录成功'); }} onOpenPrd={handleOpenPrd} /> ) : bizModule ? ( bizModule === 'audit' ? ( - + ) : bizModule === 'inspection' ? ( ) : bizModule === 'vehicle' ? (