diff --git a/.axhub/make/axhub.config.json b/.axhub/make/axhub.config.json index 687d7e0..35830c1 100644 --- a/.axhub/make/axhub.config.json +++ b/.axhub/make/axhub.config.json @@ -33,8 +33,8 @@ "region": "cn-hangzhou", "bucket": "model-lnoneos", "prefix": "", - "baseUrl": "http://prototype.lnoneos.com/", - "endpoint": "" + "baseUrl": "https://prototype.lnoneos.com", + "endpoint": "https://model-lnoneos.oss-cn-hangzhou.aliyuncs.com" }, "githubPages": { "repository": "", @@ -42,11 +42,7 @@ "sourceDirectory": "/" }, "publishSettings": { - "includeSource": true, - "visibleTargets": [ - "axhub", - "s3" - ] + "includeSource": true } } -} \ No newline at end of file +} diff --git a/.axhub/make/sidebar-tree.json b/.axhub/make/sidebar-tree.json index aed63b0..d1bd8cc 100644 --- a/.axhub/make/sidebar-tree.json +++ b/.axhub/make/sidebar-tree.json @@ -1,12 +1,18 @@ { "version": 1, - "updatedAt": "2026-07-01T09:58:50.712Z", + "updatedAt": "2026-07-06T05:10:19.174Z", "prototypes": [ { "id": "folder-1782874576229-r8atbu", "kind": "folder", "title": "OneOS", "children": [ + { + "id": "item:prototypes:oneos-web-workbench", + "kind": "item", + "title": "工作台", + "itemKey": "prototypes/oneos-web-workbench" + }, { "id": "folder-1782874599304-roj8fd", "kind": "folder", @@ -76,38 +82,71 @@ "itemKey": "prototypes/oneos-web-h2-station-site" } ] + }, + { + "id": "folder-oneos-data-analysis", + "kind": "folder", + "title": "数据分析", + "children": [ + { + "id": "item:prototypes:business-dept-ledger", + "kind": "item", + "title": "业务部台账", + "itemKey": "prototypes/business-dept-ledger" + } + ] + }, + { + "id": "folder-1783314569299-4ejj2g", + "kind": "folder", + "title": "台账管理", + "children": [ + { + "id": "item:prototypes:lease-business-ledger", + "kind": "item", + "title": "租赁业务台账", + "itemKey": "prototypes/lease-business-ledger" + }, + { + "id": "item:prototypes:self-operated-business-ledger", + "kind": "item", + "title": "自营业务台账", + "itemKey": "prototypes/self-operated-business-ledger" + }, + { + "id": "item:prototypes:vehicle-h2-fee-ledger", + "kind": "item", + "title": "车辆氢费明细", + "itemKey": "prototypes/vehicle-h2-fee-ledger" + } + ] + }, + { + "id": "folder-1783314610587-rwspc1", + "kind": "folder", + "title": "财务管理", + "children": [ + { + "id": "item:prototypes:payment-records", + "kind": "item", + "title": "收款记录", + "itemKey": "prototypes/payment-records" + } + ] } ] }, { - "id": "item:prototypes:lease-business-ledger", + "id": "item:prototypes:lease-business-line-overview", "kind": "item", - "title": "租赁业务台账", - "itemKey": "prototypes/lease-business-ledger" - }, - { - "id": "item:prototypes:vehicle-h2-fee-ledger", - "kind": "item", - "title": "车辆氢费明细", - "itemKey": "prototypes/vehicle-h2-fee-ledger" - }, - { - "id": "item:prototypes:self-operated-business-ledger", - "kind": "item", - "title": "自营业务台账", - "itemKey": "prototypes/self-operated-business-ledger" + "title": "业务条线说明", + "itemKey": "prototypes/lease-business-line-overview" }, { "id": "folder-prototypes-oneos-web", "kind": "folder", "title": "ONE-OS Web 端", "children": [ - { - "id": "item:prototypes:oneos-web-workbench", - "kind": "item", - "title": "工作台", - "itemKey": "prototypes/oneos-web-workbench" - }, { "id": "item:prototypes:oneos-web-login", "kind": "item", diff --git a/.cursor/rules/modal-detail-table.mdc b/.cursor/rules/modal-detail-table.mdc new file mode 100644 index 0000000..684cd04 --- /dev/null +++ b/.cursor/rules/modal-detail-table.mdc @@ -0,0 +1,40 @@ +--- +description: 弹窗/抽屉内 Ant Design Table 列对齐规范;完成含明细列表的弹窗后必须检查 +globs: src/prototypes/**/*.{tsx,jsx,ts,js} +alwaysApply: false +--- + +# 弹窗明细表列对齐(防错行) + +## 适用场景 + +Modal、Drawer 内展示明细列表的 `Table`,尤其启用 `scroll.y` 或 `scroll.x` 时。 + +## 必须遵守 + +1. **Table 属性** + - `className={LN_MODAL_DETAIL_TABLE_CLASS}`(来自 `src/common/modalDetailTable.ts`) + - `tableLayout="fixed"` + - `scroll.x` 使用 `sumColumnScrollX(columns)`,值为各列 `width` 之和(可 +8~16 预留滚动条) + +2. **列定义** + - **每一列**都必须设置数字 `width`,禁止仅 `ellipsis: true` 而不设宽度 + - 金额列:`align: 'right'` + `className: 'tabular-nums'` + - 长文本列:`ellipsis: true` + 明确 `width` + +3. **样式** + - 项目已提供 `src/common/modal-detail-table.css`(经 `vehicle-management/style.css` 全局引入) + - 不要覆盖 `.ant-table-header` / `.ant-table-body` 的 margin 或隐藏 measure-row 的局部 hack,统一用 `ln-modal-detail-table` + +## 完成前自检 + +实现或修改弹窗明细表后,在浏览器中确认: + +- [ ] 表头文字与每列首行数据**垂直对齐**(不错行、不整体右偏) +- [ ] 纵向滚动时表头与表体列宽仍一致 +- [ ] 金额列右对齐、长文本省略号正常 +- [ ] 开发控制台无 `弹窗表格列缺少 width` 警告 + +## 参考实现 + +`src/prototypes/payment-records/components/PaymentKpiDetailModal.tsx` diff --git a/AGENTS.md b/AGENTS.md index 3dca7f9..0310ab9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -16,6 +16,7 @@ | 产物/场景 | 位置 | 参考文档 | |-----------|------|----------| +| vm-page 列表分页 | `src/common/TablePagination.tsx` + `vm-pagination.css` | `src/prototypes/vm-shared/DESIGN.md` | | 主题 | `src/themes//` | `rules/theme-guide.md` | | 项目资料和文档 | `src/resources/` | `rules/resource-management-guide.md` | | 画布 | `src/prototypes//canvas.excalidraw`、`canvas-assets/` | 原型画布和画布素材 | diff --git a/CLAUDE.md b/CLAUDE.md index 31a5802..d42b985 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,6 +13,7 @@ | 产物/场景 | 位置 | 参考文档 | |-----------|------|----------| +| vm-page 列表分页 | `src/common/TablePagination.tsx` + `vm-pagination.css` | `src/prototypes/vm-shared/DESIGN.md` | | 主题 | `src/themes//` | `rules/theme-guide.md` | | 项目资料和文档 | `src/resources/` | `rules/resource-management-guide.md` | | UI Review 结论 | `src/prototypes//.spec/ui-review.md` | `rules/ui-review-guide.md` | diff --git a/rules/prototype-development-guide.md b/rules/prototype-development-guide.md index 3ec8112..b4fdd8e 100644 --- a/rules/prototype-development-guide.md +++ b/rules/prototype-development-guide.md @@ -86,6 +86,16 @@ export default function MyApp() { - 使用主题 CSS Variables 时,按所选 `DESIGN.md` 和主题规则引入,不复制另一套 token。 +## 列表分页(vm-page 强制) + +凡 `vm-page` 下的数据列表页,表格底部 **必须** 使用全局分页组件与样式,规范见 `src/prototypes/vm-shared/DESIGN.md`: + +- 组件:`import { TablePagination, DEFAULT_PAGE_SIZE } from '../../common/TablePagination'` +- 样式:引入 `vehicle-management/style.css`(已包含 `src/common/vm-pagination.css`) +- 禁止:下拉加载更多、自建分页 UI、与 `vm-pagination*` 不一致的第三方分页 + +参考:`vehicle-management/index.tsx`、`lease-business-ledger/index.tsx`。 + ## 验收流程 运行原型验收脚本: diff --git a/scripts/publish-all-to-s3.mjs b/scripts/publish-all-to-s3.mjs new file mode 100644 index 0000000..697a540 --- /dev/null +++ b/scripts/publish-all-to-s3.mjs @@ -0,0 +1,289 @@ +#!/usr/bin/env node +/** + * 将项目原型页发布到 S3(阿里云 OSS)。 + * 流程:Make Admin export-html 构建静态包 → 按页面独立前缀上传到 OSS。 + * + * 用法: + * node scripts/publish-all-to-s3.mjs + * node scripts/publish-all-to-s3.mjs --dry-run + * node scripts/publish-all-to-s3.mjs --group prototypes + */ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; +import extract from 'extract-zip'; +import { readServerInfo } from './utils/serverInfo.mjs'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const projectRoot = path.resolve(__dirname, '..'); +const CONFIG_PATH = path.join(projectRoot, '.axhub/make/axhub.config.json'); + +function parseArgs(argv) { + const args = { + projectId: 'oneos1.2', + adminOrigin: '', + dryRun: false, + group: 'all', + includeSource: true, + }; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (arg === '--project-id' && argv[i + 1]) args.projectId = argv[++i].trim(); + else if (arg === '--admin-origin' && argv[i + 1]) args.adminOrigin = argv[++i].trim(); + else if (arg === '--group' && argv[i + 1]) args.group = argv[++i].trim(); + else if (arg === '--dry-run') args.dryRun = true; + else if (arg === '--no-source') args.includeSource = false; + } + return args; +} + +function resolveAdminOrigin(explicit) { + if (explicit) return explicit.replace(/\/+$/u, ''); + const info = readServerInfo(projectRoot, 'admin'); + if (info?.origin) return info.origin.replace(/\/+$/u, ''); + return 'http://localhost:53817'; +} + +function readS3Config() { + const raw = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8')); + const s3 = raw?.cloudPublishing?.s3; + if (!s3?.accessKeyId || !s3?.secretAccessKey || !s3?.bucket) { + throw new Error('请在 .axhub/make/axhub.config.json 中配置 cloudPublishing.s3'); + } + return { + ...s3, + includeSource: raw?.cloudPublishing?.publishSettings?.includeSource !== false, + }; +} + +function toPublishPath(resource) { + const raw = resource.filePath || resource.sourcePath || ''; + return String(raw).replace(/\\/gu, '/').replace(/\/index\.tsx?$/iu, ''); +} + +function resolveObjectPrefix(entry) { + const normalized = entry.path.replace(/^\/+|\/+$/gu, ''); + const prototypeMatch = normalized.match(/^(?:src\/)?prototypes\/(.+)$/u); + if (prototypeMatch?.[1]) return prototypeMatch[1]; + const themeMatch = normalized.match(/^(?:src\/)?themes\/(.+)$/u); + if (themeMatch?.[1]) return `themes/${themeMatch[1]}`; + return entry.id; +} + +function resolvePublicUrl(baseUrl, prefix) { + const base = String(baseUrl || '').replace(/\/?$/u, '/'); + const key = `${prefix.replace(/^\/+|\/+$/gu, '')}/index.html`; + return `${base}${key.split('/').map(encodeURIComponent).join('/')}`; +} + +function guessContentType(filePath) { + const ext = path.extname(filePath).toLowerCase(); + const map = { + '.html': 'text/html; charset=utf-8', + '.js': 'application/javascript; charset=utf-8', + '.css': 'text/css; charset=utf-8', + '.json': 'application/json; charset=utf-8', + '.webp': 'image/webp', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.svg': 'image/svg+xml', + '.woff2': 'font/woff2', + '.woff': 'font/woff', + '.txt': 'text/plain; charset=utf-8', + }; + return map[ext] || 'application/octet-stream'; +} + +async function collectPublishEntries(adminOrigin, projectId, groupFilter) { + const res = await fetch(`${adminOrigin}/api/projects/${encodeURIComponent(projectId)}/resources`); + if (!res.ok) { + throw new Error(`GET /api/projects/${projectId}/resources failed: ${res.status}`); + } + const data = await res.json(); + const groups = groupFilter === 'all' ? ['prototypes', 'themes'] : [groupFilter]; + const entries = []; + for (const group of groups) { + for (const item of data.resources?.[group] || []) { + const publishPath = toPublishPath(item); + if (!publishPath) continue; + entries.push({ + group, + id: item.id, + title: item.title || item.id, + path: publishPath, + prefix: resolveObjectPrefix({ path: publishPath, id: item.id }), + }); + } + } + return entries; +} + +async function exportHtmlZip(adminOrigin, projectId, entry, includeSource) { + const params = new URLSearchParams({ + path: entry.path, + projectId, + }); + if (includeSource) params.set('includeSource', 'true'); + const res = await fetch(`${adminOrigin}/api/export-html?${params.toString()}`); + if (!res.ok) { + const text = await res.text().catch(() => ''); + let message = text; + try { + message = JSON.parse(text).error || text; + } catch { + // keep raw text + } + throw new Error(message || `export-html failed (${res.status})`); + } + const buffer = Buffer.from(await res.arrayBuffer()); + if (buffer.length < 4 || buffer[0] !== 0x50 || buffer[1] !== 0x4b) { + throw new Error('export-html 未返回有效 ZIP'); + } + return buffer; +} + +function resolveS3Endpoint(s3Config) { + const bucket = String(s3Config.bucket || '').trim(); + const endpoint = String(s3Config.endpoint || '').trim().replace(/\/+$/u, ''); + const region = String(s3Config.region || 'cn-hangzhou').trim(); + + if (endpoint) { + // 配置里可能是 bucket 级域名(model-lnoneos.oss-...),AWS SDK 只需区域 endpoint。 + const bucketHostPrefix = bucket ? `${bucket}.` : ''; + if (bucketHostPrefix && endpoint.includes(bucketHostPrefix)) { + return endpoint.replace(bucketHostPrefix, ''); + } + return endpoint; + } + + return `https://oss-${region}.aliyuncs.com`; +} + +function createS3Client(s3Config) { + return new S3Client({ + region: s3Config.region || 'cn-hangzhou', + endpoint: resolveS3Endpoint(s3Config), + forcePathStyle: false, + credentials: { + accessKeyId: s3Config.accessKeyId, + secretAccessKey: s3Config.secretAccessKey, + }, + }); +} + +async function uploadDirectory(client, bucket, prefix, dir) { + const uploaded = []; + const walk = async (currentDir, relative = '') => { + for (const name of fs.readdirSync(currentDir)) { + const abs = path.join(currentDir, name); + const rel = relative ? `${relative}/${name}` : name; + if (fs.statSync(abs).isDirectory()) { + await walk(abs, rel); + continue; + } + const key = [prefix.replace(/^\/+|\/+$/gu, ''), rel].filter(Boolean).join('/'); + await client.send(new PutObjectCommand({ + Bucket: bucket, + Key: key, + Body: fs.readFileSync(abs), + ContentType: guessContentType(abs), + })); + uploaded.push(key); + } + }; + await walk(dir); + return uploaded; +} + +async function publishEntry(client, s3Config, adminOrigin, projectId, entry, includeSource) { + const zipBuffer = await exportHtmlZip(adminOrigin, projectId, entry, includeSource); + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'axhub-publish-')); + const zipPath = path.join(tempDir, 'bundle.zip'); + const extractDir = path.join(tempDir, 'site'); + fs.writeFileSync(zipPath, zipBuffer); + fs.mkdirSync(extractDir, { recursive: true }); + await extract(zipPath, { dir: extractDir }); + const objectPrefix = s3Config.prefix + ? `${String(s3Config.prefix).replace(/^\/+|\/+$/gu, '')}/${entry.prefix}` + : entry.prefix; + const keys = await uploadDirectory(client, s3Config.bucket, objectPrefix, extractDir); + fs.rmSync(tempDir, { recursive: true, force: true }); + return { + url: resolvePublicUrl(s3Config.baseUrl, objectPrefix), + fileCount: keys.length, + keys, + }; +} + +async function main() { + const args = parseArgs(process.argv.slice(2)); + const adminOrigin = resolveAdminOrigin(args.adminOrigin); + const s3Config = readS3Config(); + const includeSource = args.includeSource && s3Config.includeSource; + const entries = await collectPublishEntries(adminOrigin, args.projectId, args.group); + + console.log(`Admin: ${adminOrigin}`); + console.log(`Bucket: ${s3Config.bucket}`); + console.log(`Base URL: ${s3Config.baseUrl}`); + console.log(`Pages to publish: ${entries.length}`); + + if (args.dryRun) { + for (const entry of entries) { + console.log(`[dry-run] ${entry.group}/${entry.id} -> ${entry.prefix}/index.html`); + } + return; + } + + const client = createS3Client(s3Config); + const results = []; + let failed = 0; + + for (let i = 0; i < entries.length; i += 1) { + const entry = entries[i]; + const label = `[${i + 1}/${entries.length}] ${entry.group}/${entry.id}`; + process.stdout.write(`${label} ... `); + try { + const result = await publishEntry(client, s3Config, adminOrigin, args.projectId, entry, includeSource); + console.log(`OK ${result.url} (${result.fileCount} files)`); + results.push({ ...entry, status: 'success', ...result }); + } catch (error) { + failed += 1; + const message = error instanceof Error ? error.message : String(error); + console.log(`FAIL ${message}`); + results.push({ ...entry, status: 'failed', error: message }); + } + } + + const reportPath = path.join( + projectRoot, + '.axhub/make/exports', + `cloud.publish.s3-all-${new Date().toISOString().replace(/[:.]/gu, '-')}.json`, + ); + fs.mkdirSync(path.dirname(reportPath), { recursive: true }); + fs.writeFileSync(reportPath, `${JSON.stringify({ + schemaVersion: 2, + projectId: args.projectId, + target: 's3', + method: 'export-html+s3-upload', + total: entries.length, + success: entries.length - failed, + failed, + completedAt: new Date().toISOString(), + results: results.map(({ keys, ...rest }) => ({ + ...rest, + fileCount: rest.fileCount ?? keys?.length ?? 0, + })), + }, null, 2)}\n`, 'utf8'); + + console.log(`\nDone: ${entries.length - failed}/${entries.length} succeeded`); + if (failed > 0) process.exitCode = 1; + console.log(`Report: ${reportPath}`); +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : error); + process.exit(1); +}); diff --git a/scripts/sync-oneos-web-prototypes.mjs b/scripts/sync-oneos-web-prototypes.mjs index 175c03f..7052e1d 100644 --- a/scripts/sync-oneos-web-prototypes.mjs +++ b/scripts/sync-oneos-web-prototypes.mjs @@ -20,6 +20,12 @@ const XLL_MODULES = [ { slug: 'oneos-web-safety-training', title: '业务-司机安全培训', skipCodegen: true }, ]; +/** 从 ONE-OS Web 合包拆出、由项目内手写 index 维护的独立原型 */ +const STANDALONE_MODULES = [ + { slug: 'business-dept-ledger', title: '业务部台账', skipCodegen: true }, + { slug: 'oneos-web-h2-station-site', title: '站点信息', skipCodegen: true }, +]; + const MODULES = [ { slug: 'oneos-web-workbench', title: '工作台', files: ['工作台.jsx'] }, { slug: 'oneos-web-login', title: '登录', files: ['登录.jsx'] }, @@ -29,8 +35,8 @@ const MODULES = [ { slug: 'oneos-web-finance', title: '财务管理', dir: '财务管理', excludeDirs: ['文档'] }, { slug: 'oneos-web-procurement', title: '采购管理', dir: '采购管理' }, { slug: 'oneos-web-lease-contract', title: '车辆租赁合同', dir: '车辆租赁合同' }, - { slug: 'oneos-web-h2-station', title: '加氢站管理', dir: '加氢站管理', excludeDirs: ['export-tools', 'AI-加氢站站点信息-complete'] }, - { slug: 'oneos-web-data-analysis', title: '数据分析', dir: '数据分析' }, + { slug: 'oneos-web-h2-station', title: '加氢站管理', dir: '加氢站管理', excludeDirs: ['export-tools', 'AI-加氢站站点信息-complete'], excludeFiles: ['站点信息.jsx'] }, + { slug: 'oneos-web-data-analysis', title: '数据分析', dir: '数据分析', excludeFiles: ['业务部台账.jsx'] }, { slug: 'oneos-web-ledger-data', title: '台账数据', dir: '台账数据', excludeDirs: ['docs'] }, { slug: 'oneos-web-business', title: '业务管理', dir: '业务管理', excludeDirs: ['文档', 'export-tools', 'AI-保险采购-complete'] }, { slug: 'oneos-web-ops', title: '运维管理', dir: '运维管理' }, @@ -81,6 +87,7 @@ function collectJsxFiles(module) { continue; } if (!entry.name.endsWith('.jsx')) continue; + if (module.excludeFiles?.includes(entry.name)) continue; results.push({ rel, abs: full, @@ -223,6 +230,15 @@ function toComponentName(slug) { .join(''); } +const WORKBENCH_SIDEBAR_ITEM = { + id: 'item:prototypes:oneos-web-workbench', + kind: 'item', + title: '工作台', + itemKey: 'prototypes/oneos-web-workbench', +}; + +const ONEOS_NAV_FOLDER_ID = 'folder-1782874576229-r8atbu'; + function toSidebarItem(module) { return { id: `item:prototypes:${module.slug}`, @@ -232,6 +248,17 @@ function toSidebarItem(module) { }; } +function ensureWorkbenchInOneOsRoot(prototypes) { + for (const item of prototypes) { + if (item?.id !== ONEOS_NAV_FOLDER_ID || item.kind !== 'folder' || !Array.isArray(item.children)) { + continue; + } + const rest = item.children.filter((child) => child.itemKey !== WORKBENCH_SIDEBAR_ITEM.itemKey); + item.children = [WORKBENCH_SIDEBAR_ITEM, ...rest]; + return; + } +} + function updateSidebar(webModules, xllModules) { const sidebar = JSON.parse(fs.readFileSync(sidebarPath, 'utf8')); const prefix = 'item:prototypes:oneos-web-'; @@ -244,6 +271,10 @@ function updateSidebar(webModules, xllModules) { && !String(item.itemKey).startsWith('prototypes/oneos-web-'), ); + ensureWorkbenchInOneOsRoot(existing); + + const webModulesForFolder = webModules.filter((module) => module.slug !== 'oneos-web-workbench'); + const xllFolder = { id: 'folder-prototypes-xll-miniapp', kind: 'folder', @@ -256,7 +287,7 @@ function updateSidebar(webModules, xllModules) { kind: 'folder', title: 'ONE-OS Web 端', defaultExpanded: true, - children: webModules.map(toSidebarItem), + children: webModulesForFolder.map(toSidebarItem), }; sidebar.prototypes = [...existing, xllFolder, oneosFolder]; @@ -270,7 +301,7 @@ function main() { process.exit(1); } - const allModules = [...XLL_MODULES, ...MODULES]; + const allModules = [...XLL_MODULES, ...STANDALONE_MODULES, ...MODULES]; for (const module of allModules) { if (module.skipCodegen) { diff --git a/src/common/TablePagination.tsx b/src/common/TablePagination.tsx new file mode 100644 index 0000000..39eb635 --- /dev/null +++ b/src/common/TablePagination.tsx @@ -0,0 +1,105 @@ +import React, { useMemo } from 'react'; +import { ChevronLeft, ChevronRight } from 'lucide-react'; + +/** 全局默认每页条数,见 vm-shared/DESIGN.md */ +export const DEFAULT_PAGE_SIZE = 20; + +/** 全局可选每页条数 */ +export const PAGE_SIZE_OPTIONS = [10, 20, 50, 100] as const; + +export interface TablePaginationProps { + page: number; + pageSize: number; + total: number; + onPageChange: (page: number) => void; + onPageSizeChange: (size: number) => void; +} + +function buildPageItems(current: number, totalPages: number): Array { + if (totalPages <= 7) { + return Array.from({ length: totalPages }, (_, index) => index + 1); + } + + const items: Array = [1]; + if (current > 3) items.push('ellipsis'); + + const start = Math.max(2, current - 1); + const end = Math.min(totalPages - 1, current + 1); + for (let page = start; page <= end; page += 1) { + items.push(page); + } + + if (current < totalPages - 2) items.push('ellipsis'); + if (totalPages > 1) items.push(totalPages); + return items; +} + +export function TablePagination({ + page, + pageSize, + total, + onPageChange, + onPageSizeChange, +}: TablePaginationProps) { + const totalPages = Math.max(1, Math.ceil(total / pageSize)); + const pageItems = useMemo(() => buildPageItems(page, totalPages), [page, totalPages]); + + if (total === 0) return null; + + return ( +
+ + +
+ + + {pageItems.map((item, index) => ( + item === 'ellipsis' ? ( + + ) : ( + + ) + ))} + + +
+
+ ); +} diff --git a/src/common/modal-detail-table.css b/src/common/modal-detail-table.css new file mode 100644 index 0000000..21c4b85 --- /dev/null +++ b/src/common/modal-detail-table.css @@ -0,0 +1,172 @@ +/** + * 弹窗 / 抽屉内 Ant Design Table 通用样式 + * 防止 scroll.y 场景下表头与表体列宽错行、measure-row 撑开列宽等问题。 + * 使用方式:Table className="ln-modal-detail-table" tableLayout="fixed" + 每列显式 width + */ +.ln-modal-detail-table.ant-table-wrapper .ant-table { + background: transparent; +} + +.ln-modal-detail-table.ant-table-wrapper .ant-table-container { + border-inline-start: none; + border-top: none; +} + +.ln-modal-detail-table.ant-table-wrapper .ant-table-header { + margin-bottom: 0 !important; + overflow: hidden !important; +} + +.ln-modal-detail-table.ant-table-wrapper .ant-table-body { + margin-top: 0 !important; + overflow: auto !important; +} + +.ln-modal-detail-table.ant-table-wrapper .ant-table-body > table, +.ln-modal-detail-table.ant-table-wrapper .ant-table-header > table { + margin-top: 0 !important; + table-layout: fixed !important; +} + +.ln-modal-detail-table .ant-table-tbody > tr.ant-table-measure-row, +.ln-modal-detail-table .ant-table-tbody > tr.ant-table-measure-row > td, +.ln-modal-detail-table .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; +} + +.ln-modal-detail-table .ant-table-thead > tr > th { + background: var(--ln-canvas-soft, #f8fafc) !important; + font-size: 12px !important; + font-weight: 600 !important; + color: var(--ln-muted, #64748b) !important; + padding: 8px 12px !important; + white-space: nowrap; +} + +.ln-modal-detail-table .ant-table-tbody > tr:not(.ant-table-measure-row) > td { + padding: 8px 12px !important; + font-size: 13px; + vertical-align: middle; +} + +.ln-modal-detail-table .ant-table-tbody > tr:not(.ant-table-measure-row) > td.ant-table-cell-ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.ln-modal-detail-table .ant-table-tbody > tr:hover > td { + background: var(--ln-canvas-soft, #f8fafc) !important; +} + +.ln-modal-detail-table .ant-table-cell-scrollbar { + box-shadow: none !important; +} + +.ln-modal-detail-table .ant-table-thead > tr > th.ln-modal-detail-table__money, +.ln-modal-detail-table .ant-table-tbody > tr > td.ln-modal-detail-table__money { + font-variant-numeric: tabular-nums; +} + +/* 左侧冻结列(收款时间等) */ +.ln-modal-detail-table .ant-table-cell-fix-left, +.ln-modal-detail-table .ant-table-cell-fix-start { + z-index: 2; + background: var(--ln-surface-card, #fff) !important; +} + +.ln-modal-detail-table .ant-table-thead > tr > th.ant-table-cell-fix-left, +.ln-modal-detail-table .ant-table-thead > tr > th.ant-table-cell-fix-start { + z-index: 3; + background: var(--ln-canvas-soft, #f8fafc) !important; +} + +.ln-modal-detail-table .ant-table-tbody > tr:hover > td.ant-table-cell-fix-left, +.ln-modal-detail-table .ant-table-tbody > tr:hover > td.ant-table-cell-fix-start { + background: var(--ln-canvas-soft, #f8fafc) !important; +} + +.ln-modal-detail-table .ant-table-cell-fix-left-last::after, +.ln-modal-detail-table .ant-table-cell-fix-start-last::after { + box-shadow: inset 10px 0 8px -8px rgba(15, 23, 42, 0.12); +} + +.ln-modal-detail-table .ln-modal-detail-table__sticky-time { + white-space: nowrap; +} + +/* 弹窗明细列表面板容器 */ +.ln-modal-detail-panel { + border: 1px solid var(--ln-hairline, #e2e8f0); + border-radius: var(--ln-radius-card, 12px); + background: var(--ln-surface-card, #fff); + overflow: hidden; + box-shadow: var(--ln-shadow-soft, 0 1px 2px rgba(24, 24, 27, 0.06)); +} + +.ln-modal-detail-panel__head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 10px 14px; + border-bottom: 1px solid var(--ln-hairline, #e2e8f0); + background: linear-gradient(180deg, #fafbfc 0%, #f6f7f7 100%); +} + +.ln-modal-detail-panel__title { + font-size: 13px; + font-weight: 600; + color: var(--ln-body-strong, #18181b); +} + +.ln-modal-detail-panel__meta { + font-size: 12px; + color: var(--ln-muted, #71717a); +} + +.ln-modal-detail-panel .ln-modal-detail-table.ant-table-wrapper { + padding: 0; +} + +.ln-modal-detail-panel .ln-modal-detail-table .ant-table-pagination { + margin: 0 !important; + padding: 10px 14px !important; + border-top: 1px solid var(--ln-hairline, #e2e8f0); + background: #fafbfc; +} + +.ln-modal-detail-empty { + padding: 28px 16px; + text-align: center; + color: var(--ln-muted, #71717a); +} + +.ln-modal-detail-empty p { + margin: 0; + font-size: 14px; + color: var(--ln-body, #52525b); +} + +.ln-modal-detail-empty__hint { + margin-top: 6px !important; + font-size: 12px !important; + color: var(--ln-muted, #94a3b8) !important; +} + +@media (prefers-reduced-motion: reduce) { + .pr-kpi-detail-modal .ant-modal { + animation: none !important; + } +} diff --git a/src/common/modalDetailTable.ts b/src/common/modalDetailTable.ts new file mode 100644 index 0000000..ca3ba6d --- /dev/null +++ b/src/common/modalDetailTable.ts @@ -0,0 +1,25 @@ +import type { ColumnsType } from 'antd/es/table'; + +/** 弹窗明细表统一 className,配合 src/common/modal-detail-table.css */ +export const LN_MODAL_DETAIL_TABLE_CLASS = 'ln-modal-detail-table'; + +/** 计算 Ant Table scroll.x;expand 默认预留滚动条/展开列余量 */ +export function sumColumnScrollX(columns: ColumnsType, expand = 0): number { + const base = columns.reduce((sum, col) => sum + (Number(col.width) || 0), 0); + return base + expand; +} + +/** 开发环境检查:弹窗表每列必须设置 width,避免表头表体错行 */ +export function warnMissingModalColumnWidths( + columns: ColumnsType, + context: string, +): void { + if (typeof import.meta !== 'undefined' && !import.meta.env?.DEV) return; + const missing = columns.filter((col) => col.width == null); + if (missing.length > 0) { + console.warn( + `[${context}] 弹窗表格列缺少 width,可能导致表头与内容错行:`, + missing.map((col) => col.key ?? col.title), + ); + } +} diff --git a/src/common/vm-pagination.css b/src/common/vm-pagination.css new file mode 100644 index 0000000..244d809 --- /dev/null +++ b/src/common/vm-pagination.css @@ -0,0 +1,138 @@ +/** + * ONE-OS vm-page 列表分页 — 全局样式 + * 规范:src/prototypes/vm-shared/DESIGN.md + * 组件:src/common/TablePagination.tsx + */ + +.vm-pagination { + display: flex; + justify-content: flex-end; + align-items: center; + flex-wrap: wrap; + gap: 12px 16px; + width: 100%; + padding: 0; +} + +.vm-pagination-size { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: 0.875rem; + color: var(--ln-muted); + flex-shrink: 0; +} + +.vm-pagination-size-label { + white-space: nowrap; +} + +.vm-pagination-select { + min-width: 72px; + height: var(--vm-control-height); + padding: 0 28px 0 10px; + border: 1px solid var(--ln-hairline-strong); + border-radius: var(--ln-radius-control); + background: var(--ln-surface-card); + color: var(--ln-ink); + font-size: 0.875rem; + cursor: pointer; +} + +.vm-pagination-select:focus { + outline: none; + border-color: var(--vm-focus-border-color); +} + +.vm-pagination-pages { + display: inline-flex; + align-items: center; + gap: 4px; + flex-shrink: 0; +} + +.vm-pagination-nav, +.vm-pagination-page { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: var(--vm-control-height); + height: var(--vm-control-height); + padding: 0 8px; + border: 1px solid var(--ln-hairline-strong); + border-radius: var(--ln-radius-control); + background: var(--ln-surface-card); + color: var(--ln-ink); + font-size: 0.875rem; + font-weight: 500; + cursor: pointer; + transition: background 0.2s, border-color 0.2s, color 0.2s; +} + +.vm-pagination-nav:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +.vm-pagination-nav:hover:not(:disabled), +.vm-pagination-page:hover:not(.active) { + background: var(--ln-canvas-soft); + border-color: var(--ln-hairline-strong); +} + +.vm-pagination-page.active { + background: var(--ln-primary); + border-color: var(--ln-primary); + color: var(--ln-on-primary); +} + +.vm-pagination-nav:focus-visible, +.vm-pagination-page:focus-visible { + outline: none; + border-color: var(--vm-focus-border-color); +} + +.vm-pagination-ellipsis { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 28px; + height: var(--vm-control-height); + color: var(--ln-muted); + font-size: 0.875rem; +} + +/* 详情 Tab 等紧凑场景:vm-table-footer--split vm-table-footer--compact */ +.vm-table-footer--compact .vm-pagination { + width: auto; + flex: 0 1 auto; + justify-content: flex-end; + gap: 8px; + flex-wrap: nowrap; +} + +.vm-table-footer--compact .vm-pagination-size { + gap: 4px; + font-size: 0.8125rem; +} + +.vm-table-footer--compact .vm-pagination-select { + min-width: 52px; + height: 28px; + padding: 0 22px 0 8px; + font-size: 0.8125rem; +} + +.vm-table-footer--compact .vm-pagination-nav, +.vm-table-footer--compact .vm-pagination-page { + min-width: 28px; + height: 28px; + padding: 0 6px; + font-size: 0.8125rem; +} + +.vm-table-footer--compact .vm-pagination-ellipsis { + min-width: 20px; + height: 28px; + font-size: 0.8125rem; +} diff --git a/src/prototypes/business-dept-ledger/index.tsx b/src/prototypes/business-dept-ledger/index.tsx new file mode 100644 index 0000000..a287323 --- /dev/null +++ b/src/prototypes/business-dept-ledger/index.tsx @@ -0,0 +1,26 @@ +/** + * @name 业务部台账 + * 自 ONE-OS Web 端 / 数据分析 / 业务部台账 独立预览(OneOS 菜单入口) + */ +import '../../common/oneosWebLegacy/legacyGlobals'; +import React, { useEffect } from 'react'; +import * as antd from 'antd'; +import { ConfigProvider } from 'antd'; +import 'antd/dist/reset.css'; +import { clearHostPrototypeRouteInfo } from '../../common/useHashPage'; +import BusinessDeptLedgerPage from '../oneos-web-data-analysis/pages/05-业务部台账.jsx'; + +window.React = React; +window.antd = antd; + +export default function BusinessDeptLedger() { + useEffect(() => { + clearHostPrototypeRouteInfo(); + }, []); + + return ( + + + + ); +} diff --git a/src/prototypes/contract-template-management/annotation-source.json b/src/prototypes/contract-template-management/annotation-source.json index 1acbeca..5ad344d 100644 --- a/src/prototypes/contract-template-management/annotation-source.json +++ b/src/prototypes/contract-template-management/annotation-source.json @@ -5,7 +5,7 @@ "version": 2, "prototypeName": "contract-template-management", "pageId": "list", - "updatedAt": 1782871095265, + "updatedAt": 1783328981482, "nodes": [ { "id": "ct-list-filter", @@ -332,66 +332,10 @@ "title": "ONE-OS 原型导航", "defaultExpanded": true, "children": [ - { - "type": "link", - "id": "nav-link-contract-template-management", - "title": "合同模板管理(当前)", - "href": "/prototypes/contract-template-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-insurance-procurement", - "title": "保险采购", - "href": "/prototypes/insurance-procurement", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-vehicle-management", - "title": "车辆管理", - "href": "/prototypes/vehicle-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-lease-contract-management", - "title": "租赁合同管理", - "href": "/prototypes/lease-contract-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-customer-management", - "title": "客户管理", - "href": "/prototypes/customer-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-lease-business-ledger", - "title": "租赁业务台账", - "href": "/prototypes/lease-business-ledger", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-vehicle-h2-fee-ledger", - "title": "车辆氢费明细", - "href": "/prototypes/vehicle-h2-fee-ledger", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-self-operated-business-ledger", - "title": "自营业务台账", - "href": "/prototypes/self-operated-business-ledger", - "target": "self" - }, { "type": "folder", - "id": "nav-folder-prototypes-oneos-web", - "title": "ONE-OS Web 端", + "id": "nav-folder-1782874576229-r8atbu", + "title": "OneOS", "defaultExpanded": true, "children": [ { @@ -400,7 +344,22 @@ "title": "工作台", "href": "/prototypes/oneos-web-workbench", "target": "self" - }, + } + ] + }, + { + "type": "link", + "id": "nav-link-lease-business-line-overview", + "title": "业务条线说明", + "href": "/prototypes/lease-business-line-overview", + "target": "self" + }, + { + "type": "folder", + "id": "nav-folder-prototypes-oneos-web", + "title": "ONE-OS Web 端", + "defaultExpanded": true, + "children": [ { "type": "link", "id": "nav-link-oneos-web-login", diff --git a/src/prototypes/contract-template-management/contract-template-section-filter.js b/src/prototypes/contract-template-management/contract-template-section-filter.js index d0ca8e2..6616a42 100644 --- a/src/prototypes/contract-template-management/contract-template-section-filter.js +++ b/src/prototypes/contract-template-management/contract-template-section-filter.js @@ -93,3 +93,24 @@ export function applyAttachmentSectionVehicleFilter(html, sectionVehicleBindings } return out; } + +/** 附件章节删减后,按当前保留顺序重排「附件 N」序号 */ +export function renumberAttachmentSections(html) { + var source = String(html || ''); + var ranges = collectSectionRanges(source); + if (!ranges.length) return source; + + var chunks = []; + var cursor = 0; + ranges.forEach(function (range, idx) { + var newNo = idx + 1; + chunks.push(source.slice(cursor, range.start)); + var slice = source.slice(range.start, range.end); + slice = slice.replace(/附件\s*\d+\s*[::]/, '附件' + newNo + ':'); + slice = slice.replace(/\s*(\d+):租赁订单\s*<\/b>/, '' + newNo + ':租赁订单 '); + chunks.push(slice); + cursor = range.end; + }); + chunks.push(source.slice(cursor)); + return chunks.join(''); +} diff --git a/src/prototypes/contract-template-management/contract-template-vars.js b/src/prototypes/contract-template-management/contract-template-vars.js index 10674f0..915e2ef 100644 --- a/src/prototypes/contract-template-management/contract-template-vars.js +++ b/src/prototypes/contract-template-management/contract-template-vars.js @@ -68,10 +68,10 @@ export var MOCK_LEASE_CUSTOMERS = [ bankAccount: '6222021234567890123', taxId: '91330400MA2XXXXX1', attachments: { - businessLicense: { name: '嘉兴某某物流-营业执照.pdf' }, - legalIdFront: { name: '法人身份证-正面.jpg' }, - legalIdBack: { name: '法人身份证-反面.jpg' }, - roadTransportPermit: { name: '道路运输经营许可证.pdf' }, + businessLicense: { name: '嘉兴某某物流-营业执照.pdf', ocrVerified: true, expiryDate: '2028-06-30' }, + legalIdFront: { name: '法人身份证-正面.jpg', ocrVerified: true, expiryDate: '2032-08-15' }, + legalIdBack: { name: '法人身份证-反面.jpg', ocrVerified: true, expiryDate: '2032-08-15' }, + roadTransportPermit: { name: '道路运输经营许可证.pdf', ocrVerified: true, expiryDate: '2027-12-31' }, }, }, { @@ -91,10 +91,10 @@ export var MOCK_LEASE_CUSTOMERS = [ bankAccount: '6217001234567890123', taxId: '91310000MA2XXXXX2', attachments: { - businessLicense: { name: '上海某某运输-营业执照.pdf' }, - legalIdFront: { name: '法人身份证-正面.jpg' }, - legalIdBack: { name: '法人身份证-反面.jpg' }, - roadTransportPermit: { name: '道路运输经营许可证.pdf' }, + businessLicense: { name: '上海某某运输-营业执照.pdf', ocrVerified: true, expiryDate: '2027-03-01' }, + legalIdFront: { name: '法人身份证-正面.jpg', ocrVerified: true, expiryDate: '2029-11-20' }, + legalIdBack: { name: '法人身份证-反面.jpg', ocrVerified: true, expiryDate: '2029-11-20' }, + roadTransportPermit: { name: '道路运输经营许可证.pdf', ocrVerified: true, expiryDate: '2026-01-10' }, }, }, { @@ -114,10 +114,10 @@ export var MOCK_LEASE_CUSTOMERS = [ bankAccount: '6228481234567890123', taxId: '91330100MA2XXXXX3', attachments: { - businessLicense: { name: '杭州某某租赁-营业执照.pdf' }, - legalIdFront: { name: '法人身份证-正面.jpg' }, - legalIdBack: { name: '法人身份证-反面.jpg' }, - roadTransportPermit: { name: '道路运输经营许可证.pdf' }, + businessLicense: { name: '杭州某某租赁-营业执照.pdf', ocrVerified: true, expiryDate: '2026-09-20' }, + legalIdFront: { name: '法人身份证-正面.jpg', ocrVerified: true, expiryDate: '2030-05-08' }, + legalIdBack: { name: '法人身份证-反面.jpg', ocrVerified: true, expiryDate: '2030-05-08' }, + roadTransportPermit: { name: '道路运输经营许可证.pdf', ocrVerified: true, expiryDate: '2026-02-01' }, }, }, ]; @@ -214,6 +214,16 @@ export var DEFAULT_FEE_INFO = { returnHydrogenDiffUnitPrice: null, }; +/** 新建合同时系统自动生成的编号后缀(不含 LNZLHT 前缀) */ +export function generateAutoContractCodeSuffix() { + var now = new Date(); + var y = now.getFullYear(); + var m = String(now.getMonth() + 1).padStart(2, '0'); + var d = String(now.getDate()).padStart(2, '0'); + var seq = String(Math.floor(Math.random() * 9000) + 1000); + return y + m + d + seq; +} + export var PAYMENT_PERIOD_OPTIONS = [ { value: 1, label: '1个月' }, { value: 3, label: '3个月' }, @@ -224,6 +234,7 @@ export var PAYMENT_PERIOD_OPTIONS = [ export var HYDROGEN_PAYMENT_METHOD_OPTIONS = [ { value: 'self', label: '自行解决' }, { value: 'prepay', label: '预付款' }, + { value: 'month', label: '按月结算(原型占位,条款待法务确认)' }, ]; export function getLessorCompanies() { diff --git a/src/prototypes/customer-management/annotation-source.json b/src/prototypes/customer-management/annotation-source.json index 2594d62..99e819a 100644 --- a/src/prototypes/customer-management/annotation-source.json +++ b/src/prototypes/customer-management/annotation-source.json @@ -5,7 +5,7 @@ "version": 2, "prototypeName": "customer-management", "pageId": "list", - "updatedAt": 1782896901748, + "updatedAt": 1783328981485, "nodes": [ { "id": "cm-list-filter", @@ -245,6 +245,135 @@ "assetMap": {}, "directory": { "nodes": [ + { + "type": "folder", + "id": "oneos-project-nav", + "title": "ONE-OS 原型导航", + "defaultExpanded": true, + "children": [ + { + "type": "folder", + "id": "nav-folder-1782874576229-r8atbu", + "title": "OneOS", + "defaultExpanded": true, + "children": [ + { + "type": "link", + "id": "nav-link-oneos-web-workbench", + "title": "工作台", + "href": "/prototypes/oneos-web-workbench", + "target": "self" + } + ] + }, + { + "type": "link", + "id": "nav-link-lease-business-line-overview", + "title": "业务条线说明", + "href": "/prototypes/lease-business-line-overview", + "target": "self" + }, + { + "type": "folder", + "id": "nav-folder-prototypes-oneos-web", + "title": "ONE-OS Web 端", + "defaultExpanded": true, + "children": [ + { + "type": "link", + "id": "nav-link-oneos-web-login", + "title": "登录", + "href": "/prototypes/oneos-web-login", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-vehicle-asset", + "title": "车辆管理", + "href": "/prototypes/oneos-web-vehicle-asset", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-contract-template", + "title": "合同模板管理", + "href": "/prototypes/oneos-web-contract-template", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-help-center", + "title": "帮助中心", + "href": "/prototypes/oneos-web-help-center", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-finance", + "title": "财务管理", + "href": "/prototypes/oneos-web-finance", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-procurement", + "title": "采购管理", + "href": "/prototypes/oneos-web-procurement", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-lease-contract", + "title": "车辆租赁合同", + "href": "/prototypes/oneos-web-lease-contract", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-h2-station", + "title": "加氢站管理", + "href": "/prototypes/oneos-web-h2-station", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-data-analysis", + "title": "数据分析", + "href": "/prototypes/oneos-web-data-analysis", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-ledger-data", + "title": "台账数据", + "href": "/prototypes/oneos-web-ledger-data", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-business", + "title": "业务管理", + "href": "/prototypes/oneos-web-business", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-ops", + "title": "运维管理", + "href": "/prototypes/oneos-web-ops", + "target": "self" + }, + { + "type": "link", + "id": "nav-link-oneos-web-requirements", + "title": "需求说明", + "href": "/prototypes/oneos-web-requirements", + "target": "self" + } + ] + } + ] + }, { "type": "folder", "id": "cm-doc-root", @@ -261,7 +390,7 @@ "type": "link", "id": "cm-link-self", "title": "客户管理原型", - "href": "/prototypes/customer-management", + "href": "./index.html", "target": "self" }, { diff --git a/src/prototypes/insurance-procurement/annotation-source.json b/src/prototypes/insurance-procurement/annotation-source.json index c36fdb5..38d683c 100644 --- a/src/prototypes/insurance-procurement/annotation-source.json +++ b/src/prototypes/insurance-procurement/annotation-source.json @@ -5,7 +5,7 @@ "version": 2, "prototypeName": "insurance-procurement", "pageId": "list", - "updatedAt": 1782871095269, + "updatedAt": 1783328981486, "nodes": [ { "id": "ipc-header", @@ -502,66 +502,10 @@ "title": "ONE-OS 原型导航", "defaultExpanded": true, "children": [ - { - "type": "link", - "id": "nav-link-contract-template-management", - "title": "合同模板管理", - "href": "/prototypes/contract-template-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-insurance-procurement", - "title": "保险采购(当前)", - "href": "/prototypes/insurance-procurement", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-vehicle-management", - "title": "车辆管理", - "href": "/prototypes/vehicle-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-lease-contract-management", - "title": "租赁合同管理", - "href": "/prototypes/lease-contract-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-customer-management", - "title": "客户管理", - "href": "/prototypes/customer-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-lease-business-ledger", - "title": "租赁业务台账", - "href": "/prototypes/lease-business-ledger", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-vehicle-h2-fee-ledger", - "title": "车辆氢费明细", - "href": "/prototypes/vehicle-h2-fee-ledger", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-self-operated-business-ledger", - "title": "自营业务台账", - "href": "/prototypes/self-operated-business-ledger", - "target": "self" - }, { "type": "folder", - "id": "nav-folder-prototypes-oneos-web", - "title": "ONE-OS Web 端", + "id": "nav-folder-1782874576229-r8atbu", + "title": "OneOS", "defaultExpanded": true, "children": [ { @@ -570,7 +514,22 @@ "title": "工作台", "href": "/prototypes/oneos-web-workbench", "target": "self" - }, + } + ] + }, + { + "type": "link", + "id": "nav-link-lease-business-line-overview", + "title": "业务条线说明", + "href": "/prototypes/lease-business-line-overview", + "target": "self" + }, + { + "type": "folder", + "id": "nav-folder-prototypes-oneos-web", + "title": "ONE-OS Web 端", + "defaultExpanded": true, + "children": [ { "type": "link", "id": "nav-link-oneos-web-login", diff --git a/src/prototypes/lease-business-ledger/.spec/requirements-prd.md b/src/prototypes/lease-business-ledger/.spec/requirements-prd.md index 9855b81..f0f202d 100644 --- a/src/prototypes/lease-business-ledger/.spec/requirements-prd.md +++ b/src/prototypes/lease-business-ledger/.spec/requirements-prd.md @@ -1,6 +1,6 @@ # 租赁业务台账 · 产品需求说明(PRD) -> 对齐《租赁业务运营明细台账模版》;业务服务组维护各自台账,标记已确认与收款关联为原型演示。 +> 对齐《租赁业务运营明细台账模版》;业务服务组维护各自台账,收款关联与状态自动计算为原型演示。 --- @@ -10,8 +10,8 @@ |---|---| | 模块名称 | 台账数据 — 租赁业务台账 | | 目标用户 | 租赁业务客服、业务服务组主管 | -| 核心任务 | 维护租赁运营明细、汇总应收实收与盈亏、标记确认与关联收款 | -| 页面结构 | 筛选区 + KPI 统计 + 工具栏 + 宽表 + 下拉加载更多(不做分页) | +| 核心任务 | 维护租赁运营明细、汇总应收实收与盈亏、关联收款记录 | +| 页面结构 | 筛选区 + KPI 统计 + 工具栏 + 宽表 + 底部分页 | --- @@ -25,8 +25,8 @@ | 业务部门 / 业务员 | 精确匹配 | | 车牌号码 | 精确匹配 | | 客户名称 | 模糊包含 | -| 明细状态 | 草稿 / 已确认 / 部分收款 / 已收款 | -| 付款日期 | 日期区间 | +| 明细状态 | 未收款 / 部分收款 / 已收款 | +| 应付款日 | 单输入框双日历区间,精确至日 | --- @@ -55,18 +55,18 @@ |---|---| | 批量导入 | 下载模板并上传 Excel(原型 Toast) | | 导出 | 导出当前筛选结果 | -| 标记为已确认 | 勾选草稿行后二次确认 | -| 提交收款审批 | 勾选行提交审批 | +| 保存 | 勾选记录后设为未归档,保存后不可编辑 | +| 设置为归档 | 勾选记录后锁定为已归档 | -添加行已移至表格底部;列表采用下拉加载更多,不做分页。 +表格底部提供分页,可切换页码与每页条数。 -### 标记为已确认 +### 保存 -勾选草稿记录后点击,弹出二次确认:「确认后的数据只有主管才能继续进行修改,是否确认数据准确无误?」确认后状态变更为已确认,业务服务组人员不可再删改。 +勾选台账记录后点击,将账单状态设为**未归档**。未归档数据不可编辑,仅草稿可编辑。 -### 添加行 +### 设置为归档 -位于表格底部;列表不做分页,采用下拉加载更多,避免多选受分页限制。 +勾选台账记录后点击,将账单状态设为**已归档**并锁定编辑。 --- @@ -78,132 +78,344 @@ --- -## 6. 状态流转 +## 6. 收款状态 -1. 新增/导入 → **草稿**(业务服务组可删改) -2. 多选 + 「标记为已确认」→ **已确认**(仅主管可改) -3. 已确认行可「关联收款记录」;到账合计 < 应收 → **部分收款**;≥ 应收 → **已收款** +## 状态 + +**数据来源**:收款记录模块中关联到本账单的分配金额、账单应收合计。 +**计算方式**:分配金额 ≥ 应收合计且应收 > 0 → 已收款;0 < 分配金额 < 应收 → 部分收款;未关联收款 → 未收款。 +**录入方式**:系统自动计算,只读。 + +**业务说明**:当收款记录中分配金额完全覆盖账单的应收金额时,显示已收款。当收款记录中分配金额≤账单的应收金额时,显示部分收款。未分配收款记录时,显示为未收款。其他状态去除 --- ## 7. 字段说明 -### 业务部门列 +### 应付款日 -业务部门与业务负责人合并为一列:第一行显示为业务部门,第二行显示为业务负责人。 +**数据来源**:账单起始日期(优先)或提车日期作为开始计费日;账单所属年月。 +**计算方式**:首期账单应付款日 = 开始计费日;后续每期 = 账单所属自然月 5 日。 +**录入方式**:系统自动计算,只读。 -### 车牌号码列 +**业务说明**:交车后按「开始计费日期」生成首期账单应付款日;后续每期账单在所属自然月 5 日生成下一期应付款日。 -车牌与车型合并为一列:上方车牌号码,下方品牌与型号;导入/新增时按车牌在系统中自动匹配。 +### 车牌号码 -### 客户名称列 +**数据来源**:车辆档案(按车牌匹配品牌、型号)。 +**计算方式**:导入/新增台账时按车牌号反写车辆信息。 +**录入方式**:只读展示(车牌 + 车型两行)。 -客户名称与项目名称合并为一列:上方客户名称,下方项目名称;按账单日期与车牌号自动匹配。 +**业务说明**:车牌与车型合并为一列:上方车牌号码,下方品牌与型号;导入/新增时按车牌在系统中自动匹配。 + +### 客户名称 + +**数据来源**:租赁合同(按账单日期 + 车牌匹配客户、项目)。 +**计算方式**:匹配当前车辆在账期内的有效合同,带出客户名称与项目名称。 +**录入方式**:只读展示(客户 + 项目两行)。 + +**业务说明**:客户名称与项目名称合并为一列:上方客户名称,下方项目名称;按账单日期与车牌号自动匹配。 + +### 增值服务 + +**数据来源**:租赁合同签订时勾选的增值服务项目。 +**计算方式**:按车牌匹配合同增值服务配置,多项服务分行展示。 +**录入方式**:只读。 + +**业务说明**:签订合同时勾选的增值服务项目,按车牌自动匹配合同数据;多项服务各占一行展示。 ### 提车日期 -等于交车管理中该车辆运维 E 签宝签字完成的时间。 +**数据来源**:交车管理 / 运维 E 签宝签字完成时间。 +**计算方式**:取该车辆实际交车办结时间。 +**录入方式**:只读。 + +**业务说明**:运维实际交车日期。 + +### 合同生效日期 + +**数据来源**:提车日期(交车办结时间)。 +**计算方式**:合同生效日期 = 提车日期(YYYY-MM-DD),系统自动反写。 +**录入方式**:系统自动反写,只读。 + +**业务说明**:等于提车日期,即租赁合同生效日期,系统自动反写,只读。 + +### 合同到期日期 + +**数据来源**:合同租期月数 + 提车日期,或合同约定的到期日。 +**计算方式**:日期模式:取合同存储的 contractEndDate;租期模式:提车日 + leaseTermMonths 个月。 +**录入方式**:系统自动计算,只读。 + +**业务说明**:合同到期日:租期模式按提车日期 + 租期月数计算;日期模式取合同中约定的到期日。 + +### 起始日期 + +**数据来源**:账单年月、提车日期。 +**计算方式**:月前已提车 → 当月 1 日;月内提车 → 提车日;月后提车 → 空(calcPeriodStartDate)。 +**录入方式**:系统自动计算,只读。 + +**业务说明**:账单所属月内的租赁起始日:月前已提车取当月 1 日,月内提车取提车日;系统自动计算,只读。 + +### 退车日期 + +**数据来源**:退车管理登记的退车日期。 +**计算方式**:取该车牌退车办结日期;未退车为空。 +**录入方式**:只读。 + +**业务说明**:退车管理中登记的退车日期;未退车时为空。 + +### 平均天数 + +**数据来源**:账单月内租赁天数、当月自然日天数。 +**计算方式**:平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数(calcAvgDays)。 +**录入方式**:系统自动计算,只读。 + +**业务说明**:平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数;用于成本分摊口径。 ### 保证金 -与创建合同时的保证金、提车应收款中的保证金等同;提车应收款有保证金时显示。 +**数据来源**:提车应收款 / 合同保证金。 +**计算方式**:与创建合同时保证金、提车应收款中该车辆保证金一致。 +**录入方式**:只读。 + +**业务说明**:显示该车辆实付保证金金额,与提车应收款时该车辆收取的提车应收款相同。 ### 合同标的租金 -等于该车辆在签订该合同时合同中的租金(月租金标准)。 +**数据来源**:租赁合同月租金标准。 +**计算方式**:签订合同时该车辆的月租金(合同标的租金)。 +**录入方式**:合同带入,只读。 + +**业务说明**:等于该车辆在签订该合同时合同中的租金(月租金标准)。 + +### 应收合计 + +**数据来源**:应收租金、保险上浮费、运维费(收入侧)、其他收入、里程/其他减免。 +**计算方式**:应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免 − 其他减免(calcReceivableTotal)。 +**录入方式**:系统自动汇总,只读。 + +**业务说明**:应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。 ### 应收租金 -按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。 +**数据来源**:合同标的租金、合同付款周期月数。 +**计算方式**:应收租金 = 合同标的租金 × 付款周期月数(1/3/6/12)(calcReceivableRent)。 +**录入方式**:系统自动计算,只读。 + +**业务说明**:按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。 ### 月度收入 -租金 + 服务费 − 里程减免金额 − 其他减免金额(后两项为减项)。 +**数据来源**:月度租金、维保包干、保险上浮费、运维费(收入侧)、其他收入、减免项。 +**计算方式**:月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免 − 其他减免(calcMonthlyIncome)。 +**录入方式**:系统自动计算,只读。 + +**业务说明**:月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。 ### 月度租金 -根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。 +**数据来源**:合同标的租金。 +**计算方式**:月度租金 = 合同标的租金(calcMonthlyRent)。 +**录入方式**:只读。 + +**业务说明**:根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。 ### 维保包干收入 -合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。 +**数据来源**:合同维保包干配置、账单里程。 +**计算方式**:勾选维保包干时:单价(元/km)× 里程数;未勾选为 0(calcMaintenanceIncome)。 +**录入方式**:包干未勾选时不可编辑。 + +**业务说明**:合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。 ### 保险上浮费 -事故中有保险上浮费时,最新账单显示警示标志;关联事故单后自动汇总上浮费,支持多选。 +**数据来源**:事故台账关联的保险上浮费。 +**计算方式**:关联事故单后汇总 linkedAccidentIds 对应上浮费;最新账单未关联时显示警示。 +**录入方式**:关联后自动汇总,支持多选事故单。 -### 运维费(收入侧) +**业务说明**:事故中有保险上浮费时,最新账单显示警示标志;关联事故单后自动汇总上浮费,支持多选。 -维修/保养台账为「客户承担」时,最新一期账单显示警示图标,提醒关联维修/保养记录;关联后自动汇总运维费,支持多选。 +### 运维费 + +**数据来源**:维修/保养台账(客户承担)、账单月内该车牌完工记录。 +**计算方式**:汇总 bearBy=客户承担 的维保金额;可关联 linkedMaintenanceIds(sumMaintenanceForBill)。 +**录入方式**:关联后自动汇总;最新账单可关联记录。 + +**业务说明**:收入侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「客户承担」的金额;最新一期账单可关联记录。 ### 其他收入 -手工填写,预留作为特殊情况记录使用。 +**数据来源**:行内其他收入明细(事由、金额、备注)。 +**计算方式**:多条明细金额合计计入应收与月度收入(sumLineItems)。 +**录入方式**:草稿状态可编辑明细。 + +**业务说明**:支持多条明细录入(事由、金额、备注);合计自动计入应收与月度收入。 + +### 里程减免金额 + +**数据来源**:BI 里程(GPS)、里程减免单价。 +**计算方式**:里程减免 = GPS 里程 × 单价;有 GPS 时默认 0.5 元/km,无 GPS 为 0(calcMileageDeduction)。 +**录入方式**:系统自动计算,只读。 + +**业务说明**:里程减免金额 = GPS 里程 × 里程减免单价;有 GPS 里程时默认单价 0.5 元/km,无 GPS 时为 0。 + +### 其他减免金额 + +**数据来源**:行内其他减免明细。 +**计算方式**:多条明细金额合计,从应收与月度收入扣减(sumLineItems)。 +**录入方式**:草稿状态可编辑明细。 + +**业务说明**:支持多条明细录入(事由、金额、备注);合计自动从应收与月度收入中扣减。 ### 实收金额 -根据财务导入收款明细归集;支持关联多条并分配计入金额;超出应收部分在单据下自行分配。 +**数据来源**:收款记录模块关联分配金额。 +**计算方式**:关联收款单后按分配计入金额汇总,不超过应收合计(calcReceivedAmountFromReceipts)。 +**录入方式**:通过「关联收款」操作维护。 + +**业务说明**:从「收款记录」功能关联该账单后分配的实收金额;点击可查看收款明细列表。 ### 未收金额 -未收金额 = 应收合计 − 实收金额,系统自动计算,不可手工录入。 +**数据来源**:应收合计、实收金额。 +**计算方式**:未收金额 = 应收合计 − 实收金额(calcUnreceived)。 +**录入方式**:系统自动计算,不可手工录入。 + +**业务说明**:未收金额 = 应收合计 − 实收金额,系统自动计算,不可手工录入。 ### 开票日期 -账单开票后由财务维护,自动反写,只读。 +**数据来源**:关联收款记录中的开票信息。 +**计算方式**:resolveInvoiceDateFromReceipts 取关联收款单开票日期。 +**录入方式**:只读。 + +**业务说明**:从「收款记录」功能关联开票记录,显示开票日期。 ### 实际付款日期 -关联收款记录时取对应到账记录的付款日期;未关联时为空。 +**数据来源**:关联收款记录的到账日期。 +**计算方式**:有关联收款时取到账记录付款日期;未关联为空。 +**录入方式**:只读。 + +**业务说明**:关联收款记录时取对应到账记录的付款日期;未关联时为空。 ### 付款方式 -由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。 +**数据来源**:合同付款周期月数。 +**计算方式**:1→月度预付,3→季度预付,6→半年预付,12→年度预付(resolvePaymentMethod)。 +**录入方式**:只读。 + +**业务说明**:由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。 ### 车辆标准成本 -固定成本,按车型明细维护,只读。 +**数据来源**:车型成本明细 / 车牌标准成本配置(PLATE_STANDARD_COST)。 +**计算方式**:按车型维护的固定月标准成本。 +**录入方式**:只读。 + +**业务说明**:固定成本,按车型明细维护,只读。 ### 车辆实际成本 -车辆标准成本 ×(实际天数 / 30),自动计算。 +**数据来源**:车辆标准成本、账单月内租赁天数。 +**计算方式**:车辆实际成本 = 标准成本 × 租赁天数 / 30(calcVehicleActualCost)。 +**录入方式**:系统自动计算,只读。 + +**业务说明**:车辆实际成本 = 车辆标准成本 × 账单月内租赁天数 / 30,自动计算。 ### 保险费 -暂保留,不可编辑和导入;后续可能自动计算。 +**数据来源**:保险采购金额、保险有效天数、账单月租赁天数。 +**计算方式**:保险费 =(采购金额 / 有效天数)× 租赁天数,四舍五入两位(calcInsuranceFee)。 +**录入方式**:只读。 + +**业务说明**:保险费 =(保险采购金额 / 保险有效天数)× 账单月内租赁天数,四舍五入保留两位小数。 ### 氢费 -表头提示:仅显示合同氢费承担方式为「我司承担」时,该账单期内氢费总和(含未对账/已对账)。 +**数据来源**:氢费明细台账、合同氢费承担方式。 +**计算方式**:合同为「我司承担」时,汇总账单月内该车牌氢费(sumHydrogenFeeForBill);客户承担不计入。 +**录入方式**:只读。 -### 运维费(成本侧) +**业务说明**:仅汇总该账单月内、氢费明细中「我司承担」的氢费(含未对账/已对账);合同为客户承担时不计入。 -与收入侧运维费平进平出,自动同步。 +### 运维费 + +**数据来源**:维修/保养台账(我司承担)、账单月内该车牌。 +**计算方式**:汇总 bearBy=我司承担 的维保金额(sumMaintenanceForBill)。 +**录入方式**:只读。 + +**业务说明**:成本侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「我司承担」的金额。 ### 居间费 -手动输入。 +**数据来源**:行内手工录入。 +**计算方式**:直接存储 brokerageFee 字段。 +**录入方式**:草稿可编辑。 -### 其他(成本侧) +**业务说明**:手动输入。 -前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。 +### 其他 + +**数据来源**:行内手工录入。 +**计算方式**:直接存储 otherCost;前方有其他收入时本项必填。 +**录入方式**:草稿可编辑。 + +**业务说明**:前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。 ### GPS里程 -从 BI 里程取账单时间段的数据,自动展示。 +**数据来源**:BI 里程数据(bi-mileage.json / 车机 GPS)。 +**计算方式**:lookupBiMileage(车牌, 年, 月) 取账单期里程。 +**录入方式**:只读。 + +**业务说明**:从 BI 里程取账单时间段的数据,自动展示。 ### 其他减免金额明细内容 -手动输入,备注明细内容。 +**数据来源**:行内手工录入。 +**计算方式**:存储 otherDeductionDetail 文本。 +**录入方式**:草稿可编辑。 + +**业务说明**:手动输入,备注明细内容。 ### 资产归属 -显示车辆实际归属公司名称,按车辆档案自动获取。 +**数据来源**:车辆档案资产归属。 +**计算方式**:按车牌从 PLATE_ASSET_OWNER / 车辆档案反写。 +**录入方式**:只读。 + +**业务说明**:显示车辆实际归属公司名称,按车辆档案自动获取。 ### 签约公司 -租赁合同甲方,签订合同时自动获取;用于租赁总账利润归集。 +**数据来源**:租赁合同甲方。 +**计算方式**:按车牌匹配签订合同时甲方名称(PLATE_SIGNING_COMPANY)。 +**录入方式**:只读。 + +**业务说明**:显示租赁合同签订时甲方名称。 ### 备注 -手动输入。 +**数据来源**:行内手工录入。 +**计算方式**:存储 remark 文本。 +**录入方式**:草稿可编辑。 + +**业务说明**:本列为人工手动填写。 + +### 账单状态 + +**数据来源**:账单归档状态字段 archiveStatus。 +**计算方式**:草稿 / 未归档 / 已归档;工具栏「保存」「设置为归档」批量变更。 +**录入方式**:仅草稿可编辑业务字段。 + +**业务说明**:状态分为已归档、未归档、草稿。仅草稿可编辑;工具栏「保存」将勾选记录设为未归档(不可编辑);「设置为归档」将勾选记录锁定为已归档。 + +### 维护时间 + +**数据来源**:台账行维护记录。 +**计算方式**:展示最近一次保存/维护时间(maintainerTime)。 +**录入方式**:系统记录,只读。 + +**业务说明**:展示最近一次维护时间(YYYY-MM-DD HH:MM);维护人显示最后一次维护用户姓名。 diff --git a/src/prototypes/lease-business-ledger/annotation-source.json b/src/prototypes/lease-business-ledger/annotation-source.json index c4ec07d..0b50a11 100644 --- a/src/prototypes/lease-business-ledger/annotation-source.json +++ b/src/prototypes/lease-business-ledger/annotation-source.json @@ -5,7 +5,7 @@ "version": 2, "prototypeName": "lease-business-ledger", "pageId": "list", - "updatedAt": 1782871095270, + "updatedAt": 1783329264666, "nodes": [ { "id": "lbl-filter", @@ -20,7 +20,7 @@ "path": [] }, "aiPrompt": "年份、月份、部门、业务员等筛选。", - "annotationText": "## 2. 筛选区\n\n默认展示 4 项(一行),点击「更多筛选」展开全部 8 项。\n\n| 筛选项 | 说明 |\n|---|---|\n| 年份 / 月份 | 账单所属年月 |\n| 业务部门 / 业务员 | 精确匹配 |\n| 车牌号码 | 精确匹配 |\n| 客户名称 | 模糊包含 |\n| 明细状态 | 草稿 / 已确认 / 部分收款 / 已收款 |\n| 付款日期 | 日期区间 |\n\n---", + "annotationText": "## 2. 筛选区\n\n默认展示 4 项(一行),点击「更多筛选」展开全部 8 项。\n\n| 筛选项 | 说明 |\n|---|---|\n| 年份 / 月份 | 账单所属年月 |\n| 业务部门 / 业务员 | 精确匹配 |\n| 车牌号码 | 精确匹配 |\n| 客户名称 | 模糊包含 |\n| 明细状态 | 未收款 / 部分收款 / 已收款 |\n| 应付款日 | 单输入框双日历区间,精确至日 |\n\n---", "hasMarkdown": true, "color": "#2563eb", "images": [], @@ -103,8 +103,8 @@ "fingerprint": "lbl-toolbar", "path": [] }, - "aiPrompt": "导入、导出、标记确认、提交审批。", - "annotationText": "## 4. 列表工具栏\n\n左侧「仅显示未收款数据」勾选后,列表仅显示状态不等于已收款的记录。\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板并上传 Excel(原型 Toast) |\n| 导出 | 导出当前筛选结果 |\n| 标记为已确认 | 勾选草稿行后二次确认 |\n| 提交收款审批 | 勾选行提交审批 |\n\n添加行已移至表格底部;列表采用下拉加载更多,不做分页。\n\n---", + "aiPrompt": "导入、导出、保存、设置为归档。", + "annotationText": "## 4. 列表工具栏\n\n左侧「仅显示未收款数据」勾选后,列表仅显示状态不等于已收款的记录。\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板并上传 Excel(原型 Toast) |\n| 导出 | 导出当前筛选结果 |\n| 保存 | 勾选记录后设为未归档,保存后不可编辑 |\n| 设置为归档 | 勾选记录后锁定为已归档 |\n\n表格底部提供分页,可切换页码与每页条数。\n\n---", "hasMarkdown": true, "color": "#0f766e", "images": [], @@ -113,45 +113,45 @@ "controls": [] }, { - "id": "lbl-btn-mark-confirmed", + "id": "lbl-btn-save-unarchived", "index": 6, - "title": "标记为已确认", + "title": "保存", "pageId": "list", "locator": { "selectors": [ - "[data-annotation-id=\"lbl-btn-mark-confirmed\"]" + "[data-annotation-id=\"lbl-btn-save-unarchived\"]" ], - "fingerprint": "lbl-btn-mark-confirmed", + "fingerprint": "lbl-btn-save-unarchived", "path": [] }, - "aiPrompt": "草稿批量确认与权限收口。", - "annotationText": "## 标记为已确认\n\n勾选草稿记录后点击,弹出二次确认:「确认后的数据只有主管才能继续进行修改,是否确认数据准确无误?」确认后状态变更为已确认,业务服务组人员不可再删改。\n\n---", - "hasMarkdown": true, - "color": "#0f766e", - "images": [], - "createdAt": 1782700000000, - "updatedAt": 1782700000000, - "controls": [] - }, - { - "id": "lbl-btn-add-row", - "index": 7, - "title": "添加行", - "pageId": "list", - "locator": { - "selectors": [ - "[data-annotation-id=\"lbl-btn-add-row\"]" - ], - "fingerprint": "lbl-btn-add-row", - "path": [] - }, - "aiPrompt": "表格底部新增行。", - "annotationText": "## 添加行\n\n位于表格底部;列表不做分页,采用下拉加载更多,避免多选受分页限制。\n\n---", + "aiPrompt": "勾选记录批量设为未归档。", + "annotationText": "## 保存\n\n勾选台账记录后点击,将账单状态设为**未归档**。未归档数据不可编辑,仅草稿可编辑。\n\n---", "hasMarkdown": true, "color": "#0f766e", "images": [], "createdAt": 1740787200000, - "updatedAt": 1782711877197, + "updatedAt": 1783260796701, + "controls": [] + }, + { + "id": "lbl-btn-set-archived", + "index": 7, + "title": "设置为归档", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-btn-set-archived\"]" + ], + "fingerprint": "lbl-btn-set-archived", + "path": [] + }, + "aiPrompt": "勾选记录批量归档。", + "annotationText": "## 设置为归档\n\n勾选台账记录后点击,将账单状态设为**已归档**并锁定编辑。\n\n---", + "hasMarkdown": true, + "color": "#0f766e", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783259785963, "controls": [] }, { @@ -178,7 +178,7 @@ { "id": "lbl-col-status", "index": 9, - "title": "状态流转", + "title": "状态", "pageId": "list", "locator": { "selectors": [ @@ -187,8 +187,8 @@ "fingerprint": "lbl-col-status", "path": [] }, - "aiPrompt": "状态流转字段说明。", - "annotationText": "## 状态流转\n\n1. 新增/导入 → **草稿**(业务服务组可删改)\n2. 多选 + 「标记为已确认」→ **已确认**(仅主管可改)\n3. 已确认行可「关联收款记录」;到账合计 < 应收 → **部分收款**;≥ 应收 → **已收款**\n\n---", + "aiPrompt": "状态字段的数据来源与计算口径。", + "annotationText": "## 状态\n\n**数据来源**:收款记录模块中关联到本账单的分配金额、账单应收合计。\n**计算方式**:分配金额 ≥ 应收合计且应收 > 0 → 已收款;0 < 分配金额 < 应收 → 部分收款;未关联收款 → 未收款。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:当收款记录中分配金额完全覆盖账单的应收金额时,显示已收款。当收款记录中分配金额≤账单的应收金额时,显示部分收款。未分配收款记录时,显示为未收款。其他状态去除\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -197,24 +197,24 @@ "controls": [] }, { - "id": "lbl-col-dept", + "id": "lbl-col-payment-due", "index": 10, - "title": "业务部门", + "title": "应付款日", "pageId": "list", "locator": { "selectors": [ - "[data-annotation-id=\"lbl-col-dept\"]" + "[data-annotation-id=\"lbl-col-payment-due\"]" ], - "fingerprint": "lbl-col-dept", + "fingerprint": "lbl-col-payment-due", "path": [] }, - "aiPrompt": "业务部门字段说明。", - "annotationText": "## 业务部门列\n\n业务部门与业务员合并为一列:上方业务部门,下方业务员。\n\n---", + "aiPrompt": "应付款日字段的数据来源与计算口径。", + "annotationText": "## 应付款日\n\n**数据来源**:账单起始日期(优先)或提车日期作为开始计费日;账单所属年月。\n**计算方式**:首期账单应付款日 = 开始计费日;后续每期 = 账单所属自然月 5 日。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:交车后按「开始计费日期」生成首期账单应付款日;后续每期账单在所属自然月 5 日生成下一期应付款日。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], - "createdAt": 1782700000000, - "updatedAt": 1782700000000, + "createdAt": 1740787200000, + "updatedAt": 1783251873620, "controls": [] }, { @@ -229,8 +229,8 @@ "fingerprint": "lbl-col-plate", "path": [] }, - "aiPrompt": "车牌号码字段说明。", - "annotationText": "## 车牌号码列\n\n车牌与车型合并为一列:上方车牌号码,下方品牌与型号;导入/新增时按车牌在系统中自动匹配。\n\n---", + "aiPrompt": "车牌号码字段的数据来源与计算口径。", + "annotationText": "## 车牌号码\n\n**数据来源**:车辆档案(按车牌匹配品牌、型号)。\n**计算方式**:导入/新增台账时按车牌号反写车辆信息。\n**录入方式**:只读展示(车牌 + 车型两行)。\n\n**业务说明**:车牌与车型合并为一列:上方车牌号码,下方品牌与型号;导入/新增时按车牌在系统中自动匹配。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -250,8 +250,8 @@ "fingerprint": "lbl-col-customer", "path": [] }, - "aiPrompt": "客户名称字段说明。", - "annotationText": "## 客户名称列\n\n客户名称与项目名称合并为一列:上方客户名称,下方项目名称;按账单日期与车牌号自动匹配。\n\n---", + "aiPrompt": "客户名称字段的数据来源与计算口径。", + "annotationText": "## 客户名称\n\n**数据来源**:租赁合同(按账单日期 + 车牌匹配客户、项目)。\n**计算方式**:匹配当前车辆在账期内的有效合同,带出客户名称与项目名称。\n**录入方式**:只读展示(客户 + 项目两行)。\n\n**业务说明**:客户名称与项目名称合并为一列:上方客户名称,下方项目名称;按账单日期与车牌号自动匹配。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -260,8 +260,29 @@ "controls": [] }, { - "id": "lbl-col-pickup-date", + "id": "lbl-col-value-added-service", "index": 13, + "title": "增值服务", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-value-added-service\"]" + ], + "fingerprint": "lbl-col-value-added-service", + "path": [] + }, + "aiPrompt": "增值服务字段的数据来源与计算口径。", + "annotationText": "## 增值服务\n\n**数据来源**:租赁合同签订时勾选的增值服务项目。\n**计算方式**:按车牌匹配合同增值服务配置,多项服务分行展示。\n**录入方式**:只读。\n\n**业务说明**:签订合同时勾选的增值服务项目,按车牌自动匹配合同数据;多项服务各占一行展示。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783257117558, + "controls": [] + }, + { + "id": "lbl-col-pickup-date", + "index": 14, "title": "提车日期", "pageId": "list", "locator": { @@ -271,8 +292,8 @@ "fingerprint": "lbl-col-pickup-date", "path": [] }, - "aiPrompt": "提车日期字段说明。", - "annotationText": "## 提车日期\n\n等于交车管理中该车辆运维 E 签宝签字完成的时间。\n\n---", + "aiPrompt": "提车日期字段的数据来源与计算口径。", + "annotationText": "## 提车日期\n\n**数据来源**:交车管理 / 运维 E 签宝签字完成时间。\n**计算方式**:取该车辆实际交车办结时间。\n**录入方式**:只读。\n\n**业务说明**:运维实际交车日期。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -280,9 +301,114 @@ "updatedAt": 1782711877197, "controls": [] }, + { + "id": "lbl-col-contract-start-date", + "index": 15, + "title": "合同生效日期", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-contract-start-date\"]" + ], + "fingerprint": "lbl-col-contract-start-date", + "path": [] + }, + "aiPrompt": "合同生效日期字段的数据来源与计算口径。", + "annotationText": "## 合同生效日期\n\n**数据来源**:提车日期(交车办结时间)。\n**计算方式**:合同生效日期 = 提车日期(YYYY-MM-DD),系统自动反写。\n**录入方式**:系统自动反写,只读。\n\n**业务说明**:等于提车日期,即租赁合同生效日期,系统自动反写,只读。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783257117558, + "controls": [] + }, + { + "id": "lbl-col-contract-end-date", + "index": 16, + "title": "合同到期日期", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-contract-end-date\"]" + ], + "fingerprint": "lbl-col-contract-end-date", + "path": [] + }, + "aiPrompt": "合同到期日期字段的数据来源与计算口径。", + "annotationText": "## 合同到期日期\n\n**数据来源**:合同租期月数 + 提车日期,或合同约定的到期日。\n**计算方式**:日期模式:取合同存储的 contractEndDate;租期模式:提车日 + leaseTermMonths 个月。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:合同到期日:租期模式按提车日期 + 租期月数计算;日期模式取合同中约定的到期日。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783257117558, + "controls": [] + }, + { + "id": "lbl-col-period-start-date", + "index": 17, + "title": "起始日期", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-period-start-date\"]" + ], + "fingerprint": "lbl-col-period-start-date", + "path": [] + }, + "aiPrompt": "起始日期字段的数据来源与计算口径。", + "annotationText": "## 起始日期\n\n**数据来源**:账单年月、提车日期。\n**计算方式**:月前已提车 → 当月 1 日;月内提车 → 提车日;月后提车 → 空(calcPeriodStartDate)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:账单所属月内的租赁起始日:月前已提车取当月 1 日,月内提车取提车日;系统自动计算,只读。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783257117558, + "controls": [] + }, + { + "id": "lbl-col-return-date", + "index": 18, + "title": "退车日期", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-return-date\"]" + ], + "fingerprint": "lbl-col-return-date", + "path": [] + }, + "aiPrompt": "退车日期字段的数据来源与计算口径。", + "annotationText": "## 退车日期\n\n**数据来源**:退车管理登记的退车日期。\n**计算方式**:取该车牌退车办结日期;未退车为空。\n**录入方式**:只读。\n\n**业务说明**:退车管理中登记的退车日期;未退车时为空。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783257117558, + "controls": [] + }, + { + "id": "lbl-col-avg-days", + "index": 19, + "title": "平均天数", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-avg-days\"]" + ], + "fingerprint": "lbl-col-avg-days", + "path": [] + }, + "aiPrompt": "平均天数字段的数据来源与计算口径。", + "annotationText": "## 平均天数\n\n**数据来源**:账单月内租赁天数、当月自然日天数。\n**计算方式**:平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数(calcAvgDays)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数;用于成本分摊口径。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783257117558, + "controls": [] + }, { "id": "lbl-col-deposit", - "index": 14, + "index": 20, "title": "保证金", "pageId": "list", "locator": { @@ -292,8 +418,8 @@ "fingerprint": "lbl-col-deposit", "path": [] }, - "aiPrompt": "保证金字段说明。", - "annotationText": "## 保证金\n\n与创建合同时的保证金、提车应收款中的保证金等同;提车应收款有保证金时显示。\n\n---", + "aiPrompt": "保证金字段的数据来源与计算口径。", + "annotationText": "## 保证金\n\n**数据来源**:提车应收款 / 合同保证金。\n**计算方式**:与创建合同时保证金、提车应收款中该车辆保证金一致。\n**录入方式**:只读。\n\n**业务说明**:显示该车辆实付保证金金额,与提车应收款时该车辆收取的提车应收款相同。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -303,7 +429,7 @@ }, { "id": "lbl-col-contract-rent", - "index": 15, + "index": 21, "title": "合同标的租金", "pageId": "list", "locator": { @@ -313,8 +439,8 @@ "fingerprint": "lbl-col-contract-rent", "path": [] }, - "aiPrompt": "合同标的租金字段说明。", - "annotationText": "## 合同标的租金\n\n等于该车辆在签订该合同时合同中的租金(月租金标准)。\n\n---", + "aiPrompt": "合同标的租金字段的数据来源与计算口径。", + "annotationText": "## 合同标的租金\n\n**数据来源**:租赁合同月租金标准。\n**计算方式**:签订合同时该车辆的月租金(合同标的租金)。\n**录入方式**:合同带入,只读。\n\n**业务说明**:等于该车辆在签订该合同时合同中的租金(月租金标准)。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -322,9 +448,30 @@ "updatedAt": 1782711877197, "controls": [] }, + { + "id": "lbl-col-receivable-total", + "index": 22, + "title": "应收合计", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-receivable-total\"]" + ], + "fingerprint": "lbl-col-receivable-total", + "path": [] + }, + "aiPrompt": "应收合计字段的数据来源与计算口径。", + "annotationText": "## 应收合计\n\n**数据来源**:应收租金、保险上浮费、运维费(收入侧)、其他收入、里程/其他减免。\n**计算方式**:应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免 − 其他减免(calcReceivableTotal)。\n**录入方式**:系统自动汇总,只读。\n\n**业务说明**:应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783257117558, + "controls": [] + }, { "id": "lbl-col-receivable-rent", - "index": 16, + "index": 23, "title": "应收租金", "pageId": "list", "locator": { @@ -334,8 +481,8 @@ "fingerprint": "lbl-col-receivable-rent", "path": [] }, - "aiPrompt": "应收租金字段说明。", - "annotationText": "## 应收租金\n\n按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。\n\n---", + "aiPrompt": "应收租金字段的数据来源与计算口径。", + "annotationText": "## 应收租金\n\n**数据来源**:合同标的租金、合同付款周期月数。\n**计算方式**:应收租金 = 合同标的租金 × 付款周期月数(1/3/6/12)(calcReceivableRent)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -345,7 +492,7 @@ }, { "id": "lbl-col-monthly-income", - "index": 17, + "index": 24, "title": "月度收入", "pageId": "list", "locator": { @@ -355,8 +502,8 @@ "fingerprint": "lbl-col-monthly-income", "path": [] }, - "aiPrompt": "月度收入字段说明。", - "annotationText": "## 月度收入\n\n租金 + 服务费 − 里程减免金额 − 其他减免金额(后两项为减项)。\n\n---", + "aiPrompt": "月度收入字段的数据来源与计算口径。", + "annotationText": "## 月度收入\n\n**数据来源**:月度租金、维保包干、保险上浮费、运维费(收入侧)、其他收入、减免项。\n**计算方式**:月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免 − 其他减免(calcMonthlyIncome)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -366,7 +513,7 @@ }, { "id": "lbl-col-monthly-rent", - "index": 18, + "index": 25, "title": "月度租金", "pageId": "list", "locator": { @@ -376,8 +523,8 @@ "fingerprint": "lbl-col-monthly-rent", "path": [] }, - "aiPrompt": "月度租金字段说明。", - "annotationText": "## 月度租金\n\n根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。\n\n---", + "aiPrompt": "月度租金字段的数据来源与计算口径。", + "annotationText": "## 月度租金\n\n**数据来源**:合同标的租金。\n**计算方式**:月度租金 = 合同标的租金(calcMonthlyRent)。\n**录入方式**:只读。\n\n**业务说明**:根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -387,7 +534,7 @@ }, { "id": "lbl-col-maintenance-income", - "index": 19, + "index": 26, "title": "维保包干收入", "pageId": "list", "locator": { @@ -397,8 +544,8 @@ "fingerprint": "lbl-col-maintenance-income", "path": [] }, - "aiPrompt": "维保包干收入字段说明。", - "annotationText": "## 维保包干收入\n\n合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。\n\n---", + "aiPrompt": "维保包干收入字段的数据来源与计算口径。", + "annotationText": "## 维保包干收入\n\n**数据来源**:合同维保包干配置、账单里程。\n**计算方式**:勾选维保包干时:单价(元/km)× 里程数;未勾选为 0(calcMaintenanceIncome)。\n**录入方式**:包干未勾选时不可编辑。\n\n**业务说明**:合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -408,7 +555,7 @@ }, { "id": "lbl-col-insurance-surcharge", - "index": 20, + "index": 27, "title": "保险上浮费", "pageId": "list", "locator": { @@ -418,8 +565,8 @@ "fingerprint": "lbl-col-insurance-surcharge", "path": [] }, - "aiPrompt": "保险上浮费字段说明。", - "annotationText": "## 保险上浮费\n\n事故中有保险上浮费时,最新账单显示警示标志;关联事故单后自动汇总上浮费,支持多选。\n\n---", + "aiPrompt": "保险上浮费字段的数据来源与计算口径。", + "annotationText": "## 保险上浮费\n\n**数据来源**:事故台账关联的保险上浮费。\n**计算方式**:关联事故单后汇总 linkedAccidentIds 对应上浮费;最新账单未关联时显示警示。\n**录入方式**:关联后自动汇总,支持多选事故单。\n\n**业务说明**:事故中有保险上浮费时,最新账单显示警示标志;关联事故单后自动汇总上浮费,支持多选。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -429,8 +576,8 @@ }, { "id": "lbl-col-ops-income", - "index": 21, - "title": "运维费(收入侧)", + "index": 28, + "title": "运维费", "pageId": "list", "locator": { "selectors": [ @@ -439,8 +586,8 @@ "fingerprint": "lbl-col-ops-income", "path": [] }, - "aiPrompt": "运维费(收入侧)字段说明。", - "annotationText": "## 运维费(收入侧)\n\n维修/保养台账为「客户承担」时,最新一期账单显示警示图标,提醒关联维修/保养记录;关联后自动汇总运维费,支持多选。\n\n---", + "aiPrompt": "运维费字段的数据来源与计算口径。", + "annotationText": "## 运维费\n\n**数据来源**:维修/保养台账(客户承担)、账单月内该车牌完工记录。\n**计算方式**:汇总 bearBy=客户承担 的维保金额;可关联 linkedMaintenanceIds(sumMaintenanceForBill)。\n**录入方式**:关联后自动汇总;最新账单可关联记录。\n\n**业务说明**:收入侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「客户承担」的金额;最新一期账单可关联记录。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -450,7 +597,7 @@ }, { "id": "lbl-col-other-income", - "index": 22, + "index": 29, "title": "其他收入", "pageId": "list", "locator": { @@ -460,8 +607,8 @@ "fingerprint": "lbl-col-other-income", "path": [] }, - "aiPrompt": "其他收入字段说明。", - "annotationText": "## 其他收入\n\n手工填写,预留作为特殊情况记录使用。\n\n---", + "aiPrompt": "其他收入字段的数据来源与计算口径。", + "annotationText": "## 其他收入\n\n**数据来源**:行内其他收入明细(事由、金额、备注)。\n**计算方式**:多条明细金额合计计入应收与月度收入(sumLineItems)。\n**录入方式**:草稿状态可编辑明细。\n\n**业务说明**:支持多条明细录入(事由、金额、备注);合计自动计入应收与月度收入。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -469,9 +616,51 @@ "updatedAt": 1782711877197, "controls": [] }, + { + "id": "lbl-col-mileage-deduction", + "index": 30, + "title": "里程减免金额", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-mileage-deduction\"]" + ], + "fingerprint": "lbl-col-mileage-deduction", + "path": [] + }, + "aiPrompt": "里程减免金额字段的数据来源与计算口径。", + "annotationText": "## 里程减免金额\n\n**数据来源**:BI 里程(GPS)、里程减免单价。\n**计算方式**:里程减免 = GPS 里程 × 单价;有 GPS 时默认 0.5 元/km,无 GPS 为 0(calcMileageDeduction)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:里程减免金额 = GPS 里程 × 里程减免单价;有 GPS 里程时默认单价 0.5 元/km,无 GPS 时为 0。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783257117558, + "controls": [] + }, + { + "id": "lbl-col-other-deduction", + "index": 31, + "title": "其他减免金额", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-other-deduction\"]" + ], + "fingerprint": "lbl-col-other-deduction", + "path": [] + }, + "aiPrompt": "其他减免金额字段的数据来源与计算口径。", + "annotationText": "## 其他减免金额\n\n**数据来源**:行内其他减免明细。\n**计算方式**:多条明细金额合计,从应收与月度收入扣减(sumLineItems)。\n**录入方式**:草稿状态可编辑明细。\n\n**业务说明**:支持多条明细录入(事由、金额、备注);合计自动从应收与月度收入中扣减。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783257117558, + "controls": [] + }, { "id": "lbl-col-received-amount", - "index": 23, + "index": 32, "title": "实收金额", "pageId": "list", "locator": { @@ -481,8 +670,8 @@ "fingerprint": "lbl-col-received-amount", "path": [] }, - "aiPrompt": "实收金额字段说明。", - "annotationText": "## 实收金额\n\n根据财务导入收款明细归集;支持关联多条并分配计入金额;超出应收部分在单据下自行分配。\n\n---", + "aiPrompt": "实收金额字段的数据来源与计算口径。", + "annotationText": "## 实收金额\n\n**数据来源**:收款记录模块关联分配金额。\n**计算方式**:关联收款单后按分配计入金额汇总,不超过应收合计(calcReceivedAmountFromReceipts)。\n**录入方式**:通过「关联收款」操作维护。\n\n**业务说明**:从「收款记录」功能关联该账单后分配的实收金额;点击可查看收款明细列表。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -492,7 +681,7 @@ }, { "id": "lbl-col-unreceived", - "index": 24, + "index": 33, "title": "未收金额", "pageId": "list", "locator": { @@ -502,8 +691,8 @@ "fingerprint": "lbl-col-unreceived", "path": [] }, - "aiPrompt": "未收金额字段说明。", - "annotationText": "## 未收金额\n\n未收金额 = 应收合计 − 实收金额,系统自动计算,不可手工录入。\n\n---", + "aiPrompt": "未收金额字段的数据来源与计算口径。", + "annotationText": "## 未收金额\n\n**数据来源**:应收合计、实收金额。\n**计算方式**:未收金额 = 应收合计 − 实收金额(calcUnreceived)。\n**录入方式**:系统自动计算,不可手工录入。\n\n**业务说明**:未收金额 = 应收合计 − 实收金额,系统自动计算,不可手工录入。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -513,7 +702,7 @@ }, { "id": "lbl-col-invoice-date", - "index": 25, + "index": 34, "title": "开票日期", "pageId": "list", "locator": { @@ -523,8 +712,8 @@ "fingerprint": "lbl-col-invoice-date", "path": [] }, - "aiPrompt": "开票日期字段说明。", - "annotationText": "## 开票日期\n\n账单开票后由财务维护,自动反写,只读。\n\n---", + "aiPrompt": "开票日期字段的数据来源与计算口径。", + "annotationText": "## 开票日期\n\n**数据来源**:关联收款记录中的开票信息。\n**计算方式**:resolveInvoiceDateFromReceipts 取关联收款单开票日期。\n**录入方式**:只读。\n\n**业务说明**:从「收款记录」功能关联开票记录,显示开票日期。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -534,7 +723,7 @@ }, { "id": "lbl-col-actual-payment", - "index": 26, + "index": 35, "title": "实际付款日期", "pageId": "list", "locator": { @@ -544,8 +733,8 @@ "fingerprint": "lbl-col-actual-payment", "path": [] }, - "aiPrompt": "实际付款日期字段说明。", - "annotationText": "## 实际付款日期\n\n关联收款记录时取对应到账记录的付款日期;未关联时为空。\n\n---", + "aiPrompt": "实际付款日期字段的数据来源与计算口径。", + "annotationText": "## 实际付款日期\n\n**数据来源**:关联收款记录的到账日期。\n**计算方式**:有关联收款时取到账记录付款日期;未关联为空。\n**录入方式**:只读。\n\n**业务说明**:关联收款记录时取对应到账记录的付款日期;未关联时为空。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -555,7 +744,7 @@ }, { "id": "lbl-col-payment-method", - "index": 27, + "index": 36, "title": "付款方式", "pageId": "list", "locator": { @@ -565,8 +754,8 @@ "fingerprint": "lbl-col-payment-method", "path": [] }, - "aiPrompt": "付款方式字段说明。", - "annotationText": "## 付款方式\n\n由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。\n\n---", + "aiPrompt": "付款方式字段的数据来源与计算口径。", + "annotationText": "## 付款方式\n\n**数据来源**:合同付款周期月数。\n**计算方式**:1→月度预付,3→季度预付,6→半年预付,12→年度预付(resolvePaymentMethod)。\n**录入方式**:只读。\n\n**业务说明**:由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -576,7 +765,7 @@ }, { "id": "lbl-col-vehicle-standard-cost", - "index": 28, + "index": 37, "title": "车辆标准成本", "pageId": "list", "locator": { @@ -586,8 +775,8 @@ "fingerprint": "lbl-col-vehicle-standard-cost", "path": [] }, - "aiPrompt": "车辆标准成本字段说明。", - "annotationText": "## 车辆标准成本\n\n固定成本,按车型明细维护,只读。\n\n---", + "aiPrompt": "车辆标准成本字段的数据来源与计算口径。", + "annotationText": "## 车辆标准成本\n\n**数据来源**:车型成本明细 / 车牌标准成本配置(PLATE_STANDARD_COST)。\n**计算方式**:按车型维护的固定月标准成本。\n**录入方式**:只读。\n\n**业务说明**:固定成本,按车型明细维护,只读。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -597,7 +786,7 @@ }, { "id": "lbl-col-vehicle-actual-cost", - "index": 29, + "index": 38, "title": "车辆实际成本", "pageId": "list", "locator": { @@ -607,8 +796,8 @@ "fingerprint": "lbl-col-vehicle-actual-cost", "path": [] }, - "aiPrompt": "车辆实际成本字段说明。", - "annotationText": "## 车辆实际成本\n\n车辆标准成本 ×(实际天数 / 30),自动计算。\n\n---", + "aiPrompt": "车辆实际成本字段的数据来源与计算口径。", + "annotationText": "## 车辆实际成本\n\n**数据来源**:车辆标准成本、账单月内租赁天数。\n**计算方式**:车辆实际成本 = 标准成本 × 租赁天数 / 30(calcVehicleActualCost)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:车辆实际成本 = 车辆标准成本 × 账单月内租赁天数 / 30,自动计算。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -618,7 +807,7 @@ }, { "id": "lbl-col-insurance-fee", - "index": 30, + "index": 39, "title": "保险费", "pageId": "list", "locator": { @@ -628,8 +817,8 @@ "fingerprint": "lbl-col-insurance-fee", "path": [] }, - "aiPrompt": "保险费字段说明。", - "annotationText": "## 保险费\n\n暂保留,不可编辑和导入;后续可能自动计算。\n\n---", + "aiPrompt": "保险费字段的数据来源与计算口径。", + "annotationText": "## 保险费\n\n**数据来源**:保险采购金额、保险有效天数、账单月租赁天数。\n**计算方式**:保险费 =(采购金额 / 有效天数)× 租赁天数,四舍五入两位(calcInsuranceFee)。\n**录入方式**:只读。\n\n**业务说明**:保险费 =(保险采购金额 / 保险有效天数)× 账单月内租赁天数,四舍五入保留两位小数。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -639,7 +828,7 @@ }, { "id": "lbl-col-hydrogen-fee", - "index": 31, + "index": 40, "title": "氢费", "pageId": "list", "locator": { @@ -649,8 +838,8 @@ "fingerprint": "lbl-col-hydrogen-fee", "path": [] }, - "aiPrompt": "氢费字段说明。", - "annotationText": "## 氢费\n\n表头提示:仅显示合同氢费承担方式为「我司承担」时,该账单期内氢费总和(含未对账/已对账)。\n\n---", + "aiPrompt": "氢费字段的数据来源与计算口径。", + "annotationText": "## 氢费\n\n**数据来源**:氢费明细台账、合同氢费承担方式。\n**计算方式**:合同为「我司承担」时,汇总账单月内该车牌氢费(sumHydrogenFeeForBill);客户承担不计入。\n**录入方式**:只读。\n\n**业务说明**:仅汇总该账单月内、氢费明细中「我司承担」的氢费(含未对账/已对账);合同为客户承担时不计入。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -660,8 +849,8 @@ }, { "id": "lbl-col-ops-cost", - "index": 32, - "title": "运维费(成本侧)", + "index": 41, + "title": "运维费", "pageId": "list", "locator": { "selectors": [ @@ -670,8 +859,8 @@ "fingerprint": "lbl-col-ops-cost", "path": [] }, - "aiPrompt": "运维费(成本侧)字段说明。", - "annotationText": "## 运维费(成本侧)\n\n与收入侧运维费平进平出,自动同步。\n\n---", + "aiPrompt": "运维费字段的数据来源与计算口径。", + "annotationText": "## 运维费\n\n**数据来源**:维修/保养台账(我司承担)、账单月内该车牌。\n**计算方式**:汇总 bearBy=我司承担 的维保金额(sumMaintenanceForBill)。\n**录入方式**:只读。\n\n**业务说明**:成本侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「我司承担」的金额。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -681,7 +870,7 @@ }, { "id": "lbl-col-brokerage-fee", - "index": 33, + "index": 42, "title": "居间费", "pageId": "list", "locator": { @@ -691,8 +880,8 @@ "fingerprint": "lbl-col-brokerage-fee", "path": [] }, - "aiPrompt": "居间费字段说明。", - "annotationText": "## 居间费\n\n手动输入。\n\n---", + "aiPrompt": "居间费字段的数据来源与计算口径。", + "annotationText": "## 居间费\n\n**数据来源**:行内手工录入。\n**计算方式**:直接存储 brokerageFee 字段。\n**录入方式**:草稿可编辑。\n\n**业务说明**:手动输入。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -702,8 +891,8 @@ }, { "id": "lbl-col-other-cost", - "index": 34, - "title": "其他(成本侧)", + "index": 43, + "title": "其他", "pageId": "list", "locator": { "selectors": [ @@ -712,8 +901,8 @@ "fingerprint": "lbl-col-other-cost", "path": [] }, - "aiPrompt": "其他(成本侧)字段说明。", - "annotationText": "## 其他(成本侧)\n\n前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。\n\n---", + "aiPrompt": "其他字段的数据来源与计算口径。", + "annotationText": "## 其他\n\n**数据来源**:行内手工录入。\n**计算方式**:直接存储 otherCost;前方有其他收入时本项必填。\n**录入方式**:草稿可编辑。\n\n**业务说明**:前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -723,7 +912,7 @@ }, { "id": "lbl-col-gps-mileage", - "index": 35, + "index": 44, "title": "GPS里程", "pageId": "list", "locator": { @@ -733,8 +922,8 @@ "fingerprint": "lbl-col-gps-mileage", "path": [] }, - "aiPrompt": "GPS里程字段说明。", - "annotationText": "## GPS里程\n\n从 BI 里程取账单时间段的数据,自动展示。\n\n---", + "aiPrompt": "GPS里程字段的数据来源与计算口径。", + "annotationText": "## GPS里程\n\n**数据来源**:BI 里程数据(bi-mileage.json / 车机 GPS)。\n**计算方式**:lookupBiMileage(车牌, 年, 月) 取账单期里程。\n**录入方式**:只读。\n\n**业务说明**:从 BI 里程取账单时间段的数据,自动展示。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -744,7 +933,7 @@ }, { "id": "lbl-col-deduction-detail", - "index": 36, + "index": 45, "title": "其他减免金额明细内容", "pageId": "list", "locator": { @@ -754,8 +943,8 @@ "fingerprint": "lbl-col-deduction-detail", "path": [] }, - "aiPrompt": "其他减免金额明细内容字段说明。", - "annotationText": "## 其他减免金额明细内容\n\n手动输入,备注明细内容。\n\n---", + "aiPrompt": "其他减免金额明细内容字段的数据来源与计算口径。", + "annotationText": "## 其他减免金额明细内容\n\n**数据来源**:行内手工录入。\n**计算方式**:存储 otherDeductionDetail 文本。\n**录入方式**:草稿可编辑。\n\n**业务说明**:手动输入,备注明细内容。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -765,7 +954,7 @@ }, { "id": "lbl-col-asset-ownership", - "index": 37, + "index": 46, "title": "资产归属", "pageId": "list", "locator": { @@ -775,8 +964,8 @@ "fingerprint": "lbl-col-asset-ownership", "path": [] }, - "aiPrompt": "资产归属字段说明。", - "annotationText": "## 资产归属\n\n显示车辆实际归属公司名称,按车辆档案自动获取。\n\n---", + "aiPrompt": "资产归属字段的数据来源与计算口径。", + "annotationText": "## 资产归属\n\n**数据来源**:车辆档案资产归属。\n**计算方式**:按车牌从 PLATE_ASSET_OWNER / 车辆档案反写。\n**录入方式**:只读。\n\n**业务说明**:显示车辆实际归属公司名称,按车辆档案自动获取。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -786,7 +975,7 @@ }, { "id": "lbl-col-signing-company", - "index": 38, + "index": 47, "title": "签约公司", "pageId": "list", "locator": { @@ -796,8 +985,8 @@ "fingerprint": "lbl-col-signing-company", "path": [] }, - "aiPrompt": "签约公司字段说明。", - "annotationText": "## 签约公司\n\n租赁合同甲方,签订合同时自动获取;用于租赁总账利润归集。\n\n---", + "aiPrompt": "签约公司字段的数据来源与计算口径。", + "annotationText": "## 签约公司\n\n**数据来源**:租赁合同甲方。\n**计算方式**:按车牌匹配签订合同时甲方名称(PLATE_SIGNING_COMPANY)。\n**录入方式**:只读。\n\n**业务说明**:显示租赁合同签订时甲方名称。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], @@ -807,7 +996,7 @@ }, { "id": "lbl-col-remark", - "index": 39, + "index": 48, "title": "备注", "pageId": "list", "locator": { @@ -817,231 +1006,158 @@ "fingerprint": "lbl-col-remark", "path": [] }, - "aiPrompt": "备注字段说明。", - "annotationText": "## 备注\n\n手动输入。\n\n---", + "aiPrompt": "备注字段的数据来源与计算口径。", + "annotationText": "## 备注\n\n**数据来源**:行内手工录入。\n**计算方式**:存储 remark 文本。\n**录入方式**:草稿可编辑。\n\n**业务说明**:本列为人工手动填写。\n\n---", "hasMarkdown": true, "color": "#64748b", "images": [], "createdAt": 1740787200000, "updatedAt": 1782711877197, "controls": [] + }, + { + "id": "lbl-col-archive-status", + "index": 49, + "title": "账单状态", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-archive-status\"]" + ], + "fingerprint": "lbl-col-archive-status", + "path": [] + }, + "aiPrompt": "账单状态字段的数据来源与计算口径。", + "annotationText": "## 账单状态\n\n**数据来源**:账单归档状态字段 archiveStatus。\n**计算方式**:草稿 / 未归档 / 已归档;工具栏「保存」「设置为归档」批量变更。\n**录入方式**:仅草稿可编辑业务字段。\n\n**业务说明**:状态分为已归档、未归档、草稿。仅草稿可编辑;工具栏「保存」将勾选记录设为未归档(不可编辑);「设置为归档」将勾选记录锁定为已归档。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783259785963, + "controls": [] + }, + { + "id": "lbl-col-maintainer-time", + "index": 50, + "title": "维护时间", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-maintainer-time\"]" + ], + "fingerprint": "lbl-col-maintainer-time", + "path": [] + }, + "aiPrompt": "维护时间字段的数据来源与计算口径。", + "annotationText": "## 维护时间\n\n**数据来源**:台账行维护记录。\n**计算方式**:展示最近一次保存/维护时间(maintainerTime)。\n**录入方式**:系统记录,只读。\n\n**业务说明**:展示最近一次维护时间(YYYY-MM-DD HH:MM);维护人显示最后一次维护用户姓名。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783257117558, + "controls": [] + }, + { + "id": "lbl-col-dept", + "index": 51, + "title": "业务部门", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-dept\"]" + ], + "fingerprint": "lbl-col-dept", + "path": [] + }, + "aiPrompt": "业务部门字段说明。", + "annotationText": "## 业务部门\n\n**数据来源**:台账行业务部门、业务员字段。\n**计算方式**:导入或维护时写入,列表以「部门 + 业务员」两行展示。\n**录入方式**:导入/草稿可维护。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1782700000000, + "updatedAt": 1782700000000, + "controls": [] + }, + { + "id": "lbl-col-payment-date", + "index": 52, + "title": "付款日期", + "pageId": "list", + "locator": { + "selectors": [ + "[data-annotation-id=\"lbl-col-payment-date\"]" + ], + "fingerprint": "lbl-col-payment-date", + "path": [] + }, + "aiPrompt": "付款日期字段说明。", + "annotationText": "## 付款日期\n\n**数据来源**:收款记录关联反写。\n**计算方式**:关联租赁订单收款后反显收款日期。\n**录入方式**:只读。\n\n---", + "hasMarkdown": true, + "color": "#64748b", + "images": [], + "createdAt": 1740787200000, + "updatedAt": 1783251873620, + "controls": [] } ] }, "markdownMap": { - "lbl-filter": "## 2. 筛选区\n\n默认展示 4 项(一行),点击「更多筛选」展开全部 8 项。\n\n| 筛选项 | 说明 |\n|---|---|\n| 年份 / 月份 | 账单所属年月 |\n| 业务部门 / 业务员 | 精确匹配 |\n| 车牌号码 | 精确匹配 |\n| 客户名称 | 模糊包含 |\n| 明细状态 | 草稿 / 已确认 / 部分收款 / 已收款 |\n| 付款日期 | 日期区间 |\n\n---", + "lbl-filter": "## 2. 筛选区\n\n默认展示 4 项(一行),点击「更多筛选」展开全部 8 项。\n\n| 筛选项 | 说明 |\n|---|---|\n| 年份 / 月份 | 账单所属年月 |\n| 业务部门 / 业务员 | 精确匹配 |\n| 车牌号码 | 精确匹配 |\n| 客户名称 | 模糊包含 |\n| 明细状态 | 未收款 / 部分收款 / 已收款 |\n| 应付款日 | 单输入框双日历区间,精确至日 |\n\n---", "lbl-kpi": "## 3. KPI 统计卡片(6 张)\n\n台账条数、应收总计、实收总计、未收总计、成本总计、盈亏总计。\n\n- **台账条数**:员工仅统计本人录入;主管统计全组。点击切换列表为显示全部。\n- **未收总计**:点击筛选下方列表为未收款数据。\n\n---", "lbl-kpi-count": "## 台账条数 KPI\n\n业务服务组员工只能看到自己录入的数据条数以及金额;业务服务组主管可以查看所有业务服务组人员录入的数据总和。点击可切换列表显示全部数据。\n\n---", "lbl-kpi-unreceived": "## 未收总计 KPI\n\n点击未收总计卡片,下方列表仅展示未收款数据(状态不等于已收款)。\n\n---", - "lbl-toolbar": "## 4. 列表工具栏\n\n左侧「仅显示未收款数据」勾选后,列表仅显示状态不等于已收款的记录。\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板并上传 Excel(原型 Toast) |\n| 导出 | 导出当前筛选结果 |\n| 标记为已确认 | 勾选草稿行后二次确认 |\n| 提交收款审批 | 勾选行提交审批 |\n\n添加行已移至表格底部;列表采用下拉加载更多,不做分页。\n\n---", + "lbl-toolbar": "## 4. 列表工具栏\n\n左侧「仅显示未收款数据」勾选后,列表仅显示状态不等于已收款的记录。\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板并上传 Excel(原型 Toast) |\n| 导出 | 导出当前筛选结果 |\n| 保存 | 勾选记录后设为未归档,保存后不可编辑 |\n| 设置为归档 | 勾选记录后锁定为已归档 |\n\n表格底部提供分页,可切换页码与每页条数。\n\n---", "lbl-table": "## 5. 列表字段\n\n对齐 Excel「租赁车辆收入明细表」全量字段:年份、月份、业务部门(含业务员)、付款日期、车牌(含车型)、客户(含项目)、增值服务、享免政策、提车/合同/起止日期、平均天数、押金、合同标的租金、应收与收入拆分、减免、实收/未收、开票与付款信息、成本拆分、盈亏、GPS里程、减免明细、资产归属、签约公司、备注。\n\n宽表支持横向滚动;序号与操作列固定。", - "lbl-btn-mark-confirmed": "## 标记为已确认\n\n勾选草稿记录后点击,弹出二次确认:「确认后的数据只有主管才能继续进行修改,是否确认数据准确无误?」确认后状态变更为已确认,业务服务组人员不可再删改。\n\n---", - "lbl-col-status": "## 状态流转\n\n1. 新增/导入 → **草稿**(业务服务组可删改)\n2. 多选 + 「标记为已确认」→ **已确认**(仅主管可改)\n3. 已确认行可「关联收款记录」;到账合计 < 应收 → **部分收款**;≥ 应收 → **已收款**\n\n---", - "lbl-col-dept": "## 业务部门列\n\n业务部门与业务员合并为一列:上方业务部门,下方业务员。\n\n---", - "lbl-col-plate": "## 车牌号码列\n\n车牌与车型合并为一列:上方车牌号码,下方品牌与型号;导入/新增时按车牌在系统中自动匹配。\n\n---", - "lbl-col-customer": "## 客户名称列\n\n客户名称与项目名称合并为一列:上方客户名称,下方项目名称;按账单日期与车牌号自动匹配。\n\n---", - "lbl-col-unreceived": "## 未收金额\n\n未收金额 = 应收合计 − 实收金额,系统自动计算,不可手工录入。\n\n---", - "lbl-col-deposit": "## 保证金\n\n与创建合同时的保证金、提车应收款中的保证金等同;提车应收款有保证金时显示。\n\n---", - "lbl-col-contract-rent": "## 合同标的租金\n\n等于该车辆在签订该合同时合同中的租金(月租金标准)。\n\n---", - "lbl-col-receivable-rent": "## 应收租金\n\n按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。\n\n---", - "lbl-col-monthly-rent": "## 月度租金\n\n根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。\n\n---", - "lbl-col-actual-payment": "## 实际付款日期\n\n关联收款记录时取对应到账记录的付款日期;未关联时为空。\n\n---", - "lbl-col-payment-method": "## 付款方式\n\n由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。\n\n---", - "lbl-col-asset-ownership": "## 资产归属\n\n显示车辆实际归属公司名称,按车辆档案自动获取。\n\n---", - "lbl-col-signing-company": "## 签约公司\n\n租赁合同甲方,签订合同时自动获取;用于租赁总账利润归集。\n\n---", - "lbl-col-pickup-date": "## 提车日期\n\n等于交车管理中该车辆运维 E 签宝签字完成的时间。\n\n---", - "lbl-btn-add-row": "## 添加行\n\n位于表格底部;列表不做分页,采用下拉加载更多,避免多选受分页限制。\n\n---", - "lbl-col-other-income": "## 其他收入\n\n手工填写,预留作为特殊情况记录使用。\n\n---", - "lbl-col-ops-income": "## 运维费(收入侧)\n\n维修/保养台账为「客户承担」时,最新一期账单显示警示图标,提醒关联维修/保养记录;关联后自动汇总运维费,支持多选。\n\n---", - "lbl-col-insurance-surcharge": "## 保险上浮费\n\n事故中有保险上浮费时,最新账单显示警示标志;关联事故单后自动汇总上浮费,支持多选。\n\n---", - "lbl-col-maintenance-income": "## 维保包干收入\n\n合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。\n\n---", - "lbl-col-monthly-income": "## 月度收入\n\n租金 + 服务费 − 里程减免金额 − 其他减免金额(后两项为减项)。\n\n---", - "lbl-col-remark": "## 备注\n\n手动输入。\n\n---", - "lbl-col-deduction-detail": "## 其他减免金额明细内容\n\n手动输入,备注明细内容。\n\n---", - "lbl-col-gps-mileage": "## GPS里程\n\n从 BI 里程取账单时间段的数据,自动展示。\n\n---", - "lbl-col-other-cost": "## 其他(成本侧)\n\n前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。\n\n---", - "lbl-col-brokerage-fee": "## 居间费\n\n手动输入。\n\n---", - "lbl-col-ops-cost": "## 运维费(成本侧)\n\n与收入侧运维费平进平出,自动同步。\n\n---", - "lbl-col-hydrogen-fee": "## 氢费\n\n表头提示:仅显示合同氢费承担方式为「我司承担」时,该账单期内氢费总和(含未对账/已对账)。\n\n---", - "lbl-col-insurance-fee": "## 保险费\n\n暂保留,不可编辑和导入;后续可能自动计算。\n\n---", - "lbl-col-vehicle-actual-cost": "## 车辆实际成本\n\n车辆标准成本 ×(实际天数 / 30),自动计算。\n\n---", - "lbl-col-vehicle-standard-cost": "## 车辆标准成本\n\n固定成本,按车型明细维护,只读。\n\n---", - "lbl-col-invoice-date": "## 开票日期\n\n账单开票后由财务维护,自动反写,只读。\n\n---", - "lbl-col-received-amount": "## 实收金额\n\n根据财务导入收款明细归集;支持关联多条并分配计入金额;超出应收部分在单据下自行分配。\n\n---" + "lbl-col-status": "## 状态\n\n**数据来源**:收款记录模块中关联到本账单的分配金额、账单应收合计。\n**计算方式**:分配金额 ≥ 应收合计且应收 > 0 → 已收款;0 < 分配金额 < 应收 → 部分收款;未关联收款 → 未收款。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:当收款记录中分配金额完全覆盖账单的应收金额时,显示已收款。当收款记录中分配金额≤账单的应收金额时,显示部分收款。未分配收款记录时,显示为未收款。其他状态去除\n\n---", + "lbl-col-dept": "## 业务部门\n\n**数据来源**:台账行业务部门、业务员字段。\n**计算方式**:导入或维护时写入,列表以「部门 + 业务员」两行展示。\n**录入方式**:导入/草稿可维护。\n\n---", + "lbl-col-plate": "## 车牌号码\n\n**数据来源**:车辆档案(按车牌匹配品牌、型号)。\n**计算方式**:导入/新增台账时按车牌号反写车辆信息。\n**录入方式**:只读展示(车牌 + 车型两行)。\n\n**业务说明**:车牌与车型合并为一列:上方车牌号码,下方品牌与型号;导入/新增时按车牌在系统中自动匹配。\n\n---", + "lbl-col-customer": "## 客户名称\n\n**数据来源**:租赁合同(按账单日期 + 车牌匹配客户、项目)。\n**计算方式**:匹配当前车辆在账期内的有效合同,带出客户名称与项目名称。\n**录入方式**:只读展示(客户 + 项目两行)。\n\n**业务说明**:客户名称与项目名称合并为一列:上方客户名称,下方项目名称;按账单日期与车牌号自动匹配。\n\n---", + "lbl-col-unreceived": "## 未收金额\n\n**数据来源**:应收合计、实收金额。\n**计算方式**:未收金额 = 应收合计 − 实收金额(calcUnreceived)。\n**录入方式**:系统自动计算,不可手工录入。\n\n**业务说明**:未收金额 = 应收合计 − 实收金额,系统自动计算,不可手工录入。\n\n---", + "lbl-col-deposit": "## 保证金\n\n**数据来源**:提车应收款 / 合同保证金。\n**计算方式**:与创建合同时保证金、提车应收款中该车辆保证金一致。\n**录入方式**:只读。\n\n**业务说明**:显示该车辆实付保证金金额,与提车应收款时该车辆收取的提车应收款相同。\n\n---", + "lbl-col-contract-rent": "## 合同标的租金\n\n**数据来源**:租赁合同月租金标准。\n**计算方式**:签订合同时该车辆的月租金(合同标的租金)。\n**录入方式**:合同带入,只读。\n\n**业务说明**:等于该车辆在签订该合同时合同中的租金(月租金标准)。\n\n---", + "lbl-col-receivable-rent": "## 应收租金\n\n**数据来源**:合同标的租金、合同付款周期月数。\n**计算方式**:应收租金 = 合同标的租金 × 付款周期月数(1/3/6/12)(calcReceivableRent)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。\n\n---", + "lbl-col-monthly-rent": "## 月度租金\n\n**数据来源**:合同标的租金。\n**计算方式**:月度租金 = 合同标的租金(calcMonthlyRent)。\n**录入方式**:只读。\n\n**业务说明**:根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。\n\n---", + "lbl-col-actual-payment": "## 实际付款日期\n\n**数据来源**:关联收款记录的到账日期。\n**计算方式**:有关联收款时取到账记录付款日期;未关联为空。\n**录入方式**:只读。\n\n**业务说明**:关联收款记录时取对应到账记录的付款日期;未关联时为空。\n\n---", + "lbl-col-payment-method": "## 付款方式\n\n**数据来源**:合同付款周期月数。\n**计算方式**:1→月度预付,3→季度预付,6→半年预付,12→年度预付(resolvePaymentMethod)。\n**录入方式**:只读。\n\n**业务说明**:由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。\n\n---", + "lbl-col-asset-ownership": "## 资产归属\n\n**数据来源**:车辆档案资产归属。\n**计算方式**:按车牌从 PLATE_ASSET_OWNER / 车辆档案反写。\n**录入方式**:只读。\n\n**业务说明**:显示车辆实际归属公司名称,按车辆档案自动获取。\n\n---", + "lbl-col-signing-company": "## 签约公司\n\n**数据来源**:租赁合同甲方。\n**计算方式**:按车牌匹配签订合同时甲方名称(PLATE_SIGNING_COMPANY)。\n**录入方式**:只读。\n\n**业务说明**:显示租赁合同签订时甲方名称。\n\n---", + "lbl-col-pickup-date": "## 提车日期\n\n**数据来源**:交车管理 / 运维 E 签宝签字完成时间。\n**计算方式**:取该车辆实际交车办结时间。\n**录入方式**:只读。\n\n**业务说明**:运维实际交车日期。\n\n---", + "lbl-col-other-income": "## 其他收入\n\n**数据来源**:行内其他收入明细(事由、金额、备注)。\n**计算方式**:多条明细金额合计计入应收与月度收入(sumLineItems)。\n**录入方式**:草稿状态可编辑明细。\n\n**业务说明**:支持多条明细录入(事由、金额、备注);合计自动计入应收与月度收入。\n\n---", + "lbl-col-ops-income": "## 运维费\n\n**数据来源**:维修/保养台账(客户承担)、账单月内该车牌完工记录。\n**计算方式**:汇总 bearBy=客户承担 的维保金额;可关联 linkedMaintenanceIds(sumMaintenanceForBill)。\n**录入方式**:关联后自动汇总;最新账单可关联记录。\n\n**业务说明**:收入侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「客户承担」的金额;最新一期账单可关联记录。\n\n---", + "lbl-col-insurance-surcharge": "## 保险上浮费\n\n**数据来源**:事故台账关联的保险上浮费。\n**计算方式**:关联事故单后汇总 linkedAccidentIds 对应上浮费;最新账单未关联时显示警示。\n**录入方式**:关联后自动汇总,支持多选事故单。\n\n**业务说明**:事故中有保险上浮费时,最新账单显示警示标志;关联事故单后自动汇总上浮费,支持多选。\n\n---", + "lbl-col-maintenance-income": "## 维保包干收入\n\n**数据来源**:合同维保包干配置、账单里程。\n**计算方式**:勾选维保包干时:单价(元/km)× 里程数;未勾选为 0(calcMaintenanceIncome)。\n**录入方式**:包干未勾选时不可编辑。\n\n**业务说明**:合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。\n\n---", + "lbl-col-monthly-income": "## 月度收入\n\n**数据来源**:月度租金、维保包干、保险上浮费、运维费(收入侧)、其他收入、减免项。\n**计算方式**:月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免 − 其他减免(calcMonthlyIncome)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。\n\n---", + "lbl-col-remark": "## 备注\n\n**数据来源**:行内手工录入。\n**计算方式**:存储 remark 文本。\n**录入方式**:草稿可编辑。\n\n**业务说明**:本列为人工手动填写。\n\n---", + "lbl-col-deduction-detail": "## 其他减免金额明细内容\n\n**数据来源**:行内手工录入。\n**计算方式**:存储 otherDeductionDetail 文本。\n**录入方式**:草稿可编辑。\n\n**业务说明**:手动输入,备注明细内容。\n\n---", + "lbl-col-gps-mileage": "## GPS里程\n\n**数据来源**:BI 里程数据(bi-mileage.json / 车机 GPS)。\n**计算方式**:lookupBiMileage(车牌, 年, 月) 取账单期里程。\n**录入方式**:只读。\n\n**业务说明**:从 BI 里程取账单时间段的数据,自动展示。\n\n---", + "lbl-col-other-cost": "## 其他\n\n**数据来源**:行内手工录入。\n**计算方式**:直接存储 otherCost;前方有其他收入时本项必填。\n**录入方式**:草稿可编辑。\n\n**业务说明**:前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。\n\n---", + "lbl-col-brokerage-fee": "## 居间费\n\n**数据来源**:行内手工录入。\n**计算方式**:直接存储 brokerageFee 字段。\n**录入方式**:草稿可编辑。\n\n**业务说明**:手动输入。\n\n---", + "lbl-col-ops-cost": "## 运维费\n\n**数据来源**:维修/保养台账(我司承担)、账单月内该车牌。\n**计算方式**:汇总 bearBy=我司承担 的维保金额(sumMaintenanceForBill)。\n**录入方式**:只读。\n\n**业务说明**:成本侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「我司承担」的金额。\n\n---", + "lbl-col-hydrogen-fee": "## 氢费\n\n**数据来源**:氢费明细台账、合同氢费承担方式。\n**计算方式**:合同为「我司承担」时,汇总账单月内该车牌氢费(sumHydrogenFeeForBill);客户承担不计入。\n**录入方式**:只读。\n\n**业务说明**:仅汇总该账单月内、氢费明细中「我司承担」的氢费(含未对账/已对账);合同为客户承担时不计入。\n\n---", + "lbl-col-insurance-fee": "## 保险费\n\n**数据来源**:保险采购金额、保险有效天数、账单月租赁天数。\n**计算方式**:保险费 =(采购金额 / 有效天数)× 租赁天数,四舍五入两位(calcInsuranceFee)。\n**录入方式**:只读。\n\n**业务说明**:保险费 =(保险采购金额 / 保险有效天数)× 账单月内租赁天数,四舍五入保留两位小数。\n\n---", + "lbl-col-vehicle-actual-cost": "## 车辆实际成本\n\n**数据来源**:车辆标准成本、账单月内租赁天数。\n**计算方式**:车辆实际成本 = 标准成本 × 租赁天数 / 30(calcVehicleActualCost)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:车辆实际成本 = 车辆标准成本 × 账单月内租赁天数 / 30,自动计算。\n\n---", + "lbl-col-vehicle-standard-cost": "## 车辆标准成本\n\n**数据来源**:车型成本明细 / 车牌标准成本配置(PLATE_STANDARD_COST)。\n**计算方式**:按车型维护的固定月标准成本。\n**录入方式**:只读。\n\n**业务说明**:固定成本,按车型明细维护,只读。\n\n---", + "lbl-col-invoice-date": "## 开票日期\n\n**数据来源**:关联收款记录中的开票信息。\n**计算方式**:resolveInvoiceDateFromReceipts 取关联收款单开票日期。\n**录入方式**:只读。\n\n**业务说明**:从「收款记录」功能关联开票记录,显示开票日期。\n\n---", + "lbl-col-received-amount": "## 实收金额\n\n**数据来源**:收款记录模块关联分配金额。\n**计算方式**:关联收款单后按分配计入金额汇总,不超过应收合计(calcReceivedAmountFromReceipts)。\n**录入方式**:通过「关联收款」操作维护。\n\n**业务说明**:从「收款记录」功能关联该账单后分配的实收金额;点击可查看收款明细列表。\n\n---", + "lbl-col-payment-due": "## 应付款日\n\n**数据来源**:账单起始日期(优先)或提车日期作为开始计费日;账单所属年月。\n**计算方式**:首期账单应付款日 = 开始计费日;后续每期 = 账单所属自然月 5 日。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:交车后按「开始计费日期」生成首期账单应付款日;后续每期账单在所属自然月 5 日生成下一期应付款日。\n\n---", + "lbl-col-payment-date": "## 付款日期\n\n**数据来源**:收款记录关联反写。\n**计算方式**:关联租赁订单收款后反显收款日期。\n**录入方式**:只读。\n\n---", + "lbl-col-value-added-service": "## 增值服务\n\n**数据来源**:租赁合同签订时勾选的增值服务项目。\n**计算方式**:按车牌匹配合同增值服务配置,多项服务分行展示。\n**录入方式**:只读。\n\n**业务说明**:签订合同时勾选的增值服务项目,按车牌自动匹配合同数据;多项服务各占一行展示。\n\n---", + "lbl-col-contract-start-date": "## 合同生效日期\n\n**数据来源**:提车日期(交车办结时间)。\n**计算方式**:合同生效日期 = 提车日期(YYYY-MM-DD),系统自动反写。\n**录入方式**:系统自动反写,只读。\n\n**业务说明**:等于提车日期,即租赁合同生效日期,系统自动反写,只读。\n\n---", + "lbl-col-contract-end-date": "## 合同到期日期\n\n**数据来源**:合同租期月数 + 提车日期,或合同约定的到期日。\n**计算方式**:日期模式:取合同存储的 contractEndDate;租期模式:提车日 + leaseTermMonths 个月。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:合同到期日:租期模式按提车日期 + 租期月数计算;日期模式取合同中约定的到期日。\n\n---", + "lbl-col-period-start-date": "## 起始日期\n\n**数据来源**:账单年月、提车日期。\n**计算方式**:月前已提车 → 当月 1 日;月内提车 → 提车日;月后提车 → 空(calcPeriodStartDate)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:账单所属月内的租赁起始日:月前已提车取当月 1 日,月内提车取提车日;系统自动计算,只读。\n\n---", + "lbl-col-return-date": "## 退车日期\n\n**数据来源**:退车管理登记的退车日期。\n**计算方式**:取该车牌退车办结日期;未退车为空。\n**录入方式**:只读。\n\n**业务说明**:退车管理中登记的退车日期;未退车时为空。\n\n---", + "lbl-col-avg-days": "## 平均天数\n\n**数据来源**:账单月内租赁天数、当月自然日天数。\n**计算方式**:平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数(calcAvgDays)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数;用于成本分摊口径。\n\n---", + "lbl-col-receivable-total": "## 应收合计\n\n**数据来源**:应收租金、保险上浮费、运维费(收入侧)、其他收入、里程/其他减免。\n**计算方式**:应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免 − 其他减免(calcReceivableTotal)。\n**录入方式**:系统自动汇总,只读。\n\n**业务说明**:应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。\n\n---", + "lbl-col-mileage-deduction": "## 里程减免金额\n\n**数据来源**:BI 里程(GPS)、里程减免单价。\n**计算方式**:里程减免 = GPS 里程 × 单价;有 GPS 时默认 0.5 元/km,无 GPS 为 0(calcMileageDeduction)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:里程减免金额 = GPS 里程 × 里程减免单价;有 GPS 里程时默认单价 0.5 元/km,无 GPS 时为 0。\n\n---", + "lbl-col-other-deduction": "## 其他减免金额\n\n**数据来源**:行内其他减免明细。\n**计算方式**:多条明细金额合计,从应收与月度收入扣减(sumLineItems)。\n**录入方式**:草稿状态可编辑明细。\n\n**业务说明**:支持多条明细录入(事由、金额、备注);合计自动从应收与月度收入中扣减。\n\n---", + "lbl-col-maintainer-time": "## 维护时间\n\n**数据来源**:台账行维护记录。\n**计算方式**:展示最近一次保存/维护时间(maintainerTime)。\n**录入方式**:系统记录,只读。\n\n**业务说明**:展示最近一次维护时间(YYYY-MM-DD HH:MM);维护人显示最后一次维护用户姓名。\n\n---", + "lbl-col-archive-status": "## 账单状态\n\n**数据来源**:账单归档状态字段 archiveStatus。\n**计算方式**:草稿 / 未归档 / 已归档;工具栏「保存」「设置为归档」批量变更。\n**录入方式**:仅草稿可编辑业务字段。\n\n**业务说明**:状态分为已归档、未归档、草稿。仅草稿可编辑;工具栏「保存」将勾选记录设为未归档(不可编辑);「设置为归档」将勾选记录锁定为已归档。\n\n---", + "lbl-btn-set-archived": "## 设置为归档\n\n勾选台账记录后点击,将账单状态设为**已归档**并锁定编辑。\n\n---", + "lbl-btn-save-unarchived": "## 保存\n\n勾选台账记录后点击,将账单状态设为**未归档**。未归档数据不可编辑,仅草稿可编辑。\n\n---" }, "assetMap": {}, "directory": { "nodes": [ - { - "type": "folder", - "id": "oneos-project-nav", - "title": "ONE-OS 原型导航", - "defaultExpanded": true, - "children": [ - { - "type": "link", - "id": "nav-link-contract-template-management", - "title": "合同模板管理", - "href": "/prototypes/contract-template-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-insurance-procurement", - "title": "保险采购", - "href": "/prototypes/insurance-procurement", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-vehicle-management", - "title": "车辆管理", - "href": "/prototypes/vehicle-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-lease-contract-management", - "title": "租赁合同管理", - "href": "/prototypes/lease-contract-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-customer-management", - "title": "客户管理", - "href": "/prototypes/customer-management", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-lease-business-ledger", - "title": "租赁业务台账(当前)", - "href": "/prototypes/lease-business-ledger", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-vehicle-h2-fee-ledger", - "title": "车辆氢费明细", - "href": "/prototypes/vehicle-h2-fee-ledger", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-self-operated-business-ledger", - "title": "自营业务台账", - "href": "/prototypes/self-operated-business-ledger", - "target": "self" - }, - { - "type": "folder", - "id": "nav-folder-prototypes-oneos-web", - "title": "ONE-OS Web 端", - "defaultExpanded": true, - "children": [ - { - "type": "link", - "id": "nav-link-oneos-web-workbench", - "title": "工作台", - "href": "/prototypes/oneos-web-workbench", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-login", - "title": "登录", - "href": "/prototypes/oneos-web-login", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-vehicle-asset", - "title": "车辆管理", - "href": "/prototypes/oneos-web-vehicle-asset", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-contract-template", - "title": "合同模板管理", - "href": "/prototypes/oneos-web-contract-template", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-help-center", - "title": "帮助中心", - "href": "/prototypes/oneos-web-help-center", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-finance", - "title": "财务管理", - "href": "/prototypes/oneos-web-finance", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-procurement", - "title": "采购管理", - "href": "/prototypes/oneos-web-procurement", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-lease-contract", - "title": "车辆租赁合同", - "href": "/prototypes/oneos-web-lease-contract", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-h2-station", - "title": "加氢站管理", - "href": "/prototypes/oneos-web-h2-station", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-data-analysis", - "title": "数据分析", - "href": "/prototypes/oneos-web-data-analysis", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-ledger-data", - "title": "台账数据", - "href": "/prototypes/oneos-web-ledger-data", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-business", - "title": "业务管理", - "href": "/prototypes/oneos-web-business", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-ops", - "title": "运维管理", - "href": "/prototypes/oneos-web-ops", - "target": "self" - }, - { - "type": "link", - "id": "nav-link-oneos-web-requirements", - "title": "需求说明", - "href": "/prototypes/oneos-web-requirements", - "target": "self" - } - ] - } - ] - }, { "type": "folder", "id": "lbl-doc-root", @@ -1052,20 +1168,20 @@ "type": "markdown", "id": "lbl-doc-overview", "title": "模块总览", - "markdown": "## 1. 模块定位\n\n| 项 | 说明 |\n|---|---|\n| 模块名称 | 台账数据 — 租赁业务台账 |\n| 目标用户 | 租赁业务客服、业务服务组主管 |\n| 核心任务 | 维护租赁运营明细、汇总应收实收与盈亏、标记确认与关联收款 |\n| 页面结构 | 筛选区 + KPI 统计 + 工具栏 + 宽表 + 下拉加载更多(不做分页) |\n\n---" + "markdown": "## 1. 模块定位\n\n| 项 | 说明 |\n|---|---|\n| 模块名称 | 台账数据 — 租赁业务台账 |\n| 目标用户 | 租赁业务客服、业务服务组主管 |\n| 核心任务 | 维护租赁运营明细、汇总应收实收与盈亏、关联收款记录 |\n| 页面结构 | 筛选区 + KPI 统计 + 工具栏 + 宽表 + 底部分页 |\n\n---" }, { "type": "link", "id": "lbl-link-self", "title": "租赁业务台账原型", - "href": "./index.html", + "href": "/prototypes/lease-business-ledger", "target": "self" }, { "type": "markdown", "id": "lbl-doc-prd", "title": "PRD 全文", - "markdown": "# 租赁业务台账 · 产品需求说明(PRD)\n\n> 对齐《租赁业务运营明细台账模版》;业务服务组维护各自台账,标记已确认与收款关联为原型演示。\n\n---\n\n## 1. 模块定位\n\n| 项 | 说明 |\n|---|---|\n| 模块名称 | 台账数据 — 租赁业务台账 |\n| 目标用户 | 租赁业务客服、业务服务组主管 |\n| 核心任务 | 维护租赁运营明细、汇总应收实收与盈亏、标记确认与关联收款 |\n| 页面结构 | 筛选区 + KPI 统计 + 工具栏 + 宽表 + 下拉加载更多(不做分页) |\n\n---\n\n## 2. 筛选区\n\n默认展示 4 项(一行),点击「更多筛选」展开全部 8 项。\n\n| 筛选项 | 说明 |\n|---|---|\n| 年份 / 月份 | 账单所属年月 |\n| 业务部门 / 业务员 | 精确匹配 |\n| 车牌号码 | 精确匹配 |\n| 客户名称 | 模糊包含 |\n| 明细状态 | 草稿 / 已确认 / 部分收款 / 已收款 |\n| 付款日期 | 日期区间 |\n\n---\n\n## 3. KPI 统计卡片(6 张)\n\n台账条数、应收总计、实收总计、未收总计、成本总计、盈亏总计。\n\n- **台账条数**:员工仅统计本人录入;主管统计全组。点击切换列表为显示全部。\n- **未收总计**:点击筛选下方列表为未收款数据。\n\n### 台账条数 KPI\n\n业务服务组员工只能看到自己录入的数据条数以及金额;业务服务组主管可以查看所有业务服务组人员录入的数据总和。点击可切换列表显示全部数据。\n\n### 未收总计 KPI\n\n点击未收总计卡片,下方列表仅展示未收款数据(状态不等于已收款)。\n\n---\n\n## 4. 列表工具栏\n\n左侧「仅显示未收款数据」勾选后,列表仅显示状态不等于已收款的记录。\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板并上传 Excel(原型 Toast) |\n| 导出 | 导出当前筛选结果 |\n| 标记为已确认 | 勾选草稿行后二次确认 |\n| 提交收款审批 | 勾选行提交审批 |\n\n添加行已移至表格底部;列表采用下拉加载更多,不做分页。\n\n### 标记为已确认\n\n勾选草稿记录后点击,弹出二次确认:「确认后的数据只有主管才能继续进行修改,是否确认数据准确无误?」确认后状态变更为已确认,业务服务组人员不可再删改。\n\n### 添加行\n\n位于表格底部;列表不做分页,采用下拉加载更多,避免多选受分页限制。\n\n---\n\n## 5. 列表字段\n\n对齐 Excel「租赁车辆收入明细表」全量字段:年份、月份、业务部门(含业务员)、付款日期、车牌(含车型)、客户(含项目)、增值服务、享免政策、提车/合同/起止日期、平均天数、押金、合同标的租金、应收与收入拆分、减免、实收/未收、开票与付款信息、成本拆分、盈亏、GPS里程、减免明细、资产归属、签约公司、备注。\n\n宽表支持横向滚动;序号与操作列固定。\n\n---\n\n## 6. 状态流转\n\n1. 新增/导入 → **草稿**(业务服务组可删改)\n2. 多选 + 「标记为已确认」→ **已确认**(仅主管可改)\n3. 已确认行可「关联收款记录」;到账合计 < 应收 → **部分收款**;≥ 应收 → **已收款**\n\n---\n\n## 7. 字段说明\n\n### 业务部门列\n\n业务部门与业务员合并为一列:上方业务部门,下方业务员。\n\n### 车牌号码列\n\n车牌与车型合并为一列:上方车牌号码,下方品牌与型号;导入/新增时按车牌在系统中自动匹配。\n\n### 客户名称列\n\n客户名称与项目名称合并为一列:上方客户名称,下方项目名称;按账单日期与车牌号自动匹配。\n\n### 提车日期\n\n等于交车管理中该车辆运维 E 签宝签字完成的时间。\n\n### 保证金\n\n与创建合同时的保证金、提车应收款中的保证金等同;提车应收款有保证金时显示。\n\n### 合同标的租金\n\n等于该车辆在签订该合同时合同中的租金(月租金标准)。\n\n### 应收租金\n\n按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。\n\n### 月度收入\n\n租金 + 服务费 − 里程减免金额 − 其他减免金额(后两项为减项)。\n\n### 月度租金\n\n根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。\n\n### 维保包干收入\n\n合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。\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### 实际付款日期\n\n关联收款记录时取对应到账记录的付款日期;未关联时为空。\n\n### 付款方式\n\n由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。\n\n### 车辆标准成本\n\n固定成本,按车型明细维护,只读。\n\n### 车辆实际成本\n\n车辆标准成本 ×(实际天数 / 30),自动计算。\n\n### 保险费\n\n暂保留,不可编辑和导入;后续可能自动计算。\n\n### 氢费\n\n表头提示:仅显示合同氢费承担方式为「我司承担」时,该账单期内氢费总和(含未对账/已对账)。\n\n### 运维费(成本侧)\n\n与收入侧运维费平进平出,自动同步。\n\n### 居间费\n\n手动输入。\n\n### 其他(成本侧)\n\n前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。\n\n### GPS里程\n\n从 BI 里程取账单时间段的数据,自动展示。\n\n### 其他减免金额明细内容\n\n手动输入,备注明细内容。\n\n### 资产归属\n\n显示车辆实际归属公司名称,按车辆档案自动获取。\n\n### 签约公司\n\n租赁合同甲方,签订合同时自动获取;用于租赁总账利润归集。\n\n### 备注\n\n手动输入。", + "markdown": "# 租赁业务台账 · 产品需求说明(PRD)\n\n> 对齐《租赁业务运营明细台账模版》;业务服务组维护各自台账,收款关联与状态自动计算为原型演示。\n\n---\n\n## 1. 模块定位\n\n| 项 | 说明 |\n|---|---|\n| 模块名称 | 台账数据 — 租赁业务台账 |\n| 目标用户 | 租赁业务客服、业务服务组主管 |\n| 核心任务 | 维护租赁运营明细、汇总应收实收与盈亏、关联收款记录 |\n| 页面结构 | 筛选区 + KPI 统计 + 工具栏 + 宽表 + 底部分页 |\n\n---\n\n## 2. 筛选区\n\n默认展示 4 项(一行),点击「更多筛选」展开全部 8 项。\n\n| 筛选项 | 说明 |\n|---|---|\n| 年份 / 月份 | 账单所属年月 |\n| 业务部门 / 业务员 | 精确匹配 |\n| 车牌号码 | 精确匹配 |\n| 客户名称 | 模糊包含 |\n| 明细状态 | 未收款 / 部分收款 / 已收款 |\n| 应付款日 | 单输入框双日历区间,精确至日 |\n\n---\n\n## 3. KPI 统计卡片(6 张)\n\n台账条数、应收总计、实收总计、未收总计、成本总计、盈亏总计。\n\n- **台账条数**:员工仅统计本人录入;主管统计全组。点击切换列表为显示全部。\n- **未收总计**:点击筛选下方列表为未收款数据。\n\n### 台账条数 KPI\n\n业务服务组员工只能看到自己录入的数据条数以及金额;业务服务组主管可以查看所有业务服务组人员录入的数据总和。点击可切换列表显示全部数据。\n\n### 未收总计 KPI\n\n点击未收总计卡片,下方列表仅展示未收款数据(状态不等于已收款)。\n\n---\n\n## 4. 列表工具栏\n\n左侧「仅显示未收款数据」勾选后,列表仅显示状态不等于已收款的记录。\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板并上传 Excel(原型 Toast) |\n| 导出 | 导出当前筛选结果 |\n| 保存 | 勾选记录后设为未归档,保存后不可编辑 |\n| 设置为归档 | 勾选记录后锁定为已归档 |\n\n表格底部提供分页,可切换页码与每页条数。\n\n### 保存\n\n勾选台账记录后点击,将账单状态设为**未归档**。未归档数据不可编辑,仅草稿可编辑。\n\n### 设置为归档\n\n勾选台账记录后点击,将账单状态设为**已归档**并锁定编辑。\n\n---\n\n## 5. 列表字段\n\n对齐 Excel「租赁车辆收入明细表」全量字段:年份、月份、业务部门(含业务员)、付款日期、车牌(含车型)、客户(含项目)、增值服务、享免政策、提车/合同/起止日期、平均天数、押金、合同标的租金、应收与收入拆分、减免、实收/未收、开票与付款信息、成本拆分、盈亏、GPS里程、减免明细、资产归属、签约公司、备注。\n\n宽表支持横向滚动;序号与操作列固定。\n\n---\n\n## 6. 收款状态\n\n## 状态\n\n**数据来源**:收款记录模块中关联到本账单的分配金额、账单应收合计。\n**计算方式**:分配金额 ≥ 应收合计且应收 > 0 → 已收款;0 < 分配金额 < 应收 → 部分收款;未关联收款 → 未收款。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:当收款记录中分配金额完全覆盖账单的应收金额时,显示已收款。当收款记录中分配金额≤账单的应收金额时,显示部分收款。未分配收款记录时,显示为未收款。其他状态去除\n\n---\n\n## 7. 字段说明\n\n### 应付款日\n\n**数据来源**:账单起始日期(优先)或提车日期作为开始计费日;账单所属年月。\n**计算方式**:首期账单应付款日 = 开始计费日;后续每期 = 账单所属自然月 5 日。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:交车后按「开始计费日期」生成首期账单应付款日;后续每期账单在所属自然月 5 日生成下一期应付款日。\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### 提车日期\n\n**数据来源**:交车管理 / 运维 E 签宝签字完成时间。\n**计算方式**:取该车辆实际交车办结时间。\n**录入方式**:只读。\n\n**业务说明**:运维实际交车日期。\n\n### 合同生效日期\n\n**数据来源**:提车日期(交车办结时间)。\n**计算方式**:合同生效日期 = 提车日期(YYYY-MM-DD),系统自动反写。\n**录入方式**:系统自动反写,只读。\n\n**业务说明**:等于提车日期,即租赁合同生效日期,系统自动反写,只读。\n\n### 合同到期日期\n\n**数据来源**:合同租期月数 + 提车日期,或合同约定的到期日。\n**计算方式**:日期模式:取合同存储的 contractEndDate;租期模式:提车日 + leaseTermMonths 个月。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:合同到期日:租期模式按提车日期 + 租期月数计算;日期模式取合同中约定的到期日。\n\n### 起始日期\n\n**数据来源**:账单年月、提车日期。\n**计算方式**:月前已提车 → 当月 1 日;月内提车 → 提车日;月后提车 → 空(calcPeriodStartDate)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:账单所属月内的租赁起始日:月前已提车取当月 1 日,月内提车取提车日;系统自动计算,只读。\n\n### 退车日期\n\n**数据来源**:退车管理登记的退车日期。\n**计算方式**:取该车牌退车办结日期;未退车为空。\n**录入方式**:只读。\n\n**业务说明**:退车管理中登记的退车日期;未退车时为空。\n\n### 平均天数\n\n**数据来源**:账单月内租赁天数、当月自然日天数。\n**计算方式**:平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数(calcAvgDays)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数;用于成本分摊口径。\n\n### 保证金\n\n**数据来源**:提车应收款 / 合同保证金。\n**计算方式**:与创建合同时保证金、提车应收款中该车辆保证金一致。\n**录入方式**:只读。\n\n**业务说明**:显示该车辆实付保证金金额,与提车应收款时该车辆收取的提车应收款相同。\n\n### 合同标的租金\n\n**数据来源**:租赁合同月租金标准。\n**计算方式**:签订合同时该车辆的月租金(合同标的租金)。\n**录入方式**:合同带入,只读。\n\n**业务说明**:等于该车辆在签订该合同时合同中的租金(月租金标准)。\n\n### 应收合计\n\n**数据来源**:应收租金、保险上浮费、运维费(收入侧)、其他收入、里程/其他减免。\n**计算方式**:应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免 − 其他减免(calcReceivableTotal)。\n**录入方式**:系统自动汇总,只读。\n\n**业务说明**:应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。\n\n### 应收租金\n\n**数据来源**:合同标的租金、合同付款周期月数。\n**计算方式**:应收租金 = 合同标的租金 × 付款周期月数(1/3/6/12)(calcReceivableRent)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。\n\n### 月度收入\n\n**数据来源**:月度租金、维保包干、保险上浮费、运维费(收入侧)、其他收入、减免项。\n**计算方式**:月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免 − 其他减免(calcMonthlyIncome)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。\n\n### 月度租金\n\n**数据来源**:合同标的租金。\n**计算方式**:月度租金 = 合同标的租金(calcMonthlyRent)。\n**录入方式**:只读。\n\n**业务说明**:根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。\n\n### 维保包干收入\n\n**数据来源**:合同维保包干配置、账单里程。\n**计算方式**:勾选维保包干时:单价(元/km)× 里程数;未勾选为 0(calcMaintenanceIncome)。\n**录入方式**:包干未勾选时不可编辑。\n\n**业务说明**:合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。\n\n### 保险上浮费\n\n**数据来源**:事故台账关联的保险上浮费。\n**计算方式**:关联事故单后汇总 linkedAccidentIds 对应上浮费;最新账单未关联时显示警示。\n**录入方式**:关联后自动汇总,支持多选事故单。\n\n**业务说明**:事故中有保险上浮费时,最新账单显示警示标志;关联事故单后自动汇总上浮费,支持多选。\n\n### 运维费\n\n**数据来源**:维修/保养台账(客户承担)、账单月内该车牌完工记录。\n**计算方式**:汇总 bearBy=客户承担 的维保金额;可关联 linkedMaintenanceIds(sumMaintenanceForBill)。\n**录入方式**:关联后自动汇总;最新账单可关联记录。\n\n**业务说明**:收入侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「客户承担」的金额;最新一期账单可关联记录。\n\n### 其他收入\n\n**数据来源**:行内其他收入明细(事由、金额、备注)。\n**计算方式**:多条明细金额合计计入应收与月度收入(sumLineItems)。\n**录入方式**:草稿状态可编辑明细。\n\n**业务说明**:支持多条明细录入(事由、金额、备注);合计自动计入应收与月度收入。\n\n### 里程减免金额\n\n**数据来源**:BI 里程(GPS)、里程减免单价。\n**计算方式**:里程减免 = GPS 里程 × 单价;有 GPS 时默认 0.5 元/km,无 GPS 为 0(calcMileageDeduction)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:里程减免金额 = GPS 里程 × 里程减免单价;有 GPS 里程时默认单价 0.5 元/km,无 GPS 时为 0。\n\n### 其他减免金额\n\n**数据来源**:行内其他减免明细。\n**计算方式**:多条明细金额合计,从应收与月度收入扣减(sumLineItems)。\n**录入方式**:草稿状态可编辑明细。\n\n**业务说明**:支持多条明细录入(事由、金额、备注);合计自动从应收与月度收入中扣减。\n\n### 实收金额\n\n**数据来源**:收款记录模块关联分配金额。\n**计算方式**:关联收款单后按分配计入金额汇总,不超过应收合计(calcReceivedAmountFromReceipts)。\n**录入方式**:通过「关联收款」操作维护。\n\n**业务说明**:从「收款记录」功能关联该账单后分配的实收金额;点击可查看收款明细列表。\n\n### 未收金额\n\n**数据来源**:应收合计、实收金额。\n**计算方式**:未收金额 = 应收合计 − 实收金额(calcUnreceived)。\n**录入方式**:系统自动计算,不可手工录入。\n\n**业务说明**:未收金额 = 应收合计 − 实收金额,系统自动计算,不可手工录入。\n\n### 开票日期\n\n**数据来源**:关联收款记录中的开票信息。\n**计算方式**:resolveInvoiceDateFromReceipts 取关联收款单开票日期。\n**录入方式**:只读。\n\n**业务说明**:从「收款记录」功能关联开票记录,显示开票日期。\n\n### 实际付款日期\n\n**数据来源**:关联收款记录的到账日期。\n**计算方式**:有关联收款时取到账记录付款日期;未关联为空。\n**录入方式**:只读。\n\n**业务说明**:关联收款记录时取对应到账记录的付款日期;未关联时为空。\n\n### 付款方式\n\n**数据来源**:合同付款周期月数。\n**计算方式**:1→月度预付,3→季度预付,6→半年预付,12→年度预付(resolvePaymentMethod)。\n**录入方式**:只读。\n\n**业务说明**:由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。\n\n### 车辆标准成本\n\n**数据来源**:车型成本明细 / 车牌标准成本配置(PLATE_STANDARD_COST)。\n**计算方式**:按车型维护的固定月标准成本。\n**录入方式**:只读。\n\n**业务说明**:固定成本,按车型明细维护,只读。\n\n### 车辆实际成本\n\n**数据来源**:车辆标准成本、账单月内租赁天数。\n**计算方式**:车辆实际成本 = 标准成本 × 租赁天数 / 30(calcVehicleActualCost)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:车辆实际成本 = 车辆标准成本 × 账单月内租赁天数 / 30,自动计算。\n\n### 保险费\n\n**数据来源**:保险采购金额、保险有效天数、账单月租赁天数。\n**计算方式**:保险费 =(采购金额 / 有效天数)× 租赁天数,四舍五入两位(calcInsuranceFee)。\n**录入方式**:只读。\n\n**业务说明**:保险费 =(保险采购金额 / 保险有效天数)× 账单月内租赁天数,四舍五入保留两位小数。\n\n### 氢费\n\n**数据来源**:氢费明细台账、合同氢费承担方式。\n**计算方式**:合同为「我司承担」时,汇总账单月内该车牌氢费(sumHydrogenFeeForBill);客户承担不计入。\n**录入方式**:只读。\n\n**业务说明**:仅汇总该账单月内、氢费明细中「我司承担」的氢费(含未对账/已对账);合同为客户承担时不计入。\n\n### 运维费\n\n**数据来源**:维修/保养台账(我司承担)、账单月内该车牌。\n**计算方式**:汇总 bearBy=我司承担 的维保金额(sumMaintenanceForBill)。\n**录入方式**:只读。\n\n**业务说明**:成本侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「我司承担」的金额。\n\n### 居间费\n\n**数据来源**:行内手工录入。\n**计算方式**:直接存储 brokerageFee 字段。\n**录入方式**:草稿可编辑。\n\n**业务说明**:手动输入。\n\n### 其他\n\n**数据来源**:行内手工录入。\n**计算方式**:直接存储 otherCost;前方有其他收入时本项必填。\n**录入方式**:草稿可编辑。\n\n**业务说明**:前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。\n\n### GPS里程\n\n**数据来源**:BI 里程数据(bi-mileage.json / 车机 GPS)。\n**计算方式**:lookupBiMileage(车牌, 年, 月) 取账单期里程。\n**录入方式**:只读。\n\n**业务说明**:从 BI 里程取账单时间段的数据,自动展示。\n\n### 其他减免金额明细内容\n\n**数据来源**:行内手工录入。\n**计算方式**:存储 otherDeductionDetail 文本。\n**录入方式**:草稿可编辑。\n\n**业务说明**:手动输入,备注明细内容。\n\n### 资产归属\n\n**数据来源**:车辆档案资产归属。\n**计算方式**:按车牌从 PLATE_ASSET_OWNER / 车辆档案反写。\n**录入方式**:只读。\n\n**业务说明**:显示车辆实际归属公司名称,按车辆档案自动获取。\n\n### 签约公司\n\n**数据来源**:租赁合同甲方。\n**计算方式**:按车牌匹配签订合同时甲方名称(PLATE_SIGNING_COMPANY)。\n**录入方式**:只读。\n\n**业务说明**:显示租赁合同签订时甲方名称。\n\n### 备注\n\n**数据来源**:行内手工录入。\n**计算方式**:存储 remark 文本。\n**录入方式**:草稿可编辑。\n\n**业务说明**:本列为人工手动填写。\n\n### 账单状态\n\n**数据来源**:账单归档状态字段 archiveStatus。\n**计算方式**:草稿 / 未归档 / 已归档;工具栏「保存」「设置为归档」批量变更。\n**录入方式**:仅草稿可编辑业务字段。\n\n**业务说明**:状态分为已归档、未归档、草稿。仅草稿可编辑;工具栏「保存」将勾选记录设为未归档(不可编辑);「设置为归档」将勾选记录锁定为已归档。\n\n### 维护时间\n\n**数据来源**:台账行维护记录。\n**计算方式**:展示最近一次保存/维护时间(maintainerTime)。\n**录入方式**:系统记录,只读。\n\n**业务说明**:展示最近一次维护时间(YYYY-MM-DD HH:MM);维护人显示最后一次维护用户姓名。", "markdownPath": "src/prototypes/lease-business-ledger/.spec/requirements-prd.md" }, { @@ -1078,7 +1194,7 @@ "type": "markdown", "id": "lbl-doc-lbl-filter", "title": "筛选条件", - "markdown": "## 2. 筛选区\n\n默认展示 4 项(一行),点击「更多筛选」展开全部 8 项。\n\n| 筛选项 | 说明 |\n|---|---|\n| 年份 / 月份 | 账单所属年月 |\n| 业务部门 / 业务员 | 精确匹配 |\n| 车牌号码 | 精确匹配 |\n| 客户名称 | 模糊包含 |\n| 明细状态 | 草稿 / 已确认 / 部分收款 / 已收款 |\n| 付款日期 | 日期区间 |\n\n---" + "markdown": "## 2. 筛选区\n\n默认展示 4 项(一行),点击「更多筛选」展开全部 8 项。\n\n| 筛选项 | 说明 |\n|---|---|\n| 年份 / 月份 | 账单所属年月 |\n| 业务部门 / 业务员 | 精确匹配 |\n| 车牌号码 | 精确匹配 |\n| 客户名称 | 模糊包含 |\n| 明细状态 | 未收款 / 部分收款 / 已收款 |\n| 应付款日 | 单输入框双日历区间,精确至日 |\n\n---" }, { "type": "folder", @@ -1116,19 +1232,19 @@ "type": "markdown", "id": "lbl-doc-lbl-toolbar", "title": "列表工具栏", - "markdown": "## 4. 列表工具栏\n\n左侧「仅显示未收款数据」勾选后,列表仅显示状态不等于已收款的记录。\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板并上传 Excel(原型 Toast) |\n| 导出 | 导出当前筛选结果 |\n| 标记为已确认 | 勾选草稿行后二次确认 |\n| 提交收款审批 | 勾选行提交审批 |\n\n添加行已移至表格底部;列表采用下拉加载更多,不做分页。\n\n---" + "markdown": "## 4. 列表工具栏\n\n左侧「仅显示未收款数据」勾选后,列表仅显示状态不等于已收款的记录。\n\n| 按钮 | 行为 |\n|---|---|\n| 批量导入 | 下载模板并上传 Excel(原型 Toast) |\n| 导出 | 导出当前筛选结果 |\n| 保存 | 勾选记录后设为未归档,保存后不可编辑 |\n| 设置为归档 | 勾选记录后锁定为已归档 |\n\n表格底部提供分页,可切换页码与每页条数。\n\n---" }, { "type": "markdown", - "id": "lbl-doc-lbl-btn-mark-confirmed", - "title": "标记为已确认", - "markdown": "## 标记为已确认\n\n勾选草稿记录后点击,弹出二次确认:「确认后的数据只有主管才能继续进行修改,是否确认数据准确无误?」确认后状态变更为已确认,业务服务组人员不可再删改。\n\n---" + "id": "lbl-doc-lbl-btn-save-unarchived", + "title": "保存", + "markdown": "## 保存\n\n勾选台账记录后点击,将账单状态设为**未归档**。未归档数据不可编辑,仅草稿可编辑。\n\n---" }, { "type": "markdown", - "id": "lbl-doc-lbl-btn-add-row", - "title": "添加行", - "markdown": "## 添加行\n\n位于表格底部;列表不做分页,采用下拉加载更多,避免多选受分页限制。\n\n---" + "id": "lbl-doc-lbl-btn-set-archived", + "title": "设置为归档", + "markdown": "## 设置为归档\n\n勾选台账记录后点击,将账单状态设为**已归档**并锁定编辑。\n\n---" } ] }, @@ -1147,188 +1263,254 @@ { "type": "markdown", "id": "lbl-doc-lbl-col-status", - "title": "状态流转", - "markdown": "## 状态流转\n\n1. 新增/导入 → **草稿**(业务服务组可删改)\n2. 多选 + 「标记为已确认」→ **已确认**(仅主管可改)\n3. 已确认行可「关联收款记录」;到账合计 < 应收 → **部分收款**;≥ 应收 → **已收款**\n\n---" + "title": "状态", + "markdown": "## 状态\n\n**数据来源**:收款记录模块中关联到本账单的分配金额、账单应收合计。\n**计算方式**:分配金额 ≥ 应收合计且应收 > 0 → 已收款;0 < 分配金额 < 应收 → 部分收款;未关联收款 → 未收款。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:当收款记录中分配金额完全覆盖账单的应收金额时,显示已收款。当收款记录中分配金额≤账单的应收金额时,显示部分收款。未分配收款记录时,显示为未收款。其他状态去除\n\n---" }, { "type": "markdown", - "id": "lbl-doc-lbl-col-dept", - "title": "业务部门", - "markdown": "## 业务部门列\n\n业务部门与业务员合并为一列:上方业务部门,下方业务员。\n\n---" + "id": "lbl-doc-lbl-col-payment-due", + "title": "应付款日", + "markdown": "## 应付款日\n\n**数据来源**:账单起始日期(优先)或提车日期作为开始计费日;账单所属年月。\n**计算方式**:首期账单应付款日 = 开始计费日;后续每期 = 账单所属自然月 5 日。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:交车后按「开始计费日期」生成首期账单应付款日;后续每期账单在所属自然月 5 日生成下一期应付款日。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-plate", "title": "车牌号码", - "markdown": "## 车牌号码列\n\n车牌与车型合并为一列:上方车牌号码,下方品牌与型号;导入/新增时按车牌在系统中自动匹配。\n\n---" + "markdown": "## 车牌号码\n\n**数据来源**:车辆档案(按车牌匹配品牌、型号)。\n**计算方式**:导入/新增台账时按车牌号反写车辆信息。\n**录入方式**:只读展示(车牌 + 车型两行)。\n\n**业务说明**:车牌与车型合并为一列:上方车牌号码,下方品牌与型号;导入/新增时按车牌在系统中自动匹配。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-customer", "title": "客户名称", - "markdown": "## 客户名称列\n\n客户名称与项目名称合并为一列:上方客户名称,下方项目名称;按账单日期与车牌号自动匹配。\n\n---" + "markdown": "## 客户名称\n\n**数据来源**:租赁合同(按账单日期 + 车牌匹配客户、项目)。\n**计算方式**:匹配当前车辆在账期内的有效合同,带出客户名称与项目名称。\n**录入方式**:只读展示(客户 + 项目两行)。\n\n**业务说明**:客户名称与项目名称合并为一列:上方客户名称,下方项目名称;按账单日期与车牌号自动匹配。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-value-added-service", + "title": "增值服务", + "markdown": "## 增值服务\n\n**数据来源**:租赁合同签订时勾选的增值服务项目。\n**计算方式**:按车牌匹配合同增值服务配置,多项服务分行展示。\n**录入方式**:只读。\n\n**业务说明**:签订合同时勾选的增值服务项目,按车牌自动匹配合同数据;多项服务各占一行展示。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-pickup-date", "title": "提车日期", - "markdown": "## 提车日期\n\n等于交车管理中该车辆运维 E 签宝签字完成的时间。\n\n---" + "markdown": "## 提车日期\n\n**数据来源**:交车管理 / 运维 E 签宝签字完成时间。\n**计算方式**:取该车辆实际交车办结时间。\n**录入方式**:只读。\n\n**业务说明**:运维实际交车日期。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-contract-start-date", + "title": "合同生效日期", + "markdown": "## 合同生效日期\n\n**数据来源**:提车日期(交车办结时间)。\n**计算方式**:合同生效日期 = 提车日期(YYYY-MM-DD),系统自动反写。\n**录入方式**:系统自动反写,只读。\n\n**业务说明**:等于提车日期,即租赁合同生效日期,系统自动反写,只读。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-contract-end-date", + "title": "合同到期日期", + "markdown": "## 合同到期日期\n\n**数据来源**:合同租期月数 + 提车日期,或合同约定的到期日。\n**计算方式**:日期模式:取合同存储的 contractEndDate;租期模式:提车日 + leaseTermMonths 个月。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:合同到期日:租期模式按提车日期 + 租期月数计算;日期模式取合同中约定的到期日。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-period-start-date", + "title": "起始日期", + "markdown": "## 起始日期\n\n**数据来源**:账单年月、提车日期。\n**计算方式**:月前已提车 → 当月 1 日;月内提车 → 提车日;月后提车 → 空(calcPeriodStartDate)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:账单所属月内的租赁起始日:月前已提车取当月 1 日,月内提车取提车日;系统自动计算,只读。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-return-date", + "title": "退车日期", + "markdown": "## 退车日期\n\n**数据来源**:退车管理登记的退车日期。\n**计算方式**:取该车牌退车办结日期;未退车为空。\n**录入方式**:只读。\n\n**业务说明**:退车管理中登记的退车日期;未退车时为空。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-avg-days", + "title": "平均天数", + "markdown": "## 平均天数\n\n**数据来源**:账单月内租赁天数、当月自然日天数。\n**计算方式**:平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数(calcAvgDays)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数;用于成本分摊口径。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-deposit", "title": "保证金", - "markdown": "## 保证金\n\n与创建合同时的保证金、提车应收款中的保证金等同;提车应收款有保证金时显示。\n\n---" + "markdown": "## 保证金\n\n**数据来源**:提车应收款 / 合同保证金。\n**计算方式**:与创建合同时保证金、提车应收款中该车辆保证金一致。\n**录入方式**:只读。\n\n**业务说明**:显示该车辆实付保证金金额,与提车应收款时该车辆收取的提车应收款相同。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-contract-rent", "title": "合同标的租金", - "markdown": "## 合同标的租金\n\n等于该车辆在签订该合同时合同中的租金(月租金标准)。\n\n---" + "markdown": "## 合同标的租金\n\n**数据来源**:租赁合同月租金标准。\n**计算方式**:签订合同时该车辆的月租金(合同标的租金)。\n**录入方式**:合同带入,只读。\n\n**业务说明**:等于该车辆在签订该合同时合同中的租金(月租金标准)。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-receivable-total", + "title": "应收合计", + "markdown": "## 应收合计\n\n**数据来源**:应收租金、保险上浮费、运维费(收入侧)、其他收入、里程/其他减免。\n**计算方式**:应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免 − 其他减免(calcReceivableTotal)。\n**录入方式**:系统自动汇总,只读。\n\n**业务说明**:应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-receivable-rent", "title": "应收租金", - "markdown": "## 应收租金\n\n按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。\n\n---" + "markdown": "## 应收租金\n\n**数据来源**:合同标的租金、合同付款周期月数。\n**计算方式**:应收租金 = 合同标的租金 × 付款周期月数(1/3/6/12)(calcReceivableRent)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-monthly-income", "title": "月度收入", - "markdown": "## 月度收入\n\n租金 + 服务费 − 里程减免金额 − 其他减免金额(后两项为减项)。\n\n---" + "markdown": "## 月度收入\n\n**数据来源**:月度租金、维保包干、保险上浮费、运维费(收入侧)、其他收入、减免项。\n**计算方式**:月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免 − 其他减免(calcMonthlyIncome)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-monthly-rent", "title": "月度租金", - "markdown": "## 月度租金\n\n根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。\n\n---" + "markdown": "## 月度租金\n\n**数据来源**:合同标的租金。\n**计算方式**:月度租金 = 合同标的租金(calcMonthlyRent)。\n**录入方式**:只读。\n\n**业务说明**:根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-maintenance-income", "title": "维保包干收入", - "markdown": "## 维保包干收入\n\n合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。\n\n---" + "markdown": "## 维保包干收入\n\n**数据来源**:合同维保包干配置、账单里程。\n**计算方式**:勾选维保包干时:单价(元/km)× 里程数;未勾选为 0(calcMaintenanceIncome)。\n**录入方式**:包干未勾选时不可编辑。\n\n**业务说明**:合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-insurance-surcharge", "title": "保险上浮费", - "markdown": "## 保险上浮费\n\n事故中有保险上浮费时,最新账单显示警示标志;关联事故单后自动汇总上浮费,支持多选。\n\n---" + "markdown": "## 保险上浮费\n\n**数据来源**:事故台账关联的保险上浮费。\n**计算方式**:关联事故单后汇总 linkedAccidentIds 对应上浮费;最新账单未关联时显示警示。\n**录入方式**:关联后自动汇总,支持多选事故单。\n\n**业务说明**:事故中有保险上浮费时,最新账单显示警示标志;关联事故单后自动汇总上浮费,支持多选。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-ops-income", - "title": "运维费(收入侧)", - "markdown": "## 运维费(收入侧)\n\n维修/保养台账为「客户承担」时,最新一期账单显示警示图标,提醒关联维修/保养记录;关联后自动汇总运维费,支持多选。\n\n---" + "title": "运维费", + "markdown": "## 运维费\n\n**数据来源**:维修/保养台账(客户承担)、账单月内该车牌完工记录。\n**计算方式**:汇总 bearBy=客户承担 的维保金额;可关联 linkedMaintenanceIds(sumMaintenanceForBill)。\n**录入方式**:关联后自动汇总;最新账单可关联记录。\n\n**业务说明**:收入侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「客户承担」的金额;最新一期账单可关联记录。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-other-income", "title": "其他收入", - "markdown": "## 其他收入\n\n手工填写,预留作为特殊情况记录使用。\n\n---" + "markdown": "## 其他收入\n\n**数据来源**:行内其他收入明细(事由、金额、备注)。\n**计算方式**:多条明细金额合计计入应收与月度收入(sumLineItems)。\n**录入方式**:草稿状态可编辑明细。\n\n**业务说明**:支持多条明细录入(事由、金额、备注);合计自动计入应收与月度收入。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-mileage-deduction", + "title": "里程减免金额", + "markdown": "## 里程减免金额\n\n**数据来源**:BI 里程(GPS)、里程减免单价。\n**计算方式**:里程减免 = GPS 里程 × 单价;有 GPS 时默认 0.5 元/km,无 GPS 为 0(calcMileageDeduction)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:里程减免金额 = GPS 里程 × 里程减免单价;有 GPS 里程时默认单价 0.5 元/km,无 GPS 时为 0。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-other-deduction", + "title": "其他减免金额", + "markdown": "## 其他减免金额\n\n**数据来源**:行内其他减免明细。\n**计算方式**:多条明细金额合计,从应收与月度收入扣减(sumLineItems)。\n**录入方式**:草稿状态可编辑明细。\n\n**业务说明**:支持多条明细录入(事由、金额、备注);合计自动从应收与月度收入中扣减。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-received-amount", "title": "实收金额", - "markdown": "## 实收金额\n\n根据财务导入收款明细归集;支持关联多条并分配计入金额;超出应收部分在单据下自行分配。\n\n---" + "markdown": "## 实收金额\n\n**数据来源**:收款记录模块关联分配金额。\n**计算方式**:关联收款单后按分配计入金额汇总,不超过应收合计(calcReceivedAmountFromReceipts)。\n**录入方式**:通过「关联收款」操作维护。\n\n**业务说明**:从「收款记录」功能关联该账单后分配的实收金额;点击可查看收款明细列表。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-unreceived", "title": "未收金额", - "markdown": "## 未收金额\n\n未收金额 = 应收合计 − 实收金额,系统自动计算,不可手工录入。\n\n---" + "markdown": "## 未收金额\n\n**数据来源**:应收合计、实收金额。\n**计算方式**:未收金额 = 应收合计 − 实收金额(calcUnreceived)。\n**录入方式**:系统自动计算,不可手工录入。\n\n**业务说明**:未收金额 = 应收合计 − 实收金额,系统自动计算,不可手工录入。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-invoice-date", "title": "开票日期", - "markdown": "## 开票日期\n\n账单开票后由财务维护,自动反写,只读。\n\n---" + "markdown": "## 开票日期\n\n**数据来源**:关联收款记录中的开票信息。\n**计算方式**:resolveInvoiceDateFromReceipts 取关联收款单开票日期。\n**录入方式**:只读。\n\n**业务说明**:从「收款记录」功能关联开票记录,显示开票日期。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-actual-payment", "title": "实际付款日期", - "markdown": "## 实际付款日期\n\n关联收款记录时取对应到账记录的付款日期;未关联时为空。\n\n---" + "markdown": "## 实际付款日期\n\n**数据来源**:关联收款记录的到账日期。\n**计算方式**:有关联收款时取到账记录付款日期;未关联为空。\n**录入方式**:只读。\n\n**业务说明**:关联收款记录时取对应到账记录的付款日期;未关联时为空。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-payment-method", "title": "付款方式", - "markdown": "## 付款方式\n\n由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。\n\n---" + "markdown": "## 付款方式\n\n**数据来源**:合同付款周期月数。\n**计算方式**:1→月度预付,3→季度预付,6→半年预付,12→年度预付(resolvePaymentMethod)。\n**录入方式**:只读。\n\n**业务说明**:由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-vehicle-standard-cost", "title": "车辆标准成本", - "markdown": "## 车辆标准成本\n\n固定成本,按车型明细维护,只读。\n\n---" + "markdown": "## 车辆标准成本\n\n**数据来源**:车型成本明细 / 车牌标准成本配置(PLATE_STANDARD_COST)。\n**计算方式**:按车型维护的固定月标准成本。\n**录入方式**:只读。\n\n**业务说明**:固定成本,按车型明细维护,只读。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-vehicle-actual-cost", "title": "车辆实际成本", - "markdown": "## 车辆实际成本\n\n车辆标准成本 ×(实际天数 / 30),自动计算。\n\n---" + "markdown": "## 车辆实际成本\n\n**数据来源**:车辆标准成本、账单月内租赁天数。\n**计算方式**:车辆实际成本 = 标准成本 × 租赁天数 / 30(calcVehicleActualCost)。\n**录入方式**:系统自动计算,只读。\n\n**业务说明**:车辆实际成本 = 车辆标准成本 × 账单月内租赁天数 / 30,自动计算。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-insurance-fee", "title": "保险费", - "markdown": "## 保险费\n\n暂保留,不可编辑和导入;后续可能自动计算。\n\n---" + "markdown": "## 保险费\n\n**数据来源**:保险采购金额、保险有效天数、账单月租赁天数。\n**计算方式**:保险费 =(采购金额 / 有效天数)× 租赁天数,四舍五入两位(calcInsuranceFee)。\n**录入方式**:只读。\n\n**业务说明**:保险费 =(保险采购金额 / 保险有效天数)× 账单月内租赁天数,四舍五入保留两位小数。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-hydrogen-fee", "title": "氢费", - "markdown": "## 氢费\n\n表头提示:仅显示合同氢费承担方式为「我司承担」时,该账单期内氢费总和(含未对账/已对账)。\n\n---" + "markdown": "## 氢费\n\n**数据来源**:氢费明细台账、合同氢费承担方式。\n**计算方式**:合同为「我司承担」时,汇总账单月内该车牌氢费(sumHydrogenFeeForBill);客户承担不计入。\n**录入方式**:只读。\n\n**业务说明**:仅汇总该账单月内、氢费明细中「我司承担」的氢费(含未对账/已对账);合同为客户承担时不计入。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-ops-cost", - "title": "运维费(成本侧)", - "markdown": "## 运维费(成本侧)\n\n与收入侧运维费平进平出,自动同步。\n\n---" + "title": "运维费", + "markdown": "## 运维费\n\n**数据来源**:维修/保养台账(我司承担)、账单月内该车牌。\n**计算方式**:汇总 bearBy=我司承担 的维保金额(sumMaintenanceForBill)。\n**录入方式**:只读。\n\n**业务说明**:成本侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「我司承担」的金额。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-brokerage-fee", "title": "居间费", - "markdown": "## 居间费\n\n手动输入。\n\n---" + "markdown": "## 居间费\n\n**数据来源**:行内手工录入。\n**计算方式**:直接存储 brokerageFee 字段。\n**录入方式**:草稿可编辑。\n\n**业务说明**:手动输入。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-other-cost", - "title": "其他(成本侧)", - "markdown": "## 其他(成本侧)\n\n前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。\n\n---" + "title": "其他", + "markdown": "## 其他\n\n**数据来源**:行内手工录入。\n**计算方式**:直接存储 otherCost;前方有其他收入时本项必填。\n**录入方式**:草稿可编辑。\n\n**业务说明**:前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-gps-mileage", "title": "GPS里程", - "markdown": "## GPS里程\n\n从 BI 里程取账单时间段的数据,自动展示。\n\n---" + "markdown": "## GPS里程\n\n**数据来源**:BI 里程数据(bi-mileage.json / 车机 GPS)。\n**计算方式**:lookupBiMileage(车牌, 年, 月) 取账单期里程。\n**录入方式**:只读。\n\n**业务说明**:从 BI 里程取账单时间段的数据,自动展示。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-deduction-detail", "title": "其他减免金额明细内容", - "markdown": "## 其他减免金额明细内容\n\n手动输入,备注明细内容。\n\n---" + "markdown": "## 其他减免金额明细内容\n\n**数据来源**:行内手工录入。\n**计算方式**:存储 otherDeductionDetail 文本。\n**录入方式**:草稿可编辑。\n\n**业务说明**:手动输入,备注明细内容。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-asset-ownership", "title": "资产归属", - "markdown": "## 资产归属\n\n显示车辆实际归属公司名称,按车辆档案自动获取。\n\n---" + "markdown": "## 资产归属\n\n**数据来源**:车辆档案资产归属。\n**计算方式**:按车牌从 PLATE_ASSET_OWNER / 车辆档案反写。\n**录入方式**:只读。\n\n**业务说明**:显示车辆实际归属公司名称,按车辆档案自动获取。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-signing-company", "title": "签约公司", - "markdown": "## 签约公司\n\n租赁合同甲方,签订合同时自动获取;用于租赁总账利润归集。\n\n---" + "markdown": "## 签约公司\n\n**数据来源**:租赁合同甲方。\n**计算方式**:按车牌匹配签订合同时甲方名称(PLATE_SIGNING_COMPANY)。\n**录入方式**:只读。\n\n**业务说明**:显示租赁合同签订时甲方名称。\n\n---" }, { "type": "markdown", "id": "lbl-doc-lbl-col-remark", "title": "备注", - "markdown": "## 备注\n\n手动输入。\n\n---" + "markdown": "## 备注\n\n**数据来源**:行内手工录入。\n**计算方式**:存储 remark 文本。\n**录入方式**:草稿可编辑。\n\n**业务说明**:本列为人工手动填写。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-archive-status", + "title": "账单状态", + "markdown": "## 账单状态\n\n**数据来源**:账单归档状态字段 archiveStatus。\n**计算方式**:草稿 / 未归档 / 已归档;工具栏「保存」「设置为归档」批量变更。\n**录入方式**:仅草稿可编辑业务字段。\n\n**业务说明**:状态分为已归档、未归档、草稿。仅草稿可编辑;工具栏「保存」将勾选记录设为未归档(不可编辑);「设置为归档」将勾选记录锁定为已归档。\n\n---" + }, + { + "type": "markdown", + "id": "lbl-doc-lbl-col-maintainer-time", + "title": "维护时间", + "markdown": "## 维护时间\n\n**数据来源**:台账行维护记录。\n**计算方式**:展示最近一次保存/维护时间(maintainerTime)。\n**录入方式**:系统记录,只读。\n\n**业务说明**:展示最近一次维护时间(YYYY-MM-DD HH:MM);维护人显示最后一次维护用户姓名。\n\n---" } ] } diff --git a/src/prototypes/lease-business-ledger/columnHeaderTips.ts b/src/prototypes/lease-business-ledger/columnHeaderTips.ts new file mode 100644 index 0000000..ad38f37 --- /dev/null +++ b/src/prototypes/lease-business-ledger/columnHeaderTips.ts @@ -0,0 +1,66 @@ +/** 表头悬浮说明 — 与 annotation-source 中 lbl-col-* 标注对齐 */ +export const COLUMN_HEADER_TIPS: Record = { + 'lbl-col-status': + '当收款记录中分配金额完全覆盖账单的应收金额时,显示已收款。当收款记录中分配金额≤账单的应收金额时,显示部分收款。未分配收款记录时,显示为未收款。其他状态去除', + 'lbl-col-archive-status': + '状态分为已归档、未归档、草稿。仅草稿可编辑;工具栏「保存」将勾选记录设为未归档(不可编辑);「设置为归档」将勾选记录锁定为已归档。', + 'lbl-col-payment-due': + '交车后按「开始计费日期」生成首期账单应付款日;后续每期账单在所属自然月 5 日生成下一期应付款日。', + 'lbl-col-plate': '车牌与车型合并为一列:上方车牌号码,下方品牌与型号;导入/新增时按车牌在系统中自动匹配。', + 'lbl-col-customer': '客户名称与项目名称合并为一列:上方客户名称,下方项目名称;按账单日期与车牌号自动匹配。', + 'lbl-col-value-added-service': + '签订合同时勾选的增值服务项目,按车牌自动匹配合同数据;多项服务各占一行展示。', + 'lbl-col-pickup-date': '运维实际交车日期。', + 'lbl-col-contract-start-date': '等于提车日期,即租赁合同生效日期,系统自动反写,只读。', + 'lbl-col-contract-end-date': + '合同到期日:租期模式按提车日期 + 租期月数计算;日期模式取合同中约定的到期日。', + 'lbl-col-period-start-date': + '账单所属月内的租赁起始日:月前已提车取当月 1 日,月内提车取提车日;系统自动计算,只读。', + 'lbl-col-return-date': '退车管理中登记的退车日期;未退车时为空。', + 'lbl-col-avg-days': + '平均天数 = 账单月内租赁天数 ÷ 当月自然日天数,保留两位小数;用于成本分摊口径。', + 'lbl-col-deposit': '显示该车辆实付保证金金额,与提车应收款时该车辆收取的提车应收款相同。', + 'lbl-col-contract-rent': '等于该车辆在签订该合同时合同中的租金(月租金标准)。', + 'lbl-col-receivable-total': + '应收合计 = 应收租金 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。', + 'lbl-col-receivable-rent': '按合同付款周期(1/3/6/12 个月)计算的单期账单租金总金额 = 合同标的租金 × 付款周期月数。', + 'lbl-col-monthly-income': + '月度收入 = 月度租金 + 维保包干收入 + 保险上浮费 + 运维费(收入侧)+ 其他收入 − 里程减免金额 − 其他减免金额。', + 'lbl-col-monthly-rent': '根据客户付款周期间隔,计算每个月需收取的租金,等于合同标的租金。', + 'lbl-col-maintenance-income': '合同勾选维保包干时:单价(元/km)× 里程数,必填;未勾选时默认 0 且不可编辑。', + 'lbl-col-insurance-surcharge': '事故中有保险上浮费时,最新账单显示警示标志;关联事故单后自动汇总上浮费,支持多选。', + 'lbl-col-ops-income': + '收入侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「客户承担」的金额;最新一期账单可关联记录。', + 'lbl-col-other-income': '支持多条明细录入(事由、金额、备注);合计自动计入应收与月度收入。', + 'lbl-col-mileage-deduction': + '里程减免金额 = GPS 里程 × 里程减免单价;有 GPS 里程时默认单价 0.5 元/km,无 GPS 时为 0。', + 'lbl-col-other-deduction': '支持多条明细录入(事由、金额、备注);合计自动从应收与月度收入中扣减。', + 'lbl-col-received-amount': '从「收款记录」功能关联该账单后分配的实收金额;点击可查看收款明细列表。', + 'lbl-col-unreceived': '未收金额 = 应收合计 − 实收金额,系统自动计算,不可手工录入。', + 'lbl-col-invoice-date': '从「收款记录」功能关联开票记录,显示开票日期。', + 'lbl-col-actual-payment': '关联收款记录时取对应到账记录的付款日期;未关联时为空。', + 'lbl-col-payment-method': '由合同付款周期决定:1 个月→月度预付,3 个月→季度预付,6 个月→半年预付,12 个月→年度预付。', + 'lbl-col-vehicle-standard-cost': '固定成本,按车型明细维护,只读。', + 'lbl-col-vehicle-actual-cost': + '车辆实际成本 = 车辆标准成本 × 账单月内租赁天数 / 30,自动计算。', + 'lbl-col-insurance-fee': + '保险费 =(保险采购金额 / 保险有效天数)× 账单月内租赁天数,四舍五入保留两位小数。', + 'lbl-col-hydrogen-fee': + '仅汇总该账单月内、氢费明细中「我司承担」的氢费(含未对账/已对账);合同为客户承担时不计入。', + 'lbl-col-ops-cost': + '成本侧运维费:自动汇总该账单月内、该车牌维修/保养台账中「我司承担」的金额。', + 'lbl-col-brokerage-fee': '手动输入。', + 'lbl-col-other-cost': '前方其他收入有填写时,此处为必填项;与收入侧其他费用区分。', + 'lbl-col-gps-mileage': '从 BI 里程取账单时间段的数据,自动展示。', + 'lbl-col-deduction-detail': '手动输入,备注明细内容。', + 'lbl-col-asset-ownership': '显示车辆实际归属公司名称,按车辆档案自动获取。', + 'lbl-col-signing-company': '显示租赁合同签订时甲方名称。', + 'lbl-col-remark': '本列为人工手动填写。', + 'lbl-col-maintainer-time': '展示最近一次维护时间(YYYY-MM-DD HH:MM);维护人显示最后一次维护用户姓名。', +}; + +export function resolveColumnHeaderTip(annotationId?: string, headerTip?: string): string | undefined { + if (headerTip) return headerTip; + if (annotationId && COLUMN_HEADER_TIPS[annotationId]) return COLUMN_HEADER_TIPS[annotationId]; + return undefined; +} diff --git a/src/prototypes/lease-business-ledger/components/DeleteConfirmModal.tsx b/src/prototypes/lease-business-ledger/components/DeleteConfirmModal.tsx index 89c2fd3..3bbd969 100644 --- a/src/prototypes/lease-business-ledger/components/DeleteConfirmModal.tsx +++ b/src/prototypes/lease-business-ledger/components/DeleteConfirmModal.tsx @@ -3,12 +3,13 @@ import { X } from 'lucide-react'; interface DeleteConfirmModalProps { open: boolean; - plateNo: string; + plateNo?: string; + meta?: string; onCancel: () => void; onConfirm: () => void; } -export function DeleteConfirmModal({ open, plateNo, onCancel, onConfirm }: DeleteConfirmModalProps) { +export function DeleteConfirmModal({ open, plateNo = '', meta, onCancel, onConfirm }: DeleteConfirmModalProps) { if (!open) return null; return ( @@ -30,7 +31,7 @@ export function DeleteConfirmModal({ open, plateNo, onCancel, onConfirm }: Delet

删除后该条台账记录将无法恢复,是否确认删除?

-

{plateNo ? `车牌:${plateNo}` : ''}

+

{meta ?? (plateNo ? `车牌:${plateNo}` : '')}