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
+ +
三、列表卡片字段
+ +
四、筛选与搜索
+ +
五、跳转规则
+ +
+ ), + }, + 'audit-pickup': { + title: '提车应收款审批 · 产品需求说明', + body: ( +
+ 审批中心 / 提车应收款 +
版本 V1.0 · 数据源自提车应收款业务单 · 审批节点:业管 → 财务
+
一、页面目标
+

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

+
二、Hero 区
+ +
三、正文区块
+ +
四、底部操作(待办态)
+ +
+ ), + }, + 'audit-return': { + title: '还车应结款审批 · 产品需求说明', + body: ( +
+ 审批中心 / 还车应结款 +
版本 V1.0 · 数据源自还车结算单 · 多部门分组提交后汇总审批
+
一、页面目标
+

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

+
当保证金 ≥ 待结算总额时,Hero 展示「应退还总额」;否则展示「应补缴总额」。
+
二、Hero 区(紫色主题)
+ +
三、分组结算卡片
+ +
四、审批与操作
+

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

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

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

+
二、Hero 区(蓝色主题)
+ +
三、正文区块
+ +
四、金额计算口径(开发)
+ +
+ ), + }, + 'audit-transfer-create': { + title: '车辆调拨审批(申请方) · 产品需求说明', + body: ( +
+ 审批中心 / 车辆调拨 · 申请方 +
版本 V1.0 · transferStage=create · 区域间车辆调配申请
+
一、页面目标
+

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

+
二、Hero 区(绿色主题)
+ +
三、正文区块
+ +
四、与运维方审批的差异
+

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

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

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

+
二、页面结构
+

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

+
三、审批要点
+ +
+ ), + }, + 'audit-replace': { + title: '替换车申请审批 · 产品需求说明', + body: ( +
+ 审批中心 / 替换车申请 +
版本 V1.0 · 数据源自替换车业务单 · 审批节点:业务主管 → 事业部主管 → 运维主管
+
一、页面目标
+

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

+
二、Hero 区(玫红主题)
+ +
三、替换对卡片
+ +
四、审批与操作
+

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

+
+ ), + }, }; 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' ? (