@@ -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.title}
+
+
+
{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' ? (