车牌号
diff --git a/src/prototypes/oneos-h5-h2-order/styles/index.css b/src/prototypes/oneos-h5-h2-order/styles/index.css
index 80bbfe3..e6b1940 100644
--- a/src/prototypes/oneos-h5-h2-order/styles/index.css
+++ b/src/prototypes/oneos-h5-h2-order/styles/index.css
@@ -1317,6 +1317,17 @@
color: var(--color-text);
}
+.h5-detail-row--station {
+ min-width: 0;
+}
+
+.h5-detail-row--station strong {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
.h5-panel--detail {
padding-top: 14px;
}
@@ -1424,13 +1435,6 @@
font-weight: 600;
}
-.h5-detail-photo__hint {
- margin: 0;
- font-size: 11px;
- line-height: 1.4;
- color: #94a3b8;
-}
-
.h5-loading {
display: flex;
align-items: center;
diff --git a/src/prototypes/oneos-h5-h2-order/utils/orders.ts b/src/prototypes/oneos-h5-h2-order/utils/orders.ts
index 60856c5..6c12f10 100644
--- a/src/prototypes/oneos-h5-h2-order/utils/orders.ts
+++ b/src/prototypes/oneos-h5-h2-order/utils/orders.ts
@@ -159,6 +159,8 @@ export function upsertStationOrder(input: {
platePhotoUrl: String(input.platePhotoUrl || ''),
panelPhotoUrl: String(input.panelPhotoUrl || ''),
creatorName: '站端账号',
+ recordSource: 'station',
+ changeLogOperator: '站端账号',
reconcileStatus: 'pending',
verifyStatus: 'unverified',
});
diff --git a/src/prototypes/oneos-prototype-nav/nav-menu.json b/src/prototypes/oneos-prototype-nav/nav-menu.json
index e5bb4c6..b7c4d3d 100644
--- a/src/prototypes/oneos-prototype-nav/nav-menu.json
+++ b/src/prototypes/oneos-prototype-nav/nav-menu.json
@@ -113,7 +113,7 @@
{
"id": "item:prototypes:oneos-h5-h2-order",
"kind": "item",
- "title": "加氢订单",
+ "title": "加氢记录(H5)",
"itemKey": "prototypes/oneos-h5-h2-order"
},
{
@@ -224,6 +224,19 @@
}
]
},
+ {
+ "id": "folder-1784341576489-spa7ms",
+ "kind": "folder",
+ "title": "审批中心",
+ "children": [
+ {
+ "id": "item:prototypes:oneos-web-approval",
+ "kind": "item",
+ "title": "审批中心",
+ "itemKey": "prototypes/oneos-web-approval"
+ }
+ ]
+ },
{
"id": "item:prototypes:lease-business-line-overview",
"kind": "item",
diff --git a/src/prototypes/oneos-prototype-nav/prototype-registry.json b/src/prototypes/oneos-prototype-nav/prototype-registry.json
index 77784c5..e0f8eae 100644
--- a/src/prototypes/oneos-prototype-nav/prototype-registry.json
+++ b/src/prototypes/oneos-prototype-nav/prototype-registry.json
@@ -1,6 +1,6 @@
{
"version": 1,
- "updatedAt": "2026-07-18T02:26:51.943Z",
+ "updatedAt": "2026-07-18T04:30:15.800Z",
"prototypes": {
"oneos-web-workbench": {
"title": "工作台",
@@ -57,10 +57,10 @@
},
"vehicle-management": {
"title": "车辆资产",
- "version": "v1.7",
- "revision": 7,
- "lastUpdated": "2026-07-18T02:21:08.457Z",
- "contentHash": "7f7269086b98de7022d4e4fc3657c7c1ef3204ae9aac6f31d3b6a24a0bd632e5",
+ "version": "v1.11",
+ "revision": 11,
+ "lastUpdated": "2026-07-18T04:30:15.800Z",
+ "contentHash": "31524a813ece4d38c7971d7a945b6cf68dde1c72ab114f90665061d7ad191848",
"trackedFiles": [
".spec/prototype-comments.json",
".spec/prototype-review.md",
@@ -146,6 +146,90 @@
"utils/violationRecords.ts"
],
"changelog": [
+ {
+ "version": "v1.11",
+ "date": "2026-07-18",
+ "time": "12:30",
+ "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"
+ ],
+ "details": [
+ "DateRangeFilterField 与 filter placeholder 统一 0.875rem / muted-soft",
+ "对齐 global-design-spec §4.1 更多筛选与日期区间规则"
+ ]
+ },
+ {
+ "version": "v1.10",
+ "date": "2026-07-18",
+ "time": "10:51",
+ "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-18",
+ "time": "10: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.8",
+ "date": "2026-07-18",
+ "time": "10: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-18",
@@ -597,10 +681,10 @@
},
"lease-contract-management": {
"title": "租赁合同",
- "version": "v1.9",
- "revision": 9,
- "lastUpdated": "2026-07-12T14:44:00.000Z",
- "contentHash": "9893fd2bd34c29a9bf60a11d16061cbf71015bd27f918ecdc282477bb47a243a",
+ "version": "v1.10",
+ "revision": 10,
+ "lastUpdated": "2026-07-18T03:17:53.200Z",
+ "contentHash": "71e374a81e5dd49b522c4ec9e0acdaea60957ce826a6fabd32b905623d5ddf10",
"trackedFiles": [
".spec/prototype-comments.json",
".spec/requirements-annotation-context.md",
@@ -634,6 +718,26 @@
"styles/lease-contract.css"
],
"changelog": [
+ {
+ "version": "v1.10",
+ "date": "2026-07-18",
+ "time": "11:17",
+ "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.9",
"date": "2026-07-12",
@@ -2176,10 +2280,10 @@
},
"vehicle-h2-fee-ledger": {
"title": "车辆氢费明细",
- "version": "v1.6",
- "revision": 6,
- "lastUpdated": "2026-07-17T08:10:00.000Z",
- "contentHash": "1a18653f7e28ef0c9dda965948c05aef6b908f9f23ffd5797921b410016c4469",
+ "version": "v1.18",
+ "revision": 18,
+ "lastUpdated": "2026-07-18T04:30:15.800Z",
+ "contentHash": "7d8df9ed52511e05498e4e3fb14e4343757505c96688df7df9498ca6157d6e95",
"trackedFiles": [
".spec/PRD.md",
".spec/prototype-comments.json",
@@ -2189,6 +2293,179 @@
"index.tsx"
],
"changelog": [
+ {
+ "version": "v1.18",
+ "date": "2026-07-18",
+ "time": "12:30",
+ "summary": "车辆氢费明细:来源标签、核对人/对账人与行级变更日志",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ],
+ "details": [
+ "车牌下方标注站端上传/羚牛上传",
+ "完成核对写入核对人;对账单提交写入对账人",
+ "变更日志同步行级 changeLogs,弹窗展示时间/操作人/修改项/原值/新值"
+ ]
+ },
+ {
+ "version": "v1.17",
+ "date": "2026-07-18",
+ "time": "11:44",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "version": "v1.16",
+ "date": "2026-07-18",
+ "time": "11:44",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "version": "v1.15",
+ "date": "2026-07-18",
+ "time": "11:43",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "version": "v1.14",
+ "date": "2026-07-18",
+ "time": "11:43",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "version": "v1.13",
+ "date": "2026-07-18",
+ "time": "11:43",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "version": "v1.12",
+ "date": "2026-07-18",
+ "time": "11:43",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "version": "v1.11",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "version": "v1.10",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "version": "v1.9",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "version": "v1.8",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "version": "v1.7",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
{
"version": "v1.6",
"date": "2026-07-17",
@@ -2518,9 +2795,9 @@
},
"oneos-prototype-nav": {
"title": "oneos-prototype-nav",
- "version": "v1.7",
- "revision": 7,
- "lastUpdated": "2026-07-17T08:12:20.228Z",
+ "version": "v1.8",
+ "revision": 8,
+ "lastUpdated": "2026-07-18T04:30:15.800Z",
"contentHash": "a303e48dcd21ad8e2124de72c0d8dcc7e86abdaca76605af69d33606f6d70363",
"trackedFiles": [
".spec/prototype-comments.json",
@@ -2531,6 +2808,24 @@
"xll-nav-source.json"
],
"changelog": [
+ {
+ "version": "v1.8",
+ "date": "2026-07-18",
+ "time": "12:30",
+ "summary": "同步本版加氢链路更新日志与导航:H5 更名、审批中心、下线合同模板",
+ "details": [
+ "侧栏/菜单:加氢订单更名为加氢记录(H5);新增审批中心;移除合同模板入口",
+ "写入加氢记录/氢费明细/H5/车辆管理本版变更说明到导航变更日志"
+ ],
+ "files": [
+ ".spec/prototype-comments.json",
+ "index.tsx",
+ "nav-data.ts",
+ "style.css",
+ "xll-nav-menu.json",
+ "xll-nav-source.json"
+ ]
+ },
{
"version": "v1.7",
"date": "2026-07-17",
@@ -2991,14 +3286,15 @@
},
"oneos-web-h2-station": {
"title": "加氢记录",
- "version": "v1.12",
- "revision": 12,
- "lastUpdated": "2026-07-17T08:24:48.851Z",
- "contentHash": "26a6df6de3c13221ec1014aff2cf65284171a4642e9afd96dd51e9bb8eac4670",
+ "version": "v1.80",
+ "revision": 80,
+ "lastUpdated": "2026-07-18T04:30:15.800Z",
+ "contentHash": "58b8bf57edc79b6aaa26ad8edc82e20abfc976130716565640bb342640d07c52",
"trackedFiles": [
".spec/prototype-comments.json",
".spec/prototype-review.md",
".spec/record-data-model.md",
+ ".spec/record-source-changelog.md",
".spec/requirements-prd.md",
".spec/ui-review.md",
"index.tsx",
@@ -3008,182 +3304,522 @@
],
"changelog": [
{
- "version": "v1.12",
- "date": "2026-07-17",
- "time": "16:24",
- "summary": "更新需求说明与标注",
+ "version": "v1.80",
+ "date": "2026-07-18",
+ "time": "12:30",
+ "summary": "加氢记录:日统计默认收起,来源标签/变更日志/核对人与对账人,筛选规范对齐",
"files": [
".spec/prototype-comments.json",
".spec/prototype-review.md",
".spec/record-data-model.md",
+ ".spec/record-source-changelog.md",
".spec/requirements-prd.md",
".spec/ui-review.md",
"index.tsx",
"pages/02-加氢记录.jsx",
"pages/README.md",
"styles/h2-station-vm-filter.css"
- ]
- },
- {
- "version": "v1.11",
- "date": "2026-07-17",
- "time": "16:24",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/record-data-model.md",
- ".spec/requirements-prd.md",
- ".spec/ui-review.md",
- "index.tsx",
- "pages/02-加氢记录.jsx",
- "pages/README.md",
- "styles/h2-station-vm-filter.css"
- ]
- },
- {
- "version": "v1.10",
- "date": "2026-07-17",
- "time": "16:24",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/record-data-model.md",
- ".spec/requirements-prd.md",
- ".spec/ui-review.md",
- "index.tsx",
- "pages/02-加氢记录.jsx",
- "pages/README.md",
- "styles/h2-station-vm-filter.css"
- ]
- },
- {
- "version": "v1.9",
- "date": "2026-07-17",
- "time": "16:24",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/record-data-model.md",
- ".spec/requirements-prd.md",
- ".spec/ui-review.md",
- "index.tsx",
- "pages/02-加氢记录.jsx",
- "pages/README.md",
- "styles/h2-station-vm-filter.css"
- ]
- },
- {
- "version": "v1.8",
- "date": "2026-07-17",
- "time": "16:23",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/record-data-model.md",
- ".spec/requirements-prd.md",
- ".spec/ui-review.md",
- "index.tsx",
- "pages/02-加氢记录.jsx",
- "pages/README.md",
- "styles/h2-station-vm-filter.css"
- ]
- },
- {
- "version": "v1.7",
- "date": "2026-07-17",
- "time": "16:10",
- "summary": "页面逻辑与交互:index.tsx",
- "details": [
- "需求说明与 PRD:prototype-review.md、record-data-model.md、requirements-prd.md、ui-review.md"
],
- "commit": "305199c",
+ "details": [
+ "每日统计默认收起为一行 KPI,展开后才显示 7 日卡片,优先露出列表",
+ "车牌附来源标签:站端上传 / 羚牛上传;操作更多含变更日志",
+ "核对时间后增核对人,对账时间后增对账人;导出列同步",
+ "补齐 record-source-changelog 规格与 PRD/标注"
+ ]
+ },
+ {
+ "version": "v1.79",
+ "date": "2026-07-18",
+ "time": "11:46",
+ "summary": "更新需求说明与标注",
"files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/record-source-changelog.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.78",
+ "date": "2026-07-18",
+ "time": "11:46",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/record-source-changelog.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.77",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
".spec/prototype-review.md",
".spec/record-data-model.md",
".spec/requirements-prd.md",
".spec/ui-review.md",
"index.tsx",
- "pages/README.md"
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
]
},
{
- "version": "v1.6",
- "date": "2026-07-16",
- "time": "09:00",
- "summary": "加氢记录/订单同源对账",
- "details": [
- "租赁明细校验与月度损益",
- "车辆与台账增强",
- "页面逻辑与交互:index.tsx",
- "需求说明与 PRD:record-data-model.md、requirements-prd.md"
- ],
- "commit": "47c223a",
+ "version": "v1.76",
+ "date": "2026-07-18",
+ "time": "11:41",
+ "summary": "更新需求说明与标注",
"files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
".spec/record-data-model.md",
".spec/requirements-prd.md",
- "index.tsx"
- ]
- },
- {
- "version": "v1.5",
- "date": "2026-07-12",
- "time": "22:44",
- "summary": "页面逻辑与交互:index.tsx",
- "details": [],
- "commit": "131b963",
- "files": [
- "index.tsx"
- ]
- },
- {
- "version": "v1.4",
- "date": "2026-07-08",
- "time": "11:44",
- "summary": "样式与布局:h2-station-vm-filter.css",
- "details": [],
- "commit": "6d14c58",
- "files": [
- "styles/h2-station-vm-filter.css"
- ]
- },
- {
- "version": "v1.3",
- "date": "2026-07-02",
- "time": "03:35",
- "summary": "页面逻辑与交互:index.tsx",
- "details": [
- "样式与布局:h2-station-vm-filter.css"
- ],
- "commit": "f5e3126",
- "files": [
+ ".spec/ui-review.md",
"index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
"styles/h2-station-vm-filter.css"
]
},
{
- "version": "v1.2",
- "date": "2026-06-30",
- "time": "16:54",
- "summary": "页面逻辑与交互:index.tsx",
- "details": [],
- "commit": "0982837",
+ "version": "v1.75",
+ "date": "2026-07-18",
+ "time": "11:41",
+ "summary": "更新需求说明与标注",
"files": [
- "index.tsx"
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
]
},
{
- "version": "v1.1",
- "date": "2026-06-30",
- "time": "16:36",
- "summary": "页面逻辑与交互:index.tsx",
- "details": [],
- "commit": "d71ebc5",
+ "version": "v1.74",
+ "date": "2026-07-18",
+ "time": "11:41",
+ "summary": "更新需求说明与标注",
"files": [
- "index.tsx"
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.73",
+ "date": "2026-07-18",
+ "time": "11:41",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.72",
+ "date": "2026-07-18",
+ "time": "11:41",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.71",
+ "date": "2026-07-18",
+ "time": "11:40",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.70",
+ "date": "2026-07-18",
+ "time": "11:40",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.69",
+ "date": "2026-07-18",
+ "time": "11:31",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.68",
+ "date": "2026-07-18",
+ "time": "11:31",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.67",
+ "date": "2026-07-18",
+ "time": "11:29",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.66",
+ "date": "2026-07-18",
+ "time": "11:29",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.65",
+ "date": "2026-07-18",
+ "time": "11:28",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.64",
+ "date": "2026-07-18",
+ "time": "11:28",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.63",
+ "date": "2026-07-18",
+ "time": "11:27",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.62",
+ "date": "2026-07-18",
+ "time": "11:27",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.61",
+ "date": "2026-07-18",
+ "time": "11:27",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.60",
+ "date": "2026-07-18",
+ "time": "11:24",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.59",
+ "date": "2026-07-18",
+ "time": "11:24",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.58",
+ "date": "2026-07-18",
+ "time": "11:22",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.57",
+ "date": "2026-07-18",
+ "time": "11:22",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.56",
+ "date": "2026-07-18",
+ "time": "11:22",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.55",
+ "date": "2026-07-18",
+ "time": "11:20",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.54",
+ "date": "2026-07-18",
+ "time": "11:19",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.53",
+ "date": "2026-07-18",
+ "time": "11:19",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.52",
+ "date": "2026-07-18",
+ "time": "11:18",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "version": "v1.51",
+ "date": "2026-07-18",
+ "time": "11:18",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
]
}
]
@@ -3473,15 +4109,28 @@
},
"ledger-shared": {
"title": "ledger-shared",
- "version": "v1.5",
- "revision": 5,
- "lastUpdated": "2026-07-16T01:00:00.000Z",
- "contentHash": "b054a507022e66542500e71a659ba63e7f0011658bf8ed3ff3f8912eb8f036c5",
+ "version": "v1.6",
+ "revision": 6,
+ "lastUpdated": "2026-07-18T04:30:15.800Z",
+ "contentHash": "cc964f24cd8ed59fec05c5f52ddee558bdceeae54b03f272d9f2364788cfd42e",
"trackedFiles": [
"DESIGN.md",
"styles/ledger-page.css"
],
"changelog": [
+ {
+ "version": "v1.6",
+ "date": "2026-07-18",
+ "time": "12:30",
+ "summary": "台账共享样式微调,对齐筛选与列表密度",
+ "files": [
+ "DESIGN.md",
+ "styles/ledger-page.css"
+ ],
+ "details": [
+ "ledger-page.css 小幅样式调整"
+ ]
+ },
{
"version": "v1.5",
"date": "2026-07-16",
@@ -3699,11 +4348,11 @@
]
},
"oneos-h5-h2-order": {
- "title": "加氢订单",
- "version": "v1.18",
- "revision": 18,
- "lastUpdated": "2026-07-17T09:27:10.428Z",
- "contentHash": "52cde05edabca23007e9e1c5f3e17c7c61e342c688bc2dee4581b31df76c1411",
+ "title": "加氢记录(H5)",
+ "version": "v1.23",
+ "revision": 23,
+ "lastUpdated": "2026-07-18T04:30:15.800Z",
+ "contentHash": "f8635009e1ef7839b558004c630e4e9a00f87dc6e6f43f454e5b136bc2828753",
"trackedFiles": [
".spec/2026-07-14-implementation-plan.md",
".spec/2026-07-14-requirements-design.md",
@@ -3736,6 +4385,110 @@
"utils/vehicle-mileage.ts"
],
"changelog": [
+ {
+ "version": "v1.23",
+ "date": "2026-07-18",
+ "time": "12:30",
+ "summary": "加氢记录(H5):站端写入标注来源,手工台账说明同步",
+ "files": [
+ ".spec/2026-07-14-implementation-plan.md",
+ ".spec/2026-07-14-requirements-design.md",
+ ".spec/feature-create.md",
+ ".spec/feature-detail.md",
+ ".spec/feature-list.md",
+ ".spec/feature-manual-ledger.md",
+ ".spec/fleet-plate-tag.md",
+ ".spec/prototype-comments.json",
+ ".spec/reconcile-linkage.md",
+ ".spec/requirements-prd.md",
+ "components/CreateWizard.tsx",
+ "components/DateTimePickerSheet.tsx"
+ ],
+ "details": [
+ "upsert 写入 recordSource=station(站端上传)",
+ "手工台账规格与详情展示小幅同步"
+ ]
+ },
+ {
+ "version": "v1.22",
+ "date": "2026-07-18",
+ "time": "10:36",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/2026-07-14-implementation-plan.md",
+ ".spec/2026-07-14-requirements-design.md",
+ ".spec/feature-create.md",
+ ".spec/feature-detail.md",
+ ".spec/feature-list.md",
+ ".spec/feature-manual-ledger.md",
+ ".spec/fleet-plate-tag.md",
+ ".spec/prototype-comments.json",
+ ".spec/reconcile-linkage.md",
+ ".spec/requirements-prd.md",
+ "components/CreateWizard.tsx",
+ "components/DateTimePickerSheet.tsx"
+ ]
+ },
+ {
+ "version": "v1.21",
+ "date": "2026-07-18",
+ "time": "10:36",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/2026-07-14-implementation-plan.md",
+ ".spec/2026-07-14-requirements-design.md",
+ ".spec/feature-create.md",
+ ".spec/feature-detail.md",
+ ".spec/feature-list.md",
+ ".spec/feature-manual-ledger.md",
+ ".spec/fleet-plate-tag.md",
+ ".spec/prototype-comments.json",
+ ".spec/reconcile-linkage.md",
+ ".spec/requirements-prd.md",
+ "components/CreateWizard.tsx",
+ "components/DateTimePickerSheet.tsx"
+ ]
+ },
+ {
+ "version": "v1.20",
+ "date": "2026-07-18",
+ "time": "10:33",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/2026-07-14-implementation-plan.md",
+ ".spec/2026-07-14-requirements-design.md",
+ ".spec/feature-create.md",
+ ".spec/feature-detail.md",
+ ".spec/feature-list.md",
+ ".spec/feature-manual-ledger.md",
+ ".spec/fleet-plate-tag.md",
+ ".spec/prototype-comments.json",
+ ".spec/reconcile-linkage.md",
+ ".spec/requirements-prd.md",
+ "components/CreateWizard.tsx",
+ "components/DateTimePickerSheet.tsx"
+ ]
+ },
+ {
+ "version": "v1.19",
+ "date": "2026-07-18",
+ "time": "10:33",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/2026-07-14-implementation-plan.md",
+ ".spec/2026-07-14-requirements-design.md",
+ ".spec/feature-create.md",
+ ".spec/feature-detail.md",
+ ".spec/feature-list.md",
+ ".spec/feature-manual-ledger.md",
+ ".spec/fleet-plate-tag.md",
+ ".spec/prototype-comments.json",
+ ".spec/reconcile-linkage.md",
+ ".spec/requirements-prd.md",
+ "components/CreateWizard.tsx",
+ "components/DateTimePickerSheet.tsx"
+ ]
+ },
{
"version": "v1.18",
"date": "2026-07-17",
@@ -4272,30 +5025,89 @@
},
"recentUpdates": [
{
- "prototypeId": "xll-miniapp",
- "title": "小羚羚小程序",
- "version": "v1.1",
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.80",
"date": "2026-07-18",
- "time": "10:26",
- "summary": "完善小羚羚小程序待办分区与交车连拍交互,并同步 PRD V1.3.2 与侧栏结构。",
+ "time": "12:30",
+ "summary": "加氢记录:日统计默认收起,来源标签/变更日志/核对人与对账人,筛选规范对齐",
+ "details": [
+ "每日统计默认收起为一行 KPI,展开后才显示 7 日卡片,优先露出列表",
+ "车牌附来源标签:站端上传 / 羚牛上传;操作更多含变更日志",
+ "核对时间后增核对人,对账时间后增对账人;导出列同步",
+ "补齐 record-source-changelog 规格与 PRD/标注"
+ ],
"files": [
- "index.tsx",
- "annotation-source.json",
- ".spec/authorized-person.md",
".spec/prototype-comments.json",
- "PRD-00-小程序总览.md",
- "PRD-02-交车说明.md",
- "sidebar-tree.json",
- "client.json"
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/record-source-changelog.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.18",
+ "date": "2026-07-18",
+ "time": "12:30",
+ "summary": "车辆氢费明细:来源标签、核对人/对账人与行级变更日志",
+ "details": [
+ "车牌下方标注站端上传/羚牛上传",
+ "完成核对写入核对人;对账单提交写入对账人",
+ "变更日志同步行级 changeLogs,弹窗展示时间/操作人/修改项/原值/新值"
+ ],
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "oneos-h5-h2-order",
+ "title": "加氢记录(H5)",
+ "version": "v1.23",
+ "date": "2026-07-18",
+ "time": "12:30",
+ "summary": "加氢记录(H5):站端写入标注来源,手工台账说明同步",
+ "details": [
+ "upsert 写入 recordSource=station(站端上传)",
+ "手工台账规格与详情展示小幅同步"
+ ],
+ "files": [
+ ".spec/2026-07-14-implementation-plan.md",
+ ".spec/2026-07-14-requirements-design.md",
+ ".spec/feature-create.md",
+ ".spec/feature-detail.md",
+ ".spec/feature-list.md",
+ ".spec/feature-manual-ledger.md",
+ ".spec/fleet-plate-tag.md",
+ ".spec/prototype-comments.json",
+ ".spec/reconcile-linkage.md",
+ ".spec/requirements-prd.md",
+ "components/CreateWizard.tsx",
+ "components/DateTimePickerSheet.tsx"
]
},
{
"prototypeId": "vehicle-management",
"title": "车辆资产",
- "version": "v1.7",
+ "version": "v1.11",
"date": "2026-07-18",
- "time": "10:21",
- "summary": "更新需求说明与标注",
+ "time": "12:30",
+ "summary": "车辆管理:筛选占位符与日期区间对齐全局设计规范",
+ "details": [
+ "DateRangeFilterField 与 filter placeholder 统一 0.875rem / muted-soft",
+ "对齐 global-design-spec §4.1 更多筛选与日期区间规则"
+ ],
"files": [
".spec/prototype-comments.json",
".spec/prototype-review.md",
@@ -4312,774 +5124,642 @@
]
},
{
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.27",
- "date": "2026-07-17",
- "time": "17:43",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.26",
- "date": "2026-07-17",
- "time": "17:41",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.25",
- "date": "2026-07-17",
- "time": "17:41",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.24",
- "date": "2026-07-17",
- "time": "17:41",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.23",
- "date": "2026-07-17",
- "time": "17:40",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.22",
- "date": "2026-07-17",
- "time": "17:40",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.21",
- "date": "2026-07-17",
- "time": "17:39",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.20",
- "date": "2026-07-17",
- "time": "17:39",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.19",
- "date": "2026-07-17",
- "time": "17:38",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.18",
- "date": "2026-07-17",
- "time": "17:37",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.17",
- "date": "2026-07-17",
- "time": "17:37",
- "summary": "对账单仅纳入已核对氢费明细",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.16",
- "date": "2026-07-17",
- "time": "17:37",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/dispenser-brand.md",
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- ".spec/statement-verified-filter.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.18",
- "date": "2026-07-17",
- "time": "17:27",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.17",
- "date": "2026-07-17",
- "time": "17:27",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.16",
- "date": "2026-07-17",
- "time": "17:26",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.15",
- "date": "2026-07-17",
- "time": "17:26",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.14",
- "date": "2026-07-17",
- "time": "17:26",
- "summary": "更新 demo-photo.ts",
- "files": [
- "utils/demo-photo.ts"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.13",
- "date": "2026-07-17",
- "time": "17:26",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.12",
- "date": "2026-07-17",
- "time": "17:25",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.11",
- "date": "2026-07-17",
- "time": "17:23",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.10",
- "date": "2026-07-17",
- "time": "17:23",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.9",
- "date": "2026-07-17",
- "time": "17:21",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.15",
- "date": "2026-07-17",
- "time": "17:20",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.14",
- "date": "2026-07-17",
- "time": "17:20",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.13",
- "date": "2026-07-17",
- "time": "17:19",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.8",
- "date": "2026-07-17",
- "time": "17:19",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.7",
- "date": "2026-07-17",
- "time": "17:19",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
+ "prototypeId": "ledger-shared",
+ "title": "ledger-shared",
"version": "v1.6",
- "date": "2026-07-17",
- "time": "17:19",
- "summary": "更新需求说明与标注",
+ "date": "2026-07-18",
+ "time": "12:30",
+ "summary": "台账共享样式微调,对齐筛选与列表密度",
+ "details": [
+ "ledger-page.css 小幅样式调整"
+ ],
"files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
+ "DESIGN.md",
+ "styles/ledger-page.css"
]
},
{
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.5",
- "date": "2026-07-17",
- "time": "17:19",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/2026-07-14-implementation-plan.md",
- ".spec/2026-07-14-requirements-design.md",
- ".spec/feature-create.md",
- ".spec/feature-detail.md",
- ".spec/feature-list.md",
- ".spec/feature-manual-ledger.md",
- ".spec/fleet-plate-tag.md",
- ".spec/prototype-comments.json",
- ".spec/reconcile-linkage.md",
- ".spec/requirements-prd.md",
- "components/CreateWizard.tsx",
- "components/DateTimePickerSheet.tsx"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.4",
- "date": "2026-07-17",
- "time": "17:18",
- "summary": "更新 vehicle-mileage.ts",
- "files": [
- "utils/vehicle-mileage.ts"
- ]
- },
- {
- "prototypeId": "oneos-h5-h2-order",
- "title": "加氢订单",
- "version": "v1.3",
- "date": "2026-07-17",
- "time": "17:18",
- "summary": "更新 photo-watermark.ts",
- "files": [
- "utils/photo-watermark.ts"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.12",
- "date": "2026-07-17",
- "time": "16:27",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.11",
- "date": "2026-07-17",
- "time": "16:27",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.10",
- "date": "2026-07-17",
- "time": "16:26",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.9",
- "date": "2026-07-17",
- "time": "16:26",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
+ "prototypeId": "oneos-prototype-nav",
+ "title": "oneos-prototype-nav",
"version": "v1.8",
- "date": "2026-07-17",
- "time": "16:26",
- "summary": "更新需求说明与标注",
+ "date": "2026-07-18",
+ "time": "12:30",
+ "summary": "同步本版加氢链路更新日志与导航:H5 更名、审批中心、下线合同模板",
+ "details": [
+ "侧栏/菜单:加氢订单更名为加氢记录(H5);新增审批中心;移除合同模板入口",
+ "写入加氢记录/氢费明细/H5/车辆管理本版变更说明到导航变更日志"
+ ],
"files": [
- ".spec/period-end-balance.md",
".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
"index.tsx",
- "pages/03-站点信息.jsx"
- ]
- },
- {
- "prototypeId": "oneos-web-h2-station-site",
- "title": "站点信息",
- "version": "v1.7",
- "date": "2026-07-17",
- "time": "16:25",
- "summary": "更新需求说明与标注",
- "files": [
- ".spec/period-end-balance.md",
- ".spec/prototype-comments.json",
- ".spec/prototype-review.md",
- ".spec/requirements-prd-kpi-balance-alert.md",
- ".spec/requirements-prd-list.md",
- ".spec/requirements-prd-statement.md",
- ".spec/requirements-prd.md",
- ".spec/requirements.md",
- "index.tsx",
- "pages/03-站点信息.jsx"
+ "nav-data.ts",
+ "style.css",
+ "xll-nav-menu.json",
+ "xll-nav-source.json"
]
},
{
"prototypeId": "oneos-web-h2-station",
"title": "加氢记录",
+ "version": "v1.79",
+ "date": "2026-07-18",
+ "time": "11:46",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/record-source-changelog.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.78",
+ "date": "2026-07-18",
+ "time": "11:46",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/record-source-changelog.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.17",
+ "date": "2026-07-18",
+ "time": "11:44",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.16",
+ "date": "2026-07-18",
+ "time": "11:44",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.15",
+ "date": "2026-07-18",
+ "time": "11:43",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.14",
+ "date": "2026-07-18",
+ "time": "11:43",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.13",
+ "date": "2026-07-18",
+ "time": "11:43",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
"version": "v1.12",
- "date": "2026-07-17",
- "time": "16:24",
+ "date": "2026-07-18",
+ "time": "11:43",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.11",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.10",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.9",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.8",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "vehicle-h2-fee-ledger",
+ "title": "车辆氢费明细",
+ "version": "v1.7",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/PRD.md",
+ ".spec/prototype-comments.json",
+ ".spec/verify-reconcile.md",
+ "globals.ts",
+ "H2LedgerPage.jsx",
+ "index.tsx"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.77",
+ "date": "2026-07-18",
+ "time": "11:42",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.76",
+ "date": "2026-07-18",
+ "time": "11:41",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.75",
+ "date": "2026-07-18",
+ "time": "11:41",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.74",
+ "date": "2026-07-18",
+ "time": "11:41",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.73",
+ "date": "2026-07-18",
+ "time": "11:41",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.72",
+ "date": "2026-07-18",
+ "time": "11:41",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.71",
+ "date": "2026-07-18",
+ "time": "11:40",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.70",
+ "date": "2026-07-18",
+ "time": "11:40",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.69",
+ "date": "2026-07-18",
+ "time": "11:31",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.68",
+ "date": "2026-07-18",
+ "time": "11:31",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.67",
+ "date": "2026-07-18",
+ "time": "11:29",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.66",
+ "date": "2026-07-18",
+ "time": "11:29",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.65",
+ "date": "2026-07-18",
+ "time": "11:28",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.64",
+ "date": "2026-07-18",
+ "time": "11:28",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.63",
+ "date": "2026-07-18",
+ "time": "11:27",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.62",
+ "date": "2026-07-18",
+ "time": "11:27",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.61",
+ "date": "2026-07-18",
+ "time": "11:27",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.60",
+ "date": "2026-07-18",
+ "time": "11:24",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.59",
+ "date": "2026-07-18",
+ "time": "11:24",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.58",
+ "date": "2026-07-18",
+ "time": "11:22",
+ "summary": "更新需求说明与标注",
+ "files": [
+ ".spec/prototype-comments.json",
+ ".spec/prototype-review.md",
+ ".spec/record-data-model.md",
+ ".spec/requirements-prd.md",
+ ".spec/ui-review.md",
+ "index.tsx",
+ "pages/02-加氢记录.jsx",
+ "pages/README.md",
+ "styles/h2-station-vm-filter.css"
+ ]
+ },
+ {
+ "prototypeId": "oneos-web-h2-station",
+ "title": "加氢记录",
+ "version": "v1.57",
+ "date": "2026-07-18",
+ "time": "11:22",
"summary": "更新需求说明与标注",
"files": [
".spec/prototype-comments.json",
diff --git a/src/prototypes/oneos-prototype-nav/xll-nav-menu.json b/src/prototypes/oneos-prototype-nav/xll-nav-menu.json
index 05b88de..894d18d 100644
--- a/src/prototypes/oneos-prototype-nav/xll-nav-menu.json
+++ b/src/prototypes/oneos-prototype-nav/xll-nav-menu.json
@@ -1,6 +1,6 @@
{
"version": 1,
- "updatedAt": "2026-07-18T02:26:51.884Z",
+ "updatedAt": "2026-07-18T02:52:26.271Z",
"title": "小羚羚",
"sectionId": "folder-prototypes-xll-miniapp",
"description": "氢能车辆运营移动端原型;菜单与小羚羚「小程序」项目目录同步。",
diff --git a/src/prototypes/oneos-web-contract-template/index.tsx b/src/prototypes/oneos-web-contract-template/index.tsx
deleted file mode 100644
index 68783a9..0000000
--- a/src/prototypes/oneos-web-contract-template/index.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * @name 合同模板管理
- * 自 ONE-OS web端 原稿复刻(1 个页面)
- */
-import '../../common/oneosWebLegacy/legacyGlobals';
-import React from 'react';
-import '../vehicle-management/style.css';
-import Page1 from './pages/01-合同模板管理.jsx';
-import { OneosWebLegacyShell } from '../../common/oneosWebLegacy/OneosWebLegacyShell';
-
-const pages = [
- { id: 'u5408u540cu6a21u677fu7ba1u7406', title: '合同模板管理', component: Page1 },
-];
-
-export default function OneosWebContractTemplate() {
- return (
-
- );
-}
diff --git a/src/prototypes/oneos-web-contract-template/pages/01-合同模板管理.jsx b/src/prototypes/oneos-web-contract-template/pages/01-合同模板管理.jsx
deleted file mode 100644
index 3c6762b..0000000
--- a/src/prototypes/oneos-web-contract-template/pages/01-合同模板管理.jsx
+++ /dev/null
@@ -1,2362 +0,0 @@
-// AUTO-GENERATED V26.5 Word HTML
-var V265_LEASE_DOCUMENT_HTML = `
商用车租赁合同
合同编号:【LNZLHT {{contractCode}} 】
甲方(出租方):{{lessorName}} (盖章) | 乙方(承租方):{{customerName}} (盖章) |
签订日期: 年 月 日 | 签订日期: 年 月日 |
(正文部分)
本合同经双方平等自愿协商,根据《中华人民共和国民法典》及相关法规,就甲方向乙方提供氢燃料电池车租赁服务之事宜,达成如下一致条款,以资共同遵守。
第一条 租赁标的、服务内容、租期、里程
租赁标的:租赁车辆信息及租金价格、保证金标准详见《租赁订单》(附件1)。
1.2 服务内容:甲方根据乙方的需求,为乙方提供符合约定的商用车供乙方合法使用,并提供有偿非车辆质量问题导致的车辆故障、事故救援服务。
1.3 租期:以双方签订的《租赁订单》(附件1)为准。约定的租期届满,若双方对租赁订单的内容没有变更,且任何一方未提出终止合同的,租赁期限顺延,顺延的期限与本次租赁订单的期限相同。若租赁订单内容有变更,双方签署新的《租赁订单》,租金价格、租期等相关内容,以新的《租赁订单》为准,《租赁订单》未约定的内容,仍以本合同的约定为准。
1.4 里程:乙方承诺按如下约定完成公里数(请在方框里用“√”进行选择。)
1.4.1 Ρ每月完成【 】公里;
1.4.2 ≤每季度完成【 】公里。
若乙方未完成本合同中约定的里程,甲方有权将车辆强制收回,甲方不承担违约责任。
第二条 租金、费用及支付
2.1 租金的结算及支付
2.1.1 租金、服务费先付后用,每【 】个自然月为一个付款周期,每个付款周期末月的25日向甲方支付下个周期的租金和服务费,如25日为节假日的,付款日顺延至节假日后的第一个工作日。
2.1.2 保证金和首期租金及服务费支付:①提车日为当月15日前(含15日)的,于提车前2日内支付保证金和当月剩余天数租金及服务费,当月25日支付下个付款周期的租金及服务费;②提车日为当月15日后的,于提车前2日内支付保证金和当月实际剩余天数和下个付款周期的租金及服务费。
2.1.3 提车或还车当月的租金及服务费,以当月实际租赁天数按比例计算,计算公式如下:【(月租金+月服务费)/30】*当月实际租赁天数支付(金额取数按四舍五入取整到单位“元”)。
2.1.4 租赁期间非因车辆自身质量原因造成的租赁车辆无法上路、无法使用等情况的,乙方仍应按本合同约定支付租金及服务费。包括本条2.3.1中约定的其他费用。
2.1.5租金减免条件:
2.1.5.1基础减免:当月行驶里程达到6000公里及以上的,次月可享受2000元/辆的租金减免,当月行驶里程未达6000公里的,次月不享受租金减免。
2.1.5.2里程补足与累计:次月行驶里程可用于补足上月(截至2026年5月31日之前的月份)未达6000公里的差额部分,补足后可补享上月对应的租金减免,当月行驶里程超过6000公里的部分,可累计计入次月里程。
2.1.5.3连续周期减免:若连续两个月累计行驶里程达到12000公里,该两个月均能享受租金减免。
2.1.5.4持续达标减免:若租赁期间每月行驶里程均满6000公里,可每月享受次月2000元/辆的租金减免(若租期为1年,第12个月里程达标对应的减免,在第13个月租金结算时执行)。
本租金减免政策有效期至2026年12月31日止。
2.2 氢气费(含加氢相关服务费)
2.2.1 氢气原则上由乙方自行解决。如需甲方安排加氢的,先款后货、全额预付款支付及结算。乙方提前预估当月用气总量并计算氢气费用后将氢气预付款【 】元提前【 】个工作日内转账给甲方,甲方在收到乙方预付款后安排加氢。乙方预付款不足【 】元时,乙方接到甲方通知后2个工作日内支付预付款;否则,甲方有权不予安排车辆加氢气,由此造成的一切损失由乙方承担,给甲方造成损失的,乙方还应承担赔偿责任。
2.2.3每月25日核对上月25日至本月24日的用气对账单,有异议2个工作日内提出,双方重新核对账单,账单核对无误后,对核对无误的账单书面确认。
2.2.4 氢气价格按市场价随行就市调整。
2.2.5 乙方还车时车里剩余氢气量若低于交车时的氢气量,则按照【 】元/公斤向甲方支付氢气费,若高于交车时的氢气量,乙方同意甲方不向乙方返还氢气费。
2.2.6 租赁车辆充电产生的电费及与充电相关的费用由乙方承担。租赁车辆原则上优先选择甲方经营的充电桩充电,若选择甲方经营的充电桩充电,费用结算方式为现结。
2.3 其他费用
2.3.1 租赁期间车辆产生的其他费用,包括但不限于非质量问题产生的车辆维修费、保养费、违章费用、施救费、证照补办费用、改装费、违约金、能耗费、路桥费及乙方要求增加购买其他保险的费用等,均由乙方全额另行承担。
2.4 垫付费用:本合同中若甲方垫付费用的,乙方应在甲方通知后【3】个工作日内一次性足额支付给甲方。
2.5 甲方收款账户
2.5.1乙方应将上述租金、服务费、保证金、氢气费及其他费用统一汇入甲方如下指定账户,否则视为未支付:
户 名:【{{lessorAccountName}}】
开户行:【{{lessorBankName}} 】
账 号:【{{lessorBankAccount}} 】
2.5.2 本合同所涉及的所有费用均通过银行转账的方式支付至甲方上述指定账户。甲方不会以任何方式允许甲方人员通过个人账户收取本合同所涉及的各项费用,若甲方人员要求将本合同项下产生的各项费用汇至其个人账户或其他账户,乙方可拨打甲方24小时服务热线:400-021-1773。
2.5.3 乙方将本合同所涉及的费用汇入甲方指定上述收款账户之外的任何账户导致的损失,由乙方自行承担,同时乙方仍须按本合同约定向甲方支付各项费用。
2.6 发票
2.6.1 乙方开票信息如下:
企业名称:
开户银行:
银行账号:
纳税人识别号:
企业地址:
企业电话:
2.6.2甲方收到乙方支付的租金和服务费后分别开具等额的增值税发票。若乙方变更开票信息,乙方需在付款周期15日前书面告知甲方,否则所产生的损失由乙方承担。若国家发布新的税收政策导致税率变化,甲方按最新政策开具发票,乙方支付的总价款不变。
2.6.3 甲方除开具租金和服务费发票外,本合同中的其他费用,甲方不向乙方开具对应的服务费发票。
2.7 乙方款项抵扣
乙方应及时足额地支付租赁费、服务费、保证金以及其他应当由乙方承担的各项费用;乙方存在任何应付未付费用时,甲方有权从保证金、应返还乙方的保险理赔款以及乙方在甲方处的其他款项中先行抵扣,不足部分,乙方应及时补足。
2.8 碳资产
本合同约定仅限于车辆使用,该车辆所产生的碳资产数据权益和碳资产收益归甲方所有,本合同报价不含减碳、碳资产管理费用等。
第三条 交车与还车
3.1 本合同签署前,乙方需提供如下有效证据资料:包括但不限于营业执照、法定代表人身份证复印件、驾驶员驾驶证、驾驶员从业资格证等。复印件留存甲方,原件查验后退回。
3.2 租赁车辆交付时,乙方应对租赁车辆状况及附属设施、有效证件标志进行现场检验,确认无误后应在《交接车验收清单》上签字/盖章确认。提车后,非车辆质量问题产生的一切风险由乙方承担。
3.3 还车时,乙方负责将租赁车辆归还至甲方指定的还车地点。 乙方还车时,应携带提车时签订的《交接车验收清单》,经甲方检查车辆确认无误后,双方签署《交接车验收清单》,确认还车。
3.4 返还车辆除正常使用耗损外,车辆信息与《交接车验收清单》保持一致,无任何毁损,证照齐全,无未处理交通违章、交通事故等不存在未决纠纷争议可能影响甲方利益情形。否则,甲方有权拒绝接收车辆,乙方应在限期内整改,整改期内日租金按两倍日租金标准继续计算,直至车辆符合交还标准;如乙方拒绝或超过十五天仍未完成整改的,甲方有权强制收回车辆并送至修理厂进行修复或调整,因此产生的运输费、修理费等费用以及处理交通违章、事故等发生的一切费用,均由乙方全额承担。
第四条 车辆的风险与管理
4.1 车辆自交付乙方之时起,车辆发生损毁、灭失、被盗、遗失等风险的,由乙方承担。乙方应赔偿甲方全部损失,但该损失是因车辆自身质量问题导致的除外。租赁期间,因租赁车辆引发的甲方、乙方、乙方聘用人员或第三者损失的,乙方应承担全额赔偿责任。
4.2 车辆自交付乙方之时起,乙方负责车辆相关安全保管义务和日常管理,乙方应在本合同约定的使用区域内使用车辆,使用车辆时应符合国家、地方的相关法律法规、规章制度,遵守交通规则,禁止超速、超载,禁止装载易燃易爆、易腐蚀等危险物品及在车中留下刺激性气味的物品。
4.3 租赁期间,乙方装载4.2条中禁止装载的物品,或车辆发生交通事故或其他安全、意外事故,造成甲方、乙方、第三方财产损失或人身损害、车辆损失、设备损失,或导致包括但不限于有关部门的罚金或罚分、行政处罚等一切责任的,均由乙方承担全部责任。给甲方造成的损失或者导致甲方承担责任的,乙方除承担本条前述的全部责任外,还须承担甲方的间接损失、可得利益等。如导致甲方赔偿的,甲方有权向乙方追偿。
4.4 租赁车辆的车身外观、车身广告等权益由甲方享有,未经甲方书面同意,乙方不得擅自更改车身外观,增加车身广告等。否则必须恢复车辆原状,若未恢复的,根据实际发生的费用向甲方支付修复费用,此费用甲方有权从保证金中直接扣除,不足部分,另行向甲方支付。
4.5 无论乙方自身运营或聘用他人运营标的车辆,乙方承诺自身或聘用第三人具备运营车辆的全部证照,乙方对聘用人员证照负有审核义务,证照包括但不限于营业执照、组织机构代码、车辆驾驶人员驾驶证、身份证、道路运输许可证(如进行营运的)、运输人员从业资格证等,乙方对证照的真实性、有效性以及完整性负责,并就该第三人驾驶或使用标的车辆的行为所产生的一切法律责任承担无限连带责任,如导致甲方赔偿的,甲方有权向乙方追偿。在签订合同时,乙方应向甲方出示原件并提供全部证照复印件备案,如驾驶人员发生变更的,乙方应在变更前将全部证照提供给甲方备案。
4.6 未经甲方书面同意,乙方不得将租赁车辆以转让、出借、转租、合租等任何方式许可任何第三方使用,不得设立任何形式抵押、留置、质押等权利负担,不得擅自改装(安装)车辆或拆除车辆设施、设备、标记、广告等,不得拆卸、更换车辆零部件,不得将车辆的行驶证件及相关手续、车辆号牌以任何方式许可第三方使用。
第五条 车辆的维修、保养
5.1 租赁期间,乙方应按照驾驶技术规范及该车使用说明书等规定的要求使用、保养车辆,坚持“三检三查”制,确保车辆技术状况符合规范和要求。甲方有权对车辆的技术状况进行定期或不定期的检查,并根据检查情况要求乙方修复。
5.2 乙方应每天对刹车油、防冻液、刹车片、轮胎、轮胎气压、灯光等做常规检查,如发现问题,应及时到甲方指定的维修站进行维修,并及时向甲方报备维修情况。
5.3 租赁期间,租赁车辆损坏的,乙方应在甲方指定维修站对车辆进行维修、保养,将车辆修复至符合有关技术规范标准的状态,费用由乙方全额承担,并在3日内通知甲方,将维修、保养相关单据的原件交回甲方留存。如需在指定维修站以外维修、保养车辆的,应征得甲方书面同意,否则属于乙方违约,乙方应按2000元/次的标准向甲方支付违约金。
5.4 租赁期间,乙方应负责保管车辆及GPS等设施设备,进行定期或不定期的检修、检测,确保其性能可靠、使用正常。如造成车辆及设施设备损坏、过度磨损或遗失、损毁、失效的,由乙方负责照价赔偿甲方。
5.5 乙方另行购买甲方维保服务的,甲方所提供维保服务仅限车辆日常的技术指导、使用培训、易损件的维修更换服务,不含车辆维修等其他服务。
5.6 非因车辆自身质量问题产生的车辆维修费用及拖车费由乙方全额承担。费用以维修站的价格为准。
5.7 因发生车辆故障、交通事故等情形,甲乙双方对是否属于车辆质量缺陷导致、车损价值等无法达成一致意见的,双方可委托共同认可的第三方机构进行评估、鉴定。鉴定、评估前费用由双方共同平均分担,评估后鉴定结果属于甲方全部或部分责任的,鉴定、评估费由甲方全部或部分承担,甲方应向乙方支付乙方承担的全部或部分鉴定、评估费;不属于甲方责任或属于甲方部分责任的,鉴定、评估费由乙方全部或部分承担,乙方应向甲方支付甲方先行承担的全部或部分鉴定费、评估费。乙方未响应甲方办理评估、鉴定委托事宜通知的,甲方可单方委托第三方机构进行评估鉴定。
第六条 保险、事故、动态违规及违章处理
6.1 甲方负责的保险
6.1.1 若租金中已含租赁车辆的交强险及商业险(包括三者险、车损险)保险费用,乙方对甲方所投保险险种及保额没有异议。如乙方要求增加险种或提高保险额度的,乙方应在租金标准外另行向甲方支付保险费用,由甲方负责向甲方合作的保险服务商购买保险。
6.1.2 若租金中不包含租赁车辆的交强险或商业险保险费用,乙方需按照甲方要求的保险险种委托甲方代为购买,乙方应另行向甲方支付保险费用。若标的车辆保险费用已经由甲方先行购买的,乙方应将相应保险费用支付给甲方。如遇租期内续保,乙方应在甲方通知后【3】个工作日内将相应保险费用支付给甲方。
6.2 乙方负责的保险
6.2.1 汽车车上人员责任保险(驾驶员、车上其他人员)由乙方购买:乙方应为使用该车辆的驾驶员及车上其他人员购买责任保险,租赁期内所发生的与乙方驾驶员及车上其他人员相关的一切财产、人身损失等由乙方承担,若给甲方造成损失的,乙方需向甲方承担赔偿责任。
6.2.2 货物保险:乙方应自行购买货物运输相关保险,并自行承担所有管货责任。租赁期内,无论何种原因导致乙方货物毁损、灭失、污染、变质、损耗、短少等异常情况,甲方均免责。乙方投保时,亦应向保险人要求豁免甲方责任,即使货物异常是由于甲方车辆问题所致,甲方亦不承担任何赔偿责任。
6.3 事故报告
6.3.1在租赁期内,车辆发生安全事故的,乙方应在1小时内如实报告公安交通管理机关、甲方和甲方安全部及保险公司,并配合甲方处理,且到甲方指定的维修站进行维修,若乙方隐瞒事故真实情况、虚构事故情况等或未在甲方指定维修站进行维修的,需向甲方承担3000元/次/辆违约金。当需要办理保险理赔事项时,乙方应协助甲方办理保险理赔手续,因协助办理所产生的费用由乙方承担,若不配合甲方处理安全事故或者不协助办理保险理赔事项的,须向甲方承担500元/次/辆违约金。本条项下全部应付违约金,统一并入下一租金付款周期同步结算。
6.3.2 如乙方怠于履行本合同约定义务导致无法办理保险理赔或保险公司拒赔、免赔的,全部损失和法律责任由乙方承担,造成甲方或第三方损失的,乙方应予以赔偿。
6.4 出险
6.4.1 租赁期间,如车辆发生安全事故造成损失超出保险公司赔付金额的,超出部分的损失由乙方全额承担。
6.4.2 租赁期间,租赁车辆出险并办理保险理赔的,乙方应每次向甲方支付保险上浮费,18吨车型主责及以上责任为3000元/次/辆,其他责任为2000元/次/辆(驾驶员无责除外)。如乙方自车辆出险之日起 5个工作日内未向甲方支付上述保险上浮费,则甲方有权直接从车损险理赔款项中扣除对应的保险上浮费,若车损险理赔款项不足以覆盖乙方应向甲方支付的保险上浮费,差额部分乙方须于下一租金支付周期内,连同当期租金及其他应付费用一并结清。
6.4.3 乙方出险进保,应征得甲方书面同意。如事故损失总金额不满足甲方进保理赔标准的(2000元里面不允许进保,),由乙方向甲方报备后自行到甲方指定维修站维修并由乙方自行承担相应费用,无需办理保险理赔手续。如乙方在未征得甲方书面同意前提下向保险公司报案赔付的,须向甲方承担2000元/次/辆违约金,同时,甲方不向乙方支付任何保险理赔款,若保险理赔款直接打入乙方账户的,乙方需将保险理赔款返还给甲方。
6.4.4 保险上浮费和超出保险公司赔偿的部分,甲方有权从保险理赔款中先行抵扣,如保险理赔款有剩余且应支付给乙方的,在乙方不存在到期应付未付款项时,甲方在收到理赔款后 15个工作日内无息支付给乙方,如保险理赔款直接赔付给第三方的,则乙方应在甲方通知后3个工作日内支付给甲方,且甲方有权从保证金中直接抵扣。
6.4.5 单车事故进保审批
6.4.5.1 租赁期间,因乙方违反限高、限速、限重等交通管理规定或操作规范导致的单车事故,原则上不予办理保险理赔,相关车辆维修、施救等全部费用由乙方自行承担。
6.4.5.2 若乙方因特殊情况申请对本条 6.4.5.1 约定的单车事故进行保险理赔(以下简称 “进保申请”),需向甲方提交书面申请,并附事故现场照片、交警部门出具的事故认定书(如有)、车辆损失评估报告等相关证明材料。
6.4.5.3 甲方收到乙方进保申请后,由甲方在收到材料后【5】个工作日内完成审批并出具意见。
6.4.5.4 仅甲方审批通过,甲方才协助办理理赔,未经审批擅自进保的,乙方支付【2000】元/次辆违约金,且承担全部保险费用及理赔损失。
6.4.5.5 经甲方审批通过的进保,乙方仍需按 6.4.2 条支付保险上浮费,甲方可根据情况要求乙方额外承担评估费、手续费等。
6.5 安全教育
6.5.1 乙方发生交通事故或者安全事故的,甲方有权对乙方及乙方驾驶员进行教育培训。
6.5.2 在租赁期内,若乙方发生一般有责事故及以上事故,乙方必须做到:①查清事故原因;②严肃处理事故责任者;③对车辆事故的驾驶员进行教育培训;④落实防范措施。若甲方做过安全教育培训的,还需向甲方提供安全教育会议内容、安全教育签到表、现场至少三张照片。若乙方未做到前述事项的,须向甲方承担1000元违约金。
6.5.3若乙方发生三次或者三次以上(含三次)以及一个星期连续发生两次及两次以上(含两次)安全事故或者交通事故的,甲方有权对乙方及乙方驾驶员进行安全教育培训,乙方必须参加甲方组织的教育培训活动,乙方接到甲方教育培训未按时参加的,需向甲方承担1000元违约金。如乙方经甲方约谈教育后仍发生事故,视为乙方严重违约,甲方有权单方面无条件强制收回租赁车辆,无需承担任何违约责任。收车过程中产生的拖车费、保管费、运输费、场地占用费等一切相关费用,均由乙方承担;同时,因乙方前述违约行为造成甲方全部损失(含但不限于行政罚款、赔付款项、律师费、诉讼费、保全费、差旅费等),均由乙方全额承担,甲方有权从保证金中直接抵扣,保证金不足以清偿的,甲方有权向乙方继续追偿剩余款项。
6.5.4动态监控违规管理:
6.5.4.1一般违规:租赁期限内,因驾驶员违规行为产生属实动态监控预警风险的,乙方按以下标准承担违约金:首次50元/次,第二次100元/次,第三次及以上违规500元/次,乙方应当在甲方通知违规之日起1个自然日内支付给甲方,逾期未支付的,乙方须在次月车辆租金结算时一并向甲方支付。乙方更换新驾驶员须提前向甲方书面报备,人员更换后违规次数将重新计算。
6.5.4.2 严重违规处置及车辆收回:租赁期限内,车辆因违规导致动态监控风险属实,连续2个月被交管部门通报的,甲方有权要求乙方在第2个自然月底起将车辆停运1个月,停运期间正常计收租金。为避免车辆营运证连续3个月通报导致被注销,乙方须严格遵照甲方停运要求执行,乙方拒不配合停运的,视为严重违约,甲方有权单方无条件强制收回租赁车辆,无需承担任何违约及赔偿责任。若因乙方拒不配合收车、违规持续营运造成车辆营运证被注销的,乙方须全额承担营运证注销后6个月内全部车辆租金。车辆强制收回过程中产生的拖车费、停放保管费、转运费、场地使用费等全部费用均由乙方承担。因乙方前述违约行为给甲方造成的全部损失(含但不限于行政罚款、赔偿金、律师费、诉讼费、保全费、差旅费等),均由乙方全额承担,甲方有权从车辆保证金中直接抵扣,保证金不足以清偿的,甲方有权就剩余差额向乙方另行追偿。
6.6 违章处理
6.6.1车辆发生违法违规的,乙方应及时处理车辆违章并承担处理费用(违章,最晚应在甲方通知后15个自然日内处理完毕)。乙方超过15天未处理的,甲方有权代办处理,并向乙方发送强办告知函,明确强办时间、强办费用,强办处理的收费标准以附件2的约定为准。同时,甲方有权按一条违章信息1200元的标准(广东区域内为2000元/条),向乙方收取违约金;违约金金额不足以覆盖甲方损失时,乙方还应承担赔偿责任。
6.6.2在处理违章过程中,乙方必须遵循如下驾驶证使用限制:车辆租赁期限6个月以下的(含6个月),仅限于一本驾驶证处理违章,租赁期限超过6个月的,仅限于两本驾驶证处理违章,乙方处理违章超过前述限制的,须向甲方承担 5000元/ 次/辆的违约金。租赁满一个记分周期可使用三本驾驶证。
6.7 年检年审配合
6.7.1甲方负责办理车辆年检年审等相关证照手续,乙方应积极配合,在甲方通知的时间内将车辆开到指定地点。乙方完全明白且理解,车辆的年检年审等检验检测工作,是车辆依法、安全运营的基本保障,如乙方未能在甲方通知时间内将车辆开到甲方指定地点,属于乙方严重违约行为,不论最终是否顺利完成相关检验检测手续,乙方均应向甲方支付2000元/次的违约金。
6.7.2车辆年审过程中发现有未处理违章罚分、罚款等,经甲方以口头、电话、短信、微信及其他方式等前述任一方式告知乙方后,乙方在【3】个工作日内仍未履行的,甲方有偿代办处理,代办处理费用同6.6.1条规定。
6.7.3 乙方应按有关规定使用车辆,不得私自改装车辆,如需改装应经甲方同意,保证车辆在年检时符合要求,如年检不合格,乙方应自费维修整改,经维修整改后仍不合格的,乙方应赔偿甲方重新购买同款同型车辆及设施设备的全部费用。如乙方未经甲方同意,私自拆卸、改装车辆核心零部件,视为乙方严重违约,由此产生的一切责任和后果均由乙方承担;如因此造成车辆严重安全隐患,乙方须根据甲方要求,按照该车辆购买价(以发票金额为准)的两倍购买该改装车辆。
6.7.4 租赁期间,车辆相关证照遗失、被盗、毁损的,甲方可以协助补办,乙方应承担补办证照发生的费用(包括但不限于差旅费、工本费、官费等);具体费用标准以附件2约定的为准。在证照办理期间,租赁费用不停止计费。
第七条 调换车辆和备用车辆服务标准
7.1 甲方有权根据实际运营情况,对已经出租给乙方的车辆进行调换,但调换车辆应是同类型车辆,并提前15天通知乙方,若乙方不同意,甲方有权强制收车,终止与乙方的合作,本合同即终止,双方均不承担违约责任。
7.2 在租赁期内,如非因车辆自身质量问题导致维修的,维修期间,乙方可向甲方申请备用车辆,在征得甲方同意后,交付备用车辆供乙方使用,乙方应按照交付车辆类型对应的租金标准另行向甲方支付租金、保险费等租赁费用。
7.3 调换车辆和备用车辆交还车流程参照本合同相应条款的约定。
第八条 违约责任
8.1如乙方违反本合同项下任何约定(含保证人违约),视为乙方违约,乙方应当按照现行法律法规及本合同约定向甲方承担违约责任,且甲方有权采取如下一种或者多种救济措施以维护其权利:
8.1.1要求乙方在5日内补正或采取补救措施,未在5日内整改补正的,甲方有权书面通知乙方单方终止本合同或终止所涉车辆租赁关系。
8.1.2要求乙方赔偿甲方的经济损失。乙方致使甲方承担任何费用、责任或者遭受任何损失的,乙方应就前述任何费用、责任或者损失向甲方进行赔偿,这些费用、损失包括甲方向第三方支付的或导致第三方遭受的赔偿金、违约金等费用及损失。
8.1.3要求乙方承担因乙方行为导致甲方进行各类诉讼或者仲裁而产生的费用,包括但不限于诉讼费、律师费、保全费、公证费、鉴定费、人员工资、差旅费等,且这些费用不应包含在本合同约定的违约金中。
8.2 乙方同意并确认,如乙方违反本合同项下任何一项约定、任何承诺和保证,除本合同另有特别约定外,乙方应按5000元/次的标准向甲方支付违约金。致使甲方承担任何费用、责任或者遭受损失的,乙方应就上述任何费用、责任或者损失(包括但不限于因违约而支付或损失的利息以及律师费)向甲方另行赔偿。
8.3 本合同履行期内,乙方逾期支付租赁费、保证金以及应支付的其他任何费用的,每逾期一日,应向甲方支付应付款项千分之三的违约金,且甲方有权锁车再进行协商处理;超过当期结算日期3天仍未支付相关费用,甲方有权提前终止本合同并强制收回车辆。
8.4 乙方根据法律及本合同约定应向甲方支付费用、赔偿损失或承担其他法律责任,在乙方未能全面履行时,甲方可从保证金中直接进行等额抵扣,不足部分仍由乙方承担,且乙方应在甲方书面通知后3个工作日内补足保证金至本合同约定数额,否则,每逾期1日,乙方每日按照应付未付保证金金额的千分之三向甲方支付违约金。
8.5 在租赁期内,乙方使用标的车辆超载、超速或有其他违反交通规范行为但未造成损失的,法律责任由乙方承担,甲方给予乙方警告处理,后续若拒不纠正再次发生的,乙方应向甲方支付2000元/次违约金,达到提前终止合同条件的,甲方有权提前终止合同并强制收回车辆。
8.6 若因乙方未按1.4条完成里程,造成甲方或车辆厂商不能或未能足额申领国家、地方补贴的,差额部分由乙方负责赔偿给甲方或车辆厂商,导致甲方赔偿的,甲方有权向乙方追偿。
8.7 乙方按照本合同约定向甲方支付违约金的,如同一违约情形下违约金约定不一致的,以约定较高标准的违约金为准,如同一违约情形下设定不同类型违约金的,违约金应累计计算,如违约金不足以弥补甲方损失的,乙方另行向甲方补足。
第九条 合同终止、解除
9.1 因不可抗力或行业主管部门的要求,致使本合同无法继续履行的,甲乙双方均有权提前终止本合同,双方均不承担违约责任,在乙方向甲方结清全部费用后,双方无任何争议,甲方将剩余保证金及租金无息退还乙方。
9.2 因甲方经营状况发生重大变化,致使甲方不能继续从事车辆租赁服务的,甲乙双方均有权提前终止本合同,且双方均不承担违约责任,在乙方归还甲方车辆,向甲方结清全部费用后,甲方应将剩余保证金及租金无息退还乙方。
9.3 经甲乙双方协商一致,本合同可以解除或提前终止。
9.4 在租赁期限内,因乙方行为导致甲方解除或提前终止本合同的,或乙方出现下列情形之一的,甲方有权立即解除或提前终止本合同并强制收回车辆,且乙方应向甲方支付违约金,违约金标准为租赁当年月平均租金总价标准的2倍:
9.4.1利用标的车辆从事违法犯罪活动的,或因涉嫌违法犯罪被采取强制措施或受到行政处罚的;
9.4.2 未按期支付本合同项下的相应费用超过3个工作日的,经甲方催告后仍不支付的;
9.4.3涉酒涉毒驾车、交通事故逃逸、不及时抢救伤员保护现场、谎报或瞒报交通事故的;
9.4.4 擅自将标的车辆转让、转租、转包,或设置抵押、留置、质押等负担,或恶意更换车辆零部件或拆撤、损毁、涂抹车辆设施、设备、标记、广告等的;
9.4.5 标的车辆技术状况经甲方累计3次检查不合格,或经甲方检查不合格要求乙方修复,乙方在3日内拒不修复的;
9.4.6 向甲方提供虚假证件或资料的;
9.4.7 发生3次有责交通事故或单次有重大、特大交通事故的;
9.4.8甲方通知乙方协助办理标的车辆年检手续,乙方不按甲方的要求履行协助义务,导致标的车辆无法年检或年检不合格的;
9.4.9利用标的车辆进行相关法律法规明令禁止的行为,或其他严重影响甲方权益或可能导致甲方损失的行为;
9.4.10 乙方有违反本合同约定导致甲方解除或提前终止本合同的其他情形的。
9.5 租赁期限届满前,乙方提前退租的,则属于乙方严重违约,乙方应按租赁当年月平均租金总价标准的2倍向甲方支付租金补贴,租金补贴甲方有权从乙方保证金中直接抵扣。
9.6 甲方提前解除本合同的,应提前15天书面通知乙方,乙方如有异议的,乙方应在通知送达之日起15日内书面回复,但不影响甲方解除合同的效力。
9.7 本合同中的合同解除、业务终止之标准:甲乙双方在《交接车验收清单》上签字,退车手续办理完毕,乙方处理完所有违章,扣除各种乙方应承担的费用,甲方无息退还保证金。
9.8 乙方若需要办理ETC,由乙方自行办理。合同解除、业务终止后,乙方须先自行注销ETC,再办理退车手续,否则向甲方支付2000元/卡退卡费。
第十条 其他
10.1 关于送达:任何与本合同有关的由一方发送给其他方的通知或其他通讯往来(“通知”)应采用书面形式,按照下列通讯地址或通讯号码或电子邮箱送达被通知人均构成有效通知,包括但不限于法院、仲裁机构的法律文书及双方的来往函件等。
甲方:{{lessorName}}
通讯地址:{{lessorAddress}}
联系人姓名及电话:{{lessorContact}} {{lessorPhone}}
邮箱:{{lessorEmail}}
乙 方 :
通讯地址:
联系人姓名及电话:
邮箱:
10.2 任何一方上述的通讯地址或通知方式发生变化(“变动方”),变动方应当在该变更发生后的七(7)日内通知其他方。变动方因上述地址不明确或未按约定及时通知,导致法院、仲裁机构的法律文书或任一方文件无法送达的,文件退回之日即视为送达之日。甲乙双方确认,前述送达方式适用于各个司法阶段,包括但不限于一审、二审、再审、执行以及督促程序。
10.3 本合同中约定的违约责任、赔偿责任条款以及乙方义务,甲方于订立合同时已提请乙方注意并按乙方要求对该条款予以说明,乙方已充分了解并自愿订立且不再提出违约金、赔偿金过高和义务过多的请求。
10.4 本合同未尽事宜可另行签订补充合同,补充合同与本合同具有同等效力。
10.5 甲、乙双方因履行本合同发生争议,可协商解决,协商不成提起诉讼的,甲乙双方一致同意由合同签订地(浙江省嘉兴市平湖市乍浦镇)人民法院管辖。
10.6 本合同一式两份,甲方持一份,乙方持一份,在甲方盖章,乙方签字(自然人)或盖章后生效,若有保证人,保证人签署本合同及附件《保证人的保证责任》后,对保证人生效。
10.7 本合同所有附件、附表、车辆交接单均是本合同的有效组成部分,与本合同具有同等的法律效力。本合同包括但不限于以下附件:
附件1《租赁订单》、附件2《车辆产生的费用》、附件3《安全责任告知书》、附件4《重型普通货运车辆租赁动态监管责任告知与确认书》、附件5《安全责任承诺书》、附件6《车辆使用规范和驾驶员要求》《授权委托书》《安全责任协议》及其他。
(以下无正文)
附件1:租赁订单 订单编号(LNZLHT )
甲方(出租方): {{lessorName}}
乙方(承租方):
本订单租赁车辆总计辆,合同租金及服务费含税总价为:¥ 元,保证金总计需缴纳¥ 元(若开具保证金收据的,退车时应提交保证金收据原件方可退还保证金),首期租金及服务费含税需支付¥ 元。租赁车辆含保险总计辆,每辆保险险种包含 三者责任险【】万元、车损 ,含通行证总计张。
一、租赁车辆信息
品牌 车型 |
车牌号 | 租金及服务费 小计 (元/ 月/辆,含税) | 价格及服务内容 |
保证金 (元/辆) |
车辆租赁期限 |
车辆租金
(元/月/辆,含税)服务费
(含税)服务内容
车牌号在签约时无法确定的,以实际交付的车牌号为准,若后续需要更换车辆的,均以《交接车验收清单》为准。
二、其他约定:
1.车辆交付(交还)地点: 。车辆交付时间:车辆交付时间: 年 月 日(以实际交付的时间为准)。
2.租赁车辆仅限 行政区域范围内使用,超出前述约定区域范围使用租赁车辆应事先征得甲方书面同意并办理相关手续。
3.甲乙双方协商一致增加租赁车辆的,双方另行制作《租赁订单》,经甲方盖章,乙方签字/盖章后生效。
4 、甲乙双方均认可并接受双方签订的《商用车租赁合同》(合同编号 )全部内容,本租赁订单列明的条款的,按本租赁订单执行,本租赁订单未列明的条款,均按照《商用车租赁合同》执行。
5.甲方有权对租赁车辆进行调换,但应提前15天通知乙方,乙方必须配合。还车、调换车辆时车辆外观、驾驶室、车厢必须保持干净整洁,否则收取清洗费,车身原车广告未经甲方同意不得撕毁、损坏、涂抹,否则承担车辆的修复费。本条中的清洗费,500元/辆,车身修复费,5000元/辆,甲方有权在保证金直接扣除。
6.租赁期内车辆产生的能耗费、停车费等用车费用由乙方承担。
7.本《租赁订单》一式两份,甲方执一份,乙方执一份,在甲方盖章,乙方签字(自然人)或盖章后生效。保证人签字(自然人)或盖章后,对保证人生效。
甲方(签章): |
| 乙方(签字/盖章): |
授权代表: |
| 授权代表: |
签订日期: | 年 月 日 | 签订日期: 年 月日 |
附件2:车辆产生的费用
一、车辆维保、易损件、车辆轮胎、蓄电池及送车上门和上门收车费用:
维保服务 | 易损件 | 轮胎及蓄电池 |
自行承担车辆维保所发生的所有费用 | 自费承担 | 型号:11.00R20 18PR ,自费承担,还车时轮胎每磨损1mm,乙方需向甲方支付【110 】元/毫米的折旧费(计费公式:(交车时轮胎厚度-还车时轮胎厚度)*【mm 】,如乙方在租赁期内更换过轮胎,计算费用为负值的,乙方无需支付费用,甲方也不做任何补偿。)蓄电池,自费承担,每块电池【1200 】元/2年,按照实际租赁时间折算费用。 |
特别说明:1、轮胎、门把手、刹车片等易损件正常磨损达到需更换时客户负责更换,配件、维修工时费乙方自理;2、乙方充分知晓和同意,如果承租的甲方车辆并非全新车辆,或面临车辆租赁后标的车辆配件即过保的情形;3、如乙方未根据下表维护保养标准执行车辆维护工作,造成车辆脱保的,由此给甲方产生的不利影响、额外义务负担、费用损失等均由乙方自行承担。 |
送车上门,上门收车:从出发往返1公里以内免费;往返1公里以上,按8元/公里收费;人工费以实际维修项目算。拖车费:起步价【400】元+【 5】元/公里/空车,起步价【400】元+【15】元/公里/重车;基础服务费为【100 】元/辆/次。材料费以维修站的价格为准,最终以甲方确定的价格为准。 |
二、保养和修复:不论乙方租赁车辆期限长短,乙方确认并同意均按照下述规则维护保养和修复标准执行, 产生的费用按维修站的价格计算,若维修站未确定价格的,参考下表价格执行,最终以甲方确定的价格为准:1、底盘保养
序号区分保养项目周期/万KM型号数量单价次数总价公里要求(万公里)1配件驱动电机、电池冷却液24个月/20万公里重负荷有机乙二醇型冷却液36L1432286202工时501503配件转向器6个月/10万公里8 号液力传动液)及滤芯1.7L251.742.5104工时501505配件新能源法士特、绿控12个月/5万公里GL-5\\85W7L25717556工时501507配件油润滑的中
后桥12个月/10万公里GL-5\\80W-909L29.79267.3108工时501509配件脂润滑的轮边2个月/1.5万公里3#锂脂3KG203601.510工时7517511配件驾驶室举升器6个月/5万公里10 号航空液压油1L30130512工时5015013配件空气干燥器12个月/10万公里科诺尔、威伯科1个18411841014工时3013015配件空气滤清器12个月/4万公里空气滤芯1个1501150416工时3013017配件各类球头2个月/1万公里2号锂基脂751751合计
2.燃料电池保养项目
序号保养配件周期/万KM次数量单价(元,未税)工时【90】元/时公里要求(万公里)1空滤27/1099 4522离子过滤器首次1万KM,之后每次间隔3万KM4/969.5790首次1万,后每次间隔3万3冷却液8万KM140L1664.845 1808三、证照及违章处理等收费标准:如甲方代为处理,乙方应向甲方支付的代处理费计费结构为:(基础费用)+(服务费收费标准),具体如下表:
项目 | 基础费用 | 服务费收费基础 | 服务费/元 |
补办行驶证 | 以实际收费为准 | 每台车每次 | 200 |
补办牌照 | 以实际收费为准 | 每台车每次 | 300 |
补办营运证 | 以实际收费为准 | 每台车每次 | 300 |
补办加氢证 | 以实际收费为准 | 每台车每次 | 300 |
处理违章(罚款) | 实际罚款为准 | 每台车每条 | 100 |
处理违章(罚分) | 实际罚分为准 | 每台车每条 | 100 |
借用备用钥匙 | 送上门,20公里内100元,每超1公里3元每公里,过桥过路费额外收取 | 每台车每次 | 100 |
补配钥匙 | 实际补配价格 | 每台车每次 | 400 |
附件3:安全责任告知书
一、各车辆使用人责任主体:
1.各租赁客户合作伙伴、挂靠我司车辆的用户,当您使用我司车辆期间必须承担安全责任,责任主体是:车辆使用人(公司或个人),挂靠车辆使用人(公司或个人)。
2.根据《中华人民共和国民法典》第一千二百零九条,因租赁、借用等情形机动车所有人、管理人与使用人不是同一人时,发生交通事故等造成损害,属于该机动车一方责任的,由机动车承租人和使用人承担该赔偿责任。
3.租赁车辆、挂靠车辆使用人,平时要做好出车检查,制订车辆日常检查记录表,对于:氢系统、电池、灯光、轮胎、车辆外观、随车配置物品等做好日常检查并记录,如有异常必须及时处理,车辆合格满足出车条件以后才能出车,并且必须保持车辆定位系统在线。
4.车辆、挂靠车辆使用人,要做好我司车辆的安全、事故台账,出事故必须登记在台账中,并且开展四不放过教育:①事故原因没有查清不放过,②事故责任者没有严肃处理不放过,③全体司机及车队管理人员没受到教育不放过,④防范措施没有落实不放过。
开展教育必须有现场多张照片,所有司机及车队管理人员在教育签到表上签字,照片及签到表原件留档,我司安全部备查。
二、车辆使用安全注意事项:
1.所有驾驶员要有从业资格证,9.6米厢车与4.2米冷藏车,必须出示本人资格证,登记后才可以提车。
2.注意车辆高度,苏龙、柳汽乘龙等9.6米车高4米。跃进、现代冷链4.2米车高3.38米。现代普货车高3.28米。集卡飞驰车头3.9米,挂车装载平箱4.2米左右。驾驶员一定要注意车厢高度,当心限高杆、桥梁、树枝等物。
3.因为是氢用车,车内不得吸烟,车周边10米以内不得吸烟,车辆远离烟火(周边10米以上),不得将车停放在高压电线下。
4.进入加氢站,必须无烟火,关闭总电源后加氢。服从加氢站管理,如:静电接地,不超过35Mpa压力等等。
5.车辆遇到氢气泄漏,不严重移至空旷处,关闭总电源!车辆旁边不得有闲杂人等,远离明火,联系运维人员:江浙沪沈帅15021428914;新疆赵波18639103977;广东王河北13928468652;集卡车李泽琦13383480807;北京及其他地方赵小峰18868302409。
6.系统漏气并着火,火焰未烧至其他管路和车身;处理方式:立即熄火,关闭电源,马上灭火,立即打上述专业人员电话,在他们指导下灭火,以防电池等爆炸。如果火势大、控制难、立即拨打 119,人员撤离至安全区域。
7.供氢系统漏气着火,或电池着火,火焰烧至其他管路或车身;处理方式:立即拨打119,人员撤离至安全区域。
8.车辆每日检查:轮胎完好、气压标准、灯光设施齐全、车辆不带病上路。
9.雨雾天气,降低速度。注意能见度,与前车保持足够安全距离。
10.行驶中电池高温冒烟,马上靠边,断开高压系统,马上联系运维。
11.车辆发生火情立即停车,用灭火器降温灭火,关闭电源,火势大要保证人身安全,离开车辆打119报警。
12.氢能车辆禁止电焊,周围不许任何焊接,此类维修通知专业人员来修理。
13.出交通事故,第一时间打安全经理王屹青电话:18116198188,告知实际情况,加此电话微信,拍现场照片:整体事故场景、我方车牌、对方车牌、我方及对方车辆受损部位。并发定位,安全经理会指导处理事故。
贵方上述安全告知已收到并熟悉,我方(被告知人)郑重承诺:无条件遵守上述安全操作事项。若因我方(被告知人)原因导致发生安全事故,我方(被告知人)自行承担一切法律责任。
我方已清楚地了解附件 1《租赁订单》、附件2《车辆产生的费用》、附件3《安全责任告知书》和所有内容及车辆租用相关要求,在此向出租人郑重承诺:保证遵守《商用车租赁合同》及附件文件所有约定。
确认方(签字/盖章):
确认时间: 年 月 日
附件4:重型普通货运车辆租赁动态监管责任告知与确认书
甲方(出租方):{{lessorName}}
乙方(承租方):{{customerName}}
为严格落实《中华人民共和国道路交通安全法》《道路货物运输及站场管理规定》等相关法律法规及行业监管要求,规范重型普通货运车辆租赁期间的安全运营行为,强化驾驶员安全管控,防范道路交通安全风险,保障租赁车辆、人员及公共安全,现就甲方租赁给乙方车辆的动态监管违规行为及处置事宜,正式告知如下:
甲方将对租赁车辆实施24小时动态监管,重点监测驾驶员存在的超速行驶、超时驾驶(持续时间≥4小时)、接打手持电话、操作手机、抽烟、生理疲劳驾驶、未按规定系安全带、偏离驾驶位、佩戴红外阻断型墨镜遮挡视线、动态监控设备被遮挡或失效、双手脱离方向盘、不目视前方行驶、实线变道、前向碰撞、车道偏离、前向车距过近等各类违反道路交通安全法律法规及双方签订的《商用车租赁合同》约定的违规行为。本确认书所载违规行为的认定,以甲方提供的、由车辆合法装载的动态监控设备所记录的数据、影像为准。若乙方对相关数据、影像记录的违规事实有异议,应在收到甲方通知后48小时内书面提出,并提出理由。乙方驾驶员的上述违规行为,不仅会给乙方自身运营带来重大安全隐患与法律责任风险,还将对甲方造成合规、运营等多方面的不利影响及实际损失,具体如下:
一、合规经营风险:
甲方作为重型普通货运车辆出租主体,依法承担租赁车辆的动态监管主体责任,若乙方驾驶员的违规行为被交通运输、公安交管等监管部门查处,甲方将面临行政处罚、行业资质核查、信用评级下调等合规风险,情节严重的,将直接影响甲方道路运输相关业务的正常开展。若租赁车辆因乙方原因(包含但不限于乙方驾驶员屡次、严重违规或乙方安全管理缺失)导致租赁车辆被交通主管部门依法做出撤销/吊销/注销其道路运输证,导致车辆无法运营,相关损失由乙方承担。
二、运营资源消耗:
针对乙方驾驶员的违规行为,甲方需额外投入大量人力、物力开展违规核实、沟通对接、整改监督等工作,占用甲方动态监管、车辆维护、客户服务等核心运营资源,大幅降低整体租赁业务运营效率,严重影响甲方对其他合规客户的服务质量,造成甲方运营成本增加。
针对监测发现的驾驶员违规行为,结合上述违规行为对甲方造成的各类影响与损失,甲方将采取分级处置措施,具体如下:
(1)一般违规:租赁期限内,因驾驶员违规行为产生属实动态监控预警风险的,乙方按以下标准承担违约金:首次50元/次,第二次100元/次,第三次及以上违规500元/次,乙方应当在甲方通知违规之日起1个自然日内支付给甲方,逾期未支付的,乙方须在次月车辆租金结算时一并向甲方支付。乙方更换新驾驶员须提前向甲方书面报备,人员更换后违规次数将重新计算。
(2)严重违规处置及车辆收回:租赁期限内,车辆因违规导致动态监控风险属实,连续2个月被交管部门通报的,甲方有权要求乙方在第2个自然月底起将车辆停运1个月,停运期间正常计收租金。为避免车辆营运证连续3个月通报导致被注销,乙方须严格遵照甲方停运要求执行,乙方拒不配合停运的,视为严重违约,甲方有权单方无条件强制收回租赁车辆,无需承担任何违约及赔偿责任。若因乙方拒不配合收车、违规持续营运造成车辆营运证被注销的,乙方须全额承担营运证注销后6个月内全部车辆租金。车辆强制收回过程中产生的拖车费、停放保管费、转运费、场地使用费等全部费用均由乙方承担。因乙方前述违约行为给甲方造成的全部损失(含但不限于行政罚款、赔偿金、律师费、诉讼费、保全费、差旅费等),均由乙方全额承担,甲方有权从车辆保证金中直接抵扣,保证金不足以清偿的,甲方有权就剩余差额向乙方另行追偿。
乙方需高度重视租赁车辆驾驶员的安全管控工作,切实履行承租方安全管理主体责任,加强对驾驶员的日常安全教育、培训及常态化管理,严格落实本确认书约定的分级处置措施,积极配合甲方的动态监管工作,及时整改各类违规行为。甲方将定期向乙方反馈车辆动态监管情况,对乙方未按本确认书要求落实处置措施、整改不到位或者拒不配合监管的行为,甲方将严格按照法律法规及双方签订的《租赁合同》约定处理。
本确认书自甲乙双方签字或盖章后生效,本确认书作为《商用车租赁合同》的附件,与《商用车租赁合同》具有同等法律效力。本确认书未尽事宜,按照双方签订的《商用车租赁合同》相关约定执行;若本确认书内容与相关法律法规冲突,按法律法规规定执行。
乙方确认:已认真阅读并充分全面理解本确认书全部内容,自愿严格遵照本确认书约定及相关法律法规要求执行,并承担因违反确认书约定及相关规定产生的全部责任。
(以下无正文)
甲方(盖章): 乙方(签字/盖章):
授权代表(签字): 授权代表(签字):
日期: 年 月 日 日期: 年 月 日
附件5:
安全责任承诺书
为严格落实《道路运输车辆动态监督管理办法》《广东省道路运输条例》及粤标动态监控管理要求,防范因超速、疲劳驾驶、接打电话、抽烟、遮挡摄像头、屏蔽设备、离线等违规行为被交通运输主管部门连续通报,避免因此导致车辆被责令停运、营运证被暂扣或注销等严重后果,并就车辆粤标动态监控相关安全责任,作出如下郑重承诺:
1.严格遵守《道路运输车辆动态监督管理办法》《广东省道路运输车辆智能监管系统应用管理办法》等国家及地方性法规,并已阅读、理解且承诺遵守贵公司提供的《粤标动态监控专项安全管理方案》(下称“管理方案”)相关规定,服从贵公司依据该方案及相关法规实施的动态监控管理。
2.负责督促我司承租司机规范驾驶,杜绝疲劳驾驶、超速、分心驾驶等违规行为,严禁破坏、屏蔽、断电、拆机等影响粤标监控设备正常运行的行为。
3.及时接收贵公司反馈的车辆违规信息,严格按照要求落实整改,配合贵公司开展司机安全教育、车辆停运等处置措施。
4.若因我司及我司承租司机违规行为,导致车辆被交管、运政部门通报、处罚或贵公司遭受其他损失的,我方同意承担由此产生的全部直接经济损失,包括但不限于政府部门处以的罚款、贵公司为处理此事支出的合理费用(如差旅费、律师费)以及车辆被责令停运期间的租金损失(按《商用车租赁合同》(下称“主合同”)约定标准计算)。
5.我司知悉,若因连续违规被主管部门通报3次及以上,导致贵公司营运证被暂扣或注销等严重后果的,自愿承担全部赔偿责任(包括但不限于车辆价值贬损、营运损失等)。同时,贵公司有权单方解除《商用车租赁合同》,且有权在5年内拒绝与我司及关联方开展任何商业合作。
6.本承诺书自签订之日起生效,有效期至《商用车租赁合同》约定租赁期满之日止。
7.本承诺书作为《商用车租赁合同》的有效附件,与主合同具有同等法律效力。如本承诺书内容与主合同内容约定不一致,则以更严格约束我司义务的条款为准。
(以下无正文)
承诺客户(盖章):__________
法定代表人/授权代表人(签字):__________
签订日期: 年 月 日
附件6:车辆使用规范和驾驶员要求
一、车辆使用规范
启动前 的操作 | 1.确认电源总开关处于开启状态。 |
2.检查储氢瓶的气密性,是否变形。 |
3.确认驻车制动操纵手柄处于驻车状态,确认变速操纵杆处于空挡位置。 |
4.车辆起步前,观察仪表有无异常显示和报警:剩余氢气量(SOC)不低于10%或者氢气压力不低于3.5兆帕,且动力电池电压显示不低于520V,低压蓄电池显示于22V以上,原地转动方向盘检查转向泵工作是否正常若仪表有指示灯亮起或声音报警,应停车检查。 |
5.系好安全带,检查安全措施。 |
车辆起步 | 1.先将钥匙转动至“ACC”位置,踩住刹车再继续转动至“START”,停留3秒。 |
2.仪表盘会显示READY等字样。 |
3.在观察电机运转正常,各仪表、指示灯、无警报灯正常的情况下方可起步。 |
4.仪表显示“ready”,踩下制动踏板,挂前进挡时,换挡杆切换至“D”,挂倒挡时,换挡杆切换至“R”。 |
5.放下驻车制动操作手柄,缓慢踩踏加速踏板,电机启动,车辆开始行驶。 |
停车动作
| 1.应先放松加速踏板,降低车速。 |
2.必须在车辆完全停稳后踩住刹车才能换入倒档,否则传动系统将受到损坏。 |
3.怠速运转夏天5分钟、冬天10分钟时间,关闭电源,停车时长超过2小时需要关闭总电源。 |
4.关闭用氢系统开关。 |
起步 注意事项 | 1.观察左右反光镜,注意车辆行人。 |
2.两次起动车辆的间隔时间不少于30秒。 |
3.驾驶室倾翻起来的情况下,禁止启动电机。(一体式车头除外) |
4.严禁不松手刹的情况下强行行驶。 |
5.起步和行车途中手刹处于施加状态电机功率将会降低50%。 |
汽车行驶 注意事项 | 1.汽车行驶中,注意使电机冷却液温度保持在正常状态。 |
2.严禁行驶途中关闭氢能源开关。到加氢站加氢时,提前5分钟关闭用氢开关。 |
3.行驶中注意观察电池电量(SOC),如果低于设定值50%以下,停车检查是否打开用氢开关,再报售后维修。 |
4.遇水后请注意特别驾驶,制动器受潮会暂时降低制动力。并缓慢通过。 |
5.车辆倒车速度不超过15公里/时。 |
6.紧急刹车制动距离较长且急速刹车时车辆会向左倾斜,应注意车速(最佳车速在40—50),且必要时预见性减速。 |
7.长时间或下雨天停车要关闭整车总闸,避免损耗低压电或线路故障。 |
8.行车途中若听见不正常的声音或嗅到不正常的味道应及时停车找出原因。 |
9.所有高压电源均由点火开关控制,驾驶员离开车辆时必须关掉点火开关,取走钥匙。 |
10驾驶过程中严禁吸烟(包括但不限于驾驶室、密封空间、距离车辆【10】米范围内)。 |
11.注意观察冷机的温度是否在正常范围之内。 |
加氢流程 | 提前5分钟关闭用氢开关—车辆停在指定位置--人员离开到安全位置等待--加氢进行--加氢完毕关闭加氢口--纯电启动驶离加氢站--打开用氢开关。 |
加氢注意事项 | 1.氢的剩余量不能低于SOC10%。气压不能低于3.5兆帕。 |
2.加氢时严禁在加氢站点燃明火,或者吸烟。 |
3.要在听从加氢站工作人员的指导下开到指定位置,关闭电源,停车,由工作人员代驾。 |
| 4.禁止个人加氢,避免储氢瓶氢气泄漏,加氢需到加氢站。 |
5.不要携带手机、打火机、MP3等易引起爆炸、自燃的物品进入氢化工作区域。 |
6.在加氢站附近,拿工具、零件时应轻拿轻放,不得发生刚性撞击产生火花。 |
特别注意 | 1.不能急加速,匀速行驶。 |
2.车辆停车后,要等空压机吹扫结束再关闭电源(建议停车前10分钟关闭EV开关)。 |
3.电池电量不可低于25%。低于25%时,整车报警,低于15%时,整车无法上高压,将无法启动,应提前外接充电或开启混动模式充电。 |
4.氢气余量不可低于10%。 |
5.当车辆soc电量低于50%且未充电,则要确认是否在用氢状态,或靠边确认故障。 |
6.仪表台中部“EV”按钮为运行模式切换,按下后车辆由混合动力转换为纯动,再按则转换回混合动力,正常无需对此按钮进行操作。 |
7.加氢时关闭EV开关,使用电动进站加氢,离开加氢站再启动氢(EV开关)。 |
8.车辆为自动换挡,正常行驶中无需换挡操作,且车辆为电驱动系统,滑行时不须切换为空挡,切换空挡会导致车辆失去油门响应;如需换挡时,应踩刹车进行换挡,切换挡位时须先切换为空挡,并在空挡停留0.5s~1s。 |
9.开车前检查水箱防冻液是否缺失,过久未使用车辆需更换防冻液。 |
10.不要随意开启氢罐两侧的门,更不能随意关闭氢管路的阀门。 |
11.不要频繁关闭开启氢开关,停车20分钟左右的不需关闭。 |
12.非紧急情况下禁止碰高压急停开关,紧急情况下使用(如事故,涉水,起火)。 |
13.不能用水枪冲洗橙色线路,避免进水报绝缘和漏电。 |
14.车辆为电动车辆,因此涉水高度最高为300mm,如积水超过500mm严禁通行,且通过积水路段时应注意减速慢行。 |
15.停机注意:首先关闭所有用电设备(如空调)钥匙关一档(待燃料电池完全停止工作—再可关二档—最后方可关闭总电源开关)包括重新启动按以上要求操作。 |
二、车辆操作提醒
(一)安全/充电事项
1.高压安全:高压橙色线束及其连接件,不能随意触碰,有高压触电风险。
2.氢气安全:若有泄漏,立即现场隔离。 严禁人、车入内。供氢系统发生火灾:若条件允许,车辆移动空旷区域,人员撤离;若条件允许,可用淋水对氢瓶降温。
3.充电事项:充电时,需选择电压大于500V及辅助电压为24V的充电桩。尽量避免人为使用EV模式驾驶,减少充电次数。
3.加氢事项:行车前,合理规划路线,关注氢剩余量,及时补充。
4.氢堆功率待机条件:混动模式下氢堆功率输出条件
SOC在85%以上时氢堆自动进入待机状态,直到SOC低于65%时自动开始启动;然后电池开始充电直到SOC在85%以上又进入待机状态,依次循环。
注意:氢堆待机时,如果驾驶员要求功率大于电池放电功率限制值,氢堆也会自动启动输出功率。
5.功率限制
限制条件 | 限制措施 | 限制现象 |
纯EV模式 | SOC≤30% | 输出功率限制 | 空调停止使用,电池电量报警灯点亮/SOC进度条显示黄色 |
SOC≤20% | 车辆限速≤52km/h/电池低电量警告灯+闪烁/SOC进度条显示红色 |
SOC≤10% | 车辆限速≤17km/h/电池低电量警告灯+闪烁/整车故障灯点亮/SOC进度条显示红色,车辆限输出扭矩 |
(二)主要故障灯处理
1.氢燃料电池冷却液报警指示灯:停车检查,检查燃料电池冷却液液面状态,联系羚牛运维服务人员检查冷却液是否泄漏或其他原因。
2.氢燃料电池堆报警灯:氢燃料电池控制系统某个运行数据异常,切换E V模式、联系羚牛运维服务人员处理。
3.氢气泄漏报警灯:立即切换为EV模式,立即寻找远离火源空旷通风区域停车,关闭低压电源总开关,联系羚牛运维服务人员处理。
4.供氢系统报警灯:车辆可能会出现限制功率输出;切换EV模式、联系羚牛运维服务人员处理。
5.按指示灯颜色判断:绿灯正常运行-黄灯检查警告-红灯停车检查。
(三)驾驶模式切换-混动/EV模式
EV模式:按下EV开关键,仪表指示灯亮,车辆执行EV纯电模式运行。
混动模式:EV开关键关闭下,车辆启动,系统默认为混动模式。
注意:为延长动力电池寿命,纯EV模式仅允许在紧急情况下使用,严禁长期使用; EV模式可以在任何条件下切换到混动模式;混动模式只能在停车后才可切换为EV模式。
(四)能量回收功能
1.开启方法:拨杆在最上位置时为1档,拨动开关到最下位置时为2档。 (车辆默认挡位为1档)
2.启用条件:SOC<95%、车速>15Km/h、未踩加速踏板。
3.解除条件:踩下加速踏板或 SOC>90%或车速<15Km/h。
4.当道路平坦需长距离滑行或坡度较大需要较大制动力时,下拨能量回收开关到2档。
注意:合理使用能量回收,能有效减少制动系统磨损和降低氢耗;能量回收不能代替行车制动。
(五)ECO模式
开启方法:按下ECO模式开关,仪表ECO指示灯点亮,车辆进入节能模式运行;否则为正常运行模式。
注意:重载时使用正常模式(ECO未开启);道路平坦,空车或者轻载时,打开ECO开关,使用
节能模式;合理使用能量回收和ECO功能,可以提高续航里程。
(六)车辆停放
车辆停车后,将钥匙置于OFF档,等待3分钟,待氢堆完成自洁后夏天5分钟和冬天10分钟,再关闭低压电源总开关;停车区尽量选择空旷非封闭空间且应远离火源;为保护低压蓄电池性能,长时间停车(超过2个小时),强烈建议关闭低压电源总开关。
(七)提升续航驾驶
1.不要急加、减速:急加、减速能量损耗大,严重降低续航。
2.经济车速40-70KM/H:车速保持在此阶段匀速行驶 ,能有效地提高车辆续航里程。
3.能量回收和ECO模式使用:能量回收模式可回收多余动能提高续航,合理使用ECO模式,降低动力输出提高续航。
注意:合理使用空调,避免夏季过冷,冬季过热,导致能耗增加。
(八)AVAS-低速报警
1.开启条件:根据车速自动激活;D挡时:车速在1-20km/h时,发出“嗡嗡”报警声,车速高于20km/h时,报警自动取消;R档时,发出倒车音提示音。
2.作用:车辆启动行驶时,车辆噪声较小,为确保行车安全,强烈建议开启低速报警功能,提醒行人注意安全。
(九)定速巡航
1. 开启方法:按下定速巡航开关按键,通过方向盘设定速度。
2.启用条件:车辆无故障、40km/h≤车速≤90km/h。
3.解除条件:关闭巡航开关、踩下制动踏板、车速>90km/h、车速<40km/h。
注意:用定速巡航开关以外的方式解除定速巡航,巡航控制系统仍处于待命状态。 按下“SET/-”时,车辆会自动恢复到最近设定的巡航速度。
(十)故障处理流程
1.若车辆出现故障时,请及时联系羚牛运维服务人员。
2.若车辆故障时,为快速及有效地判断故障原因,请驾驶员记录以下信息,反馈给现代商用车服务人员。需提供车辆信息如下:车辆铭牌、故障码内容照片、仪表整体显示照片。
3.故障现象描述:车辆在行驶过程中或启动时,仪表显示故障灯,车辆有什么故障现象;车辆在使用过程中,车辆什么功能无法使用;尽可能拍摄故障时照片或视频,便于快速故障原因判断;
(十一)参数/故障查询方法:
1.车辆运行参数查询:按下方向盘上“菜单键”,进入“设置”界面,按“选择键”选择“信息栏目”项后,再按“确认键”,可读取相关系统信息。
2.车辆故障内容查询:按下方向盘“菜单键”,进入“故障诊断”界面,按“选择键”选择“故障内容”项后,再按“确认键”,可读取故障码内容。
三、驾驶员安全管理要求:
1.乙方驾驶员必须遵守《中华人民共和国道路交通安全法》《中华人民共和国道路运输条例》及有关交通安全管理的规章规则,安全驾车,并应遵守其他相关的规章制度。
2. 乙方与驾驶员须签订聘书,聘用条件为:
⑴须持有合法的驾驶执照,对于租赁车辆的同车型实际驾龄必须超过2年;
⑵年龄不超过55周岁;
⑶取得道路运输管理部门颁发的从业资格证;
⑷经乙方组织对其进行面试、理论和机械常识考核、道路驾驶技术测试合格。
3.驾驶员的管理、宣传、教育。
(1)驾驶员应爱惜甲方车辆,平时要注意车辆的保养,经常检查车辆的主要机件。每月至少用半天时间对自己所开车辆进行检修,确保车辆,以保持车辆的清洁。驾驶员发现车辆有故障时要立即检修。不会检修的,应立即报告管理人员,并提出具体的维修意见(包括维修项目和大致需要的经费等)。未经批准,不许私自将车辆送厂维修;
(2)驾驶员对自己所开车辆的各种证件的有效性应经常检查,出车时一定保证证件齐全。连续行车里程超过四小时的,须配备两名驾驶员,每位驾驶员连续驾驶时间不得超过四小时;
(3)乙方应对本单位每位驾驶员进行岗前安全教育培训、考核,考核不合格的,不得上车驾驶。并保存驾驶员安全培训记录;
(4)对违章次数多、出险率高、发生交通事故的驾驶员进行再教育培训或依据公司制度进行惩罚。
4.承租人在收到违章信息通知后,从通知日期后15天内处理完毕,防止积累。(北京要求10个工作日内处理)。
5.承租人如果发生违章,将会收到短信,微信或者书面形式通知,并会有出租人或售后人员致电确认。
6.如若自身不便处理违章,请在发生违章之日起 10日内 联系出租人或售后人员并说明情况,由出租人代为处理,产生的一切费用由客户自行承担。在收到以下违章信息的情况下,必须在得到通知后的10天内必须处理完毕:
(1)单辆车累计扣分6分以上或罚款800元以上;
(2)单辆车未处理违章3条以上;
(3)因年审要求,在注册日期当月最后截止日期前10个工作日处理掉所有违章。不处理的,出租方将安排代为加急处理,产生的费用由承租方承担。
7.如收到违章信息超出规定时间拒不处理的,出租人将预警发函或进行远程控制(如锁车)措施处理。
8.对半年内单辆车出现违章超过10次(北京在季度内单辆车不能超过两次违章,并且不能出现一次扣6分的违章)、发生交通事故负有责任4次以上或者重大交通事故一次的情况下,出租人将会做出以下应对方案:
(1)承租人必须更换司机;
(2)拒不整改配合,则视承租人为违约做收车处理。
9.欢迎您对我们的服务进行监督并提出宝贵意见。我公司的监督投诉电话:【 400-021-1773】。
接收方(签字/盖章):
时间: 年 月 日
授权委托书
致:{{lessorName}}
兹委托受托人1 姓名【】联系方式【】证件号码【】代表委托人处理委托人与办理Ρ签署《商用车租赁合同》(合同编号:)及前述合同相关包括但不限于《租赁订单》等合同附件、Ρ提车、Ρ退车、Ρ更换车、≤ 事宜,授权期限自本授权委托书签署之日起至《商用车租赁合同》终止之日止。
兹委托受托人2 姓名【】联系方式【】证件号码【 】代表委托人处理委托人与办理≤签署《商用车租赁合同》(合同编号:)及前述合同相关包括但不限于《租赁订单》等合同附件、≤提车、≤退车、≤更换车、≤ 合同抬头变更事宜,授权期限自本授权委托书签署之日起至《商用车租赁合同》终止之日止。
上列受托人的代理权限为特别授权,即受托人有权代委托人签署《商用车租赁合同》及前述合同相关包括但不限于《租赁订单》等合同附件、有权代为履行前述合同及附件内容、有权代为签收、确认前述合同及其附件相关通知、函件、诉讼文件等。委托人对上列受托人在授权范围内的行为承担全部法律责任。
本授权委托书手填部分有效,委托人特此声明及确认。
委托人(签字/盖章):
年 月 日
安全责任协议
甲方(出租方):
经办人:
联系电话:
乙方(承租方):
统一社会信用代码/身份证号:
通信地址:
经办人:
联系电话:
为明确双方车辆租赁期间安全管理责任,保障运输作业安全,依据相关法律法规,在已签订《车辆租赁合同》同时,签订本协议,约定租赁车辆安全运营及管理责任。
一、协议目的
1.1本协议明确双方合作期间安全责任,确保企业主体责任履行,保障人员、车辆和货物安全,避免事故发生。
1.2本协议有效期与《车辆租赁合同》合同期限保持一致,租赁期间内乙方承担全部车辆相关的安全责任。
二、安全责任划分
2.1车辆交接时,乙方确认车辆状态,在交接单签字即视为认可车辆状况,甲方完成合格交付。自交付之日起,车辆运营安全责任及维修保养责任转移至乙方。
三、乙方安全承诺
乙方结合车辆安全和加氢安全实际,就安全生产做出承诺并制定规程、制度、预案等。
3.1安全管理制度
3.1.1乙方建立健全本单位安全生产责任制,成立安全生产管理机构、依据规定配备专职或兼职安全管理人员,明确各部门、各岗位安全职责。
3.1.2乙方制定本单位生产安全事故隐患排查治理制度,明确各层级隐患排查职责,及时消除安全隐患。
3.1.3乙方制定本单位交通事故应急救援预案,明确应急组织机构及职责,确定应急处置流程、储备相应应急物资。
3.1.4乙方制定本单位驾驶员安全培训制度,落实驾驶员岗前安全培训、考核工作,并保存驾驶员培训记录。
3.1.5乙方制定并落实安全生产、交通运输等法律规定的其他安全管理制度。
3.1.6乙方负责按照甲方的要求提供企业营业执照及必要资质、运营证件及个人驾驶证、身份证供甲方审查核验。
3.1.7甲方有权对每一位租赁车辆的驾驶员证件信息、有效期资质进行审核。
3.2 事故隐患排查治理
3.2.1乙方每月至少进行一次全面安全检查,重点检查安全管理制度是否完善,是否定期组织召开安全会议,是否对每位驾驶员开展岗前安全培训,是否定期开展隐患排查及隐患限期整改落实,是否至少每半年开展一次应急演练等安全事项。发现存在安全隐患立即通知整改,并立即抓好落实,及时消除。
3.2.2乙方做好出车前、停车后的准备、检查工作,确保行车安全,发现隐患要及时修复后方可出车。
3.2.3乙方装货时严查超载和擅自装载危险品,确认无误后方可出车。
3.2.4乙方不定期检查车辆的安全装置、灯光信号、证件。
3.2.5乙方检查驾驶员是否带病、疲劳、酒后驾驶,是否违反安全驾驶操作规程。
3.2.6乙方建立驾驶员安全考核奖惩制度,针对违章次数多、出险率较高的司机进行再教育或依制度进行处罚。
3.3 驾驶员管理
3.3.1乙方驾驶员必须遵守《中华人民共和国道路交通法》《中华人民共和国道路运输条例》及有关交通安全管理的规章规则,安全驾车,并应遵守其他相关的规章制度。
3.3.2 乙方与驾驶员签订聘书,聘用条件为:
(1)驾驶员须持有合法驾照;
(2)年龄不超过60周岁;
(3)驾驶4.5T以上车型须有从业资格证,且经乙方面试、理论和机械常识考核、道路驾驶技术测试合格。
3.3.3乙方应对驾驶员进行岗前及定期安全教育培训、考核,考核不及格的,不得上车驾驶,保存培训材料,对违章次数多、出险率高或发生交通事故的驾驶员进行再教育或依据公司制度进行处罚。
3.3.4 乙方应当对驾驶员进行安全生产教育和培训,保证驾驶员具备必要的安全生产知识,熟悉道路交通安全规章规则,掌握行车安全操作技能,了解事故应急处理措施,知悉自身在交通安全方面的权利和义务。未经安全教育和培训合格的驾驶员,乙方不得让其上岗作业。
3.3.5 乙方必须依法参加工伤保险,为驾驶员缴纳保险费。
3.4车辆安全管理要求
3.4.1车辆发生故障必须及时修复,特别是危及行车安全的重大隐患,如制动、转向、轮胎、灯光装置等。严禁车辆带病出场。
3.4.2严禁超员、超载行驶,严禁客货混装,严禁超速行驶。
3.4.3车辆在运行途中,驾驶员应主动做好车辆的自检自查,发现问题及时解决。
3.4.4车辆周围10米内严禁抽烟,严禁明火。进入加氢站加氢时按操作流程执行。
3.4.5车辆必须按规定位置停放,严禁停放在密封场所、低洼积水区域。车辆停放不得占据消防通道或妨碍消防通道畅通,不得将车辆停放在有人员居住的建筑物内,不得将车辆停放在可能造成人员伤亡的坡道路段,应确保车辆与爆破、吊装、起重、动火、高温等危险作业场所保持足够的安全距离。乙方违反本条事项要求所造成的人员伤亡、财产损失,均由乙方自行承担。
3.5车辆技术管理要求
3.5.1乙方应根据甲方保养要求及时对车辆组织保养维修,并及时将保养维修、车辆肇事情况通知甲方。
3.5.2车辆重要部位改动或加装部件,乙方应征得甲方同意并报甲方登记备案。
3.5.3甲方运维部管理人员检查车辆上路行驶情况时,在告知其身份后,司机必须停车配合,如发现车辆状况不佳或违反甲方安全管理规定的,甲方管理人员有对车辆进行停驶、回场检查的权利。
3.5.4 乙方要配合甲方对车辆进行年审、二级维护、检测、事故违章处理等工作。
3.6突发事件应急处置
为减少、避免事故的发生,把事故的损失降到最低程度,乙方及乙方驾驶员应做到:
3.6.1交通事故
驾驶员在车辆运行中发生交通事故时,停车后马上下车关闭车辆总电源,查看事故情况及是否有人员受伤,并将事故碰撞现场进行拍照留存,在车辆后方100米处放置警示标志。
发生交通事故,当事人应立即进行自救,并报警。电话: 122(交警)、119(消防)、120(急救),应简明讲清事故地点、伤亡、损失等情况,以及事故对周围环境的危害程度,保护现场,抢救伤员,保护货物财产并上报公司领导及甲方管理部门。
事故如果导致氢气压力异常和氢气管路有“嗤嗤声”等异常现象,发现车辆有漏气情况时,驾驶员要第一时间通知公司领导或甲方相关人员告知事故情况,甲方安排专业售后人员进行应急处理。
远离人群,事故车的处理地点应尽量避免在人口密集区,如只能在原地进行处理,应在周围设置提示牌。
安全撤离,当车辆发生明火现象时,驾驶人员应停车并关闭车辆总电源,并采取紧急灭火措施,灭火器应使用二氧化碳灭火器,对着火点进行喷射。如遇到无法扑灭时,立即疏散周围人员及车辆并撤离到安全地带拨打119报警,等待救援。
3.6.2车辆氢气泄漏
(1)驾驶员在车辆运行中发现氢气泄漏报警情况时,应就近安全区域停车。
(2)停车后马上关闭车辆总电源、在车辆后方100米处放置警示标志,并疏散周围人员车辆。
(3)驾驶员将情况通知公司领导或甲方相关人员告知,甲方安排专业售后人员进行应急处理。
3.6.3车辆运行中发生整车故障
驾驶员驾驶车辆行驶中发生整车故障报警情况时,应在安全地带停车。
停车后关闭车辆总电源,并电话联系甲方,甲方收到信息后安排售后人员电话指导驾驶员进行处理。如电话无法处理时,安排厂家前往现场进行处理或拖至服务站处理。
3.6.4火灾事故
(1)发生车辆火灾事故或出现火险苗头时,驾驶员应立即熄火有条件地迅速将车转移至安全地点,切断电源,关闭气阀。
(2)使用二氧化碳灭火器对着火点进行喷射。
(3)火灾现场在进行初期扑救的同时或发现火势较大,估计自身无法扑灭的,并撤离到安全地带,疏散周围人员及车辆。迅速拨打火警电话报警,并通知公司领导及甲方管理部门。
(4)如有受伤人员,必须首先将伤员抢救出来,及时送往附近医院进行救治。
(5)公安消防人员到达现场后,应急救援人员应服从专业消防人员的指挥,在消防人员的统一组织下,积极参加火灾事故的救援工作。
3.7 禁止第三方使用
3.7.1 严格禁止乙方擅自将甲方车辆转租、分租、出借或以联营、合作、借用等形式变相交由第三方使用。如有违反,甲方有权立即解除合同、收回车辆,并要求乙方支付相当于三个月租金的违约金,且不影响其他损失赔偿权利。
四、甲方安全管理责任和权利
4.1 甲方有权审查乙方拟租赁车型是否在乙方经营许可范围之内,审查所交车型是否与乙方提车人驾驶证准驾车型匹配,驾驶证、从业资格证是否在有效期内。
4.2甲方负责按照《车辆可交付标准》对乙方拟租赁车辆进行整备,确保车辆性能完好、安全附件齐备。
4.3甲方负责指引乙方按照“交车单”内容项进行实物及车况确认,无误后甲乙双方在交车单上签字。
4.4甲方负责通知乙方所承租车辆的保养、年审、违法处理等信息。
4.5乙方在履行安全管理责任时,若需要甲方协助的,甲方在自身能力范围内且在不影响自身正常运营的情况下,对乙方提供必要的技术指导和信息支持等协助。
4.6乙方承诺自愿按照“乙方安全承诺”的规范内容进行操作,对于违反“乙方安全承诺”内容的操作行为,乙方应向甲方支付相当于三个月租金的违约金;若该违约金不足以弥补甲方损失的,乙方还应赔偿甲方因此遭受的全部损失。
4.7 尽管有上述规定,甲方是否行使甲方的安全管理责任和权利以及如何行使甲方的安全管理责任和权利,无论如何均不影响乙方根据本协议及“乙方安全承诺”履行其安全管理责任,也不减免或减轻其任何安全管理责任。
五、其他
5.1 本协议的任何变更或补充需经双方书面协商一致,并签订相关协议变更或补充文件。
5.2 本协议为《车辆租赁合同》的附件,本协议未约定的,以《车辆租赁合同》约定为准;若本协议约定与《车辆租赁合同》约定不一致的,以本协议约定为准。
5.3 本协议经双方签字(盖章)之日起生效,一式两份,甲乙双方各执一份,具有同等法律效力。
甲方(签章): |
| 乙方(签字/盖章): |
授权代表: |
| 授权代表: |
签订日期: | 年 月 日 | 签订日期: 年 月 日 |
附:承租方(乙方)营业执照、法定代表人身份证复印件(若有授权书,需附被授权人身份证复印件)、道路运输经营许可证等。
V26.5
PAGE \\* MERGEFORMAT 1
`;
-// END AUTO-GENERATED V26.5
-
-var DEFAULT_LESSOR_COMPANIES = [
- {
- id: 'jx', shortName: '嘉兴羚牛', enabled: true,
- legalName: '浙江羚牛氢能科技有限公司',
- creditCode: '91330481MA2JXXXXX',
- address: '浙江省嘉兴市平湖市乍浦镇杭州湾大道1号',
- contact: '法务部', phone: '0573-88888888', email: 'legal@lingniu-jx.com',
- accountName: '浙江羚牛氢能科技有限公司',
- bankName: '招商银行嘉兴分行',
- bankAccount: '120924165110301',
- hotline: '400-021-1773'
- },
- {
- id: 'sh', shortName: '上海羚牛', enabled: true,
- legalName: '羚牛氢能科技(上海)有限公司',
- creditCode: '91310115MA1HXXXXX',
- address: '上海市浦东新区张江高科技园区科苑路88号',
- contact: '法务部', phone: '021-88888888', email: 'legal@lingniu-sh.com',
- accountName: '羚牛氢能科技(上海)有限公司',
- bankName: '招商银行上海张江支行',
- bankAccount: '120924165110401',
- hotline: '400-021-1773'
- },
- {
- id: 'gd', shortName: '广东羚牛', enabled: true,
- legalName: '羚牛氢能科技(广东)有限公司',
- creditCode: '91440101MA5CXXXXX',
- address: '广东省广州市黄埔区科学城开源大道11号',
- contact: '法务部', phone: '020-88888888', email: 'legal@lingniu-gd.com',
- accountName: '羚牛氢能科技(广东)有限公司',
- bankName: '招商银行广州萝岗支行',
- bankAccount: '120924165110201',
- hotline: '400-021-1773'
- }
-];
-var LESSOR_TEMPLATE_VARS = [
- { key: 'lessorName', label: '甲方全称' },
- { key: 'lessorAddress', label: '甲方地址' },
- { key: 'lessorContact', label: '甲方联系人' },
- { key: 'lessorPhone', label: '甲方电话' },
- { key: 'lessorEmail', label: '甲方邮箱' },
- { key: 'lessorAccountName', label: '收款户名' },
- { key: 'lessorBankName', label: '开户行' },
- { key: 'lessorBankAccount', label: '银行账号' }
-];
-var CONTRACT_TEMPLATE_VAR_GROUPS = [
- {
- title: '甲方签约主体',
- desc: '创建合同时按所选签约公司自动替换',
- vars: LESSOR_TEMPLATE_VARS
- },
- {
- title: '合同通用',
- desc: '创建合同时由系统或客服填写',
- vars: [
- { key: 'contractCode', label: '合同编号' },
- { key: 'customerName', label: '乙方公司全称' },
- { key: 'creditCode', label: '乙方统一社会信用代码' },
- { key: 'customerAddress', label: '乙方地址' },
- { key: 'customerContact', label: '乙方联系人' },
- { key: 'customerPhone', label: '乙方联系电话' },
- { key: 'signDateYear', label: '签订年份' },
- { key: 'signDateMonth', label: '签订月份' },
- { key: 'signDateDay', label: '签订日期' }
- ]
- }
-];
-var DEFAULT_LESSOR_HOTLINE = '400-021-1773';
-if (typeof window !== 'undefined') {
- if (!window.ONEOS_LESSOR_COMPANIES || !window.ONEOS_LESSOR_COMPANIES.length) {
- window.ONEOS_LESSOR_COMPANIES = DEFAULT_LESSOR_COMPANIES;
- }
- window.ONEOS_LESSOR_TEMPLATE_VARS = LESSOR_TEMPLATE_VARS;
- window.ONEOS_CONTRACT_TEMPLATE_VAR_GROUPS = CONTRACT_TEMPLATE_VAR_GROUPS;
- window.ONEOS_CONTRACT_CLAUSE_MARKERS = {
- lockSelector: '.ct-inline-lock[data-inline-lock="1"]',
- riskRedlineSelector: '.ct-risk-redline[data-risk-redline="1"]',
- nonstdTriggerAttr: 'data-nonstd-trigger',
- nonstdApprovalType: '非标准合同审批'
- };
-}
-
-// 【重要】必须使用 const Component 作为组件变量名
-// ONE-OS 合同模板管理(法务人员维护 Word 版合同基础模板)
-// 设计规范:docs/ONE-OS-DESIGN-SPEC.md · 样式:web端/styles/contract-template.css
-
-import { OperationActions } from '../../../common/OperationActions';
-
-const Component = function () {
- var ONEOS_ANT_TABLE_GLOBAL_FIX = [
- '.ant-table-container .ant-table-header { margin-bottom: 0 !important; }',
- '.ant-table-container .ant-table-body { margin-top: 0 !important; }',
- '.ant-table-container .ant-table-body > table, .ant-table-content table { margin-top: 0 !important; }',
- '.ant-table-tbody > tr.ant-table-measure-row, .ant-table-tbody > tr.ant-table-measure-row > td, .ant-table-tbody > tr.ant-table-measure-row > th { display: none !important; height: 0 !important; max-height: 0 !important; min-height: 0 !important; padding: 0 !important; margin: 0 !important; border: none !important; line-height: 0 !important; font-size: 0 !important; overflow: hidden !important; visibility: hidden !important; pointer-events: none !important; }'
- ];
-
- var useState = React.useState;
- var useMemo = React.useMemo;
- var useRef = React.useRef;
- var useEffect = React.useEffect;
- var antd = window.antd;
- var App = antd.App;
- var Card = antd.Card;
- var Table = antd.Table;
- var Button = antd.Button;
- var Tabs = antd.Tabs;
- var Select = antd.Select;
- var Input = antd.Input;
- var Space = antd.Space;
- var Tag = antd.Tag;
- var Modal = antd.Modal;
- var Row = antd.Row;
- var Col = antd.Col;
- var Upload = antd.Upload;
- var Tooltip = antd.Tooltip;
- var Popover = antd.Popover;
- var Divider = antd.Divider;
- var Dropdown = antd.Dropdown;
- var message = antd.message;
-
- var FONT_SIZE_OPTIONS = [
- { value: '12px', label: '12px' },
- { value: '14px', label: '14px' },
- { value: '16px', label: '16px' },
- { value: '18px', label: '18px' },
- { value: '20px', label: '20px' },
- { value: '24px', label: '24px' },
- { value: '28px', label: '28px' },
- { value: '32px', label: '32px' }
- ];
-
- var FONT_FAMILY_OPTIONS = [
- { value: 'Microsoft YaHei', label: '微软雅黑' },
- { value: 'SimSun', label: '宋体' },
- { value: 'SimHei', label: '黑体' },
- { value: 'KaiTi', label: '楷体' },
- { value: 'FangSong', label: '仿宋' },
- { value: 'Arial', label: 'Arial' },
- { value: 'Times New Roman', label: 'Times' }
- ];
-
- var COLOR_OPTIONS = [
- { value: '#000000', label: '■ 黑' },
- { value: '#dc2626', label: '■ 红' },
- { value: '#2563eb', label: '■ 蓝' },
- { value: '#16a34a', label: '■ 绿' },
- { value: '#ca8a04', label: '■ 金' },
- { value: '#64748b', label: '■ 灰' }
- ];
-
- var BG_COLOR_OPTIONS = [
- { value: '#fef08a', label: '■ 黄' },
- { value: '#bbf7d0', label: '■ 绿' },
- { value: '#bfdbfe', label: '■ 蓝' },
- { value: '#fecaca', label: '■ 红' },
- { value: '#f1f5f9', label: '■ 灰' },
- { value: '#ffffff', label: '■ 无' }
- ];
-
- var LINE_HEIGHT_OPTIONS = [
- { value: '1', label: '1.0 倍' },
- { value: '1.25', label: '1.25 倍' },
- { value: '1.5', label: '1.5 倍' },
- { value: '1.75', label: '1.75 倍' },
- { value: '2', label: '2.0 倍' },
- { value: '2.5', label: '2.5 倍' }
- ];
-
- var PARAGRAPH_STYLE_OPTIONS = [
- { value: 'p', label: '正文' },
- { value: 'h1', label: '标题 1' },
- { value: 'h2', label: '标题 2' },
- { value: 'h3', label: '标题 3' },
- { value: 'h4', label: '标题 4' },
- { value: 'blockquote', label: '引用块' },
- { value: 'pre', label: '预格式/代码' }
- ];
-
- var SPECIAL_CHAR_ITEMS = [
- { key: 'sq', label: '方框 □', char: '□' },
- { key: 'ck', label: '对勾 √', char: '√' },
- { key: 'cc', label: '版权 ©', char: '©' },
- { key: 'reg', label: '注册 ®', char: '®' },
- { key: 'yen', label: '人民币 ¥', char: '¥' },
- { key: 'deg', label: '度数 °', char: '°' },
- { key: 'mul', label: '乘号 ×', char: '×' },
- { key: 'div', label: '除号 ÷', char: '÷' },
- { key: 'ell', label: '省略号 …', char: '…' },
- { key: 'dash', label: '破折号 —', char: '—' },
- { key: 'middot', label: '间隔号 ·', char: '·' }
- ];
-
- var TABLE_PRESET_ITEMS = [
- { key: '2x2', label: '2 × 2', rows: 2, cols: 2 },
- { key: '3x3', label: '3 × 3', rows: 3, cols: 3 },
- { key: '4x4', label: '4 × 4', rows: 4, cols: 4 },
- { key: '5x4', label: '5 × 4', rows: 5, cols: 4 },
- { key: '6x5', label: '6 × 5', rows: 6, cols: 5 }
- ];
-
- var LETTER_SPACING_OPTIONS = [
- { value: 'normal', label: '默认间距' },
- { value: '1px', label: '1px' },
- { value: '2px', label: '2px' },
- { value: '4px', label: '4px' }
- ];
-
- function rteSvg(children, extraClass) {
- return React.createElement('svg', {
- className: 'ct-rte-svg' + (extraClass ? ' ' + extraClass : ''),
- width: 16, height: 16, viewBox: '0 0 24 24',
- fill: 'none', stroke: 'currentColor', strokeWidth: 1.75,
- strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': true
- }, children);
- }
-
- function rteLetterIcon(letter, barColor, extraClass) {
- return React.createElement('span', { className: 'ct-rte-letter' + (extraClass ? ' ' + extraClass : '') },
- letter,
- barColor !== false ? React.createElement('span', {
- className: 'ct-rte-letter__bar',
- style: barColor ? { background: barColor } : null
- }) : null
- );
- }
-
- function rteIcon(name) {
- var map = {
- bold: rteLetterIcon('B', false),
- italic: rteLetterIcon('I', false, 'is-italic'),
- underline: rteLetterIcon('U', '#ef4444'),
- fontColor: rteLetterIcon('A', '#ef4444'),
- highlight: React.createElement('span', { className: 'ct-rte-letter ct-rte-letter--highlight' }, 'A'),
- eraser: rteSvg([
- React.createElement('path', { key: 'p', d: 'M20 20H8L4 16l8-8 8 8-4 4z' }),
- React.createElement('path', { key: 'p2', d: 'M12 6l6 6' })
- ]),
- image: rteSvg([
- React.createElement('rect', { key: 'r', x: '3', y: '5', width: '18', height: '14', rx: '2' }),
- React.createElement('circle', { key: 'c', cx: '9', cy: '10', r: '1.5', fill: 'currentColor', stroke: 'none' }),
- React.createElement('path', { key: 'p', d: 'M21 16l-5-5L5 19' })
- ]),
- link: rteSvg([
- React.createElement('path', { key: 'p', d: 'M10 14a4 4 0 0 1 0-5.5L12 6a4 4 0 0 1 5.5 0' }),
- React.createElement('path', { key: 'p2', d: 'M14 10a4 4 0 0 1 0 5.5L12 18a4 4 0 0 1-5.5 0' })
- ]),
- table: rteSvg([
- React.createElement('rect', { key: 'r', x: '3', y: '5', width: '18', height: '14', rx: '1' }),
- React.createElement('path', { key: 'p', d: 'M3 10h18M3 14h18M9 5v14M15 5v14' })
- ]),
- bulb: rteSvg([
- React.createElement('path', { key: 'p', d: 'M9 18h6M10 22h4' }),
- React.createElement('path', { key: 'p2', d: 'M12 2a6 6 0 0 0-3 11v1h6v-1a6 6 0 0 0-3-11z' })
- ]),
- undo: rteSvg(React.createElement('path', { d: 'M9 7H5v4M5 11a7 7 0 1 0 1.5 4.5' })),
- redo: rteSvg(React.createElement('path', { d: 'M15 7h4v4M19 11a7 7 0 1 1-1.5 4.5' })),
- more: rteSvg([
- React.createElement('circle', { key: 'c1', cx: '6', cy: '12', r: '1.25', fill: 'currentColor', stroke: 'none' }),
- React.createElement('circle', { key: 'c2', cx: '12', cy: '12', r: '1.25', fill: 'currentColor', stroke: 'none' }),
- React.createElement('circle', { key: 'c3', cx: '18', cy: '12', r: '1.25', fill: 'currentColor', stroke: 'none' })
- ]),
- alignLeft: rteSvg([
- React.createElement('path', { key: 'p', d: 'M4 6h16M4 10h10M4 14h16M4 18h8' })
- ]),
- alignCenter: rteSvg([
- React.createElement('path', { key: 'p', d: 'M4 6h16M7 10h10M5 14h14M8 18h8' })
- ]),
- alignRight: rteSvg([
- React.createElement('path', { key: 'p', d: 'M4 6h16M10 10h10M4 14h16M12 18h8' })
- ]),
- alignJustify: rteSvg([
- React.createElement('path', { key: 'p', d: 'M4 6h16M4 10h16M4 14h16M4 18h16' })
- ]),
- lineHeight: rteSvg([
- React.createElement('path', { key: 'p', d: 'M4 7h12M4 12h12M4 17h12' }),
- React.createElement('path', { key: 'p2', d: 'M20 7v10M18 9l2-2 2 2M18 15l2 2 2-2' })
- ]),
- letterSpacing: rteSvg([
- React.createElement('path', { key: 'p', d: 'M6 8v8M18 8v8M9 12h6' }),
- React.createElement('path', { key: 'p2', d: 'M4 12h2M18 12h2' })
- ]),
- outdent: rteSvg([
- React.createElement('path', { key: 'p', d: 'M4 6h16M4 10h10M4 14h16M4 18h8' }),
- React.createElement('path', { key: 'p2', d: 'M20 8l-3 4 3 4' })
- ]),
- indent: rteSvg([
- React.createElement('path', { key: 'p', d: 'M4 6h16M10 10h10M4 14h16M8 18h12' }),
- React.createElement('path', { key: 'p2', d: 'M4 8l3 4-3 4' })
- ]),
- listBullet: rteSvg([
- React.createElement('circle', { key: 'c1', cx: '5', cy: '7', r: '1', fill: 'currentColor', stroke: 'none' }),
- React.createElement('circle', { key: 'c2', cx: '5', cy: '12', r: '1', fill: 'currentColor', stroke: 'none' }),
- React.createElement('circle', { key: 'c3', cx: '5', cy: '17', r: '1', fill: 'currentColor', stroke: 'none' }),
- React.createElement('path', { key: 'p', d: 'M9 7h11M9 12h11M9 17h11' })
- ]),
- listOrdered: rteSvg([
- React.createElement('path', { key: 'p', d: 'M9 7h11M9 12h11M9 17h11' }),
- React.createElement('path', { key: 'n1', d: 'M4 7h1v3H4V7z', fill: 'currentColor', stroke: 'none' }),
- React.createElement('path', { key: 'n2', d: 'M4 11h2v1H4v2h2', fill: 'none' }),
- React.createElement('path', { key: 'n3', d: 'M4 16h2c0 1-1 1.5-2 2', fill: 'none' })
- ]),
- script: rteSvg([
- React.createElement('path', { key: 'p', d: 'M8 6h8M6 18l4-8h4l-2 8' }),
- React.createElement('path', { key: 'p2', d: 'M16 6v4' })
- ]),
- chevron: rteSvg(React.createElement('path', { d: 'M8 10l4 4 4-4' }), 'ct-rte-svg--chevron')
- };
- return map[name] || null;
- }
-
- function isHtmlContent(text) {
- return /<[a-z][\s\S]*>/i.test(String(text || ''));
- }
-
- function toEditorHtml(content) {
- if (!content) return '';
- if (isHtmlContent(content)) return String(content);
- return String(content)
- .replace(/&/g, '&')
- .replace(//g, '>')
- .replace(/\n/g, '
');
- }
-
- function htmlToPlainText(html) {
- if (!html) return '';
- if (!isHtmlContent(html)) return String(html);
- var div = document.createElement('div');
- div.innerHTML = html;
- return (div.textContent || div.innerText || '').trim();
- }
-
- function mergeBlocksToDocument(blocks) {
- var list = blocks || [];
- if (!list.length) return '';
- if (list.length === 1) {
- var single = String(list[0].content || '');
- return isHtmlContent(single) ? single : toEditorHtml(single);
- }
- return list.map(function (b) { return toEditorHtml(b.content); }).join('');
- }
-
- function documentToBlocks(html) {
- if (!html) return [];
- var div = document.createElement('div');
- div.innerHTML = html;
- var sections = div.querySelectorAll('.ct-section');
- if (!sections.length) {
- return [{ id: 'doc', title: '合同全文', content: html, locked: false }];
- }
- var blocks = [];
- sections.forEach(function (sec, idx) {
- var clone = sec.cloneNode(true);
- var labelClone = clone.querySelector('.ct-section-label');
- if (labelClone) labelClone.parentNode.removeChild(labelClone);
- blocks.push({
- id: sec.getAttribute('data-section-id') || ('s' + idx),
- title: sec.getAttribute('data-section-title') || ('模块' + (idx + 1)),
- locked: sec.getAttribute('data-section-locked') === '1',
- content: clone.innerHTML
- });
- });
- return blocks;
- }
-
- function countLockRegions(source) {
- var html = typeof source === 'string' ? source : mergeBlocksToDocument(source);
- var div = document.createElement('div');
- div.innerHTML = html;
- return div.querySelectorAll('.ct-inline-lock[data-inline-lock="1"]').length;
- }
-
- function countRiskRedlineRegions(source) {
- var html = typeof source === 'string' ? source : mergeBlocksToDocument(source);
- var div = document.createElement('div');
- div.innerHTML = html;
- return div.querySelectorAll('.ct-risk-redline[data-risk-redline="1"]').length;
- }
-
- function stripRiskRedlinePreviewFooters(html) {
- if (!html || typeof document === 'undefined') return String(html || '');
- var div = document.createElement('div');
- div.innerHTML = html;
- div.querySelectorAll('.ct-risk-redline__footer').forEach(function (el) {
- el.parentNode.removeChild(el);
- });
- return div.innerHTML;
- }
-
- function preparePreviewHtml(html) {
- var content = String(html || '');
- if (isWordFormattedDoc(content)) content = fixWordPreviewHtml(content);
- return stripRiskRedlinePreviewFooters(content);
- }
-
- function getDocumentTitle(html) {
- var div = document.createElement('div');
- div.innerHTML = html || '';
- var h1 = div.querySelector('h1');
- if (h1) return htmlToPlainText(h1.innerHTML) || '合同预览';
- var wordTitle = div.querySelector('.ct-word-title');
- if (wordTitle) return htmlToPlainText(wordTitle.innerHTML) || '合同预览';
- return htmlToPlainText(div.innerHTML).split('\n')[0].trim() || '合同预览';
- }
-
- function buildTableHtml(rows, cols) {
- var r = rows || 3;
- var c = cols || 3;
- var html = '
';
- for (var i = 0; i < r; i++) {
- html += '';
- for (var j = 0; j < c; j++) html += '| | ';
- html += '
';
- }
- return html + '
';
- }
-
- var CATEGORY_OPTIONS = [
- { value: 'lease', label: '商用车租赁合同', desc: '商用车租赁标准合同' },
- { value: 'purchase', label: '采购合同', desc: '车辆及备件采购标准合同' },
- { value: 'service', label: '服务合同', desc: '运维、加氢等服务类标准合同' }
- ];
-
- function v265LeaseBlocks() {
- if (typeof V265_LEASE_DOCUMENT_HTML !== 'undefined' && V265_LEASE_DOCUMENT_HTML) {
- return [{ id: 'doc', title: '合同全文', locked: false, content: V265_LEASE_DOCUMENT_HTML }];
- }
- return [
- { id: 'b1', title: '合同标题', locked: true, content: "商用车租赁合同" },
- { id: 'b2', title: '合同编号', locked: true, content: "合同编号:【LNZLHT {{contractCode}} 】" },
- { id: 'b3', title: '甲方(出租方)', locked: true, content: "甲方(出租方):{{lessorName}} (盖章)\n地址:{{lessorAddress}}\n联系人:{{lessorContact}}\n联系电话:{{lessorPhone}}" },
- { id: 'b4', title: '乙方(承租方)', locked: false, content: "乙方(承租方):{{customerName}} (盖章)\n统一社会信用代码:{{creditCode}}\n地址:{{customerAddress}}\n联系人:{{customerContact}}\n联系电话:{{customerPhone}}" },
- { id: 'b5', title: '正文部分', locked: false, content: "
(正文部分)
本合同经双方平等自愿协商,根据《中华人民共和国民法典》及相关法规,就甲方向乙方提供氢燃料电池车租赁服务之事宜,达成如下一致条款,以资共同遵守。
第一条 租赁标的、服务内容、租期、里程
租赁标的:租赁车辆信息及租金价格、保证金标准详见《租赁订单》(附件1)。
1.2 服务内容:甲方根据乙方的需求,为乙方提供符合约定的商用车供乙方合法使用,并提供有偿非车辆质量问题导致的车辆故障、事故救援服务。
1.3 租期:以双方签订的《租赁订单》(附件1)为准。约定的租期届满,若双方对租赁订单的内容没有变更,且任何一方未提出终止合同的,租赁期限顺延,顺延的期限与本次租赁订单的期限相同。若租赁订单内容有变更,双方签署新的《租赁订单》,租金价格、租期等相关内容,以新的《租赁订单》为准,《租赁订单》未约定的内容,仍以本合同的约定为准。
1.4 里程:乙方承诺按如下约定完成公里数(请在方框里用“√”进行选择。)
1.4.1 Ρ每月完成【 】公里;
1.4.2 ≤每季度完成【 】公里。
若乙方未完成本合同中约定的里程,甲方有权将车辆强制收回,甲方不承担违约责任。
" },
- { id: 'b6', title: '租金、费用及支付', locked: false, content: "
第二条 租金、费用及支付
2.1 租金的结算及支付
2.1.1 租金、服务费先付后用,每【 】个自然月为一个付款周期,每个付款周期末月的25日向甲方支付下个周期的租金和服务费,如25日为节假日的,付款日顺延至节假日后的第一个工作日。
2.1.2 保证金和首期租金及服务费支付:①提车日为当月15日前(含15日)的,于提车前2日内支付保证金和当月剩余天数租金及服务费,当月25日支付下个付款周期的租金及服务费;②提车日为当月15日后的,于提车前2日内支付保证金和当月实际剩余天数和下个付款周期的租金及服务费。
2.1.3 提车或还车当月的租金及服务费,以当月实际租赁天数按比例计算,计算公式如下:【(月租金+月服务费)/30】*当月实际租赁天数支付(金额取数按四舍五入取整到单位“元”)。
2.1.4 租赁期间非因车辆自身质量原因造成的租赁车辆无法上路、无法使用等情况的,乙方仍应按本合同约定支付租金及服务费。包括本条2.3.1中约定的其他费用。
2.1.5租金减免条件:
2.1.5.1基础减免:当月行驶里程达到6000公里及以上的,次月可享受2000元/辆的租金减免,当月行驶里程未达6000公里的,次月不享受租金减免。
2.1.5.2里程补足与累计:次月行驶里程可用于补足上月(截至2026年5月31日之前的月份)未达6000公里的差额部分,补足后可补享上月对应的租金减免,当月行驶里程超过6000公里的部分,可累计计入次月里程。
2.1.5.3连续周期减免:若连续两个月累计行驶里程达到12000公里,该两个月均能享受租金减免。
2.1.5.4持续达标减免:若租赁期间每月行驶里程均满6000公里,可每月享受次月2000元/辆的租金减免(若租期为1年,第12个月里程达标对应的减免,在第13个月租金结算时执行)。
本租金减免政策有效期至2026年12月31日止。
2.2 氢气费(含加氢相关服务费)
2.2.1 氢气原则上由乙方自行解决。如需甲方安排加氢的,先款后货、全额预付款支付及结算。乙方提前预估当月用气总量并计算氢气费用后将氢气预付款【 】元提前【 】个工作日内转账给甲方,甲方在收到乙方预付款后安排加氢。乙方预付款不足【 】元时,乙方接到甲方通知后2个工作日内支付预付款;否则,甲方有权不予安排车辆加氢气,由此造成的一切损失由乙方承担,给甲方造成损失的,乙方还应承担赔偿责任。
2.2.3每月25日核对上月25日至本月24日的用气对账单,有异议2个工作日内提出,双方重新核对账单,账单核对无误后,对核对无误的账单书面确认。
2.2.4 氢气价格按市场价随行就市调整。
2.2.5 乙方还车时车里剩余氢气量若低于交车时的氢气量,则按照【 】元/公斤向甲方支付氢气费,若高于交车时的氢气量,乙方同意甲方不向乙方返还氢气费。
2.2.6 租赁车辆充电产生的电费及与充电相关的费用由乙方承担。租赁车辆原则上优先选择甲方经营的充电桩充电,若选择甲方经营的充电桩充电,费用结算方式为现结。
2.3 其他费用
2.3.1 租赁期间车辆产生的其他费用,包括但不限于非质量问题产生的车辆维修费、保养费、违章费用、施救费、证照补办费用、改装费、违约金、能耗费、路桥费及乙方要求增加购买其他保险的费用等,均由乙方全额另行承担。
2.4 垫付费用:本合同中若甲方垫付费用的,乙方应在甲方通知后【3】个工作日内一次性足额支付给甲方。
2.5 甲方收款账户
2.5.1乙方应将上述租金、服务费、保证金、氢气费及其他费用统一汇入甲方如下指定账户,否则视为未支付:
户 名:【羚牛氢能科技(广东)有限公司 】
开户行:【招商银行广州萝岗支行 】
账 号:【120924165110201 】
2.5.2 本合同所涉及的所有费用均通过银行转账的方式支付至甲方上述指定账户。甲方不会以任何方式允许甲方人员通过个人账户收取本合同所涉及的各项费用,若甲方人员要求将本合同项下产生的各项费用汇至其个人账户或其他账户,乙方可拨打甲方24小时服务热线:400-021-1773。
2.5.3 乙方将本合同所涉及的费用汇入甲方指定上述收款账户之外的任何账户导致的损失,由乙方自行承担,同时乙方仍须按本合同约定向甲方支付各项费用。
2.6 发票
2.6.1 乙方开票信息如下:
企业名称:
开户银行:
银行账号:
纳税人识别号:
企业地址:
企业电话:
2.6.2甲方收到乙方支付的租金和服务费后分别开具等额的增值税发票。若乙方变更开票信息,乙方需在付款周期15日前书面告知甲方,否则所产生的损失由乙方承担。若国家发布新的税收政策导致税率变化,甲方按最新政策开具发票,乙方支付的总价款不变。
2.6.3 甲方除开具租金和服务费发票外,本合同中的其他费用,甲方不向乙方开具对应的服务费发票。
2.7 乙方款项抵扣
乙方应及时足额地支付租赁费、服务费、保证金以及其他应当由乙方承担的各项费用;乙方存在任何应付未付费用时,甲方有权从保证金、应返还乙方的保险理赔款以及乙方在甲方处的其他款项中先行抵扣,不足部分,乙方应及时补足。
2.8 碳资产
本合同约定仅限于车辆使用,该车辆所产生的碳资产数据权益和碳资产收益归甲方所有,本合同报价不含减碳、碳资产管理费用等。
" },
- { id: 'b7', title: '交车与车辆管理', locked: false, content: "
第三条 交车与还车
3.1 本合同签署前,乙方需提供如下有效证据资料:包括但不限于营业执照、法定代表人身份证复印件、驾驶员驾驶证、驾驶员从业资格证等。复印件留存甲方,原件查验后退回。
3.2 租赁车辆交付时,乙方应对租赁车辆状况及附属设施、有效证件标志进行现场检验,确认无误后应在《交接车验收清单》上签字/盖章确认。提车后,非车辆质量问题产生的一切风险由乙方承担。
3.3 还车时,乙方负责将租赁车辆归还至甲方指定的还车地点。 乙方还车时,应携带提车时签订的《交接车验收清单》,经甲方检查车辆确认无误后,双方签署《交接车验收清单》,确认还车。
3.4 返还车辆除正常使用耗损外,车辆信息与《交接车验收清单》保持一致,无任何毁损,证照齐全,无未处理交通违章、交通事故等不存在未决纠纷争议可能影响甲方利益情形。否则,甲方有权拒绝接收车辆,乙方应在限期内整改,整改期内日租金按两倍日租金标准继续计算,直至车辆符合交还标准;如乙方拒绝或超过十五天仍未完成整改的,甲方有权强制收回车辆并送至修理厂进行修复或调整,因此产生的运输费、修理费等费用以及处理交通违章、事故等发生的一切费用,均由乙方全额承担。
第四条 车辆的风险与管理
4.1 车辆自交付乙方之时起,车辆发生损毁、灭失、被盗、遗失等风险的,由乙方承担。乙方应赔偿甲方全部损失,但该损失是因车辆自身质量问题导致的除外。租赁期间,因租赁车辆引发的甲方、乙方、乙方聘用人员或第三者损失的,乙方应承担全额赔偿责任。
4.2 车辆自交付乙方之时起,乙方负责车辆相关安全保管义务和日常管理,乙方应在本合同约定的使用区域内使用车辆,使用车辆时应符合国家、地方的相关法律法规、规章制度,遵守交通规则,禁止超速、超载,禁止装载易燃易爆、易腐蚀等危险物品及在车中留下刺激性气味的物品。
4.3 租赁期间,乙方装载4.2条中禁止装载的物品,或车辆发生交通事故或其他安全、意外事故,造成甲方、乙方、第三方财产损失或人身损害、车辆损失、设备损失,或导致包括但不限于有关部门的罚金或罚分、行政处罚等一切责任的,均由乙方承担全部责任。给甲方造成的损失或者导致甲方承担责任的,乙方除承担本条前述的全部责任外,还须承担甲方的间接损失、可得利益等。如导致甲方赔偿的,甲方有权向乙方追偿。
4.4 租赁车辆的车身外观、车身广告等权益由甲方享有,未经甲方书面同意,乙方不得擅自更改车身外观,增加车身广告等。否则必须恢复车辆原状,若未恢复的,根据实际发生的费用向甲方支付修复费用,此费用甲方有权从保证金中直接扣除,不足部分,另行向甲方支付。
4.5 无论乙方自身运营或聘用他人运营标的车辆,乙方承诺自身或聘用第三人具备运营车辆的全部证照,乙方对聘用人员证照负有审核义务,证照包括但不限于营业执照、组织机构代码、车辆驾驶人员驾驶证、身份证、道路运输许可证(如进行营运的)、运输人员从业资格证等,乙方对证照的真实性、有效性以及完整性负责,并就该第三人驾驶或使用标的车辆的行为所产生的一切法律责任承担无限连带责任,如导致甲方赔偿的,甲方有权向乙方追偿。在签订合同时,乙方应向甲方出示原件并提供全部证照复印件备案,如驾驶人员发生变更的,乙方应在变更前将全部证照提供给甲方备案。
4.6 未经甲方书面同意,乙方不得将租赁车辆以转让、出借、转租、合租等任何方式许可任何第三方使用,不得设立任何形式抵押、留置、质押等权利负担,不得擅自改装(安装)车辆或拆除车辆设施、设备、标记、广告等,不得拆卸、更换车辆零部件,不得将车辆的行驶证件及相关手续、车辆号牌以任何方式许可第三方使用。
第五条 车辆的维修、保养
5.1 租赁期间,乙方应按照驾驶技术规范及该车使用说明书等规定的要求使用、保养车辆,坚持“三检三查”制,确保车辆技术状况符合规范和要求。甲方有权对车辆的技术状况进行定期或不定期的检查,并根据检查情况要求乙方修复。
5.2 乙方应每天对刹车油、防冻液、刹车片、轮胎、轮胎气压、灯光等做常规检查,如发现问题,应及时到甲方指定的维修站进行维修,并及时向甲方报备维修情况。
5.3 租赁期间,租赁车辆损坏的,乙方应在甲方指定维修站对车辆进行维修、保养,将车辆修复至符合有关技术规范标准的状态,费用由乙方全额承担,并在3日内通知甲方,将维修、保养相关单据的原件交回甲方留存。如需在指定维修站以外维修、保养车辆的,应征得甲方书面同意,否则属于乙方违约,乙方应按2000元/次的标准向甲方支付违约金。
5.4 租赁期间,乙方应负责保管车辆及GPS等设施设备,进行定期或不定期的检修、检测,确保其性能可靠、使用正常。如造成车辆及设施设备损坏、过度磨损或遗失、损毁、失效的,由乙方负责照价赔偿甲方。
5.5 乙方另行购买甲方维保服务的,甲方所提供维保服务仅限车辆日常的技术指导、使用培训、易损件的维修更换服务,不含车辆维修等其他服务。
5.6 非因车辆自身质量问题产生的车辆维修费用及拖车费由乙方全额承担。费用以维修站的价格为准。
5.7 因发生车辆故障、交通事故等情形,甲乙双方对是否属于车辆质量缺陷导致、车损价值等无法达成一致意见的,双方可委托共同认可的第三方机构进行评估、鉴定。鉴定、评估前费用由双方共同平均分担,评估后鉴定结果属于甲方全部或部分责任的,鉴定、评估费由甲方全部或部分承担,甲方应向乙方支付乙方承担的全部或部分鉴定、评估费;不属于甲方责任或属于甲方部分责任的,鉴定、评估费由乙方全部或部分承担,乙方应向甲方支付甲方先行承担的全部或部分鉴定费、评估费。乙方未响应甲方办理评估、鉴定委托事宜通知的,甲方可单方委托第三方机构进行评估鉴定。
第六条 保险、事故、动态违规及违章处理
6.1 甲方负责的保险
6.1.1 若租金中已含租赁车辆的交强险及商业险(包括三者险、车损险)保险费用,乙方对甲方所投保险险种及保额没有异议。如乙方要求增加险种或提高保险额度的,乙方应在租金标准外另行向甲方支付保险费用,由甲方负责向甲方合作的保险服务商购买保险。
6.1.2 若租金中不包含租赁车辆的交强险或商业险保险费用,乙方需按照甲方要求的保险险种委托甲方代为购买,乙方应另行向甲方支付保险费用。若标的车辆保险费用已经由甲方先行购买的,乙方应将相应保险费用支付给甲方。如遇租期内续保,乙方应在甲方通知后【3】个工作日内将相应保险费用支付给甲方。
6.2 乙方负责的保险
6.2.1 汽车车上人员责任保险(驾驶员、车上其他人员)由乙方购买:乙方应为使用该车辆的驾驶员及车上其他人员购买责任保险,租赁期内所发生的与乙方驾驶员及车上其他人员相关的一切财产、人身损失等由乙方承担,若给甲方造成损失的,乙方需向甲方承担赔偿责任。
6.2.2 货物保险:乙方应自行购买货物运输相关保险,并自行承担所有管货责任。租赁期内,无论何种原因导致乙方货物毁损、灭失、污染、变质、损耗、短少等异常情况,甲方均免责。乙方投保时,亦应向保险人要求豁免甲方责任,即使货物异常是由于甲方车辆问题所致,甲方亦不承担任何赔偿责任。
6.3 事故报告
6.3.1在租赁期内,车辆发生安全事故的,乙方应在1小时内如实报告公安交通管理机关、甲方和甲方安全部及保险公司,并配合甲方处理,且到甲方指定的维修站进行维修,若乙方隐瞒事故真实情况、虚构事故情况等或未在甲方指定维修站进行维修的,需向甲方承担3000元/次/辆违约金。当需要办理保险理赔事项时,乙方应协助甲方办理保险理赔手续,因协助办理所产生的费用由乙方承担,若不配合甲方处理安全事故或者不协助办理保险理赔事项的,须向甲方承担500元/次/辆违约金。本条项下全部应付违约金,统一并入下一租金付款周期同步结算。
6.3.2 如乙方怠于履行本合同约定义务导致无法办理保险理赔或保险公司拒赔、免赔的,全部损失和法律责任由乙方承担,造成甲方或第三方损失的,乙方应予以赔偿。
6.4 出险
6.4.1 租赁期间,如车辆发生安全事故造成损失超出保险公司赔付金额的,超出部分的损失由乙方全额承担。
6.4.2 租赁期间,租赁车辆出险并办理保险理赔的,乙方应每次向甲方支付保险上浮费,18吨车型主责及以上责任为3000元/次/辆,其他责任为2000元/次/辆(驾驶员无责除外)。如乙方自车辆出险之日起 5个工作日内未向甲方支付上述保险上浮费,则甲方有权直接从车损险理赔款项中扣除对应的保险上浮费,若车损险理赔款项不足以覆盖乙方应向甲方支付的保险上浮费,差额部分乙方须于下一租金支付周期内,连同当期租金及其他应付费用一并结清。
6.4.3 乙方出险进保,应征得甲方书面同意。如事故损失总金额不满足甲方进保理赔标准的(2000元里面不允许进保,),由乙方向甲方报备后自行到甲方指定维修站维修并由乙方自行承担相应费用,无需办理保险理赔手续。如乙方在未征得甲方书面同意前提下向保险公司报案赔付的,须向甲方承担2000元/次/辆违约金,同时,甲方不向乙方支付任何保险理赔款,若保险理赔款直接打入乙方账户的,乙方需将保险理赔款返还给甲方。
6.4.4 保险上浮费和超出保险公司赔偿的部分,甲方有权从保险理赔款中先行抵扣,如保险理赔款有剩余且应支付给乙方的,在乙方不存在到期应付未付款项时,甲方在收到理赔款后 15个工作日内无息支付给乙方,如保险理赔款直接赔付给第三方的,则乙方应在甲方通知后3个工作日内支付给甲方,且甲方有权从保证金中直接抵扣。
6.4.5 单车事故进保审批
6.4.5.1 租赁期间,因乙方违反限高、限速、限重等交通管理规定或操作规范导致的单车事故,原则上不予办理保险理赔,相关车辆维修、施救等全部费用由乙方自行承担。
6.4.5.2 若乙方因特殊情况申请对本条 6.4.5.1 约定的单车事故进行保险理赔(以下简称 “进保申请”),需向甲方提交书面申请,并附事故现场照片、交警部门出具的事故认定书(如有)、车辆损失评估报告等相关证明材料。
6.4.5.3 甲方收到乙方进保申请后,由甲方在收到材料后【5】个工作日内完成审批并出具意见。
6.4.5.4 仅甲方审批通过,甲方才协助办理理赔,未经审批擅自进保的,乙方支付【2000】元/次辆违约金,且承担全部保险费用及理赔损失。
6.4.5.5 经甲方审批通过的进保,乙方仍需按 6.4.2 条支付保险上浮费,甲方可根据情况要求乙方额外承担评估费、手续费等。
6.5 安全教育
6.5.1 乙方发生交通事故或者安全事故的,甲方有权对乙方及乙方驾驶员进行教育培训。
6.5.2 在租赁期内,若乙方发生一般有责事故及以上事故,乙方必须做到:①查清事故原因;②严肃处理事故责任者;③对车辆事故的驾驶员进行教育培训;④落实防范措施。若甲方做过安全教育培训的,还需向甲方提供安全教育会议内容、安全教育签到表、现场至少三张照片。若乙方未做到前述事项的,须向甲方承担1000元违约金。
6.5.3若乙方发生三次或者三次以上(含三次)以及一个星期连续发生两次及两次以上(含两次)安全事故或者交通事故的,甲方有权对乙方及乙方驾驶员进行安全教育培训,乙方必须参加甲方组织的教育培训活动,乙方接到甲方教育培训未按时参加的,需向甲方承担1000元违约金。如乙方经甲方约谈教育后仍发生事故,视为乙方严重违约,甲方有权单方面无条件强制收回租赁车辆,无需承担任何违约责任。收车过程中产生的拖车费、保管费、运输费、场地占用费等一切相关费用,均由乙方承担;同时,因乙方前述违约行为造成甲方全部损失(含但不限于行政罚款、赔付款项、律师费、诉讼费、保全费、差旅费等),均由乙方全额承担,甲方有权从保证金中直接抵扣,保证金不足以清偿的,甲方有权向乙方继续追偿剩余款项。
6.5.4动态监控违规管理:
6.5.4.1一般违规:租赁期限内,因驾驶员违规行为产生属实动态监控预警风险的,乙方按以下标准承担违约金:首次50元/次,第二次100元/次,第三次及以上违规500元/次,乙方应当在甲方通知违规之日起1个自然日内支付给甲方,逾期未支付的,乙方须在次月车辆租金结算时一并向甲方支付。乙方更换新驾驶员须提前向甲方书面报备,人员更换后违规次数将重新计算。
6.5.4.2 严重违规处置及车辆收回:租赁期限内,车辆因违规导致动态监控风险属实,连续2个月被交管部门通报的,甲方有权要求乙方在第2个自然月底起将车辆停运1个月,停运期间正常计收租金。为避免车辆营运证连续3个月通报导致被注销,乙方须严格遵照甲方停运要求执行,乙方拒不配合停运的,视为严重违约,甲方有权单方无条件强制收回租赁车辆,无需承担任何违约及赔偿责任。若因乙方拒不配合收车、违规持续营运造成车辆营运证被注销的,乙方须全额承担营运证注销后6个月内全部车辆租金。车辆强制收回过程中产生的拖车费、停放保管费、转运费、场地使用费等全部费用均由乙方承担。因乙方前述违约行为给甲方造成的全部损失(含但不限于行政罚款、赔偿金、律师费、诉讼费、保全费、差旅费等),均由乙方全额承担,甲方有权从车辆保证金中直接抵扣,保证金不足以清偿的,甲方有权就剩余差额向乙方另行追偿。
6.6 违章处理
6.6.1车辆发生违法违规的,乙方应及时处理车辆违章并承担处理费用(违章,最晚应在甲方通知后15个自然日内处理完毕)。乙方超过15天未处理的,甲方有权代办处理,并向乙方发送强办告知函,明确强办时间、强办费用,强办处理的收费标准以附件2的约定为准。同时,甲方有权按一条违章信息1200元的标准(广东区域内为2000元/条),向乙方收取违约金;违约金金额不足以覆盖甲方损失时,乙方还应承担赔偿责任。
6.6.2在处理违章过程中,乙方必须遵循如下驾驶证使用限制:车辆租赁期限6个月以下的(含6个月),仅限于一本驾驶证处理违章,租赁期限超过6个月的,仅限于两本驾驶证处理违章,乙方处理违章超过前述限制的,须向甲方承担 5000元/ 次/辆的违约金。租赁满一个记分周期可使用三本驾驶证。
6.7 年检年审配合
6.7.1甲方负责办理车辆年检年审等相关证照手续,乙方应积极配合,在甲方通知的时间内将车辆开到指定地点。乙方完全明白且理解,车辆的年检年审等检验检测工作,是车辆依法、安全运营的基本保障,如乙方未能在甲方通知时间内将车辆开到甲方指定地点,属于乙方严重违约行为,不论最终是否顺利完成相关检验检测手续,乙方均应向甲方支付2000元/次的违约金。
6.7.2车辆年审过程中发现有未处理违章罚分、罚款等,经甲方以口头、电话、短信、微信及其他方式等前述任一方式告知乙方后,乙方在【3】个工作日内仍未履行的,甲方有偿代办处理,代办处理费用同6.6.1条规定。
6.7.3 乙方应按有关规定使用车辆,不得私自改装车辆,如需改装应经甲方同意,保证车辆在年检时符合要求,如年检不合格,乙方应自费维修整改,经维修整改后仍不合格的,乙方应赔偿甲方重新购买同款同型车辆及设施设备的全部费用。如乙方未经甲方同意,私自拆卸、改装车辆核心零部件,视为乙方严重违约,由此产生的一切责任和后果均由乙方承担;如因此造成车辆严重安全隐患,乙方须根据甲方要求,按照该车辆购买价(以发票金额为准)的两倍购买该改装车辆。
6.7.4 租赁期间,车辆相关证照遗失、被盗、毁损的,甲方可以协助补办,乙方应承担补办证照发生的费用(包括但不限于差旅费、工本费、官费等);具体费用标准以附件2约定的为准。在证照办理期间,租赁费用不停止计费。
第七条 调换车辆和备用车辆服务标准
7.1 甲方有权根据实际运营情况,对已经出租给乙方的车辆进行调换,但调换车辆应是同类型车辆,并提前15天通知乙方,若乙方不同意,甲方有权强制收车,终止与乙方的合作,本合同即终止,双方均不承担违约责任。
7.2 在租赁期内,如非因车辆自身质量问题导致维修的,维修期间,乙方可向甲方申请备用车辆,在征得甲方同意后,交付备用车辆供乙方使用,乙方应按照交付车辆类型对应的租金标准另行向甲方支付租金、保险费等租赁费用。
7.3 调换车辆和备用车辆交还车流程参照本合同相应条款的约定。
" },
- { id: 'b8', title: '违约责任', locked: true, content: "
第八条 违约责任
8.1如乙方违反本合同项下任何约定(含保证人违约),视为乙方违约,乙方应当按照现行法律法规及本合同约定向甲方承担违约责任,且甲方有权采取如下一种或者多种救济措施以维护其权利:
8.1.1要求乙方在5日内补正或采取补救措施,未在5日内整改补正的,甲方有权书面通知乙方单方终止本合同或终止所涉车辆租赁关系。
8.1.2要求乙方赔偿甲方的经济损失。乙方致使甲方承担任何费用、责任或者遭受任何损失的,乙方应就前述任何费用、责任或者损失向甲方进行赔偿,这些费用、损失包括甲方向第三方支付的或导致第三方遭受的赔偿金、违约金等费用及损失。
8.1.3要求乙方承担因乙方行为导致甲方进行各类诉讼或者仲裁而产生的费用,包括但不限于诉讼费、律师费、保全费、公证费、鉴定费、人员工资、差旅费等,且这些费用不应包含在本合同约定的违约金中。
8.2 乙方同意并确认,如乙方违反本合同项下任何一项约定、任何承诺和保证,除本合同另有特别约定外,乙方应按5000元/次的标准向甲方支付违约金。致使甲方承担任何费用、责任或者遭受损失的,乙方应就上述任何费用、责任或者损失(包括但不限于因违约而支付或损失的利息以及律师费)向甲方另行赔偿。
8.3 本合同履行期内,乙方逾期支付租赁费、保证金以及应支付的其他任何费用的,每逾期一日,应向甲方支付应付款项千分之三的违约金,且甲方有权锁车再进行协商处理;超过当期结算日期3天仍未支付相关费用,甲方有权提前终止本合同并强制收回车辆。
8.4 乙方根据法律及本合同约定应向甲方支付费用、赔偿损失或承担其他法律责任,在乙方未能全面履行时,甲方可从保证金中直接进行等额抵扣,不足部分仍由乙方承担,且乙方应在甲方书面通知后3个工作日内补足保证金至本合同约定数额,否则,每逾期1日,乙方每日按照应付未付保证金金额的千分之三向甲方支付违约金。
8.5 在租赁期内,乙方使用标的车辆超载、超速或有其他违反交通规范行为但未造成损失的,法律责任由乙方承担,甲方给予乙方警告处理,后续若拒不纠正再次发生的,乙方应向甲方支付2000元/次违约金,达到提前终止合同条件的,甲方有权提前终止合同并强制收回车辆。
8.6 若因乙方未按1.4条完成里程,造成甲方或车辆厂商不能或未能足额申领国家、地方补贴的,差额部分由乙方负责赔偿给甲方或车辆厂商,导致甲方赔偿的,甲方有权向乙方追偿。
8.7 乙方按照本合同约定向甲方支付违约金的,如同一违约情形下违约金约定不一致的,以约定较高标准的违约金为准,如同一违约情形下设定不同类型违约金的,违约金应累计计算,如违约金不足以弥补甲方损失的,乙方另行向甲方补足。
" },
- { id: 'b9', title: '合同终止及其他', locked: true, content: "
第九条 合同终止、解除
9.1 因不可抗力或行业主管部门的要求,致使本合同无法继续履行的,甲乙双方均有权提前终止本合同,双方均不承担违约责任,在乙方向甲方结清全部费用后,双方无任何争议,甲方将剩余保证金及租金无息退还乙方。
9.2 因甲方经营状况发生重大变化,致使甲方不能继续从事车辆租赁服务的,甲乙双方均有权提前终止本合同,且双方均不承担违约责任,在乙方归还甲方车辆,向甲方结清全部费用后,甲方应将剩余保证金及租金无息退还乙方。
9.3 经甲乙双方协商一致,本合同可以解除或提前终止。
9.4 在租赁期限内,因乙方行为导致甲方解除或提前终止本合同的,或乙方出现下列情形之一的,甲方有权立即解除或提前终止本合同并强制收回车辆,且乙方应向甲方支付违约金,违约金标准为租赁当年月平均租金总价标准的2倍:
9.4.1利用标的车辆从事违法犯罪活动的,或因涉嫌违法犯罪被采取强制措施或受到行政处罚的;
9.4.2 未按期支付本合同项下的相应费用超过3个工作日的,经甲方催告后仍不支付的;
9.4.3涉酒涉毒驾车、交通事故逃逸、不及时抢救伤员保护现场、谎报或瞒报交通事故的;
9.4.4 擅自将标的车辆转让、转租、转包,或设置抵押、留置、质押等负担,或恶意更换车辆零部件或拆撤、损毁、涂抹车辆设施、设备、标记、广告等的;
9.4.5 标的车辆技术状况经甲方累计3次检查不合格,或经甲方检查不合格要求乙方修复,乙方在3日内拒不修复的;
9.4.6 向甲方提供虚假证件或资料的;
9.4.7 发生3次有责交通事故或单次有重大、特大交通事故的;
9.4.8甲方通知乙方协助办理标的车辆年检手续,乙方不按甲方的要求履行协助义务,导致标的车辆无法年检或年检不合格的;
9.4.9利用标的车辆进行相关法律法规明令禁止的行为,或其他严重影响甲方权益或可能导致甲方损失的行为;
9.4.10 乙方有违反本合同约定导致甲方解除或提前终止本合同的其他情形的。
9.5 租赁期限届满前,乙方提前退租的,则属于乙方严重违约,乙方应按租赁当年月平均租金总价标准的2倍向甲方支付租金补贴,租金补贴甲方有权从乙方保证金中直接抵扣。
9.6 甲方提前解除本合同的,应提前15天书面通知乙方,乙方如有异议的,乙方应在通知送达之日起15日内书面回复,但不影响甲方解除合同的效力。
9.7 本合同中的合同解除、业务终止之标准:甲乙双方在《交接车验收清单》上签字,退车手续办理完毕,乙方处理完所有违章,扣除各种乙方应承担的费用,甲方无息退还保证金。
9.8 乙方若需要办理ETC,由乙方自行办理。合同解除、业务终止后,乙方须先自行注销ETC,再办理退车手续,否则向甲方支付2000元/卡退卡费。
第十条 其他
10.1 关于送达:任何与本合同有关的由一方发送给其他方的通知或其他通讯往来(“通知”)应采用书面形式,按照下列通讯地址或通讯号码或电子邮箱送达被通知人均构成有效通知,包括但不限于法院、仲裁机构的法律文书及双方的来往函件等。
甲方:羚牛氢能科技(广东)有限公司
通讯地址:
联系人姓名及电话:
邮箱:
乙 方 :
通讯地址:
联系人姓名及电话:
邮箱:
10.2 任何一方上述的通讯地址或通知方式发生变化(“变动方”),变动方应当在该变更发生后的七(7)日内通知其他方。变动方因上述地址不明确或未按约定及时通知,导致法院、仲裁机构的法律文书或任一方文件无法送达的,文件退回之日即视为送达之日。甲乙双方确认,前述送达方式适用于各个司法阶段,包括但不限于一审、二审、再审、执行以及督促程序。
10.3 本合同中约定的违约责任、赔偿责任条款以及乙方义务,甲方于订立合同时已提请乙方注意并按乙方要求对该条款予以说明,乙方已充分了解并自愿订立且不再提出违约金、赔偿金过高和义务过多的请求。
10.4 本合同未尽事宜可另行签订补充合同,补充合同与本合同具有同等效力。
10.5 甲、乙双方因履行本合同发生争议,可协商解决,协商不成提起诉讼的,甲乙双方一致同意由合同签订地(浙江省嘉兴市平湖市乍浦镇)人民法院管辖。
10.6 本合同一式两份,甲方持一份,乙方持一份,在甲方盖章,乙方签字(自然人)或盖章后生效,若有保证人,保证人签署本合同及附件《保证人的保证责任》后,对保证人生效。
10.7 本合同所有附件、附表、车辆交接单均是本合同的有效组成部分,与本合同具有同等的法律效力。本合同包括但不限于以下附件:
附件1《租赁订单》、附件2《车辆产生的费用》、附件3《安全责任告知书》、附件4《重型普通货运车辆租赁动态监管责任告知与确认书》、附件5《安全责任承诺书》、附件6《车辆使用规范和驾驶员要求》《授权委托书》《安全责任协议》及其他。
(以下无正文)
" },
- { id: 'b10', title: '签章页', locked: true, content: "甲方(盖章):____________ 乙方(盖章):____________\n签订日期:{{signDateYear}} 年 {{signDateMonth}} 月 {{signDateDay}} 日\n\n(以下无正文)\n\n本合同所有附件、附表、车辆交接单均是本合同的有效组成部分,与本合同具有同等的法律效力。本合同包括但不限于以下附件:\n附件1《租赁订单》、附件2《车辆产生的费用》、附件3《安全责任告知书》、附件4《重型普通货运车辆租赁动态监管责任告知与确认书》、附件5《安全责任承诺书》、附件6《车辆使用规范和驾驶员要求》《授权委托书》《安全责任协议》及其他。" },
- { id: 'b11', title: '附件1 租赁订单', locked: false, content: "
附件 1:租赁订单 订单编号(LNZLHT )
甲方(出租方): 羚牛氢能科技(广东)有限公司
乙方(承租方):
本订单租赁车辆总计 辆,合同租金及服务费含税总价为:¥ 元,保证金总计需缴纳¥ 元(若开具保证金收据的,退车时应提交保证金收据原件方可退还保证金),首期租金及服务费含税需支付¥ 元。租赁车辆含保险总计 辆,每辆保险险种包含 三者责任险【 】万元、车损 ,含通行证总计 张。
一、租赁车辆信息
品牌
车型
车牌号
租金及服务费
小计
(元/ 月/辆,含税)
价格及服务内容
保证金
(元/辆)
车辆租赁期限
\u0007\u0007\u0007车辆租金
(元/月/辆,含税)\u0007服务费
(含税)\u0007服务内容\u0007\u0007\u0007\u0007 \u0007 \u0007 \u0007 \u0007 \u0007 \u0007 \u0007 \u0007\u0007 \u0007 \u0007 \u0007 \u0007\u0007 \u0007\u0007 \u0007\u0007
车牌号在签约时无法确定的,以实际交付的车牌号为准,若后续需要更换车辆的,均以《交接车验收清单》为准。
二、其他约定:
1.车辆交付(交还)地点: 。车辆交付时间:车辆交付时间: 年 月 日(以实际交付的时间为准)。
2.租赁车辆仅限 行政区域范围内使用,超出前述约定区域范围使用租赁车辆应事先征得甲方书面同意并办理相关手续。
3.甲乙双方协商一致增加租赁车辆的,双方另行制作《租赁订单》,经甲方盖章,乙方签字/盖章后生效。
4 、甲乙双方均认可并接受双方签订的《商用车租赁合同》(合同编号 )全部内容,本租赁订单列明的条款的,按本租赁订单执行,本租赁订单未列明的条款,均按照《商用车租赁合同》执行。
5.甲方有权对租赁车辆进行调换,但应提前15天通知乙方,乙方必须配合。还车、调换车辆时车辆外观、驾驶室、车厢必须保持干净整洁,否则收取清洗费,车身原车广告未经甲方同意不得撕毁、损坏、涂抹,否则承担车辆的修复费。本条中的清洗费,500元/辆,车身修复费,5000元/辆,甲方有权在保证金直接扣除。
6.租赁期内车辆产生的能耗费、停车费等用车费用由乙方承担。
7.本《租赁订单》一式两份,甲方执一份,乙方执一份,在甲方盖章,乙方签字(自然人)或盖章后生效。保证人签字(自然人)或盖章后,对保证人生效。
甲方(签章):
乙方(签字/盖章):
授权代表:
授权代表:
签订日期:
年 月 日
签订日期: 年 月 日
" },
- { id: 'b12', title: '附件2 车辆产生的费用', locked: false, content: "
附件2:车辆产生的费用
一、车辆维保、易损件、车辆轮胎、蓄电池及送车上门和上门收车费用:
维保服务
易损件
轮胎及蓄电池
自行承担车辆维保所发生的所有费用
自费承担
型号:11.00R20 18PR ,自费承担,还车时轮胎每磨损1mm,乙方需向甲方支付【110 】元/毫米的折旧费(计费公式:(交车时轮胎厚度-还车时轮胎厚度)*【mm 】,如乙方在租赁期内更换过轮胎,计算费用为负值的,乙方无需支付费用,甲方也不做任何补偿。)蓄电池,自费承担,每块电池【1200 】元/2年,按照实际租赁时间折算费用。
特别说明:1、轮胎、门把手、刹车片等易损件正常磨损达到需更换时客户负责更换,配件、维修工时费乙方自理;2、乙方充分知晓和同意,如果承租的甲方车辆并非全新车辆,或面临车辆租赁后标的车辆配件即过保的情形;3、如乙方未根据下表维护保养标准执行车辆维护工作,造成车辆脱保的,由此给甲方产生的不利影响、额外义务负担、费用损失等均由乙方自行承担。
送车上门,上门收车:从出发往返1公里以内免费;往返1公里以上,按8元/公里收费;人工费以实际维修项目算。拖车费:起步价【400】元+【 5】元/公里/空车,起步价【400】元+【15】元/公里/重车;基础服务费为【100 】元/辆/次。材料费以维修站的价格为准,最终以甲方确定的价格为准。
二、保养和修复:不论乙方租赁车辆期限长短,乙方确认并同意均按照下述规则维护保养和修复标准执行, 产生的费用按维修站的价格计算,若维修站未确定价格的,参考下表价格执行,最终以甲方确定的价格为准:1、底盘保养
序号\u0007区分\u0007保养项目\u0007周期/万KM\u0007型号\u0007数量\u0007单价\u0007次数\u0007总价\u0007公里要求(万公里)\u0007\u00071\u0007配件\u0007驱动电机、电池冷却液\u000724个月/20万公里\u0007重负荷有机乙二醇型冷却液\u000736L\u0007143\u00072\u0007286\u000720\u0007\u00072\u0007工时\u0007\u0007\u0007\u0007\u000750\u00071\u000750\u0007\u0007\u00073\u0007配件\u0007转向器\u00076个月/10万公里\u00078 号液力传动液)及滤芯\u00071.7L\u000725\u00071.7\u000742.5\u000710\u0007\u00074\u0007工时\u0007\u0007\u0007\u0007\u000750\u00071\u000750\u0007\u0007\u00075\u0007配件\u0007新能源法士特、绿控\u000712个月/5万公里\u0007GL-5\\\\85W\u00077L\u000725\u00077\u0007175\u00075\u0007\u00076\u0007工时\u0007\u0007\u0007\u0007\u000750\u00071\u000750\u0007\u0007\u00077\u0007配件\u0007油润滑的中
后桥\u000712个月/10万公里\u0007GL-5\\\\80W-90\u00079L\u000729.7\u00079\u0007267.3\u000710\u0007\u00078\u0007工时\u0007\u0007\u0007\u0007\u000750\u00071\u000750\u0007\u0007\u00079\u0007配件\u0007脂润滑的轮边\u00072个月/1.5万公里\u00073#锂脂\u00073KG\u000720\u00073\u000760\u00071.5\u0007\u000710\u0007工时\u0007\u0007\u0007\u0007\u000775\u00071\u000775\u0007\u0007\u000711\u0007配件\u0007驾驶室举升器\u00076个月/5万公里\u000710 号航空液压油\u00071L\u000730\u00071\u000730\u00075\u0007\u000712\u0007工时\u0007\u0007\u0007\u0007\u000750\u00071\u000750\u0007\u0007\u000713\u0007配件\u0007空气干燥器\u000712个月/10万公里\u0007科诺尔、威伯科\u00071个\u0007184\u00071\u0007184\u000710\u0007\u000714\u0007工时\u0007\u0007\u0007\u0007\u000730\u00071\u000730\u0007\u0007\u000715\u0007配件\u0007空气滤清器\u000712个月/4万公里\u0007空气滤芯\u00071个\u0007150\u00071\u0007150\u00074\u0007\u000716\u0007工时\u0007\u0007\u0007\u0007\u000730\u00071\u000730\u0007\u0007\u000717\u0007配件\u0007各类球头\u00072个月/1万公里\u00072号锂基脂\u0007\u000775\u00071\u000775\u00071\u0007\u0007合计
2.燃料电池保养项目
序号\u0007保养配件\u0007周期/万KM\u0007次数\u0007量\u0007单价(元,未税)\u0007工时【90】元/时\u0007公里要求(万公里)\u0007\u00071\u0007空滤\u00072\u00077\u0007/\u00071099 \u000745\u00072\u0007\u00072\u0007离子过滤器\u0007首次1万KM,之后每次间隔3万KM\u00074\u0007/\u0007969.57\u000790\u0007首次1万,后每次间隔3万\u0007\u00073\u0007冷却液\u00078万KM\u00071\u000740L\u00071664.845 \u0007 180\u00078\u0007\u0007三、证照及违章处理等收费标准:如甲方代为处理,乙方应向甲方支付的代处理费计费结构为:(基础费用)+(服务费收费标准),具体如下表:
项目
基础费用
服务费收费基础
服务费/元
补办行驶证
以实际收费为准
每台车每次
200
补办牌照
以实际收费为准
每台车每次
300
补办营运证
以实际收费为准
每台车每次
300
补办加氢证
以实际收费为准
每台车每次
300
处理违章(罚款)
实际罚款为准
每台车每条
100
处理违章(罚分)
实际罚分为准
每台车每条
100
借用备用钥匙
送上门,20公里内100元,每超1公里3元每公里,过桥过路费额外收取
每台车每次
100
补配钥匙
实际补配价格
每台车每次
400
" },
- { id: 'b13', title: '附件3至6 安全与规范', locked: false, content: "
附件3:安全责任告知书
一、各车辆使用人责任主体:
1.各租赁客户合作伙伴、挂靠我司车辆的用户,当您使用我司车辆期间必须承担安全责任,责任主体是:车辆使用人(公司或个人),挂靠车辆使用人(公司或个人)。
2.根据《中华人民共和国民法典》第一千二百零九条,因租赁、借用等情形机动车所有人、管理人与使用人不是同一人时,发生交通事故等造成损害,属于该机动车一方责任的,由机动车承租人和使用人承担该赔偿责任。
3.租赁车辆、挂靠车辆使用人,平时要做好出车检查,制订车辆日常检查记录表,对于:氢系统、电池、灯光、轮胎、车辆外观、随车配置物品等做好日常检查并记录,如有异常必须及时处理,车辆合格满足出车条件以后才能出车,并且必须保持车辆定位系统在线。
4.车辆、挂靠车辆使用人,要做好我司车辆的安全、事故台账,出事故必须登记在台账中,并且开展四不放过教育:①事故原因没有查清不放过,②事故责任者没有严肃处理不放过,③全体司机及车队管理人员没受到教育不放过,④防范措施没有落实不放过。
开展教育必须有现场多张照片,所有司机及车队管理人员在教育签到表上签字,照片及签到表原件留档,我司安全部备查。
二、车辆使用安全注意事项:
1.所有驾驶员要有从业资格证,9.6米厢车与4.2米冷藏车,必须出示本人资格证,登记后才可以提车。
2.注意车辆高度,苏龙、柳汽乘龙等9.6米车高4米。跃进、现代冷链4.2米车高3.38米。现代普货车高3.28米。集卡飞驰车头3.9米,挂车装载平箱4.2米左右。驾驶员一定要注意车厢高度,当心限高杆、桥梁、树枝等物。
3.因为是氢用车,车内不得吸烟,车周边10米以内不得吸烟,车辆远离烟火(周边10米以上),不得将车停放在高压电线下。
4.进入加氢站,必须无烟火,关闭总电源后加氢。服从加氢站管理,如:静电接地,不超过35Mpa压力等等。
5.车辆遇到氢气泄漏,不严重移至空旷处,关闭总电源!车辆旁边不得有闲杂人等,远离明火,联系运维人员:江浙沪沈帅15021428914;新疆赵波18639103977;广东王河北13928468652;集卡车李泽琦13383480807;北京及其他地方赵小峰18868302409。
6.系统漏气并着火,火焰未烧至其他管路和车身;处理方式:立即熄火,关闭电源,马上灭火,立即打上述专业人员电话,在他们指导下灭火,以防电池等爆炸。如果火势大、控制难、立即拨打 119,人员撤离至安全区域。
7.供氢系统漏气着火,或电池着火,火焰烧至其他管路或车身;处理方式:立即拨打119,人员撤离至安全区域。
8.车辆每日检查:轮胎完好、气压标准、灯光设施齐全、车辆不带病上路。
9.雨雾天气,降低速度。注意能见度,与前车保持足够安全距离。
10.行驶中电池高温冒烟,马上靠边,断开高压系统,马上联系运维。
11.车辆发生火情立即停车,用灭火器降温灭火,关闭电源,火势大要保证人身安全,离开车辆打119报警。
12.氢能车辆禁止电焊,周围不许任何焊接,此类维修通知专业人员来修理。
13.出交通事故,第一时间打安全经理王屹青电话:18116198188,告知实际情况,加此电话微信,拍现场照片:整体事故场景、我方车牌、对方车牌、我方及对方车辆受损部位。并发定位,安全经理会指导处理事故。
贵方上述安全告知已收到并熟悉,我方(被告知人)郑重承诺:无条件遵守上述安全操作事项。若因我方(被告知人)原因导致发生安全事故,我方(被告知人)自行承担一切法律责任。
我方已清楚地了解附件 1《租赁订单》、附件2《车辆产生的费用》、附件3《安全责任告知书》和所有内容及车辆租用相关要求,在此向出租人郑重承诺:保证遵守《商用车租赁合同》及附件文件所有约定。
确认方(签字/盖章):
确认时间: 年 月 日
附件4:重型普通货运车辆租赁动态监管责任告知与确认书
甲方(出租方):羚牛氢能科技(广东)有限公司
乙方(承租方):
为严格落实《中华人民共和国道路交通安全法》《道路货物运输及站场管理规定》等相关法律法规及行业监管要求,规范重型普通货运车辆租赁期间的安全运营行为,强化驾驶员安全管控,防范道路交通安全风险,保障租赁车辆、人员及公共安全,现就甲方租赁给乙方车辆的动态监管违规行为及处置事宜,正式告知如下:
甲方将对租赁车辆实施24小时动态监管,重点监测驾驶员存在的超速行驶、超时驾驶(持续时间≥4小时)、接打手持电话、操作手机、抽烟、生理疲劳驾驶、未按规定系安全带、偏离驾驶位、佩戴红外阻断型墨镜遮挡视线、动态监控设备被遮挡或失效、双手脱离方向盘、不目视前方行驶、实线变道、前向碰撞、车道偏离、前向车距过近等各类违反道路交通安全法律法规及双方签订的《商用车租赁合同》约定的违规行为。本确认书所载违规行为的认定,以甲方提供的、由车辆合法装载的动态监控设备所记录的数据、影像为准。若乙方对相关数据、影像记录的违规事实有异议,应在收到甲方通知后48小时内书面提出,并提出理由。乙方驾驶员的上述违规行为,不仅会给乙方自身运营带来重大安全隐患与法律责任风险,还将对甲方造成合规、运营等多方面的不利影响及实际损失,具体如下:
一、合规经营风险:
甲方作为重型普通货运车辆出租主体,依法承担租赁车辆的动态监管主体责任,若乙方驾驶员的违规行为被交通运输、公安交管等监管部门查处,甲方将面临行政处罚、行业资质核查、信用评级下调等合规风险,情节严重的,将直接影响甲方道路运输相关业务的正常开展。若租赁车辆因乙方原因(包含但不限于乙方驾驶员屡次、严重违规或乙方安全管理缺失)导致租赁车辆被交通主管部门依法做出撤销/吊销/注销其道路运输证,导致车辆无法运营,相关损失由乙方承担。
二、运营资源消耗:
针对乙方驾驶员的违规行为,甲方需额外投入大量人力、物力开展违规核实、沟通对接、整改监督等工作,占用甲方动态监管、车辆维护、客户服务等核心运营资源,大幅降低整体租赁业务运营效率,严重影响甲方对其他合规客户的服务质量,造成甲方运营成本增加。
针对监测发现的驾驶员违规行为,结合上述违规行为对甲方造成的各类影响与损失,甲方将采取分级处置措施,具体如下:
(1)一般违规:租赁期限内,因驾驶员违规行为产生属实动态监控预警风险的,乙方按以下标准承担违约金:首次50元/次,第二次100元/次,第三次及以上违规500元/次,乙方应当在甲方通知违规之日起1个自然日内支付给甲方,逾期未支付的,乙方须在次月车辆租金结算时一并向甲方支付。乙方更换新驾驶员须提前向甲方书面报备,人员更换后违规次数将重新计算。
(2)严重违规处置及车辆收回:租赁期限内,车辆因违规导致动态监控风险属实,连续2个月被交管部门通报的,甲方有权要求乙方在第2个自然月底起将车辆停运1个月,停运期间正常计收租金。为避免车辆营运证连续3个月通报导致被注销,乙方须严格遵照甲方停运要求执行,乙方拒不配合停运的,视为严重违约,甲方有权单方无条件强制收回租赁车辆,无需承担任何违约及赔偿责任。若因乙方拒不配合收车、违规持续营运造成车辆营运证被注销的,乙方须全额承担营运证注销后6个月内全部车辆租金。车辆强制收回过程中产生的拖车费、停放保管费、转运费、场地使用费等全部费用均由乙方承担。因乙方前述违约行为给甲方造成的全部损失(含但不限于行政罚款、赔偿金、律师费、诉讼费、保全费、差旅费等),均由乙方全额承担,甲方有权从车辆保证金中直接抵扣,保证金不足以清偿的,甲方有权就剩余差额向乙方另行追偿。
乙方需高度重视租赁车辆驾驶员的安全管控工作,切实履行承租方安全管理主体责任,加强对驾驶员的日常安全教育、培训及常态化管理,严格落实本确认书约定的分级处置措施,积极配合甲方的动态监管工作,及时整改各类违规行为。甲方将定期向乙方反馈车辆动态监管情况,对乙方未按本确认书要求落实处置措施、整改不到位或者拒不配合监管的行为,甲方将严格按照法律法规及双方签订的《租赁合同》约定处理。
本确认书自甲乙双方签字或盖章后生效,本确认书作为《商用车租赁合同》的附件,与《商用车租赁合同》具有同等法律效力。本确认书未尽事宜,按照双方签订的《商用车租赁合同》相关约定执行;若本确认书内容与相关法律法规冲突,按法律法规规定执行。
乙方确认:已认真阅读并充分全面理解本确认书全部内容,自愿严格遵照本确认书约定及相关法律法规要求执行,并承担因违反确认书约定及相关规定产生的全部责任。
(以下无正文)
甲方(盖章): 乙方(签字/盖章):
授权代表(签字): 授权代表(签字):
日期: 年 月 日 日期: 年 月 日
附件5:
安全责任承诺书
为严格落实《道路运输车辆动态监督管理办法》《广东省道路运输条例》及粤标动态监控管理要求,防范因超速、疲劳驾驶、接打电话、抽烟、遮挡摄像头、屏蔽设备、离线等违规行为被交通运输主管部门连续通报,避免因此导致车辆被责令停运、营运证被暂扣或注销等严重后果,并就车辆粤标动态监控相关安全责任,作出如下郑重承诺:
1.严格遵守《道路运输车辆动态监督管理办法》《广东省道路运输车辆智能监管系统应用管理办法》等国家及地方性法规,并已阅读、理解且承诺遵守贵公司提供的《粤标动态监控专项安全管理方案》(下称“管理方案”)相关规定,服从贵公司依据该方案及相关法规实施的动态监控管理。
2.负责督促我司承租司机规范驾驶,杜绝疲劳驾驶、超速、分心驾驶等违规行为,严禁破坏、屏蔽、断电、拆机等影响粤标监控设备正常运行的行为。
3.及时接收贵公司反馈的车辆违规信息,严格按照要求落实整改,配合贵公司开展司机安全教育、车辆停运等处置措施。
4.若因我司及我司承租司机违规行为,导致车辆被交管、运政部门通报、处罚或贵公司遭受其他损失的,我方同意承担由此产生的全部直接经济损失,包括但不限于政府部门处以的罚款、贵公司为处理此事支出的合理费用(如差旅费、律师费)以及车辆被责令停运期间的租金损失(按《商用车租赁合同》(下称“主合同”)约定标准计算)。
5.我司知悉,若因连续违规被主管部门通报3次及以上,导致贵公司营运证被暂扣或注销等严重后果的,自愿承担全部赔偿责任(包括但不限于车辆价值贬损、营运损失等)。同时,贵公司有权单方解除《商用车租赁合同》,且有权在5年内拒绝与我司及关联方开展任何商业合作。
6.本承诺书自签订之日起生效,有效期至《商用车租赁合同》约定租赁期满之日止。
7.本承诺书作为《商用车租赁合同》的有效附件,与主合同具有同等法律效力。如本承诺书内容与主合同内容约定不一致,则以更严格约束我司义务的条款为准。
(以下无正文)
承诺客户(盖章):__________
法定代表人/授权代表人(签字):__________
签订日期: 年 月 日
附件6:车辆使用规范和驾驶员要求
一、车辆使用规范
启动前
的操作
1.确认电源总开关处于开启状态。
2.检查储氢瓶的气密性,是否变形。
3.确认驻车制动操纵手柄处于驻车状态,确认变速操纵杆处于空挡位置。
4.车辆起步前,观察仪表有无异常显示和报警:剩余氢气量(SOC)不低于10%或者氢气压力不低于3.5兆帕,且动力电池电压显示不低于520V,低压蓄电池显示于22V以上,原地转动方向盘检查转向泵工作是否正常若仪表有指示灯亮起或声音报警,应停车检查。
5.系好安全带,检查安全措施。
车辆起步
1.先将钥匙转动至“ACC”位置,踩住刹车再继续转动至“START”,停留3秒。
2.仪表盘会显示READY等字样。
3.在观察电机运转正常,各仪表、指示灯、无警报灯正常的情况下方可起步。
4.仪表显示“ready”,踩下制动踏板,挂前进挡时,换挡杆切换至“D”,挂倒挡时,换挡杆切换至“R”。
5.放下驻车制动操作手柄,缓慢踩踏加速踏板,电机启动,车辆开始行驶。
停车动作
1.应先放松加速踏板,降低车速。
2.必须在车辆完全停稳后踩住刹车才能换入倒档,否则传动系统将受到损坏。
3.怠速运转夏天5分钟、冬天10分钟时间,关闭电源,停车时长超过2小时需要关闭总电源。
4.关闭用氢系统开关。
起步
注意事项
1.观察左右反光镜,注意车辆行人。
2.两次起动车辆的间隔时间不少于30秒。
3.驾驶室倾翻起来的情况下,禁止启动电机。(一体式车头除外)
4.严禁不松手刹的情况下强行行驶。
5.起步和行车途中手刹处于施加状态电机功率将会降低50%。
汽车行驶
注意事项
1.汽车行驶中,注意使电机冷却液温度保持在正常状态。
2.严禁行驶途中关闭氢能源开关。到加氢站加氢时,提前5分钟关闭用氢开关。
3.行驶中注意观察电池电量(SOC),如果低于设定值50%以下,停车检查是否打开用氢开关,再报售后维修。
4.遇水后请注意特别驾驶,制动器受潮会暂时降低制动力。并缓慢通过。
5.车辆倒车速度不超过15公里/时。
6.紧急刹车制动距离较长且急速刹车时车辆会向左倾斜,应注意车速(最佳车速在40—50),且必要时预见性减速。
7.长时间或下雨天停车要关闭整车总闸,避免损耗低压电或线路故障。
8.行车途中若听见不正常的声音或嗅到不正常的味道应及时停车找出原因。
9.所有高压电源均由点火开关控制,驾驶员离开车辆时必须关掉点火开关,取走钥匙。
10驾驶过程中严禁吸烟(包括但不限于驾驶室、密封空间、距离车辆【10】米范围内)。
11.注意观察冷机的温度是否在正常范围之内。
加氢流程
提前5分钟关闭用氢开关—车辆停在指定位置--人员离开到安全位置等待--加氢进行--加氢完毕关闭加氢口--纯电启动驶离加氢站--打开用氢开关。
加氢注意事项
1.氢的剩余量不能低于SOC10%。气压不能低于3.5兆帕。
2.加氢时严禁在加氢站点燃明火,或者吸烟。
3.要在听从加氢站工作人员的指导下开到指定位置,关闭电源,停车,由工作人员代驾。
4.禁止个人加氢,避免储氢瓶氢气泄漏,加氢需到加氢站。
5.不要携带手机、打火机、MP3等易引起爆炸、自燃的物品进入氢化工作区域。
6.在加氢站附近,拿工具、零件时应轻拿轻放,不得发生刚性撞击产生火花。
特别注意
1.不能急加速,匀速行驶。
2.车辆停车后,要等空压机吹扫结束再关闭电源(建议停车前10分钟关闭EV开关)。
3.电池电量不可低于25%。低于25%时,整车报警,低于15%时,整车无法上高压,将无法启动,应提前外接充电或开启混动模式充电。
4.氢气余量不可低于10%。
5.当车辆soc电量低于50%且未充电,则要确认是否在用氢状态,或靠边确认故障。
6.仪表台中部“EV”按钮为运行模式切换,按下后车辆由混合动力转换为纯动,再按则转换回混合动力,正常无需对此按钮进行操作。
7.加氢时关闭EV开关,使用电动进站加氢,离开加氢站再启动氢(EV开关)。
8.车辆为自动换挡,正常行驶中无需换挡操作,且车辆为电驱动系统,滑行时不须切换为空挡,切换空挡会导致车辆失去油门响应;如需换挡时,应踩刹车进行换挡,切换挡位时须先切换为空挡,并在空挡停留0.5s~1s。
9.开车前检查水箱防冻液是否缺失,过久未使用车辆需更换防冻液。
10.不要随意开启氢罐两侧的门,更不能随意关闭氢管路的阀门。
11.不要频繁关闭开启氢开关,停车20分钟左右的不需关闭。
12.非紧急情况下禁止碰高压急停开关,紧急情况下使用(如事故,涉水,起火)。
13.不能用水枪冲洗橙色线路,避免进水报绝缘和漏电。
14.车辆为电动车辆,因此涉水高度最高为300mm,如积水超过500mm严禁通行,且通过积水路段时应注意减速慢行。
15.停机注意:首先关闭所有用电设备(如空调)钥匙关一档(待燃料电池完全停止工作—再可关二档—最后方可关闭总电源开关)包括重新启动按以上要求操作。
二、车辆操作提醒
(一)安全/充电事项
1.高压安全:高压橙色线束及其连接件,不能随意触碰,有高压触电风险。
2.氢气安全:若有泄漏,立即现场隔离。 严禁人、车入内。供氢系统发生火灾:若条件允许,车辆移动空旷区域,人员撤离;若条件允许,可用淋水对氢瓶降温。
3.充电事项:充电时,需选择电压大于500V及辅助电压为24V的充电桩。尽量避免人为使用EV模式驾驶,减少充电次数。
3.加氢事项:行车前,合理规划路线,关注氢剩余量,及时补充。
4.氢堆功率待机条件:混动模式下氢堆功率输出条件
SOC在85%以上时氢堆自动进入待机状态,直到SOC低于65%时自动开始启动;然后电池开始充电直到SOC在85%以上又进入待机状态,依次循环。
注意:氢堆待机时,如果驾驶员要求功率大于电池放电功率限制值,氢堆也会自动启动输出功率。
5.功率限制
限制条件
限制措施
限制现象
纯EV模式
SOC≤30%
输出功率限制
空调停止使用,电池电量报警灯点亮/SOC进度条显示黄色
SOC≤20%
车辆限速≤52km/h/电池低电量警告灯+闪烁/SOC进度条显示红色
SOC≤10%
车辆限速≤17km/h/电池低电量警告灯+闪烁/整车故障灯点亮/SOC进度条显示红色,车辆限输出扭矩
(二)主要故障灯处理
1.氢燃料电池冷却液报警指示灯:停车检查,检查燃料电池冷却液液面状态,联系羚牛运维服务人员检查冷却液是否泄漏或其他原因。
2.氢燃料电池堆报警灯:氢燃料电池控制系统某个运行数据异常,切换E V模式、联系羚牛运维服务人员处理。
3.氢气泄漏报警灯:立即切换为EV模式,立即寻找远离火源空旷通风区域停车,关闭低压电源总开关,联系羚牛运维服务人员处理。
4.供氢系统报警灯:车辆可能会出现限制功率输出;切换EV模式、联系羚牛运维服务人员处理。
5.按指示灯颜色判断:绿灯正常运行-黄灯检查警告-红灯停车检查。
(三)驾驶模式切换-混动/EV模式
EV模式:按下EV开关键,仪表指示灯亮,车辆执行EV纯电模式运行。
混动模式:EV开关键关闭下,车辆启动,系统默认为混动模式。
注意:为延长动力电池寿命,纯EV模式仅允许在紧急情况下使用,严禁长期使用; EV模式可以在任何条件下切换到混动模式;混动模式只能在停车后才可切换为EV模式。
(四)能量回收功能
1.开启方法:拨杆在最上位置时为1档,拨动开关到最下位置时为2档。 (车辆默认挡位为1档)
2.启用条件:SOC<95%、车速>15Km/h、未踩加速踏板。
3.解除条件:踩下加速踏板或 SOC>90%或车速<15Km/h。
4.当道路平坦需长距离滑行或坡度较大需要较大制动力时,下拨能量回收开关到2档。
注意:合理使用能量回收,能有效减少制动系统磨损和降低氢耗;能量回收不能代替行车制动。
(五)ECO模式
开启方法:按下ECO模式开关,仪表ECO指示灯点亮,车辆进入节能模式运行;否则为正常运行模式。
注意:重载时使用正常模式(ECO未开启);道路平坦,空车或者轻载时,打开ECO开关,使用
节能模式;合理使用能量回收和ECO功能,可以提高续航里程。
(六)车辆停放
车辆停车后,将钥匙置于OFF档,等待3分钟,待氢堆完成自洁后夏天5分钟和冬天10分钟,再关闭低压电源总开关;停车区尽量选择空旷非封闭空间且应远离火源;为保护低压蓄电池性能,长时间停车(超过2个小时),强烈建议关闭低压电源总开关。
(七)提升续航驾驶
1.不要急加、减速:急加、减速能量损耗大,严重降低续航。
2.经济车速40-70KM/H:车速保持在此阶段匀速行驶 ,能有效地提高车辆续航里程。
3.能量回收和ECO模式使用:能量回收模式可回收多余动能提高续航,合理使用ECO模式,降低动力输出提高续航。
注意:合理使用空调,避免夏季过冷,冬季过热,导致能耗增加。
(八)AVAS-低速报警
1.开启条件:根据车速自动激活;D挡时:车速在1-20km/h时,发出“嗡嗡”报警声,车速高于20km/h时,报警自动取消;R档时,发出倒车音提示音。
2.作用:车辆启动行驶时,车辆噪声较小,为确保行车安全,强烈建议开启低速报警功能,提醒行人注意安全。
(九)定速巡航
1. 开启方法:按下定速巡航开关按键,通过方向盘设定速度。
2.启用条件:车辆无故障、40km/h≤车速≤90km/h。
3.解除条件:关闭巡航开关、踩下制动踏板、车速>90km/h、车速<40km/h。
注意:用定速巡航开关以外的方式解除定速巡航,巡航控制系统仍处于待命状态。 按下“SET/-”时,车辆会自动恢复到最近设定的巡航速度。
(十)故障处理流程
1.若车辆出现故障时,请及时联系羚牛运维服务人员。
2.若车辆故障时,为快速及有效地判断故障原因,请驾驶员记录以下信息,反馈给现代商用车服务人员。需提供车辆信息如下:车辆铭牌、故障码内容照片、仪表整体显示照片。
3.故障现象描述:车辆在行驶过程中或启动时,仪表显示故障灯,车辆有什么故障现象;车辆在使用过程中,车辆什么功能无法使用;尽可能拍摄故障时照片或视频,便于快速故障原因判断;
(十一)参数/故障查询方法:
1.车辆运行参数查询:按下方向盘上“菜单键”,进入“设置”界面,按“选择键”选择“信息栏目”项后,再按“确认键”,可读取相关系统信息。
2.车辆故障内容查询:按下方向盘“菜单键”,进入“故障诊断”界面,按“选择键”选择“故障内容”项后,再按“确认键”,可读取故障码内容。
三、驾驶员安全管理要求:
1.乙方驾驶员必须遵守《中华人民共和国道路交通安全法》《中华人民共和国道路运输条例》及有关交通安全管理的规章规则,安全驾车,并应遵守其他相关的规章制度。
2. 乙方与驾驶员须签订聘书,聘用条件为:
⑴须持有合法的驾驶执照,对于租赁车辆的同车型实际驾龄必须超过2年;
⑵年龄不超过55周岁;
⑶取得道路运输管理部门颁发的从业资格证;
⑷经乙方组织对其进行面试、理论和机械常识考核、道路驾驶技术测试合格。
3.驾驶员的管理、宣传、教育。
(1)驾驶员应爱惜甲方车辆,平时要注意车辆的保养,经常检查车辆的主要机件。每月至少用半天时间对自己所开车辆进行检修,确保车辆,以保持车辆的清洁。驾驶员发现车辆有故障时要立即检修。不会检修的,应立即报告管理人员,并提出具体的维修意见(包括维修项目和大致需要的经费等)。未经批准,不许私自将车辆送厂维修;
(2)驾驶员对自己所开车辆的各种证件的有效性应经常检查,出车时一定保证证件齐全。连续行车里程超过四小时的,须配备两名驾驶员,每位驾驶员连续驾驶时间不得超过四小时;
(3)乙方应对本单位每位驾驶员进行岗前安全教育培训、考核,考核不合格的,不得上车驾驶。并保存驾驶员安全培训记录;
(4)对违章次数多、出险率高、发生交通事故的驾驶员进行再教育培训或依据公司制度进行惩罚。
4.承租人在收到违章信息通知后,从通知日期后15天内处理完毕,防止积累。(北京要求10个工作日内处理)。
5.承租人如果发生违章,将会收到短信,微信或者书面形式通知,并会有出租人或售后人员致电确认。
6.如若自身不便处理违章,请在发生违章之日起 10日内 联系出租人或售后人员并说明情况,由出租人代为处理,产生的一切费用由客户自行承担。在收到以下违章信息的情况下,必须在得到通知后的10天内必须处理完毕:
(1)单辆车累计扣分6分以上或罚款800元以上;
(2)单辆车未处理违章3条以上;
(3)因年审要求,在注册日期当月最后截止日期前10个工作日处理掉所有违章。不处理的,出租方将安排代为加急处理,产生的费用由承租方承担。
7.如收到违章信息超出规定时间拒不处理的,出租人将预警发函或进行远程控制(如锁车)措施处理。
8.对半年内单辆车出现违章超过10次(北京在季度内单辆车不能超过两次违章,并且不能出现一次扣6分的违章)、发生交通事故负有责任4次以上或者重大交通事故一次的情况下,出租人将会做出以下应对方案:
(1)承租人必须更换司机;
(2)拒不整改配合,则视承租人为违约做收车处理。
9.欢迎您对我们的服务进行监督并提出宝贵意见。我公司的监督投诉电话:【 400-021-1773】。
接收方(签字/盖章):
时间: 年 月 日
授权委托书
致:羚牛氢能科技(广东)有限公司
兹委托受托人1 姓名【FORMTEXT 】联系方式【FORMTEXT 】证件号码【FORMTEXT 】代表委托人处理委托人与FORMTEXT 办理Ρ签署《商用车租赁合同》(合同编号:FORMTEXT )及前述合同相关包括但不限于《租赁订单》等合同附件、Ρ提车、Ρ退车、Ρ更换车、≤ FORMTEXT 事宜,授权期限自本授权委托书签署之日起至《商用车租赁合同》终止之日止。
兹委托受托人2 姓名【FORMTEXT 】联系方式【FORMTEXT 】证件号码【 FORMTEXT 】代表委托人处理委托人与FORMTEXT 办理≤签署《商用车租赁合同》(合同编号:FORMTEXT )及前述合同相关包括但不限于《租赁订单》等合同附件、≤提车、≤退车、≤更换车、≤ 合同抬头变更事宜,授权期限自本授权委托书签署之日起至《商用车租赁合同》终止之日止。
上列受托人的代理权限为特别授权,即受托人有权代委托人签署《商用车租赁合同》及前述合同相关包括但不限于《租赁订单》等合同附件、有权代为履行前述合同及附件内容、有权代为签收、确认前述合同及其附件相关通知、函件、诉讼文件等。委托人对上列受托人在授权范围内的行为承担全部法律责任。
本授权委托书手填部分有效,委托人特此声明及确认。
委托人(签字/盖章):
年 月 日
安全责任协议
甲方(出租方):
经办人:
联系电话:
乙方(承租方):
统一社会信用代码/身份证号:
通信地址:
经办人:
联系电话:
为明确双方车辆租赁期间安全管理责任,保障运输作业安全,依据相关法律法规,在已签订《车辆租赁合同》同时,签订本协议,约定租赁车辆安全运营及管理责任。
一、协议目的
1.1本协议明确双方合作期间安全责任,确保企业主体责任履行,保障人员、车辆和货物安全,避免事故发生。
1.2本协议有效期与《车辆租赁合同》合同期限保持一致,租赁期间内乙方承担全部车辆相关的安全责任。
二、安全责任划分
2.1车辆交接时,乙方确认车辆状态,在交接单签字即视为认可车辆状况,甲方完成合格交付。自交付之日起,车辆运营安全责任及维修保养责任转移至乙方。
三、乙方安全承诺
乙方结合车辆安全和加氢安全实际,就安全生产做出承诺并制定规程、制度、预案等。
3.1安全管理制度
3.1.1乙方建立健全本单位安全生产责任制,成立安全生产管理机构、依据规定配备专职或兼职安全管理人员,明确各部门、各岗位安全职责。
3.1.2乙方制定本单位生产安全事故隐患排查治理制度,明确各层级隐患排查职责,及时消除安全隐患。
3.1.3乙方制定本单位交通事故应急救援预案,明确应急组织机构及职责,确定应急处置流程、储备相应应急物资。
3.1.4乙方制定本单位驾驶员安全培训制度,落实驾驶员岗前安全培训、考核工作,并保存驾驶员培训记录。
3.1.5乙方制定并落实安全生产、交通运输等法律规定的其他安全管理制度。
3.1.6乙方负责按照甲方的要求提供企业营业执照及必要资质、运营证件及个人驾驶证、身份证供甲方审查核验。
3.1.7甲方有权对每一位租赁车辆的驾驶员证件信息、有效期资质进行审核。
3.2 事故隐患排查治理
3.2.1乙方每月至少进行一次全面安全检查,重点检查安全管理制度是否完善,是否定期组织召开安全会议,是否对每位驾驶员开展岗前安全培训,是否定期开展隐患排查及隐患限期整改落实,是否至少每半年开展一次应急演练等安全事项。发现存在安全隐患立即通知整改,并立即抓好落实,及时消除。
3.2.2乙方做好出车前、停车后的准备、检查工作,确保行车安全,发现隐患要及时修复后方可出车。
3.2.3乙方装货时严查超载和擅自装载危险品,确认无误后方可出车。
3.2.4乙方不定期检查车辆的安全装置、灯光信号、证件。
3.2.5乙方检查驾驶员是否带病、疲劳、酒后驾驶,是否违反安全驾驶操作规程。
3.2.6乙方建立驾驶员安全考核奖惩制度,针对违章次数多、出险率较高的司机进行再教育或依制度进行处罚。
3.3 驾驶员管理
3.3.1乙方驾驶员必须遵守《中华人民共和国道路交通法》《中华人民共和国道路运输条例》及有关交通安全管理的规章规则,安全驾车,并应遵守其他相关的规章制度。
3.3.2 乙方与驾驶员签订聘书,聘用条件为:
(1)驾驶员须持有合法驾照;
(2)年龄不超过60周岁;
(3)驾驶4.5T以上车型须有从业资格证,且经乙方面试、理论和机械常识考核、道路驾驶技术测试合格。
3.3.3乙方应对驾驶员进行岗前及定期安全教育培训、考核,考核不及格的,不得上车驾驶,保存培训材料,对违章次数多、出险率高或发生交通事故的驾驶员进行再教育或依据公司制度进行处罚。
3.3.4 乙方应当对驾驶员进行安全生产教育和培训,保证驾驶员具备必要的安全生产知识,熟悉道路交通安全规章规则,掌握行车安全操作技能,了解事故应急处理措施,知悉自身在交通安全方面的权利和义务。未经安全教育和培训合格的驾驶员,乙方不得让其上岗作业。
3.3.5 乙方必须依法参加工伤保险,为驾驶员缴纳保险费。
3.4车辆安全管理要求
3.4.1车辆发生故障必须及时修复,特别是危及行车安全的重大隐患,如制动、转向、轮胎、灯光装置等。严禁车辆带病出场。
3.4.2严禁超员、超载行驶,严禁客货混装,严禁超速行驶。
3.4.3车辆在运行途中,驾驶员应主动做好车辆的自检自查,发现问题及时解决。
3.4.4车辆周围10米内严禁抽烟,严禁明火。进入加氢站加氢时按操作流程执行。
3.4.5车辆必须按规定位置停放,严禁停放在密封场所、低洼积水区域。车辆停放不得占据消防通道或妨碍消防通道畅通,不得将车辆停放在有人员居住的建筑物内,不得将车辆停放在可能造成人员伤亡的坡道路段,应确保车辆与爆破、吊装、起重、动火、高温等危险作业场所保持足够的安全距离。乙方违反本条事项要求所造成的人员伤亡、财产损失,均由乙方自行承担。
3.5车辆技术管理要求
3.5.1乙方应根据甲方保养要求及时对车辆组织保养维修,并及时将保养维修、车辆肇事情况通知甲方。
3.5.2车辆重要部位改动或加装部件,乙方应征得甲方同意并报甲方登记备案。
3.5.3甲方运维部管理人员检查车辆上路行驶情况时,在告知其身份后,司机必须停车配合,如发现车辆状况不佳或违反甲方安全管理规定的,甲方管理人员有对车辆进行停驶、回场检查的权利。
3.5.4 乙方要配合甲方对车辆进行年审、二级维护、检测、事故违章处理等工作。
3.6突发事件应急处置
为减少、避免事故的发生,把事故的损失降到最低程度,乙方及乙方驾驶员应做到:
3.6.1交通事故
驾驶员在车辆运行中发生交通事故时,停车后马上下车关闭车辆总电源,查看事故情况及是否有人员受伤,并将事故碰撞现场进行拍照留存,在车辆后方100米处放置警示标志。
发生交通事故,当事人应立即进行自救,并报警。电话: 122(交警)、119(消防)、120(急救),应简明讲清事故地点、伤亡、损失等情况,以及事故对周围环境的危害程度,保护现场,抢救伤员,保护货物财产并上报公司领导及甲方管理部门。
事故如果导致氢气压力异常和氢气管路有“嗤嗤声”等异常现象,发现车辆有漏气情况时,驾驶员要第一时间通知公司领导或甲方相关人员告知事故情况,甲方安排专业售后人员进行应急处理。
远离人群,事故车的处理地点应尽量避免在人口密集区,如只能在原地进行处理,应在周围设置提示牌。
安全撤离,当车辆发生明火现象时,驾驶人员应停车并关闭车辆总电源,并采取紧急灭火措施,灭火器应使用二氧化碳灭火器,对着火点进行喷射。如遇到无法扑灭时,立即疏散周围人员及车辆并撤离到安全地带拨打119报警,等待救援。
3.6.2车辆氢气泄漏
(1)驾驶员在车辆运行中发现氢气泄漏报警情况时,应就近安全区域停车。
(2)停车后马上关闭车辆总电源、在车辆后方100米处放置警示标志,并疏散周围人员车辆。
(3)驾驶员将情况通知公司领导或甲方相关人员告知,甲方安排专业售后人员进行应急处理。
3.6.3车辆运行中发生整车故障
驾驶员驾驶车辆行驶中发生整车故障报警情况时,应在安全地带停车。
停车后关闭车辆总电源,并电话联系甲方,甲方收到信息后安排售后人员电话指导驾驶员进行处理。如电话无法处理时,安排厂家前往现场进行处理或拖至服务站处理。
3.6.4火灾事故
(1)发生车辆火灾事故或出现火险苗头时,驾驶员应立即熄火有条件地迅速将车转移至安全地点,切断电源,关闭气阀。
(2)使用二氧化碳灭火器对着火点进行喷射。
(3)火灾现场在进行初期扑救的同时或发现火势较大,估计自身无法扑灭的,并撤离到安全地带,疏散周围人员及车辆。迅速拨打火警电话报警,并通知公司领导及甲方管理部门。
(4)如有受伤人员,必须首先将伤员抢救出来,及时送往附近医院进行救治。
(5)公安消防人员到达现场后,应急救援人员应服从专业消防人员的指挥,在消防人员的统一组织下,积极参加火灾事故的救援工作。
3.7 禁止第三方使用
3.7.1 严格禁止乙方擅自将甲方车辆转租、分租、出借或以联营、合作、借用等形式变相交由第三方使用。如有违反,甲方有权立即解除合同、收回车辆,并要求乙方支付相当于三个月租金的违约金,且不影响其他损失赔偿权利。
四、甲方安全管理责任和权利
4.1 甲方有权审查乙方拟租赁车型是否在乙方经营许可范围之内,审查所交车型是否与乙方提车人驾驶证准驾车型匹配,驾驶证、从业资格证是否在有效期内。
4.2甲方负责按照《车辆可交付标准》对乙方拟租赁车辆进行整备,确保车辆性能完好、安全附件齐备。
4.3甲方负责指引乙方按照“交车单”内容项进行实物及车况确认,无误后甲乙双方在交车单上签字。
4.4甲方负责通知乙方所承租车辆的保养、年审、违法处理等信息。
4.5乙方在履行安全管理责任时,若需要甲方协助的,甲方在自身能力范围内且在不影响自身正常运营的情况下,对乙方提供必要的技术指导和信息支持等协助。
4.6乙方承诺自愿按照“乙方安全承诺”的规范内容进行操作,对于违反“乙方安全承诺”内容的操作行为,乙方应向甲方支付相当于三个月租金的违约金;若该违约金不足以弥补甲方损失的,乙方还应赔偿甲方因此遭受的全部损失。
4.7 尽管有上述规定,甲方是否行使甲方的安全管理责任和权利以及如何行使甲方的安全管理责任和权利,无论如何均不影响乙方根据本协议及“乙方安全承诺”履行其安全管理责任,也不减免或减轻其任何安全管理责任。
五、其他
5.1 本协议的任何变更或补充需经双方书面协商一致,并签订相关协议变更或补充文件。
5.2 本协议为《车辆租赁合同》的附件,本协议未约定的,以《车辆租赁合同》约定为准;若本协议约定与《车辆租赁合同》约定不一致的,以本协议约定为准。
5.3 本协议经双方签字(盖章)之日起生效,一式两份,甲乙双方各执一份,具有同等法律效力。
甲方(签章):
乙方(签字/盖章):
授权代表:
授权代表:
签订日期:
年 月 日
签订日期: 年 月 日
附:承租方(乙方)营业执照、法定代表人身份证复印件(若有授权书,需附被授权人身份证复印件)、道路运输经营许可证等。
" },
- ];
- }
-
- function defaultLeaseBlocks() {
- return v265LeaseBlocks();
- }
- function defaultPurchaseBlocks() {
- return [
- { id: 'p1', title: '合同标题', content: '车辆采购合同', locked: true },
- { id: 'p2', title: '合同编号', content: '合同编号:{{contractCode}}', locked: true },
- { id: 'p3', title: '买方信息', content: '买方:浙江羚牛氢能科技有限公司\n地址:浙江省嘉兴市南湖区科技大道 1 号', locked: true },
- { id: 'p4', title: '卖方信息', content: '卖方:{{supplierName}}\n统一社会信用代码:{{supplierCreditCode}}', locked: false },
- { id: 'p5', title: '采购标的', content: '一、采购标的\n车辆型号:{{vehicleModel}}\n数量:{{quantity}} 台\n单价:¥{{unitPrice}}', locked: false },
- { id: 'p6', title: '交付条款', content: '二、交付\n交付地点:{{deliveryPlace}}\n交付日期:{{deliveryDate}}', locked: false },
- { id: 'p7', title: '付款方式', content: '三、付款方式\n{{paymentTerms}}', locked: true },
- { id: 'p8', title: '签章页', content: '买方(盖章):____________ 卖方(盖章):____________', locked: true }
- ];
- }
-
- function defaultServiceBlocks() {
- return [
- { id: 's1', title: '合同标题', content: '氢能车辆运维服务合同', locked: true },
- { id: 's2', title: '合同编号', content: '合同编号:{{contractCode}}', locked: true },
- { id: 's3', title: '委托方', content: '委托方(甲方):{{customerName}}', locked: false },
- { id: 's4', title: '服务方', content: '服务方(乙方):浙江羚牛氢能科技有限公司', locked: true },
- { id: 's5', title: '服务内容', content: '一、服务内容\n包括但不限于车辆日常运维、故障响应、定期巡检等。', locked: false },
- { id: 's6', title: '服务期限', content: '二、服务期限\n自 {{serviceStart}} 至 {{serviceEnd}}', locked: false },
- { id: 's7', title: '服务费用', content: '三、服务费用\n服务费合计:¥{{serviceFee}}', locked: false },
- { id: 's8', title: '违约责任', content: '四、违约责任\n(标准条款,锁定不可修改)', locked: true }
- ];
- }
-
- function getDefaultBlocksForCategory(category) {
- if (category === 'purchase') return defaultPurchaseBlocks();
- if (category === 'service') return defaultServiceBlocks();
- return defaultLeaseBlocks();
- }
-
- function mockWordBlocks(fileName, category) {
- var cat = category || 'lease';
- var name = fileName || 'Word';
- if (cat === 'lease' && (/V26\.5|现代18吨|数智中心版/i.test(name) || /商用车租赁合同/.test(name))) {
- return JSON.parse(JSON.stringify(v265LeaseBlocks()));
- }
- var base = getDefaultBlocksForCategory(cat);
- base[0].content = base[0].content + '(导入自 ' + name + ')';
- return base;
- }
-
- var templatesState = useState([
- {
- id: 't8',
- category: 'lease',
- versionNo: 'v1.00',
- versionName: '现代18吨车型-数智中心版',
- status: 'published',
- isDefault: true,
- blocks: v265LeaseBlocks(),
- creator: '法务-王静',
- createTime: '2026-05-25 09:13',
- updater: '法务-王静',
- updateTime: '2026-05-25 09:13',
- remark: '参照 Word 原版导入;含现代18吨车型专项条款、租金减免政策及全套附件'
- },
- {
- id: 't1',
- category: 'lease',
- versionNo: 'v1.01',
- versionName: '2026年标准商用车租赁合同',
- status: 'published',
- isDefault: false,
- blocks: defaultLeaseBlocks(),
- creator: '法务-王静',
- createTime: '2026-03-15 14:30',
- updater: '法务-王静',
- updateTime: '2026-03-15 14:30',
- remark: '客服草拟合同时默认使用;含氢能车辆专项条款'
- },
- {
- id: 't2',
- category: 'lease',
- versionNo: 'v1.02',
- versionName: '2025年修订版',
- status: 'published',
- isDefault: false,
- blocks: defaultLeaseBlocks(),
- creator: '法务-王静',
- createTime: '2025-11-08 10:20',
- updater: '法务-李明',
- updateTime: '2025-12-01 16:45',
- remark: '历史发布版本'
- },
- {
- id: 't3',
- category: 'lease',
- versionNo: null,
- versionName: '2026年二季度草案',
- status: 'draft',
- isDefault: false,
- blocks: defaultLeaseBlocks(),
- creator: '法务-李明',
- createTime: '2026-06-01 09:15',
- updater: '法务-李明',
- updateTime: '2026-06-01 09:15',
- remark: '待法务审核发布'
- },
- {
- id: 't4',
- category: 'purchase',
- versionNo: 'v1.00',
- versionName: '2026年车辆采购标准版',
- status: 'published',
- isDefault: true,
- blocks: defaultPurchaseBlocks(),
- creator: '法务-王静',
- createTime: '2026-04-10 11:00',
- updater: '法务-王静',
- updateTime: '2026-04-10 11:00',
- remark: '采购类标准模板'
- },
- {
- id: 't5',
- category: 'purchase',
- versionNo: 'v1.01',
- versionName: '2025年采购版',
- status: 'published',
- isDefault: false,
- blocks: defaultPurchaseBlocks(),
- creator: '法务-李明',
- createTime: '2025-09-20 16:40',
- updater: '法务-李明',
- updateTime: '2025-09-20 16:40',
- remark: ''
- },
- {
- id: 't6',
- category: 'service',
- versionNo: 'v1.00',
- versionName: '运维服务标准合同',
- status: 'published',
- isDefault: true,
- blocks: defaultServiceBlocks(),
- creator: '法务-王静',
- createTime: '2026-02-28 09:30',
- updater: '法务-王静',
- updateTime: '2026-02-28 09:30',
- remark: '服务类标准模板'
- },
- {
- id: 't7',
- category: 'service',
- versionNo: null,
- versionName: '加氢服务草案',
- status: 'draft',
- isDefault: false,
- blocks: defaultServiceBlocks(),
- creator: '法务-李明',
- createTime: '2026-05-18 15:20',
- updater: '法务-李明',
- updateTime: '2026-05-18 15:20',
- remark: '加氢站服务专项条款待补充'
- }
- ]);
- var templates = templatesState[0];
- var setTemplates = templatesState[1];
-
- var categoryFilterState = useState('lease');
- var categoryFilter = categoryFilterState[0];
- var setCategoryFilter = categoryFilterState[1];
-
- var pageViewState = useState('list');
- var pageView = pageViewState[0];
- var setPageView = pageViewState[1];
-
- var editorModeState = useState('create');
- var editorMode = editorModeState[0];
- var setEditorMode = editorModeState[1];
-
- var editingRecordState = useState(null);
- var editingRecord = editingRecordState[0];
- var setEditingRecord = editingRecordState[1];
-
- var lastImportFileNameState = useState('');
- var importChangedInSessionState = useState(false);
- var formBlocksState = useState([]);
- var formDocumentHtmlState = useState('');
-
- var deleteModalState = useState(false);
- var deleteTargetState = useState(null);
- var defaultConfirmModalState = useState(false);
- var defaultConfirmTargetState = useState(null);
- var editorSyncKeyState = useState(0);
- var editorInsertHandlerRef = useRef(null);
- var registerEditorInsertRef = useRef(function (fn) { editorInsertHandlerRef.current = fn; });
- var placeholderPopoverOpenState = useState(false);
- var previewLessorIdState = useState('gd');
- var previewLessorId = previewLessorIdState[0];
- var setPreviewLessorId = previewLessorIdState[1];
-
-
- var CURRENT_USER = '法务-当前用户';
-
- var pageStyle = ONEOS_ANT_TABLE_GLOBAL_FIX.concat([
- '.oneos-page.ct-page,.ct-page{font-family:Inter,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;color:#0f172a}' +
- '.ct-page *{box-sizing:border-box}' +
- '.ct-category-tabs .ant-tabs-nav::before{border-color:#E2E8F0}' +
- '.ct-category-tabs .ant-tabs-tab{border-radius:8px 8px 0 0!important;transition:color .2s ease}' +
- '.ct-category-tabs .ant-tabs-tab-active .ant-tabs-tab-btn{color:#10b981!important;font-weight:600}' +
- '.ct-category-tabs .ant-tabs-ink-bar{background:#10b981;height:3px;border-radius:3px 3px 0 0}' +
- '.ct-data-table .ant-table-thead>tr>th{background:#F8FAFC!important;font-weight:600;font-size:13px;color:#475569}' +
- '.ct-data-table .ant-table-tbody>tr.ct-row-hover:hover>td{background:#F8FAFC!important}' +
- '.ct-data-table .ant-table-tbody>tr>td{font-size:13px;transition:background .15s ease}' +
- '.ct-panel-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid #E2E8F0}' +
- '.ct-panel-head__title{font-size:13px;font-weight:600;color:#334155;display:flex;align-items:center;gap:8px}' +
- '.ct-panel-head__badge{font-size:11px;font-weight:500;color:#64748B;background:#F1F5F9;padding:2px 8px;border-radius:999px}' +
- '.ct-modal-form-label{display:block;margin-bottom:6px;font-size:12px;font-weight:500;color:#64748B}' +
- '.ct-rich-toolbar{background:#fff;border:1px solid #E8E8E8;border-bottom:none;border-radius:8px 8px 0 0;padding:4px 8px 2px}' +
- '.ct-rich-toolbar__row{display:flex;align-items:center;flex-wrap:nowrap;gap:1px;min-height:34px;padding:2px 0;overflow-x:auto}' +
- '.ct-rich-toolbar__row+.ct-rich-toolbar__row{border-top:1px solid #F0F0F0;margin-top:2px;padding-top:4px}' +
- '.ct-rte-sep{width:1px;height:18px;background:#E8E8E8;margin:0 5px;flex-shrink:0}' +
- '.ct-rte-btn{display:inline-flex;align-items:center;justify-content:center;min-width:28px;height:28px;border:none;background:transparent;border-radius:4px;color:#595959;cursor:pointer;padding:0 4px;transition:background .15s,color .15s;flex-shrink:0;font:inherit}' +
- '.ct-rte-btn:hover{background:#F5F5F5;color:#262626}' +
- '.ct-rte-btn.is-active{background:#ecfdf5;color:#10b981}' +
- '.ct-rte-btn:disabled{opacity:.35;cursor:not-allowed}' +
- '.ct-rte-btn:focus-visible{outline:2px solid #10b981;outline-offset:1px}' +
- '.ct-rte-btn--dropdown{gap:2px;padding:0 4px 0 6px}' +
- '.ct-rte-letter{display:inline-flex;flex-direction:column;align-items:center;justify-content:center;font-size:13px;font-weight:600;line-height:1;min-width:14px;font-family:"Inter, "PingFang SC", "Microsoft YaHei"",sans-serif}' +
- '.ct-rte-letter.is-italic{font-style:italic;font-weight:500}' +
- '.ct-rte-letter__bar{display:block;width:14px;height:2px;margin-top:1px;border-radius:1px;background:#595959}' +
- '.ct-rte-letter--highlight{background:#FEF08A;border-radius:2px;padding:0 2px}' +
- '.ct-rte-svg{display:block;flex-shrink:0}' +
- '.ct-rte-svg--chevron{width:10px;height:10px;opacity:.45;margin-left:-2px}' +
- '.ct-rte-align-group{display:inline-flex;align-items:center;background:#FAFAFA;border-radius:4px;padding:2px;gap:1px;flex-shrink:0}' +
- '.ct-rte-align-group .ct-rte-btn{min-width:26px;height:26px}' +
- '.ct-rte-select.ant-select{font-size:13px;color:#262626;flex-shrink:0}' +
- '.ct-rte-select .ant-select-selector{background:transparent!important;border:none!important;box-shadow:none!important;padding:0 18px 0 6px!important;height:28px!important;min-height:28px!important}' +
- '.ct-rte-select .ant-select-selection-item,.ct-rte-select .ant-select-selection-placeholder{line-height:28px!important;font-size:13px;color:#262626}' +
- '.ct-rte-select .ant-select-arrow{color:#8C8C8C;right:4px}' +
- '.ct-rte-select--size{width:68px}' +
- '.ct-rte-select--font{width:108px}' +
- '.ct-rte-dropdown-wrap{display:inline-flex;align-items:center}' +
- '.ct-rich-toolbar .ant-btn:focus-visible,.ct-page .ant-btn:focus-visible{outline:2px solid #10b981;outline-offset:2px}' +
- '@media(max-width:992px){.ct-editor-panel,.ct-preview-panel{max-height:none}.ct-rich-editor{min-height:320px;max-height:420px}}' +
- '@media(prefers-reduced-motion:reduce){.ct-data-table .ant-table-tbody>tr>td,.ct-rich-toolbar .ant-btn{transition:none}}' +
- '.ct-preview-doc{background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:32px 40px;min-height:520px;box-shadow:0 2px 12px rgba(15,23,42,0.06);font-size:14px;line-height:1.85;color:#1e293b}' +
- '.ct-preview-doc h1{text-align:center;font-size:20px;font-weight:700;margin:0 0 24px;color:#0f172a}' +
- '.ct-preview-section{margin-bottom:18px;word-break:break-word}' +
- '.ct-preview-section__body{line-height:1.85}' +
- '.ct-preview-section__body p{margin:0 0 10px}' +
- '.ct-preview-section__body strong{font-weight:700;color:#0f172a}' +
- '.ct-preview-section__body em{font-style:italic}' +
- '.ct-preview-section__body img{max-width:100%;height:auto;margin:10px 0;border-radius:4px;display:block}' +
- '.ct-preview-doc table.ct-doc-table,.ct-rich-editor table.ct-doc-table{width:100%;border-collapse:collapse;margin:12px 0;font-size:13px}' +
- '.ct-preview-doc table.ct-doc-table td,.ct-preview-doc table.ct-doc-table th,.ct-rich-editor table.ct-doc-table td,.ct-rich-editor table.ct-doc-table th{border:1px solid #cbd5e1;padding:6px 10px;min-width:48px;vertical-align:top}' +
- '.ct-preview-doc table.ct-doc-table th,.ct-rich-editor table.ct-doc-table th{background:#f1f5f9;font-weight:600}' +
- '.ct-preview-doc h2,.ct-rich-editor h2{font-size:18px;font-weight:700;margin:16px 0 10px}' +
- '.ct-preview-doc h3,.ct-rich-editor h3{font-size:16px;font-weight:600;margin:14px 0 8px}' +
- '.ct-preview-doc ul,.ct-preview-doc ol,.ct-rich-editor ul,.ct-rich-editor ol{margin:8px 0;padding-left:24px}' +
- '.ct-preview-doc blockquote,.ct-rich-editor blockquote{margin:10px 0;padding:8px 14px;border-left:3px solid #cbd5e1;background:#f8fafc;color:#475569}' +
- '.ct-preview-doc a,.ct-rich-editor a{color:#2563eb;text-decoration:underline}' +
- '.ct-inline-lock{background:#fef3c7;border-bottom:1px dashed #f59e0b;padding:0 2px;border-radius:2px}' +
- '.ct-preview-doc .ct-inline-lock{background:#f8fafc;border-left:2px solid #94a3b8;padding:2px 4px}' +
- '.ct-rich-editor .ct-risk-redline,.ct-preview-doc .ct-risk-redline,.ct-preview-page__body .ct-risk-redline,.ct-word-doc .ct-risk-redline{background:rgba(254,226,226,0.4);border:1px dashed #f87171;border-radius:3px;padding:0 2px;box-decoration-break:clone;-webkit-box-decoration-break:clone}' +
- '.ct-rte-btn--text{width:auto;padding:0 10px;font-size:12px;font-weight:600;color:#dc2626;border:1px solid #fecaca;background:#fef2f2;border-radius:4px;min-width:auto;height:28px;gap:4px}' +
- '.ct-rte-btn--text:hover{background:#fee2e2;border-color:#fca5a5;color:#b91c1c}' +
- '.ct-rte-btn--text.is-muted{color:#64748B;border-color:#E2E8F0;background:#F8FAFC;font-weight:500}' +
- '.ct-rte-btn--text.is-muted:hover{background:#F1F5F9;color:#475569}' +
- '.ct-editor-panel{border:1px solid #e2e8f0;border-radius:12px;background:#fafbfc;max-height:calc(100vh - 280px);overflow:hidden;padding:0}' +
- '.ct-preview-panel{border:1px solid #e2e8f0;border-radius:12px;background:#f1f5f9;max-height:calc(100vh - 280px);overflow:auto;padding:16px}' +
- '.ct-category-tabs .ant-tabs-nav{margin-bottom:0}' +
- '.ct-category-tabs .ant-tabs-tab{font-size:14px;padding:10px 4px}' +
- '.ct-tab-summary{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;padding:14px 0 16px;border-bottom:1px solid #E2E8F0;margin-bottom:14px}' +
- '.ct-tab-summary__meta{font-size:13px;color:#64748B;line-height:1.5}' +
- '.ct-tab-summary__default{display:flex;align-items:center;flex-wrap:wrap;gap:8px}' +
- '.ct-tab-label{display:inline-flex;align-items:center;gap:6px}' +
- '.ct-rich-wrap{margin-top:4px}' +
- '.ct-rich-editor{flex:1;min-height:calc(100vh - 380px);max-height:calc(100vh - 320px);overflow-y:auto;padding:16px 20px;border:1px solid #e2e8f0;border-top:none;border-radius:0 0 8px 8px;background:#fff;font-size:14px;line-height:1.75;outline:none;word-break:break-word}' +
- '.ct-rich-editor:focus{border-color:#10b981;box-shadow:0 0 0 2px rgba(37,99,235,0.15)}' +
- '.ct-rich-editor.is-readonly{background:#f8fafc;color:#475569;cursor:default}' +
- '.ct-rich-editor img{max-width:100%;height:auto;margin:8px 0;border-radius:4px;display:block}' +
- '.ct-rich-wrap.is-fullscreen{position:fixed;inset:0;z-index:1100;background:#fff;padding:12px;display:flex;flex-direction:column}' +
- '.ct-rich-wrap.is-fullscreen .ct-rich-editor{max-height:none;min-height:0;flex:1}' +
- '.ct-rich-wrap.is-fullscreen .ct-rich-toolbar{border-radius:8px}' +
- '.ct-rich-source{width:100%;min-height:calc(100vh - 380px);max-height:calc(100vh - 320px);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;line-height:1.6;padding:14px 16px;border:1px solid #E2E8F0;border-top:none;border-radius:0 0 8px 8px;resize:vertical;outline:none}' +
- '.ct-rich-source:focus{border-color:#10b981;box-shadow:0 0 0 2px rgba(37,99,235,0.15)}' +
- '.ct-rich-statusbar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:6px 12px;font-size:12px;color:#64748B;background:#F8FAFC;border:1px solid #E2E8F0;border-top:none;border-radius:0 0 8px 8px}' +
- '.ct-rich-statusbar__stats{display:flex;gap:16px;flex-wrap:wrap}' +
- '.ct-page-break{display:block;height:0;border:none;border-top:2px dashed #CBD5E1;margin:24px 0;page-break-after:always}' +
- '.ct-preview-doc .ct-page-break{border-top-color:#94A3B8}' +
- '.ct-preview-doc.ct-word-doc,.ct-preview-doc .ct-word-doc{font-family:FangSong,STFangsong,"仿宋",SimSun,"宋体",serif;font-size:10.5pt;line-height:1.5;color:#000;letter-spacing:0}' +
- '.ct-preview-doc.ct-word-doc{padding:48px 56px 56px}' +
- '.ct-word-doc p{margin:0 0 4px}' +
- '.ct-word-title{text-align:center;font-size:18pt;font-weight:700;margin:0 0 10px!important;line-height:1.4}' +
- '.ct-word-contract-no{text-align:right;margin:0 0 14px!important;padding-right:1em;font-size:10.5pt}' +
- '.ct-word-party-line{margin:0!important;line-height:1.8;font-size:10.5pt}' +
- '.ct-word-body{text-align:justify;text-justify:inter-ideograph;margin:0 0 4px!important}' +
- '.ct-word-clause-indent,.ct-word-clause-indent2{text-align:justify;text-justify:inter-ideograph;text-indent:2em;margin:0 0 4px!important}' +
- '.ct-word-clause-title{text-align:justify;text-justify:inter-ideograph;margin:6px 0 4px!important;font-weight:700}' +
- '.ct-word-table{width:100%;border-collapse:collapse;margin:6px 0 12px;table-layout:fixed}' +
- '.ct-word-table .ct-word-party-left,.ct-word-table .ct-word-party-right{width:50%;border:none!important;padding:2px 6px;vertical-align:top}' +
- '.ct-word-table .ct-word-party-left{padding-right:12px}' +
- '.ct-word-table .ct-word-party-right{padding-left:12px}' +
- '.ct-word-table .ct-word-td{border:1px solid #bfbfbf;padding:4px 6px;vertical-align:top;font-size:10.5pt}' +
- '.ct-word-table .ct-word-td.ct-word-td-full,.ct-word-table td[colspan]{width:100%}' +
- '.ct-word-table .ct-word-td p{margin:0!important}' +
- '.ct-preview-doc.ct-word-doc b,.ct-preview-doc.ct-word-doc strong{font-weight:700}' +
- '.ct-preview-doc.ct-word-doc .ct-preview-section__body{line-height:1.5}' +
- '.ct-preview-doc.ct-word-paginated{padding:0!important;background:transparent!important;border:none!important;box-shadow:none!important;min-height:0!important}' +
- '.ct-preview-pager{display:flex;align-items:center;justify-content:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}' +
- '.ct-preview-pager__info{font-size:12px;color:#64748B;min-width:88px;text-align:center}' +
- '.ct-preview-pages{display:flex;flex-direction:column;align-items:center;gap:20px;padding:4px 0 12px}' +
- '.ct-preview-page{width:210mm;min-height:297mm;padding:25.4mm 31.8mm;box-sizing:border-box;background:#fff;border:1px solid #d9d9d9;box-shadow:0 2px 12px rgba(0,0,0,0.12);position:relative;flex-shrink:0}' +
- '.ct-preview-page__body{width:100%;overflow:hidden;word-break:break-word}' +
- '.ct-preview-page__footer{position:absolute;bottom:10mm;left:0;right:0;text-align:center;font-size:9pt;color:#999;font-family:FangSong,STFangsong,"仿宋",SimSun,"宋体",serif}' +
- '.ct-preview-page.is-loading{min-height:120px;display:flex;align-items:center;justify-content:center;color:#94A3B8;font-size:13px;width:210mm}' +
- '.ct-preview-panel--word{background:#b8b8b8;padding:16px 12px}' +
- '.ct-rich-editor .ct-word-doc,.ct-rich-editor .ct-word-doc{font-family:FangSong,STFangsong,"仿宋",SimSun,"宋体",serif;font-size:10.5pt;line-height:1.5;color:#000}' +
- '.ct-rich-editor .ct-word-title{text-align:center;font-size:18pt;font-weight:700}' +
- '.ct-rich-editor .ct-word-contract-no{text-align:right;padding-right:1em}' +
- '.ct-rich-editor .ct-word-clause-indent,.ct-rich-editor .ct-word-clause-indent2{text-indent:2em;text-align:justify}' +
- '.ct-rich-editor .ct-word-table{width:100%;border-collapse:collapse;margin:6px 0}' +
- '.ct-rich-editor .ct-word-table .ct-word-party-left,.ct-rich-editor .ct-word-table .ct-word-party-right{width:50%;border:none!important;vertical-align:top}' +
- '.ct-rich-editor .ct-word-table .ct-word-td{border:1px solid #bfbfbf;padding:4px 6px;vertical-align:top}' +
- '.ct-placeholder-card{width:320px;max-height:420px;overflow:auto}' +
- '.ct-placeholder-card__head{margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid #E2E8F0}' +
- '.ct-placeholder-card__title{font-size:13px;font-weight:600;color:#334155;margin:0 0 4px}' +
- '.ct-placeholder-card__desc{font-size:12px;color:#64748B;margin:0;line-height:1.5}' +
- '.ct-placeholder-card__group{margin-bottom:12px}' +
- '.ct-placeholder-card__group:last-child{margin-bottom:0}' +
- '.ct-placeholder-card__group-title{font-size:12px;font-weight:600;color:#475569;margin:0 0 6px}' +
- '.ct-placeholder-card__group-desc{font-size:11px;color:#94A3B8;margin:0 0 8px;line-height:1.45}' +
- '.ct-placeholder-card__item{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 10px;border:1px solid #E2E8F0;border-radius:8px;background:#fff;cursor:pointer;transition:background .15s,border-color .15s,box-shadow .15s;margin-bottom:6px}' +
- '.ct-placeholder-card__item:last-child{margin-bottom:0}' +
- '.ct-placeholder-card__item:hover{background:#F8FAFC;border-color:#CBD5E1;box-shadow:0 1px 4px rgba(15,23,42,.06)}' +
- '.ct-placeholder-card__item-main{min-width:0;flex:1}' +
- '.ct-placeholder-card__item-label{font-size:12px;color:#334155;font-weight:500}' +
- '.ct-placeholder-card__item-token{font-size:11px;color:#64748B;font-family:ui-monospace,Menlo,monospace;margin-top:2px;word-break:break-all}' +
- '.ct-placeholder-card__item-actions{display:flex;gap:4px;flex-shrink:0}' +
- '.ct-placeholder-card__action{font-size:11px;color:#64748B;padding:2px 6px;border-radius:4px;border:1px solid #E2E8F0;background:#F8FAFC;cursor:pointer}' +
- '.ct-placeholder-card__action:hover{color:#10b981;border-color:#bbf7d0;background:#ecfdf5}' +
- '.ct-placeholder-trigger.ant-btn{display:inline-flex;align-items:center;gap:6px}' +
- '.ct-preview-lessor-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px;flex-wrap:wrap}' +
- '.ct-preview-lessor-bar__label{font-size:12px;color:#64748B;white-space:nowrap}' +
- '.ct-editor-page{display:flex;flex-direction:column;min-height:calc(100vh - 48px)}' +
- '.ct-editor-page__topbar{margin-bottom:12px}' +
- '.ct-editor-page__header{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:16px;padding:12px 16px;background:#fff;border:1px solid #E2E8F0;border-radius:12px;flex-wrap:wrap}' +
- '.ct-panel-head__actions{display:flex;align-items:center;gap:8px;flex-shrink:0}' +
- '.ct-editor-page__title{margin:0;font-size:18px;font-weight:700;color:#0F172A;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}' +
- '.ct-editor-page__footer{position:sticky;bottom:0;margin-top:16px;padding:12px 16px;background:#fff;border:1px solid #E2E8F0;border-radius:12px;display:flex;justify-content:flex-end;box-shadow:0 -4px 12px rgba(15,23,42,.04);z-index:2}' +
- '.ct-editor-page .ct-editor-panel,.ct-editor-page .ct-preview-panel{max-height:calc(100vh - 220px)}' +
- '.ct-editor-page .ct-rich-editor,.ct-editor-page .ct-rich-source{min-height:calc(100vh - 300px);max-height:calc(100vh - 260px)}'
- ]).join('\n');
-
- var categoryStats = useMemo(function () {
- var map = {};
- CATEGORY_OPTIONS.forEach(function (c) {
- var list = templates.filter(function (t) { return t.category === c.value; });
- var def = list.find(function (t) { return t.isDefault && t.status === 'published'; });
- map[c.value] = {
- count: list.length,
- defaultVersion: def ? def.versionNo : '—',
- defaultName: def ? def.versionName : '未设置'
- };
- });
- return map;
- }, [templates]);
-
- function statusTag(status) {
- if (status === 'published') return React.createElement(Tag, { color: 'success' }, '已发布');
- if (status === 'draft') return React.createElement(Tag, { color: 'processing' }, '草稿');
- return React.createElement(Tag, null, '已归档');
- }
-
- function loadDocumentFromBlocks(blocks) {
- var html = mergeBlocksToDocument(blocks);
- formDocumentHtmlState[1](html);
- formBlocksState[1](blocks);
- }
-
- function parseVersionNo(versionNo) {
- var m = String(versionNo || '').match(/^[vV](\d+)\.(\d{1,2})$/);
- if (!m) return null;
- return { major: parseInt(m[1], 10), minor: parseInt(m[2], 10) };
- }
-
- function formatVersionNo(major, minor) {
- return 'v' + major + '.' + String(minor).padStart(2, '0');
- }
-
- function formatNowTime() {
- return '2026-06-09 ' + new Date().toTimeString().slice(0, 5);
- }
-
- function generateNextVersionNo(category) {
- var list = templates.filter(function (t) {
- return t.category === category && t.status === 'published' && t.versionNo;
- });
- var maxMajor = 0;
- var maxMinor = -1;
- list.forEach(function (t) {
- var parsed = parseVersionNo(t.versionNo);
- if (!parsed) return;
- if (parsed.major > maxMajor || (parsed.major === maxMajor && parsed.minor > maxMinor)) {
- maxMajor = parsed.major;
- maxMinor = parsed.minor;
- }
- });
- if (maxMinor < 0) return 'v1.00';
- if (maxMinor >= 99) return formatVersionNo(maxMajor + 1, 0);
- return formatVersionNo(maxMajor, maxMinor + 1);
- }
-
- function stripFileExtension(name) {
- return String(name || '').replace(/\.[^.]+$/, '');
- }
-
- function buildAutoVersionName(category, versionNo, importFileName) {
- var imported = stripFileExtension(importFileName);
- if (imported) return imported;
- var catOpt = CATEGORY_OPTIONS.find(function (c) { return c.value === category; });
- if (!versionNo) return (catOpt ? catOpt.label : '合同模板') + ' 草稿';
- return (catOpt ? catOpt.label : '合同模板') + ' ' + versionNo;
- }
-
- function openCreate() {
- setEditorMode('create');
- setEditingRecord(null);
- lastImportFileNameState[1]('');
- importChangedInSessionState[1](false);
- formDocumentHtmlState[1]('');
- formBlocksState[1]([]);
- editorSyncKeyState[1](function (v) { return v + 1; });
- setPageView('editor');
- }
-
- function openEdit(record) {
- setEditorMode('edit');
- setEditingRecord(record);
- lastImportFileNameState[1]('');
- importChangedInSessionState[1](false);
- loadDocumentFromBlocks(JSON.parse(JSON.stringify(record.blocks || getDefaultBlocksForCategory(record.category))));
- setPageView('editor');
- }
-
- function handleImportWord(file) {
- var name = file && file.name ? file.name : 'Word';
- var cat = editingRecord ? editingRecord.category : categoryFilter;
- lastImportFileNameState[1](name);
- importChangedInSessionState[1](true);
- loadDocumentFromBlocks(mockWordBlocks(name, cat));
- editorSyncKeyState[1](function (v) { return v + 1; });
- message.success('已导入 Word 并合并为单一文档(原型模拟)');
- return false;
- }
-
- function syncDocumentHtml(html) {
- formDocumentHtmlState[1](html);
- formBlocksState[1](documentToBlocks(html));
- }
-
- function handleSaveTemplate(publish) {
- var docHtml = (formDocumentHtmlState[0] || '').trim();
- if (!docHtml) {
- message.warning('请先导入 Word 并解析到编辑器');
- return;
- }
- var blocks = documentToBlocks(docHtml);
- var now = formatNowTime();
- var importName = lastImportFileNameState[0] || '';
-
- if (editorMode === 'create') {
- if (publish) {
- var versionNo = generateNextVersionNo(categoryFilter);
- var newItem = {
- id: 't' + Date.now(),
- category: categoryFilter,
- versionNo: versionNo,
- versionName: buildAutoVersionName(categoryFilter, versionNo, importName),
- status: 'published',
- isDefault: false,
- blocks: JSON.parse(JSON.stringify(blocks)),
- creator: CURRENT_USER,
- createTime: now,
- updater: CURRENT_USER,
- updateTime: now,
- remark: ''
- };
- setTemplates(function (prev) { return prev.concat([newItem]); });
- message.success('已发布,版本号 ' + versionNo);
- } else {
- var draftItem = {
- id: 't' + Date.now(),
- category: categoryFilter,
- versionNo: null,
- versionName: buildAutoVersionName(categoryFilter, null, importName),
- status: 'draft',
- isDefault: false,
- blocks: JSON.parse(JSON.stringify(blocks)),
- creator: CURRENT_USER,
- createTime: now,
- updater: CURRENT_USER,
- updateTime: now,
- remark: ''
- };
- setTemplates(function (prev) { return prev.concat([draftItem]); });
- message.success('草稿已保存(未生成版本号)');
- }
- } else if (editingRecord) {
- if (publish) {
- if (editingRecord.status === 'published') {
- var cat = editingRecord.category;
- var nextVersionNo = generateNextVersionNo(cat);
- var newVersion = {
- id: 't' + Date.now(),
- category: cat,
- versionNo: nextVersionNo,
- versionName: buildAutoVersionName(cat, nextVersionNo, importName || editingRecord.versionName),
- status: 'published',
- isDefault: false,
- blocks: JSON.parse(JSON.stringify(blocks)),
- creator: CURRENT_USER,
- createTime: now,
- updater: CURRENT_USER,
- updateTime: now,
- remark: editingRecord.remark || ''
- };
- setTemplates(function (prev) { return prev.concat([newVersion]); });
- message.success('已发布新版本 ' + nextVersionNo + ',原版本保留可回滚');
- } else {
- var publishVersionNo = generateNextVersionNo(editingRecord.category);
- setTemplates(function (prev) {
- return prev.map(function (t) {
- if (t.id !== editingRecord.id) return t;
- return Object.assign({}, t, {
- versionNo: publishVersionNo,
- versionName: buildAutoVersionName(t.category, publishVersionNo, importName || t.versionName),
- status: 'published',
- blocks: JSON.parse(JSON.stringify(blocks)),
- updater: CURRENT_USER,
- updateTime: now
- });
- });
- });
- message.success('已发布,版本号 ' + publishVersionNo);
- }
- } else {
- setTemplates(function (prev) {
- return prev.map(function (t) {
- if (t.id !== editingRecord.id) return t;
- var patch = {
- blocks: JSON.parse(JSON.stringify(blocks)),
- updater: CURRENT_USER,
- updateTime: now,
- status: 'draft',
- versionNo: null
- };
- if (importName) {
- patch.versionName = buildAutoVersionName(t.category, null, importName);
- }
- return Object.assign({}, t, patch);
- });
- });
- message.success('草稿已保存(未生成版本号)');
- }
- }
- backToList();
- }
-
- function backToList() {
- setPageView('list');
- placeholderPopoverOpenState[1](false);
- editorInsertHandlerRef.current = null;
- }
-
- function confirmSetDefault(record) {
- if (record.status !== 'published') {
- message.warning('仅已发布版本可设为标准模板');
- return;
- }
- defaultConfirmTargetState[1](record);
- defaultConfirmModalState[1](true);
- }
-
- function handleSetDefault() {
- var record = defaultConfirmTargetState[0];
- if (!record) return;
- setTemplates(function (prev) {
- return prev.map(function (t) {
- if (t.category !== record.category) return t;
- return Object.assign({}, t, { isDefault: t.id === record.id });
- });
- });
- defaultConfirmModalState[1](false);
- defaultConfirmTargetState[1](null);
- message.success('已设为标准模板:' + record.versionNo);
- }
-
- function confirmDelete(record) {
- if (record.isDefault) {
- message.warning('当前为标准模板,无法删除。请先切换其他版本为标准模板。');
- return;
- }
- deleteTargetState[1](record);
- deleteModalState[1](true);
- }
-
- function handleDelete() {
- var target = deleteTargetState[0];
- if (!target) return;
- if (target.isDefault) {
- message.warning('标准模板无法删除');
- return;
- }
- setTemplates(function (prev) { return prev.filter(function (t) { return t.id !== target.id; }); });
- deleteModalState[1](false);
- deleteTargetState[1](null);
- message.success('已删除模板版本');
- }
-
- function isWordFormattedDoc(html) {
- return /ct-word-doc|ct-word-title/.test(String(html || ''));
- }
-
- function getLessorCompanies() {
- if (typeof window !== 'undefined' && window.ONEOS_LESSOR_COMPANIES && window.ONEOS_LESSOR_COMPANIES.length) {
- return window.ONEOS_LESSOR_COMPANIES;
- }
- return DEFAULT_LESSOR_COMPANIES;
- }
-
- function getLessorCompanyById(id) {
- var list = getLessorCompanies();
- return list.find(function (c) { return c.id === id; }) || list.find(function (c) { return c.enabled; }) || list[0] || null;
- }
-
- function buildLessorVars(company) {
- if (!company) return {};
- return {
- lessorName: company.legalName || '',
- lessorShortName: company.shortName || '',
- lessorAddress: company.address || '',
- lessorContact: company.contact || '',
- lessorPhone: company.phone || '',
- lessorEmail: company.email || '',
- lessorAccountName: company.accountName || company.legalName || '',
- lessorBankName: company.bankName || '',
- lessorBankAccount: company.bankAccount || '',
- lessorHotline: DEFAULT_LESSOR_HOTLINE,
- lessorCreditCode: company.creditCode || ''
- };
- }
-
- function applyTemplateVars(html, vars) {
- var out = String(html || '');
- Object.keys(vars || {}).forEach(function (key) {
- var val = vars[key] != null ? String(vars[key]) : '';
- out = out.split('{{' + key + '}}').join(val);
- });
- return out;
- }
-
- function fixWordPreviewHtml(html) {
- if (!html || typeof document === 'undefined') return String(html || '');
- var div = document.createElement('div');
- var cleaned = String(html)
- .replace(/<\/p>
]*>[\s\S]*?<\/tr><\/tbody><\/table>/g, function (frag) {
- return frag.indexOf('= 0 ? frag : '';
- });
- div.innerHTML = cleaned;
- div.querySelectorAll('table.ct-word-table').forEach(function (table) {
- var maxCols = 0;
- table.querySelectorAll('tr').forEach(function (tr) {
- var cols = 0;
- tr.querySelectorAll('td, th').forEach(function (td) {
- cols += parseInt(td.getAttribute('colspan') || '1', 10);
- });
- if (cols > maxCols) maxCols = cols;
- });
- if (maxCols <= 1) return;
- table.querySelectorAll('tr').forEach(function (tr) {
- var tds = tr.querySelectorAll('td, th');
- var cols = 0;
- tds.forEach(function (td) { cols += parseInt(td.getAttribute('colspan') || '1', 10); });
- if (tds.length === 1 && cols === 1) {
- tds[0].setAttribute('colspan', String(maxCols));
- tds[0].classList.add('ct-word-td-full');
- }
- });
- });
- return div.innerHTML;
- }
-
- function paginateWordHtml(html) {
- var MM = 96 / 25.4;
- var contentH = Math.floor((297 - 25.4 * 2) * MM);
- var contentW = Math.floor((210 - 31.8 * 2) * MM);
- var fixed = preparePreviewHtml(html);
- var sandbox = document.createElement('div');
- sandbox.style.cssText = 'position:fixed;left:-20000px;top:0;visibility:hidden;pointer-events:none;';
- document.body.appendChild(sandbox);
-
- var measure = document.createElement('div');
- measure.className = 'ct-word-doc ct-word-measure';
- measure.style.width = contentW + 'px';
- measure.style.fontFamily = 'FangSong, STFangsong, "仿宋", SimSun, "宋体", serif';
- measure.style.fontSize = '10.5pt';
- measure.style.lineHeight = '1.5';
- measure.innerHTML = fixed;
- sandbox.appendChild(measure);
-
- var root = measure.querySelector('.ct-word-doc') || measure;
- var nodes = [];
- root.childNodes.forEach(function (n) {
- if (n.nodeType === 1) nodes.push(n);
- else if (n.nodeType === 3 && String(n.textContent || '').trim()) {
- var p = document.createElement('p');
- p.className = 'ct-word-body';
- p.textContent = n.textContent;
- nodes.push(p);
- }
- });
-
- var pageMeasure = document.createElement('div');
- pageMeasure.className = 'ct-word-doc ct-word-measure';
- pageMeasure.style.width = contentW + 'px';
- pageMeasure.style.fontFamily = measure.style.fontFamily;
- pageMeasure.style.fontSize = measure.style.fontSize;
- pageMeasure.style.lineHeight = measure.style.lineHeight;
- sandbox.appendChild(pageMeasure);
-
- var pages = [];
- nodes.forEach(function (node) {
- var clone = node.cloneNode(true);
- pageMeasure.appendChild(clone);
- if (pageMeasure.scrollHeight > contentH + 4) {
- pageMeasure.removeChild(clone);
- if (pageMeasure.innerHTML.trim()) pages.push(pageMeasure.innerHTML);
- pageMeasure.innerHTML = '';
- pageMeasure.appendChild(clone);
- if (pageMeasure.scrollHeight > contentH + 4) {
- pages.push(pageMeasure.innerHTML);
- pageMeasure.innerHTML = '';
- }
- }
- });
- if (pageMeasure.innerHTML.trim()) pages.push(pageMeasure.innerHTML);
- if (!pages.length) pages.push(fixed);
-
- document.body.removeChild(sandbox);
- return pages;
- }
-
- function WordPaginatedPreview(props) {
- var html = props.html || '';
- var viewModeState = useState('scroll');
- var pagesState = useState([]);
- var pageIdxState = useState(0);
- var viewMode = viewModeState[0];
- var setViewMode = viewModeState[1];
- var pages = pagesState[0];
- var pageIdx = pageIdxState[0];
- var setPageIdx = pageIdxState[1];
-
- useEffect(function () {
- if (!html) {
- pagesState[1]([]);
- return;
- }
- var timer = window.setTimeout(function () {
- pagesState[1](paginateWordHtml(html));
- pageIdxState[1](0);
- }, 0);
- return function () { window.clearTimeout(timer); };
- }, [html]);
-
- if (!pages.length) {
- return React.createElement('div', { className: 'ct-preview-pages' },
- React.createElement('div', { className: 'ct-preview-page is-loading' }, 'Word 分页排版计算中…')
- );
- }
-
- var pager = React.createElement('div', { className: 'ct-preview-pager' },
- React.createElement(Button, {
- size: 'small',
- disabled: pageIdx <= 0,
- onClick: function () { setPageIdx(Math.max(0, pageIdx - 1)); }
- }, '上一页'),
- React.createElement('span', { className: 'ct-preview-pager__info' }, '第 ', pageIdx + 1, ' / ', pages.length, ' 页'),
- React.createElement(Button, {
- size: 'small',
- disabled: pageIdx >= pages.length - 1,
- onClick: function () { setPageIdx(Math.min(pages.length - 1, pageIdx + 1)); }
- }, '下一页'),
- React.createElement(Button, {
- size: 'small',
- type: viewMode === 'scroll' ? 'primary' : 'default',
- onClick: function () { setViewMode('scroll'); }
- }, '连续预览'),
- React.createElement(Button, {
- size: 'small',
- type: viewMode === 'single' ? 'primary' : 'default',
- onClick: function () { setViewMode('single'); }
- }, '单页预览')
- );
-
- if (viewMode === 'single') {
- return React.createElement('div', null,
- pager,
- React.createElement('div', { className: 'ct-preview-pages' },
- React.createElement('div', { className: 'ct-preview-page', key: pageIdx },
- React.createElement('div', {
- className: 'ct-preview-page__body ct-word-doc',
- dangerouslySetInnerHTML: { __html: pages[pageIdx] }
- }),
- React.createElement('div', { className: 'ct-preview-page__footer' }, '— ', pageIdx + 1, ' —')
- )
- )
- );
- }
-
- return React.createElement('div', null,
- pager,
- React.createElement('div', { className: 'ct-preview-pages' },
- pages.map(function (pageHtml, i) {
- return React.createElement('div', { className: 'ct-preview-page', key: 'p-' + i },
- React.createElement('div', {
- className: 'ct-preview-page__body ct-word-doc',
- dangerouslySetInnerHTML: { __html: pageHtml }
- }),
- React.createElement('div', { className: 'ct-preview-page__footer' }, '— ', i + 1, ' —')
- );
- })
- )
- );
- }
-
- function renderPreview(html, previewVars) {
- var raw = html || formDocumentHtmlState[0] || '';
- var content = previewVars ? applyTemplateVars(raw, previewVars) : raw;
- var displayHtml = preparePreviewHtml(content);
- var wordDoc = isWordFormattedDoc(content);
- if (wordDoc) {
- return React.createElement('div', { className: 'ct-preview-doc ct-word-doc ct-word-paginated' },
- React.createElement(WordPaginatedPreview, { html: content })
- );
- }
- var previewClass = 'ct-preview-doc';
- return React.createElement('div', { className: previewClass },
- React.createElement('h1', null, getDocumentTitle(content)),
- React.createElement('div', {
- className: 'ct-preview-section__body',
- dangerouslySetInnerHTML: { __html: displayHtml }
- })
- );
- }
-
- function UnifiedContractEditor(props) {
- var html = props.html;
- var onChange = props.onChange;
- var syncKey = props.syncKey;
- var onRegisterInsert = props.onRegisterInsert;
- var editorRef = useRef(null);
- var sourceTextareaRef = useRef(null);
- var lockIdRef = useRef(1);
- var riskIdRef = useRef(1);
- var fullscreenState = useState(false);
- var isFullscreen = fullscreenState[0];
- var setFullscreen = fullscreenState[1];
- var sourceModeState = useState(false);
- var isSourceMode = sourceModeState[0];
- var setSourceMode = sourceModeState[1];
- var isSourceModeRef = useRef(isSourceMode);
- isSourceModeRef.current = isSourceMode;
- var sourceDraftState = useState('');
- var findModalState = useState(false);
- var findTextState = useState('');
- var replaceTextState = useState('');
- var docStatsState = useState({ chars: 0, words: 0, locks: 0, riskRedlines: 0 });
- var fmtState = useState({ bold: false, italic: false, underline: false, align: 'left' });
- var fontSizePickState = useState('14px');
-
- function updateDocStats(content) {
- var plain = htmlToPlainText(content || '');
- docStatsState[1]({
- chars: plain.length,
- words: plain.trim() ? plain.trim().split(/\s+/).length : 0,
- locks: countLockRegions(content || ''),
- riskRedlines: countRiskRedlineRegions(content || '')
- });
- }
-
- useEffect(function () {
- var el = editorRef.current;
- if (!el) return;
- el.innerHTML = html || '';
- updateDocStats(html || '');
- }, [syncKey]);
-
- function insertAtCursor(text) {
- var token = String(text || '');
- if (!token) return;
- if (isSourceModeRef.current) {
- var ta = sourceTextareaRef.current;
- if (!ta) return;
- var start = ta.selectionStart != null ? ta.selectionStart : ta.value.length;
- var end = ta.selectionEnd != null ? ta.selectionEnd : start;
- var next = ta.value.slice(0, start) + token + ta.value.slice(end);
- sourceDraftState[1](next);
- onChange(next);
- updateDocStats(next);
- requestAnimationFrame(function () {
- ta.focus();
- var pos = start + token.length;
- ta.setSelectionRange(pos, pos);
- });
- return;
- }
- var el = editorRef.current;
- if (!el) return;
- el.focus();
- try { document.execCommand('insertText', false, token); } catch (e) {
- try { document.execCommand('insertHTML', false, token); } catch (e2) { /* noop */ }
- }
- syncHtml();
- }
-
- useEffect(function () {
- if (!onRegisterInsert) return;
- onRegisterInsert(insertAtCursor);
- return function () { onRegisterInsert(null); };
- }, [onRegisterInsert]);
-
- useEffect(function () {
- function refreshFmt() {
- try {
- var align = 'left';
- if (document.queryCommandState('justifyCenter')) align = 'center';
- else if (document.queryCommandState('justifyRight')) align = 'right';
- else if (document.queryCommandState('justifyFull')) align = 'justify';
- fmtState[1]({
- bold: document.queryCommandState('bold'),
- italic: document.queryCommandState('italic'),
- underline: document.queryCommandState('underline'),
- align: align
- });
- } catch (e) { /* noop */ }
- }
- document.addEventListener('selectionchange', refreshFmt);
- return function () { document.removeEventListener('selectionchange', refreshFmt); };
- }, []);
-
- function syncHtml() {
- var el = editorRef.current;
- if (!el) return;
- var inner = el.innerHTML;
- onChange(inner);
- updateDocStats(inner);
- }
-
- function runCmd(cmd, val) {
- var el = editorRef.current;
- if (!el) return;
- el.focus();
- try { document.execCommand(cmd, false, val != null ? val : null); } catch (e) { /* noop */ }
- syncHtml();
- }
-
- function rteSep(key) {
- return React.createElement('span', { key: key || 'sep', className: 'ct-rte-sep' });
- }
-
- function rteBtn(title, icon, action, opts) {
- opts = opts || {};
- var btn = React.createElement('button', {
- type: 'button',
- title: opts.wrap ? title : undefined,
- className: 'ct-rte-btn' + (opts.active ? ' is-active' : '') + (opts.dropdown ? ' ct-rte-btn--dropdown' : ''),
- disabled: !!opts.disabled,
- onMouseDown: function (e) {
- if (!opts.dropdown) e.preventDefault();
- if (!opts.disabled && action) action(e);
- }
- }, icon, opts.dropdown ? rteIcon('chevron') : null);
- if (opts.wrap) return React.createElement('span', { key: opts.key || title, className: 'ct-rte-dropdown-wrap' }, btn);
- return React.createElement(Tooltip, { key: opts.key || title, title: title }, btn);
- }
-
- function rteDropdown(menu, title, icon, key) {
- return React.createElement(Dropdown, { key: key, menu: menu, trigger: ['click'] },
- rteBtn(title, icon, null, { key: key + '-btn', dropdown: true, wrap: true })
- );
- }
-
- function rteColorMenu(options, cmd) {
- return {
- items: options.map(function (opt) {
- return {
- key: opt.value,
- label: React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', gap: 8 } },
- React.createElement('span', {
- style: {
- width: 12, height: 12, borderRadius: 2,
- background: opt.value, border: '1px solid #E2E8F0', display: 'inline-block'
- }
- }),
- opt.label
- ),
- onClick: function () { runCmd(cmd, opt.value); }
- };
- })
- };
- }
-
- function applyFontSize(size) {
- if (!size) return;
- fontSizePickState[1](size);
- var el = editorRef.current;
- if (!el) return;
- el.focus();
- var sel = window.getSelection();
- if (!sel || sel.rangeCount === 0 || sel.isCollapsed) {
- runCmd('fontSize', '4');
- syncHtml();
- return;
- }
- document.execCommand('insertHTML', false, '' + sel.toString() + '');
- syncHtml();
- }
-
- function applyLetterSpacing(spacing) {
- if (!spacing) return;
- var el = editorRef.current;
- if (!el) return;
- el.focus();
- var sel = window.getSelection();
- if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
- document.execCommand('insertHTML', false, '' + sel.toString() + '');
- syncHtml();
- }
-
- function applyFontFamily(font) {
- if (!font) return;
- runCmd('fontName', font);
- }
-
- function applyHeading(tag) {
- if (!tag) return;
- runCmd('formatBlock', '<' + tag + '>');
- }
-
- function insertTable(rows, cols) {
- var el = editorRef.current;
- if (!el) return;
- el.focus();
- document.execCommand('insertHTML', false, buildTableHtml(rows, cols));
- syncHtml();
- }
-
- function insertLink() {
- var url = window.prompt('请输入链接地址', 'https://');
- if (!url) return;
- runCmd('createLink', url);
- }
-
- function doClipboard(cmd) {
- var el = editorRef.current;
- if (!el) return;
- el.focus();
- if (cmd === 'paste') {
- if (navigator.clipboard && navigator.clipboard.readText) {
- navigator.clipboard.readText().then(function (text) {
- document.execCommand('insertText', false, text);
- syncHtml();
- }).catch(function () {
- message.info('请使用 Ctrl+V 粘贴,或在浏览器中授予剪贴板权限');
- });
- return;
- }
- message.info('请使用 Ctrl+V 粘贴');
- return;
- }
- try { document.execCommand(cmd); syncHtml(); } catch (e) { message.info('请使用快捷键 Ctrl+' + (cmd === 'copy' ? 'C' : 'X')); }
- }
-
- function applyLineHeight(lh) {
- if (!lh) return;
- var el = editorRef.current;
- if (!el) return;
- el.focus();
- var sel = window.getSelection();
- if (!sel || sel.rangeCount === 0) return;
- var block = sel.getRangeAt(0).commonAncestorContainer;
- if (block.nodeType === 3) block = block.parentNode;
- while (block && block !== el && !/^(P|DIV|H1|H2|H3|H4|BLOCKQUOTE|LI|TD|TH)$/.test(block.nodeName)) block = block.parentNode;
- if (block && block !== el) block.style.lineHeight = lh;
- else document.execCommand('insertHTML', false, '
');
- syncHtml();
- }
-
- function applyFirstLineIndent(indent) {
- var el = editorRef.current;
- if (!el) return;
- el.focus();
- var sel = window.getSelection();
- if (!sel || sel.rangeCount === 0) return;
- var block = sel.getRangeAt(0).commonAncestorContainer;
- if (block.nodeType === 3) block = block.parentNode;
- while (block && block !== el && !/^(P|DIV|H1|H2|H3|H4)$/.test(block.nodeName)) block = block.parentNode;
- if (block && block !== el) {
- block.style.textIndent = indent;
- syncHtml();
- }
- }
-
- function insertPageBreak() {
- runCmd('insertHTML', false, ' ');
- }
-
- function insertDate() {
- var d = new Date();
- var s = d.getFullYear() + '年' + (d.getMonth() + 1) + '月' + d.getDate() + '日';
- runCmd('insertText', false, s);
- }
-
- function insertSpecialChar(ch) {
- runCmd('insertText', false, ch);
- }
-
- function getActiveTableCell() {
- var sel = window.getSelection();
- var node = sel && sel.anchorNode;
- if (!node) return null;
- if (node.nodeType === 3) node = node.parentNode;
- return node && node.closest ? node.closest('td, th') : null;
- }
-
- function getActiveTable() {
- var cell = getActiveTableCell();
- if (!cell) return null;
- var table = cell.parentNode;
- while (table && table.nodeName !== 'TABLE') table = table.parentNode;
- return table;
- }
-
- function tableOp(op) {
- var cell = getActiveTableCell();
- var table = getActiveTable();
- if (!cell || !table) {
- message.info('请将光标置于表格单元格内');
- return;
- }
- var row = cell.parentNode;
- var colIdx = cell.cellIndex;
- if (op === 'addRowAbove' || op === 'addRowBelow') {
- var newRow = row.cloneNode(true);
- Array.prototype.forEach.call(newRow.cells, function (c) { c.innerHTML = ' '; });
- if (op === 'addRowAbove') row.parentNode.insertBefore(newRow, row);
- else row.parentNode.insertBefore(newRow, row.nextSibling);
- } else if (op === 'addColLeft' || op === 'addColRight') {
- var insertIdx = op === 'addColLeft' ? colIdx : colIdx + 1;
- Array.prototype.forEach.call(table.rows, function (r) {
- var td = document.createElement(r.cells[0] && r.cells[0].nodeName === 'TH' ? 'th' : 'td');
- td.innerHTML = ' ';
- if (insertIdx >= r.cells.length) r.appendChild(td);
- else r.insertBefore(td, r.cells[insertIdx]);
- });
- } else if (op === 'deleteTable') {
- table.parentNode.removeChild(table);
- }
- syncHtml();
- }
-
- function findNext() {
- var kw = (findTextState[0] || '').trim();
- if (!kw) { message.info('请输入查找内容'); return; }
- var found = window.find(kw, false, false, true, false, true, false);
- if (!found) message.info('未找到更多匹配项');
- }
-
- function replaceInDoc(all) {
- var findStr = (findTextState[0] || '').trim();
- var replStr = replaceTextState[0] || '';
- if (!findStr) { message.info('请输入查找内容'); return; }
- var el = editorRef.current;
- if (!el) return;
- var count = 0;
- var walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null);
- var nodes = [];
- while (walker.nextNode()) nodes.push(walker.currentNode);
- for (var ni = 0; ni < nodes.length; ni++) {
- var textNode = nodes[ni];
- var val = textNode.nodeValue;
- if (val.indexOf(findStr) < 0) continue;
- if (all) {
- var parts = val.split(findStr);
- count += parts.length - 1;
- textNode.nodeValue = parts.join(replStr);
- } else {
- textNode.nodeValue = val.replace(findStr, replStr);
- count = 1;
- break;
- }
- }
- if (count > 0) {
- syncHtml();
- message.success(all ? ('已替换 ' + count + ' 处') : '已替换 1 处');
- } else message.info('未找到匹配内容');
- }
-
- function toggleSourceMode() {
- if (!isSourceMode) {
- sourceDraftState[1](editorRef.current ? editorRef.current.innerHTML : html);
- setSourceMode(true);
- } else {
- onChange(sourceDraftState[0]);
- setSourceMode(false);
- setTimeout(function () {
- var el = editorRef.current;
- if (el) el.innerHTML = sourceDraftState[0];
- updateDocStats(sourceDraftState[0]);
- }, 0);
- }
- }
-
- function printDoc() {
- var content = isSourceMode ? sourceDraftState[0] : (editorRef.current ? editorRef.current.innerHTML : html);
- var w = window.open('', '_blank');
- if (!w) { message.warning('请允许弹出窗口后重试'); return; }
- w.document.write('合同打印预览');
- w.document.write(content);
- w.document.write('');
- w.document.close();
- w.focus();
- w.print();
- }
-
- function handleInsertImage(file) {
- var el = editorRef.current;
- if (!el) return false;
- if (!file || !file.type || file.type.indexOf('image') !== 0) {
- message.warning('请上传图片文件');
- return false;
- }
- var reader = new FileReader();
- reader.onload = function (ev) {
- el.focus();
- document.execCommand('insertHTML', false, ' ');
- syncHtml();
- };
- reader.readAsDataURL(file);
- return false;
- }
-
- function wrapSelectionAsLock() {
- var el = editorRef.current;
- if (!el) return;
- var sel = window.getSelection();
- if (!sel || sel.rangeCount === 0 || sel.isCollapsed) {
- message.info('请先选中要锁定的内容');
- return;
- }
- var range = sel.getRangeAt(0);
- if (!el.contains(range.commonAncestorContainer)) return;
- var lockId = 'lk' + (lockIdRef.current++);
- var span = document.createElement('span');
- span.className = 'ct-inline-lock';
- span.setAttribute('data-inline-lock', '1');
- span.setAttribute('data-lock-id', lockId);
- span.setAttribute('title', '内容锁定区');
- try {
- range.surroundContents(span);
- } catch (err) {
- document.execCommand('insertHTML', false, '' + sel.toString() + '');
- }
- syncHtml();
- message.success('已设为内容锁定区');
- }
-
- function unwrapSelectionLock() {
- var el = editorRef.current;
- if (!el) return;
- var sel = window.getSelection();
- var node = sel && sel.anchorNode;
- var lockEl = null;
- if (node) {
- if (node.nodeType === 3) node = node.parentNode;
- if (node && node.closest) lockEl = node.closest('.ct-inline-lock');
- }
- if (!lockEl) {
- message.info('请将光标置于锁定内容内再解锁');
- return;
- }
- var parent = lockEl.parentNode;
- while (lockEl.firstChild) parent.insertBefore(lockEl.firstChild, lockEl);
- parent.removeChild(lockEl);
- syncHtml();
- message.success('已解除内容锁定');
- }
-
- function getRiskWrapBlock(el, sel) {
- var node = sel && sel.anchorNode;
- if (!node) return null;
- if (node.nodeType === 3) node = node.parentNode;
- while (node && node !== el) {
- if (node.nodeType === 1 && /^(P|DIV|LI|H[1-6]|TD)$/i.test(node.tagName)) return node;
- node = node.parentNode;
- }
- return null;
- }
-
- function wrapBlockAsRiskRedline(block) {
- if (!block || block.closest('.ct-risk-redline')) {
- message.info('该段落已是风控红线条款');
- return;
- }
- var wrapper = document.createElement('div');
- wrapper.className = 'ct-risk-redline';
- wrapper.setAttribute('data-risk-redline', '1');
- wrapper.setAttribute('data-risk-id', 'rk' + (riskIdRef.current++));
- wrapper.setAttribute('data-nonstd-trigger', '1');
- wrapper.setAttribute('title', '风控红线条款:创建合同时修改将触发非标审批');
- block.parentNode.insertBefore(wrapper, block);
- wrapper.appendChild(block);
- syncHtml();
- message.success('已设为风控红线条款');
- }
-
- function wrapSelectionAsRiskRedline() {
- var el = editorRef.current;
- if (!el) return;
- var sel = window.getSelection();
- if (!sel || sel.rangeCount === 0) {
- message.info('请先选中段落或条款内容');
- return;
- }
- var range = sel.getRangeAt(0);
- if (!el.contains(range.commonAncestorContainer)) return;
- if (sel.isCollapsed || !String(sel.toString() || '').trim()) {
- var block = getRiskWrapBlock(el, sel);
- if (block) {
- wrapBlockAsRiskRedline(block);
- return;
- }
- message.info('请先选中段落或条款内容');
- return;
- }
- if (sel.anchorNode && sel.anchorNode.parentNode && sel.anchorNode.parentNode.closest &&
- sel.anchorNode.parentNode.closest('.ct-risk-redline')) {
- message.info('选中内容已在风控红线条款内');
- return;
- }
- var riskId = 'rk' + (riskIdRef.current++);
- var span = document.createElement('span');
- span.className = 'ct-risk-redline';
- span.setAttribute('data-risk-redline', '1');
- span.setAttribute('data-risk-id', riskId);
- span.setAttribute('data-nonstd-trigger', '1');
- span.setAttribute('title', '风控红线条款:创建合同时修改将触发非标审批');
- try {
- range.surroundContents(span);
- } catch (err) {
- document.execCommand('insertHTML', false,
- '' +
- sel.toString() + '');
- }
- syncHtml();
- message.success('已设为风控红线条款');
- }
-
- function unwrapSelectionRiskRedline() {
- var el = editorRef.current;
- if (!el) return;
- var sel = window.getSelection();
- var node = sel && sel.anchorNode;
- var riskEl = null;
- if (node) {
- if (node.nodeType === 3) node = node.parentNode;
- if (node && node.closest) riskEl = node.closest('.ct-risk-redline');
- }
- if (!riskEl) {
- message.info('请将光标置于风控红线条款内再取消');
- return;
- }
- var footer = riskEl.querySelector('.ct-risk-redline__footer');
- if (footer) footer.parentNode.removeChild(footer);
- var parent = riskEl.parentNode;
- while (riskEl.firstChild) parent.insertBefore(riskEl.firstChild, riskEl);
- parent.removeChild(riskEl);
- syncHtml();
- message.success('已取消风控红线条款标记');
- }
-
- function rteTextBtn(label, title, action, opts) {
- opts = opts || {};
- return React.createElement(Tooltip, { key: opts.key || label, title: title },
- React.createElement('button', {
- type: 'button',
- className: 'ct-rte-btn ct-rte-btn--text' + (opts.muted ? ' is-muted' : ''),
- onMouseDown: function (e) {
- e.preventDefault();
- if (action) action(e);
- }
- }, label)
- );
- }
-
- var fmt = fmtState[0];
-
- var tableMenuItems = TABLE_PRESET_ITEMS.map(function (item) {
- return { key: item.key, label: item.label, onClick: function () { insertTable(item.rows, item.cols); } };
- });
-
- var specialCharMenuItems = SPECIAL_CHAR_ITEMS.map(function (item) {
- return { key: item.key, label: item.label, onClick: function () { insertSpecialChar(item.char); } };
- });
-
- var lineHeightMenuItems = LINE_HEIGHT_OPTIONS.map(function (item) {
- return { key: item.value, label: item.label, onClick: function () { applyLineHeight(item.value); } };
- });
-
- var letterSpacingMenuItems = LETTER_SPACING_OPTIONS.map(function (item) {
- return { key: item.value, label: item.label, onClick: function () { applyLetterSpacing(item.value); } };
- });
-
- var scriptMenuItems = [
- { key: 'sup', label: '上标', onClick: function () { runCmd('superscript'); } },
- { key: 'sub', label: '下标', onClick: function () { runCmd('subscript'); } }
- ];
-
- var moreMenuItems = [
- { type: 'group', label: '编辑', children: [
- { key: 'find', label: '查找替换', onClick: function () { findModalState[1](true); } },
- { key: 'cut', label: '剪切', onClick: function () { doClipboard('cut'); } },
- { key: 'copy', label: '复制', onClick: function () { doClipboard('copy'); } },
- { key: 'paste', label: '粘贴', onClick: function () { doClipboard('paste'); } },
- { key: 'selectAll', label: '全选', onClick: function () { runCmd('selectAll'); } }
- ] },
- { type: 'group', label: '段落', children: [
- { key: 'heading', label: '段落样式', children: PARAGRAPH_STYLE_OPTIONS.map(function (p) {
- return { key: 'h-' + p.value, label: p.label, onClick: function () { applyHeading(p.value); } };
- }) },
- { key: 'strike', label: '删除线', onClick: function () { runCmd('strikeThrough'); } },
- { key: 'unlink', label: '取消链接', onClick: function () { runCmd('unlink'); } },
- { key: 'indent2', label: '首行缩进 2 字符', onClick: function () { applyFirstLineIndent('2em'); } },
- { key: 'indent0', label: '取消首行缩进', onClick: function () { applyFirstLineIndent('0'); } },
- { key: 'hr', label: '分隔线', onClick: function () { runCmd('insertHorizontalRule'); } },
- { key: 'pagebreak', label: '分页符', onClick: insertPageBreak },
- { key: 'date', label: '插入日期', onClick: insertDate }
- ] },
- { type: 'group', label: '表格', children: [
- { key: 'rowUp', label: '上方插入行', onClick: function () { tableOp('addRowAbove'); } },
- { key: 'rowDn', label: '下方插入行', onClick: function () { tableOp('addRowBelow'); } },
- { key: 'colL', label: '左侧插入列', onClick: function () { tableOp('addColLeft'); } },
- { key: 'colR', label: '右侧插入列', onClick: function () { tableOp('addColRight'); } },
- { key: 'delTbl', label: '删除表格', onClick: function () { tableOp('deleteTable'); } }
- ] },
- { type: 'group', label: '合同', children: [
- { key: 'lock', label: '锁定选中内容', onClick: wrapSelectionAsLock },
- { key: 'unlock', label: '解除锁定', onClick: unwrapSelectionLock },
- { key: 'risk', label: '设为风控红线条款', onClick: wrapSelectionAsRiskRedline },
- { key: 'unrisk', label: '取消风控红线条款', onClick: unwrapSelectionRiskRedline }
- ] },
- { type: 'group', label: '视图', children: [
- { key: 'fullscreen', label: isFullscreen ? '退出全屏' : '全屏编辑', onClick: function () { setFullscreen(!isFullscreen); } },
- { key: 'source', label: isSourceMode ? '返回可视化' : 'HTML 源码', onClick: toggleSourceMode },
- { key: 'print', label: '打印预览', onClick: printDoc }
- ] }
- ];
-
- var row1 = React.createElement('div', { className: 'ct-rich-toolbar__row' },
- React.createElement(Select, {
- key: 'fs', className: 'ct-rte-select ct-rte-select--size', size: 'small',
- value: fontSizePickState[0], options: FONT_SIZE_OPTIONS,
- onChange: applyFontSize
- }),
- rteSep('s1'),
- rteBtn('粗体 Ctrl+B', rteIcon('bold'), function () { runCmd('bold'); }, { key: 'bold', active: fmt.bold }),
- rteBtn('斜体 Ctrl+I', rteIcon('italic'), function () { runCmd('italic'); }, { key: 'italic', active: fmt.italic }),
- rteBtn('下划线 Ctrl+U', rteIcon('underline'), function () { runCmd('underline'); }, { key: 'underline', active: fmt.underline }),
- rteDropdown(rteColorMenu(COLOR_OPTIONS, 'foreColor'), '字体颜色', rteIcon('fontColor'), 'fg'),
- rteDropdown(rteColorMenu(BG_COLOR_OPTIONS, 'hiliteColor'), '背景色', rteIcon('highlight'), 'bg'),
- rteDropdown({ items: letterSpacingMenuItems }, '字符间距', rteIcon('letterSpacing'), 'lsp'),
- rteSep('s2'),
- React.createElement('div', { key: 'align', className: 'ct-rte-align-group' },
- rteBtn('左对齐', rteIcon('alignLeft'), function () { runCmd('justifyLeft'); }, { key: 'al', active: fmt.align === 'left' }),
- rteBtn('居中', rteIcon('alignCenter'), function () { runCmd('justifyCenter'); }, { key: 'ac', active: fmt.align === 'center' }),
- rteBtn('右对齐', rteIcon('alignRight'), function () { runCmd('justifyRight'); }, { key: 'ar', active: fmt.align === 'right' }),
- rteBtn('两端对齐', rteIcon('alignJustify'), function () { runCmd('justifyFull'); }, { key: 'aj', active: fmt.align === 'justify' })
- ),
- rteDropdown({ items: lineHeightMenuItems }, '行距', rteIcon('lineHeight'), 'lh'),
- rteBtn('减少缩进', rteIcon('outdent'), function () { runCmd('outdent'); }, { key: 'outdent' })
- );
-
- var row2 = React.createElement('div', { className: 'ct-rich-toolbar__row' },
- React.createElement(Select, {
- key: 'font', className: 'ct-rte-select ct-rte-select--font', size: 'small',
- placeholder: '默认字体', options: FONT_FAMILY_OPTIONS,
- onChange: applyFontFamily, allowClear: true
- }),
- rteSep('s3'),
- rteBtn('清除格式', rteIcon('eraser'), function () { runCmd('removeFormat'); }, { key: 'eraser' }),
- React.createElement(Upload, { key: 'img', showUploadList: false, accept: 'image/*', beforeUpload: handleInsertImage },
- rteBtn('插入图片', rteIcon('image'), null, { key: 'imgBtn', wrap: true })
- ),
- rteDropdown({ items: scriptMenuItems }, '上标/下标', rteIcon('script'), 'script'),
- rteBtn('无序列表', rteIcon('listBullet'), function () { runCmd('insertUnorderedList'); }, { key: 'ul' }),
- rteBtn('有序列表', rteIcon('listOrdered'), function () { runCmd('insertOrderedList'); }, { key: 'ol' }),
- rteBtn('增加缩进', rteIcon('indent'), function () { runCmd('indent'); }, { key: 'indent' }),
- rteDropdown({ items: tableMenuItems }, '插入表格', rteIcon('table'), 'tbl'),
- rteDropdown({ items: specialCharMenuItems }, '特殊字符', rteIcon('bulb'), 'spec'),
- rteBtn('插入链接', rteIcon('link'), insertLink, { key: 'link' }),
- rteSep('s4'),
- rteBtn('撤销 Ctrl+Z', rteIcon('undo'), function () { runCmd('undo'); }, { key: 'undo' }),
- rteBtn('重做 Ctrl+Y', rteIcon('redo'), function () { runCmd('redo'); }, { key: 'redo' }),
- rteSep('s5'),
- rteTextBtn('风控红线', '设为风控红线条款(选中段落或文字后点击;创建合同时修改将触发非标审批)', wrapSelectionAsRiskRedline, { key: 'risk-redline' }),
- rteTextBtn('取消红线', '取消风控红线条款标记', unwrapSelectionRiskRedline, { key: 'unrisk-redline', muted: true }),
- rteDropdown({ items: moreMenuItems }, '更多功能', rteIcon('more'), 'more')
- );
-
- var stats = docStatsState[0];
-
- return React.createElement('div', { className: 'ct-rich-wrap' + (isFullscreen ? ' is-fullscreen' : '') },
- React.createElement('div', { className: 'ct-rich-toolbar' }, row1, row2),
- isSourceMode
- ? React.createElement('textarea', {
- ref: sourceTextareaRef,
- className: 'ct-rich-source',
- value: sourceDraftState[0],
- onChange: function (e) {
- sourceDraftState[1](e.target.value);
- onChange(e.target.value);
- updateDocStats(e.target.value);
- }
- })
- : React.createElement('div', {
- ref: editorRef,
- className: 'ct-rich-editor',
- contentEditable: true,
- suppressContentEditableWarning: true,
- onInput: syncHtml,
- onBlur: syncHtml
- }),
- React.createElement('div', { className: 'ct-rich-statusbar' },
- React.createElement('div', { className: 'ct-rich-statusbar__stats' },
- React.createElement('span', null, '字符:' + stats.chars),
- React.createElement('span', null, '词数:' + stats.words),
- React.createElement('span', null, '锁定区:' + stats.locks + ' 处'),
- React.createElement('span', null, '风控红线:' + stats.riskRedlines + ' 处')
- ),
- React.createElement('span', null, isSourceMode ? 'HTML 源码模式' : '可视化编辑')
- ),
- React.createElement(Modal, {
- title: '查找与替换',
- open: findModalState[0],
- onCancel: function () { findModalState[1](false); },
- footer: React.createElement(Space, null,
- React.createElement(Button, { onClick: findNext }, '查找下一处'),
- React.createElement(Button, { onClick: function () { replaceInDoc(false); } }, '替换'),
- React.createElement(Button, { type: 'primary', onClick: function () { replaceInDoc(true); } }, '全部替换'),
- React.createElement(Button, { onClick: function () { findModalState[1](false); } }, '关闭')
- )
- },
- React.createElement('div', { style: { marginBottom: 12 } },
- React.createElement('label', { className: 'ct-modal-form-label' }, '查找内容'),
- React.createElement(Input, {
- value: findTextState[0],
- onChange: function (e) { findTextState[1](e.target.value); },
- placeholder: '输入要查找的文字',
- allowClear: true
- })
- ),
- React.createElement('div', null,
- React.createElement('label', { className: 'ct-modal-form-label' }, '替换为'),
- React.createElement(Input, {
- value: replaceTextState[0],
- onChange: function (e) { replaceTextState[1](e.target.value); },
- placeholder: '留空则删除匹配文字',
- allowClear: true
- })
- )
- )
- );
- }
-
- function renderUnifiedEditor() {
- return React.createElement(UnifiedContractEditor, {
- key: 'unified-editor-' + editorSyncKeyState[0],
- html: formDocumentHtmlState[0],
- syncKey: editorSyncKeyState[0],
- onChange: syncDocumentHtml,
- onRegisterInsert: registerEditorInsertRef.current
- });
- }
-
- function copyTemplatePlaceholder(key) {
- var token = '{{' + key + '}}';
- if (typeof navigator !== 'undefined' && navigator.clipboard && navigator.clipboard.writeText) {
- navigator.clipboard.writeText(token).then(function () {
- message.success('已复制 ' + token);
- }).catch(function () {
- message.info(token);
- });
- return;
- }
- message.info(token);
- }
-
- function insertTemplatePlaceholder(key) {
- var token = '{{' + key + '}}';
- var insertFn = editorInsertHandlerRef.current;
- if (!insertFn) {
- message.warning('请先在编辑区点击定位光标');
- return;
- }
- insertFn(token);
- message.success('已插入 ' + token);
- }
-
- function renderTemplatePlaceholderCard() {
- return React.createElement('div', { className: 'ct-placeholder-card' },
- React.createElement('div', { className: 'ct-placeholder-card__head' },
- React.createElement('p', { className: 'ct-placeholder-card__title' }, '模板占位符'),
- React.createElement('p', { className: 'ct-placeholder-card__desc' }, '点击条目插入至光标处;也可复制后在编辑区粘贴。创建合同时将按规则自动替换。')
- ),
- CONTRACT_TEMPLATE_VAR_GROUPS.map(function (group) {
- return React.createElement('div', { key: group.title, className: 'ct-placeholder-card__group' },
- React.createElement('p', { className: 'ct-placeholder-card__group-title' }, group.title),
- React.createElement('p', { className: 'ct-placeholder-card__group-desc' }, group.desc),
- group.vars.map(function (v) {
- var token = '{{' + v.key + '}}';
- return React.createElement('div', {
- key: v.key,
- className: 'ct-placeholder-card__item',
- role: 'button',
- tabIndex: 0,
- onClick: function () { insertTemplatePlaceholder(v.key); },
- onKeyDown: function (e) {
- if (e.key === 'Enter' || e.key === ' ') {
- e.preventDefault();
- insertTemplatePlaceholder(v.key);
- }
- }
- },
- React.createElement('div', { className: 'ct-placeholder-card__item-main' },
- React.createElement('div', { className: 'ct-placeholder-card__item-label' }, v.label),
- React.createElement('div', { className: 'ct-placeholder-card__item-token' }, token)
- ),
- React.createElement('div', { className: 'ct-placeholder-card__item-actions' },
- React.createElement('span', {
- className: 'ct-placeholder-card__action',
- role: 'button',
- tabIndex: 0,
- onClick: function (e) { e.stopPropagation(); copyTemplatePlaceholder(v.key); },
- onKeyDown: function (e) {
- if (e.key === 'Enter' || e.key === ' ') {
- e.preventDefault();
- e.stopPropagation();
- copyTemplatePlaceholder(v.key);
- }
- }
- }, '复制')
- )
- );
- })
- );
- })
- );
- }
-
- var columns = [
- { title: '版本号', dataIndex: 'versionNo', key: 'versionNo', width: 110, render: function (v, r) {
- return React.createElement(Space, { size: 6 },
- React.createElement('span', { style: { fontWeight: v ? 600 : 400, color: v ? '#1E293B' : '#94A3B8' } }, v || '—'),
- r.isDefault ? React.createElement(Tag, { color: 'gold' }, '标准模板') : null
- );
- } },
- { title: '版本名称', dataIndex: 'versionName', key: 'versionName', width: 200, ellipsis: true },
- { title: '状态', dataIndex: 'status', key: 'status', width: 88, align: 'center', render: statusTag },
- { title: '创建时间', dataIndex: 'createTime', key: 'createTime', width: 150 },
- { title: '创建人', dataIndex: 'creator', key: 'creator', width: 110 },
- { title: '最后更新时间', dataIndex: 'updateTime', key: 'updateTime', width: 150 },
- { title: '更新人', dataIndex: 'updater', key: 'updater', width: 110 },
- { title: '备注', dataIndex: 'remark', key: 'remark', ellipsis: true },
- {
- title: '操作', key: 'action', width: 168, fixed: 'right',
- render: function (_, record) {
- var more = [];
- if (record.status === 'published' && !record.isDefault) {
- more.push({ key: 'setDefault', label: '设为标准模板', onClick: function () { confirmSetDefault(record); } });
- }
- if (record.isDefault) {
- more.push({ key: 'currentDefault', label: '当前标准模板', disabled: true });
- }
- if (record.isDefault) {
- more.push({ key: 'deleteDisabled', label: '删除', disabled: true, danger: true });
- } else {
- more.push({ key: 'delete', label: '删除', danger: true, onClick: function () { confirmDelete(record); } });
- }
- return React.createElement(OperationActions, {
- edit: { onClick: function () { openEdit(record); } },
- more: more
- });
- }
- }
- ];
-
- var lessorCompanies = getLessorCompanies();
- var previewLessorCompany = getLessorCompanyById(previewLessorId);
- var previewTemplateVars = Object.assign(
- { customerName: '【承租方公司名称】', contractCode: '20260001' },
- buildLessorVars(previewLessorCompany)
- );
-
- function getListByCategory(categoryKey) {
- return templates.filter(function (r) {
- return r.category === categoryKey;
- }).sort(function (a, b) {
- if (a.isDefault !== b.isDefault) return a.isDefault ? -1 : 1;
- return String(b.updateTime).localeCompare(String(a.updateTime));
- });
- }
-
- function renderTabTable(categoryKey) {
- var list = getListByCategory(categoryKey);
- var stats = categoryStats[categoryKey] || { count: 0, defaultVersion: '—', defaultName: '未设置' };
- var catOpt = CATEGORY_OPTIONS.find(function (c) { return c.value === categoryKey; });
- return React.createElement('div', null,
- React.createElement('div', { className: 'ct-tab-summary' },
- React.createElement('div', { className: 'ct-tab-summary__meta' },
- (catOpt ? catOpt.desc : '') + ' · 共 ' + stats.count + ' 个版本'
- ),
- React.createElement('div', { className: 'ct-tab-summary__default' },
- React.createElement(Tag, { color: 'success', style: { margin: 0, fontWeight: 600 } }, '标准模板 · ' + stats.defaultVersion),
- React.createElement('span', { style: { fontSize: 13, color: '#475569' } }, stats.defaultName)
- )
- ),
- React.createElement('div', { className: 'oneos-table-card ct-table-card' },
- React.createElement(Table, {
- className: 'oneos-list-table ct-data-table',
- rowKey: 'id',
- columns: columns,
- dataSource: list,
- size: 'middle',
- bordered: false,
- rowClassName: function () { return 'ct-row-hover'; },
- pagination: { pageSize: 10, showTotal: function (t) { return '共 ' + t + ' 条'; }, showSizeChanger: false },
- scroll: { x: 1280 },
- locale: { emptyText: '该分类暂无合同模板,点击「新增标准合同」创建' }
- })
- )
- );
- }
-
- var tabItems = CATEGORY_OPTIONS.map(function (c) {
- var stats = categoryStats[c.value] || { count: 0 };
- return {
- key: c.value,
- label: React.createElement('span', { className: 'ct-tab-label' },
- c.label,
- React.createElement(Tag, { style: { margin: 0, lineHeight: '18px' } }, stats.count)
- ),
- children: renderTabTable(c.value)
- };
- });
-
- function renderEditorWorkspace() {
- var hasContent = !!(formDocumentHtmlState[0] || '').trim();
- return React.createElement(Row, { gutter: 16 },
- React.createElement(Col, { xs: 24, lg: 12 },
- React.createElement('div', { className: 'ct-panel-head' },
- React.createElement('div', { className: 'ct-panel-head__title' }, '编辑区',
- React.createElement('span', { className: 'ct-panel-head__badge' }, '富文本 · 图文混排')
- ),
- React.createElement('div', { className: 'ct-panel-head__actions' },
- React.createElement(Popover, {
- content: renderTemplatePlaceholderCard(),
- title: null,
- trigger: 'click',
- placement: 'bottomRight',
- open: placeholderPopoverOpenState[0],
- onOpenChange: placeholderPopoverOpenState[1],
- overlayInnerStyle: { padding: '12px 14px' }
- },
- React.createElement(Button, {
- size: 'small',
- className: 'ct-placeholder-trigger',
- type: placeholderPopoverOpenState[0] ? 'primary' : 'default',
- ghost: placeholderPopoverOpenState[0]
- }, '{ } 模板占位符')
- ),
- React.createElement(Upload, {
- accept: '.doc,.docx',
- showUploadList: false,
- beforeUpload: handleImportWord
- }, React.createElement(Button, {
- size: 'small',
- type: !hasContent && editorMode === 'create' ? 'primary' : 'default',
- className: !hasContent && editorMode === 'create' ? 'ct-btn-cta' : ''
- }, '导入 Word 模板'))
- )
- ),
- React.createElement('div', { key: 'editor-panel-' + editorSyncKeyState[0], className: 'ct-editor-panel' }, renderUnifiedEditor())
- ),
- React.createElement(Col, { xs: 24, lg: 12 },
- React.createElement('div', { className: 'ct-panel-head' },
- React.createElement('div', { className: 'ct-panel-head__title' }, '实时预览',
- React.createElement('span', { className: 'ct-panel-head__badge' },
- '锁定 ' + countLockRegions(formDocumentHtmlState[0]) + ' 处 · 风控红线 ' + countRiskRedlineRegions(formDocumentHtmlState[0]) + ' 处'
- )
- )
- ),
- React.createElement('div', { className: 'ct-preview-lessor-bar' },
- React.createElement('span', { className: 'ct-preview-lessor-bar__label' }, '预览签约主体(模拟创建合同时选择)'),
- React.createElement(Select, {
- style: { minWidth: 200 },
- value: previewLessorId,
- onChange: setPreviewLessorId,
- options: lessorCompanies.filter(function (c) { return c.enabled !== false; }).map(function (c) {
- return { value: c.id, label: c.legalName };
- })
- })
- ),
- React.createElement('div', { className: 'ct-preview-panel ct-preview-panel--word' }, renderPreview(formDocumentHtmlState[0], previewTemplateVars))
- )
- );
- }
-
- function renderEditorPage() {
- var editorTitle = editorMode === 'create'
- ? '新增标准合同'
- : ('编辑标准合同 · ' + (editingRecord
- ? (editingRecord.versionNo || '草稿')
- : ''));
- var hasContent = !!(formDocumentHtmlState[0] || '').trim();
- return React.createElement('div', { className: 'ct-editor-page' },
- React.createElement('div', { className: 'ct-editor-page__topbar' },
- React.createElement(Button, { className: 'vm-btn vm-btn-back', onClick: backToList }, '返回列表')
- ),
- React.createElement('div', { className: 'ct-editor-page__header' },
- React.createElement('h2', { className: 'ct-editor-page__title' }, editorTitle),
- !hasContent && editorMode === 'create'
- ? React.createElement('span', { style: { fontSize: 13, color: '#64748B' } }, '请先导入 Word 模板')
- : null
- ),
- React.createElement('div', { className: 'ct-editor-page__body' }, renderEditorWorkspace()),
- React.createElement('div', { className: 'ct-editor-page__footer' },
- React.createElement(Space, { size: 12 },
- React.createElement(Button, { onClick: backToList }, '取消'),
- !(editorMode === 'edit' && editingRecord && editingRecord.status === 'published')
- ? React.createElement(Button, { onClick: function () { handleSaveTemplate(false); } }, '保存草稿')
- : null,
- React.createElement(Button, { type: 'primary', className: 'ct-btn-cta', onClick: function () { handleSaveTemplate(true); } }, '保存并发布')
- )
- )
- );
- }
-
- function renderListPage() {
- return React.createElement('div', { className: 'oneos-table-section ct-table-section' },
- React.createElement(Card, {
- className: 'oneos-filter-card ct-list-card',
- title: '合同模板',
- extra: React.createElement(Button, { type: 'primary', className: 'ct-btn-cta', onClick: openCreate }, '新增标准合同')
- },
- React.createElement(Tabs, {
- className: 'ct-category-tabs',
- activeKey: categoryFilter,
- onChange: setCategoryFilter,
- type: 'card',
- items: tabItems
- })
- )
- );
- }
-
- return React.createElement(App, null,
- React.createElement('style', null, pageStyle),
- React.createElement('div', { className: 'oneos-page ct-page' },
- pageView === 'editor' ? renderEditorPage() : renderListPage(),
-
- React.createElement(Modal, {
- wrapClassName: 'oneos-modal-wrap ct-modal-wrap',
- title: '确认设为标准模板',
- open: defaultConfirmModalState[0],
- onOk: handleSetDefault,
- onCancel: function () { defaultConfirmModalState[1](false); defaultConfirmTargetState[1](null); },
- okText: '确认设置',
- cancelText: '取消'
- }, defaultConfirmTargetState[0]
- ? React.createElement('div', { style: { lineHeight: 1.6 } },
- '同一类型合同同时只能有一个标准模板。设为标准模板后,客服草拟新合同时将默认使用此版本。',
- React.createElement('div', { style: { marginTop: 12, fontSize: 13, color: '#64748B' } },
- '将「', defaultConfirmTargetState[0].versionNo, ' · ', defaultConfirmTargetState[0].versionName, '」设为本分类标准模板'
- )
- )
- : null),
-
- React.createElement(Modal, {
- wrapClassName: 'oneos-modal-wrap ct-modal-wrap',
- title: '确认删除',
- open: deleteModalState[0],
- onOk: handleDelete,
- onCancel: function () { deleteModalState[1](false); deleteTargetState[1](null); },
- okText: '删除',
- okButtonProps: { danger: true }
- }, deleteTargetState[0]
- ? React.createElement('div', null, '确定删除版本「', deleteTargetState[0].versionNo, ' · ', deleteTargetState[0].versionName, '」?删除后不可恢复。')
- : null
- ),
-
- )
- );
-};
-
-export default Component;
diff --git a/src/prototypes/oneos-web-h2-station/.spec/prototype-review.md b/src/prototypes/oneos-web-h2-station/.spec/prototype-review.md
index 29fae90..3e02351 100644
--- a/src/prototypes/oneos-web-h2-station/.spec/prototype-review.md
+++ b/src/prototypes/oneos-web-h2-station/.spec/prototype-review.md
@@ -8,11 +8,12 @@
- 菜单:`.axhub/make/sidebar-tree.json`(加氢站管理分组)
- 生成时间:2026-07-16 09:56
- 修复闭环:2026-07-16(按 Review 建议处理 P1/P2/P3)
+- 产品变更:2026-07-18 — **预约加氢已下线**(Tab / 受理 / 落账均移除);下文预约相关「已修复」条目仅作历史记录。
- 资料冲突/待确认:**部分仍有**(对账权威入口叙事,见下)
## 总体点评
-主路径(筛选 → 近 30 日统计 → 列表增删改/导出 → 已对账只读 → 与 H5 共用 Bridge)完整可演示。按评审建议已补齐:**预约带站名(全站运营)**、**接受预约落账**、**重复键拦截**、**总额偏差确认**、**孤儿页清理与对账入口文档对齐**。剩余待确认项主要为「车辆氢费明细点完成」与「站点对账单提交」两条对账叙事并存,不阻塞本页演示。
+主路径(筛选 → 近 30 日统计 → 列表增删改/导出 → 手工台账 → 已对账只读 → 与 H5 共用 Bridge)完整可演示。按评审建议已补齐:**重复键拦截**、**总额偏差确认**、**孤儿页清理与对账入口文档对齐**。剩余待确认项主要为「车辆氢费明细点完成」与「站点对账单提交」两条对账叙事并存,不阻塞本页演示。
## P0-P3 优先级问题
@@ -40,12 +41,11 @@
| 维度 | 结论 |
|------|------|
-| 核心任务 | 已覆盖:筛选、统计、CRUD、导出、预约受理并落账、重复键/总额校验 |
+| 核心任务 | 已覆盖:筛选、统计、CRUD、导出、手工台账、重复键/总额校验 |
| 菜单对齐 | 站点信息 / 加氢订单(H5) / 加氢记录 / 数量统计 — 与 sidebar 一致;本包仅承载加氢记录 |
| 资料冲突/待确认 | 对账权威入口已拍板:见 [../vehicle-h2-fee-ledger/.spec/verify-reconcile.md](../vehicle-h2-fee-ledger/.spec/verify-reconcile.md)(核对 ≠ 对账) |
## 业务逻辑连贯性
- **流水生命周期**:新增 pending →(站点对账提交)reconciled → 禁编删。
-- **预约状态机**:pending → accepted(+ 未对账流水)/ rejected;徽标随全站 pending 递减。
- **双端同步**:同会话 Bridge;重复键与总额规则 Web/H5 共用。
diff --git a/src/prototypes/oneos-web-h2-station/.spec/record-data-model.md b/src/prototypes/oneos-web-h2-station/.spec/record-data-model.md
index e0010ee..dfae84f 100644
--- a/src/prototypes/oneos-web-h2-station/.spec/record-data-model.md
+++ b/src/prototypes/oneos-web-h2-station/.spec/record-data-model.md
@@ -3,7 +3,7 @@
| 项 | 说明 |
|---|---|
| 代码路径 | UI:`pages/02-加氢记录.jsx`;Store:`src/common/h2VehicleLedgerBridge.js` |
-| 对齐模块 | H5「加氢订单」`oneos-h5-h2-order`(同一业务、同一 Store;PC 多导出 / 预约加氢) |
+| 对齐模块 | H5「加氢订单」`oneos-h5-h2-order`(同一业务、同一 Store;PC 多导出 / 手工台账) |
| 对账入口 | 菜单原型 `oneos-web-h2-station-site`(实现:`oneos-web-h2-station-site/pages/03-站点信息.jsx`) |
| 数据源 | 原型本地种子 + 内存共享 Store(**未接真实 API**) |
@@ -24,12 +24,30 @@
| 加氢总额(元) | 映射 `costTotal` / `customerAmount` |
| 核对状态 | `verifyStatus`:`unverified` / `verified`;能源部「完成核对」写入 |
| 核对时间 | `verifiedAt`;未核对应「—」 |
+| 核对人 | `verifiedByName`;完成核对手写入操作员姓名 |
| 对账状态 | `pending` / `reconciled`;**仅**站点对账单提交后变为已对账 |
| 对账时间 | **仅** `reconcileDate`(对账单回写);勿用 `reconciledAt` 判定对账 |
+| 对账人 | `reconciledByName`;对账单提交时的 `reconciler` |
+| 记录来源 | `recordSource`:`station`(站端上传)/ `lingniu`(羚牛上传) |
+| 变更日志 | `changeLogs[]`:时间、操作人、修改项、原值、新值 |
-写入 Bridge 时默认:`settlementStatus=customer`、`creatorName=站端账号`、`verifyStatus=unverified`、`reconcileStatus=pending`(与 H5 相同)。`mileageKm` 由表单选填写入,未填为 `null`。
+写入 Bridge 时默认:`settlementStatus=customer`、`creatorName=站端账号`、`recordSource=station`、`verifyStatus=unverified`、`reconcileStatus=pending`(与 H5 相同)。`mileageKm` 由表单选填写入,未填为 `null`。
-> 双状态全文:[../vehicle-h2-fee-ledger/.spec/verify-reconcile.md](../vehicle-h2-fee-ledger/.spec/verify-reconcile.md)
+> 双状态全文:[../vehicle-h2-fee-ledger/.spec/verify-reconcile.md](../vehicle-h2-fee-ledger/.spec/verify-reconcile.md)
+> 来源 / 日志 / 操作人:[record-source-changelog.md](./record-source-changelog.md)
+
+### 1.1 列表筛选(Web)
+
+交互对齐全局规范(`rules/global-design-spec.md` §4.1)与物流业务明细:`splitFilterFields` / `shouldShowFilterExpand` 拆分首行与展开区;默认 **1 行 4 项**;`vm-filter-expand` +「更多筛选 / 收起」;占位符统一 `0.875rem` / `--ln-muted-soft`。
+
+| 区域 | 条件 | 规则 |
+|---|---|---|
+| 首行 | 加氢时间 | 按 `hydrogenTime` 日期闭区间 |
+| 首行 | 车牌号 / 加氢站 | 精确匹配 |
+| 首行 | 对账状态 | 已对账 / 未对账(`hrIsReconciled`) |
+| 更多 | 核对状态 | 已核对 / 未核对(`hrIsVerified`) |
+| 更多 | 核对时间 | 按 `verifiedAt` 日期闭区间;无核对时间则不命中 |
+| 更多 | 对账时间 | 按 `reconcileTime` 或 `reconcileDate` 日期闭区间;无对账时间则不命中 |
---
@@ -47,7 +65,7 @@
|---|---|
| 共享 Bridge 不可用 | 列表用本地 fallback;保存/删除提示失败 |
| 已核对或已对账点编辑/删除 | 对应警告文案 |
-| PC 独有 | **导出**含核对/对账列;**预约加氢**接受后写入未核对流水 |
+| PC 独有 | **导出**含核对/对账列;手工台账上传(站点按角色范围;今日双态提示;右侧预览区确认上传) |
## 4. 数据流
@@ -57,11 +75,11 @@ Web / H5 新增加氢记录
→ 车辆氢费明细可见
车辆氢费明细 · 完成核对
- → verifyStatus=verified + verifiedAt
+ → verifyStatus=verified + verifiedAt + verifiedByName
→ Web / H5 同步「已核对」
站点信息 · 对账单提交(仅已核对 ∧ 未对账)
- → reconcileStatus=reconciled + reconcileDate
+ → reconcileStatus=reconciled + reconcileDate + reconciledByName
→ Web / H5 / 台账同步「已对账」
```
@@ -84,28 +102,8 @@ Web / H5 新增加氢记录
| 超过容差 | 二次确认「仍要保存」;确认后按用户填写的总额写入(不强制改回) |
| 代码 | Bridge.`totalAmountMismatch`;Web Modal / H5 `confirm` |
-## 7. 预约加氢(PC 独有 · 全站运营视角)
-
-| 字段 | 说明 |
-|---|---|
-| 加氢站名称 | `stationName`(必有);列表与接受/拒绝确认文案展示 |
-| 站点编码 | `stationCode` |
-| 车牌 / 预约时间 / 量 / 司机 / 联系方式 | 司机预约信息 |
-| 状态 | `pending` / `accepted` / `rejected` |
-| 关联流水 | 接受成功后写 `linkedRecordId`(对应加氢记录 id) |
-
-| 规则 | 说明 |
-|---|---|
-| 运营视角 | **全站运营**:顶栏「预约加氢」Tab 列出全部站点预约;靠「加氢站名称」列区分归属;列表含处理情况 |
-| 徽标 | 统计全部 `pending` 条数,不随主列表站点筛选收缩 |
-| 接受落账 | 生成 **未对账** 流水:`hydrogenTime=预约时间`,`hydrogenKg=预约量`,`unitPrice=该站近期单价`(`lookupStationUnitPrice`,缺省 42.5),总额=单价×量;`creatorName=预约受理` |
-| 拒绝 | 仅改预约状态,不写流水 |
-| 重复键 | 若同站同车牌同预约时间已有流水,**拒绝落账**并提示 |
-
-代码:`HR_INITIAL_APPOINTMENTS`、`handleAcceptAppointment`(`pages/02-加氢记录.jsx`)。
-
-## 8. 边界
+## 7. 边界
- Web 不做 OCR;录入单价×量可自动带出总额,总额仍可手改(超容差需确认)
-- 预约列表数据本地维护;落账写入共享 Store 后与 H5 / 对账单可见
- 跨页联动依赖同浏览器会话内共享 Store
+- 本期不提供「预约加氢」Tab / 受理能力
diff --git a/src/prototypes/oneos-web-h2-station/.spec/record-source-changelog.md b/src/prototypes/oneos-web-h2-station/.spec/record-source-changelog.md
new file mode 100644
index 0000000..7fbf335
--- /dev/null
+++ b/src/prototypes/oneos-web-h2-station/.spec/record-source-changelog.md
@@ -0,0 +1,95 @@
+# 加氢记录 · 来源标注 / 变更日志 / 核对人与对账人
+
+| 项 | 说明 |
+|---|---|
+| 代码路径 | Bridge:`src/common/h2VehicleLedgerBridge.js`;Web:`pages/02-加氢记录.jsx`;台账:`vehicle-h2-fee-ledger/H2LedgerPage.jsx`;H5:`oneos-h5-h2-order/utils/orders.ts` |
+| 数据源 | 原型本地种子 + 内存共享 Store(**未接真实 API**) |
+
+---
+
+## 1. 记录来源(`recordSource`)
+
+| 值 | 标签文案 | 写入场景 |
+|---|---|---|
+| `station` | **站端上传** | H5 / Web 站端新增加氢记录;`creatorName=站端账号` 或客户名含 `·站端上报` |
+| `lingniu` | **羚牛上传** | 车辆氢费明细人工新增 / 复制 / 导入 |
+
+### 判定优先级
+
+| 优先级 | 条件 | 结果 |
+|---|---|---|
+| 1 | 行上已有 `recordSource` 为 `station` / `lingniu` | 原样使用 |
+| 2 | `creatorName === '站端账号'` 或 `customerName` 含 `·站端上报` | `station` |
+| 3 | 其他 | `lingniu` |
+
+### 展示
+
+- **车辆氢费明细**:车牌号下方标签(站端=绿 / 羚牛=蓝)
+- **加氢记录 Web**:车牌号下方同口径标签
+- 导出 CSV 含「来源」列
+
+---
+
+## 2. 变更日志(`changeLogs[]`)
+
+挂在每条加氢记录上,供审计。条目字段:
+
+| 字段 | 说明 |
+|---|---|
+| `at` | 修改时间 |
+| `operatorName` / `userName` | 操作人 |
+| `fieldLabel` | 修改项(业务名) |
+| `oldValue` / `before` | 原值 |
+| `newValue` / `after` | 新值 |
+
+### 写入时机
+
+| 场景 | 规则 |
+|---|---|
+| 站端编辑(Web/H5 upsert) | Bridge 对比加氢时间/车牌/量/单价/总额/里程,有差异则追加 |
+| 车辆氢费明细字段修改 | `appendChangeLog` 同时写入行内 `changeLogs` 与本地索引 |
+| 完成核对 | 记录核对状态变化 |
+
+### 查看
+
+操作列 **更多 → 变更日志**(Web 加氢记录 / 车辆氢费明细),弹窗按时间倒序。
+
+### 前置条件
+
+- 无变更时弹窗空态「暂无变更记录」
+- 原型演示种子:`rf-13`、`rf-1` 预置各 1 条日志
+
+---
+
+## 3. 核对人 / 对账人
+
+| 字段 | 含义 | 写入时机 |
+|---|---|---|
+| `verifiedByName` | 核对人 | 车辆氢费明细「完成核对」→ 当前操作员姓名 |
+| `reconciledByName` | 对账人 | 站点信息对账单提交 patches 中的 `reconciler` |
+
+### 展示位置
+
+- **加氢记录 Web**:核对时间后「核对人」;对账时间后「对账人」
+- **车辆氢费明细**:核对状态后「核对时间」「核对人」;对账日期后「对账人」
+
+未核/未对时显示「—」。
+
+---
+
+## 4. 每日统计占用(第一屏)
+
+| 项 | 规则 |
+|---|---|
+| 默认 | **收起**:仅一行标题 + 近 30 天 KPI 胶囊 +「展开明细」 |
+| 展开 | 显示 7 日卡片轨与翻页 |
+| 目的 | 第一屏优先露出列表行 |
+
+---
+
+## 5. 验收要点
+
+1. 站端新增记录在台账/Web 显示「站端上传」;台账手增显示「羚牛上传」
+2. 编辑量/价等后,变更日志可见时间、操作人、修改项、原值、新值
+3. 完成核对后「核对人」有值;对账单提交后「对账人」有值
+4. 每日统计默认收起,展开后才占日卡片高度
diff --git a/src/prototypes/oneos-web-h2-station/.spec/requirements-prd.md b/src/prototypes/oneos-web-h2-station/.spec/requirements-prd.md
index 4dc3fc7..05fe634 100644
--- a/src/prototypes/oneos-web-h2-station/.spec/requirements-prd.md
+++ b/src/prototypes/oneos-web-h2-station/.spec/requirements-prd.md
@@ -13,7 +13,7 @@
## 1. 背景与目标
-与 H5「加氢订单」为同一业务:站端上报加氢流水。Web 供 PC 操作;H5 供移动端。数据结构、共享账本与对账规则一致。Web **额外**提供导出、预约加氢处理。
+与 H5「加氢订单」为同一业务:站端上报加氢流水。Web 供 PC 操作;H5 供移动端。数据结构、共享账本与对账规则一致。Web **额外**提供导出与手工台账上传。
### 1.0 加氢站管理菜单分工
@@ -21,22 +21,30 @@
|---|---|---|
| 站点信息 | `oneos-web-h2-station-site` | 站点主数据、对账单生成与提交回写 |
| 加氢订单 | `oneos-h5-h2-order` | 站端手机浏览器录入本站流水 |
-| 加氢记录 | **本原型** | PC 多站流水台账、导出、预约受理 |
+| 加氢记录 | **本原型** | PC 多站流水台账、导出、手工台账 |
### 1.1 功能清单
| # | 功能 | 说明 |
|---|---|---|
-| 1 | 列表 / 筛选 | 字段与 H5 一致;可按时间、车牌、站名、对账状态筛选 |
-| 2 | 手工台账 | 与 H5 同逻辑:月历标已传/未传、可补传过往日;未上传今日台账不可新增;见 [feature-manual-ledger](../oneos-h5-h2-order/.spec/feature-manual-ledger.md) |
+| 1 | 列表 / 筛选 | 字段与 H5 一致;默认一行(加氢时间/车牌/站名/对账状态);`splitFilterFields` + **更多筛选/收起**(`vm-filter-expand` / `vm-filter-toggle`)对齐物流业务明细;占位符样式见全局设计规范 §4.1.1 |
+| 2 | 手工台账 | 与 H5 同逻辑:站点按登录角色范围过滤;今日已传/未传双态提示;右侧「手工台账」预览(空态/全屏翻页/已归档角标)+ 确认前二次提示;月历补传与拦截见 [feature-manual-ledger](../oneos-h5-h2-order/.spec/feature-manual-ledger.md) |
| 3 | 新增 / 批量 / 编辑 | 字段:时间、站、车牌、**里程(选填)**、单价、量、总额;已对账只读;同站同车牌同时间拦截;总额偏离单价×量超 0.05 元需确认 |
| 4 | 删除 | 仅未对账;写共享 Store |
| 5 | 导出 | 当前筛选结果 CSV(Web 独有) |
-| 6 | 预约加氢 | 列表工具栏左上角第三个 Tab;列表展示预约信息与处理情况;**接受后自动生成未对账加氢记录** |
### 1.2 列表字段
-加氢时间、加氢站名称、车牌号、里程(km)、氢气单价(元/kg)、加氢量、加氢总额、核对状态、核对时间、对账状态、对账时间。
+加氢时间、加氢站名称、车牌号(附来源标签)、里程(km)、氢气单价(元/kg)、加氢量、加氢总额、核对状态、核对时间、核对人、对账状态、对账时间、对账人;操作含 **变更日志**。
+
+### 1.3 工具栏 Tab
+
+列表工具栏左侧为分段 Tab(对齐物流业务明细 `lbd-main-tab`):**加氢记录** / **手工台账**。
+悬浮:浅绿底 + 深色字;选中:主色浅底 + 主色字。本期不提供「预约加氢」。
+
+### 1.4 每日统计(第一屏)
+
+默认**收起**为一行 KPI 摘要 +「展开明细」,避免挤占列表;展开后才显示近 7 日卡片与翻页。规格见 [record-source-changelog.md](./record-source-changelog.md) §4。
---
@@ -44,12 +52,13 @@
1. 列表/表单字段与 H5「加氢订单」一致(含选填里程;无充装员 / 承担方式录入)
2. 与 H5 读写同一共享 Store;一端增删改后另一端可见(同会话)
-3. 已核对或已对账不可编辑、删除;**已对账记录对账时间不为空**(对账单回写);核对由车辆氢费明细「完成核对」触发
-4. 导出列与列表字段一致(含核对/对账)
-5. 列表左上角三个 Tab:加氢记录 / 手工台账 / 预约加氢;预约 Tab 列表展示预约信息与处理情况
-6. 预约徽标为全站待处理条数(全站运营视角,不随列表站点筛选收缩)
-7. 接受预约后列表出现对应未对账流水(时间/站/车牌/量与预约一致)
-8. 同站同车牌同加氢时间重复保存被拦截;总额与单价×量偏差 > 0.05 元时出现确认
+3. 筛选默认一行;更多筛选/收起对齐物流业务明细;支持核对状态、核对时间、对账状态、对账时间;占位符样式与全局规范一致
+4. 已核对或已对账不可编辑、删除;**已对账记录对账时间不为空**(对账单回写);核对由车辆氢费明细「完成核对」触发
+5. 导出列与列表字段一致(含来源、核对人、对账人)
+6. 列表左上角两个 Tab:加氢记录 / 手工台账;悬浮与选中样式符合分段 Tab 规范;无预约加氢入口
+7. 同站同车牌同加氢时间重复保存被拦截;总额与单价×量偏差 > 0.05 元时出现确认
+8. 来源标签:站端上报→「站端上传」,台账手增→「羚牛上传」;变更日志含时间/操作人/修改项/原值/新值;核对时间后有核对人、对账时间后有对账人
+9. 每日统计默认收起,第一屏以列表为主
---
@@ -57,6 +66,6 @@
| 主题 | 摘要 | 全文 |
|---|---|---|
-| 数据结构与对账 | 站端口径字段;**核对 vs 对账**双状态;PC 多导出/预约落账 | [record-data-model.md](./record-data-model.md)、[../vehicle-h2-fee-ledger/.spec/verify-reconcile.md](../vehicle-h2-fee-ledger/.spec/verify-reconcile.md) |
+| 数据结构与对账 | 站端口径字段;**核对 vs 对账**双状态;PC 多导出 | [record-data-model.md](./record-data-model.md)、[../vehicle-h2-fee-ledger/.spec/verify-reconcile.md](../vehicle-h2-fee-ledger/.spec/verify-reconcile.md) |
| 重复键 / 总额偏差 | 业务主键拦截;总额偏差二次确认 | [record-data-model.md](./record-data-model.md) §5–6 |
-| 预约接受落账 | 接受 → 未对账草稿流水 | [record-data-model.md](./record-data-model.md) §7 |
+| 来源 / 变更日志 / 操作人 | `recordSource`、行级 `changeLogs`、核对人/对账人 | [record-source-changelog.md](./record-source-changelog.md) |
diff --git a/src/prototypes/oneos-web-h2-station/.spec/ui-review.md b/src/prototypes/oneos-web-h2-station/.spec/ui-review.md
index abe8a54..88c1191 100644
--- a/src/prototypes/oneos-web-h2-station/.spec/ui-review.md
+++ b/src/prototypes/oneos-web-h2-station/.spec/ui-review.md
@@ -4,14 +4,15 @@
- 使用设计依据:`src/prototypes/vm-shared/DESIGN.md`
- 生成时间:2026-07-17 12:55
- 修复回写:2026-07-17(P0–P2 已按规范落地)
+- 产品变更:2026-07-18 — **预约加氢已下线**;工具栏仅「加氢记录 / 手工台账」两 Tab,悬浮/选中对齐物流业务明细分段 Tab。下文涉及预约的条目视为历史记录。
## 总体点评
-加氢记录页是典型中后台列表:筛选、近 30 日 KPI 轮播、三 Tab(加氢记录 / 手工台账 / 预约加氢)与明细表同屏协作,任务路径清晰。视觉上延续 emerald 主色、白卡片与 tabular-nums 数字排版,和站点信息等 OneOS Web 列表气质一致;列表工具栏左上角放 Tab、右侧放导出/新增,信息架构合理。
+加氢记录页是典型中后台列表:筛选、近 30 日 KPI 轮播、两 Tab(加氢记录 / 手工台账)与明细表同屏协作,任务路径清晰。视觉上延续 emerald 主色、白卡片与 tabular-nums 数字排版,和站点信息等 OneOS Web 列表气质一致;列表工具栏左上角放 Tab、右侧放导出/新增,信息架构合理。
-与 `vm-shared/DESIGN.md` 对照时,偏离曾集中在三条**强制规范**:底部分页、筛选日期区间、操作列。已改为 `TablePagination` / `DateRangeFilterField` / `OperationActions`,数字列去掉右对齐,预约统计卡去掉左侧色条。
+与 `vm-shared/DESIGN.md` 对照时,偏离曾集中在三条**强制规范**:底部分页、筛选日期区间、操作列。已改为 `TablePagination` / `DateRangeFilterField` / `OperationActions`,数字列去掉右对齐。
-亮点:每日统计卡片带 `aria-label`、预约待处理徽标、手工台账拦截提示可点击跳转;新增/编辑页底栏固定、主按钮约 44px。预约 Tab 列表化后比弹窗更易扫读处理情况。
+亮点:每日统计卡片带 `aria-label`、手工台账拦截提示可点击跳转;新增/编辑页底栏固定、主按钮约 44px。
## P0-P3 优先级问题
diff --git a/src/prototypes/oneos-web-h2-station/annotation-source.json b/src/prototypes/oneos-web-h2-station/annotation-source.json
index 475a169..4a33371 100644
--- a/src/prototypes/oneos-web-h2-station/annotation-source.json
+++ b/src/prototypes/oneos-web-h2-station/annotation-source.json
@@ -18,7 +18,7 @@
"fingerprint": "filter|h2-record",
"path": []
},
- "annotationText": "按加氢时间、车牌、加氢站、对账状态筛选;字段口径与 H5「加氢订单」一致。",
+ "annotationText": "默认一行四项(splitFilterFields);更多筛选/收起用 vm-filter-expand + vm-filter-toggle(对齐物流业务明细);占位符 0.875rem / --ln-muted-soft 全局统一。",
"hasMarkdown": false,
"color": "#2563EB",
"images": [],
@@ -38,7 +38,7 @@
"fingerprint": "toolbar|h2-record",
"path": []
},
- "annotationText": "有待处理预约时显示全站待处理条数。弹窗含加氢站名称(全站运营视角)。接受预约将自动生成一条未对账加氢记录(时间=预约时间、量=预约量);拒绝仅改预约状态。",
+ "annotationText": "左侧分段 Tab:加氢记录 / 手工台账(悬浮浅绿底,选中主色;对齐物流业务明细)。右侧导出、新增。",
"hasMarkdown": false,
"color": "#059669",
"images": [],
@@ -58,7 +58,7 @@
"fingerprint": "table|h2-record",
"path": []
},
- "annotationText": "列:加氢时间、站名、车牌、里程、单价、量、总额、核对状态/时间、对账状态/时间。已核对或已对账禁改删;对账仅对账单提交后出现。",
+ "annotationText": "列:加氢时间、站名、车牌(附来源:站端上传/羚牛上传)、里程、单价、量、总额、核对状态/时间/人、对账状态/时间/人。操作更多含变更日志。已核对或已对账禁改删;对账仅对账单提交后出现。",
"hasMarkdown": false,
"color": "#FF7D00",
"images": [],
@@ -79,16 +79,89 @@
"fingerprint": "daily-stats|h2-record",
"path": []
},
- "annotationText": "近30天(含今天,自今日前推):展示起止日期与加氢总量;每日卡片上方「数据条数」下分「总数 / 已核对 / 已对账」,下方为加氢量与加氢总额;随筛选结果实时汇总。",
+ "annotationText": "默认收起为一行 KPI(加氢总量 / 总额主题色 / 条数)+「展开明细」,优先保证第一屏列表可见行数;展开后显示 7 日卡片轨与翻页。每日卡以加氢量为主数字、总额为主题色,底部「记录 / 已核对 / 已对账」。随筛选实时汇总。",
"hasMarkdown": false,
"color": "#7C3AED",
"images": [],
"createdAt": 1784013600000,
- "updatedAt": 1784165900000,
+ "updatedAt": 1784345100000,
+ "controls": []
+ },
+ {
+ "id": "hr-manual-station",
+ "index": 5,
+ "title": "加氢站选择(角色范围)",
+ "pageId": "h2-record",
+ "locator": {
+ "selectors": [
+ "[data-annotation-id=\"hr-manual-station\"]"
+ ],
+ "fingerprint": "manual-station|h2-record",
+ "path": []
+ },
+ "annotationText": "选项=当前登录用户角色对应站点。单站仅 1 个且不可切换;多站可切换;超级管理员可选全部。原型未接真实登录,用下方状态切换演示。",
+ "hasMarkdown": false,
+ "color": "#0F766E",
+ "images": [],
+ "createdAt": 1784344200000,
+ "updatedAt": 1784344200000,
+ "controls": [
+ {
+ "type": "segmented",
+ "attributeId": "hr_station_scope",
+ "displayName": "登录角色站点范围",
+ "info": "演示站端人员可见站点:单站 / 多站 / 超级管理员。",
+ "initialValue": "single",
+ "options": [
+ { "label": "单站人员", "value": "single" },
+ { "label": "多站人员", "value": "multi" },
+ { "label": "超级管理员", "value": "super_admin" }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "hr-manual-today-status",
+ "index": 6,
+ "title": "今日台账状态提示",
+ "pageId": "h2-record",
+ "locator": {
+ "selectors": [
+ "[data-annotation-id=\"hr-manual-today-status\"]"
+ ],
+ "fingerprint": "manual-today-status|h2-record",
+ "path": []
+ },
+ "annotationText": "放在右侧「当日台账」卡片内。双态:异常「今日尚未上传手工台账(YYYY-MM-DD)」橙底;正常「今日已上传手工台账(YYYY-MM-DD)」绿底。随当前选中站+今日是否已传切换。",
+ "hasMarkdown": false,
+ "color": "#D97706",
+ "images": [],
+ "createdAt": 1784344200000,
+ "updatedAt": 1784344200000,
+ "controls": []
+ },
+ {
+ "id": "hr-manual-upload-panel",
+ "index": 7,
+ "title": "手工台账上传面板",
+ "pageId": "h2-record",
+ "locator": {
+ "selectors": [
+ "[data-annotation-id=\"hr-manual-upload-panel\"]"
+ ],
+ "fingerprint": "manual-upload-panel|h2-record",
+ "path": []
+ },
+ "annotationText": "标题「手工台账」。中部预览区:空态/缩略图(已归档角标);可点全屏翻页;区内可上传。底部确认前二次提示「提交后将无法修改…」;提交后立即展示已归档图。与左侧月历等高。",
+ "hasMarkdown": false,
+ "color": "#2563EB",
+ "images": [],
+ "createdAt": 1784344200000,
+ "updatedAt": 1784344200000,
"controls": []
}
],
- "updatedAt": 1784013600000
+ "updatedAt": 1784344200000
},
"markdownMap": {},
"assetMap": {}
diff --git a/src/prototypes/oneos-web-h2-station/pages/02-加氢记录.jsx b/src/prototypes/oneos-web-h2-station/pages/02-加氢记录.jsx
index b7ac5c4..15b162f 100644
--- a/src/prototypes/oneos-web-h2-station/pages/02-加氢记录.jsx
+++ b/src/prototypes/oneos-web-h2-station/pages/02-加氢记录.jsx
@@ -1,11 +1,37 @@
// 【重要】必须使用 const Component 作为组件变量名
-// 加氢站管理 - 加氢记录(与 H5 加氢订单同 Store/字段;PC 另含导出 + 预约加氢)
+// 加氢站管理 - 加氢记录(与 H5 加氢订单同 Store/字段;PC 另含导出)
import React from 'react';
+import { useProtoDevState } from '@axhub/annotation';
import { TablePagination, COMPACT_PAGE_SIZE_OPTIONS } from '../../../common/TablePagination';
import { OperationActions } from '../../../common/OperationActions';
+import {
+ splitFilterFields,
+ shouldShowFilterExpand,
+ VM_FILTER_PRIMARY_VISIBLE_COUNT,
+} from '../../../common/vm-filter-panel';
import { DateRangeFilterField } from '../../vehicle-management/components/DateRangeFilterField';
+/** 原型演示:登录角色对应站点范围(未接真实登录态) */
+var HR_STATION_SCOPE_NAMES = {
+ single: ['中国石油中油高新能源牙谷加油加氢站'],
+ multi: ['中国石油中油高新能源牙谷加油加氢站', '杭州临平加氢站'],
+ super_admin: null
+};
+
+function hrNormalizeStationScope(value) {
+ if (value === 'multi' || value === 'super_admin' || value === 'single') return value;
+ return 'single';
+}
+
+function hrFilterStationsByScope(allOptions, scope) {
+ var allowed = HR_STATION_SCOPE_NAMES[scope];
+ if (!allowed) return allOptions.slice();
+ var set = {};
+ allowed.forEach(function (name) { set[name] = true; });
+ return allOptions.filter(function (o) { return set[o.value]; });
+}
+
function hrSvgIcon(paths, size) {
return React.createElement('svg', {
viewBox: '0 0 24 24',
@@ -80,25 +106,41 @@ var HR_PAGE_STYLE = ONEOS_ANT_TABLE_GLOBAL_FIX.concat([
'.h2-station-page .h2-create-footer-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-left: auto; }',
'.h2-station-page .h2-create-footer-actions .ant-btn { min-height: 44px; padding: 0 20px; border-radius: 10px; font-weight: 600; }',
'.h2-station-page .h2-create-footer-actions .ant-btn-primary { min-width: 120px; box-shadow: 0 4px 14px -2px rgba(16, 185, 129, 0.45); }',
- '.h2-station-page .lc-filter-card.ant-card { border-radius: 16px !important; border: 1px solid #e2e8f0 !important; box-shadow: 0 4px 20px -4px rgba(15, 23, 42, 0.03) !important; margin-bottom: 16px; }',
+ '.h2-station-page .lc-filter-card.ant-card { border-radius: 16px !important; border: 1px solid #e2e8f0 !important; box-shadow: 0 4px 20px -4px rgba(15, 23, 42, 0.03) !important; margin-bottom: 16px; overflow: visible !important; }',
'.h2-station-page .lc-filter-card > .ant-card-head { border-bottom: 1px solid #f1f5f9 !important; min-height: auto; padding: 12px 20px !important; }',
'.h2-station-page .lc-filter-card > .ant-card-head .ant-card-head-title { font-size: 15px !important; font-weight: 700 !important; color: #0f172a !important; padding: 0 !important; }',
- '.h2-station-page .lc-filter-card > .ant-card-body { padding: 16px 20px 20px !important; }',
- '.h2-station-page .lc-filter-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px 24px; align-items: center; }',
+ '.h2-station-page .lc-filter-card > .ant-card-body { padding: 16px 20px 20px !important; overflow: visible !important; }',
+ '.h2-station-page .lc-filter-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px 24px; align-items: center; overflow: visible; }',
'@media (max-width: 1280px) { .h2-station-page .lc-filter-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }',
'@media (max-width: 640px) { .h2-station-page .lc-filter-grid { grid-template-columns: 1fr; } }',
- '.h2-station-page .lc-filter-field { display: flex; align-items: center; gap: 12px; min-width: 0; min-height: 32px; }',
+ '.h2-station-page .lc-filter-field { display: flex; align-items: center; gap: 12px; min-width: 0; min-height: 32px; overflow: visible; }',
'.h2-station-page .lc-filter-field-label { flex: 0 0 88px; text-align: right; font-size: 13px; font-weight: 500; color: #475569; line-height: 32px; white-space: nowrap; }',
- '.h2-station-page .lc-filter-field-control { flex: 1; min-width: 0; }',
- '.h2-station-page .lc-filter-field-control .ant-input, .h2-station-page .lc-filter-field-control .ant-input-affix-wrapper, .h2-station-page .lc-filter-field-control .ant-select .ant-select-selector, .h2-station-page .lc-filter-field-control .ant-picker, .h2-station-page .lc-filter-field-control .ant-picker-range { width: 100%; height: 32px !important; min-height: 32px !important; border-radius: 8px !important; box-sizing: border-box; }',
+ '.h2-station-page .lc-filter-field-control { flex: 1; min-width: 0; overflow: visible; position: relative; }',
+ '.h2-station-page .lc-filter-field-control .ant-input, .h2-station-page .lc-filter-field-control .ant-input-affix-wrapper, .h2-station-page .lc-filter-field-control .ant-select .ant-select-selector, .h2-station-page .lc-filter-field-control .ant-picker, .h2-station-page .lc-filter-field-control .ant-picker-range, .h2-station-page .lc-filter-field-control .vm-filter-picker-control { width: 100%; height: 32px !important; min-height: 32px !important; border-radius: 8px !important; box-sizing: border-box; }',
+ '.h2-station-page .lc-filter-field-control .vm-date-range-field, .h2-station-page .lc-filter-field-control .vm-filter-picker-field { width: 100%; display: block; }',
'.h2-station-page .lc-filter-field-control .ant-input-affix-wrapper { display: inline-flex; align-items: center; padding-top: 0 !important; padding-bottom: 0 !important; }',
+ '.h2-station-page .lc-filter-field-control .ant-select { width: 100%; }',
'.h2-station-page .lc-filter-field-control .ant-select-single .ant-select-selector { display: flex; align-items: center; }',
- '.h2-station-page .lc-filter-field-control .ant-select-single .ant-select-selector .ant-select-selection-item, .h2-station-page .lc-filter-field-control .ant-select-single .ant-select-selector .ant-select-selection-placeholder { line-height: 30px !important; }',
- '.h2-station-page .lc-filter-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; padding-top: 16px; border-top: 1px solid #f1f5f9; }',
+ '.h2-station-page .lc-filter-field-control .ant-select-single .ant-select-selector .ant-select-selection-item, .h2-station-page .lc-filter-field-control .ant-select-single .ant-select-selector .ant-select-selection-placeholder { line-height: 30px !important; font-family: var(--vm-font); font-size: 0.875rem !important; font-weight: 400; }',
+ '.h2-station-page .lc-filter-field-control .ant-select-selection-placeholder { color: var(--ln-muted-soft) !important; opacity: 1 !important; }',
+ '.h2-station-page .lc-filter-body { display: flex; flex-direction: column; gap: 0; overflow: visible; }',
+ '.h2-station-page .lc-filter-actions { display: flex; justify-content: flex-end; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 16px; padding-top: 16px; border-top: 1px solid #f1f5f9; }',
+ '.h2-station-page .lc-filter-actions .vm-filter-toggle { margin-right: auto; }',
'.h2-station-page .lc-table-section { margin-bottom: 0; flex: 1; display: flex; flex-direction: column; min-height: 0; }',
'.h2-station-page .lc-table-toolbar { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px 16px; margin-bottom: 8px; min-height: 32px; overflow: visible; }',
'.h2-station-page .lc-table-toolbar-left { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; overflow: visible; padding-top: 4px; }',
'.h2-station-page .lc-table-toolbar-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-left: auto; }',
+ '.h2-station-page .hr-main-tabs { display: flex; gap: 4px; padding: 4px; border-radius: var(--ln-radius-control, 8px); border: 1px solid var(--ln-hairline, #e5e7eb); background: var(--ln-surface-card, #fff); width: fit-content; max-width: 100%; flex-wrap: wrap; flex-shrink: 0; }',
+ '.h2-station-page .hr-main-tab { appearance: none; border: none; background: transparent; color: var(--ln-muted, #71717a); font-family: var(--vm-font, inherit); font-size: 0.875rem; font-weight: 500; padding: 8px 14px; border-radius: calc(var(--ln-radius-control, 8px) - 2px); cursor: pointer; transition: background 0.15s ease, color 0.15s ease; line-height: 1.25; }',
+ '.h2-station-page .hr-main-tab:hover { background: color-mix(in srgb, var(--ln-primary, #32a06e) 8%, transparent); color: var(--ln-ink, #18181b); }',
+ '.h2-station-page .hr-main-tab:focus-visible { outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, var(--ln-primary, #32a06e) 35%, transparent); }',
+ '.h2-station-page .hr-main-tab.is-active { background: color-mix(in srgb, var(--ln-primary, #32a06e) 12%, var(--ln-surface-card, #fff)); color: var(--ln-primary, #32a06e); box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06); }',
+ '.h2-station-page .hr-main-tab.is-active:hover { background: color-mix(in srgb, var(--ln-primary, #32a06e) 16%, var(--ln-surface-card, #fff)); color: var(--ln-primary, #32a06e); }',
+ '@media (prefers-reduced-motion: reduce) { .h2-station-page .hr-main-tab { transition: none; } }',
+ '.h2-station-page .hr-card-title-with-help { display: inline-flex; align-items: center; gap: 6px; }',
+ '.h2-station-page .hr-help-tip { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; color: #94a3b8; cursor: help; border-radius: 999px; line-height: 0; flex-shrink: 0; }',
+ '.h2-station-page .hr-help-tip:hover { color: var(--ln-primary, #32a06e); background: color-mix(in srgb, var(--ln-primary, #32a06e) 8%, transparent); }',
+ '.h2-station-page .hr-help-tip:focus-visible { outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, var(--ln-primary, #32a06e) 35%, transparent); color: var(--ln-primary, #32a06e); }',
'.h2-station-page .lc-table-card { background: #fff; border-radius: 16px; border: 1px solid #e2e8f0; box-shadow: 0 4px 20px -4px rgba(15, 23, 42, 0.03); overflow: hidden; flex: 1; overflow-y: auto; display: flex; flex-direction: column; }',
'.h2-station-page .lc-list-table .ant-table-wrapper, .h2-station-page .lc-list-table .ant-table { width: 100% !important; }',
'.h2-station-page .lc-table-card .ant-table-thead > tr > th { background: #f8fafc !important; color: #475569 !important; font-weight: 700 !important; font-size: 13px !important; border-bottom: 1px solid #e2e8f0 !important; padding: 12px 16px !important; }',
@@ -109,18 +151,12 @@ var HR_PAGE_STYLE = ONEOS_ANT_TABLE_GLOBAL_FIX.concat([
'.h2-station-page .lc-action-btn { font-weight: 600 !important; color: #10b981 !important; padding: 0 !important; }',
'.h2-station-page .lc-action-btn-danger { color: #ef4444 !important; }',
'/* 数字字体:对齐租赁业务明细「项目盈亏情况」tabular-nums + JetBrains Mono */',
- '.h2-station-page .hr-num, .h2-station-page .hr-refuel-plate, .h2-station-page .hr-refuel-kg, .h2-station-page .hr-refuel-money, .h2-station-page .hr-refuel-time, .h2-station-page .hr-daily-stat-card__value, .h2-station-page .hr-daily-stats-head__meta, .h2-refuel-drill-modal .h2-refuel-drill-stat__value, .h2-refuel-drill-modal .h2-refuel-drill-kg, .h2-refuel-drill-modal .h2-refuel-drill-time, .h2-refuel-drill-modal .h2-refuel-drill-plate, .h2-refuel-drill-modal .h2-refuel-drill-contact, .h2-refuel-drill-modal .h2-refuel-drill-table-head__count, .h2-refuel-drill-modal .h2-refuel-drill-station-card__meta, .h2-station-page .hr-appointment-contact, .h2-station-page .hr-appointment-badge-wrap .ant-badge-count { font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }',
+ '.h2-station-page .hr-num, .h2-station-page .hr-refuel-plate, .h2-station-page .hr-refuel-kg, .h2-station-page .hr-refuel-money, .h2-station-page .hr-refuel-time, .h2-station-page .hr-daily-stat-card__value, .h2-station-page .hr-daily-stats-head__meta, .h2-refuel-drill-modal .h2-refuel-drill-stat__value, .h2-refuel-drill-modal .h2-refuel-drill-kg, .h2-refuel-drill-modal .h2-refuel-drill-time, .h2-refuel-drill-modal .h2-refuel-drill-plate, .h2-refuel-drill-modal .h2-refuel-drill-contact, .h2-refuel-drill-modal .h2-refuel-drill-table-head__count, .h2-refuel-drill-modal .h2-refuel-drill-station-card__meta { font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }',
'.h2-station-page .hr-refuel-plate { font-weight: 700; color: #0f172a; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }',
- '.h2-station-page .hr-refuel-kg { font-weight: 700; color: #059669; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }',
- '.h2-station-page .hr-refuel-money { font-weight: 600; color: #4f46e5; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }',
+ '.h2-station-page .hr-refuel-kg { font-weight: 500; color: #334155; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }',
+ '.h2-station-page .hr-refuel-money { font-weight: 700; color: var(--ln-primary, #32a06e); font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }',
'.h2-station-page .hr-refuel-km { font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; color: #334155; }',
'.h2-station-page .hr-refuel-time { font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; color: #334155; font-size: 13px; white-space: nowrap; }',
- '.h2-station-page .hr-appointment-driver { font-weight: 600; color: #0f172a; }',
- '.h2-station-page .hr-appointment-contact { font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; color: #475569; }',
- '.h2-station-page .hr-appointment-reject-reason { font-size: 12px; color: #94a3b8; margin-top: 4px; max-width: 220px; }',
- '.h2-station-page .hr-appointment-badge-wrap { display: inline-flex; position: relative; overflow: visible; }',
- '.h2-station-page .hr-appointment-badge-wrap .ant-badge { overflow: visible; }',
- '.h2-station-page .hr-appointment-badge-wrap .ant-badge-count { box-shadow: 0 0 0 1px #fff; font-weight: 700; }',
'.h2-station-page .h2-refuel-drill-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }',
'@media (max-width: 860px) { .h2-station-page .h2-refuel-drill-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }',
'@media (max-width: 520px) { .h2-station-page .h2-refuel-drill-stats { grid-template-columns: 1fr; } }',
@@ -174,42 +210,131 @@ var HR_PAGE_STYLE = ONEOS_ANT_TABLE_GLOBAL_FIX.concat([
'.h2-refuel-drill-modal .h2-refuel-record-table .h2-refuel-drill-kg { font-weight: 700; color: #059669; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }',
'.h2-refuel-drill-modal .h2-refuel-record-table .h2-refuel-drill-contact { font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; color: #475569; font-size: 13px; }',
'.h2-refuel-drill-modal .h2-refuel-record-table .h2-refuel-drill-driver { font-weight: 600; color: #0f172a; }',
- '.h2-refuel-drill-modal .h2-refuel-record-table .hr-appointment-reject-reason { font-size: 12px; color: #94a3b8; margin-top: 4px; max-width: 220px; }',
- '.h2-station-page .hr-daily-stats-section { margin-bottom: 16px; }',
- '.h2-station-page .hr-daily-stats-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }',
- '.h2-station-page .hr-daily-stats-head__title { font-size: 15px; font-weight: 700; color: #0f172a; }',
- '.h2-station-page .hr-daily-stats-head__meta { font-size: 12px; color: #64748b; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }',
- '.h2-station-page .hr-daily-stats-carousel { display: flex; align-items: stretch; gap: 8px; }',
- '.h2-station-page .hr-daily-stats-nav-btn { flex: 0 0 36px; width: 36px !important; min-width: 36px !important; height: auto !important; min-height: 132px !important; padding: 0 !important; border-radius: 10px !important; font-size: 20px !important; font-weight: 700 !important; color: #475569 !important; border: 1px solid #e2e8f0 !important; background: #fff !important; display: inline-flex !important; align-items: center !important; justify-content: center !important; box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06); }',
+ '.h2-station-page .hr-daily-stats-section { margin-bottom: 10px; padding: 8px 12px; border-radius: 12px; border: 1px solid #e2e8f0; background: #fff; box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04); }',
+ '.h2-station-page .hr-daily-stats-section.is-expanded { padding: 12px; margin-bottom: 12px; }',
+ '.h2-station-page .hr-daily-stats-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 0; }',
+ '.h2-station-page .hr-daily-stats-section.is-expanded .hr-daily-stats-head { margin-bottom: 10px; align-items: flex-start; }',
+ '.h2-station-page .hr-daily-stats-head__left { display: flex; flex-direction: row; align-items: center; gap: 10px; min-width: 0; flex: 1; flex-wrap: wrap; }',
+ '.h2-station-page .hr-daily-stats-section.is-expanded .hr-daily-stats-head__left { flex-direction: column; align-items: flex-start; gap: 8px; }',
+ '.h2-station-page .hr-daily-stats-head__title-row { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }',
+ '.h2-station-page .hr-daily-stats-head__title { font-size: 13px; font-weight: 700; color: #0f172a; }',
+ '.h2-station-page .hr-daily-stats-head__range { font-size: 11px; color: #64748b; font-variant-numeric: tabular-nums; }',
+ '.h2-station-page .hr-daily-stats-kpis { display: flex; flex-wrap: wrap; gap: 6px; }',
+ '.h2-station-page .hr-daily-stats-kpi { display: inline-flex; align-items: baseline; gap: 4px; padding: 2px 8px; border-radius: 999px; background: #f8fafc; border: 1px solid #e2e8f0; min-height: 24px; }',
+ '.h2-station-page .hr-daily-stats-kpi__label { font-size: 11px; font-weight: 600; color: #64748b; }',
+ '.h2-station-page .hr-daily-stats-kpi__value { font-size: 12px; font-weight: 700; color: #0f172a; font-variant-numeric: tabular-nums; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); }',
+ '.h2-station-page .hr-daily-stats-kpi--primary { background: #ecfdf5; border-color: #a7f3d0; }',
+ '.h2-station-page .hr-daily-stats-kpi--primary .hr-daily-stats-kpi__value { color: var(--ln-primary, #32a06e); }',
+ '.h2-station-page .hr-daily-stats-head__right { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; }',
+ '.h2-station-page .hr-daily-stats-toggle { height: 28px !important; padding: 0 10px !important; border-radius: 8px !important; font-size: 12px !important; font-weight: 600 !important; color: #475569 !important; border: 1px solid #e2e8f0 !important; background: #fff !important; cursor: pointer; min-height: 28px; }',
+ '.h2-station-page .hr-daily-stats-toggle:hover { color: #059669 !important; border-color: #10b981 !important; background: #f0fdf4 !important; }',
+ '.h2-station-page .hr-daily-stats-toggle:focus-visible { outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, #32a06e 35%, transparent); }',
+ '.h2-station-page .hr-daily-stats-pager { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; }',
+ '.h2-station-page .hr-daily-stats-pager__label { font-size: 11px; font-weight: 600; color: #64748b; font-variant-numeric: tabular-nums; min-width: 40px; text-align: center; }',
+ '.h2-station-page .hr-daily-stats-nav-btn { width: 28px !important; min-width: 28px !important; height: 28px !important; padding: 0 !important; border-radius: 8px !important; font-size: 16px !important; font-weight: 700 !important; color: #475569 !important; border: 1px solid #e2e8f0 !important; background: #fff !important; display: inline-flex !important; align-items: center !important; justify-content: center !important; cursor: pointer; }',
'.h2-station-page .hr-daily-stats-nav-btn:hover:not(:disabled) { color: #059669 !important; border-color: #10b981 !important; background: #f0fdf4 !important; }',
- '.h2-station-page .hr-daily-stats-nav-btn:disabled { opacity: 0.35; cursor: not-allowed; box-shadow: none; }',
- '.h2-station-page .hr-daily-stats-track { flex: 1; min-width: 0; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px; }',
- '.h2-station-page .hr-daily-stat-card { display: flex; flex-direction: column; gap: 8px; min-height: 132px; padding: 12px 10px; border-radius: 12px; border: 1px solid #e2e8f0; background: #fff; box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06); box-sizing: border-box; min-width: 0; }',
- '.h2-station-page .hr-daily-stat-card--today { border-color: #86efac; background: linear-gradient(180deg, #fff 0%, #f0fdf4 100%); box-shadow: 0 2px 8px rgba(16, 185, 129, 0.12); }',
- '.h2-station-page .hr-daily-stat-card__date { font-size: 12px; font-weight: 700; color: #0f172a; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; padding-bottom: 8px; border-bottom: 1px solid #f1f5f9; display: flex; align-items: center; justify-content: space-between; gap: 4px; }',
- '.h2-station-page .hr-daily-stat-card__today-tag { font-size: 10px; font-weight: 700; color: #059669; background: #ecfdf5; padding: 1px 6px; border-radius: 999px; flex-shrink: 0; }',
- '.h2-station-page .hr-daily-stat-card__metrics { display: flex; flex-direction: column; gap: 8px; }',
- '.h2-station-page .hr-daily-stat-card__count-block { display: flex; flex-direction: column; gap: 4px; min-width: 0; }',
- '.h2-station-page .hr-daily-stat-card__count-title { color: #64748b; font-weight: 600; font-size: 11px; line-height: 1.3; }',
- '.h2-station-page .hr-daily-stat-card__count-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; }',
- '.h2-station-page .hr-daily-stat-card__count-item { display: flex; flex-direction: column; gap: 2px; min-width: 0; }',
- '.h2-station-page .hr-daily-stat-card__count-item-label { color: #94a3b8; font-weight: 600; font-size: 10px; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }',
- '.h2-station-page .hr-daily-stat-card__metrics-bottom { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; }',
- '.h2-station-page .hr-daily-stat-card__metric { display: flex; flex-direction: column; gap: 2px; min-width: 0; }',
- '.h2-station-page .hr-daily-stat-card__label { color: #64748b; font-weight: 600; font-size: 11px; line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }',
- '.h2-station-page .hr-daily-stat-card__value { font-weight: 800; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; font-size: 13px; line-height: 1.2; }',
- '.h2-station-page .hr-daily-stat-card__value--count { color: #2563eb; }',
- '.h2-station-page .hr-daily-stat-card__value--verified { color: #7c3aed; }',
- '.h2-station-page .hr-daily-stat-card__value--reconciled { color: #0f766e; }',
- '.h2-station-page .hr-daily-stat-card__value--kg { color: #059669; }',
- '.h2-station-page .hr-daily-stat-card__value--amount { color: #d97706; }',
+ '.h2-station-page .hr-daily-stats-nav-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, #32a06e 35%, transparent); }',
+ '.h2-station-page .hr-daily-stats-nav-btn:disabled { opacity: 0.35; cursor: not-allowed; }',
+ '.h2-station-page .hr-daily-stats-track { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px; }',
+ '.h2-station-page .hr-source-tag { margin: 0; border-radius: 4px; font-size: 11px; line-height: 18px; padding: 0 6px; font-weight: 600; }',
+ '.h2-station-page .hr-plate-cell { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }',
+ '@media (max-width: 1200px) { .h2-station-page .hr-daily-stats-track { grid-template-columns: repeat(4, minmax(0, 1fr)); } }',
+ '@media (max-width: 720px) { .h2-station-page .hr-daily-stats-track { grid-template-columns: repeat(2, minmax(0, 1fr)); } }',
+ '@media (prefers-reduced-motion: reduce) { .h2-station-page .hr-daily-stats-section * { transition: none !important; } }',
+ '.h2-station-page .hr-daily-stat-card { display: flex; flex-direction: column; gap: 8px; min-height: 132px; padding: 10px; border-radius: 12px; border: 1px solid #e2e8f0; background: linear-gradient(180deg, #fff 0%, #fafbfc 100%); box-sizing: border-box; min-width: 0; transition: border-color 0.15s ease, box-shadow 0.15s ease; }',
+ '.h2-station-page .hr-daily-stat-card:hover { border-color: #cbd5e1; box-shadow: 0 6px 16px -10px rgba(15, 23, 42, 0.18); }',
+ '.h2-station-page .hr-daily-stat-card--today { border-color: #86efac; background: linear-gradient(180deg, #fff 0%, #f0fdf4 100%); box-shadow: 0 2px 10px rgba(16, 185, 129, 0.12); }',
+ '.h2-station-page .hr-daily-stat-card--empty { opacity: 0.72; }',
+ '.h2-station-page .hr-daily-stat-card__date { display: flex; align-items: center; justify-content: space-between; gap: 6px; }',
+ '.h2-station-page .hr-daily-stat-card__date-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }',
+ '.h2-station-page .hr-daily-stat-card__date-num { font-size: 14px; font-weight: 700; color: #0f172a; font-variant-numeric: tabular-nums; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); }',
+ '.h2-station-page .hr-daily-stat-card__weekday { font-size: 11px; font-weight: 600; color: #94a3b8; }',
+ '.h2-station-page .hr-daily-stat-card__today-tag { font-size: 10px; font-weight: 700; color: #059669; background: #ecfdf5; padding: 2px 8px; border-radius: 999px; flex-shrink: 0; border: 1px solid #a7f3d0; }',
+ '.h2-station-page .hr-daily-stat-card__hero { display: flex; flex-direction: column; gap: 2px; padding: 8px 0 2px; }',
+ '.h2-station-page .hr-daily-stat-card__hero-label { font-size: 11px; font-weight: 600; color: #64748b; }',
+ '.h2-station-page .hr-daily-stat-card__hero-value { font-size: 18px; font-weight: 800; color: #0f172a; line-height: 1.15; font-variant-numeric: tabular-nums; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); }',
+ '.h2-station-page .hr-daily-stat-card__hero-value.is-empty { color: #94a3b8; font-weight: 700; }',
+ '.h2-station-page .hr-daily-stat-card__hero-unit { font-size: 12px; font-weight: 600; color: #94a3b8; margin-left: 4px; }',
+ '.h2-station-page .hr-daily-stat-card__amount { font-size: 14px; font-weight: 700; color: var(--ln-primary, #32a06e); font-variant-numeric: tabular-nums; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); }',
+ '.h2-station-page .hr-daily-stat-card__amount.is-empty { color: #94a3b8; font-weight: 600; }',
+ '.h2-station-page .hr-daily-stat-card__footer { margin-top: auto; padding-top: 10px; border-top: 1px solid #f1f5f9; }',
+ '.h2-station-page .hr-daily-stat-card__status-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }',
+ '.h2-station-page .hr-daily-stat-card__status-item { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px 4px; border-radius: 10px; background: #f8fafc; border: 1px solid #f1f5f9; min-width: 0; text-align: center; }',
+ '.h2-station-page .hr-daily-stat-card__status-label { font-size: 11px; font-weight: 600; color: #64748b; line-height: 1.2; white-space: nowrap; }',
+ '.h2-station-page .hr-daily-stat-card__status-value { font-size: 14px; font-weight: 700; color: #0f172a; line-height: 1.2; font-variant-numeric: tabular-nums; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); }',
+ '.h2-station-page .hr-daily-stat-card__status-item.is-muted .hr-daily-stat-card__status-value { color: #94a3b8; }',
+ '.h2-station-page .hr-daily-stat-card__status-item.is-ok { background: #ecfdf5; border-color: #d1fae5; }',
+ '.h2-station-page .hr-daily-stat-card__status-item.is-ok .hr-daily-stat-card__status-value { color: #047857; }',
+ '@media (prefers-reduced-motion: reduce) { .h2-station-page .hr-daily-stat-card { transition: none; } }',
'.h2-station-page--create .hr-batch-create-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }',
'.h2-station-page--create .hr-batch-create-toolbar__count { font-size: 13px; color: #64748b; font-family: var(--vm-font-mono, ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }',
'.h2-station-page--create .hr-batch-create-table-wrap { background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden; box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04); }',
'.h2-station-page--create .hr-batch-create-table .ant-table-thead > tr > th { background: #f8fafc !important; font-size: 12px !important; font-weight: 700 !important; color: #475569 !important; padding: 10px 12px !important; }',
'.h2-station-page--create .hr-batch-create-table .ant-table-tbody > tr > td { padding: 8px 10px !important; vertical-align: middle !important; }',
'.h2-station-page--create .hr-batch-create-table .ant-input, .h2-station-page--create .hr-batch-create-table .ant-input-number, .h2-station-page--create .hr-batch-create-table .ant-select .ant-select-selector, .h2-station-page--create .hr-batch-create-table .ant-picker { border-radius: 8px !important; font-size: 13px !important; }',
- '.h2-station-page--create .hr-batch-create-seq { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; height: 24px; border-radius: 6px; background: #f1f5f9; color: #64748b; font-size: 12px; font-weight: 700; }'
+ '.h2-station-page--create .hr-batch-create-seq { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; height: 24px; border-radius: 6px; background: #f1f5f9; color: #64748b; font-size: 12px; font-weight: 700; }',
+ '.h2-station-page .hr-manual-toolbar { margin-bottom: 16px; max-width: 480px; }',
+ '.h2-station-page .hr-manual-station-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }',
+ '.h2-station-page .hr-manual-station-field__label { font-size: 12px; font-weight: 600; color: #64748b; letter-spacing: 0.02em; }',
+ '.h2-station-page .hr-manual-status { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 12px; font-weight: 600; font-size: 13px; line-height: 1.4; min-height: 44px; box-sizing: border-box; margin: 10px 0 0; }',
+ '.h2-station-page .hr-manual-status.is-ok { background: linear-gradient(135deg, #ecfdf5 0%, #f0fdf4 100%); border: 1px solid #a7f3d0; color: #047857; }',
+ '.h2-station-page .hr-manual-status.is-warn { background: linear-gradient(135deg, #fff7ed 0%, #fffbeb 100%); border: 1px solid #fed7aa; color: #c2410c; }',
+ '.h2-station-page .hr-manual-status__icon { flex-shrink: 0; width: 28px; height: 28px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; }',
+ '.h2-station-page .hr-manual-status.is-ok .hr-manual-status__icon { background: rgba(16, 185, 129, 0.15); color: #059669; }',
+ '.h2-station-page .hr-manual-status.is-warn .hr-manual-status__icon { background: rgba(251, 146, 60, 0.18); color: #ea580c; }',
+ '.h2-station-page .hr-manual-split { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: stretch; }',
+ '@media (max-width: 1100px) { .h2-station-page .hr-manual-split { grid-template-columns: 1fr; } }',
+ '.h2-station-page .hr-manual-side { min-width: 0; display: flex; }',
+ '.h2-station-page .hr-manual-side-card { display: flex; flex-direction: column; width: 100%; border: 1px solid #e2e8f0; border-radius: 16px; padding: 18px; background: #fff; min-height: 480px; box-sizing: border-box; box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px -12px rgba(15, 23, 42, 0.08); }',
+ '.h2-station-page .hr-manual-side-card__eyebrow { font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: #94a3b8; margin-bottom: 4px; }',
+ '.h2-station-page .hr-manual-cal-nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; gap: 8px; }',
+ '.h2-station-page .hr-manual-cal-nav__title { font-size: 16px; font-weight: 700; color: #0f172a; font-variant-numeric: tabular-nums; }',
+ '.h2-station-page .hr-manual-cal-nav .ant-btn { width: 36px; height: 36px; min-width: 36px; padding: 0; border-radius: 10px; color: #475569; border: 1px solid #e2e8f0; background: #f8fafc; cursor: pointer; }',
+ '.h2-station-page .hr-manual-cal-nav .ant-btn:hover { color: #059669; border-color: #a7f3d0; background: #ecfdf5; }',
+ '.h2-station-page .hr-manual-cal-summary { font-size: 13px; color: #64748b; margin-bottom: 14px; line-height: 1.5; padding: 10px 12px; border-radius: 10px; background: #f8fafc; border: 1px solid #f1f5f9; }',
+ '.h2-station-page .hr-manual-cal-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; margin-bottom: 6px; text-align: center; font-size: 12px; color: #94a3b8; font-weight: 600; }',
+ '.h2-station-page .hr-manual-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; flex: 1; }',
+ '.h2-station-page .hr-manual-cal-day { appearance: none; border: 1px solid transparent; border-radius: 10px; background: #fff; color: #0f172a; cursor: pointer; padding: 8px 0 6px; min-height: 48px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; font-weight: 500; font-variant-numeric: tabular-nums; transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease; }',
+ '.h2-station-page .hr-manual-cal-day:hover:not(:disabled) { background: #f0fdf4; border-color: #bbf7d0; }',
+ '.h2-station-page .hr-manual-cal-day:focus-visible { outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, #32a06e 35%, transparent); }',
+ '.h2-station-page .hr-manual-cal-day.is-out { color: #cbd5e1; }',
+ '.h2-station-page .hr-manual-cal-day.is-future { color: #cbd5e1; background: #f8fafc; cursor: not-allowed; }',
+ '.h2-station-page .hr-manual-cal-day.is-uploaded { background: #ecfdf5; color: #047857; }',
+ '.h2-station-page .hr-manual-cal-day.is-missing { background: #fff7ed; color: #c2410c; }',
+ '.h2-station-page .hr-manual-cal-day.is-idle { background: #f8fafc; color: #94a3b8; }',
+ '.h2-station-page .hr-manual-cal-day.is-today { box-shadow: inset 0 0 0 1px #34d399; }',
+ '.h2-station-page .hr-manual-cal-day.is-selected { border: 2px solid #059669; font-weight: 700; box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.12); }',
+ '.h2-station-page .hr-manual-cal-dot { display: block; width: 6px; height: 6px; border-radius: 50%; background: #fb923c; }',
+ '.h2-station-page .hr-manual-cal-dot.is-on { background: #10b981; }',
+ '.h2-station-page .hr-manual-cal-legend { display: flex; gap: 16px; margin-top: 14px; font-size: 12px; color: #64748b; }',
+ '.h2-station-page .hr-manual-cal-legend i { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; vertical-align: middle; }',
+ '.h2-station-page .hr-manual-panel-head { margin-bottom: 14px; flex-shrink: 0; }',
+ '.h2-station-page .hr-manual-panel-title { margin: 0; font-size: 17px; font-weight: 700; color: #0f172a; }',
+ '.h2-station-page .hr-manual-panel-sub { margin: 6px 0 0; font-size: 13px; color: #64748b; line-height: 1.55; }',
+ '.h2-station-page .hr-manual-panel-meta { display: inline-flex; align-items: center; gap: 6px; margin-top: 8px; padding: 4px 10px; border-radius: 999px; background: #f1f5f9; color: #475569; font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }',
+ '.h2-station-page .hr-manual-preview { flex: 1; min-height: 260px; border: 1px solid #e2e8f0; border-radius: 14px; background: linear-gradient(180deg, #f8fafc 0%, #fff 48%); padding: 14px; display: flex; flex-direction: column; gap: 12px; box-sizing: border-box; }',
+ '.h2-station-page .hr-manual-preview-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; text-align: center; color: #94a3b8; padding: 28px 16px; }',
+ '.h2-station-page .hr-manual-preview-empty__icon { width: 56px; height: 56px; border-radius: 16px; background: #ecfdf5; color: #059669; display: inline-flex; align-items: center; justify-content: center; }',
+ '.h2-station-page .hr-manual-preview-empty__title { font-size: 15px; font-weight: 700; color: #475569; }',
+ '.h2-station-page .hr-manual-preview-empty__desc { font-size: 13px; line-height: 1.55; max-width: 280px; color: #94a3b8; }',
+ '.h2-station-page .hr-manual-preview-grid { display: flex; flex-wrap: wrap; gap: 12px; align-content: flex-start; flex: 1; }',
+ '.h2-station-page .hr-manual-thumb { width: 120px; border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden; background: #fff; position: relative; box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04); transition: transform 0.15s ease, box-shadow 0.15s ease; }',
+ '.h2-station-page .hr-manual-thumb:hover { transform: translateY(-1px); box-shadow: 0 6px 16px -8px rgba(15, 23, 42, 0.18); }',
+ '.h2-station-page .hr-manual-thumb .ant-image { display: block; cursor: zoom-in; width: 100%; }',
+ '.h2-station-page .hr-manual-thumb .ant-image-img { width: 120px !important; height: 90px !important; object-fit: cover; }',
+ '.h2-station-page .hr-manual-thumb__ph { width: 120px; height: 90px; display: flex; align-items: center; justify-content: center; color: #94a3b8; font-size: 12px; font-weight: 600; background: #f1f5f9; }',
+ '.h2-station-page .hr-manual-thumb__badge { position: absolute; top: 6px; left: 6px; z-index: 1; padding: 2px 8px; border-radius: 999px; background: rgba(15, 23, 42, 0.72); color: #fff; font-size: 11px; font-weight: 700; pointer-events: none; backdrop-filter: blur(4px); }',
+ '.h2-station-page .hr-manual-thumb__badge.is-draft { background: rgba(37, 99, 235, 0.85); }',
+ '.h2-station-page .hr-manual-thumb__actions { display: flex; justify-content: center; background: #f8fafc; border-top: 1px solid #f1f5f9; min-height: 30px; }',
+ '.h2-station-page .hr-manual-upload-tile { width: 120px; height: 120px; border: 1px dashed #94a3b8; border-radius: 12px; background: #fff; color: #475569; display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; cursor: pointer; font-size: 12px; font-weight: 600; transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease; }',
+ '.h2-station-page .hr-manual-upload-tile:hover { border-color: var(--ln-primary, #32a06e); color: var(--ln-primary, #32a06e); background: color-mix(in srgb, var(--ln-primary, #32a06e) 6%, #fff); }',
+ '.h2-station-page .hr-manual-upload-tile:focus-visible { outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, #32a06e 35%, transparent); }',
+ '.h2-station-page .hr-manual-upload-tile.is-disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; }',
+ '.h2-station-page .hr-manual-upload-tile__plus { width: 28px; height: 28px; border-radius: 999px; border: 1px solid currentColor; display: inline-flex; align-items: center; justify-content: center; font-size: 18px; line-height: 1; }',
+ '.h2-station-page .hr-manual-panel-footer { margin-top: 16px; flex-shrink: 0; display: flex; flex-direction: column; gap: 8px; }',
+ '.h2-station-page .hr-manual-panel-footer__hint { font-size: 12px; color: #94a3b8; text-align: center; line-height: 1.4; }',
+ '.h2-station-page .hr-manual-panel-footer .ant-btn { width: 100%; min-height: 44px; font-size: 14px; }',
+ '@media (prefers-reduced-motion: reduce) { .h2-station-page .hr-manual-thumb, .h2-station-page .hr-manual-cal-day, .h2-station-page .hr-manual-upload-tile { transition: none; } .h2-station-page .hr-manual-thumb:hover { transform: none; } }'
]).join('\n');
var HR_DAILY_STATS_WINDOW = 30;
@@ -242,19 +367,6 @@ var HR_FALLBACK_RECORDS = [
{ id: 'rf-10', hydrogenTime: '2026-03-15 10:00:00', plateNo: '苏E33333F', stationName: '苏州工业园区备用站', stationCode: 'SZ-H2-004', unitPrice: 41, hydrogenKg: 6.2, totalAmount: 254.2, customerAmount: 254.2, reconcileStatus: 'pending', reconcileTime: '' }
];
-var HR_APPOINTMENT_STATUS_MAP = {
- pending: { label: '待处理', color: 'processing' },
- accepted: { label: '已接受', color: 'success' },
- rejected: { label: '已拒绝', color: 'error' }
-};
-
-var HR_INITIAL_APPOINTMENTS = [
- { id: 'ap-1', stationName: '嘉兴加氢站(一期)', stationCode: 'JX-H2-001', plateNo: '浙A12345F', appointmentTime: '2026-06-10 09:00:00', appointmentKg: 15.0, driverName: '刘建国', contact: '13800138011', status: 'pending' },
- { id: 'ap-2', stationName: '杭州临平加氢站', stationCode: 'HZ-H2-002', plateNo: '浙B23456F', appointmentTime: '2026-06-10 11:30:00', appointmentKg: 12.5, driverName: '陈师傅', contact: '13900139022', status: 'pending' },
- { id: 'ap-3', stationName: '嘉兴加氢站(一期)', stationCode: 'JX-H2-001', plateNo: '浙A67890F', appointmentTime: '2026-06-09 14:00:00', appointmentKg: 10.0, driverName: '王磊', contact: '13700137033', status: 'pending' },
- { id: 'ap-4', stationName: '上海宝山加氢站', stationCode: 'SH-H2-003', plateNo: '沪A88888F', appointmentTime: '2026-06-08 16:20:00', appointmentKg: 8.5, driverName: '张强', contact: '13600136044', status: 'accepted', handledTime: '2026-06-08 10:15:00' },
- { id: 'ap-5', stationName: '杭州临平加氢站', stationCode: 'HZ-H2-002', plateNo: '浙B99999F', appointmentTime: '2026-06-07 08:45:00', appointmentKg: 18.0, driverName: '赵明', contact: '13500135055', status: 'rejected', rejectReason: '预约时段站点设备检修,请改约其他时间', handledTime: '2026-06-06 17:30:00' }
-];
function hrFormatKg(v) {
var n = typeof v === 'number' ? v : parseFloat(v);
@@ -332,21 +444,26 @@ function hrBuildRecentDailyWindow(list, dayjs, windowDays) {
for (i = 0; i < windowDays; i++) {
var key;
var shortLabel;
+ var weekday;
+ var weekNames = ['日', '一', '二', '三', '四', '五', '六'];
if (dayjs) {
var d = dayjs().startOf('day').subtract(i, 'day');
key = d.format('YYYY-MM-DD');
shortLabel = d.format('MM-DD');
+ weekday = weekNames[d.day()];
} else {
var native = new Date();
native.setHours(0, 0, 0, 0);
native.setDate(native.getDate() - i);
key = hrDateToKey(native);
shortLabel = hrPad2(native.getMonth() + 1) + '-' + hrPad2(native.getDate());
+ weekday = weekNames[native.getDay()];
}
var stat = statsMap[key];
days.push({
date: key,
dateLabel: shortLabel,
+ weekday: weekday,
isToday: i === 0,
count: stat ? stat.count : 0,
verifiedCount: stat ? stat.verifiedCount : 0,
@@ -501,11 +618,26 @@ function hrUpsertBridgeRow(payload) {
settlementStatus: 'customer',
mileageKm: payload.mileageKm != null ? payload.mileageKm : null,
creatorName: payload.fillerName || '站端账号',
+ recordSource: 'station',
+ changeLogOperator: payload.fillerName || '站端账号',
reconcileStatus: payload.reconcileStatus || 'pending',
verifyStatus: payload.verifyStatus || 'unverified'
});
}
+function hrRecordSourceLabel(record) {
+ var source = record && record.recordSource;
+ if (source === 'lingniu') return '羚牛上传';
+ if (source === 'station') return '站端上传';
+ var creator = String((record && record.fillerName) || '').trim();
+ if (creator && creator !== '站端账号') return '羚牛上传';
+ return '站端上传';
+}
+
+function hrIsLingniuSource(record) {
+ return hrRecordSourceLabel(record) === '羚牛上传';
+}
+
function hrRemoveBridgeRow(id) {
var bridge = hrGetVehicleLedgerBridge();
if (!bridge || typeof bridge.removeRow !== 'function') return false;
@@ -566,14 +698,6 @@ function hrTotalAmountMismatch(unitPrice, hydrogenKg, totalAmount) {
return { expected: expected, actual: actual, diff: diff };
}
-function hrLookupStationUnitPrice(stationName) {
- var bridge = hrGetVehicleLedgerBridge();
- if (bridge && typeof bridge.lookupStationUnitPrice === 'function') {
- return bridge.lookupStationUnitPrice(stationName);
- }
- return 42.5;
-}
-
function hrTodayDateKey(dayjsLib) {
if (dayjsLib) return dayjsLib().format('YYYY-MM-DD');
var d = new Date();
@@ -716,6 +840,9 @@ const Component = function () {
var useState = React.useState;
var useMemo = React.useMemo;
var useCallback = React.useCallback;
+ var useEffect = React.useEffect;
+ var protoDevState = useProtoDevState();
+ var stationScope = hrNormalizeStationScope(protoDevState && protoDevState.hr_station_scope);
var antd = window.antd;
var Card = antd.Card;
@@ -733,10 +860,22 @@ const Component = function () {
var Badge = antd.Badge;
var Upload = antd.Upload;
var Image = antd.Image;
+ var Tooltip = antd.Tooltip;
var message = antd.message;
var dayjs = window.dayjs;
- var emptyFilters = { startDate: '', endDate: '', plateNo: undefined, stationName: undefined, reconcileStatus: undefined };
+ var emptyFilters = {
+ startDate: '',
+ endDate: '',
+ plateNo: undefined,
+ stationName: undefined,
+ verifyStatus: undefined,
+ verifiedStartDate: '',
+ verifiedEndDate: '',
+ reconcileStatus: undefined,
+ reconcileStartDate: '',
+ reconcileEndDate: ''
+ };
var subViewState = useState('list');
var subView = subViewState[0];
@@ -800,6 +939,10 @@ const Component = function () {
var appliedFilters = appliedFiltersState[0];
var setAppliedFilters = appliedFiltersState[1];
+ var filterExpandedState = useState(false);
+ var filterExpanded = filterExpandedState[0];
+ var setFilterExpanded = filterExpandedState[1];
+
var pageState = useState(1);
var page = pageState[0];
var setPage = pageState[1];
@@ -823,27 +966,19 @@ const Component = function () {
var deleteModal = deleteModalState[0];
var setDeleteModal = deleteModalState[1];
- var appointmentDataState = useState(function () {
- return HR_INITIAL_APPOINTMENTS.map(function (r) { return Object.assign({}, r); });
- });
- var appointmentData = appointmentDataState[0];
- var setAppointmentData = appointmentDataState[1];
-
- var appointmentPageState = useState(1);
- var appointmentPage = appointmentPageState[0];
- var setAppointmentPage = appointmentPageState[1];
- var appointmentPageSizeState = useState(20);
- var appointmentPageSize = appointmentPageSizeState[0];
- var setAppointmentPageSize = appointmentPageSizeState[1];
-
- var rejectModalState = useState({ open: false, record: null, reason: '' });
- var rejectModal = rejectModalState[0];
- var setRejectModal = rejectModalState[1];
var dailyStatsPageState = useState(0);
var dailyStatsPage = dailyStatsPageState[0];
var setDailyStatsPage = dailyStatsPageState[1];
+ var dailyStatsExpandedState = useState(false);
+ var dailyStatsExpanded = dailyStatsExpandedState[0];
+ var setDailyStatsExpanded = dailyStatsExpandedState[1];
+
+ var changeLogModalState = useState({ open: false, record: null });
+ var changeLogModal = changeLogModalState[0];
+ var setChangeLogModal = changeLogModalState[1];
+
var plateOptions = useMemo(function () {
var map = {};
listData.forEach(function (r) {
@@ -854,7 +989,7 @@ const Component = function () {
});
}, [listData]);
- var stationOptions = useMemo(function () {
+ var allStationOptions = useMemo(function () {
var bridge = hrGetVehicleLedgerBridge();
if (bridge && typeof bridge.getStationList === 'function') {
return bridge.getStationList().map(function (item) {
@@ -870,9 +1005,16 @@ const Component = function () {
});
}, [listData]);
- React.useEffect(function () {
- if (manualStation) return;
- if (stationOptions[0] && stationOptions[0].value) {
+ var stationOptions = useMemo(function () {
+ return hrFilterStationsByScope(allStationOptions, stationScope);
+ }, [allStationOptions, stationScope]);
+
+ var stationSelectDisabled = stationOptions.length <= 1;
+
+ useEffect(function () {
+ if (!stationOptions.length) return;
+ var stillValid = stationOptions.some(function (o) { return o.value === manualStation; });
+ if (!manualStation || !stillValid) {
setManualStation(stationOptions[0].value);
}
}, [stationOptions, manualStation]);
@@ -986,22 +1128,36 @@ const Component = function () {
message.warning('请至少上传一张手工台账照片');
return;
}
- var found = stationOptions.find(function (o) { return o.value === activeManualStation; });
- var saved = hrUpsertManualLedger({
- stationId: found && found.stationCode ? found.stationCode : '',
- stationName: activeManualStation,
- ledgerDate: manualSelectedDate,
- images: manualDraftImages
+ Modal.confirm({
+ title: '确认提交手工台账',
+ content: '提交后将无法修改,是否确认手工台账照片无误',
+ okText: '确认提交',
+ cancelText: '再检查一下',
+ centered: true,
+ onOk: function () {
+ var found = stationOptions.find(function (o) { return o.value === activeManualStation; });
+ var saved = hrUpsertManualLedger({
+ stationId: found && found.stationCode ? found.stationCode : '',
+ stationName: activeManualStation,
+ ledgerDate: manualSelectedDate,
+ images: manualDraftImages
+ });
+ if (!saved) {
+ message.error('上传失败,请重试');
+ return Promise.reject();
+ }
+ if (saved.images && saved.images.length) {
+ setManualDraftImages(saved.images.map(function (img) {
+ return Object.assign({}, img, { archived: true });
+ }));
+ }
+ message.success(manualSelectedUploaded
+ ? manualSelectedDate + ' 已补传'
+ : manualSelectedDate + ' 手工台账已上传');
+ setManualTick(function (n) { return n + 1; });
+ }
});
- if (!saved) {
- message.error('上传失败,请重试');
- return;
- }
- message.success(manualSelectedUploaded
- ? manualSelectedDate + ' 已补传'
- : manualSelectedDate + ' 手工台账已上传');
- setManualTick(function (n) { return n + 1; });
- }, [activeManualStation, manualDraftImages, manualSelectedDate, manualSelectedUploaded, dayjs, message, stationOptions]);
+ }, [activeManualStation, manualDraftImages, manualSelectedDate, manualSelectedUploaded, dayjs, message, stationOptions, Modal]);
var shiftManualMonth = useCallback(function (delta) {
setManualCursorYm(function (prev) {
@@ -1013,37 +1169,6 @@ const Component = function () {
});
}, []);
- var pendingAppointmentCount = useMemo(function () {
- var count = 0;
- var i;
- for (i = 0; i < appointmentData.length; i++) {
- if (appointmentData[i].status === 'pending') count += 1;
- }
- return count;
- }, [appointmentData]);
-
- var sortedAppointments = useMemo(function () {
- return appointmentData.slice().sort(function (a, b) {
- return String(b.appointmentTime || '').localeCompare(String(a.appointmentTime || ''));
- });
- }, [appointmentData]);
-
- var appointmentSummary = useMemo(function () {
- var pending = 0;
- var accepted = 0;
- var rejected = 0;
- var totalKg = 0;
- var i;
- for (i = 0; i < appointmentData.length; i++) {
- var item = appointmentData[i];
- var kg = parseFloat(item.appointmentKg);
- if (!isNaN(kg)) totalKg += kg;
- if (item.status === 'pending') pending += 1;
- else if (item.status === 'accepted') accepted += 1;
- else if (item.status === 'rejected') rejected += 1;
- }
- return { pending: pending, accepted: accepted, rejected: rejected, totalKg: totalKg, total: appointmentData.length };
- }, [appointmentData]);
var filteredList = useMemo(function () {
var list = listData.slice();
@@ -1053,6 +1178,12 @@ const Component = function () {
if (appliedFilters.stationName) {
list = list.filter(function (r) { return r.stationName === appliedFilters.stationName; });
}
+ if (appliedFilters.verifyStatus) {
+ list = list.filter(function (r) {
+ var done = hrIsVerified(r);
+ return appliedFilters.verifyStatus === 'verified' ? done : !done;
+ });
+ }
if (appliedFilters.reconcileStatus) {
list = list.filter(function (r) {
var done = hrIsReconciled(r);
@@ -1064,6 +1195,17 @@ const Component = function () {
return hrInDateRange(r.hydrogenTime, appliedFilters.startDate, appliedFilters.endDate);
});
}
+ if (appliedFilters.verifiedStartDate || appliedFilters.verifiedEndDate) {
+ list = list.filter(function (r) {
+ return hrInDateRange(r.verifiedAt, appliedFilters.verifiedStartDate, appliedFilters.verifiedEndDate);
+ });
+ }
+ if (appliedFilters.reconcileStartDate || appliedFilters.reconcileEndDate) {
+ list = list.filter(function (r) {
+ var t = r.reconcileTime || r.reconcileDate || '';
+ return hrInDateRange(t, appliedFilters.reconcileStartDate, appliedFilters.reconcileEndDate);
+ });
+ }
return list.sort(function (a, b) {
return String(b.hydrogenTime || '').localeCompare(String(a.hydrogenTime || ''));
});
@@ -1087,9 +1229,13 @@ const Component = function () {
var dailyStatsSummary = useMemo(function () {
var totalKg = 0;
+ var totalAmount = 0;
+ var totalCount = 0;
var i;
for (i = 0; i < dailyStatsWindow.length; i++) {
totalKg += dailyStatsWindow[i].totalKg || 0;
+ totalAmount += dailyStatsWindow[i].totalAmount || 0;
+ totalCount += dailyStatsWindow[i].count || 0;
}
var rangeEnd = dailyStatsWindow[0] ? dailyStatsWindow[0].date : '—';
var rangeStart = dailyStatsWindow.length
@@ -1098,43 +1244,193 @@ const Component = function () {
return {
rangeStart: rangeStart,
rangeEnd: rangeEnd,
- totalKg: Math.round(totalKg * 100) / 100
+ totalKg: Math.round(totalKg * 100) / 100,
+ totalAmount: Math.round(totalAmount * 100) / 100,
+ totalCount: totalCount
};
}, [dailyStatsWindow]);
+ var dailyStatsPageCount = Math.max(1, Math.ceil(HR_DAILY_STATS_WINDOW / HR_DAILY_STATS_PAGE_SIZE));
var dailyStatsPageItems = useMemo(function () {
var start = dailyStatsPage * HR_DAILY_STATS_PAGE_SIZE;
var chunk = dailyStatsWindow.slice(start, start + HR_DAILY_STATS_PAGE_SIZE);
return chunk.slice().reverse();
}, [dailyStatsWindow, dailyStatsPage]);
- var renderFilterField = useCallback(function (label, control) {
- return React.createElement('div', { className: 'lc-filter-field' },
- React.createElement('span', { className: 'lc-filter-field-label' }, label),
- React.createElement('div', { className: 'lc-filter-field-control' }, control)
+ var renderFilterField = useCallback(function (field) {
+ return React.createElement('div', { key: field.key, className: 'lc-filter-field' },
+ React.createElement('span', { className: 'lc-filter-field-label' }, field.label),
+ React.createElement('div', { className: 'lc-filter-field-control' }, field.control)
);
}, []);
+ var filterFields = useMemo(function () {
+ return [
+ {
+ key: 'hydrogenTime',
+ label: '加氢时间',
+ control: React.createElement(DateRangeFilterField, {
+ startDate: draftFilters.startDate || '',
+ endDate: draftFilters.endDate || '',
+ startPlaceholder: '开始日期',
+ endPlaceholder: '结束日期',
+ ariaLabel: '加氢时间',
+ onChange: function (range) {
+ setDraftFilters(function (p) {
+ return Object.assign({}, p, {
+ startDate: range.startDate || '',
+ endDate: range.endDate || ''
+ });
+ });
+ }
+ })
+ },
+ {
+ key: 'plateNo',
+ label: '车牌号',
+ control: React.createElement(Select, {
+ placeholder: '请选择车牌号',
+ allowClear: true,
+ showSearch: true,
+ optionFilterProp: 'label',
+ value: draftFilters.plateNo,
+ options: plateOptions,
+ onChange: function (v) { setDraftFilters(function (p) { return Object.assign({}, p, { plateNo: v }); }); },
+ style: { width: '100%' },
+ dropdownStyle: { borderRadius: 8 }
+ })
+ },
+ {
+ key: 'stationName',
+ label: '加氢站',
+ control: React.createElement(Select, {
+ placeholder: '请选择加氢站',
+ allowClear: true,
+ showSearch: true,
+ optionFilterProp: 'label',
+ value: draftFilters.stationName,
+ options: stationOptions,
+ onChange: function (v) { setDraftFilters(function (p) { return Object.assign({}, p, { stationName: v }); }); },
+ style: { width: '100%' },
+ dropdownStyle: { borderRadius: 8 }
+ })
+ },
+ {
+ key: 'reconcileStatus',
+ label: '对账状态',
+ control: React.createElement(Select, {
+ placeholder: '请选择对账状态',
+ allowClear: true,
+ value: draftFilters.reconcileStatus,
+ options: [
+ { value: 'pending', label: '未对账' },
+ { value: 'reconciled', label: '已对账' }
+ ],
+ onChange: function (v) { setDraftFilters(function (p) { return Object.assign({}, p, { reconcileStatus: v }); }); },
+ style: { width: '100%' },
+ dropdownStyle: { borderRadius: 8 }
+ })
+ },
+ {
+ key: 'verifyStatus',
+ label: '核对状态',
+ control: React.createElement(Select, {
+ placeholder: '请选择核对状态',
+ allowClear: true,
+ value: draftFilters.verifyStatus,
+ options: [
+ { value: 'unverified', label: '未核对' },
+ { value: 'verified', label: '已核对' }
+ ],
+ onChange: function (v) { setDraftFilters(function (p) { return Object.assign({}, p, { verifyStatus: v }); }); },
+ style: { width: '100%' },
+ dropdownStyle: { borderRadius: 8 }
+ })
+ },
+ {
+ key: 'verifiedAt',
+ label: '核对时间',
+ control: React.createElement(DateRangeFilterField, {
+ startDate: draftFilters.verifiedStartDate || '',
+ endDate: draftFilters.verifiedEndDate || '',
+ startPlaceholder: '开始日期',
+ endPlaceholder: '结束日期',
+ ariaLabel: '核对时间',
+ onChange: function (range) {
+ setDraftFilters(function (p) {
+ return Object.assign({}, p, {
+ verifiedStartDate: range.startDate || '',
+ verifiedEndDate: range.endDate || ''
+ });
+ });
+ }
+ })
+ },
+ {
+ key: 'reconcileAt',
+ label: '对账时间',
+ control: React.createElement(DateRangeFilterField, {
+ startDate: draftFilters.reconcileStartDate || '',
+ endDate: draftFilters.reconcileEndDate || '',
+ startPlaceholder: '开始日期',
+ endPlaceholder: '结束日期',
+ ariaLabel: '对账时间',
+ onChange: function (range) {
+ setDraftFilters(function (p) {
+ return Object.assign({}, p, {
+ reconcileStartDate: range.startDate || '',
+ reconcileEndDate: range.endDate || ''
+ });
+ });
+ }
+ })
+ }
+ ];
+ }, [draftFilters, plateOptions, stationOptions]);
+
+ var filterSplit = useMemo(function () {
+ return splitFilterFields(filterFields, VM_FILTER_PRIMARY_VISIBLE_COUNT);
+ }, [filterFields]);
+ var showFilterExpand = shouldShowFilterExpand(filterFields.length, VM_FILTER_PRIMARY_VISIBLE_COUNT);
+
var handleFilterQuery = useCallback(function () {
setAppliedFilters({
startDate: draftFilters.startDate || '',
endDate: draftFilters.endDate || '',
plateNo: draftFilters.plateNo,
stationName: draftFilters.stationName,
- reconcileStatus: draftFilters.reconcileStatus
+ verifyStatus: draftFilters.verifyStatus,
+ verifiedStartDate: draftFilters.verifiedStartDate || '',
+ verifiedEndDate: draftFilters.verifiedEndDate || '',
+ reconcileStatus: draftFilters.reconcileStatus,
+ reconcileStartDate: draftFilters.reconcileStartDate || '',
+ reconcileEndDate: draftFilters.reconcileEndDate || ''
});
setPage(1);
setDailyStatsPage(0);
}, [draftFilters]);
var handleFilterReset = useCallback(function () {
- var empty = { startDate: '', endDate: '', plateNo: undefined, stationName: undefined, reconcileStatus: undefined };
+ var empty = Object.assign({}, emptyFilters);
setDraftFilters(empty);
setAppliedFilters(empty);
+ setFilterExpanded(false);
setPage(1);
setDailyStatsPage(0);
}, []);
+ var extraFilterActiveCount = useMemo(function () {
+ var n = 0;
+ if (draftFilters.verifyStatus) n += 1;
+ if (draftFilters.verifiedStartDate || draftFilters.verifiedEndDate) n += 1;
+ if (draftFilters.reconcileStartDate || draftFilters.reconcileEndDate) n += 1;
+ return n;
+ }, [draftFilters]);
+
+ useEffect(function () {
+ if (extraFilterActiveCount > 0) setFilterExpanded(true);
+ }, [extraFilterActiveCount]);
+
var resetFormView = useCallback(function () {
setSubView('list');
setForm(hrEmptyForm());
@@ -1394,117 +1690,30 @@ const Component = function () {
doBatchSave();
}, [batchRows, formSubmitting, resetFormView, dayjs]);
- var handleAcceptAppointment = useCallback(function (record) {
- if (!record || record.status !== 'pending') return;
- Modal.confirm({
- title: '接受预约',
- content: '确认接受「' + (record.stationName || '加氢站') + '」车牌「' + (record.plateNo || '') + '」的加氢预约?接受后将自动生成一条未对账加氢记录(时间=预约时间,量=预约量,单价取该站近期单价)。',
- okText: '接受并生成记录',
- cancelText: '取消',
- centered: true,
- okButtonProps: { style: HR_PRIMARY_BTN_STYLE },
- onOk: function () {
- var stationName = (record.stationName || '').trim();
- var stationCode = (record.stationCode || '').trim();
- var hydrogenTime = record.appointmentTime || '';
- var plateNo = record.plateNo || '';
- var hydrogenKg = Math.round(parseFloat(record.appointmentKg) * 100) / 100;
- if (!stationName || !hydrogenTime || !plateNo || isNaN(hydrogenKg) || hydrogenKg <= 0) {
- message.error('预约信息不完整,无法生成加氢记录');
- return Promise.reject();
- }
- var dup = hrFindDuplicateRow({
- stationName: stationName,
- plateNo: plateNo,
- hydrogenTime: hydrogenTime
- });
- if (dup) {
- message.error('已存在相同加氢站、车牌号与加氢时间的记录,无法重复落账');
- return Promise.reject();
- }
- var unitPrice = hrLookupStationUnitPrice(stationName);
- var totalAmount = Math.round(unitPrice * hydrogenKg * 100) / 100;
- var saved = hrUpsertBridgeRow({
- hydrogenTime: hydrogenTime,
- stationName: stationName,
- stationCode: stationCode,
- plateNo: plateNo,
- unitPrice: unitPrice,
- hydrogenKg: hydrogenKg,
- totalAmount: totalAmount,
- fillerName: '预约受理',
- reconcileStatus: 'pending'
- });
- if (!saved) {
- message.error('接受失败:共享账本不可用');
- return Promise.reject();
- }
- var now = dayjs ? dayjs().format('YYYY-MM-DD HH:mm:ss') : '';
- var linkedId = saved.id || saved.key || '';
- setAppointmentData(function (prev) {
- return prev.map(function (r) {
- if (r.id !== record.id) return r;
- return Object.assign({}, r, {
- status: 'accepted',
- handledTime: now,
- rejectReason: '',
- linkedRecordId: linkedId
- });
- });
- });
- message.success('已接受预约,并生成未对账加氢记录');
- }
- });
- }, [dayjs]);
-
- var openRejectAppointment = useCallback(function (record) {
- if (!record || record.status !== 'pending') return;
- setRejectModal({ open: true, record: record, reason: '' });
- }, []);
-
- var closeRejectModal = useCallback(function () {
- setRejectModal({ open: false, record: null, reason: '' });
- }, []);
-
- var handleConfirmRejectAppointment = useCallback(function () {
- if (!rejectModal.record) return;
- var reason = (rejectModal.reason || '').trim();
- if (!reason) {
- message.warning('请填写拒绝原因');
- return;
- }
- var recordId = rejectModal.record.id;
- var now = dayjs ? dayjs().format('YYYY-MM-DD HH:mm:ss') : '';
- setAppointmentData(function (prev) {
- return prev.map(function (r) {
- if (r.id !== recordId) return r;
- return Object.assign({}, r, { status: 'rejected', rejectReason: reason, handledTime: now });
- });
- });
- message.success('已拒绝预约');
- closeRejectModal();
- }, [rejectModal, dayjs, closeRejectModal]);
var handleExport = useCallback(function () {
if (!filteredList.length) {
message.warning('当前筛选条件下暂无数据可导出');
return;
}
- var headers = ['序号', '加氢时间', '加氢站名称', '车牌号', '里程(km)', '氢气单价(元/kg)', '加氢量(kg)', '加氢总额(元)', '核对状态', '核对时间', '对账状态', '对账时间'];
+ var headers = ['序号', '加氢时间', '加氢站名称', '车牌号', '来源', '里程(km)', '氢气单价(元/kg)', '加氢量(kg)', '加氢总额(元)', '核对状态', '核对时间', '核对人', '对账状态', '对账时间', '对账人'];
var rows = filteredList.map(function (r, index) {
return [
index + 1,
r.hydrogenTime || '',
r.stationName || '',
r.plateNo || '',
+ hrRecordSourceLabel(r),
r.mileageKm != null && r.mileageKm !== '' ? String(Math.round(Number(r.mileageKm))) : '',
hrFormatYuan(r.unitPrice != null ? r.unitPrice : r.costUnitPrice),
hrFormatKg(r.hydrogenKg),
hrFormatYuan(r.totalAmount != null ? r.totalAmount : r.customerAmount),
hrIsVerified(r) ? '已核对' : '未核对',
hrFormatReconcileTime(r.verifiedAt),
+ r.verifiedByName || '',
hrIsReconciled(r) ? '已对账' : '未对账',
- hrFormatReconcileTime(r.reconcileTime)
+ hrFormatReconcileTime(r.reconcileTime),
+ r.reconciledByName || ''
];
});
hrDownloadCsv('加氢记录_' + new Date().getTime() + '.csv', headers, rows);
@@ -1534,9 +1743,16 @@ const Component = function () {
title: '车牌号',
dataIndex: 'plateNo',
key: 'plateNo',
- width: 120,
- render: function (v) {
- return React.createElement('span', { className: 'hr-refuel-plate tabular-nums' }, hrFormatPlateDisplay(v));
+ width: 128,
+ render: function (v, record) {
+ var lingniu = hrIsLingniuSource(record);
+ return React.createElement('div', { className: 'hr-plate-cell' },
+ React.createElement('span', { className: 'hr-refuel-plate tabular-nums' }, hrFormatPlateDisplay(v)),
+ React.createElement(Tag, {
+ className: 'hr-source-tag',
+ color: lingniu ? 'blue' : 'green'
+ }, hrRecordSourceLabel(record))
+ );
}
},
{
@@ -1555,7 +1771,7 @@ const Component = function () {
width: 128,
render: function (v, record) {
var price = v != null ? v : record.costUnitPrice;
- return React.createElement('span', { className: 'hr-refuel-money tabular-nums' }, hrFormatYuan(price));
+ return React.createElement('span', { className: 'hr-refuel-km tabular-nums' }, hrFormatYuan(price));
}
},
{
@@ -1599,6 +1815,15 @@ const Component = function () {
return React.createElement('span', { className: 'hr-refuel-time tabular-nums' }, hrFormatReconcileTime(v));
}
},
+ {
+ title: '核对人',
+ dataIndex: 'verifiedByName',
+ key: 'verifiedByName',
+ width: 88,
+ render: function (v) {
+ return v || '—';
+ }
+ },
{
title: '对账状态',
dataIndex: 'reconcileStatus',
@@ -1621,6 +1846,15 @@ const Component = function () {
return React.createElement('span', { className: 'hr-refuel-time tabular-nums' }, hrFormatReconcileTime(v));
}
},
+ {
+ title: '对账人',
+ dataIndex: 'reconciledByName',
+ key: 'reconciledByName',
+ width: 88,
+ render: function (v) {
+ return v || '—';
+ }
+ },
{
title: '操作',
key: 'actions',
@@ -1641,6 +1875,13 @@ const Component = function () {
}
},
more: [
+ {
+ key: 'changelog',
+ label: '变更日志',
+ onClick: function () {
+ setChangeLogModal({ open: true, record: record });
+ }
+ },
{
key: 'delete',
label: '删除',
@@ -1661,139 +1902,6 @@ const Component = function () {
];
}, [openEdit, message]);
- var appointmentColumns = useMemo(function () {
- return [
- {
- title: '序号',
- key: 'seq',
- width: 52,
- align: 'center',
- render: function (_, __, index) {
- return React.createElement('span', { className: 'h2-refuel-drill-seq tabular-nums' }, index + 1);
- }
- },
- {
- title: '加氢站名称',
- dataIndex: 'stationName',
- key: 'stationName',
- width: 160,
- ellipsis: true,
- render: function (v) {
- return React.createElement('span', { className: 'h2-refuel-drill-station', title: v || '' }, v || '—');
- }
- },
- {
- title: '车牌号',
- dataIndex: 'plateNo',
- key: 'plateNo',
- width: 120,
- render: function (v) {
- return React.createElement('span', { className: 'h2-refuel-drill-plate tabular-nums' }, v || '—');
- }
- },
- {
- title: '预约时间',
- dataIndex: 'appointmentTime',
- key: 'appointmentTime',
- width: 168,
- render: function (v) {
- return React.createElement('span', { className: 'h2-refuel-drill-time tabular-nums' }, v || '—');
- }
- },
- {
- title: '预约加氢量(kg)',
- dataIndex: 'appointmentKg',
- key: 'appointmentKg',
- width: 140,
- render: function (v) {
- return React.createElement('span', { className: 'h2-refuel-drill-kg tabular-nums' }, hrFormatKg(v));
- }
- },
- {
- title: '预约司机',
- dataIndex: 'driverName',
- key: 'driverName',
- width: 110,
- render: function (v) {
- return React.createElement('span', { className: 'h2-refuel-drill-driver' }, v || '—');
- }
- },
- {
- title: '联系方式',
- dataIndex: 'contact',
- key: 'contact',
- width: 130,
- render: function (v) {
- return React.createElement('span', { className: 'h2-refuel-drill-contact tabular-nums' }, v || '—');
- }
- },
- {
- title: '状态',
- dataIndex: 'status',
- key: 'status',
- width: 100,
- render: function (v) {
- var info = HR_APPOINTMENT_STATUS_MAP[v] || { label: v || '—', color: 'default' };
- return React.createElement(Tag, { color: info.color, style: { margin: 0, borderRadius: 6, fontWeight: 600 } }, info.label);
- }
- },
- {
- title: '处理情况',
- key: 'handleInfo',
- width: 240,
- render: function (_, record) {
- if (record.status === 'pending') {
- return React.createElement('span', { style: { color: '#2563eb', fontWeight: 600 } }, '待站端处理');
- }
- var timeText = record.handledTime
- ? React.createElement('div', { className: 'tabular-nums', style: { fontSize: 12, color: '#64748b' } }, '处理时间:' + record.handledTime)
- : null;
- if (record.status === 'accepted') {
- return React.createElement('div', null,
- React.createElement('span', { style: { color: '#059669', fontWeight: 600 } }, '已接受,已生成加氢记录'),
- timeText
- );
- }
- if (record.status === 'rejected') {
- return React.createElement('div', null,
- React.createElement('span', { style: { color: '#dc2626', fontWeight: 600 } }, '已拒绝'),
- timeText,
- record.rejectReason
- ? React.createElement('div', { className: 'hr-appointment-reject-reason', title: record.rejectReason }, '原因:' + record.rejectReason)
- : null
- );
- }
- return React.createElement('span', { style: { color: '#94a3b8' } }, '—');
- }
- },
- {
- title: '操作',
- key: 'actions',
- width: 148,
- fixed: 'right',
- render: function (_, record) {
- if (record.status !== 'pending') {
- return React.createElement(OperationActions, { more: [] });
- }
- return React.createElement(OperationActions, {
- more: [
- {
- key: 'accept',
- label: '接受',
- onClick: function () { handleAcceptAppointment(record); }
- },
- {
- key: 'reject',
- label: '拒绝',
- danger: true,
- onClick: function () { openRejectAppointment(record); }
- }
- ]
- });
- }
- }
- ];
- }, [handleAcceptAppointment, openRejectAppointment]);
var formTimeValue = null;
if (dayjs && form.hydrogenTime) {
@@ -2016,120 +2124,33 @@ const Component = function () {
);
var renderListMainTabs = function () {
- return React.createElement('div', {
- style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' },
+ return React.createElement('nav', {
+ className: 'hr-main-tabs',
role: 'tablist',
- 'aria-label': '加氢记录、手工台账与预约加氢'
+ 'aria-label': '加氢记录与手工台账'
},
- React.createElement(Button, {
- type: listMainTab === 'records' ? 'primary' : 'default',
- style: listMainTab === 'records' ? HR_PRIMARY_BTN_STYLE : { borderRadius: 8, fontWeight: 600 },
+ React.createElement('button', {
+ type: 'button',
+ role: 'tab',
+ className: 'hr-main-tab' + (listMainTab === 'records' ? ' is-active' : ''),
+ 'aria-selected': listMainTab === 'records',
onClick: function () { setListMainTab('records'); }
}, '加氢记录'),
React.createElement(Badge, {
dot: !manualTodayUploaded,
offset: [-2, 2]
},
- React.createElement(Button, {
- type: listMainTab === 'manual' ? 'primary' : 'default',
- style: listMainTab === 'manual' ? HR_PRIMARY_BTN_STYLE : { borderRadius: 8, fontWeight: 600 },
+ React.createElement('button', {
+ type: 'button',
+ role: 'tab',
+ className: 'hr-main-tab' + (listMainTab === 'manual' ? ' is-active' : ''),
+ 'aria-selected': listMainTab === 'manual',
onClick: function () { setListMainTab('manual'); }
}, '手工台账')
- ),
- React.createElement(Badge, {
- count: pendingAppointmentCount,
- overflowCount: 99,
- offset: [6, -2],
- size: 'small',
- showZero: false,
- title: pendingAppointmentCount ? ('待处理预约 ' + pendingAppointmentCount + ' 条') : undefined
- },
- React.createElement(Button, {
- type: listMainTab === 'appointments' ? 'primary' : 'default',
- style: listMainTab === 'appointments' ? HR_PRIMARY_BTN_STYLE : { borderRadius: 8, fontWeight: 600 },
- onClick: function () { setListMainTab('appointments'); },
- 'aria-label': pendingAppointmentCount
- ? ('预约加氢,待处理 ' + pendingAppointmentCount + ' 条')
- : '预约加氢'
- }, '预约加氢')
)
);
};
- var renderAppointmentPanel = function () {
- var records = sortedAppointments;
- var summary = appointmentSummary;
- var apptTotalPages = Math.max(1, Math.ceil(records.length / appointmentPageSize) || 1);
- var safeAppointmentPage = Math.min(appointmentPage, apptTotalPages);
- var apptStart = (safeAppointmentPage - 1) * appointmentPageSize;
- var pagedAppointments = records.slice(apptStart, apptStart + appointmentPageSize);
- var stats = [
- { key: 'pending', label: '待处理预约', value: String(summary.pending || 0), mod: 'count', valueMod: 'count' },
- { key: 'accepted', label: '已接受', value: String(summary.accepted || 0), mod: 'kg', valueMod: 'kg' },
- { key: 'rejected', label: '已拒绝', value: String(summary.rejected || 0), mod: 'cost', valueMod: 'cost' },
- { key: 'totalKg', label: '预约加氢量合计(kg)', value: hrFormatKg(summary.totalKg), mod: 'customer', valueMod: 'customer' }
- ];
- return React.createElement('div', { className: 'lc-table-section', style: { flex: 1, overflow: 'auto', display: 'flex', flexDirection: 'column', gap: 12 } },
- React.createElement('div', { className: 'lc-table-toolbar' },
- React.createElement('div', { className: 'lc-table-toolbar-left' }, renderListMainTabs()),
- React.createElement('div', { className: 'lc-table-toolbar-actions' },
- summary.pending
- ? React.createElement(Tag, { color: 'processing', style: { margin: 0, borderRadius: 6, fontWeight: 600 } }, summary.pending + ' 条待处理')
- : React.createElement(Tag, { style: { margin: 0, borderRadius: 6, color: '#64748b' } }, '暂无待处理')
- )
- ),
- React.createElement(Card, {
- className: 'lc-filter-card',
- bordered: false,
- title: '预约信息与处理情况'
- },
- React.createElement('div', { style: { color: '#64748b', fontSize: 13, marginBottom: 12, lineHeight: 1.6 } },
- '全站运营视角 · 列表展示预约信息与处理情况;待处理可接受或拒绝,接受后自动生成未对账加氢记录。'
- ),
- React.createElement('div', { className: 'h2-refuel-drill-stats', role: 'group', 'aria-label': '预约统计', style: { marginBottom: 0 } },
- stats.map(function (item) {
- return React.createElement('div', {
- key: item.key,
- className: 'h2-refuel-drill-stat h2-refuel-drill-stat--' + item.mod,
- role: 'article',
- 'aria-label': item.label + ' ' + item.value
- },
- React.createElement('div', { className: 'h2-refuel-drill-stat__label' }, item.label),
- React.createElement('div', {
- className: 'h2-refuel-drill-stat__value h2-refuel-drill-stat__value--' + item.valueMod + ' tabular-nums'
- }, item.value)
- );
- })
- )
- ),
- React.createElement('div', { className: 'lc-table-card', style: { flex: 1 } },
- React.createElement(Table, {
- className: 'lc-list-table',
- size: 'middle',
- bordered: false,
- rowKey: 'id',
- columns: appointmentColumns,
- dataSource: pagedAppointments,
- pagination: false,
- locale: { emptyText: '暂无预约记录' },
- scroll: { x: 1280, y: 'calc(100vh - 420px)' }
- }),
- React.createElement('div', { className: 'vm-table-footer' },
- React.createElement(TablePagination, {
- page: safeAppointmentPage,
- pageSize: appointmentPageSize,
- total: records.length,
- pageSizeOptions: COMPACT_PAGE_SIZE_OPTIONS,
- onPageChange: setAppointmentPage,
- onPageSizeChange: function (size) {
- setAppointmentPageSize(size);
- setAppointmentPage(1);
- }
- })
- )
- )
- );
- };
var batchCreateViewNode = subView === 'form' && formMode === 'create' ? React.createElement('div', { className: 'h2-create-shell' },
React.createElement('div', { className: 'h2-create-topbar' },
@@ -2382,318 +2403,308 @@ const Component = function () {
),
React.createElement(Card, {
className: 'lc-filter-card',
- title: '手工台账上传',
+ title: React.createElement('span', { className: 'hr-card-title-with-help' },
+ '手工台账上传',
+ React.createElement(Tooltip, {
+ title: '每日需上传本站纸质手工台账照片。日历可查看已传/未传日期,点选过往日期可补传;未上传今日台账时,不可新增加氢记录。',
+ placement: 'top',
+ overlayStyle: { maxWidth: 360 }
+ },
+ React.createElement('button', {
+ type: 'button',
+ className: 'hr-help-tip',
+ 'aria-label': '手工台账上传说明',
+ onClick: function (e) { e.preventDefault(); e.stopPropagation(); }
+ },
+ React.createElement('svg', {
+ width: 14,
+ height: 14,
+ viewBox: '0 0 24 24',
+ fill: 'none',
+ stroke: 'currentColor',
+ strokeWidth: 2,
+ strokeLinecap: 'round',
+ strokeLinejoin: 'round',
+ 'aria-hidden': true
+ },
+ React.createElement('circle', { cx: 12, cy: 12, r: 10 }),
+ React.createElement('path', { d: 'M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3' }),
+ React.createElement('line', { x1: 12, y1: 17, x2: 12.01, y2: 17 })
+ )
+ )
+ )
+ ),
bordered: false,
style: { flex: 1, overflow: 'auto' }
},
- React.createElement('div', { style: { marginBottom: 12, color: '#64748b', fontSize: 13, lineHeight: 1.6 } },
- '每日需上传本站纸质手工台账照片。日历可查看已传/未传日期,点选过往日期可补传;未上传今日台账时,不可新增加氢记录。'
- ),
- React.createElement(Row, { gutter: [16, 16], style: { marginBottom: 16 } },
- React.createElement(Col, { xs: 24, md: 10 },
- React.createElement('div', { style: { marginBottom: 6, fontWeight: 600, color: '#475569', fontSize: 13 } }, '加氢站'),
+ React.createElement('div', { className: 'hr-manual-toolbar' },
+ React.createElement('div', { className: 'hr-manual-station-field', 'data-annotation-id': 'hr-manual-station' },
+ React.createElement('span', { className: 'hr-manual-station-field__label' }, '加氢站'),
React.createElement(Select, {
style: { width: '100%' },
value: activeManualStation || undefined,
options: stationOptions,
placeholder: '请选择加氢站',
- onChange: function (v) { setManualStation(v); }
+ disabled: stationSelectDisabled,
+ onChange: function (v) { setManualStation(v); },
+ 'aria-label': '加氢站(按登录角色范围)'
})
- ),
- React.createElement(Col, { xs: 24, md: 14 },
- React.createElement('div', {
- style: {
- padding: '12px 14px',
- borderRadius: 10,
- background: manualTodayUploaded ? '#ecfdf5' : '#fff7ed',
- border: '1px solid ' + (manualTodayUploaded ? '#a7f3d0' : '#fed7aa'),
- color: manualTodayUploaded ? '#047857' : '#c2410c',
- fontWeight: 600,
- marginTop: 22
- }
- }, manualTodayUploaded
- ? '今日已上传手工台账(' + manualTodayKey + ')'
- : '今日尚未上传手工台账(' + manualTodayKey + ')')
)
),
- React.createElement(Row, { gutter: [24, 24] },
- React.createElement(Col, { xs: 24, lg: 12 },
- React.createElement('div', {
- style: {
- border: '1px solid #e2e8f0',
- borderRadius: 12,
- padding: 16,
- background: '#fff'
- }
- },
- React.createElement('div', {
- style: {
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'space-between',
- marginBottom: 8
- }
- },
+ React.createElement('div', { className: 'hr-manual-split' },
+ React.createElement('div', { className: 'hr-manual-side' },
+ React.createElement('div', { className: 'hr-manual-side-card' },
+ React.createElement('div', { className: 'hr-manual-side-card__eyebrow' }, '上传日历'),
+ React.createElement('div', { className: 'hr-manual-cal-nav' },
React.createElement(Button, {
- type: 'text',
onClick: function () { shiftManualMonth(-1); },
'aria-label': '上一月'
}, '‹'),
- React.createElement('strong', {
- className: 'tabular-nums',
- style: { fontSize: 15 }
- }, manualCursorYm.y + '年' + manualCursorYm.m + '月'),
+ React.createElement('strong', { className: 'hr-manual-cal-nav__title' },
+ manualCursorYm.y + '年' + manualCursorYm.m + '月'),
React.createElement(Button, {
- type: 'text',
onClick: function () { shiftManualMonth(1); },
'aria-label': '下一月'
}, '›')
),
+ React.createElement('div', { className: 'hr-manual-cal-summary' },
+ manualFirstHydrogenDate
+ ? (manualMissingCount > 0
+ ? '本月尚有 ' + manualMissingCount + ' 天未上传(自 ' + manualFirstHydrogenDate + ' 起),点选日期可补传'
+ : '本月自 ' + manualFirstHydrogenDate + ' 起截至今日均已上传')
+ : '本站尚无加氢记录,历史日期无需补传'
+ ),
+ React.createElement('div', { className: 'hr-manual-cal-week' },
+ ['日', '一', '二', '三', '四', '五', '六'].map(function (w) {
+ return React.createElement('span', { key: w }, w);
+ })
+ ),
React.createElement('div', {
- style: { fontSize: 13, color: '#64748b', marginBottom: 12 }
- }, manualFirstHydrogenDate
- ? (manualMissingCount > 0
- ? '本月尚有 ' + manualMissingCount + ' 天未上传(自 ' + manualFirstHydrogenDate + ' 起),点选日期可补传'
- : '本月自 ' + manualFirstHydrogenDate + ' 起截至今日均已上传')
- : '本站尚无加氢记录,历史日期无需补传'),
- React.createElement('div', {
- style: {
- display: 'grid',
- gridTemplateColumns: 'repeat(7, 1fr)',
- gap: 4,
- marginBottom: 6,
- textAlign: 'center',
- fontSize: 12,
- color: '#94a3b8',
- fontWeight: 600
- }
- }, ['日', '一', '二', '三', '四', '五', '六'].map(function (w) {
- return React.createElement('span', { key: w }, w);
- })),
- React.createElement('div', {
+ className: 'hr-manual-cal-grid',
role: 'grid',
- 'aria-label': '手工台账日历',
- style: {
- display: 'grid',
- gridTemplateColumns: 'repeat(7, 1fr)',
- gap: 4
- }
+ 'aria-label': '手工台账日历'
}, manualMonthCells.map(function (cell) {
var selected = manualSelectedDate === cell.dateKey;
- var bg = '#fff';
- var color = cell.inMonth ? '#0f172a' : '#cbd5e1';
- var border = '1px solid transparent';
- if (cell.isFuture) {
- color = '#cbd5e1';
- bg = '#f8fafc';
- } else if (cell.needsLedger && cell.uploaded) {
- bg = '#ecfdf5';
- color = '#047857';
- } else if (cell.needsLedger && !cell.uploaded) {
- bg = '#fff7ed';
- color = '#c2410c';
- } else if (cell.inMonth) {
- bg = '#f8fafc';
- color = '#94a3b8';
- }
- if (selected) {
- border = '2px solid #059669';
- } else if (cell.isToday) {
- border = '1px solid #34d399';
- }
var statusLabel = cell.isFuture
? '未来'
: (!cell.needsLedger ? '无需补传' : (cell.uploaded ? '已上传' : '未上传'));
+ var dayClass = 'hr-manual-cal-day'
+ + (cell.inMonth ? '' : ' is-out')
+ + (cell.isFuture ? ' is-future' : '')
+ + (cell.isToday ? ' is-today' : '')
+ + (selected ? ' is-selected' : '')
+ + (cell.needsLedger && cell.uploaded ? ' is-uploaded' : '')
+ + (cell.needsLedger && !cell.uploaded && !cell.isFuture ? ' is-missing' : '')
+ + (!cell.needsLedger && cell.inMonth && !cell.isFuture ? ' is-idle' : '');
return React.createElement('button', {
key: cell.dateKey + (cell.inMonth ? '' : '-o'),
type: 'button',
+ className: dayClass,
disabled: cell.isFuture,
onClick: function () {
if (cell.isFuture) return;
setManualSelectedDate(cell.dateKey);
},
- 'aria-label': cell.dateKey + statusLabel,
- style: {
- appearance: 'none',
- WebkitAppearance: 'none',
- border: border,
- borderRadius: 8,
- background: bg,
- color: color,
- cursor: cell.isFuture ? 'not-allowed' : 'pointer',
- padding: '8px 0 6px',
- minHeight: 44,
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'center',
- justifyContent: 'center',
- gap: 4,
- fontWeight: cell.isToday || selected ? 700 : 500,
- fontVariantNumeric: 'tabular-nums'
- }
+ 'aria-label': cell.dateKey + statusLabel
},
React.createElement('span', null, cell.day),
cell.inMonth && cell.needsLedger
? React.createElement('i', {
- 'aria-hidden': true,
- style: {
- display: 'block',
- width: 6,
- height: 6,
- borderRadius: '50%',
- background: cell.uploaded ? '#10b981' : '#fb923c'
- }
+ className: 'hr-manual-cal-dot' + (cell.uploaded ? ' is-on' : ''),
+ 'aria-hidden': true
})
: React.createElement('span', { style: { height: 6 } })
);
})),
- React.createElement('div', {
- style: {
- display: 'flex',
- gap: 16,
- marginTop: 12,
- fontSize: 12,
- color: '#64748b'
- }
- },
+ React.createElement('div', { className: 'hr-manual-cal-legend' },
React.createElement('span', null,
- React.createElement('i', {
- style: {
- display: 'inline-block',
- width: 8,
- height: 8,
- borderRadius: '50%',
- background: '#10b981',
- marginRight: 6,
- verticalAlign: 'middle'
- }
- }),
+ React.createElement('i', { style: { background: '#10b981' } }),
'已上传'
),
React.createElement('span', null,
- React.createElement('i', {
- style: {
- display: 'inline-block',
- width: 8,
- height: 8,
- borderRadius: '50%',
- background: '#fb923c',
- marginRight: 6,
- verticalAlign: 'middle'
- }
- }),
+ React.createElement('i', { style: { background: '#fb923c' } }),
'未上传'
)
)
)
),
- React.createElement(Col, { xs: 24, lg: 12 },
- React.createElement('div', {
- style: {
- border: '1px solid #e2e8f0',
- borderRadius: 12,
- padding: 16,
- background: '#fff',
- minHeight: 320
- }
- },
- React.createElement('div', { style: { fontWeight: 700, marginBottom: 4, fontSize: 15 } },
- '上传 ' + manualSelectedDate + (manualSelectedDate === manualTodayKey ? '(今日)' : '')
+ React.createElement('div', { className: 'hr-manual-side', 'data-annotation-id': 'hr-manual-upload-panel' },
+ React.createElement('div', { className: 'hr-manual-side-card' },
+ React.createElement('div', { className: 'hr-manual-panel-head' },
+ React.createElement('div', { className: 'hr-manual-side-card__eyebrow' }, '当日台账'),
+ React.createElement('h3', { className: 'hr-manual-panel-title' }, '手工台账'),
+ React.createElement('div', { className: 'hr-manual-panel-meta' },
+ manualSelectedDate
+ + (manualSelectedDate === manualTodayKey ? ' · 今日' : '')
+ + (manualDraftImages.length ? ' · ' + manualDraftImages.length + ' 张' : '')
+ ),
+ React.createElement('div', {
+ 'data-annotation-id': 'hr-manual-today-status',
+ className: 'hr-manual-status ' + (manualTodayUploaded ? 'is-ok' : 'is-warn'),
+ role: 'status'
+ },
+ React.createElement('span', {
+ className: 'hr-manual-status__icon',
+ 'aria-hidden': true
+ },
+ React.createElement('svg', {
+ width: 14,
+ height: 14,
+ viewBox: '0 0 24 24',
+ fill: 'none',
+ stroke: 'currentColor',
+ strokeWidth: 2.4,
+ strokeLinecap: 'round',
+ strokeLinejoin: 'round'
+ }, manualTodayUploaded
+ ? React.createElement('polyline', { points: '20 6 9 17 4 12' })
+ : React.createElement(React.Fragment, null,
+ React.createElement('circle', { cx: 12, cy: 12, r: 10 }),
+ React.createElement('line', { x1: 12, y1: 8, x2: 12, y2: 12 }),
+ React.createElement('line', { x1: 12, y1: 16, x2: 12.01, y2: 16 })
+ ))
+ ),
+ React.createElement('span', null, manualTodayUploaded
+ ? '今日已上传手工台账(' + manualTodayKey + ')'
+ : '今日尚未上传手工台账(' + manualTodayKey + ')')
+ ),
+ React.createElement('p', { className: 'hr-manual-panel-sub' },
+ manualSelectedDate > manualTodayKey
+ ? '不能上传未来日期'
+ : (manualSelectedUploaded
+ ? '该日已归档,可继续补传新图;点击照片可全屏翻页预览'
+ : '请上传清晰的纸质台账照片,可多张;确认提交后归档不可修改')
+ )
),
React.createElement('div', {
- style: { fontSize: 13, color: '#64748b', marginBottom: 14 }
- }, manualSelectedDate > manualTodayKey
- ? '不能上传未来日期'
- : (manualSelectedUploaded
- ? '该日台账已归档,仅可补传新图,不可删除'
- : '请拍摄清晰的纸质台账照片,可多张;确认后归档不可删')),
- React.createElement(Upload, {
- accept: 'image/*',
- multiple: true,
- showUploadList: false,
- disabled: manualSelectedDate > manualTodayKey,
- beforeUpload: function (file, fileList) {
- if (file === fileList[0]) handleManualUploadFiles(fileList);
- return false;
- }
+ className: 'hr-manual-preview',
+ 'aria-label': '台账照片预览区'
},
+ manualDraftImages.length
+ ? React.createElement('div', { className: 'hr-manual-preview-grid' },
+ React.createElement(Image.PreviewGroup, null,
+ manualDraftImages.map(function (img) {
+ var archived = Boolean(img.archived || img.placeholder);
+ return React.createElement('div', {
+ key: img.id,
+ className: 'hr-manual-thumb'
+ },
+ React.createElement('span', {
+ className: 'hr-manual-thumb__badge' + (archived ? '' : ' is-draft')
+ }, archived ? '已归档' : '待提交'),
+ img.dataUrl
+ ? React.createElement(Image, {
+ src: img.dataUrl,
+ width: 120,
+ height: 90,
+ style: { objectFit: 'cover' },
+ alt: img.name || '台账照片'
+ })
+ : React.createElement('div', { className: 'hr-manual-thumb__ph' }, '无预览'),
+ React.createElement('div', { className: 'hr-manual-thumb__actions' },
+ archived
+ ? React.createElement('span', {
+ style: { fontSize: 11, color: '#94a3b8', fontWeight: 600, lineHeight: '30px' }
+ }, '不可删除')
+ : React.createElement(Button, {
+ type: 'link',
+ danger: true,
+ size: 'small',
+ onClick: function () {
+ setManualDraftImages(function (prev) {
+ return prev.filter(function (x) {
+ return x.id !== img.id;
+ });
+ });
+ }
+ }, '删除')
+ )
+ );
+ })
+ ),
+ React.createElement(Upload, {
+ accept: 'image/*',
+ multiple: true,
+ showUploadList: false,
+ disabled: manualSelectedDate > manualTodayKey,
+ beforeUpload: function (file, fileList) {
+ if (file === fileList[0]) handleManualUploadFiles(fileList);
+ return false;
+ }
+ },
+ React.createElement('button', {
+ type: 'button',
+ className: 'hr-manual-upload-tile' + (manualSelectedDate > manualTodayKey ? ' is-disabled' : ''),
+ disabled: manualSelectedDate > manualTodayKey,
+ 'aria-label': '上传台账照片'
+ },
+ React.createElement('span', { className: 'hr-manual-upload-tile__plus', 'aria-hidden': true }, '+'),
+ React.createElement('span', null, '继续上传')
+ )
+ )
+ )
+ : React.createElement(React.Fragment, null,
+ React.createElement('div', { className: 'hr-manual-preview-empty' },
+ React.createElement('div', {
+ className: 'hr-manual-preview-empty__icon',
+ 'aria-hidden': true
+ },
+ React.createElement('svg', {
+ width: 26,
+ height: 26,
+ viewBox: '0 0 24 24',
+ fill: 'none',
+ stroke: 'currentColor',
+ strokeWidth: 1.8,
+ strokeLinecap: 'round',
+ strokeLinejoin: 'round'
+ },
+ React.createElement('path', { d: 'M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z' }),
+ React.createElement('circle', { cx: 12, cy: 13, r: 4 })
+ )
+ ),
+ React.createElement('div', { className: 'hr-manual-preview-empty__title' }, '暂无台账照片'),
+ React.createElement('div', { className: 'hr-manual-preview-empty__desc' },
+ '请拍摄或选择清晰的纸质台账照片,可多张;确认提交后将归档且不可修改')
+ ),
+ React.createElement(Upload, {
+ accept: 'image/*',
+ multiple: true,
+ showUploadList: false,
+ disabled: manualSelectedDate > manualTodayKey,
+ beforeUpload: function (file, fileList) {
+ if (file === fileList[0]) handleManualUploadFiles(fileList);
+ return false;
+ },
+ style: { alignSelf: 'center' }
+ },
+ React.createElement(Button, {
+ type: 'default',
+ style: { borderRadius: 10, minHeight: 40, fontWeight: 600 },
+ disabled: manualSelectedDate > manualTodayKey
+ }, '拍照 / 选择图片')
+ )
+ )
+ ),
+ React.createElement('div', { className: 'hr-manual-panel-footer' },
React.createElement(Button, {
- style: { borderRadius: 8, marginBottom: 12 },
- disabled: manualSelectedDate > manualTodayKey
- }, '拍照 / 选择图片')
- ),
- React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 12, marginBottom: 16 } },
- manualDraftImages.map(function (img) {
- var archived = Boolean(img.archived || img.placeholder);
- return React.createElement('div', {
- key: img.id,
- style: {
- width: 120,
- border: '1px solid #e2e8f0',
- borderRadius: 10,
- overflow: 'hidden',
- background: '#f8fafc',
- position: 'relative'
- }
- },
- img.dataUrl
- ? React.createElement(Image, { src: img.dataUrl, width: 120, height: 90, style: { objectFit: 'cover' } })
- : React.createElement('div', {
- style: {
- width: 120,
- height: 90,
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- color: '#94a3b8',
- fontSize: 12,
- fontWeight: 600
- }
- }, '已归档'),
- archived
- ? React.createElement('div', {
- style: {
- textAlign: 'center',
- padding: '4px 0',
- fontSize: 12,
- fontWeight: 600,
- color: '#64748b',
- background: '#f1f5f9'
- }
- }, '已归档')
- : React.createElement(Button, {
- type: 'link',
- danger: true,
- size: 'small',
- onClick: function () {
- setManualDraftImages(function (prev) {
- return prev.filter(function (x) {
- return x.id !== img.id;
- });
- });
- }
- }, '删除')
- );
- })
- ),
- React.createElement(Button, {
- type: 'primary',
- style: HR_PRIMARY_BTN_STYLE,
- onClick: handleManualSave,
- disabled: manualSelectedDate > manualTodayKey || (
- manualSelectedUploaded
- ? !manualDraftImages.some(function (img) { return !(img.archived || img.placeholder); })
- : !manualDraftImages.length
- )
- }, manualSelectedUploaded
- ? '确认补传 ' + manualSelectedDate
- : '确认上传 ' + manualSelectedDate)
+ type: 'primary',
+ style: HR_PRIMARY_BTN_STYLE,
+ onClick: handleManualSave,
+ disabled: manualSelectedDate > manualTodayKey || (
+ manualSelectedUploaded
+ ? !manualDraftImages.some(function (img) { return !(img.archived || img.placeholder); })
+ : !manualDraftImages.length
+ )
+ }, manualSelectedUploaded ? '确认补传' : '确认上传'),
+ React.createElement('div', { className: 'hr-manual-panel-footer__hint' },
+ '提交前将二次确认;确认后照片标记为「已归档」且不可删除')
+ )
)
)
)
)
- ) : listMainTab === 'appointments' ? renderAppointmentPanel()
- : React.createElement(React.Fragment, null,
+ ) : React.createElement(React.Fragment, null,
!manualTodayUploaded && activeManualStation ? React.createElement('div', {
style: {
marginBottom: 12,
@@ -2711,137 +2722,177 @@ const Component = function () {
tabIndex: 0
}, '今日尚未上传手工台账(' + activeManualStation + '),点击前往上传;未上传不可新增电子记录') : null,
React.createElement(Card, { className: 'lc-filter-card', title: '筛选条件', bordered: false },
- React.createElement('div', { className: 'lc-filter-grid' },
- renderFilterField('加氢时间', React.createElement(DateRangeFilterField, {
- startDate: draftFilters.startDate || '',
- endDate: draftFilters.endDate || '',
- startPlaceholder: '开始日期',
- endPlaceholder: '结束日期',
- ariaLabel: '加氢时间',
- onChange: function (range) {
- setDraftFilters(function (p) {
- return Object.assign({}, p, {
- startDate: range.startDate || '',
- endDate: range.endDate || ''
- });
- });
- }
- })),
- renderFilterField('车牌号', React.createElement(Select, {
- placeholder: '请选择车牌号',
- allowClear: true,
- showSearch: true,
- optionFilterProp: 'label',
- value: draftFilters.plateNo,
- options: plateOptions,
- onChange: function (v) { setDraftFilters(function (p) { return Object.assign({}, p, { plateNo: v }); }); },
- style: { width: '100%' },
- dropdownStyle: { borderRadius: 8 }
- })),
- renderFilterField('加氢站', React.createElement(Select, {
- placeholder: '请选择加氢站',
- allowClear: true,
- showSearch: true,
- optionFilterProp: 'label',
- value: draftFilters.stationName,
- options: stationOptions,
- onChange: function (v) { setDraftFilters(function (p) { return Object.assign({}, p, { stationName: v }); }); },
- style: { width: '100%' },
- dropdownStyle: { borderRadius: 8 }
- })),
- renderFilterField('对账状态', React.createElement(Select, {
- placeholder: '请选择对账状态',
- allowClear: true,
- value: draftFilters.reconcileStatus,
- options: [
- { value: 'pending', label: '未对账' },
- { value: 'reconciled', label: '已对账' }
- ],
- onChange: function (v) { setDraftFilters(function (p) { return Object.assign({}, p, { reconcileStatus: v }); }); },
- style: { width: '100%' },
- dropdownStyle: { borderRadius: 8 }
- }))
+ React.createElement('div', { className: 'lc-filter-body vm-filter-body' },
+ React.createElement('div', { className: 'lc-filter-grid vm-filter-grid--primary', 'data-filter-tier': 'primary' },
+ filterSplit.primary.map(renderFilterField)
+ ),
+ showFilterExpand
+ ? React.createElement('div', {
+ className: 'vm-filter-expand' + (filterExpanded ? ' is-expanded' : ''),
+ 'aria-hidden': !filterExpanded,
+ id: 'hr-filter-expand-panel'
+ },
+ React.createElement('div', { className: 'vm-filter-expand-inner' },
+ React.createElement('div', { className: 'lc-filter-grid', 'data-filter-tier': 'extra' },
+ filterExpanded ? filterSplit.extra.map(renderFilterField) : null
+ )
+ )
+ )
+ : null
),
- React.createElement('div', { className: 'lc-filter-actions' },
+ React.createElement('div', { className: 'lc-filter-actions vm-filter-actions' },
+ showFilterExpand
+ ? React.createElement('button', {
+ type: 'button',
+ className: 'vm-btn vm-btn-link vm-filter-toggle',
+ onClick: function () { setFilterExpanded(!filterExpanded); },
+ 'aria-expanded': filterExpanded,
+ 'aria-controls': 'hr-filter-expand-panel',
+ 'data-vm-icon': filterExpanded ? 'chevron-up' : 'filter'
+ },
+ filterExpanded ? '收起' : '更多筛选',
+ !filterExpanded && extraFilterActiveCount > 0
+ ? React.createElement('span', {
+ className: 'vm-filter-toggle-badge',
+ 'aria-label': '已设置 ' + extraFilterActiveCount + ' 项扩展筛选'
+ }, String(extraFilterActiveCount))
+ : null
+ )
+ : null,
React.createElement(Button, { onClick: handleFilterReset, style: { borderRadius: 8 } }, '重置'),
React.createElement(Button, { type: 'primary', onClick: handleFilterQuery, style: HR_PRIMARY_BTN_STYLE }, '查询')
)
),
- React.createElement('div', { className: 'hr-daily-stats-section' },
+ React.createElement('div', {
+ className: 'hr-daily-stats-section' + (dailyStatsExpanded ? ' is-expanded' : ''),
+ 'data-annotation-id': 'hr-daily-stats'
+ },
React.createElement('div', { className: 'hr-daily-stats-head' },
- React.createElement('span', { className: 'hr-daily-stats-head__title' }, '每日统计'),
- React.createElement('span', { className: 'hr-daily-stats-head__meta tabular-nums' },
- '近30天(含今天)· '
- + dailyStatsSummary.rangeStart + ' 至 ' + dailyStatsSummary.rangeEnd
- + ' · 加氢总量 ' + hrFormatKg(dailyStatsSummary.totalKg) + ' kg'
+ React.createElement('div', { className: 'hr-daily-stats-head__left' },
+ React.createElement('div', { className: 'hr-daily-stats-head__title-row' },
+ React.createElement('span', { className: 'hr-daily-stats-head__title' }, '每日统计'),
+ React.createElement('span', { className: 'hr-daily-stats-head__range tabular-nums' },
+ '近30天 · ' + dailyStatsSummary.rangeStart + ' 至 ' + dailyStatsSummary.rangeEnd
+ )
+ ),
+ React.createElement('div', { className: 'hr-daily-stats-kpis', 'aria-label': '近30天汇总' },
+ React.createElement('div', { className: 'hr-daily-stats-kpi' },
+ React.createElement('span', { className: 'hr-daily-stats-kpi__label' }, '加氢总量'),
+ React.createElement('span', { className: 'hr-daily-stats-kpi__value' }, hrFormatKg(dailyStatsSummary.totalKg) + ' kg')
+ ),
+ React.createElement('div', { className: 'hr-daily-stats-kpi hr-daily-stats-kpi--primary' },
+ React.createElement('span', { className: 'hr-daily-stats-kpi__label' }, '加氢总额'),
+ React.createElement('span', { className: 'hr-daily-stats-kpi__value' }, hrFormatYuanSymbol(dailyStatsSummary.totalAmount))
+ ),
+ React.createElement('div', { className: 'hr-daily-stats-kpi' },
+ React.createElement('span', { className: 'hr-daily-stats-kpi__label' }, '记录条数'),
+ React.createElement('span', { className: 'hr-daily-stats-kpi__value' }, String(dailyStatsSummary.totalCount) + ' 条')
+ )
+ )
+ ),
+ React.createElement('div', { className: 'hr-daily-stats-head__right' },
+ dailyStatsExpanded
+ ? React.createElement('div', { className: 'hr-daily-stats-pager' },
+ React.createElement(Button, {
+ type: 'default',
+ className: 'hr-daily-stats-nav-btn',
+ disabled: dailyStatsPage >= HR_DAILY_STATS_MAX_PAGE,
+ onClick: function () { setDailyStatsPage(function (p) { return Math.min(HR_DAILY_STATS_MAX_PAGE, p + 1); }); },
+ 'aria-label': '查看更早的7天'
+ }, '‹'),
+ React.createElement('span', {
+ className: 'hr-daily-stats-pager__label tabular-nums',
+ 'aria-live': 'polite'
+ }, (dailyStatsPage + 1) + ' / ' + dailyStatsPageCount),
+ React.createElement(Button, {
+ type: 'default',
+ className: 'hr-daily-stats-nav-btn',
+ disabled: dailyStatsPage <= 0,
+ onClick: function () { setDailyStatsPage(function (p) { return Math.max(0, p - 1); }); },
+ 'aria-label': '查看更近的7天'
+ }, '›')
+ )
+ : null,
+ React.createElement(Button, {
+ type: 'default',
+ className: 'hr-daily-stats-toggle',
+ onClick: function () { setDailyStatsExpanded(function (v) { return !v; }); },
+ 'aria-expanded': dailyStatsExpanded,
+ 'aria-label': dailyStatsExpanded ? '收起每日统计明细' : '展开每日统计明细'
+ }, dailyStatsExpanded ? '收起' : '展开明细')
)
),
- React.createElement('div', { className: 'hr-daily-stats-carousel' },
- React.createElement(Button, {
- type: 'default',
- className: 'hr-daily-stats-nav-btn',
- disabled: dailyStatsPage >= HR_DAILY_STATS_MAX_PAGE,
- onClick: function () { setDailyStatsPage(function (p) { return Math.min(HR_DAILY_STATS_MAX_PAGE, p + 1); }); },
- 'aria-label': '向左翻页,查看更早的7天'
- }, '‹'),
- React.createElement('div', { className: 'hr-daily-stats-track', role: 'group', 'aria-label': '每日加氢统计' },
+ dailyStatsExpanded
+ ? React.createElement('div', { className: 'hr-daily-stats-track', role: 'group', 'aria-label': '每日加氢统计' },
dailyStatsPageItems.map(function (item) {
+ var empty = !item.count;
return React.createElement('div', {
key: item.date,
- className: 'hr-daily-stat-card' + (item.isToday ? ' hr-daily-stat-card--today' : ''),
+ className: 'hr-daily-stat-card'
+ + (item.isToday ? ' hr-daily-stat-card--today' : '')
+ + (empty ? ' hr-daily-stat-card--empty' : ''),
role: 'article',
'aria-label': item.date
- + ' 数据条数 总数 ' + item.count
+ + ' 星期' + (item.weekday || '')
+ + ',加氢量 ' + hrFormatKg(item.totalKg) + ' kg'
+ + ',加氢总额 ' + hrFormatYuan(item.totalAmount) + ' 元'
+ + ',共 ' + item.count + ' 条'
+ ',已核对 ' + item.verifiedCount
+ ',已对账 ' + item.reconciledCount
- + ',加氢量 ' + hrFormatKg(item.totalKg) + ' kg,加氢总额 '
- + hrFormatYuan(item.totalAmount) + ' 元'
},
React.createElement('div', { className: 'hr-daily-stat-card__date' },
- React.createElement('span', { className: 'tabular-nums' }, item.dateLabel),
- item.isToday ? React.createElement('span', { className: 'hr-daily-stat-card__today-tag' }, '今天') : null
- ),
- React.createElement('div', { className: 'hr-daily-stat-card__metrics' },
- React.createElement('div', { className: 'hr-daily-stat-card__count-block' },
- React.createElement('span', { className: 'hr-daily-stat-card__count-title' }, '数据条数'),
- React.createElement('div', { className: 'hr-daily-stat-card__count-row' },
- React.createElement('div', { className: 'hr-daily-stat-card__count-item' },
- React.createElement('span', { className: 'hr-daily-stat-card__count-item-label' }, '总数'),
- React.createElement('span', { className: 'hr-daily-stat-card__value hr-daily-stat-card__value--count tabular-nums' }, String(item.count))
- ),
- React.createElement('div', { className: 'hr-daily-stat-card__count-item' },
- React.createElement('span', { className: 'hr-daily-stat-card__count-item-label' }, '已核对'),
- React.createElement('span', { className: 'hr-daily-stat-card__value hr-daily-stat-card__value--verified tabular-nums' }, String(item.verifiedCount))
- ),
- React.createElement('div', { className: 'hr-daily-stat-card__count-item' },
- React.createElement('span', { className: 'hr-daily-stat-card__count-item-label' }, '已对账'),
- React.createElement('span', { className: 'hr-daily-stat-card__value hr-daily-stat-card__value--reconciled tabular-nums' }, String(item.reconciledCount))
- )
- )
+ React.createElement('div', { className: 'hr-daily-stat-card__date-main' },
+ React.createElement('span', { className: 'hr-daily-stat-card__date-num' }, item.dateLabel),
+ React.createElement('span', { className: 'hr-daily-stat-card__weekday' }, '周' + (item.weekday || ''))
),
- React.createElement('div', { className: 'hr-daily-stat-card__metrics-bottom' },
- React.createElement('div', { className: 'hr-daily-stat-card__metric' },
- React.createElement('span', { className: 'hr-daily-stat-card__label' }, '加氢量'),
- React.createElement('span', { className: 'hr-daily-stat-card__value hr-daily-stat-card__value--kg tabular-nums' }, hrFormatKg(item.totalKg))
+ item.isToday
+ ? React.createElement('span', { className: 'hr-daily-stat-card__today-tag' }, '今天')
+ : null
+ ),
+ React.createElement('div', { className: 'hr-daily-stat-card__hero' },
+ React.createElement('span', { className: 'hr-daily-stat-card__hero-label' }, '加氢量'),
+ React.createElement('div', null,
+ React.createElement('span', {
+ className: 'hr-daily-stat-card__hero-value' + (empty ? ' is-empty' : '')
+ }, hrFormatKg(item.totalKg)),
+ React.createElement('span', { className: 'hr-daily-stat-card__hero-unit' }, 'kg')
+ )
+ ),
+ React.createElement('div', {
+ className: 'hr-daily-stat-card__amount' + (empty ? ' is-empty' : '')
+ }, hrFormatYuanSymbol(item.totalAmount || 0)),
+ React.createElement('div', {
+ className: 'hr-daily-stat-card__footer',
+ 'aria-label': '当日记录与核对对账情况'
+ },
+ React.createElement('div', { className: 'hr-daily-stat-card__status-grid' },
+ React.createElement('div', {
+ className: 'hr-daily-stat-card__status-item' + (empty ? ' is-muted' : '')
+ },
+ React.createElement('span', { className: 'hr-daily-stat-card__status-label' }, '记录'),
+ React.createElement('span', { className: 'hr-daily-stat-card__status-value' }, String(item.count))
),
- React.createElement('div', { className: 'hr-daily-stat-card__metric' },
- React.createElement('span', { className: 'hr-daily-stat-card__label' }, '加氢总额'),
- React.createElement('span', { className: 'hr-daily-stat-card__value hr-daily-stat-card__value--amount tabular-nums' }, hrFormatYuan(item.totalAmount))
+ React.createElement('div', {
+ className: 'hr-daily-stat-card__status-item'
+ + (item.verifiedCount > 0 ? ' is-ok' : (empty ? ' is-muted' : ''))
+ },
+ React.createElement('span', { className: 'hr-daily-stat-card__status-label' }, '已核对'),
+ React.createElement('span', { className: 'hr-daily-stat-card__status-value' }, String(item.verifiedCount))
+ ),
+ React.createElement('div', {
+ className: 'hr-daily-stat-card__status-item'
+ + (item.reconciledCount > 0 ? ' is-ok' : (empty ? ' is-muted' : ''))
+ },
+ React.createElement('span', { className: 'hr-daily-stat-card__status-label' }, '已对账'),
+ React.createElement('span', { className: 'hr-daily-stat-card__status-value' }, String(item.reconciledCount))
)
)
)
);
})
- ),
- React.createElement(Button, {
- type: 'default',
- className: 'hr-daily-stats-nav-btn',
- disabled: dailyStatsPage <= 0,
- onClick: function () { setDailyStatsPage(function (p) { return Math.max(0, p - 1); }); },
- 'aria-label': '向右翻页,查看更近的7天'
- }, '›')
- )
+ )
+ : null
),
React.createElement('div', { className: 'lc-table-section' },
@@ -2869,7 +2920,7 @@ const Component = function () {
columns: columns,
dataSource: pagedList,
size: 'middle',
- scroll: { x: 1280 },
+ scroll: { x: 1680 },
pagination: false,
locale: { emptyText: emptyNode }
}),
@@ -2918,42 +2969,65 @@ const Component = function () {
}, '确定删除该条加氢记录吗?车牌号「' + ((deleteModal.record && deleteModal.record.plateNo) || '') + '」,此操作不可撤销。'),
React.createElement(Modal, {
- title: '拒绝预约',
- open: rejectModal.open,
+ title: '变更日志' + (changeLogModal.record && changeLogModal.record.plateNo
+ ? ' · ' + hrFormatPlateDisplay(changeLogModal.record.plateNo)
+ : ''),
+ open: changeLogModal.open,
centered: true,
- width: 480,
- onCancel: closeRejectModal,
- onOk: handleConfirmRejectAppointment,
- okText: '确认拒绝',
- cancelText: '取消',
- okButtonProps: { danger: true },
+ width: 720,
+ footer: null,
+ onCancel: function () { setChangeLogModal({ open: false, record: null }); },
destroyOnClose: true
},
- React.createElement('div', { style: { marginBottom: 12, fontSize: 13, color: '#475569', lineHeight: 1.6 } },
- '加氢站:',
- React.createElement('strong', { style: { color: '#0f172a' } }, (rejectModal.record && rejectModal.record.stationName) || '—'),
- ' · 车牌号:',
- React.createElement('strong', { style: { color: '#0f172a' } }, (rejectModal.record && rejectModal.record.plateNo) || '—'),
- ' · 预约时间:',
- React.createElement('span', { style: { fontVariantNumeric: 'tabular-nums' } }, (rejectModal.record && rejectModal.record.appointmentTime) || '—')
- ),
- React.createElement(Form, { layout: 'vertical', requiredMark: false },
- React.createElement(Form.Item, {
- label: React.createElement('span', null, React.createElement('span', { style: { color: '#ef4444', marginRight: 4 } }, '*'), '拒绝原因')
- },
- React.createElement(Input.TextArea, {
- placeholder: '请填写拒绝原因,将通知预约司机',
- value: rejectModal.reason,
- rows: 4,
- maxLength: 200,
- showCount: true,
- style: { borderRadius: 8 },
- onChange: function (e) {
- setRejectModal(function (m) { return Object.assign({}, m, { reason: e.target.value }); });
+ React.createElement(Table, {
+ size: 'small',
+ rowKey: 'id',
+ pagination: ((changeLogModal.record && changeLogModal.record.changeLogs) || []).length > 8
+ ? { pageSize: 8, showSizeChanger: false }
+ : false,
+ locale: { emptyText: '暂无变更记录' },
+ dataSource: (changeLogModal.record && changeLogModal.record.changeLogs) || [],
+ columns: [
+ {
+ title: '时间',
+ dataIndex: 'at',
+ key: 'at',
+ width: 148,
+ render: function (v) {
+ return React.createElement('span', { className: 'tabular-nums' }, hrFormatReconcileTime(v));
}
- })
- )
- )
+ },
+ {
+ title: '操作人',
+ key: 'operator',
+ width: 88,
+ render: function (_, row) { return row.operatorName || row.userName || '—'; }
+ },
+ {
+ title: '修改项',
+ dataIndex: 'fieldLabel',
+ key: 'fieldLabel',
+ width: 100,
+ render: function (v) { return v || '—'; }
+ },
+ {
+ title: '原值',
+ key: 'oldValue',
+ width: 120,
+ render: function (_, row) {
+ return React.createElement('span', { style: { color: '#dc2626' } }, row.oldValue || row.before || '—');
+ }
+ },
+ {
+ title: '新值',
+ key: 'newValue',
+ width: 120,
+ render: function (_, row) {
+ return React.createElement('span', { style: { color: '#059669' } }, row.newValue || row.after || '—');
+ }
+ }
+ ]
+ })
)
);
};
diff --git a/src/prototypes/oneos-web-h2-station/pages/README.md b/src/prototypes/oneos-web-h2-station/pages/README.md
index 3c44a28..cf1c89e 100644
--- a/src/prototypes/oneos-web-h2-station/pages/README.md
+++ b/src/prototypes/oneos-web-h2-station/pages/README.md
@@ -2,7 +2,7 @@
| 文件 | 说明 |
|---|---|
-| `02-加氢记录.jsx` | 本原型唯一页面:PC 加氢流水台账(含导出、预约加氢) |
+| `02-加氢记录.jsx` | 本原型唯一页面:PC 加氢流水台账(含导出、手工台账) |
## 菜单分工(加氢站管理)
diff --git a/src/prototypes/vehicle-h2-fee-ledger/.spec/PRD.md b/src/prototypes/vehicle-h2-fee-ledger/.spec/PRD.md
index fa9b30b..4f5d770 100644
--- a/src/prototypes/vehicle-h2-fee-ledger/.spec/PRD.md
+++ b/src/prototypes/vehicle-h2-fee-ledger/.spec/PRD.md
@@ -6,7 +6,7 @@
| 产品模块 | 台账数据 → 车辆氢费明细 |
| 文档类型 | 产品需求说明 |
| 适用读者 | 产品、业务、运营、测试、项目 |
-| 修订说明 | v2.4:核对 vs 对账双状态——「完成核对」≠ 对账结案;对账仅由加氢站对账单提交回写 |
+| 修订说明 | v2.5:记录来源标签(站端上传/羚牛上传);核对人/对账人;变更日志挂行级字段 |
| 双状态规格 | [verify-reconcile.md](./verify-reconcile.md) |
---
@@ -162,7 +162,7 @@ flowchart LR
- **说明:** 合计条含「待保存 / 未对账 / 已对账」等当前列表中的全部可见记录,与导出范围(仅未对账+已对账)不同。
**列表列顺序(左→右,业务视角):**
-序号 → 加氢日期 → 加氢时间 → 加氢站名称 → 客户名称 → 车牌号 → 加氢量 → 成本单价 → 成本总价 → 加氢单价 → 加氢总价 → 行驶里程 → 备注 → 业务员 → 承担方式 → 对账日期 → **收票日期** → **加氢站付款状态** → **开票日期** → **客户收款状态** → **开票公司** → 状态 → 订单编号 → 操作(操作列固定右侧)。
+序号 → 加氢日期 → 加氢时间 → 加氢站名称 → 客户名称 → 车牌号(下来源标签:站端上传 / 羚牛上传)→ 加氢量 → 成本单价 → 成本总价 → 加氢单价 → 加氢总价 → 行驶里程 → 备注 → 业务员 → 承担方式 → 对账日期 → **对账人** → **收票日期** → **加氢站付款状态** → **开票日期** → **客户收款状态** → **开票公司** → 核对状态 → **核对时间** → **核对人** → 对账状态 → 订单编号 → 操作(操作列固定右侧)。
**系统带出字段(不可手工维护):** 收票日期、加氢站付款状态、开票日期、客户收款状态、开票公司;选择/变更客户等信息后由系统自动刷新,单元格为浅灰底只读样式。
@@ -202,7 +202,10 @@ flowchart LR
| 备注 | 否 | 自由文本 |
| 业务员 | 否 | 选客户后自动带出 |
| 承担方式 | 是* | 客户承担 / 我司承担 / 客户自行结算 / 其他结算 |
-| 对账日期 | 否 | 完成对账等流程带出,只读 |
+| 对账日期 | 否 | 对账单提交回写,只读 |
+| 对账人 | 否 | 对账单提交操作员姓名,只读 |
+| 核对时间 | 否 | 「完成核对」写入,只读 |
+| 核对人 | 否 | 「完成核对」操作员姓名,只读 |
| 收票日期 | 否 | 由财务/收票模块自动带出,不可编辑 |
| 加氢站付款状态 | 否 | 已付款 / 未付款,由加氢站打款管理带出 |
| 开票日期 | 否 | 由开票模块自动带出 |
@@ -379,23 +382,30 @@ flowchart LR
---
-## 九、变更日志
+## 九、变更日志与来源
+
+### 9.0 记录来源标签
+
+| 来源 | 标签 | 场景 |
+|---|---|---|
+| 站端主动上报 | **站端上传** | 加氢站 H5/Web 写入共享账本 |
+| 台账人工录入 | **羚牛上传** | 本页新增 / 复制 / 导入 |
### 9.1 记录什么
-满足审计与纠纷查证,以下变化需留痕:
+满足审计与纠纷查证,以下变化需留痕(写入行级 `changeLogs`,并与加氢记录 Web 同源):
- 保存(待保存 → 未对账)
-- 完成对账(未对账 → 已对账)
+- 完成核对(未核对 → 已核对)
- 各业务字段修改(前后值不同)
- **成本单价(一键替换)**、**客户名称(一键替换)**
-- 新增、复制、批量导入产生记录
+- 站端编辑加氢量/单价等(Bridge 自动追加)
### 9.2 怎么查看
在操作列点击 **「更多」→ 变更日志**,弹窗展示:
-- 修改时间、修改人、修改字段、修改前(红)、修改后(绿)
+- 修改时间、操作人、修改项、原值(红)、新值(绿)
- 按时间倒序排列
---
diff --git a/src/prototypes/vehicle-h2-fee-ledger/H2LedgerPage.jsx b/src/prototypes/vehicle-h2-fee-ledger/H2LedgerPage.jsx
index d1083b7..84dbe88 100644
--- a/src/prototypes/vehicle-h2-fee-ledger/H2LedgerPage.jsx
+++ b/src/prototypes/vehicle-h2-fee-ledger/H2LedgerPage.jsx
@@ -1782,6 +1782,7 @@ const Component = function () {
key: nextRowKey(),
createdBy: CURRENT_USER.id,
creatorName: CURRENT_USER.name,
+ recordSource: 'lingniu',
orderNo: '',
hydrogenTime: parseImportDate(get('加氢时间')) || now,
stationId: station ? station.value : undefined,
@@ -1799,7 +1800,10 @@ const Component = function () {
settlementStatus: SETTLEMENT_LABEL_TO_VALUE[settlementLabel] || 'customer',
remark: get('备注'),
createdAt: now,
- reconcileStatus: null
+ reconcileStatus: null,
+ changeLogs: [],
+ verifiedByName: '',
+ reconciledByName: ''
};
return Object.assign({}, draft, resolveLinkedModuleFields(draft));
}
@@ -2598,6 +2602,7 @@ const Component = function () {
key: nextRowKey(),
createdBy: CURRENT_USER.id,
creatorName: CURRENT_USER.name,
+ recordSource: 'lingniu',
orderNo: '',
hydrogenTime: cloneRowTimeValue(sourceRow.hydrogenTime),
stationId: sourceRow.stationId,
@@ -2624,7 +2629,10 @@ const Component = function () {
verifyStatus: null,
savedAt: null,
verifiedAt: null,
- reconciledAt: null
+ verifiedByName: '',
+ reconciledAt: null,
+ reconciledByName: '',
+ changeLogs: []
};
return recalcAllRows([draft])[0];
}
@@ -2961,11 +2969,22 @@ const Component = function () {
receiptDate: patch.receiptDate,
receiptAmount: patch.receiptAmount != null ? patch.receiptAmount : r.receiptAmount,
stationPaymentStatus: patch.paymentStatus || 'paid',
- paymentStatus: patch.paymentStatus || 'paid'
+ paymentStatus: patch.paymentStatus || 'paid',
+ reconciledByName: patch.reconciler || patch.reconciledByName || r.reconciledByName || ''
});
});
}
+ function recordSourceLabel(row) {
+ if (!row) return '羚牛上传';
+ if (row.recordSource === 'station') return '站端上传';
+ if (row.recordSource === 'lingniu') return '羚牛上传';
+ var creator = String(row.creatorName || '').trim();
+ var customer = String(row.customerName || '');
+ if (creator === '站端账号' || customer.indexOf('·站端上报') >= 0) return '站端上传';
+ return '羚牛上传';
+ }
+
function recalcRowFields(row) {
var mileage = normalizeMileageKm(row.mileageKm);
var kg = isEmptyNum(row.hydrogenKg) ? null : roundMoney(row.hydrogenKg);
@@ -3017,6 +3036,7 @@ const Component = function () {
key: nextRowKey(),
createdBy: user.id,
creatorName: user.name,
+ recordSource: 'lingniu',
orderNo: '',
hydrogenTime: now,
stationId: undefined,
@@ -3034,7 +3054,10 @@ const Component = function () {
settlementStatus: 'customer',
remark: '',
createdAt: now,
- reconcileStatus: null
+ reconcileStatus: null,
+ changeLogs: [],
+ verifiedByName: '',
+ reconciledByName: ''
}
])[0];
}
@@ -3080,6 +3103,7 @@ const Component = function () {
key: 'mock-h2-' + (i + 1),
createdBy: creator.id,
creatorName: creator.name,
+ recordSource: i === 1 ? 'station' : 'lingniu',
hydrogenTime: day,
stationId: station.value,
stationName: station.label,
@@ -3088,7 +3112,7 @@ const Component = function () {
hydrogenKg: kg,
costUnitPrice: costUnit,
customerId: customerId,
- customerName: customerName || '',
+ customerName: i === 1 ? ((station.label || '') + '·站端上报') : (customerName || ''),
customerUnitPrice: custUnit,
salesperson: salesperson,
settlementStatus: ['customer', 'internal', 'customer_self', 'other'][i % 4],
@@ -3103,7 +3127,10 @@ const Component = function () {
verifyStatus: reconcileStatus === RECONCILE_RECONCILED ? VERIFY_VERIFIED : (reconcileStatus === RECONCILE_PENDING ? VERIFY_UNVERIFIED : null),
savedAt: reconcileStatus !== RECONCILE_DRAFT ? day : null,
verifiedAt: reconcileStatus === RECONCILE_RECONCILED ? day : null,
- reconciledAt: reconcileStatus === RECONCILE_RECONCILED ? day : null
+ verifiedByName: reconcileStatus === RECONCILE_RECONCILED ? CURRENT_USER.name : '',
+ reconciledAt: reconcileStatus === RECONCILE_RECONCILED ? day : null,
+ reconciledByName: reconcileStatus === RECONCILE_RECONCILED ? '系统管理员' : '',
+ changeLogs: []
});
}
var demoStation = findStation(HYDROGEN_STATION_LIST[0].value) || HYDROGEN_STATION_LIST[0];
@@ -3455,24 +3482,36 @@ const Component = function () {
var beforeText = meta.beforeText != null ? meta.beforeText : formatLogValue(field, before, rowCtx);
var afterText = meta.afterText != null ? meta.afterText : formatLogValue(field, after, rowCtx);
if (!meta.force && beforeText === afterText) return;
+ var entry = {
+ id: 'clog-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8),
+ at: nowDayjs(),
+ userId: CURRENT_USER.id,
+ userName: CURRENT_USER.name,
+ operatorName: CURRENT_USER.name,
+ field: field,
+ fieldLabel: fieldLabel,
+ before: beforeText,
+ after: afterText,
+ oldValue: beforeText,
+ newValue: afterText,
+ remark: meta.remark || ''
+ };
setChangeLogsByKey(function (prev) {
var list = (prev[rowKey] || []).slice();
- list.unshift({
- id: 'clog-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8),
- at: nowDayjs(),
- userId: CURRENT_USER.id,
- userName: CURRENT_USER.name,
- field: field,
- fieldLabel: fieldLabel,
- before: beforeText,
- after: afterText,
- remark: meta.remark || ''
- });
+ list.unshift(entry);
var next = Object.assign({}, prev);
next[rowKey] = list;
return next;
});
- }, []);
+ setAllRows(function (prev) {
+ return prev.map(function (r) {
+ if (r.key !== rowKey) return r;
+ var logs = Array.isArray(r.changeLogs) ? r.changeLogs.slice() : [];
+ logs.unshift(entry);
+ return Object.assign({}, r, { changeLogs: logs });
+ });
+ });
+ }, [setAllRows]);
var applySystemCustomerReplace = useCallback(function (rowKey, replaceAction) {
if (!rowKey || !replaceAction || !replaceAction.customerId) return;
@@ -3840,6 +3879,7 @@ const Component = function () {
return Object.assign({}, r, {
verifyStatus: VERIFY_VERIFIED,
verifiedAt: verifiedAt,
+ verifiedByName: CURRENT_USER.name,
reconciledAt: verifiedAt
});
}
@@ -4579,22 +4619,31 @@ const Component = function () {
title: reqTitle('车牌号'),
dataIndex: 'plateNo',
key: 'plateNo',
- width: 118,
+ width: 132,
align: 'center',
render: function (v, record) {
- if (!canEditRow(record)) return readOnlyCell(v);
- return React.createElement(Select, {
- style: cellInputStyle,
- showSearch: true,
- allowClear: true,
- placeholder: '请选择',
- value: v,
- status: fieldInvalid(record, 'plateNo') ? 'error' : undefined,
- options: VEHICLE_INFO_TABLE.map(function (p) { return { value: p, label: p }; }),
- filterOption: filterOption,
- notFoundContent: '车辆不存在',
- onChange: function (val) { patch(record.key, 'plateNo', val); }
- });
+ var source = recordSourceLabel(record);
+ var tag = React.createElement(Tag, {
+ color: source === '站端上传' ? 'green' : 'blue',
+ style: { margin: 0, borderRadius: 4, fontSize: 11, lineHeight: '18px', fontWeight: 600 }
+ }, source);
+ var plateNode = !canEditRow(record)
+ ? readOnlyCell(v)
+ : React.createElement(Select, {
+ style: cellInputStyle,
+ showSearch: true,
+ allowClear: true,
+ placeholder: '请选择',
+ value: v,
+ status: fieldInvalid(record, 'plateNo') ? 'error' : undefined,
+ options: VEHICLE_INFO_TABLE.map(function (p) { return { value: p, label: p }; }),
+ filterOption: filterOption,
+ notFoundContent: '车辆不存在',
+ onChange: function (val) { patch(record.key, 'plateNo', val); }
+ });
+ return React.createElement('div', {
+ style: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4 }
+ }, plateNode, tag);
}
},
{
@@ -4785,6 +4834,16 @@ const Component = function () {
return readOnlyCell(formatDateTime(v) || formatDate(v) || '-');
}
},
+ {
+ title: '对账人',
+ dataIndex: 'reconciledByName',
+ key: 'reconciledByName',
+ width: 88,
+ align: 'center',
+ render: function (v) {
+ return readOnlyCell(v || '—');
+ }
+ },
{
title: '收票日期',
dataIndex: 'receiptDate',
@@ -4848,6 +4907,27 @@ const Component = function () {
return React.createElement(Tag, { color: color, style: { margin: 0 } }, label);
}
},
+ {
+ title: '核对时间',
+ dataIndex: 'verifiedAt',
+ key: 'verifiedAt',
+ width: 148,
+ align: 'center',
+ render: function (v) {
+ if (!v) return readOnlyCell('—');
+ return readOnlyCell(formatDateTime(v) || '—');
+ }
+ },
+ {
+ title: '核对人',
+ dataIndex: 'verifiedByName',
+ key: 'verifiedByName',
+ width: 88,
+ align: 'center',
+ render: function (v) {
+ return readOnlyCell(v || '—');
+ }
+ },
{
title: '对账状态',
key: 'recordStatus',
@@ -5149,9 +5229,27 @@ const Component = function () {
var changeLogRows = useMemo(
function () {
if (!changeLogModal.rowKey) return [];
- return changeLogsByKey[changeLogModal.rowKey] || [];
+ var fromLocal = changeLogsByKey[changeLogModal.rowKey] || [];
+ var row = null;
+ var i;
+ for (i = 0; i < allRows.length; i++) {
+ if (allRows[i].key === changeLogModal.rowKey) {
+ row = allRows[i];
+ break;
+ }
+ }
+ var fromRow = (row && Array.isArray(row.changeLogs) ? row.changeLogs : []) || [];
+ var seen = {};
+ var merged = [];
+ fromLocal.concat(fromRow).forEach(function (log) {
+ var id = log && log.id ? String(log.id) : '';
+ if (id && seen[id]) return;
+ if (id) seen[id] = true;
+ merged.push(log);
+ });
+ return merged;
},
- [changeLogModal.rowKey, changeLogsByKey]
+ [changeLogModal.rowKey, changeLogsByKey, allRows]
);
var changeLogColumns = useMemo(
diff --git a/src/prototypes/vehicle-h2-fee-ledger/annotation-source.json b/src/prototypes/vehicle-h2-fee-ledger/annotation-source.json
index 901c1ad..98b76f2 100644
--- a/src/prototypes/vehicle-h2-fee-ledger/annotation-source.json
+++ b/src/prototypes/vehicle-h2-fee-ledger/annotation-source.json
@@ -209,12 +209,12 @@
"path": []
},
"aiPrompt": "列表字段、行内编辑、客户校验与操作列。",
- "annotationText": "# 列表字段与操作\n\n**核心可编辑字段**(未对账/待保存):加氢时间、站点、车牌、加氢量、成本单价、加氢单价、承担方式等。\n\n**系统带出只读**:业务员、开票/付款相关字段等;客户名称依业务可选填,但会与车辆运营态校验。\n\n## 成本单价列\n\n- 单价前展示 **固定 / 阶梯** 标签(与加氢站价格配置一致)\n- 阶梯价悬浮:当前阶梯量、对应单价\n- 校验图标:正确绿色 ✓ / 异常红色 ⚠\n- **一键替换为标准成本单价**(未对账;创建人或主管),写入变更日志\n\n## 客户名称列\n\n- 与系统登记不一致时整行标红,单元格水印「客户疑似有误」\n- 客户名称后 **警示图标**:悬浮显示异常说明(系统客户、交车时间等)\n- **一键替换为系统客户**(仅「与系统登记客户不一致」场景,未对账数据可操作)\n- 替换写入变更日志\n\n**行操作**(更多菜单):编辑、删除、复制多行、变更日志。\n\n**列表勾选**:仅未对账记录可勾选,用于批量完成对账。\n\n表头支持批量改价(成本单价、加氢单价、承担方式)。",
+ "annotationText": "# 列表字段与操作\n\n**核心可编辑字段**(未对账/待保存):加氢时间、站点、车牌、加氢量、成本单价、加氢单价、承担方式等。\n\n**来源标签**(车牌下方):站端主动上报→「站端上传」;本页人工新增→「羚牛上传」。\n\n**系统带出只读**:业务员、开票/付款相关字段;核对时间/核对人(完成核对写入);对账日期/对账人(对账单提交写入)。\n\n## 成本单价列\n\n- 单价前展示 **固定 / 阶梯** 标签(与加氢站价格配置一致)\n- 阶梯价悬浮:当前阶梯量、对应单价\n- 校验图标:正确绿色 ✓ / 异常红色 ⚠\n- **一键替换为标准成本单价**(未对账;创建人或主管),写入变更日志\n\n## 客户名称列\n\n- 与系统登记不一致时整行标红,单元格水印「客户疑似有误」\n- 客户名称后 **警示图标**:悬浮显示异常说明(系统客户、交车时间等)\n- **一键替换为系统客户**(仅「与系统登记客户不一致」场景,未对账数据可操作)\n- 替换写入变更日志\n\n**行操作**(更多菜单):编辑、删除、复制多行、变更日志(时间/操作人/修改项/原值/新值)。\n\n**列表勾选**:仅未对账记录可勾选,用于批量完成核对。\n\n表头支持批量改价(成本单价、加氢单价、承担方式)。",
"hasMarkdown": true,
"color": "#334155",
"images": [],
"createdAt": 1782806400000,
- "updatedAt": 1782816000000,
+ "updatedAt": 1784520000000,
"controls": []
},
{
diff --git a/src/prototypes/vehicle-management/components/DateRangeFilterField.tsx b/src/prototypes/vehicle-management/components/DateRangeFilterField.tsx
index df9eabd..c90f15e 100644
--- a/src/prototypes/vehicle-management/components/DateRangeFilterField.tsx
+++ b/src/prototypes/vehicle-management/components/DateRangeFilterField.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useRef, useState } from 'react';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { createPortal } from 'react-dom';
import { Calendar, X } from 'lucide-react';
import { DateRangeCalendarPanel } from './DateRangeCalendarPanel';
import { useDismissOnFocusOutside } from './useDismissOnFocusOutside';
@@ -15,6 +16,14 @@ interface DateRangeFilterFieldProps {
endPlaceholder?: string;
}
+interface PopoverPosition {
+ top: number;
+ left: number;
+ width: number;
+}
+
+const POPOVER_MIN_WIDTH = 560;
+
function formatDisplayText(
startDate: string,
endDate: string,
@@ -36,7 +45,9 @@ export function DateRangeFilterField({
endPlaceholder = '结束日期',
}: DateRangeFilterFieldProps) {
const [open, setOpen] = useState(false);
+ const [position, setPosition] = useState({ top: 0, left: 0, width: POPOVER_MIN_WIDTH });
const fieldRef = useRef(null);
+ const popoverRef = useRef(null);
const hasValue = Boolean(startDate || endDate);
const displayText = formatDisplayText(startDate, endDate, startPlaceholder, endPlaceholder);
const placeholder = `${startPlaceholder} 至 ${endPlaceholder}`;
@@ -45,10 +56,41 @@ export function DateRangeFilterField({
setOpen(false);
}, []);
- useDismissOnFocusOutside(open, fieldRef, dismiss);
+ const updatePosition = useCallback(() => {
+ const anchor = fieldRef.current;
+ if (!anchor) return;
+ const rect = anchor.getBoundingClientRect();
+ const maxWidth = Math.max(160, window.innerWidth - 16);
+ const width = Math.min(Math.max(rect.width, POPOVER_MIN_WIDTH), maxWidth);
+ let left = rect.left;
+ if (left + width > window.innerWidth - 8) {
+ left = Math.max(8, window.innerWidth - 8 - width);
+ }
+ if (left < 8) left = 8;
+ let top = rect.bottom + 6;
+ const estimatedHeight = 360;
+ if (top + estimatedHeight > window.innerHeight - 8 && rect.top > estimatedHeight + 8) {
+ top = Math.max(8, rect.top - estimatedHeight - 6);
+ }
+ setPosition({ top, left, width });
+ }, []);
+
+ useDismissOnFocusOutside(open, [fieldRef, popoverRef], dismiss);
+
+ useEffect(() => {
+ if (!open) return;
+ updatePosition();
+ window.addEventListener('resize', updatePosition);
+ window.addEventListener('scroll', updatePosition, true);
+ return () => {
+ window.removeEventListener('resize', updatePosition);
+ window.removeEventListener('scroll', updatePosition, true);
+ };
+ }, [open, updatePosition]);
const openPicker = () => {
setOpen(true);
+ window.requestAnimationFrame(updatePosition);
};
const clear = (event: React.MouseEvent) => {
@@ -58,6 +100,31 @@ export function DateRangeFilterField({
setOpen(false);
};
+ const popover =
+ open && typeof document !== 'undefined'
+ ? createPortal(
+
+
+ ,
+ document.body,
+ )
+ : null;
+
return (
-
- {open ? (
-
-
-
- ) : null}
+ {popover}
);
}
diff --git a/src/prototypes/vehicle-management/style.css b/src/prototypes/vehicle-management/style.css
index 3d4636d..7837e53 100644
--- a/src/prototypes/vehicle-management/style.css
+++ b/src/prototypes/vehicle-management/style.css
@@ -211,6 +211,35 @@
margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--ln-hairline); flex-wrap: wrap;
}
+/* —— 筛选提示文本(强制统一,见 rules/global-design-spec.md §4.1.1) —— */
+.vm-filter-card .vm-filter-picker-input::placeholder,
+.vm-filter-card .vm-input::placeholder,
+.vm-filter-card input.vm-input::placeholder,
+.vm-filter-card .ant-select-selection-placeholder,
+.vm-filter-card .ant-input::placeholder,
+.vm-filter-card .ant-input-affix-wrapper input::placeholder,
+.lc-filter-card .vm-filter-picker-input::placeholder,
+.lc-filter-card .vm-input::placeholder,
+.lc-filter-card input.vm-input::placeholder,
+.lc-filter-card .ant-select-selection-placeholder,
+.lc-filter-card .ant-input::placeholder,
+.lc-filter-card .ant-input-affix-wrapper input::placeholder {
+ font-family: var(--vm-font);
+ font-size: 0.875rem;
+ font-weight: 400;
+ color: var(--ln-muted-soft);
+ opacity: 1;
+ line-height: 1.25;
+}
+
+.vm-filter-picker-input::placeholder {
+ font-family: var(--vm-font);
+ font-size: 0.875rem;
+ font-weight: 400;
+ color: var(--ln-muted-soft);
+ opacity: 1;
+}
+
/* —— 筛选区折叠(全局):超过 1 行(4 项)时默认收起,常量见 src/common/vm-filter-panel.ts —— */
.vm-filter-body {
display: flex;
@@ -254,6 +283,7 @@
display: inline-flex;
align-items: center;
gap: 6px;
+ margin-right: auto;
}
.vm-filter-toggle-badge {
@@ -414,10 +444,10 @@
.vm-filter-picker-input {
flex: 1; min-width: 0; height: 100%;
border: none; background: transparent; padding: 0;
- font-size: 0.875rem; color: var(--ln-ink);
+ font-family: var(--vm-font);
+ font-size: 0.875rem; font-weight: 400; color: var(--ln-ink);
}
.vm-filter-picker-input:focus { outline: none; }
-.vm-filter-picker-input::placeholder { color: var(--ln-muted-soft); }
.vm-filter-picker-clear {
display: inline-flex; align-items: center; justify-content: center;
width: 22px; height: 22px; flex-shrink: 0;
@@ -2254,6 +2284,12 @@ button.vm-btn.vm-btn-back.ant-btn:hover:not(:disabled) {
border-radius: var(--ln-radius-card);
background: var(--ln-surface-card);
box-shadow: var(--ln-shadow-hover);
+ box-sizing: border-box;
+}
+.vm-date-range-popover--portal {
+ position: fixed;
+ z-index: 1200;
+ min-width: 0;
}
.vm-date-range-calendars {
position: relative;
|