Compare commits
253 Commits
a19097d1be
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| e7ba220b34 | |||
| e79e50bf40 | |||
| a6b4a7b2d1 | |||
| 2be6a559e7 | |||
| 523a042fa9 | |||
| 07af103ecb | |||
| 6e48fa50cf | |||
| 8734c27fd3 | |||
| 7ff2b3fe28 | |||
| 17d2766f82 | |||
| 2fd927a90c | |||
| 8057e860de | |||
| ffc2942d2b | |||
| 22bbcbb7aa | |||
| 4dd63fc5fa | |||
| c525bffeca | |||
| 8f3da0e386 | |||
| d4ae6d521a | |||
| b36fa18db5 | |||
| f648285406 | |||
| fff0a29947 | |||
| 64b61c9c29 | |||
| 32065b9c54 | |||
| 5d56706eed | |||
| 9efae11811 | |||
| 9a04757a9e | |||
| e88a27d01f | |||
| b9c367e028 | |||
| 7f694bad55 | |||
| 014ee537a0 | |||
| 5bde60d844 | |||
| 799a87641e | |||
| 28baa69e8f | |||
| 4ed80268b4 | |||
| 30c59c2acb | |||
| 68904b02a5 | |||
| c0ba9ba39b | |||
| 8388a55481 | |||
| b492dd35ea | |||
| acb74cbc9a | |||
| 9a51bd2cfd | |||
| 4dd54f7e4c | |||
| 6705763951 | |||
| 4ba18acd25 | |||
| c07371450f | |||
| 5fbbb5f88f | |||
| 1ed7955764 | |||
| daab1001db | |||
| f5735e6bad | |||
| bd9da83175 | |||
| b59e43c9b7 | |||
| eae50ab909 | |||
| 39560bde79 | |||
| 8e1430491b | |||
| 9fed3785d9 | |||
| eaf431819e | |||
| c7bd4461e2 | |||
| ab7491e6d6 | |||
| d78d100824 | |||
| 9908b543ea | |||
| 46e7952e49 | |||
| 441d62a874 | |||
| 1a143aa05b | |||
| f3d69d7df0 | |||
| cd58e8ebc7 | |||
| 11d33df46a | |||
| 06de9477e5 | |||
| f7ee9273c6 | |||
| e0a420ad08 | |||
| 8388904916 | |||
| 24fec3c7d7 | |||
| b76ada9d6c | |||
| 2083754b16 | |||
| 3df09d7d45 | |||
| b878bc356e | |||
| d76977c07c | |||
| d95163663b | |||
| e95151ad51 | |||
| 5351911d50 | |||
| e602eecee8 | |||
| 70801096dd | |||
| 025cba317d | |||
| 5ce91ec5d5 | |||
| 26140aecb9 | |||
| 8d85311bb3 | |||
| 8b2fa09cb9 | |||
| 4d78466824 | |||
| fe4255c59b | |||
| c6c7c80d97 | |||
| 3397bd6a7b | |||
| 083d954765 | |||
| 78bb38e955 | |||
| 4b060fc045 | |||
| 2cf966d6e3 | |||
| d23a9b00de | |||
| d89fd9db97 | |||
| 94ee14b683 | |||
| a725d3078f | |||
| 185a0f9aec | |||
| a528788409 | |||
| 1957a78c00 | |||
| acfe9bdd74 | |||
| 72471f48de | |||
| 415e1fd58d | |||
| 698f808f0b | |||
| ea6ec13ea4 | |||
| 114c2fd2af | |||
| 6119c44394 | |||
| 9dab7f7495 | |||
| f5697e111a | |||
| 775307f5c0 | |||
| 4502881063 | |||
| 358add743e | |||
| f67a4036ed | |||
| 7ba6620f06 | |||
| 9a3652d767 | |||
| 450505715a | |||
| 9a603a3796 | |||
| 2b51619728 | |||
| 5f167aae50 | |||
| 0d8eb25253 | |||
| 74988c0b5e | |||
| e53852b05f | |||
| 8d3e87d710 | |||
| c7b07f0c95 | |||
| 4c117d87a5 | |||
| 59199397e0 | |||
| 70d49d022b | |||
| 7d16660bfc | |||
| d6bcb12c20 | |||
| e1d87f5788 | |||
| 56b8f68449 | |||
| 0ac17dea0b | |||
| 39e3115fbe | |||
| 9c0f7cb3f4 | |||
| 7b478bdbf2 | |||
| 87d6ff97a3 | |||
| e3bd44e8fc | |||
| 324daf9d4d | |||
| 37ac683fb4 | |||
| c402d68aea | |||
| e8f6311477 | |||
| fa78a68df6 | |||
| 320422856c | |||
| 0add4c5cdc | |||
| f6621392b1 | |||
| 2a5eca8393 | |||
| e4ae1d3c77 | |||
| 96783fcd7b | |||
| 372e8826a2 | |||
| 8d9fe998c0 | |||
| 92a8d4aab1 | |||
| 59a1ca8a0d | |||
| b9de34aa0e | |||
| 5544cfb3ca | |||
| fcd5ef7df9 | |||
| 489b406214 | |||
| 353148eb7f | |||
| 293b4fc6ce | |||
| 53b588063e | |||
| 0889f29c59 | |||
| f1c004813e | |||
| d67cf55491 | |||
| d7969c191a | |||
| 2f64abfc83 | |||
| a657b9d0ef | |||
| 9558426da1 | |||
| 6384e80758 | |||
| 3f019c9ac5 | |||
| e7c76c803f | |||
| eb32a275f3 | |||
| 9150213b0f | |||
| 90edc4b864 | |||
| 6a21b4ac8d | |||
| d05f8fd636 | |||
| d968c418a8 | |||
| d100e7a271 | |||
| 1c798046fd | |||
| 8d25e186b1 | |||
| c1863d0b6a | |||
| 4a0af452e8 | |||
| 447b2d9d76 | |||
| 603038d5ff | |||
| 673c47771b | |||
| 3168d365d0 | |||
| 5c97d3b5c5 | |||
| 09ce6472b0 | |||
| 5b435bef04 | |||
| d3af455374 | |||
| 0c4bb7cd82 | |||
| 4c9bbf1eb7 | |||
| 4e8163dd18 | |||
| 31794bf26a | |||
| 89bbc43f12 | |||
| 4199318aa9 | |||
| 555189177c | |||
| 1622015724 | |||
| 0e57de5c71 | |||
| 5cb7eb16d5 | |||
| ccaf944782 | |||
| aee661772b | |||
| bbe71e340a | |||
| 1ac741f785 | |||
| f7d8fbf16b | |||
| 912c1169a6 | |||
| 847f09b14d | |||
| 6596722601 | |||
| 2ae817ec38 | |||
| 6f2383a7e5 | |||
| 8db52ef168 | |||
| 38ca250242 | |||
| 73c12cc1c7 | |||
| f4542cd0b8 | |||
| 4b165471e3 | |||
| d1e779bbcc | |||
| 6d80ffde6c | |||
| acfbb4c54e | |||
| 44809ad303 | |||
| f440343830 | |||
| c1bc55e133 | |||
| baec42f876 | |||
| 4d3b6cdaed | |||
| 96b675b3be | |||
| 6067d24e3b | |||
| e051327f2d | |||
| f7759fd9e7 | |||
| 91cb3ee8c2 | |||
| b2a6d73bac | |||
| 4287133f84 | |||
| 4b01316f64 | |||
| 0b170fe5c1 | |||
| 4f29b1e0eb | |||
| 6db599400e | |||
| c5a74acd00 | |||
| f23d65e41e | |||
| fb91768585 | |||
| 6b0cb37699 | |||
| c867c5d7a5 | |||
| 411fdd2425 | |||
| 903e0a4d7b | |||
| 6461c3d80f | |||
| 8380351529 | |||
| f8a238d0c0 | |||
| 5c6fcbe951 | |||
| 7997089b16 | |||
| 089b74479b | |||
| cf542313f7 | |||
| fbad28b717 | |||
| 7ea96bcdc0 | |||
| b7af496a43 | |||
| 9e5f53702f | |||
| 8640238cbe | |||
| ef1a43f947 |
@@ -2,6 +2,7 @@
|
|||||||
node_modules
|
node_modules
|
||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
/dist
|
/dist
|
||||||
|
/dist.zip
|
||||||
|
|
||||||
/tests/e2e/videos/
|
/tests/e2e/videos/
|
||||||
/tests/e2e/screenshots/
|
/tests/e2e/screenshots/
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# 2026-10-20
|
||||||
|
|
||||||
|
## settlement-import 列表页工具栏对齐 receipt-settlement
|
||||||
|
|
||||||
|
- `src/views/settlement/settlement-import.vue`:
|
||||||
|
- 左侧只保留「新增」(`type="primary"`),删掉原来的 `plain` 文字「刷新」按钮(刷新统一收进右侧图标组,与 receipt-settlement / settlement-adjustment 一致)。
|
||||||
|
- 右侧接入 `<settlement-table-tools>`(`./components/settlement-table-tools.vue`,即 `table-header-tools` 包装):刷新 / 列设置 / 搜索显隐 / 表格尺寸 4 键,`@refresh="refreshTable"`。
|
||||||
|
- 表格列改为配置化,新增 `src/option/settlement/settlementImportTable.js`(`settlementImportTableColumns`),页面加 `tableColumns / visibleColumnKeys / tableSize / columnSettingOptions / visibleTableColumns`,`el-table` 加 `:size="tableSize"`。
|
||||||
|
- 列渲染标志:`link / status / enum / billType / count`(注意**不能用 `type` 作 key**,`type` 是 el-table-column 真实 prop,会把列变成 selection/index 列)。
|
||||||
|
- 新增 `displayValue()`;`settlementBillTypeLabel('')` 返回 `-`。
|
||||||
|
- 序号列改 `fixed="left"`;数据列与操作列统一 `align: 'center'`,操作链接 `justify-content: center`。
|
||||||
|
- 校验方式(无 dev server 时):项目根目录临时 `sfc-check.mjs` 用 `vue/compiler-sfc` 的 `parse + compileTemplate + compileScript`;SCSS 用 `sass.compileString`。用完即删。
|
||||||
|
|
||||||
|
## 追加:用户要求「列显隐 + 显示方式」→ 两个页面改 avue-crud
|
||||||
|
|
||||||
|
用户反馈上面那版不对:右侧工具按钮必须是 **avue-crud 原生**的 4 键,第 2 键是「列显隐」抽屉(不是「列设置」勾选弹窗),第 4 键是「显示方式」(表格↔卡片),不是表格尺寸循环。确认后范围:`settlement-import` + `formal-settlement`(receipt/payment 共用)都改 avue-crud。
|
||||||
|
|
||||||
|
- 关键结论:**「列显隐 + 显示方式」只有 avue-crud 原生才有**,avue 的 `dialog-column` 依赖 `inject: ['crud']`,脱离 avue-crud 拿不出来;`table-header-tools` 只是仿制件,做不到。所以目标页只能整页改 avue-crud。
|
||||||
|
- avue 右侧按钮源码:`node_modules/@smallwei/avue/lib/packages/element-plus/crud/menu/header-menu3.js`(refreshBtn/columnBtn/searchBtn/gridBtn,`gridBtn` → `handleGridShow()` 切 `gridShow` 表格↔卡片);图标默认配置在同目录 `config.js`。
|
||||||
|
- 新增 `src/option/settlement/settlementImport.js`(`settlementImportOption`)、`src/option/settlement/formalSettlement.js`(`formalSettlementOption`,表格列复用 `formalSettlementTable.js` 的 `formalSettlementTableColumns` + `COLUMN_EXTRA` 增量配置,避免两处维护)。
|
||||||
|
- `settlement-import.vue` 整页改 avue-crud(删除手写的搜索区/表格/分页);`formal-settlement-table-panel.vue` 由 el-table 改成包一层 `<avue-crud>`,父页面保留数据加载与全部业务动作。
|
||||||
|
- ⚠️ **avue 的搜索自定义控件要用 `column.renderSearch`(`h()` 渲染),不能用 `searchslot`** —— avue 3.9.2 根本不读 `searchslot`(全库无此字段),而 `searchslot: true` 还会被 `header-search2.js` 的 `searchXxx → xxx` 映射成 `slot: true`。真正的搜索插槽是 avue-crud 上 `${prop}-search`(`crud.searchSlot`,见 `index2.js` `getSlotList(["-search"])`),但其作用域**没有 `row`**(只有 value/column/label/size/readonly/disabled/dic),`mileage-record.vue` 用 `{ row }` 是错的。已用于批次号下拉(filterable + allowCreate)。
|
||||||
|
- avue `formatter` 签名确认:`detail.js` → `column.formatter(row, row[column.prop], result, column)`。
|
||||||
|
- `on-load` 由 `table-page2.js` 在 created / 翻页 / 改页容量时触发,参数是内部 `defaultPage`(已 `Object.assign` 合并外部 page)。
|
||||||
|
- 分页透传写法(父持 page、子包 avue-crud):子组件用 computed `crudPage{get/set}`,setter 里 `Object.assign(this.page, value)` 原地回写,避免 prop 直接赋值告警。
|
||||||
|
- ⚠️ `src/option/settlement/formalSettlementTable.js` **不能删** —— `formal-settlement-editor.vue` 还从它导入 `candidateColumns/candidateDetailColumns/detailColumns/sourceColumns/summaryColumns`(我一度删掉,Vite 转换报错后从 HEAD 恢复)。
|
||||||
|
- 校验方式升级:沙箱里 curl 不通 dev server(502),改用 `vite.createServer({ middlewareMode:true })` + `server.transformRequest(path)` 就地转换,能同时暴露依赖解析失败(如上面误删文件)。脚本用完即删。
|
||||||
|
|
||||||
|
## 遗留未改(仍用 table-header-tools 仿制件)
|
||||||
|
|
||||||
|
pre-settlement、settlement-adjustment、receivable-payable-detail、transport-reconciliation-table-panel、business/{master-order,loading-manage,voucher-manage}、payment/* 手写页。若用户要全站一致,需逐页改 avue-crud。
|
||||||
@@ -66,9 +66,21 @@
|
|||||||
## 表单 / 自检 / 导出
|
## 表单 / 自检 / 导出
|
||||||
- placeholder 只写 `请输入`/`请选择`;例外:`请输入或选择车辆`、日期区间 `起`/`止`、示例值。校验 message 须带字段名。
|
- placeholder 只写 `请输入`/`请选择`;例外:`请输入或选择车辆`、日期区间 `起`/`止`、示例值。校验 message 须带字段名。
|
||||||
- `business-crud-page.vue`:option 经 `cloneOption` 克隆,独立表单页走 `PageAvueForm`。
|
- `business-crud-page.vue`:option 经 `cloneOption` 克隆,独立表单页走 `PageAvueForm`。
|
||||||
- 自检:`curl "localhost:2889/src/xxx.vue"` 与 `"...?vue&type=style&index=0&scoped=true&lang.scss"`(200 / 500)。`vite build` 在 `facelogin.vue` 被沙箱中断,不能作唯一校验。dev `VITE_APP_API=/api` 代理 `172.16.203.228:8000`。
|
- 自检:`curl "localhost:2888/src/xxx.vue"` 与 `"...?vue&type=style&index=0&scoped=true&lang.scss"`(200 / 500)。`vite build` 在 `facelogin.vue` 被沙箱中断,不能作唯一校验。dev `VITE_APP_API=/api` 代理 `172.16.203.228:8000`。
|
||||||
- 导出:前端 `exportColumns` 后端未用,以 `XxxExportExcel.java` 为准;BladeX `BeanUtil` 类型不兼容静默跳过(`Date` → `LocalDateTime` 丢值,用 `DateUtil.fromDate`)。
|
- 导出:前端 `exportColumns` 后端未用,以 `XxxExportExcel.java` 为准;BladeX `BeanUtil` 类型不兼容静默跳过(`Date` → `LocalDateTime` 丢值,用 `DateUtil.fromDate`)。
|
||||||
|
|
||||||
|
## avue-crud 才是「右侧 4 键」的唯一来源(2026-10-20 定论)
|
||||||
|
用户要的右侧工具栏是 **avue-crud 原生**:刷新 / **列显隐**(el-drawer,含 隐藏/冻结/过滤/排序 + 行拖拽)/ 搜索显隐 / **显示方式**(表格↔卡片)。
|
||||||
|
- 源码:`node_modules/@smallwei/avue/lib/packages/element-plus/crud/menu/header-menu3.js`(refreshBtn/columnBtn/searchBtn/gridBtn),`gridBtn` → `handleGridShow()` 切 `gridShow`;图标默认在同目录 `config.js`。「列显隐」文案来自 avue 语言包 `crud.showTitle`(项目 `src/lang/zh.js` 已覆盖)。
|
||||||
|
- **列显隐抽屉依赖 `inject: ['crud']`,脱离 avue-crud 拿不出来**;`components/table-header-tools` 的「列设置勾选弹窗 + 表格尺寸循环」是仿制件,**做不到这两点**。所以「要和 avue 一致」= 整页改用 avue-crud,没有中间方案。
|
||||||
|
- ⚠️ 搜索自定义控件用 `column.renderSearch = scope => h(...)`(`scope.row` 可用,同 `mixins/organization-search.js`)。**不要用 `searchslot`**:avue 3.9.2 全库无此字段,且 `header-search2.js` 的 `searchXxx → xxx` 映射会把 `searchslot` 变成 `slot: true`。
|
||||||
|
- avue-crud 上的 `${prop}-search` 插槽确实存在(`index2.js` 的 `getSlotList(["-search"])`),但**作用域没有 `row`**(只有 value/column/label/size/readonly/disabled/dic)——`mileage-record.vue` 里 `{ row }` 是错的写法,别照抄。
|
||||||
|
- `formatter` 签名:`detail.js` → `column.formatter(row, row[column.prop], result, column)`。
|
||||||
|
- `on-load` 由 `table-page2.js` 在 created / 翻页 / 改页容量时触发,参数是内部 `defaultPage`(已合并外部 page)。分页若由父组件持有、子组件包一层 avue-crud,用 computed `crudPage{get/set}` + setter 里 `Object.assign(this.page, value)` 原地回写。
|
||||||
|
- 已改:settlement-import.vue、formal-settlement.vue + components/formal-settlement-table-panel.vue(receipt/payment 共用)。未改:pre-settlement、settlement-adjustment、receivable-payable-detail、transport-reconciliation-table-panel、business 与 payment 的手写页。
|
||||||
|
- ⚠️ `src/option/settlement/formalSettlementTable.js` 别删:`formal-settlement-editor.vue` 还依赖它的 candidate/detail/source/summary 列。
|
||||||
|
- 沙箱里 curl 打不通本地 dev server(一律 502)。改用 `vite.createServer({middlewareMode:true})` + `server.transformRequest(path)` 就地转换校验,还能暴露依赖解析失败。
|
||||||
|
|
||||||
## Element Plus 图标两种用法的机制差异(易误判)
|
## Element Plus 图标两种用法的机制差异(易误判)
|
||||||
`main.js` 里 `for (...ElementPlusIconsVue) app.component(key, component)` 全局注册了全部图标,因此模板里可以写标签形式 `<Location />`(靠全局注册解析)。
|
`main.js` 里 `for (...ElementPlusIconsVue) app.component(key, component)` 全局注册了全部图标,因此模板里可以写标签形式 `<Location />`(靠全局注册解析)。
|
||||||
但 `:icon="OfficeBuilding"` 是**表达式**,编译成 `_ctx.OfficeBuilding`,只会从 data / props / computed / setup 返回值里取 —— **组件对象必须放进 `data()`**;放进 `components: {}` 注册里模板取不到,会静默渲染不出图标(不报错,只是空白)。
|
但 `:icon="OfficeBuilding"` 是**表达式**,编译成 `_ctx.OfficeBuilding`,只会从 data / props / computed / setup 返回值里取 —— **组件对象必须放进 `data()`**;放进 `components: {}` 注册里模板取不到,会静默渲染不出图标(不报错,只是空白)。
|
||||||
|
|||||||
+5
-4
@@ -4,10 +4,11 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host",
|
"dev": "vite --host",
|
||||||
"prod": "vite --mode production",
|
"prod": "vite --mode production",
|
||||||
"build": "vite build",
|
"build": "vite build && node scripts/zip-dist.mjs",
|
||||||
"build:prod": "vite build --mode production",
|
"build:prod": "vite build --mode production && node scripts/zip-dist.mjs",
|
||||||
|
"zip:dist": "node scripts/zip-dist.mjs",
|
||||||
"serve": "vite preview --host",
|
"serve": "vite preview --host",
|
||||||
"typecheck": "vue-tsc --noEmit"
|
"typecheck": "vue-tsc -p jsconfig.json --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
@@ -48,7 +49,7 @@
|
|||||||
"prettier": "^2.8.7",
|
"prettier": "^2.8.7",
|
||||||
"sass": "^1.85.1",
|
"sass": "^1.85.1",
|
||||||
"terser": "^5.31.1",
|
"terser": "^5.31.1",
|
||||||
"typescript": "^7.0.2",
|
"typescript": "5.9.3",
|
||||||
"unplugin-auto-import": "^0.11.2",
|
"unplugin-auto-import": "^0.11.2",
|
||||||
"vite": "^5.4.19",
|
"vite": "^5.4.19",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
|
|||||||
Generated
+94
-295
@@ -13,31 +13,31 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@element-plus/icons-vue':
|
'@element-plus/icons-vue':
|
||||||
specifier: ^2.3.1
|
specifier: ^2.3.1
|
||||||
version: 2.3.2(vue@3.5.34(typescript@7.0.2))
|
version: 2.3.2(vue@3.5.34(typescript@5.9.3))
|
||||||
'@open-file-viewer/core':
|
'@open-file-viewer/core':
|
||||||
specifier: ^0.1.27
|
specifier: ^0.1.27
|
||||||
version: 0.1.27(pdfjs-dist@6.1.200)
|
version: 0.1.27(pdfjs-dist@6.1.200)
|
||||||
'@open-file-viewer/vue':
|
'@open-file-viewer/vue':
|
||||||
specifier: ^0.1.27
|
specifier: ^0.1.27
|
||||||
version: 0.1.27(@open-file-viewer/core@0.1.27(pdfjs-dist@6.1.200))(vue@3.5.34(typescript@7.0.2))
|
version: 0.1.27(@open-file-viewer/core@0.1.27(pdfjs-dist@6.1.200))(vue@3.5.34(typescript@5.9.3))
|
||||||
'@saber/nf-design-base-elp':
|
'@saber/nf-design-base-elp':
|
||||||
specifier: ^1.3.0
|
specifier: ^1.3.0
|
||||||
version: 1.3.0
|
version: 1.3.0
|
||||||
'@saber/nf-form-design-elp':
|
'@saber/nf-form-design-elp':
|
||||||
specifier: ^1.6.1
|
specifier: ^1.6.1
|
||||||
version: 1.6.1(vue@3.5.34(typescript@7.0.2))
|
version: 1.6.1(vue@3.5.34(typescript@5.9.3))
|
||||||
'@saber/nf-form-elp':
|
'@saber/nf-form-elp':
|
||||||
specifier: ^1.6.3
|
specifier: ^1.6.3
|
||||||
version: 1.7.0
|
version: 1.7.0
|
||||||
'@smallwei/avue':
|
'@smallwei/avue':
|
||||||
specifier: ~3.9.2
|
specifier: ~3.9.2
|
||||||
version: 3.9.2(patch_hash=5ba15ad41b2c301250bf24adf39da2ed526b8375143da2c5a495361b29e862db)(@element-plus/icons-vue@2.3.2(vue@3.5.34(typescript@7.0.2)))(debug@4.4.3(supports-color@7.2.0))(element-plus@2.14.2(vue@3.5.34(typescript@7.0.2)))(vue@3.5.34(typescript@7.0.2))
|
version: 3.9.2(patch_hash=5ba15ad41b2c301250bf24adf39da2ed526b8375143da2c5a495361b29e862db)(@element-plus/icons-vue@2.3.2(vue@3.5.34(typescript@5.9.3)))(debug@4.4.3(supports-color@7.2.0))(element-plus@2.14.2(vue@3.5.34(typescript@5.9.3)))(vue@3.5.34(typescript@5.9.3))
|
||||||
animate.css:
|
animate.css:
|
||||||
specifier: ^4.1.1
|
specifier: ^4.1.1
|
||||||
version: 4.1.1
|
version: 4.1.1
|
||||||
avue-plugin-ueditor:
|
avue-plugin-ueditor:
|
||||||
specifier: ^1.0.4
|
specifier: ^1.0.4
|
||||||
version: 1.0.4(axios@1.16.0(debug@4.4.3(supports-color@7.2.0)))(vue@3.5.34(typescript@7.0.2))
|
version: 1.0.4(axios@1.16.0(debug@4.4.3(supports-color@7.2.0)))(vue@3.5.34(typescript@5.9.3))
|
||||||
axios:
|
axios:
|
||||||
specifier: ^1.13.5
|
specifier: ^1.13.5
|
||||||
version: 1.16.0(debug@4.4.3(supports-color@7.2.0))
|
version: 1.16.0(debug@4.4.3(supports-color@7.2.0))
|
||||||
@@ -58,7 +58,7 @@ importers:
|
|||||||
version: 6.1.0
|
version: 6.1.0
|
||||||
element-plus:
|
element-plus:
|
||||||
specifier: ^2.14.2
|
specifier: ^2.14.2
|
||||||
version: 2.14.2(vue@3.5.34(typescript@7.0.2))
|
version: 2.14.2(vue@3.5.34(typescript@5.9.3))
|
||||||
exceljs:
|
exceljs:
|
||||||
specifier: ^4.4.0
|
specifier: ^4.4.0
|
||||||
version: 4.4.0
|
version: 4.4.0
|
||||||
@@ -85,29 +85,29 @@ importers:
|
|||||||
version: 0.4.0
|
version: 0.4.0
|
||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.13
|
specifier: ^3.5.13
|
||||||
version: 3.5.34(typescript@7.0.2)
|
version: 3.5.34(typescript@5.9.3)
|
||||||
vue-i18n:
|
vue-i18n:
|
||||||
specifier: ^11.4.2
|
specifier: ^11.4.2
|
||||||
version: 11.4.2(vue@3.5.34(typescript@7.0.2))
|
version: 11.4.2(vue@3.5.34(typescript@5.9.3))
|
||||||
vue-pdf-embed:
|
vue-pdf-embed:
|
||||||
specifier: ^2.1.6
|
specifier: ^2.1.6
|
||||||
version: 2.1.6(vue@3.5.34(typescript@7.0.2))
|
version: 2.1.6(vue@3.5.34(typescript@5.9.3))
|
||||||
vue-router:
|
vue-router:
|
||||||
specifier: ^4.3.2
|
specifier: ^4.3.2
|
||||||
version: 4.6.4(vue@3.5.34(typescript@7.0.2))
|
version: 4.6.4(vue@3.5.34(typescript@5.9.3))
|
||||||
vue3-clipboard:
|
vue3-clipboard:
|
||||||
specifier: ^1.0.0
|
specifier: ^1.0.0
|
||||||
version: 1.0.0(vue@3.5.34(typescript@7.0.2))
|
version: 1.0.0(vue@3.5.34(typescript@5.9.3))
|
||||||
vuex:
|
vuex:
|
||||||
specifier: ^4.1.0
|
specifier: ^4.1.0
|
||||||
version: 4.1.0(vue@3.5.34(typescript@7.0.2))
|
version: 4.1.0(vue@3.5.34(typescript@5.9.3))
|
||||||
xlsx:
|
xlsx:
|
||||||
specifier: 0.18.5
|
specifier: 0.18.5
|
||||||
version: 0.18.5
|
version: 0.18.5
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^5.2.4
|
specifier: ^5.2.4
|
||||||
version: 5.2.4(vite@5.4.21(sass@1.99.0)(terser@5.46.2))(vue@3.5.34(typescript@7.0.2))
|
version: 5.2.4(vite@5.4.21(sass@1.99.0)(terser@5.46.2))(vue@3.5.34(typescript@5.9.3))
|
||||||
'@vue/compiler-sfc':
|
'@vue/compiler-sfc':
|
||||||
specifier: ^3.4.27
|
specifier: ^3.4.27
|
||||||
version: 3.5.34
|
version: 3.5.34
|
||||||
@@ -121,11 +121,11 @@ importers:
|
|||||||
specifier: ^5.31.1
|
specifier: ^5.31.1
|
||||||
version: 5.46.2
|
version: 5.46.2
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^7.0.2
|
specifier: 5.9.3
|
||||||
version: 7.0.2
|
version: 5.9.3
|
||||||
unplugin-auto-import:
|
unplugin-auto-import:
|
||||||
specifier: ^0.11.2
|
specifier: ^0.11.2
|
||||||
version: 0.11.5(@vueuse/core@14.3.0(vue@3.5.34(typescript@7.0.2)))(rollup@4.60.3)
|
version: 0.11.5(@vueuse/core@14.3.0(vue@3.5.34(typescript@5.9.3)))(rollup@4.60.3)
|
||||||
vite:
|
vite:
|
||||||
specifier: ^5.4.19
|
specifier: ^5.4.19
|
||||||
version: 5.4.21(sass@1.99.0)(terser@5.46.2)
|
version: 5.4.21(sass@1.99.0)(terser@5.46.2)
|
||||||
@@ -137,7 +137,7 @@ importers:
|
|||||||
version: 0.4.0(vite@5.4.21(sass@1.99.0)(terser@5.46.2))
|
version: 0.4.0(vite@5.4.21(sass@1.99.0)(terser@5.46.2))
|
||||||
vue-tsc:
|
vue-tsc:
|
||||||
specifier: ^3.3.11
|
specifier: ^3.3.11
|
||||||
version: 3.3.13(typescript@7.0.2)
|
version: 3.3.13(typescript@5.9.3)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -771,126 +771,6 @@ packages:
|
|||||||
'@types/web-bluetooth@0.0.21':
|
'@types/web-bluetooth@0.0.21':
|
||||||
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
|
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
|
||||||
|
|
||||||
'@typescript/typescript-aix-ppc64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [ppc64]
|
|
||||||
os: [aix]
|
|
||||||
|
|
||||||
'@typescript/typescript-darwin-arm64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
'@typescript/typescript-darwin-x64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
'@typescript/typescript-freebsd-arm64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [freebsd]
|
|
||||||
|
|
||||||
'@typescript/typescript-freebsd-x64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [freebsd]
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-arm64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-arm@7.0.2':
|
|
||||||
resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [arm]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-loong64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [loong64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-mips64el@7.0.2':
|
|
||||||
resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [mips64el]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-ppc64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [ppc64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-riscv64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [riscv64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-s390x@7.0.2':
|
|
||||||
resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [s390x]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-x64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@typescript/typescript-netbsd-arm64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [netbsd]
|
|
||||||
|
|
||||||
'@typescript/typescript-netbsd-x64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [netbsd]
|
|
||||||
|
|
||||||
'@typescript/typescript-openbsd-arm64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [openbsd]
|
|
||||||
|
|
||||||
'@typescript/typescript-openbsd-x64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [openbsd]
|
|
||||||
|
|
||||||
'@typescript/typescript-sunos-x64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [sunos]
|
|
||||||
|
|
||||||
'@typescript/typescript-win32-arm64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@typescript/typescript-win32-x64@7.0.2':
|
|
||||||
resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==}
|
|
||||||
engines: {node: '>=16.20.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@uppy/companion-client@2.2.2':
|
'@uppy/companion-client@2.2.2':
|
||||||
resolution: {integrity: sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==}
|
resolution: {integrity: sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==}
|
||||||
|
|
||||||
@@ -2194,9 +2074,9 @@ packages:
|
|||||||
typedarray@0.0.6:
|
typedarray@0.0.6:
|
||||||
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
||||||
|
|
||||||
typescript@7.0.2:
|
typescript@5.9.3:
|
||||||
resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==}
|
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||||
engines: {node: '>=16.20.0'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
ufo@1.6.4:
|
ufo@1.6.4:
|
||||||
@@ -2408,9 +2288,9 @@ snapshots:
|
|||||||
|
|
||||||
'@ctrl/tinycolor@4.2.0': {}
|
'@ctrl/tinycolor@4.2.0': {}
|
||||||
|
|
||||||
'@element-plus/icons-vue@2.3.2(vue@3.5.34(typescript@7.0.2))':
|
'@element-plus/icons-vue@2.3.2(vue@3.5.34(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.21.5':
|
'@esbuild/aix-ppc64@0.21.5':
|
||||||
optional: true
|
optional: true
|
||||||
@@ -2651,10 +2531,10 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- geotiff
|
- geotiff
|
||||||
|
|
||||||
'@open-file-viewer/vue@0.1.27(@open-file-viewer/core@0.1.27(pdfjs-dist@6.1.200))(vue@3.5.34(typescript@7.0.2))':
|
'@open-file-viewer/vue@0.1.27(@open-file-viewer/core@0.1.27(pdfjs-dist@6.1.200))(vue@3.5.34(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@open-file-viewer/core': 0.1.27(pdfjs-dist@6.1.200)
|
'@open-file-viewer/core': 0.1.27(pdfjs-dist@6.1.200)
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
'@parcel/watcher-android-arm64@2.5.6':
|
'@parcel/watcher-android-arm64@2.5.6':
|
||||||
optional: true
|
optional: true
|
||||||
@@ -2806,9 +2686,9 @@ snapshots:
|
|||||||
codemirror: 5.65.21
|
codemirror: 5.65.21
|
||||||
randomcolor: 0.6.2
|
randomcolor: 0.6.2
|
||||||
|
|
||||||
'@saber/nf-form-design-elp@1.6.1(vue@3.5.34(typescript@7.0.2))':
|
'@saber/nf-form-design-elp@1.6.1(vue@3.5.34(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vuedraggable: 4.1.0(vue@3.5.34(typescript@7.0.2))
|
vuedraggable: 4.1.0(vue@3.5.34(typescript@5.9.3))
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
@@ -2820,16 +2700,16 @@ snapshots:
|
|||||||
countup.js: 2.10.0
|
countup.js: 2.10.0
|
||||||
signature_pad: 5.1.3
|
signature_pad: 5.1.3
|
||||||
|
|
||||||
'@smallwei/avue@3.9.2(patch_hash=5ba15ad41b2c301250bf24adf39da2ed526b8375143da2c5a495361b29e862db)(@element-plus/icons-vue@2.3.2(vue@3.5.34(typescript@7.0.2)))(debug@4.4.3(supports-color@7.2.0))(element-plus@2.14.2(vue@3.5.34(typescript@7.0.2)))(vue@3.5.34(typescript@7.0.2))':
|
'@smallwei/avue@3.9.2(patch_hash=5ba15ad41b2c301250bf24adf39da2ed526b8375143da2c5a495361b29e862db)(@element-plus/icons-vue@2.3.2(vue@3.5.34(typescript@5.9.3)))(debug@4.4.3(supports-color@7.2.0))(element-plus@2.14.2(vue@3.5.34(typescript@5.9.3)))(vue@3.5.34(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@element-plus/icons-vue': 2.3.2(vue@3.5.34(typescript@7.0.2))
|
'@element-plus/icons-vue': 2.3.2(vue@3.5.34(typescript@5.9.3))
|
||||||
axios: 0.21.4(debug@4.4.3(supports-color@7.2.0))
|
axios: 0.21.4(debug@4.4.3(supports-color@7.2.0))
|
||||||
countup.js: 1.9.3
|
countup.js: 1.9.3
|
||||||
dayjs: 1.11.20
|
dayjs: 1.11.20
|
||||||
element-plus: 2.14.2(vue@3.5.34(typescript@7.0.2))
|
element-plus: 2.14.2(vue@3.5.34(typescript@5.9.3))
|
||||||
lodash: 4.18.1
|
lodash: 4.18.1
|
||||||
lodash-es: 4.18.1
|
lodash-es: 4.18.1
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- debug
|
- debug
|
||||||
|
|
||||||
@@ -2856,66 +2736,6 @@ snapshots:
|
|||||||
|
|
||||||
'@types/web-bluetooth@0.0.21': {}
|
'@types/web-bluetooth@0.0.21': {}
|
||||||
|
|
||||||
'@typescript/typescript-aix-ppc64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-darwin-arm64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-darwin-x64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-freebsd-arm64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-freebsd-x64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-arm64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-arm@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-loong64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-mips64el@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-ppc64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-riscv64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-s390x@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-linux-x64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-netbsd-arm64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-netbsd-x64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-openbsd-arm64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-openbsd-x64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-sunos-x64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-win32-arm64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@typescript/typescript-win32-x64@7.0.2':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@uppy/companion-client@2.2.2':
|
'@uppy/companion-client@2.2.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@uppy/utils': 4.1.3
|
'@uppy/utils': 4.1.3
|
||||||
@@ -2945,10 +2765,10 @@ snapshots:
|
|||||||
'@uppy/utils': 4.1.3
|
'@uppy/utils': 4.1.3
|
||||||
nanoid: 3.3.12
|
nanoid: 3.3.12
|
||||||
|
|
||||||
'@vitejs/plugin-vue@5.2.4(vite@5.4.21(sass@1.99.0)(terser@5.46.2))(vue@3.5.34(typescript@7.0.2))':
|
'@vitejs/plugin-vue@5.2.4(vite@5.4.21(sass@1.99.0)(terser@5.46.2))(vue@3.5.34(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 5.4.21(sass@1.99.0)(terser@5.46.2)
|
vite: 5.4.21(sass@1.99.0)(terser@5.46.2)
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
'@volar/language-core@2.4.28':
|
'@volar/language-core@2.4.28':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2956,13 +2776,13 @@ snapshots:
|
|||||||
|
|
||||||
'@volar/source-map@2.4.28': {}
|
'@volar/source-map@2.4.28': {}
|
||||||
|
|
||||||
'@volar/typescript@2.4.28(typescript@7.0.2)':
|
'@volar/typescript@2.4.28(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@volar/language-core': 2.4.28
|
'@volar/language-core': 2.4.28
|
||||||
path-browserify: 1.0.1
|
path-browserify: 1.0.1
|
||||||
vscode-uri: 3.2.0
|
vscode-uri: 3.2.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 7.0.2
|
typescript: 5.9.3
|
||||||
|
|
||||||
'@vue/compiler-core@3.5.34':
|
'@vue/compiler-core@3.5.34':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3022,51 +2842,51 @@ snapshots:
|
|||||||
'@vue/shared': 3.5.34
|
'@vue/shared': 3.5.34
|
||||||
csstype: 3.2.3
|
csstype: 3.2.3
|
||||||
|
|
||||||
'@vue/server-renderer@3.5.34(vue@3.5.34(typescript@7.0.2))':
|
'@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-ssr': 3.5.34
|
'@vue/compiler-ssr': 3.5.34
|
||||||
'@vue/shared': 3.5.34
|
'@vue/shared': 3.5.34
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
'@vue/shared@3.5.34': {}
|
'@vue/shared@3.5.34': {}
|
||||||
|
|
||||||
'@vueuse/core@14.3.0(vue@3.5.34(typescript@7.0.2))':
|
'@vueuse/core@14.3.0(vue@3.5.34(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/web-bluetooth': 0.0.21
|
'@types/web-bluetooth': 0.0.21
|
||||||
'@vueuse/metadata': 14.3.0
|
'@vueuse/metadata': 14.3.0
|
||||||
'@vueuse/shared': 14.3.0(vue@3.5.34(typescript@7.0.2))
|
'@vueuse/shared': 14.3.0(vue@3.5.34(typescript@5.9.3))
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
'@vueuse/metadata@14.3.0': {}
|
'@vueuse/metadata@14.3.0': {}
|
||||||
|
|
||||||
'@vueuse/shared@14.3.0(vue@3.5.34(typescript@7.0.2))':
|
'@vueuse/shared@14.3.0(vue@3.5.34(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
'@wangeditor-next/basic-modules@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)':
|
'@wangeditor-next/basic-modules@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
dom7: 3.0.0
|
dom7: 4.0.6
|
||||||
is-url: 1.2.4
|
is-url: 1.2.4
|
||||||
lodash.throttle: 4.1.1
|
lodash.throttle: 4.1.1
|
||||||
nanoid: 5.1.11
|
nanoid: 5.1.11
|
||||||
slate: 0.123.0
|
slate: 0.123.0
|
||||||
snabbdom: 3.6.3
|
snabbdom: 3.6.3
|
||||||
|
|
||||||
'@wangeditor-next/code-highlight@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.123.0)(snabbdom@3.6.3)':
|
'@wangeditor-next/code-highlight@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.123.0)(snabbdom@3.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
dom7: 4.0.6
|
dom7: 4.0.6
|
||||||
prismjs: 1.30.0
|
prismjs: 1.30.0
|
||||||
slate: 0.123.0
|
slate: 0.123.0
|
||||||
snabbdom: 3.6.3
|
snabbdom: 3.6.3
|
||||||
|
|
||||||
'@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)':
|
'@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/event-emitter': 0.3.5
|
'@types/event-emitter': 0.3.5
|
||||||
'@uppy/core': 2.3.4
|
'@uppy/core': 2.3.4
|
||||||
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||||
dom7: 3.0.0
|
dom7: 4.0.6
|
||||||
event-emitter: 0.3.5
|
event-emitter: 0.3.5
|
||||||
html-void-elements: 3.0.0
|
html-void-elements: 3.0.0
|
||||||
i18next: 23.16.8
|
i18next: 23.16.8
|
||||||
@@ -3087,13 +2907,13 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@uppy/core': 2.3.4
|
'@uppy/core': 2.3.4
|
||||||
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||||
'@wangeditor-next/basic-modules': 2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/basic-modules': 2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
'@wangeditor-next/code-highlight': 2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/code-highlight': 2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
'@wangeditor-next/list-module': 2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/list-module': 2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
'@wangeditor-next/table-module': 2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.debounce@4.0.8)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/table-module': 2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.debounce@4.0.8)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
'@wangeditor-next/upload-image-module': 2.0.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/basic-modules@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.foreach@4.5.0)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/upload-image-module': 2.0.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/basic-modules@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.foreach@4.5.0)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
'@wangeditor-next/video-module': 2.0.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/video-module': 2.0.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
dom7: 4.0.6
|
dom7: 4.0.6
|
||||||
is-hotkey: 0.2.0
|
is-hotkey: 0.2.0
|
||||||
lodash.camelcase: 4.3.0
|
lodash.camelcase: 4.3.0
|
||||||
@@ -3106,16 +2926,16 @@ snapshots:
|
|||||||
slate: 0.123.0
|
slate: 0.123.0
|
||||||
snabbdom: 3.6.3
|
snabbdom: 3.6.3
|
||||||
|
|
||||||
'@wangeditor-next/list-module@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.123.0)(snabbdom@3.6.3)':
|
'@wangeditor-next/list-module@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.123.0)(snabbdom@3.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
dom7: 4.0.6
|
dom7: 4.0.6
|
||||||
slate: 0.123.0
|
slate: 0.123.0
|
||||||
snabbdom: 3.6.3
|
snabbdom: 3.6.3
|
||||||
|
|
||||||
'@wangeditor-next/table-module@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.debounce@4.0.8)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)':
|
'@wangeditor-next/table-module@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.debounce@4.0.8)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
dom7: 4.0.6
|
dom7: 4.0.6
|
||||||
lodash.debounce: 4.0.8
|
lodash.debounce: 4.0.8
|
||||||
lodash.throttle: 4.1.1
|
lodash.throttle: 4.1.1
|
||||||
@@ -3123,22 +2943,22 @@ snapshots:
|
|||||||
slate: 0.123.0
|
slate: 0.123.0
|
||||||
snabbdom: 3.6.3
|
snabbdom: 3.6.3
|
||||||
|
|
||||||
'@wangeditor-next/upload-image-module@2.0.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/basic-modules@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.foreach@4.5.0)(slate@0.123.0)(snabbdom@3.6.3)':
|
'@wangeditor-next/upload-image-module@2.0.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/basic-modules@2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.foreach@4.5.0)(slate@0.123.0)(snabbdom@3.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@uppy/core': 2.3.4
|
'@uppy/core': 2.3.4
|
||||||
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||||
'@wangeditor-next/basic-modules': 2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/basic-modules': 2.0.0(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
dom7: 4.0.6
|
dom7: 4.0.6
|
||||||
lodash.foreach: 4.5.0
|
lodash.foreach: 4.5.0
|
||||||
slate: 0.123.0
|
slate: 0.123.0
|
||||||
snabbdom: 3.6.3
|
snabbdom: 3.6.3
|
||||||
|
|
||||||
'@wangeditor-next/video-module@2.0.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)':
|
'@wangeditor-next/video-module@2.0.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/core@1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3))(dom7@4.0.6)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@uppy/core': 2.3.4
|
'@uppy/core': 2.3.4
|
||||||
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||||
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
'@wangeditor-next/core': 1.8.0(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.11)(slate@0.123.0)(snabbdom@3.6.3)
|
||||||
dom7: 4.0.6
|
dom7: 4.0.6
|
||||||
nanoid: 5.1.11
|
nanoid: 5.1.11
|
||||||
slate: 0.123.0
|
slate: 0.123.0
|
||||||
@@ -3185,10 +3005,10 @@ snapshots:
|
|||||||
slate-history: 0.66.0(slate@0.72.8)
|
slate-history: 0.66.0(slate@0.72.8)
|
||||||
snabbdom: 3.6.3
|
snabbdom: 3.6.3
|
||||||
|
|
||||||
'@wangeditor/editor-for-vue@5.1.12(@wangeditor/editor@5.1.23)(vue@3.5.34(typescript@7.0.2))':
|
'@wangeditor/editor-for-vue@5.1.12(@wangeditor/editor@5.1.23)(vue@3.5.34(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@wangeditor/editor': 5.1.23
|
'@wangeditor/editor': 5.1.23
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
'@wangeditor/editor@5.1.23':
|
'@wangeditor/editor@5.1.23':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3317,12 +3137,12 @@ snapshots:
|
|||||||
|
|
||||||
asynckit@0.4.0: {}
|
asynckit@0.4.0: {}
|
||||||
|
|
||||||
avue-plugin-ueditor@1.0.4(axios@1.16.0(debug@4.4.3(supports-color@7.2.0)))(vue@3.5.34(typescript@7.0.2)):
|
avue-plugin-ueditor@1.0.4(axios@1.16.0(debug@4.4.3(supports-color@7.2.0)))(vue@3.5.34(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@wangeditor/editor': 5.1.23
|
'@wangeditor/editor': 5.1.23
|
||||||
'@wangeditor/editor-for-vue': 5.1.12(@wangeditor/editor@5.1.23)(vue@3.5.34(typescript@7.0.2))
|
'@wangeditor/editor-for-vue': 5.1.12(@wangeditor/editor@5.1.23)(vue@3.5.34(typescript@5.9.3))
|
||||||
axios: 1.16.0(debug@4.4.3(supports-color@7.2.0))
|
axios: 1.16.0(debug@4.4.3(supports-color@7.2.0))
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
axios@0.21.4(debug@4.4.3(supports-color@7.2.0)):
|
axios@0.21.4(debug@4.4.3(supports-color@7.2.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3575,15 +3395,15 @@ snapshots:
|
|||||||
tslib: 2.3.0
|
tslib: 2.3.0
|
||||||
zrender: 6.1.0
|
zrender: 6.1.0
|
||||||
|
|
||||||
element-plus@2.14.2(vue@3.5.34(typescript@7.0.2)):
|
element-plus@2.14.2(vue@3.5.34(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ctrl/tinycolor': 4.2.0
|
'@ctrl/tinycolor': 4.2.0
|
||||||
'@element-plus/icons-vue': 2.3.2(vue@3.5.34(typescript@7.0.2))
|
'@element-plus/icons-vue': 2.3.2(vue@3.5.34(typescript@5.9.3))
|
||||||
'@floating-ui/dom': 1.7.6
|
'@floating-ui/dom': 1.7.6
|
||||||
'@popperjs/core': '@sxzz/popperjs-es@2.11.8'
|
'@popperjs/core': '@sxzz/popperjs-es@2.11.8'
|
||||||
'@types/lodash': 4.17.24
|
'@types/lodash': 4.17.24
|
||||||
'@types/lodash-es': 4.17.12
|
'@types/lodash-es': 4.17.12
|
||||||
'@vueuse/core': 14.3.0(vue@3.5.34(typescript@7.0.2))
|
'@vueuse/core': 14.3.0(vue@3.5.34(typescript@5.9.3))
|
||||||
async-validator: 4.2.5
|
async-validator: 4.2.5
|
||||||
dayjs: 1.11.20
|
dayjs: 1.11.20
|
||||||
lodash: 4.18.1
|
lodash: 4.18.1
|
||||||
@@ -3591,7 +3411,7 @@ snapshots:
|
|||||||
lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.18.1)(lodash@4.18.1)
|
lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.18.1)(lodash@4.18.1)
|
||||||
memoize-one: 6.0.0
|
memoize-one: 6.0.0
|
||||||
normalize-wheel-es: 1.2.0
|
normalize-wheel-es: 1.2.0
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
vue-component-type-helpers: 3.3.6
|
vue-component-type-helpers: 3.3.6
|
||||||
|
|
||||||
end-of-stream@1.4.5:
|
end-of-stream@1.4.5:
|
||||||
@@ -4352,28 +4172,7 @@ snapshots:
|
|||||||
|
|
||||||
typedarray@0.0.6: {}
|
typedarray@0.0.6: {}
|
||||||
|
|
||||||
typescript@7.0.2:
|
typescript@5.9.3: {}
|
||||||
optionalDependencies:
|
|
||||||
'@typescript/typescript-aix-ppc64': 7.0.2
|
|
||||||
'@typescript/typescript-darwin-arm64': 7.0.2
|
|
||||||
'@typescript/typescript-darwin-x64': 7.0.2
|
|
||||||
'@typescript/typescript-freebsd-arm64': 7.0.2
|
|
||||||
'@typescript/typescript-freebsd-x64': 7.0.2
|
|
||||||
'@typescript/typescript-linux-arm': 7.0.2
|
|
||||||
'@typescript/typescript-linux-arm64': 7.0.2
|
|
||||||
'@typescript/typescript-linux-loong64': 7.0.2
|
|
||||||
'@typescript/typescript-linux-mips64el': 7.0.2
|
|
||||||
'@typescript/typescript-linux-ppc64': 7.0.2
|
|
||||||
'@typescript/typescript-linux-riscv64': 7.0.2
|
|
||||||
'@typescript/typescript-linux-s390x': 7.0.2
|
|
||||||
'@typescript/typescript-linux-x64': 7.0.2
|
|
||||||
'@typescript/typescript-netbsd-arm64': 7.0.2
|
|
||||||
'@typescript/typescript-netbsd-x64': 7.0.2
|
|
||||||
'@typescript/typescript-openbsd-arm64': 7.0.2
|
|
||||||
'@typescript/typescript-openbsd-x64': 7.0.2
|
|
||||||
'@typescript/typescript-sunos-x64': 7.0.2
|
|
||||||
'@typescript/typescript-win32-arm64': 7.0.2
|
|
||||||
'@typescript/typescript-win32-x64': 7.0.2
|
|
||||||
|
|
||||||
ufo@1.6.4: {}
|
ufo@1.6.4: {}
|
||||||
|
|
||||||
@@ -4397,7 +4196,7 @@ snapshots:
|
|||||||
|
|
||||||
universalify@2.0.1: {}
|
universalify@2.0.1: {}
|
||||||
|
|
||||||
unplugin-auto-import@0.11.5(@vueuse/core@14.3.0(vue@3.5.34(typescript@7.0.2)))(rollup@4.60.3):
|
unplugin-auto-import@0.11.5(@vueuse/core@14.3.0(vue@3.5.34(typescript@5.9.3)))(rollup@4.60.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@antfu/utils': 0.7.10
|
'@antfu/utils': 0.7.10
|
||||||
'@rollup/pluginutils': 5.3.0(rollup@4.60.3)
|
'@rollup/pluginutils': 5.3.0(rollup@4.60.3)
|
||||||
@@ -4406,7 +4205,7 @@ snapshots:
|
|||||||
unimport: 1.3.0(rollup@4.60.3)
|
unimport: 1.3.0(rollup@4.60.3)
|
||||||
unplugin: 1.16.1
|
unplugin: 1.16.1
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@vueuse/core': 14.3.0(vue@3.5.34(typescript@7.0.2))
|
'@vueuse/core': 14.3.0(vue@3.5.34(typescript@5.9.3))
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- rollup
|
- rollup
|
||||||
|
|
||||||
@@ -4465,54 +4264,54 @@ snapshots:
|
|||||||
|
|
||||||
vue-component-type-helpers@3.3.6: {}
|
vue-component-type-helpers@3.3.6: {}
|
||||||
|
|
||||||
vue-i18n@11.4.2(vue@3.5.34(typescript@7.0.2)):
|
vue-i18n@11.4.2(vue@3.5.34(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@intlify/core-base': 11.4.2
|
'@intlify/core-base': 11.4.2
|
||||||
'@intlify/devtools-types': 11.4.2
|
'@intlify/devtools-types': 11.4.2
|
||||||
'@intlify/shared': 11.4.2
|
'@intlify/shared': 11.4.2
|
||||||
'@vue/devtools-api': 6.6.4
|
'@vue/devtools-api': 6.6.4
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
vue-pdf-embed@2.1.6(vue@3.5.34(typescript@7.0.2)):
|
vue-pdf-embed@2.1.6(vue@3.5.34(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
pdfjs-dist: 6.2.108
|
pdfjs-dist: 6.2.108
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
vue-router@4.6.4(vue@3.5.34(typescript@7.0.2)):
|
vue-router@4.6.4(vue@3.5.34(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/devtools-api': 6.6.4
|
'@vue/devtools-api': 6.6.4
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
vue-tsc@3.3.13(typescript@7.0.2):
|
vue-tsc@3.3.13(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@volar/typescript': 2.4.28(typescript@7.0.2)
|
'@volar/typescript': 2.4.28(typescript@5.9.3)
|
||||||
'@vue/language-core': 3.3.13
|
'@vue/language-core': 3.3.13
|
||||||
typescript: 7.0.2
|
typescript: 5.9.3
|
||||||
|
|
||||||
vue3-clipboard@1.0.0(vue@3.5.34(typescript@7.0.2)):
|
vue3-clipboard@1.0.0(vue@3.5.34(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
clipboard: 2.0.11
|
clipboard: 2.0.11
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
vue@3.5.34(typescript@7.0.2):
|
vue@3.5.34(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-dom': 3.5.34
|
'@vue/compiler-dom': 3.5.34
|
||||||
'@vue/compiler-sfc': 3.5.34
|
'@vue/compiler-sfc': 3.5.34
|
||||||
'@vue/runtime-dom': 3.5.34
|
'@vue/runtime-dom': 3.5.34
|
||||||
'@vue/server-renderer': 3.5.34(vue@3.5.34(typescript@7.0.2))
|
'@vue/server-renderer': 3.5.34(vue@3.5.34(typescript@5.9.3))
|
||||||
'@vue/shared': 3.5.34
|
'@vue/shared': 3.5.34
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 7.0.2
|
typescript: 5.9.3
|
||||||
|
|
||||||
vuedraggable@4.1.0(vue@3.5.34(typescript@7.0.2)):
|
vuedraggable@4.1.0(vue@3.5.34(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
sortablejs: 1.14.0
|
sortablejs: 1.14.0
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
vuex@4.1.0(vue@3.5.34(typescript@7.0.2)):
|
vuex@4.1.0(vue@3.5.34(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/devtools-api': 6.6.4
|
'@vue/devtools-api': 6.6.4
|
||||||
vue: 3.5.34(typescript@7.0.2)
|
vue: 3.5.34(typescript@5.9.3)
|
||||||
|
|
||||||
webpack-virtual-modules@0.6.2: {}
|
webpack-virtual-modules@0.6.2: {}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { execFileSync } from 'node:child_process';
|
||||||
|
import { existsSync, rmSync, statSync } from 'node:fs';
|
||||||
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
|
const root = process.cwd();
|
||||||
|
const distDir = resolve(root, 'dist');
|
||||||
|
const zipPath = resolve(root, 'dist.zip');
|
||||||
|
|
||||||
|
if (!existsSync(distDir) || !statSync(distDir).isDirectory()) {
|
||||||
|
console.error('[zip-dist] dist 目录不存在,请先完成构建');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existsSync(zipPath)) {
|
||||||
|
rmSync(zipPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 压缩 dist 内文件到根级(解压即 index.html / assets,便于直接上传部署)
|
||||||
|
execFileSync('zip', ['-qr', zipPath, '.', '-x', '*.DS_Store', '-x', '__MACOSX/*'], {
|
||||||
|
cwd: distDir,
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
|
||||||
|
const sizeMb = (statSync(zipPath).size / (1024 * 1024)).toFixed(2);
|
||||||
|
console.log(`[zip-dist] 已生成 ${zipPath}(${sizeMb} MB)`);
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { createCrudApi } from './common';
|
||||||
|
import { APPROVE_TIMEOUT } from '@/api/common';
|
||||||
|
import request from '@/axios';
|
||||||
|
|
||||||
|
const baseUrl = '/blade-transport/contract-change';
|
||||||
|
const api = createCrudApi(baseUrl);
|
||||||
|
|
||||||
|
export const getList = api.getList;
|
||||||
|
export const getDetail = api.getDetail;
|
||||||
|
export const submit = api.submit;
|
||||||
|
export const remove = api.remove;
|
||||||
|
|
||||||
|
export const createFromContract = (contractId, changeType) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/create-from-contract`,
|
||||||
|
method: 'post',
|
||||||
|
params: { contractId, changeType },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const saveDraft = row =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/save-draft`,
|
||||||
|
method: 'post',
|
||||||
|
data: row,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const submitApproval = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/submit-approval`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const approve = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/approve`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
timeout: APPROVE_TIMEOUT,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const reject = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/reject`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const withdraw = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/withdraw`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const markSyncStatus = (ids, syncStatus) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/mark-sync-status`,
|
||||||
|
method: 'post',
|
||||||
|
params: { ids, syncStatus },
|
||||||
|
});
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createCrudApi } from './common';
|
import { createCrudApi } from './common';
|
||||||
|
import { APPROVE_TIMEOUT } from '@/api/common';
|
||||||
import request from '@/axios';
|
import request from '@/axios';
|
||||||
|
|
||||||
const baseUrl = '/blade-transport/contract-manage';
|
const baseUrl = '/blade-transport/contract-manage';
|
||||||
@@ -36,6 +37,7 @@ export const approve = id =>
|
|||||||
url: `${baseUrl}/approve`,
|
url: `${baseUrl}/approve`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params: { id },
|
params: { id },
|
||||||
|
timeout: APPROVE_TIMEOUT,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const reject = id =>
|
export const reject = id =>
|
||||||
@@ -91,10 +93,10 @@ export const expireStats = params =>
|
|||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 按合同负责部门预览下一合同编号 */
|
/** 按平台公司 + 业务部门预览下一合同编号 */
|
||||||
export const nextContractNo = organizationId =>
|
export const nextContractNo = (organizationId, platformCompanyId) =>
|
||||||
request({
|
request({
|
||||||
url: `${baseUrl}/next-contract-no`,
|
url: `${baseUrl}/next-contract-no`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { organizationId },
|
params: { organizationId, platformCompanyId },
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
import request from '@/axios';
|
||||||
|
|
||||||
|
const baseUrl = '/blade-transport/hcs';
|
||||||
|
|
||||||
|
/** 进程内缓存,避免列表页重复请求推送开关 */
|
||||||
|
let immediateEnabledCache = null;
|
||||||
|
let immediateEnabledPromise = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询 HCS 即时推送开关(thirdParty.hcs.push.immediate-enabled)。
|
||||||
|
* 关闭时项目管理/合同管理隐藏「推送合规」「批量推送合规」。
|
||||||
|
*/
|
||||||
|
export const getPushConfig = () =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/push-config`,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const loadHcsImmediateEnabled = () => {
|
||||||
|
if (immediateEnabledCache !== null) {
|
||||||
|
return Promise.resolve(immediateEnabledCache);
|
||||||
|
}
|
||||||
|
if (immediateEnabledPromise) {
|
||||||
|
return immediateEnabledPromise;
|
||||||
|
}
|
||||||
|
immediateEnabledPromise = getPushConfig()
|
||||||
|
.then(res => {
|
||||||
|
const data = res?.data?.data ?? res?.data ?? {};
|
||||||
|
immediateEnabledCache = data.immediateEnabled === true || data.immediateEnabled === 'true';
|
||||||
|
return immediateEnabledCache;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
immediateEnabledCache = false;
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
immediateEnabledPromise = null;
|
||||||
|
});
|
||||||
|
return immediateEnabledPromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 合规推送涉及 HCS 远程多次调用(风险校验+附件转传+起草),可达 20s+,覆盖全局 10s 超时
|
||||||
|
export const repush = (bizType, id) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/sync/${bizType}/${id}`,
|
||||||
|
method: 'post',
|
||||||
|
timeout: 60000,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 批量推送为逐条同步推送,耗时随勾选行数线性增长,进一步放宽超时
|
||||||
|
export const repushBatch = (bizType, ids) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/sync/${bizType}/batch`,
|
||||||
|
method: 'post',
|
||||||
|
data: ids,
|
||||||
|
timeout: 300000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getTemplates = () =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/master-data/template`,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const refreshMasterData = () =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/master-data/refresh`,
|
||||||
|
method: 'post',
|
||||||
|
timeout: 60000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getRisk = (customerCode, creditCode, customerName) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/risk`,
|
||||||
|
method: 'get',
|
||||||
|
params: { customerCode, creditCode, customerName },
|
||||||
|
timeout: 30000,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 客商风险批量查询(客商列表页展示用):入参编号数组,后端逐个查 C101-1,单个失败跳过
|
||||||
|
export const getRiskBatch = customerCodes =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/risk/batch`,
|
||||||
|
method: 'get',
|
||||||
|
params: { customerCodes: (customerCodes || []).join(',') },
|
||||||
|
timeout: 60000,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 客商风险按名称查询(客商档案表单展示用):名称反查编号后口径同编号查询
|
||||||
|
export const getRiskByName = customerName =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/risk/by-name`,
|
||||||
|
method: 'get',
|
||||||
|
params: { customerName },
|
||||||
|
timeout: 30000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const uploadAttachment = formData =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/attachment/upload`,
|
||||||
|
method: 'post',
|
||||||
|
data: formData,
|
||||||
|
timeout: 60000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const downloadAttachment = (fdId, name) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/attachment/download`,
|
||||||
|
method: 'get',
|
||||||
|
params: { fdId, name },
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const applyContractSpec = data =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/contract/spec-apply`,
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
timeout: 60000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const confirmContractSpec = (id, result) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/contract/spec/confirm`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id, result },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const unwrapData = response => {
|
||||||
|
const data = response?.data?.data ?? response?.data;
|
||||||
|
return data && typeof data === 'object' && 'data' in data ? data.data : data;
|
||||||
|
};
|
||||||
@@ -24,11 +24,16 @@ export const getDetail = id =>
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getCarrierContracts = projectIds =>
|
export const getCarrierContracts = (projectIds, waybillIds = []) =>
|
||||||
request({
|
request({
|
||||||
url: `${baseUrl}/carrier-contracts`,
|
url: `${baseUrl}/carrier-contracts`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { projectIds: (projectIds || []).join(',') },
|
params: {
|
||||||
|
projectIds: (projectIds || []).join(','),
|
||||||
|
...(waybillIds || []).filter(Boolean).length
|
||||||
|
? { waybillIds: (waybillIds || []).filter(Boolean).join(',') }
|
||||||
|
: {},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const saveDraft = row =>
|
export const saveDraft = row =>
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ export const approve = id =>
|
|||||||
url: `${baseUrl}/approve`,
|
url: `${baseUrl}/approve`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params: { id },
|
params: { id },
|
||||||
|
// 审批通过后同步推送合规(远程多次调用),覆盖全局 10s 超时
|
||||||
|
timeout: 60000,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const reject = id =>
|
export const reject = id =>
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { createCrudApi } from './common';
|
||||||
|
import { APPROVE_TIMEOUT } from '@/api/common';
|
||||||
|
import request from '@/axios';
|
||||||
|
|
||||||
|
const baseUrl = '/blade-transport/project-change';
|
||||||
|
const api = createCrudApi(baseUrl);
|
||||||
|
|
||||||
|
export const getList = api.getList;
|
||||||
|
export const getDetail = api.getDetail;
|
||||||
|
export const submit = api.submit;
|
||||||
|
export const remove = api.remove;
|
||||||
|
|
||||||
|
export const createFromProject = (projectId, changeType) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/create-from-project`,
|
||||||
|
method: 'post',
|
||||||
|
params: { projectId, changeType },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const saveDraft = row =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/save-draft`,
|
||||||
|
method: 'post',
|
||||||
|
data: row,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const submitApproval = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/submit-approval`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const approve = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/approve`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
timeout: APPROVE_TIMEOUT,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const reject = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/reject`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const withdraw = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/withdraw`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
@@ -14,6 +14,13 @@ export const cancel = api.cancel;
|
|||||||
export const reassign = api.reassign;
|
export const reassign = api.reassign;
|
||||||
export const complete = api.complete;
|
export const complete = api.complete;
|
||||||
export const batchComplete = api.batchComplete;
|
export const batchComplete = api.batchComplete;
|
||||||
|
/** 确认回单:回单节点配成「需业务员确认」时用;后端校验司机打卡节点齐全且无未了结异常后才置完成 */
|
||||||
|
export const confirmReturn = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/confirm-return`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
export const changeRoute = data =>
|
export const changeRoute = data =>
|
||||||
request({
|
request({
|
||||||
url: `${baseUrl}/change-route`,
|
url: `${baseUrl}/change-route`,
|
||||||
@@ -88,3 +95,5 @@ export const exportImportFailures = data =>
|
|||||||
});
|
});
|
||||||
export const confirmImport = data =>
|
export const confirmImport = data =>
|
||||||
request({ url: `${baseUrl}/import-batch/confirm`, method: 'post', data, timeout: 120000 });
|
request({ url: `${baseUrl}/import-batch/confirm`, method: 'post', data, timeout: 120000 });
|
||||||
|
export const checkImportDuplicates = data =>
|
||||||
|
request({ url: `${baseUrl}/import-batch/duplicates`, method: 'post', data, timeout: 120000 });
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import request from '@/axios';
|
import request from '@/axios';
|
||||||
import { ElLoading, ElMessage } from 'element-plus';
|
import { ElLoading, ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
/** 审核按钮统一超时:审批通过后可能同步推送金蝶等耗时操作,覆盖全局 10s */
|
||||||
|
export const APPROVE_TIMEOUT = 60 * 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件流返回
|
* 文件流返回
|
||||||
* @param url 接口地址
|
* @param url 接口地址
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ export const getList = (current, size, params) =>
|
|||||||
request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } });
|
request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } });
|
||||||
export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get', params: { id } });
|
export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get', params: { id } });
|
||||||
export const getExpiryCounts = () => request({ url: `${baseUrl}/expiry-counts`, method: 'get' });
|
export const getExpiryCounts = () => request({ url: `${baseUrl}/expiry-counts`, method: 'get' });
|
||||||
export const getAvailableOptions = (keyword, deptId, selectedId) =>
|
export const getAvailableOptions = (keyword, deptId, selectedId, payerName, payeeName) =>
|
||||||
request({
|
request({
|
||||||
url: `${baseUrl}/available-options`,
|
url: `${baseUrl}/available-options`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { keyword, deptId, selectedId },
|
params: { keyword, deptId, selectedId, payerName, payeeName },
|
||||||
});
|
});
|
||||||
export const getAvailablePage = (current, size, keyword, deptId, selectedId) =>
|
export const getAvailablePage = (current, size, keyword, deptId, selectedId, payerName, payeeName) =>
|
||||||
request({
|
request({
|
||||||
url: `${baseUrl}/available-page`,
|
url: `${baseUrl}/available-page`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { current, size, keyword, deptId, selectedId },
|
params: { current, size, keyword, deptId, selectedId, payerName, payeeName },
|
||||||
});
|
});
|
||||||
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
||||||
export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import request from '@/axios';
|
import request from '@/axios';
|
||||||
|
import { APPROVE_TIMEOUT } from '@/api/common';
|
||||||
|
|
||||||
const baseUrl = '/blade-transport/invoice-application';
|
const baseUrl = '/blade-transport/invoice-application';
|
||||||
|
|
||||||
@@ -18,7 +19,8 @@ export const getReceiverInformation = settlementIds =>
|
|||||||
export const save = data => request({ url: `${baseUrl}/save`, method: 'post', data });
|
export const save = data => request({ url: `${baseUrl}/save`, method: 'post', data });
|
||||||
export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
||||||
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
||||||
export const approve = data => request({ url: `${baseUrl}/approve`, method: 'post', data });
|
export const approve = data =>
|
||||||
|
request({ url: `${baseUrl}/approve`, method: 'post', data, timeout: APPROVE_TIMEOUT });
|
||||||
export const returnBill = data => request({ url: `${baseUrl}/return`, method: 'post', data });
|
export const returnBill = data => request({ url: `${baseUrl}/return`, method: 'post', data });
|
||||||
export const voidBill = data => request({ url: `${baseUrl}/void`, method: 'post', data });
|
export const voidBill = data => request({ url: `${baseUrl}/void`, method: 'post', data });
|
||||||
export const syncKingdee = id =>
|
export const syncKingdee = id =>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import request from '@/axios';
|
import request from '@/axios';
|
||||||
|
import { APPROVE_TIMEOUT } from '@/api/common';
|
||||||
|
|
||||||
const baseUrl = '/blade-transport/invoice-receipt';
|
const baseUrl = '/blade-transport/invoice-receipt';
|
||||||
|
|
||||||
@@ -31,11 +32,21 @@ export const getReferenceInformation = settlementIds =>
|
|||||||
export const save = data => request({ url: `${baseUrl}/save`, method: 'post', data });
|
export const save = data => request({ url: `${baseUrl}/save`, method: 'post', data });
|
||||||
export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
||||||
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
||||||
export const approve = data => request({ url: `${baseUrl}/approve`, method: 'post', data });
|
export const approve = data =>
|
||||||
|
request({ url: `${baseUrl}/approve`, method: 'post', data, timeout: APPROVE_TIMEOUT });
|
||||||
export const returnBill = data => request({ url: `${baseUrl}/return`, method: 'post', data });
|
export const returnBill = data => request({ url: `${baseUrl}/return`, method: 'post', data });
|
||||||
export const voidBill = data => request({ url: `${baseUrl}/void`, method: 'post', data });
|
export const voidBill = data => request({ url: `${baseUrl}/void`, method: 'post', data });
|
||||||
export const pushKingdee = ids =>
|
export const pushKingdee = ids =>
|
||||||
request({ url: `${baseUrl}/push-kingdee`, method: 'post', timeout: 30000, data: ids });
|
request({ url: `${baseUrl}/push-kingdee`, method: 'post', timeout: 30000, data: ids });
|
||||||
|
// 先票后款:发票明细查询(收票登记明细区块按票号带出发票明细行)
|
||||||
|
export const invoiceDetailQuery = invoiceNo =>
|
||||||
|
request({ url: `${baseUrl}/invoice-detail-query`, method: 'get', params: { invoiceNo } });
|
||||||
|
// 先票后款:结算单认领收票单候选分页(审批通过且未被有效应付结算单认领)
|
||||||
|
export const claimCandidates = params =>
|
||||||
|
request({ url: `${baseUrl}/claim-candidates`, method: 'get', params });
|
||||||
|
// 先票后款:结算单已认领收票登记列表(发票登记对话框回显已认领票)
|
||||||
|
export const claimedReceipts = formalSettlementId =>
|
||||||
|
request({ url: `${baseUrl}/claimed-list`, method: 'get', params: { formalSettlementId } });
|
||||||
|
|
||||||
export const approvalStatusOptions = [
|
export const approvalStatusOptions = [
|
||||||
{ label: '草稿', value: 'draft' },
|
{ label: '草稿', value: 'draft' },
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import request from '@/axios';
|
import request from '@/axios';
|
||||||
|
import { APPROVE_TIMEOUT } from '@/api/common';
|
||||||
|
|
||||||
const baseUrl = '/blade-transport/payment-application';
|
const baseUrl = '/blade-transport/payment-application';
|
||||||
export const getList = (current, size, params) =>
|
export const getList = (current, size, params) =>
|
||||||
@@ -10,21 +11,29 @@ export const getReferenceAmount = (paymentType, referenceId, excludeId) =>
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
params: { paymentType, referenceId, excludeId: excludeId || undefined },
|
params: { paymentType, referenceId, excludeId: excludeId || undefined },
|
||||||
});
|
});
|
||||||
|
/** 按合同查询可选项目预付核销列表(审批通过且仍有可核销余额) */
|
||||||
|
export const getProjectAdvanceWriteOffOptions = params =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/project-advance-write-off-options`,
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
});
|
||||||
export const save = data => request({ url: `${baseUrl}/save`, method: 'post', data });
|
export const save = data => request({ url: `${baseUrl}/save`, method: 'post', data });
|
||||||
export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
||||||
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
||||||
export const approve = data => request({ url: `${baseUrl}/approve`, method: 'post', data });
|
export const approve = data =>
|
||||||
|
request({ url: `${baseUrl}/approve`, method: 'post', data, timeout: APPROVE_TIMEOUT });
|
||||||
export const returnBill = data => request({ url: `${baseUrl}/return`, method: 'post', data });
|
export const returnBill = data => request({ url: `${baseUrl}/return`, method: 'post', data });
|
||||||
export const voidBill = data => request({ url: `${baseUrl}/void`, method: 'post', data });
|
export const voidBill = data => request({ url: `${baseUrl}/void`, method: 'post', data });
|
||||||
// 同步金蝶涉及多次金蝶远程接口调用(A103-2 预检 + A103-1/A103-3 推送),单笔可达 20s+,覆盖全局 10s 超时
|
// 同步金蝶涉及多次金蝶远程接口调用(A103-2 预检 + A103-1/A103-3 推送),单笔可达 20s+,覆盖全局 10s 超时
|
||||||
export const syncKingdee = id =>
|
export const syncKingdee = id =>
|
||||||
request({ url: `${baseUrl}/sync-kingdee`, method: 'post', timeout: 30000, params: { id } });
|
request({ url: `${baseUrl}/sync-kingdee`, method: 'post', timeout: APPROVE_TIMEOUT, params: { id } });
|
||||||
// 批量同步逐单单据级事务串行推送,耗时随单量线性增长
|
// 批量同步逐单单据级事务串行推送,耗时随单量线性增长
|
||||||
export const syncKingdeeBatch = ids =>
|
export const syncKingdeeBatch = ids =>
|
||||||
request({ url: `${baseUrl}/sync-kingdee-batch`, method: 'post', timeout: 30000, data: ids });
|
request({ url: `${baseUrl}/sync-kingdee-batch`, method: 'post', timeout: APPROVE_TIMEOUT, data: ids });
|
||||||
// 回写任务按 paymentNo 分批远程查询 A103-2/A103-4,同样可能超过全局超时
|
// 回写任务按 paymentNo 分批远程查询 A103-2/A103-4,同样可能超过全局超时
|
||||||
export const syncKingdeeResult = () =>
|
export const syncKingdeeResult = () =>
|
||||||
request({ url: `${baseUrl}/sync-kingdee-result`, method: 'post', timeout: 30000 });
|
request({ url: `${baseUrl}/sync-kingdee-result`, method: 'post', timeout: APPROVE_TIMEOUT });
|
||||||
|
|
||||||
export const paymentTypeOptions = [
|
export const paymentTypeOptions = [
|
||||||
{ label: '项目预付', value: 'project_advance' },
|
{ label: '项目预付', value: 'project_advance' },
|
||||||
|
|||||||
@@ -8,20 +8,12 @@ export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get'
|
|||||||
export const updateAttachments = data =>
|
export const updateAttachments = data =>
|
||||||
request({ url: `${baseUrl}/attachments`, method: 'post', data });
|
request({ url: `${baseUrl}/attachments`, method: 'post', data });
|
||||||
export const voidClaim = id => request({ url: `${baseUrl}/void`, method: 'post', params: { id } });
|
export const voidClaim = id => request({ url: `${baseUrl}/void`, method: 'post', params: { id } });
|
||||||
export const queryKingdeeResult = () =>
|
|
||||||
request({ url: `${baseUrl}/query-kingdee-result`, method: 'post' });
|
|
||||||
|
|
||||||
export const claimStatusOptions = [
|
export const claimStatusOptions = [
|
||||||
{ label: '已认领', value: 'claimed' },
|
{ label: '已认领', value: 'claimed' },
|
||||||
{ label: '已作废', value: 'voided' },
|
{ label: '已作废', value: 'voided' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const pushStatusOptions = [
|
|
||||||
{ label: '未推送', value: 'none' },
|
|
||||||
{ label: '已推送', value: 'pushed' },
|
|
||||||
{ label: '推送失败', value: 'failed' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const kingdeeBillStatusOptions = [
|
export const kingdeeBillStatusOptions = [
|
||||||
{ label: '未生成', value: 'none' },
|
{ label: '未生成', value: 'none' },
|
||||||
{ label: '已推送', value: 'pushed' },
|
{ label: '已推送', value: 'pushed' },
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import request from '@/axios';
|
|||||||
|
|
||||||
const baseUrl = '/blade-transport/receipt-flow';
|
const baseUrl = '/blade-transport/receipt-flow';
|
||||||
|
|
||||||
|
/** 收款流水同步需远程拉取金蝶收款单并逐条落库,覆盖全局 10s 超时 */
|
||||||
|
export const SYNC_TIMEOUT = 30000;
|
||||||
|
|
||||||
export const getList = (current, size, params) =>
|
export const getList = (current, size, params) =>
|
||||||
request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } });
|
request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } });
|
||||||
export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get', params: { id } });
|
export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get', params: { id } });
|
||||||
@@ -12,9 +15,7 @@ export const getSettlementCandidates = (keyword, flowId) =>
|
|||||||
params: { keyword, flowId },
|
params: { keyword, flowId },
|
||||||
});
|
});
|
||||||
export const claim = data => request({ url: `${baseUrl}/claim`, method: 'post', data });
|
export const claim = data => request({ url: `${baseUrl}/claim`, method: 'post', data });
|
||||||
export const sync = () => request({ url: `${baseUrl}/sync`, method: 'post' });
|
export const sync = () => request({ url: `${baseUrl}/sync`, method: 'post', timeout: SYNC_TIMEOUT });
|
||||||
export const pushKingdee = flowId =>
|
|
||||||
request({ url: `${baseUrl}/push-kingdee`, method: 'post', params: { flowId } });
|
|
||||||
|
|
||||||
export const claimStatusOptions = [
|
export const claimStatusOptions = [
|
||||||
{ label: '未认领', value: 'unclaimed' },
|
{ label: '未认领', value: 'unclaimed' },
|
||||||
@@ -22,12 +23,6 @@ export const claimStatusOptions = [
|
|||||||
{ label: '认领完成', value: 'claimed' },
|
{ label: '认领完成', value: 'claimed' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const pushStatusOptions = [
|
|
||||||
{ label: '未推送', value: 'none' },
|
|
||||||
{ label: '已推送', value: 'pushed' },
|
|
||||||
{ label: '推送失败', value: 'failed' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const kingdeeBillStatusOptions = [
|
export const kingdeeBillStatusOptions = [
|
||||||
{ label: '已推送', value: 'pushed' },
|
{ label: '已推送', value: 'pushed' },
|
||||||
{ label: '审核通过', value: 'approved' },
|
{ label: '审核通过', value: 'approved' },
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import request from '@/axios';
|
import request from '@/axios';
|
||||||
|
import { APPROVE_TIMEOUT } from '@/api/common';
|
||||||
|
|
||||||
const baseUrl = '/blade-transport/formal-settlement';
|
const baseUrl = '/blade-transport/formal-settlement';
|
||||||
|
|
||||||
@@ -27,12 +28,20 @@ export const getCandidateDetails = (current, size, params) =>
|
|||||||
export const save = data => request({ url: `${baseUrl}/save`, method: 'post', data });
|
export const save = data => request({ url: `${baseUrl}/save`, method: 'post', data });
|
||||||
export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
||||||
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
||||||
export const approve = data => request({ url: `${baseUrl}/approve`, method: 'post', data });
|
export const approve = data =>
|
||||||
|
request({ url: `${baseUrl}/approve`, method: 'post', data, timeout: APPROVE_TIMEOUT });
|
||||||
export const returnBill = data => request({ url: `${baseUrl}/return`, method: 'post', data });
|
export const returnBill = data => request({ url: `${baseUrl}/return`, method: 'post', data });
|
||||||
export const voidBill = data => request({ url: `${baseUrl}/void`, method: 'post', data });
|
export const voidBill = data => request({ url: `${baseUrl}/void`, method: 'post', data });
|
||||||
// 同步金蝶涉及多次金蝶远程接口调用(A102-4 预检 + A102-2 保存),可达 20s+,覆盖全局 10s 超时
|
// 同步金蝶涉及多次金蝶远程接口调用(A102-4 预检 + A102-2 保存),可达 20s+,覆盖全局 10s 超时
|
||||||
export const syncKingdee = id =>
|
// config.meta.suppressErrorMessage=true 时由页面弹框汇总结果,避免拦截器重复 toast
|
||||||
request({ url: `${baseUrl}/sync-kingdee`, method: 'post', timeout: 30000, params: { id } });
|
export const syncKingdee = (id, config = {}) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/sync-kingdee`,
|
||||||
|
method: 'post',
|
||||||
|
timeout: 30000,
|
||||||
|
params: { id },
|
||||||
|
...config,
|
||||||
|
});
|
||||||
export const getDetailFees = detailId =>
|
export const getDetailFees = detailId =>
|
||||||
request({ url: `${baseUrl}/detail-fees`, method: 'get', params: { detailId } });
|
request({ url: `${baseUrl}/detail-fees`, method: 'get', params: { detailId } });
|
||||||
export const getReceiptClaims = formalSettlementId =>
|
export const getReceiptClaims = formalSettlementId =>
|
||||||
@@ -49,5 +58,21 @@ export const applyPayments = data =>
|
|||||||
request({ url: `${baseUrl}/apply-payments`, method: 'post', data });
|
request({ url: `${baseUrl}/apply-payments`, method: 'post', data });
|
||||||
export const claimInvoices = data =>
|
export const claimInvoices = data =>
|
||||||
request({ url: `${baseUrl}/claim-invoices`, method: 'post', data });
|
request({ url: `${baseUrl}/claim-invoices`, method: 'post', data });
|
||||||
|
// 先票后款:发票登记确认推送(认领收票单逐单 A302-6 指定应付),涉及多次金蝶远程调用,覆盖全局超时
|
||||||
|
export const invoiceAssignKingdee = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/invoice-assign-kingdee`,
|
||||||
|
method: 'post',
|
||||||
|
timeout: 30000,
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
// 先票后款:查看页重推认领收票单(收票单A303-2+指定应付A302-6 一步式),涉及多次金蝶远程调用,覆盖全局超时
|
||||||
|
export const repushClaimedInvoice = (id, invoiceNo, matchedAmount) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/repush-claimed-invoice`,
|
||||||
|
method: 'post',
|
||||||
|
timeout: 30000,
|
||||||
|
params: { id, invoiceNo, matchedAmount },
|
||||||
|
});
|
||||||
export const queryInvoicePool = params =>
|
export const queryInvoicePool = params =>
|
||||||
request({ url: `${baseUrl}/invoice-pool`, method: 'get', params });
|
request({ url: `${baseUrl}/invoice-pool`, method: 'get', params });
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import request from '@/axios';
|
import request from '@/axios';
|
||||||
|
import { APPROVE_TIMEOUT } from '@/api/common';
|
||||||
|
|
||||||
const baseUrl = '/blade-transport/pre-settlement';
|
const baseUrl = '/blade-transport/pre-settlement';
|
||||||
|
|
||||||
@@ -24,6 +25,8 @@ export const getContractList = (current, size, params) =>
|
|||||||
|
|
||||||
export const getFeeOptions = () => request({ url: `${baseUrl}/fee-options`, method: 'get' });
|
export const getFeeOptions = () => request({ url: `${baseUrl}/fee-options`, method: 'get' });
|
||||||
|
|
||||||
|
export const getNextNo = () => request({ url: `${baseUrl}/next-no`, method: 'get' });
|
||||||
|
|
||||||
export const getCandidateDetails = (current, size, params) =>
|
export const getCandidateDetails = (current, size, params) =>
|
||||||
request({
|
request({
|
||||||
url: `${baseUrl}/candidate-details`,
|
url: `${baseUrl}/candidate-details`,
|
||||||
@@ -40,7 +43,8 @@ export const removeDetail = (id, detailId) =>
|
|||||||
|
|
||||||
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
||||||
|
|
||||||
export const approve = data => request({ url: `${baseUrl}/approve`, method: 'post', data });
|
export const approve = data =>
|
||||||
|
request({ url: `${baseUrl}/approve`, method: 'post', data, timeout: APPROVE_TIMEOUT });
|
||||||
|
|
||||||
export const returnBill = data => request({ url: `${baseUrl}/return`, method: 'post', data });
|
export const returnBill = data => request({ url: `${baseUrl}/return`, method: 'post', data });
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ export const approve = id => request({ url: `${baseUrl}/approve`, method: 'post'
|
|||||||
export const returnBill = (id, reason) =>
|
export const returnBill = (id, reason) =>
|
||||||
request({ url: `${baseUrl}/return`, method: 'post', data: { id, reason } });
|
request({ url: `${baseUrl}/return`, method: 'post', data: { id, reason } });
|
||||||
export const repush = id => request({ url: `${baseUrl}/repush`, method: 'post', params: { id } });
|
export const repush = id => request({ url: `${baseUrl}/repush`, method: 'post', params: { id } });
|
||||||
|
export const syncKingdee = id =>
|
||||||
|
request({ url: `${baseUrl}/sync-kingdee`, method: 'post', timeout: 30000, params: { id } });
|
||||||
|
export const kingdeeWriteOffPrecheck = formalSettlementId =>
|
||||||
|
request({ url: `${baseUrl}/kingdee-writeoff-precheck`, method: 'get', params: { formalSettlementId } });
|
||||||
|
|
||||||
export const approvalStatusOptions = [
|
export const approvalStatusOptions = [
|
||||||
{ label: '草稿', value: 'draft' },
|
{ label: '草稿', value: 'draft' },
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import request from '@/axios';
|
||||||
|
|
||||||
|
const baseUrl = '/blade-transport/settlement-import';
|
||||||
|
|
||||||
|
export const getOptions = () => request({ url: `${baseUrl}/options`, method: 'get' });
|
||||||
|
|
||||||
|
export const getNextCode = () => request({ url: `${baseUrl}/next-code`, method: 'get' });
|
||||||
|
|
||||||
|
export const getList = (current, size, params) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/list`,
|
||||||
|
method: 'get',
|
||||||
|
params: { current, size, ...params },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getDetail = id =>
|
||||||
|
request({ url: `${baseUrl}/detail`, method: 'get', params: { id } });
|
||||||
|
|
||||||
|
export const exportTemplate = () =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/export-template`,
|
||||||
|
method: 'get',
|
||||||
|
responseType: 'blob',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const parseFile = file => {
|
||||||
|
const data = new FormData();
|
||||||
|
data.append('file', file);
|
||||||
|
return request({
|
||||||
|
url: `${baseUrl}/parse`,
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const validate = data =>
|
||||||
|
request({ url: `${baseUrl}/validate`, method: 'post', data, timeout: 120000 });
|
||||||
|
|
||||||
|
export const exportFailures = data =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/export-failures`,
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const saveDraft = data =>
|
||||||
|
request({ url: `${baseUrl}/draft`, method: 'post', data, timeout: 120000 });
|
||||||
|
|
||||||
|
export const confirm = data =>
|
||||||
|
request({ url: `${baseUrl}/confirm`, method: 'post', data, timeout: 120000 });
|
||||||
|
|
||||||
|
export const voidBatch = data => request({ url: `${baseUrl}/void`, method: 'post', data });
|
||||||
|
|
||||||
|
export const removeDraft = id =>
|
||||||
|
request({ url: `${baseUrl}/remove`, method: 'post', params: { id } });
|
||||||
|
|
||||||
|
export const getHistoryWaybills = params =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/history-waybills`,
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
});
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import request from '@/axios';
|
||||||
|
|
||||||
|
const baseUrl = '/blade-system/business-dept-config';
|
||||||
|
|
||||||
|
export const getList = (current, size, params) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/list`,
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
...params,
|
||||||
|
current,
|
||||||
|
size,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getDetail = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/detail`,
|
||||||
|
method: 'get',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const submit = row =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/submit`,
|
||||||
|
method: 'post',
|
||||||
|
data: row,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const remove = ids =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/remove`,
|
||||||
|
method: 'post',
|
||||||
|
params: { ids },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getByPlatformDept = (platformCompanyId, businessDeptId) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/by-platform-dept`,
|
||||||
|
method: 'get',
|
||||||
|
params: { platformCompanyId, businessDeptId },
|
||||||
|
});
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
import request from '@/axios';
|
import request from '@/axios';
|
||||||
|
|
||||||
|
/** 提交审核流(MK)统一超时:客商/项目/合同/预结算/正式结算/付款/开票/收票/汇票付款 */
|
||||||
|
export const MK_SUBMIT_TIMEOUT = 30000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用 MK processSubmit 提交审核流
|
* 调用 MK processSubmit 提交审核流
|
||||||
* @param {Object} data
|
* @param {Object} data
|
||||||
@@ -9,12 +12,14 @@ import request from '@/axios';
|
|||||||
* @param {string} data.bizId 业务主键(后端生成/复用 formInstanceId)
|
* @param {string} data.bizId 业务主键(后端生成/复用 formInstanceId)
|
||||||
* @param {string} [data.subject] 流程标题
|
* @param {string} [data.subject] 流程标题
|
||||||
* @param {string} [data.bizType] 业务类型
|
* @param {string} [data.bizType] 业务类型
|
||||||
|
* @param {Object} [data.tempVarData] MK 临时变量(如 { projectType })
|
||||||
*/
|
*/
|
||||||
export const processSubmit = data => {
|
export const processSubmit = data => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-system/businessProcess/processSubmit',
|
url: '/blade-system/businessProcess/processSubmit',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data,
|
||||||
|
timeout: MK_SUBMIT_TIMEOUT,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,6 +33,7 @@ export const processDelete = data => {
|
|||||||
url: '/blade-system/businessProcess/processDelete',
|
url: '/blade-system/businessProcess/processDelete',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data,
|
||||||
|
timeout: MK_SUBMIT_TIMEOUT,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+10
-1
@@ -77,7 +77,8 @@ export const syncOaDepartment = (
|
|||||||
size = 20,
|
size = 20,
|
||||||
signal,
|
signal,
|
||||||
incremental = false,
|
incremental = false,
|
||||||
modifiedSince
|
modifiedSince,
|
||||||
|
companyOaId
|
||||||
) => {
|
) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-system/dept/sync-oa-department',
|
url: '/blade-system/dept/sync-oa-department',
|
||||||
@@ -87,6 +88,7 @@ export const syncOaDepartment = (
|
|||||||
size,
|
size,
|
||||||
incremental: !!incremental,
|
incremental: !!incremental,
|
||||||
modifiedSince: modifiedSince || undefined,
|
modifiedSince: modifiedSince || undefined,
|
||||||
|
companyOaId: companyOaId || undefined,
|
||||||
},
|
},
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
signal,
|
signal,
|
||||||
@@ -137,3 +139,10 @@ export const getPlatformCompanySelect = () => {
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getBusinessDeptSelect = () => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-system/dept/business-dept-select',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import request from '@/axios';
|
||||||
|
|
||||||
|
export const getRoleMenuDataScopeTree = roleId => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-system/role-menu-data-scope/tree',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
roleId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const submitRoleMenuDataScope = data => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-system/role-menu-data-scope/submit',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -91,3 +91,14 @@ export const recognizeBaiduOcr = (imageUrl, type, side = '') => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const recognizeQualificationCertificateOcr = imageUrl => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-transport/baidu-ocr/qualification-certificate',
|
||||||
|
method: 'post',
|
||||||
|
timeout: 60000,
|
||||||
|
params: {
|
||||||
|
imageUrl,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -152,6 +152,34 @@ export const getScoreTemplate = quantificationId => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 线下评分 Excel 模板下载 */
|
||||||
|
export const downloadScoreExcelTemplate = quantificationId => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-transport/customer-archive/score-excel-template',
|
||||||
|
method: 'get',
|
||||||
|
responseType: 'blob',
|
||||||
|
params: {
|
||||||
|
quantificationId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 线下评分 Excel 导入(成功返回评分明细 JSON;失败返回失败明细 Excel 流) */
|
||||||
|
export const importScoreExcel = (quantificationId, file) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
return request({
|
||||||
|
url: '/blade-transport/customer-archive/score-import',
|
||||||
|
method: 'post',
|
||||||
|
data: formData,
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 60000,
|
||||||
|
params: {
|
||||||
|
quantificationId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const queryKingdeeCustomer = creditCode => {
|
export const queryKingdeeCustomer = creditCode => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-transport/bfi/customer/query-by-credit-code',
|
url: '/blade-transport/bfi/customer/query-by-credit-code',
|
||||||
@@ -163,6 +191,42 @@ export const queryKingdeeCustomer = creditCode => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 金蝶供应商编码查询(A901-1):新增客商填写信用代码后即时回显
|
||||||
|
export const querySupplierCode = creditCode => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-transport/customer-archive/query-supplier-code',
|
||||||
|
method: 'get',
|
||||||
|
timeout: 30000,
|
||||||
|
params: {
|
||||||
|
creditCode,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 金蝶开户行查询(A905-3):收款信息填写开户行失焦后精确匹配带出联行号
|
||||||
|
export const queryKingdeeBank = bankName => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-transport/customer-archive/query-bank',
|
||||||
|
method: 'get',
|
||||||
|
timeout: 30000,
|
||||||
|
params: {
|
||||||
|
bankName,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 金蝶联行号校验(A905-3):收款信息保存前按联行号精确匹配,查不到不允许保存
|
||||||
|
export const queryKingdeeBankByNumber = cnapsCode => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-transport/customer-archive/query-bank-by-number',
|
||||||
|
method: 'get',
|
||||||
|
timeout: 30000,
|
||||||
|
params: {
|
||||||
|
cnapsCode,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const syncKingdee = id => {
|
export const syncKingdee = id => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-transport/customer-archive/sync-kingdee',
|
url: '/blade-transport/customer-archive/sync-kingdee',
|
||||||
@@ -176,12 +240,11 @@ export const syncKingdee = id => {
|
|||||||
|
|
||||||
export const recognizeBusinessLicenseOcr = imageUrl => {
|
export const recognizeBusinessLicenseOcr = imageUrl => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-transport/baidu-ocr/recognize-url',
|
url: '/blade-transport/baidu-ocr/business-license',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
params: {
|
params: {
|
||||||
imageUrl,
|
imageUrl,
|
||||||
type: 'business_license',
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
+46
-18
@@ -74,12 +74,15 @@ const redirectToLogin = () => {
|
|||||||
* 统一弹出错误提示并返回带标记的 Error。
|
* 统一弹出错误提示并返回带标记的 Error。
|
||||||
* `_notified` 标记用于让业务层(批量导入等)识别「拦截器已经提示过」,
|
* `_notified` 标记用于让业务层(批量导入等)识别「拦截器已经提示过」,
|
||||||
* 避免同一条错误被弹两次。
|
* 避免同一条错误被弹两次。
|
||||||
|
* meta.suppressErrorMessage=true 时由业务层自行弹框汇总,拦截器不再 toast。
|
||||||
*/
|
*/
|
||||||
const notifiedError = message => {
|
const notifiedError = (message, config) => {
|
||||||
ElMessage({
|
if (config?.meta?.suppressErrorMessage !== true) {
|
||||||
message: message,
|
ElMessage({
|
||||||
type: 'error',
|
message: message,
|
||||||
});
|
type: 'error',
|
||||||
|
});
|
||||||
|
}
|
||||||
const error = new Error(message);
|
const error = new Error(message);
|
||||||
error._notified = true;
|
error._notified = true;
|
||||||
return error;
|
return error;
|
||||||
@@ -102,12 +105,27 @@ const isJsonContentType = res => {
|
|||||||
return contentType.includes('application/json') || contentType.includes('text/json');
|
return contentType.includes('application/json') || contentType.includes('text/json');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为可按文本读取的 Blob / Blob-like(含跨 realm)。
|
||||||
|
* 禁止对普通业务 JSON 对象调用 .text()。
|
||||||
|
*/
|
||||||
|
const isBlobLikeData = value =>
|
||||||
|
value != null &&
|
||||||
|
typeof value === 'object' &&
|
||||||
|
typeof value.size === 'number' &&
|
||||||
|
typeof value.type === 'string' &&
|
||||||
|
typeof value.text === 'function';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断响应体是否已是解析好的对象(无需再解析)。
|
* 判断响应体是否已是解析好的对象(无需再解析)。
|
||||||
* 注意 Blob 也是 object,必须排除,否则会把待解析的文件流误判为已完成。
|
* 注意 Blob 也是 object,必须排除,否则会把待解析的文件流误判为已完成。
|
||||||
*/
|
*/
|
||||||
const isPlainObject = value =>
|
const isPlainObject = value =>
|
||||||
value !== null && typeof value === 'object' && !(value instanceof Blob);
|
value !== null &&
|
||||||
|
typeof value === 'object' &&
|
||||||
|
!(value instanceof Blob) &&
|
||||||
|
!isBlobLikeData(value) &&
|
||||||
|
!(value instanceof ArrayBuffer);
|
||||||
//跨域请求,允许保存cookie
|
//跨域请求,允许保存cookie
|
||||||
axios.defaults.withCredentials = true;
|
axios.defaults.withCredentials = true;
|
||||||
// NProgress Configuration
|
// NProgress Configuration
|
||||||
@@ -187,15 +205,20 @@ axios.interceptors.response.use(
|
|||||||
// 用户就会以为系统崩了——而后端其实返回了明确的业务提示(如「未读取到数据行…」)。
|
// 用户就会以为系统崩了——而后端其实返回了明确的业务提示(如「未读取到数据行…」)。
|
||||||
// 这里按 Content-Type 判断:JSON 才解析回对象;真·文件流(Excel 等)保持原样不动。
|
// 这里按 Content-Type 判断:JSON 才解析回对象;真·文件流(Excel 等)保持原样不动。
|
||||||
// 兼容 Blob(浏览器 responseType='blob')与 string(非浏览器环境)两种形态。
|
// 兼容 Blob(浏览器 responseType='blob')与 string(非浏览器环境)两种形态。
|
||||||
|
// 仅对真正的 Blob/Blob-like 调 .text(),避免业务 JSON 已解析后出现
|
||||||
|
// 「e.data.text is not a function」。
|
||||||
if (isJsonContentType(res) && !isPlainObject(res.data)) {
|
if (isJsonContentType(res) && !isPlainObject(res.data)) {
|
||||||
try {
|
try {
|
||||||
let text = '';
|
let text = '';
|
||||||
if (typeof res.data?.text === 'function') {
|
const raw = res.data;
|
||||||
text = await res.data.text();
|
if (isBlobLikeData(raw) || (typeof Blob !== 'undefined' && raw instanceof Blob)) {
|
||||||
} else if (typeof res.data === 'string') {
|
text = await raw.text();
|
||||||
text = res.data;
|
} else if (typeof raw === 'string') {
|
||||||
} else if (typeof res.data?.arrayBuffer === 'function') {
|
text = raw;
|
||||||
text = new TextDecoder().decode(await res.data.arrayBuffer());
|
} else if (raw && typeof raw.arrayBuffer === 'function') {
|
||||||
|
text = new TextDecoder().decode(await raw.arrayBuffer());
|
||||||
|
} else if (raw instanceof ArrayBuffer) {
|
||||||
|
text = new TextDecoder().decode(raw);
|
||||||
}
|
}
|
||||||
const parsed = typeof text === 'string' && text ? JSON.parse(text) : null;
|
const parsed = typeof text === 'string' && text ? JSON.parse(text) : null;
|
||||||
if (parsed && typeof parsed === 'object') {
|
if (parsed && typeof parsed === 'object') {
|
||||||
@@ -205,10 +228,11 @@ axios.interceptors.response.use(
|
|||||||
// 声明是 JSON 却解析失败:保持原样,交给下游按文件处理
|
// 声明是 JSON 却解析失败:保持原样,交给下游按文件处理
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//获取状态信息
|
// 获取状态信息:文件流没有 code/msg,必须退回 HTTP status,禁止读 Blob 上的幽灵字段
|
||||||
const status = res.data.error_code || res.data.code || res.status;
|
const payload = isPlainObject(res.data) ? res.data : {};
|
||||||
|
const status = Number(payload.error_code || payload.code || res.status);
|
||||||
const statusWhiteList = website.statusWhiteList || [];
|
const statusWhiteList = website.statusWhiteList || [];
|
||||||
const message = res.data.msg || res.data.error_description || '系统错误';
|
const message = payload.msg || payload.error_description || '系统错误';
|
||||||
//如果在白名单里则自行catch逻辑处理
|
//如果在白名单里则自行catch逻辑处理
|
||||||
if (statusWhiteList.includes(status)) return Promise.reject(res);
|
if (statusWhiteList.includes(status)) return Promise.reject(res);
|
||||||
|
|
||||||
@@ -260,12 +284,12 @@ axios.interceptors.response.use(
|
|||||||
|
|
||||||
// OAuth2 业务错误码提示
|
// OAuth2 业务错误码提示
|
||||||
if (status > 2000 && !validatenull(res.data.error_description)) {
|
if (status > 2000 && !validatenull(res.data.error_description)) {
|
||||||
return Promise.reject(notifiedError(message));
|
return Promise.reject(notifiedError(message, config));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 其余非 200 响应统一提示
|
// 其余非 200 响应统一提示
|
||||||
if (status !== 200) {
|
if (status !== 200) {
|
||||||
return Promise.reject(notifiedError(message));
|
return Promise.reject(notifiedError(message, config));
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
@@ -273,7 +297,11 @@ axios.interceptors.response.use(
|
|||||||
NProgress.done();
|
NProgress.done();
|
||||||
// 网络级失败(HTTP 状态 >500、网关错误、超时、断网等 validateStatus 放行之外的响应)
|
// 网络级失败(HTTP 状态 >500、网关错误、超时、断网等 validateStatus 放行之外的响应)
|
||||||
// 原为静默 reject,接口报错页面无任何感知;统一补错误提示,取消请求与刷新令牌请求除外
|
// 原为静默 reject,接口报错页面无任何感知;统一补错误提示,取消请求与刷新令牌请求除外
|
||||||
if (!axios.isCancel(error) && !isRefreshTokenRequest(error?.config)) {
|
if (
|
||||||
|
!axios.isCancel(error) &&
|
||||||
|
!isRefreshTokenRequest(error?.config) &&
|
||||||
|
error?.config?.meta?.suppressErrorMessage !== true
|
||||||
|
) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: error?.response?.data?.msg || '请求失败,请稍后重试',
|
message: error?.response?.data?.msg || '请求失败,请稍后重试',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getDeptTree } from '@/api/system/dept';
|
import { getDeptTree, getPlatformCompanySelect } from '@/api/system/dept';
|
||||||
import { ElCascader } from 'element-plus';
|
import { ElCascader } from 'element-plus';
|
||||||
import { h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
@@ -12,6 +12,12 @@ import { h } from 'vue';
|
|||||||
* 1. 混入本 mixin:mixins: [organizationSearch]
|
* 1. 混入本 mixin:mixins: [organizationSearch]
|
||||||
* 2. option 中「所属组织」列加上 searchslot: true(prop 为 organizationName 或 deptName 均可)
|
* 2. option 中「所属组织」列加上 searchslot: true(prop 为 organizationName 或 deptName 均可)
|
||||||
* 3. 在 created / 初始化时调用 this.loadOrganizationOptions()
|
* 3. 在 created / 初始化时调用 this.loadOrganizationOptions()
|
||||||
|
* 4. 需要「未分配组织」筛选项的页面在 data 里置 enableUnassignedOrgFilter: true;
|
||||||
|
* 该项只追加进搜索树 organizationSearchTreeOptions,表单级联 organizationTreeOptions 不含哨兵
|
||||||
|
* 5. 表单「所属组织」只允许选平台公司的页面(运力管理)在 data 里置
|
||||||
|
* restrictFormOrgToPlatformCompany: true,表单级联样式改用
|
||||||
|
* buildFormOrganizationTree(...) 的结果,并在打开表单时把回显的组织名写进
|
||||||
|
* formOrganizationLegacyName;只影响表单,搜索栏仍是全量组织
|
||||||
*
|
*
|
||||||
* 说明:
|
* 说明:
|
||||||
* - 自动识别 organizationName / deptName 两种 prop,并挂载 column.renderSearch
|
* - 自动识别 organizationName / deptName 两种 prop,并挂载 column.renderSearch
|
||||||
@@ -26,6 +32,17 @@ import { h } from 'vue';
|
|||||||
*/
|
*/
|
||||||
const ORG_PROPS = ['organizationName', 'deptName'];
|
const ORG_PROPS = ['organizationName', 'deptName'];
|
||||||
|
|
||||||
|
// 「未分配组织」筛选项的哨兵值:不是真实组织名,选中后提交给后端的就是这串字面量。
|
||||||
|
// 后端 TransportBusiConstant.UNASSIGNED_ORG_FILTER、DriverMapper.xml / TransportVehicleMapper.xml
|
||||||
|
// 的 organizationName 分支以及司机、车辆导出查询都按它改判为 organization_name = '';
|
||||||
|
// 后端换成空串会让整段组织条件不生效,筛选静默失效。前端与后端这几处必须同步修改。
|
||||||
|
const UNASSIGNED_ORG_FILTER = '__UNASSIGNED_ORG__';
|
||||||
|
|
||||||
|
// 表单「所属组织」限定只能选平台公司时,存量记录里的旧组织名在组织树里已经找不到
|
||||||
|
// (节点被删或改名),用这个 id 补一个只读节点,否则编辑老数据时所属组织显示为空、
|
||||||
|
// 保存即把原值丢掉。
|
||||||
|
const FORM_LEGACY_ORG_ID = '__LEGACY_ORG__';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -34,12 +51,32 @@ export default {
|
|||||||
organizationTreeOptions: [],
|
organizationTreeOptions: [],
|
||||||
organizationTreeFlatOptions: [],
|
organizationTreeFlatOptions: [],
|
||||||
organizationLoading: false,
|
organizationLoading: false,
|
||||||
|
// 组织筛选是否追加「未分配组织」一项;页面在 data 里覆盖为 true 才生效
|
||||||
|
enableUnassignedOrgFilter: false,
|
||||||
|
// 表单「所属组织」是否只允许选平台公司;页面在 data 里覆盖为 true 才生效
|
||||||
|
restrictFormOrgToPlatformCompany: false,
|
||||||
|
// 平台公司部门 id(字符串),loadOrganizationOptions 时一并拉取
|
||||||
|
platformCompanyOrgIds: [],
|
||||||
|
// 表单当前回显的组织名,树里没有同名节点时用它补一个只读选项
|
||||||
|
formOrganizationLegacyName: '',
|
||||||
|
// 进行中的组织数据请求,并发调用共用(不是响应式状态,只做去重)
|
||||||
|
organizationOptionsPromise: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
// 所属组织级联配置:checkStrictly 允许选中任意层级,不必选到末级
|
// 搜索栏级联的选项:开关打开时在真实组织最前面追加「未分配组织」。
|
||||||
|
// 不能直接改 organizationTreeOptions——司机/车辆页的编辑表单也用这棵树选组织。
|
||||||
|
organizationSearchTreeOptions() {
|
||||||
|
return this.enableUnassignedOrgFilter
|
||||||
|
? [this.unassignedOrgOption(), ...this.organizationTreeOptions]
|
||||||
|
: this.organizationTreeOptions;
|
||||||
|
},
|
||||||
|
// 所属组织级联配置:checkStrictly 允许选中任意层级,不必选到末级。
|
||||||
|
// 限定只能选平台公司时用 disabled 函数只放开平台公司:非平台公司的非末级节点
|
||||||
|
// 在 checkStrictly 下仍可展开(el-cascader 的 expandable 判断),末级节点点击无效,
|
||||||
|
// 两者都选不中。disabled 在节点渲染时求值,平台公司 id 到手后节点会自行重算。
|
||||||
organizationCascaderProps() {
|
organizationCascaderProps() {
|
||||||
return {
|
const props = {
|
||||||
value: 'id',
|
value: 'id',
|
||||||
label: 'label',
|
label: 'label',
|
||||||
children: 'children',
|
children: 'children',
|
||||||
@@ -47,21 +84,31 @@ export default {
|
|||||||
checkStrictly: true,
|
checkStrictly: true,
|
||||||
expandTrigger: 'click',
|
expandTrigger: 'click',
|
||||||
};
|
};
|
||||||
|
if (this.restrictFormOrgToPlatformCompany) {
|
||||||
|
props.disabled = data => this.platformCompanyOrgDisabled(data);
|
||||||
|
}
|
||||||
|
return props;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
loadOrganizationOptions() {
|
loadOrganizationOptions() {
|
||||||
if (this.organizationLoading) return;
|
// 并发调用共用同一次请求,返回的 Promise 在数据就绪后才 resolve
|
||||||
|
if (this.organizationOptionsPromise) return this.organizationOptionsPromise;
|
||||||
this.organizationLoading = true;
|
this.organizationLoading = true;
|
||||||
const tenantId = this.userInfo?.tenantId;
|
const tenantId = this.userInfo?.tenantId;
|
||||||
getDeptTree(tenantId)
|
// 平台公司下拉失败不能拖垮组织树,单独兜住,失败时保持上一次的可选范围
|
||||||
.then(res => {
|
const platformCompanyRequest = this.restrictFormOrgToPlatformCompany
|
||||||
|
? getPlatformCompanySelect().catch(() => null)
|
||||||
|
: Promise.resolve(null);
|
||||||
|
this.organizationOptionsPromise = Promise.all([getDeptTree(tenantId), platformCompanyRequest])
|
||||||
|
.then(([res, platformRes]) => {
|
||||||
|
this.applyPlatformCompanyOptions(platformRes);
|
||||||
const source = res.data?.data || res.data || [];
|
const source = res.data?.data || res.data || [];
|
||||||
const tree = this.excludeExternalOrganization
|
const tree = this.excludeExternalOrganization
|
||||||
? this.excludeExternalOrganization(source)
|
? this.excludeExternalOrganization(source)
|
||||||
: source;
|
: source;
|
||||||
this.organizationTreeOptions = this.normalizeOrgTree(tree);
|
this.organizationTreeOptions = this.normalizeOrgTree(tree);
|
||||||
this.organizationTreeFlatOptions = this.flattenOrgTree(this.organizationTreeOptions);
|
this.organizationTreeFlatOptions = this.flattenOrgTree(this.organizationSearchTreeOptions);
|
||||||
const option = this.tableOption || this.option;
|
const option = this.tableOption || this.option;
|
||||||
if (!option) return;
|
if (!option) return;
|
||||||
ORG_PROPS.forEach(prop => {
|
ORG_PROPS.forEach(prop => {
|
||||||
@@ -73,7 +120,21 @@ export default {
|
|||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.organizationLoading = false;
|
this.organizationLoading = false;
|
||||||
|
this.organizationOptionsPromise = null;
|
||||||
});
|
});
|
||||||
|
return this.organizationOptionsPromise;
|
||||||
|
},
|
||||||
|
// 组织树与平台公司列表就绪后执行回调;已加载过则立即执行
|
||||||
|
whenOrganizationOptionsReady(callback) {
|
||||||
|
const pending = this.organizationTreeFlatOptions.length
|
||||||
|
? Promise.resolve()
|
||||||
|
: this.loadOrganizationOptions();
|
||||||
|
return Promise.resolve(pending).then(callback, () => callback());
|
||||||
|
},
|
||||||
|
applyPlatformCompanyOptions(res) {
|
||||||
|
if (!res) return;
|
||||||
|
const list = res.data?.data || res.data || [];
|
||||||
|
this.platformCompanyOrgIds = (Array.isArray(list) ? list : []).map(item => String(item.id));
|
||||||
},
|
},
|
||||||
// 默认排除「外部组织」节点;页面可覆盖
|
// 默认排除「外部组织」节点;页面可覆盖
|
||||||
excludeExternalOrganization(tree = []) {
|
excludeExternalOrganization(tree = []) {
|
||||||
@@ -100,12 +161,20 @@ export default {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// 哨兵节点的 id 与 rawLabel 都取哨兵值,resolveOrgName 取到的仍是哨兵而不是某个真实组织名
|
||||||
|
unassignedOrgOption() {
|
||||||
|
return { id: UNASSIGNED_ORG_FILTER, label: '未分配组织', rawLabel: UNASSIGNED_ORG_FILTER };
|
||||||
|
},
|
||||||
flattenOrgTree(tree = []) {
|
flattenOrgTree(tree = []) {
|
||||||
return (tree || []).flatMap(item => [
|
return (tree || []).flatMap(item => [
|
||||||
{ id: String(item.id), label: item.label, rawLabel: item.rawLabel },
|
{ id: String(item.id), label: item.label, rawLabel: item.rawLabel },
|
||||||
...this.flattenOrgTree(item.children || []),
|
...this.flattenOrgTree(item.children || []),
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
// 组织列渲染用:空串或纯空白即「未分配组织」(组织列 NOT NULL,无组织存空串)
|
||||||
|
isBlankOrganizationName(value) {
|
||||||
|
return String(value ?? '').trim() === '';
|
||||||
|
},
|
||||||
// 兼容两种入参:级联路径数组(取末级)或单个部门 id
|
// 兼容两种入参:级联路径数组(取末级)或单个部门 id
|
||||||
findOrgById(id) {
|
findOrgById(id) {
|
||||||
const value = Array.isArray(id) ? id.at(-1) : id;
|
const value = Array.isArray(id) ? id.at(-1) : id;
|
||||||
@@ -118,7 +187,9 @@ export default {
|
|||||||
for (const node of tree || []) {
|
for (const node of tree || []) {
|
||||||
const path = [...parents, String(node.id)];
|
const path = [...parents, String(node.id)];
|
||||||
if (String(node.id) === String(target)) return path;
|
if (String(node.id) === String(target)) return path;
|
||||||
const matched = this.findOrgPath(target, node.children, path);
|
// 必须显式传 node.children || []:叶节点的 children 是 undefined,
|
||||||
|
// 传 undefined 会触发默认参数重新拿到整棵树,逐层重复扫描直到爆栈
|
||||||
|
const matched = this.findOrgPath(target, node.children || [], path);
|
||||||
if (matched) return matched;
|
if (matched) return matched;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -127,6 +198,52 @@ export default {
|
|||||||
findOrgName(id) {
|
findOrgName(id) {
|
||||||
return this.findOrgById(id)?.rawLabel || '';
|
return this.findOrgById(id)?.rawLabel || '';
|
||||||
},
|
},
|
||||||
|
// 级联节点的 disabled 判定:只有平台公司可选。页面自建 props 时也复用它
|
||||||
|
platformCompanyOrgDisabled(data) {
|
||||||
|
return !this.platformCompanyOrgIds.includes(String(data?.id ?? ''));
|
||||||
|
},
|
||||||
|
// 组织名对应的节点是否为平台公司;名称在树里不存在时按「不是」处理
|
||||||
|
isPlatformCompanyOrgName(name) {
|
||||||
|
const value = String(name ?? '').trim();
|
||||||
|
if (!value) return false;
|
||||||
|
const node = this.organizationTreeFlatOptions.find(item => item.rawLabel === value);
|
||||||
|
return !!node && this.platformCompanyOrgIds.includes(String(node.id));
|
||||||
|
},
|
||||||
|
// 新增表单的默认组织:只有落在平台公司上才预填,否则留空(不能让用户从默认值
|
||||||
|
// 直接带出一个选不中的组织名)
|
||||||
|
defaultFormOrganizationName(name) {
|
||||||
|
return this.isPlatformCompanyOrgName(name) ? String(name).trim() : '';
|
||||||
|
},
|
||||||
|
// 表单级联的选项树:限定平台公司时,把回显的原组织名补成一个只读节点,
|
||||||
|
// 否则存量记录的组织在树里找不到,编辑时显示为空、保存即丢原值
|
||||||
|
buildFormOrganizationTree(tree = this.organizationTreeOptions) {
|
||||||
|
const source = tree || [];
|
||||||
|
if (!this.restrictFormOrgToPlatformCompany) return source;
|
||||||
|
const name = String(this.formOrganizationLegacyName || '').trim();
|
||||||
|
if (!name) return source;
|
||||||
|
if (this.organizationTreeFlatOptions.some(item => item.rawLabel === name)) return source;
|
||||||
|
return [...source, { id: FORM_LEGACY_ORG_ID, label: name, rawLabel: name }];
|
||||||
|
},
|
||||||
|
// 表单级联回显用的路径:树里有该组织就用真实路径,否则落到原组织兜底节点
|
||||||
|
resolveFormOrgPath(name) {
|
||||||
|
const path = this.resolveOrgPath(name);
|
||||||
|
if (path.length) return path;
|
||||||
|
const value = String(name ?? '').trim();
|
||||||
|
if (!value) return [];
|
||||||
|
return value === String(this.formOrganizationLegacyName || '').trim()
|
||||||
|
? [FORM_LEGACY_ORG_ID]
|
||||||
|
: [];
|
||||||
|
},
|
||||||
|
// 记录表单当前回显的组织名:能匹配真实节点(或已清空)就不需要兜底节点,
|
||||||
|
// 否则记下来,由 buildFormOrganizationTree 补成只读选项
|
||||||
|
syncFormOrganizationLegacy(name) {
|
||||||
|
const value = String(name ?? '').trim();
|
||||||
|
if (!value || this.organizationTreeFlatOptions.some(item => item.rawLabel === value)) {
|
||||||
|
this.formOrganizationLegacyName = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.formOrganizationLegacyName = value;
|
||||||
|
},
|
||||||
// 组织名称 → 级联路径(表单回显用;部门树异步加载完成后会自动重算)
|
// 组织名称 → 级联路径(表单回显用;部门树异步加载完成后会自动重算)
|
||||||
resolveOrgPath(name) {
|
resolveOrgPath(name) {
|
||||||
const value = String(name ?? '').trim();
|
const value = String(name ?? '').trim();
|
||||||
@@ -139,7 +256,13 @@ export default {
|
|||||||
const value = Array.isArray(path)
|
const value = Array.isArray(path)
|
||||||
? path.filter(item => item !== undefined && item !== null && item !== '')
|
? path.filter(item => item !== undefined && item !== null && item !== '')
|
||||||
: [];
|
: [];
|
||||||
return value.length ? this.findOrgById(value)?.rawLabel || '' : '';
|
if (!value.length) return '';
|
||||||
|
const node = this.findOrgById(value);
|
||||||
|
if (node) return node.rawLabel || '';
|
||||||
|
// 原组织兜底节点不在扁平表里,直接取它代表的历史名称
|
||||||
|
return String(value[value.length - 1]) === FORM_LEGACY_ORG_ID
|
||||||
|
? String(this.formOrganizationLegacyName || '').trim()
|
||||||
|
: '';
|
||||||
},
|
},
|
||||||
// 搜索提交前把级联路径数组就地转成组织名称(后端按名称过滤)
|
// 搜索提交前把级联路径数组就地转成组织名称(后端按名称过滤)
|
||||||
normalizeOrganizationSearch(params, prop = 'organizationName') {
|
normalizeOrganizationSearch(params, prop = 'organizationName') {
|
||||||
@@ -155,7 +278,7 @@ export default {
|
|||||||
// 级联单选:modelValue 必须是 id 路径数组,否则控件内部状态会错乱导致无法再次选中
|
// 级联单选:modelValue 必须是 id 路径数组,否则控件内部状态会错乱导致无法再次选中
|
||||||
if (scope.row) scope.row[prop] = Array.isArray(value) ? value : [];
|
if (scope.row) scope.row[prop] = Array.isArray(value) ? value : [];
|
||||||
},
|
},
|
||||||
options: this.organizationTreeOptions,
|
options: this.organizationSearchTreeOptions,
|
||||||
props: {
|
props: {
|
||||||
label: 'label',
|
label: 'label',
|
||||||
value: 'id',
|
value: 'id',
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export const createOption = () => ({
|
|||||||
delBtn: false,
|
delBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
|
menuWidth: 320,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export const transportTypeOptions = [
|
export const transportTypeOptions = [
|
||||||
{ label: '公路运输', value: '公路运输' },
|
{ label: '公路运输', value: '公路运输' },
|
||||||
{ label: '铁路运输', value: '铁路运输' },
|
{ label: '铁路运输', value: '铁路运输' },
|
||||||
{ label: '水路运输', value: '水路运输' },
|
{ label: '水路运输', value: '水路运输' },
|
||||||
@@ -42,6 +42,7 @@ export const waybillStatusOptions = [
|
|||||||
{ label: '草稿', value: 'draft' },
|
{ label: '草稿', value: 'draft' },
|
||||||
{ label: '待执行', value: 'pending' },
|
{ label: '待执行', value: 'pending' },
|
||||||
{ label: '进行中', value: 'running' },
|
{ label: '进行中', value: 'running' },
|
||||||
|
{ label: '待回单确认', value: 'pending_return_confirm' },
|
||||||
{ label: '已完成', value: 'completed' },
|
{ label: '已完成', value: 'completed' },
|
||||||
{ label: '已取消', value: 'cancelled' },
|
{ label: '已取消', value: 'cancelled' },
|
||||||
];
|
];
|
||||||
@@ -143,6 +144,17 @@ export const contractArchiveStatusOptions = [
|
|||||||
{ label: '已归档', value: '已归档' },
|
{ label: '已归档', value: '已归档' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const hcsSyncStatusOptions = [
|
||||||
|
{ label: '待推送', value: 'unsynced' },
|
||||||
|
{ label: '已推送', value: 'synced' },
|
||||||
|
{ label: '推送失败', value: 'failed' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const yesNoOptions = [
|
||||||
|
{ label: '是', value: true },
|
||||||
|
{ label: '否', value: false },
|
||||||
|
];
|
||||||
|
|
||||||
export const nodeOptions = [
|
export const nodeOptions = [
|
||||||
{ label: '接单', value: '接单' },
|
{ label: '接单', value: '接单' },
|
||||||
{ label: '到场', value: '到场' },
|
{ label: '到场', value: '到场' },
|
||||||
|
|||||||
@@ -0,0 +1,221 @@
|
|||||||
|
import {
|
||||||
|
approvalStatusOptions,
|
||||||
|
contractCategoryOptions,
|
||||||
|
createCrudOption,
|
||||||
|
hcsSyncStatusOptions,
|
||||||
|
signTypeOptions,
|
||||||
|
} from './common';
|
||||||
|
|
||||||
|
const listDicFormatter = res => {
|
||||||
|
const data = res?.data || res;
|
||||||
|
if (Array.isArray(data)) return data;
|
||||||
|
if (Array.isArray(data?.records)) return data.records;
|
||||||
|
if (Array.isArray(data?.data)) return data.data;
|
||||||
|
if (Array.isArray(data?.data?.records)) return data.data.records;
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const projectNameDicFormatter = res => {
|
||||||
|
const list = listDicFormatter(res);
|
||||||
|
return list.filter(item => item && item.projectName && String(item.projectName).trim());
|
||||||
|
};
|
||||||
|
|
||||||
|
export const changeTypeOptions = [
|
||||||
|
{ label: '合同信息变更', value: '合同信息变更' },
|
||||||
|
{ label: '结算规则变更', value: '结算规则变更' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
title: '合同变更',
|
||||||
|
permission: 'contract_change',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
statusTextProp: 'approvalStatusName',
|
||||||
|
deleteStatus: ['draft', 'withdrawn', 'rejected'],
|
||||||
|
editStatus: ['draft', 'withdrawn', 'rejected'],
|
||||||
|
viewStatus: ['approved'],
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
action: 'submitApproval',
|
||||||
|
label: '提交',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['draft'],
|
||||||
|
permission: 'contract_change_submit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'withdraw',
|
||||||
|
label: '撤回',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'contract_change_withdraw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'mkAudit',
|
||||||
|
label: '流程',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing', 'rejected', 'approved'],
|
||||||
|
permission: 'contract_change_approve',
|
||||||
|
mkOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'approve',
|
||||||
|
label: '通过',
|
||||||
|
type: 'success',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'contract_change_approve',
|
||||||
|
localOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'reject',
|
||||||
|
label: '驳回',
|
||||||
|
type: 'warning',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'contract_change_reject',
|
||||||
|
localOnly: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const option = createCrudOption([
|
||||||
|
{
|
||||||
|
label: '合同编号',
|
||||||
|
prop: 'contractNo',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 20,
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '合同名称',
|
||||||
|
prop: 'contractName',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 30,
|
||||||
|
minWidth: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属项目',
|
||||||
|
prop: 'projectName',
|
||||||
|
search: true,
|
||||||
|
searchType: 'select',
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 60,
|
||||||
|
dicUrl: '/blade-transport/project-apply/list?current=1&size=9999&contractSelectable=true',
|
||||||
|
dicFormatter: projectNameDicFormatter,
|
||||||
|
props: {
|
||||||
|
label: 'projectName',
|
||||||
|
value: 'projectName',
|
||||||
|
},
|
||||||
|
filterable: true,
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属组织',
|
||||||
|
prop: 'organizationName',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 10,
|
||||||
|
minWidth: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '合同类别',
|
||||||
|
prop: 'contractCategory',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 70,
|
||||||
|
dicData: contractCategoryOptions,
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '签约类型',
|
||||||
|
prop: 'signType',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 50,
|
||||||
|
dicData: signTypeOptions,
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '甲方',
|
||||||
|
prop: 'partyA',
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '乙方',
|
||||||
|
prop: 'partyB',
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '开始日期',
|
||||||
|
prop: 'startDate',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '结束日期',
|
||||||
|
prop: 'endDate',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '临时效力起',
|
||||||
|
prop: 'temporaryStartDate',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '临时效力止',
|
||||||
|
prop: 'temporaryEndDate',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '经办人',
|
||||||
|
prop: 'handlerUserName',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '创建时间',
|
||||||
|
prop: 'createTime',
|
||||||
|
type: 'datetime',
|
||||||
|
minWidth: 170,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '审核状态',
|
||||||
|
prop: 'approvalStatus',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 40,
|
||||||
|
dicData: approvalStatusOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '当前节点',
|
||||||
|
prop: 'currentNode',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '当前处理人',
|
||||||
|
prop: 'currentProcessor',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '同步状态',
|
||||||
|
prop: 'syncStatus',
|
||||||
|
type: 'select',
|
||||||
|
dicData: hcsSyncStatusOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
},
|
||||||
|
]);
|
||||||
@@ -7,9 +7,11 @@ import {
|
|||||||
createCrudOption,
|
createCrudOption,
|
||||||
effectiveTypeOptions,
|
effectiveTypeOptions,
|
||||||
nonNegativeRule,
|
nonNegativeRule,
|
||||||
|
hcsSyncStatusOptions,
|
||||||
selectRule,
|
selectRule,
|
||||||
signTypeOptions,
|
signTypeOptions,
|
||||||
textRule,
|
textRule,
|
||||||
|
yesNoOptions,
|
||||||
} from './common';
|
} from './common';
|
||||||
|
|
||||||
const contractSettlementModeOptions = [
|
const contractSettlementModeOptions = [
|
||||||
@@ -63,10 +65,12 @@ export const config = {
|
|||||||
['contractName', '合同名称'],
|
['contractName', '合同名称'],
|
||||||
['projectName', '所属项目'],
|
['projectName', '所属项目'],
|
||||||
['organizationName', '合同负责部门'],
|
['organizationName', '合同负责部门'],
|
||||||
|
['platformCompanyName', '平台公司'],
|
||||||
['contractCategory', '合同类别'],
|
['contractCategory', '合同类别'],
|
||||||
['signType', '签约类型'],
|
['signType', '签约类型'],
|
||||||
['partyA', '甲方'],
|
['partyA', '甲方'],
|
||||||
['partyB', '乙方'],
|
['partyB', '乙方'],
|
||||||
|
['partyC', '丙方'],
|
||||||
['handlerUserName', '经办人'],
|
['handlerUserName', '经办人'],
|
||||||
['signDate', '签订日期'],
|
['signDate', '签订日期'],
|
||||||
['applyDate', '申请日期'],
|
['applyDate', '申请日期'],
|
||||||
@@ -245,15 +249,26 @@ export const option = createCrudOption([
|
|||||||
hide: true,
|
hide: true,
|
||||||
labelWidth: 0,
|
labelWidth: 0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '客商',
|
||||||
|
prop: 'partyName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 14,
|
||||||
|
searchPlaceholder: '请输入甲/乙方名称',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '合同编号',
|
label: '合同编号',
|
||||||
prop: 'contractNo',
|
prop: 'contractNo',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 6,
|
searchOrder: 8,
|
||||||
searchPlaceholder: '请输入',
|
searchPlaceholder: '请输入',
|
||||||
order: 185,
|
order: 185,
|
||||||
disabled: true,
|
maxlength: 100,
|
||||||
placeholder: '不填写,则系统自动生成',
|
placeholder: '不填写则按部门规则自动生成',
|
||||||
minWidth: 200,
|
minWidth: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -262,7 +277,7 @@ export const option = createCrudOption([
|
|||||||
align: 'left',
|
align: 'left',
|
||||||
headerAlign: 'left',
|
headerAlign: 'left',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 7,
|
searchOrder: 1,
|
||||||
searchPlaceholder: '请输入',
|
searchPlaceholder: '请输入',
|
||||||
order: 180,
|
order: 180,
|
||||||
slot: true,
|
slot: true,
|
||||||
@@ -274,7 +289,7 @@ export const option = createCrudOption([
|
|||||||
label: '所属项目',
|
label: '所属项目',
|
||||||
prop: 'projectName',
|
prop: 'projectName',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 8,
|
searchOrder: 11,
|
||||||
searchType: 'select',
|
searchType: 'select',
|
||||||
searchPlaceholder: '请选择',
|
searchPlaceholder: '请选择',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
@@ -309,12 +324,19 @@ export const option = createCrudOption([
|
|||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
rules: selectRule('合同负责部门'),
|
rules: selectRule('合同负责部门'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '平台公司',
|
||||||
|
prop: 'platformCompanyName',
|
||||||
|
minWidth: 180,
|
||||||
|
order: 115,
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '合同类别',
|
label: '合同类别',
|
||||||
prop: 'contractCategory',
|
prop: 'contractCategory',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 9,
|
searchOrder: 12,
|
||||||
searchPlaceholder: '请选择',
|
searchPlaceholder: '请选择',
|
||||||
order: 170,
|
order: 170,
|
||||||
dicData: contractCategoryOptions,
|
dicData: contractCategoryOptions,
|
||||||
@@ -326,7 +348,7 @@ export const option = createCrudOption([
|
|||||||
prop: 'signType',
|
prop: 'signType',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 10,
|
searchOrder: 13,
|
||||||
searchPlaceholder: '请选择',
|
searchPlaceholder: '请选择',
|
||||||
span: 8,
|
span: 8,
|
||||||
order: 190,
|
order: 190,
|
||||||
@@ -335,11 +357,11 @@ export const option = createCrudOption([
|
|||||||
rules: selectRule('签约类型'),
|
rules: selectRule('签约类型'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '生效类型',
|
label: '合同状态',
|
||||||
prop: 'effectiveType',
|
prop: 'effectiveType',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 5,
|
searchOrder: 6,
|
||||||
searchPlaceholder: '请选择',
|
searchPlaceholder: '请选择',
|
||||||
dicData: effectiveTypeOptions,
|
dicData: effectiveTypeOptions,
|
||||||
hide: true,
|
hide: true,
|
||||||
@@ -348,24 +370,23 @@ export const option = createCrudOption([
|
|||||||
{
|
{
|
||||||
label: '甲方',
|
label: '甲方',
|
||||||
prop: 'partyA',
|
prop: 'partyA',
|
||||||
type: 'select',
|
|
||||||
formslot: true,
|
|
||||||
disabled: true,
|
|
||||||
order: 160,
|
|
||||||
filterable: true,
|
|
||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
rules: selectRule('甲方'),
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '乙方',
|
label: '乙方',
|
||||||
prop: 'partyB',
|
prop: 'partyB',
|
||||||
type: 'select',
|
|
||||||
formslot: true,
|
|
||||||
disabled: true,
|
|
||||||
order: 150,
|
|
||||||
filterable: true,
|
|
||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
rules: selectRule('乙方'),
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '丙方',
|
||||||
|
prop: 'partyC',
|
||||||
|
minWidth: 160,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '合同期限',
|
label: '合同期限',
|
||||||
@@ -606,6 +627,59 @@ export const option = createCrudOption([
|
|||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '合规状态',
|
||||||
|
prop: 'hcsSyncStatus',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 7,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
slot: true,
|
||||||
|
dicData: hcsSyncStatusOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '客商风险',
|
||||||
|
prop: 'customerRisk',
|
||||||
|
slot: true,
|
||||||
|
order: 189,
|
||||||
|
minWidth: 150,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '金蝶合同ID',
|
||||||
|
prop: 'kingdeeId',
|
||||||
|
minWidth: 130,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否同步金蝶',
|
||||||
|
prop: 'kingdeeSynced',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 9,
|
||||||
|
dicData: yesNoOptions,
|
||||||
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否同步合规',
|
||||||
|
prop: 'hcsSynced',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 10,
|
||||||
|
dicData: yesNoOptions,
|
||||||
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '当前节点',
|
label: '当前节点',
|
||||||
prop: 'currentNode',
|
prop: 'currentNode',
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
businessModeOptions,
|
businessModeOptions,
|
||||||
businessTypeOptions,
|
businessTypeOptions,
|
||||||
createCrudOption,
|
createCrudOption,
|
||||||
|
hcsSyncStatusOptions,
|
||||||
nonNegativeRule,
|
nonNegativeRule,
|
||||||
projectApprovalStatusOptions,
|
projectApprovalStatusOptions,
|
||||||
projectSourceOptions,
|
projectSourceOptions,
|
||||||
@@ -10,6 +11,7 @@ import {
|
|||||||
selectRule,
|
selectRule,
|
||||||
settlementModeOptions,
|
settlementModeOptions,
|
||||||
textRule,
|
textRule,
|
||||||
|
yesNoOptions,
|
||||||
} from './common';
|
} from './common';
|
||||||
|
|
||||||
const projectEffectiveTypeOptions = [
|
const projectEffectiveTypeOptions = [
|
||||||
@@ -97,7 +99,8 @@ export const config = {
|
|||||||
action: 'startChange',
|
action: 'startChange',
|
||||||
label: '变更',
|
label: '变更',
|
||||||
statusProp: 'approvalStatus',
|
statusProp: 'approvalStatus',
|
||||||
status: ['approved'],
|
// 立项通过、变更通过后均可再次发起变更
|
||||||
|
status: ['approved', 'change_approved'],
|
||||||
permission: 'project_apply_change',
|
permission: 'project_apply_change',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -405,6 +408,57 @@ export const option = createCrudOption([
|
|||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '合规状态',
|
||||||
|
prop: 'hcsSyncStatus',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 1,
|
||||||
|
slot: true,
|
||||||
|
dicData: hcsSyncStatusOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '金蝶项目ID',
|
||||||
|
prop: 'kingdeeId',
|
||||||
|
minWidth: 130,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '金蝶项目编号',
|
||||||
|
prop: 'kingdeeNumber',
|
||||||
|
minWidth: 130,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否同步金蝶',
|
||||||
|
prop: 'kingdeeSynced',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 2,
|
||||||
|
dicData: yesNoOptions,
|
||||||
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否同步合规',
|
||||||
|
prop: 'hcsSynced',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 3,
|
||||||
|
dicData: yesNoOptions,
|
||||||
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '生效类型',
|
label: '生效类型',
|
||||||
prop: 'effectiveType',
|
prop: 'effectiveType',
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
import {
|
||||||
|
approvalStatusOptions,
|
||||||
|
createCrudOption,
|
||||||
|
hcsSyncStatusOptions,
|
||||||
|
projectTypeOptions,
|
||||||
|
} from './common';
|
||||||
|
|
||||||
|
export const changeTypeOptions = [
|
||||||
|
{ label: '项目变更', value: '项目变更' },
|
||||||
|
{ label: '项目备案调整', value: '项目备案调整' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
title: '项目变更',
|
||||||
|
permission: 'project_change',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
statusTextProp: 'approvalStatusName',
|
||||||
|
deleteStatus: ['draft', 'withdrawn', 'rejected'],
|
||||||
|
editStatus: ['draft', 'withdrawn', 'rejected'],
|
||||||
|
viewStatus: ['approved', 'rejected', 'withdrawn'],
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
action: 'submitApproval',
|
||||||
|
label: '提交',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['draft'],
|
||||||
|
permission: 'project_change_submit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'withdraw',
|
||||||
|
label: '撤回',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'project_change_withdraw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'mkAudit',
|
||||||
|
label: '流程',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'project_change_approve',
|
||||||
|
mkOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'approve',
|
||||||
|
label: '通过',
|
||||||
|
type: 'success',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'project_change_approve',
|
||||||
|
localOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'reject',
|
||||||
|
label: '驳回',
|
||||||
|
type: 'warning',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'project_change_reject',
|
||||||
|
localOnly: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const option = createCrudOption([
|
||||||
|
{
|
||||||
|
label: '项目编号',
|
||||||
|
prop: 'projectCode',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 70,
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目名称',
|
||||||
|
prop: 'projectName',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 60,
|
||||||
|
minWidth: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '变更类型',
|
||||||
|
prop: 'changeType',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 10,
|
||||||
|
dicData: changeTypeOptions,
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目类型',
|
||||||
|
prop: 'projectType',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 20,
|
||||||
|
dicData: projectTypeOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '客户名称',
|
||||||
|
prop: 'customerNames',
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '下游承运商',
|
||||||
|
prop: 'carrierNames',
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '承办部门',
|
||||||
|
prop: 'undertakeDeptName',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 50,
|
||||||
|
minWidth: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目负责人',
|
||||||
|
prop: 'principalUserName',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 40,
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '审批状态',
|
||||||
|
prop: 'approvalStatus',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 30,
|
||||||
|
dicData: approvalStatusOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '当前节点',
|
||||||
|
prop: 'currentNode',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '当前处理人',
|
||||||
|
prop: 'currentProcessor',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '审核通过时间',
|
||||||
|
prop: 'approvedTime',
|
||||||
|
type: 'datetime',
|
||||||
|
minWidth: 170,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '同步状态',
|
||||||
|
prop: 'syncStatus',
|
||||||
|
type: 'select',
|
||||||
|
dicData: hcsSyncStatusOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
},
|
||||||
|
]);
|
||||||
@@ -124,7 +124,8 @@ const formatGoodsInfo = row => {
|
|||||||
const text = Object.entries(groups)
|
const text = Object.entries(groups)
|
||||||
.map(([unit, group]) => {
|
.map(([unit, group]) => {
|
||||||
const quantity = formatGoodsQuantity(group.quantity);
|
const quantity = formatGoodsQuantity(group.quantity);
|
||||||
return `${group.typeName}等${group.count}种货物 | ${quantity}${unit ? ` ${unit}` : ''}`;
|
const typeName = group.count > 1 ? `${group.typeName}等${group.count}种货物` : group.typeName;
|
||||||
|
return `${typeName} | ${quantity}${unit ? ` ${unit}` : ''}`;
|
||||||
})
|
})
|
||||||
.join('; ');
|
.join('; ');
|
||||||
|
|
||||||
@@ -207,6 +208,9 @@ export const config = {
|
|||||||
transportPlanImportTitle: '导入运输计划',
|
transportPlanImportTitle: '导入运输计划',
|
||||||
transportPlanTemplateUrl: '/blade-transport/transport-plan/export-template',
|
transportPlanTemplateUrl: '/blade-transport/transport-plan/export-template',
|
||||||
attachmentTitle: '附件',
|
attachmentTitle: '附件',
|
||||||
|
defaultForm: {
|
||||||
|
transportType: 'road',
|
||||||
|
},
|
||||||
searchRangeMap: {
|
searchRangeMap: {
|
||||||
planStartDateRange: ['planStartDateStart', 'planStartDateEnd'],
|
planStartDateRange: ['planStartDateStart', 'planStartDateEnd'],
|
||||||
createTimeRange: ['createTimeStart', 'createTimeEnd', '00:00:00', '23:59:59'],
|
createTimeRange: ['createTimeStart', 'createTimeEnd', '00:00:00', '23:59:59'],
|
||||||
|
|||||||
@@ -471,7 +471,7 @@ export const config = {
|
|||||||
endDateRange: ['endDateStart', 'endDateEnd'],
|
endDateRange: ['endDateStart', 'endDateEnd'],
|
||||||
createTimeRange: ['createTimeStart', 'createTimeEnd'],
|
createTimeRange: ['createTimeStart', 'createTimeEnd'],
|
||||||
},
|
},
|
||||||
actions: ['copy', 'cancel', 'reassign', 'complete', 'batchComplete'],
|
actions: ['copy', 'cancel', 'reassign', 'complete', 'batchComplete', 'confirmReturn'],
|
||||||
detailButton: true,
|
detailButton: true,
|
||||||
statusProp: 'businessStatus',
|
statusProp: 'businessStatus',
|
||||||
statusTextProp: 'businessStatusName',
|
statusTextProp: 'businessStatusName',
|
||||||
@@ -483,6 +483,8 @@ export const config = {
|
|||||||
row.requireAccept === true ||
|
row.requireAccept === true ||
|
||||||
row.requireAccept === 1 ||
|
row.requireAccept === 1 ||
|
||||||
requiresDriverAcceptConfirmation(row);
|
requiresDriverAcceptConfirmation(row);
|
||||||
|
// 待回单确认由末位打卡产生,司机必然已接单
|
||||||
|
if (status === 'pending_return_confirm') return '待回单确认';
|
||||||
// 需司机接单且尚未接单 → 待执行(含库中仍为 running 的历史数据展示校正)
|
// 需司机接单且尚未接单 → 待执行(含库中仍为 running 的历史数据展示校正)
|
||||||
if (needAccept && !hasDriverAcceptRecord(row) && !terminalStatuses.includes(status)) {
|
if (needAccept && !hasDriverAcceptRecord(row) && !terminalStatuses.includes(status)) {
|
||||||
return '待执行';
|
return '待执行';
|
||||||
@@ -504,7 +506,7 @@ export const config = {
|
|||||||
return !isDriverRejectedWaybill(row);
|
return !isDriverRejectedWaybill(row);
|
||||||
},
|
},
|
||||||
canCancel(row) {
|
canCancel(row) {
|
||||||
// 进行中的运单不允许取消
|
// 进行中的运单不允许取消;待回单确认仍可取消(与页面 canCancel 一致)
|
||||||
return !isInProgressStatus(row, row.businessStatusName);
|
return !isInProgressStatus(row, row.businessStatusName);
|
||||||
},
|
},
|
||||||
deleteStatus: ['draft'],
|
deleteStatus: ['draft'],
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ export const paymentApplicationOption = ({
|
|||||||
searchShow: true,
|
searchShow: true,
|
||||||
searchIcon: true,
|
searchIcon: true,
|
||||||
searchLabelWidth: 88,
|
searchLabelWidth: 88,
|
||||||
searchMenuSpan: 24,
|
// 查询/重置紧跟首行 4 个条件(4×5 + 菜单 4 = 24),不再独占下一整行
|
||||||
|
searchMenuSpan: 4,
|
||||||
searchIndex: 4,
|
searchIndex: 4,
|
||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
@@ -78,6 +79,7 @@ export const paymentApplicationOption = ({
|
|||||||
prop: 'paymentNo',
|
prop: 'paymentNo',
|
||||||
slot: true,
|
slot: true,
|
||||||
search: true,
|
search: true,
|
||||||
|
searchSpan: 5,
|
||||||
searchOrder: 9,
|
searchOrder: 9,
|
||||||
searchPlaceholder: '请输入',
|
searchPlaceholder: '请输入',
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
@@ -88,6 +90,7 @@ export const paymentApplicationOption = ({
|
|||||||
type: 'daterange',
|
type: 'daterange',
|
||||||
searchType: 'daterange',
|
searchType: 'daterange',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchSpan: 5,
|
||||||
searchOrder: 8,
|
searchOrder: 8,
|
||||||
hide: true,
|
hide: true,
|
||||||
showColumn: false,
|
showColumn: false,
|
||||||
@@ -95,18 +98,24 @@ export const paymentApplicationOption = ({
|
|||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
viewDisplay: false,
|
viewDisplay: false,
|
||||||
},
|
},
|
||||||
searchOnlyColumn({
|
{
|
||||||
label: '客户名称',
|
...searchOnlyColumn({
|
||||||
prop: 'payeeNameSearch',
|
label: '客户名称',
|
||||||
searchOrder: 7,
|
prop: 'payeeNameSearch',
|
||||||
searchProp: 'payeeName',
|
searchOrder: 7,
|
||||||
}),
|
searchProp: 'payeeName',
|
||||||
searchOnlyColumn({
|
}),
|
||||||
label: '项目名称',
|
searchSpan: 5,
|
||||||
prop: 'projectNameSearch',
|
},
|
||||||
searchOrder: 6,
|
{
|
||||||
searchProp: 'projectName',
|
...searchOnlyColumn({
|
||||||
}),
|
label: '项目名称',
|
||||||
|
prop: 'projectNameSearch',
|
||||||
|
searchOrder: 6,
|
||||||
|
searchProp: 'projectName',
|
||||||
|
}),
|
||||||
|
searchSpan: 5,
|
||||||
|
},
|
||||||
searchOnlyColumn({
|
searchOnlyColumn({
|
||||||
label: '关联结算单',
|
label: '关联结算单',
|
||||||
prop: 'settlementNo',
|
prop: 'settlementNo',
|
||||||
@@ -160,7 +169,8 @@ export const paymentApplicationOption = ({
|
|||||||
{ label: '当前节点', prop: 'currentNode', minWidth: 120, formatter: textFormatter },
|
{ label: '当前节点', prop: 'currentNode', minWidth: 120, formatter: textFormatter },
|
||||||
{ label: '当前处理人', prop: 'currentProcessor', minWidth: 120, formatter: textFormatter },
|
{ label: '当前处理人', prop: 'currentProcessor', minWidth: 120, formatter: textFormatter },
|
||||||
{ label: '金蝶单据号', prop: 'kingdeeBillNo', minWidth: 130, formatter: textFormatter },
|
{ label: '金蝶单据号', prop: 'kingdeeBillNo', minWidth: 130, formatter: textFormatter },
|
||||||
{ label: '金蝶单据状态', prop: 'kingdeeStatusName', minWidth: 130, formatter: textFormatter },
|
{ label: '金蝶单据状态', prop: 'kingdeeStatusName', slot: true, minWidth: 130 },
|
||||||
|
{ label: '已指定应付', prop: 'kingdeeAssignStatus', slot: true, minWidth: 120 },
|
||||||
{ label: '金蝶锁状态', prop: 'kingdeeLockStatus', slot: true, minWidth: 150 },
|
{ label: '金蝶锁状态', prop: 'kingdeeLockStatus', slot: true, minWidth: 150 },
|
||||||
{ label: '附件同步', prop: 'attachmentSyncStatusName', minWidth: 100, formatter: textFormatter },
|
{ label: '附件同步', prop: 'attachmentSyncStatusName', minWidth: 100, formatter: textFormatter },
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export const receiptClaimRecordTableColumns = [
|
export const receiptClaimRecordTableColumns = [
|
||||||
{ prop: 'receiptNoticeNo', label: '认领通知单', minWidth: 150, link: true },
|
{ prop: 'receiptNoticeNo', label: '收款单号', minWidth: 150, link: true },
|
||||||
{ prop: 'payerName', label: '付款人', minWidth: 130 },
|
{ prop: 'payerName', label: '付款人', minWidth: 130 },
|
||||||
{ prop: 'receiptAmount', label: '付款金额', minWidth: 130, money: true },
|
{ prop: 'receiptAmount', label: '收款金额', minWidth: 130, money: true },
|
||||||
{ prop: 'counterpartyName', label: '对方户名', minWidth: 150 },
|
{ prop: 'counterpartyName', label: '对方户名', minWidth: 150 },
|
||||||
{ prop: 'counterpartyAccount', label: '对方账号', minWidth: 170 },
|
{ prop: 'counterpartyAccount', label: '对方账号', minWidth: 170 },
|
||||||
{ prop: 'counterpartyBank', label: '对方开户行', minWidth: 150 },
|
{ prop: 'counterpartyBank', label: '对方开户行', minWidth: 150 },
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
export const receiptFlowTableColumns = [
|
export const receiptFlowTableColumns = [
|
||||||
{ prop: 'receiptNoticeNo', label: '认领通知单', minWidth: 150, link: true },
|
{ prop: 'receiptNoticeNo', label: '收款单号', minWidth: 150, link: true },
|
||||||
{ prop: 'payerName', label: '付款人', minWidth: 130 },
|
{ prop: 'payerName', label: '付款人', minWidth: 130 },
|
||||||
{ prop: 'receiptAmount', label: '付款金额', minWidth: 130, money: true },
|
{ prop: 'receiptAmount', label: '收款金额', minWidth: 130, money: true },
|
||||||
{ prop: 'counterpartyName', label: '对方户名', minWidth: 150 },
|
{ prop: 'counterpartyName', label: '对方户名', minWidth: 150 },
|
||||||
{ prop: 'counterpartyAccount', label: '对方账号', minWidth: 170 },
|
{ prop: 'counterpartyAccount', label: '对方账号', minWidth: 170 },
|
||||||
{ prop: 'counterpartyBank', label: '对方开户行', minWidth: 150 },
|
{ prop: 'counterpartyBank', label: '对方开户行', minWidth: 150 },
|
||||||
|
{ prop: 'payeeName', label: '收款人(公司)', minWidth: 150 },
|
||||||
|
//{ prop: 'orgNumber', label: '收款公司编码', minWidth: 130 },
|
||||||
|
//{ prop: 'openOrgNumber', label: '核算组织编码', minWidth: 130 },
|
||||||
{ prop: 'summary', label: '摘要', minWidth: 160 },
|
{ prop: 'summary', label: '摘要', minWidth: 160 },
|
||||||
{ prop: 'transactionTime', label: '交易时间', minWidth: 170 },
|
{ prop: 'transactionTime', label: '交易时间', minWidth: 170 },
|
||||||
{ prop: 'claimStatusName', label: '认领状态', minWidth: 110, status: true },
|
{ prop: 'claimStatusName', label: '认领状态', minWidth: 110, status: true },
|
||||||
{ prop: 'kingdeeClaimStatusName', label: '公告状态', minWidth: 110 },
|
|
||||||
{ prop: 'claimedAmount', label: '已认领金额', minWidth: 130, money: true },
|
{ prop: 'claimedAmount', label: '已认领金额', minWidth: 130, money: true },
|
||||||
{ prop: 'unclaimedAmount', label: '金蝶未认领金额', minWidth: 140, money: true },
|
{ prop: 'remainingAmount', label: '剩余可认领金额', minWidth: 140, money: true },
|
||||||
{ prop: 'pushStatusName', label: '推送状态', minWidth: 110, status: true },
|
{ prop: 'unmatchAmountRec', label: '未匹配金额', minWidth: 140, money: true },
|
||||||
{ prop: 'pushFailReason', label: '推送失败原因', minWidth: 160 },
|
//{ prop: 'matchAmountRec', label: '已匹配收款金额', minWidth: 140, money: true },
|
||||||
{ prop: 'kingdeeBillNo', label: '金蝶收款单号', minWidth: 150 },
|
//{ prop: 'matchAmountPay', label: '已匹配付款金额', minWidth: 140, money: true },
|
||||||
|
//{ prop: 'unmatchAmountPay', label: '未匹配付款金额', minWidth: 140, money: true },
|
||||||
|
//{ prop: 'settleAmount', label: '已结算金额', minWidth: 130, money: true },
|
||||||
|
//{ prop: 'unsettleAmount', label: '未结算金额', minWidth: 130, money: true },
|
||||||
{ prop: 'kingdeeBillStatusName', label: '金蝶状态', minWidth: 110 },
|
{ prop: 'kingdeeBillStatusName', label: '金蝶状态', minWidth: 110 },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/**
|
||||||
|
* 正式结算单列表(avue-crud)配置
|
||||||
|
* ------------------------------------------------------------------
|
||||||
|
* 列表页与其它模块统一使用 avue-crud,头部 4 个按钮(刷新 / 列显隐 / 搜索显隐 /
|
||||||
|
* 显示方式)由 avue-crud 自带,不做二次封装。
|
||||||
|
*
|
||||||
|
* 表格列复用 formalSettlementTable.js 的 formalSettlementTableColumns(与弹窗内
|
||||||
|
* 明细表共用同一份列定义),此处只补充 avue 需要的展示/搜索属性,避免两处维护。
|
||||||
|
*
|
||||||
|
* ⚠️ searchOrder 为降序排序,值越大越靠前。
|
||||||
|
* ⚠️ 仅用于搜索的列必须 hide + showColumn: false,否则会混进「列显隐」抽屉。
|
||||||
|
* ⚠️ column 数组顺序 = 表格列顺序,搜索专用列统一放在数组最前面。
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
approvalStatusOptions,
|
||||||
|
invoiceStatusOptions,
|
||||||
|
kingdeeSyncStatusOptions,
|
||||||
|
kingdeeWriteOffStatusOptions,
|
||||||
|
paymentStatusOptions,
|
||||||
|
} from './formalSettlementSearch';
|
||||||
|
import { formalSettlementTableColumns } from './formalSettlementTable';
|
||||||
|
|
||||||
|
const textFormatter = (row, value) =>
|
||||||
|
value === null || value === undefined || value === '' ? '-' : value;
|
||||||
|
|
||||||
|
/** 金额统一展示:两位小数 + 币种 */
|
||||||
|
const moneyFormatter = (row, value) =>
|
||||||
|
`${Number(value || 0).toFixed(2)} ${row?.currency || 'RMB'}`;
|
||||||
|
|
||||||
|
const pickLabel = (options, value) =>
|
||||||
|
options.find(item => item.value === value)?.label || value || '-';
|
||||||
|
|
||||||
|
const searchOnlyColumn = ({ label, prop, searchOrder, type = 'input', dicData }) => {
|
||||||
|
const column = {
|
||||||
|
label,
|
||||||
|
prop,
|
||||||
|
search: true,
|
||||||
|
searchOrder,
|
||||||
|
searchSpan: 5,
|
||||||
|
hide: true,
|
||||||
|
showColumn: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
};
|
||||||
|
if (type === 'select') {
|
||||||
|
column.type = 'select';
|
||||||
|
column.searchPlaceholder = '请选择';
|
||||||
|
column.dicData = dicData || [];
|
||||||
|
} else if (type === 'daterange') {
|
||||||
|
column.type = 'daterange';
|
||||||
|
column.searchType = 'daterange';
|
||||||
|
column.searchPlaceholder = '请选择';
|
||||||
|
} else {
|
||||||
|
column.searchPlaceholder = '请输入';
|
||||||
|
}
|
||||||
|
return column;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 表格列的 avue 增量配置:搜索项、插槽、覆盖宽度等 */
|
||||||
|
const COLUMN_EXTRA = {
|
||||||
|
formalSettlementNo: {
|
||||||
|
slot: true,
|
||||||
|
search: true,
|
||||||
|
searchSpan: 5,
|
||||||
|
searchOrder: 12,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
},
|
||||||
|
payerName: { search: true, searchSpan: 5, searchOrder: 7, searchPlaceholder: '请输入' },
|
||||||
|
payeeName: { search: true, searchSpan: 5, searchOrder: 6, searchPlaceholder: '请输入' },
|
||||||
|
projectName: { search: true, searchSpan: 5, searchOrder: 11, searchPlaceholder: '请输入' },
|
||||||
|
deptName: { search: true, searchslot: true, searchSpan: 5, searchOrder: 10 },
|
||||||
|
contractNo: { search: true, searchSpan: 5, searchOrder: 9, searchPlaceholder: '请输入' },
|
||||||
|
invoiceStatusName: { slot: true },
|
||||||
|
paymentStatusName: { slot: true },
|
||||||
|
approvalStatusName: { slot: true },
|
||||||
|
adjustFlag: {
|
||||||
|
formatter: row => row.adjustStatusName || (row.originFormalSettlementNo ? '调整后单' : '-'),
|
||||||
|
},
|
||||||
|
kingdeeSyncStatus: {
|
||||||
|
slot: true,
|
||||||
|
search: true,
|
||||||
|
type: 'select',
|
||||||
|
dicData: kingdeeSyncStatusOptions,
|
||||||
|
searchSpan: 5,
|
||||||
|
searchOrder: 2,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
},
|
||||||
|
kingdeeLockStatus: { slot: true },
|
||||||
|
kingdeeWriteOffStatus: { slot: true },
|
||||||
|
kingdeeAssignStatus: { slot: true },
|
||||||
|
createTime: { width: 180 },
|
||||||
|
};
|
||||||
|
|
||||||
|
// 已指定应付仅付款结算单(先票后款 A302-6)有,收款结算单不展示
|
||||||
|
const buildTableColumns = settlementType =>
|
||||||
|
formalSettlementTableColumns
|
||||||
|
.filter(column => !(settlementType === 'receivable' && column.prop === 'kingdeeAssignStatus'))
|
||||||
|
.map(column => {
|
||||||
|
const extra = { ...(COLUMN_EXTRA[column.prop] || {}) };
|
||||||
|
if (column.money) {
|
||||||
|
extra.formatter = moneyFormatter;
|
||||||
|
extra.align = 'right';
|
||||||
|
}
|
||||||
|
// link / status 标记的列统一走单元格插槽
|
||||||
|
if (column.link || column.status) extra.slot = true;
|
||||||
|
// 插槽列不挂兜底 formatter:avue 中 formatter 会覆盖单元格插槽渲染
|
||||||
|
if (!extra.slot && !extra.formatter) extra.formatter = textFormatter;
|
||||||
|
return { ...column, ...extra };
|
||||||
|
});
|
||||||
|
|
||||||
|
export const formalSettlementOption = (settlementType = '') => ({
|
||||||
|
height: 'auto',
|
||||||
|
calcHeight: 32,
|
||||||
|
tip: false,
|
||||||
|
searchBtnText: '查询',
|
||||||
|
emptyBtnText: '重置',
|
||||||
|
searchShow: true,
|
||||||
|
searchIcon: true,
|
||||||
|
searchLabelWidth: 100,
|
||||||
|
// 查询/重置紧跟首行 4 个条件(4×5 + 菜单 4 = 24),不再独占下一整行
|
||||||
|
searchMenuSpan: 4,
|
||||||
|
searchIndex: 4,
|
||||||
|
searchMenuPosition: 'right',
|
||||||
|
border: true,
|
||||||
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
|
indexWidth: 64,
|
||||||
|
indexFixed: 'left',
|
||||||
|
selection: true,
|
||||||
|
selectionWidth: 52,
|
||||||
|
selectionFixed: 'left',
|
||||||
|
addBtn: false,
|
||||||
|
viewBtn: false,
|
||||||
|
delBtn: false,
|
||||||
|
editBtn: false,
|
||||||
|
menuWidth: 320,
|
||||||
|
menuFixed: 'right',
|
||||||
|
column: [
|
||||||
|
// ---------- 仅搜索列 ----------
|
||||||
|
searchOnlyColumn({
|
||||||
|
label: '预付结算单号',
|
||||||
|
prop: 'preSettlementNo',
|
||||||
|
searchOrder: 8,
|
||||||
|
}),
|
||||||
|
searchOnlyColumn({
|
||||||
|
label: '发票状态',
|
||||||
|
prop: 'invoiceStatus',
|
||||||
|
searchOrder: 5,
|
||||||
|
type: 'select',
|
||||||
|
dicData: invoiceStatusOptions,
|
||||||
|
}),
|
||||||
|
searchOnlyColumn({
|
||||||
|
label: '收付款状态',
|
||||||
|
prop: 'paymentStatus',
|
||||||
|
searchOrder: 4,
|
||||||
|
type: 'select',
|
||||||
|
dicData: paymentStatusOptions,
|
||||||
|
}),
|
||||||
|
searchOnlyColumn({
|
||||||
|
label: '审核状态',
|
||||||
|
prop: 'approvalStatus',
|
||||||
|
searchOrder: 3,
|
||||||
|
type: 'select',
|
||||||
|
dicData: approvalStatusOptions,
|
||||||
|
}),
|
||||||
|
searchOnlyColumn({
|
||||||
|
label: '生成日期',
|
||||||
|
prop: 'createDateRange',
|
||||||
|
searchOrder: 1,
|
||||||
|
type: 'daterange',
|
||||||
|
}),
|
||||||
|
// ---------- 表格列(部分兼搜索项) ----------
|
||||||
|
...buildTableColumns(settlementType),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const kingdeeSyncName = value => pickLabel(kingdeeSyncStatusOptions, value);
|
||||||
|
export const kingdeeWriteOffName = value => pickLabel(kingdeeWriteOffStatusOptions, value);
|
||||||
|
export const paymentStatusName = value => pickLabel(paymentStatusOptions, value);
|
||||||
@@ -8,6 +8,8 @@ export const formalSettlementFormFields = [
|
|||||||
{ label: '收款方', prop: 'payeeName', readonly: true },
|
{ label: '收款方', prop: 'payeeName', readonly: true },
|
||||||
{ label: '结算类型', prop: 'settlementTypeName', readonly: true },
|
{ label: '结算类型', prop: 'settlementTypeName', readonly: true },
|
||||||
{ label: '结算金额', prop: 'settlementAmount', readonly: true, money: true },
|
{ label: '结算金额', prop: 'settlementAmount', readonly: true, money: true },
|
||||||
|
{ label: '业务模式', prop: 'businessModel', type: 'select', optionsKey: 'businessModelOptions' },
|
||||||
|
{ label: '运输方式', prop: 'transportType', type: 'select', optionsKey: 'transportTypeOptions' },
|
||||||
{ label: '汇率日期', prop: 'exchangeRateDate', type: 'date', required: true },
|
{ label: '汇率日期', prop: 'exchangeRateDate', type: 'date', required: true },
|
||||||
{ label: '结算汇率', prop: 'exchangeRate', type: 'number', required: true },
|
{ label: '结算汇率', prop: 'exchangeRate', type: 'number', required: true },
|
||||||
{ label: '本位币合计', prop: 'localSettlementAmount', readonly: true, money: true },
|
{ label: '本位币合计', prop: 'localSettlementAmount', readonly: true, money: true },
|
||||||
@@ -25,6 +27,8 @@ export const createFormalSettlementForm = () => ({
|
|||||||
settlementType: '',
|
settlementType: '',
|
||||||
sourcePreSettlementIds: [],
|
sourcePreSettlementIds: [],
|
||||||
sourceDetailIds: [],
|
sourceDetailIds: [],
|
||||||
|
businessModel: '',
|
||||||
|
transportType: '',
|
||||||
exchangeRateDate: '',
|
exchangeRateDate: '',
|
||||||
exchangeRate: 1,
|
exchangeRate: 1,
|
||||||
createUserName: '',
|
createUserName: '',
|
||||||
|
|||||||
@@ -34,9 +34,14 @@ export const kingdeeSyncStatusOptions = [
|
|||||||
{ label: '同步失败', value: 'failed' },
|
{ label: '同步失败', value: 'failed' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const kingdeeWriteOffStatusOptions = [
|
||||||
|
{ label: '未冲销', value: 'unwrittenoff' },
|
||||||
|
{ label: '已冲销', value: 'writtenoff' },
|
||||||
|
];
|
||||||
|
|
||||||
export const formalSettlementSearchFields = [
|
export const formalSettlementSearchFields = [
|
||||||
{ label: '结算单号', prop: 'formalSettlementNo', type: 'input' },
|
{ label: '结算单号', prop: 'formalSettlementNo', type: 'input' },
|
||||||
{ label: '预结算单号', prop: 'preSettlementNo', type: 'input' },
|
{ label: '预付结算单号', prop: 'preSettlementNo', type: 'input' },
|
||||||
{ label: '项目', prop: 'projectName', type: 'input' },
|
{ label: '项目', prop: 'projectName', type: 'input' },
|
||||||
{ label: '所属组织', prop: 'deptName', type: 'cascader' },
|
{ label: '所属组织', prop: 'deptName', type: 'cascader' },
|
||||||
{ label: '合同编号', prop: 'contractNo', type: 'input' },
|
{ label: '合同编号', prop: 'contractNo', type: 'input' },
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export const formalSettlementTableColumns = [
|
|||||||
{ label: '合同编号', prop: 'contractNo', minWidth: 150 },
|
{ label: '合同编号', prop: 'contractNo', minWidth: 150 },
|
||||||
{ label: '合同名称', prop: 'contractName', minWidth: 170 },
|
{ label: '合同名称', prop: 'contractName', minWidth: 170 },
|
||||||
{ label: '原币结算金额', prop: 'settlementAmount', minWidth: 145, money: true },
|
{ label: '原币结算金额', prop: 'settlementAmount', minWidth: 145, money: true },
|
||||||
|
{ label: '业务模式', prop: 'businessModelName', minWidth: 120 },
|
||||||
|
{ label: '运输方式', prop: 'transportTypeName', minWidth: 120 },
|
||||||
{ label: '本位币结算金额', prop: 'localSettlementAmount', minWidth: 155, money: true },
|
{ label: '本位币结算金额', prop: 'localSettlementAmount', minWidth: 155, money: true },
|
||||||
{ label: '结算汇率', prop: 'exchangeRate', minWidth: 110 },
|
{ label: '结算汇率', prop: 'exchangeRate', minWidth: 110 },
|
||||||
{ label: '申请付款金额(含预付)', prop: 'appliedPaymentAmount', minWidth: 185, money: true },
|
{ label: '申请付款金额(含预付)', prop: 'appliedPaymentAmount', minWidth: 185, money: true },
|
||||||
@@ -19,24 +21,28 @@ export const formalSettlementTableColumns = [
|
|||||||
{ label: '审核状态', prop: 'approvalStatusName', minWidth: 110, status: true },
|
{ label: '审核状态', prop: 'approvalStatusName', minWidth: 110, status: true },
|
||||||
{ label: '当前节点', prop: 'currentNode', minWidth: 130 },
|
{ label: '当前节点', prop: 'currentNode', minWidth: 130 },
|
||||||
{ label: '当前处理人', prop: 'currentProcessor', minWidth: 130 },
|
{ label: '当前处理人', prop: 'currentProcessor', minWidth: 130 },
|
||||||
|
{ label: '调整标识', prop: 'adjustFlag', minWidth: 110 },
|
||||||
|
{ label: '来源原单号', prop: 'originFormalSettlementNo', minWidth: 170 },
|
||||||
{ label: '金蝶单据号', prop: 'kingdeeBillNo', minWidth: 150 },
|
{ label: '金蝶单据号', prop: 'kingdeeBillNo', minWidth: 150 },
|
||||||
{ label: '金蝶单据状态', prop: 'kingdeeSyncStatus', minWidth: 135 },
|
{ label: '金蝶单据状态', prop: 'kingdeeSyncStatus', minWidth: 135 },
|
||||||
|
{ label: '金蝶冲销状态', prop: 'kingdeeWriteOffStatus', minWidth: 135 },
|
||||||
{ label: '金蝶锁状态', prop: 'kingdeeLockStatus', minWidth: 150 },
|
{ label: '金蝶锁状态', prop: 'kingdeeLockStatus', minWidth: 150 },
|
||||||
|
{ label: '已指定应付', prop: 'kingdeeAssignStatus', minWidth: 120 },
|
||||||
{ label: '附件同步', prop: 'attachmentSyncStatusName', minWidth: 100 },
|
{ label: '附件同步', prop: 'attachmentSyncStatusName', minWidth: 100 },
|
||||||
{ label: '创建人', prop: 'createUserName', minWidth: 110 },
|
{ label: '创建人', prop: 'createUserName', minWidth: 110 },
|
||||||
{ label: '创建时间', prop: 'createTime', minWidth: 170 },
|
{ label: '创建时间', prop: 'createTime', minWidth: 170 },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const sourceColumns = [
|
export const sourceColumns = [
|
||||||
{ label: '预结算单号', prop: 'preSettlementNo', minWidth: 160 },
|
{ label: '预付结算单号', prop: 'preSettlementNo', minWidth: 160 },
|
||||||
{ label: '结算金额', prop: 'settlementAmount', minWidth: 130, money: true },
|
{ label: '结算金额', prop: 'settlementAmount', minWidth: 130, money: true },
|
||||||
{ label: '申请预付金额', prop: 'advanceAppliedAmount', minWidth: 140, money: true },
|
{ label: '申请预付金额', prop: 'advanceAppliedAmount', minWidth: 140, money: true },
|
||||||
{ label: '已付款金额', prop: 'advancePaidAmount', minWidth: 130, money: true },
|
{ label: '已付款金额', prop: 'advancePaidAmount', minWidth: 130, money: true },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const detailColumns = [
|
export const detailColumns = [
|
||||||
{ label: '单据号', prop: 'documentNo', minWidth: 180 },
|
{ label: '单据号', prop: 'documentNo', minWidth: 180, link: true },
|
||||||
{ label: '运单号', prop: 'waybillNo', minWidth: 160 },
|
{ label: '运单号', prop: 'waybillNo', minWidth: 160, link: true },
|
||||||
{ label: '车号', prop: 'vehicleNo', minWidth: 130 },
|
{ label: '车号', prop: 'vehicleNo', minWidth: 130 },
|
||||||
{ label: '发货地址', prop: 'departureAddress', minWidth: 180 },
|
{ label: '发货地址', prop: 'departureAddress', minWidth: 180 },
|
||||||
{ label: '到货地址', prop: 'arrivalAddress', minWidth: 180 },
|
{ label: '到货地址', prop: 'arrivalAddress', minWidth: 180 },
|
||||||
@@ -48,11 +54,11 @@ export const detailColumns = [
|
|||||||
{ label: '运输总量', prop: 'transportQuantity', minWidth: 120 },
|
{ label: '运输总量', prop: 'transportQuantity', minWidth: 120 },
|
||||||
{ label: '里程(KM)', prop: 'mileage', minWidth: 120 },
|
{ label: '里程(KM)', prop: 'mileage', minWidth: 120 },
|
||||||
{ label: '批次号', prop: 'batchNo', minWidth: 120 },
|
{ label: '批次号', prop: 'batchNo', minWidth: 120 },
|
||||||
|
{ label: '计费方式', prop: 'billingType', minWidth: 130 },
|
||||||
{ label: '运输单价', prop: 'unitPrice', minWidth: 120, money: true },
|
{ label: '运输单价', prop: 'unitPrice', minWidth: 120, money: true },
|
||||||
{ label: '运费', prop: 'freightAmount', minWidth: 120, money: true },
|
{ label: '运费', prop: 'freightAmount', minWidth: 120, money: true },
|
||||||
{ label: '调整金额', prop: 'adjustAmount', minWidth: 120, money: true },
|
{ label: '调整金额', prop: 'adjustAmount', minWidth: 120, money: true },
|
||||||
{ label: '结算金额(含税)', prop: 'settlementAmountTax', minWidth: 155, money: true },
|
{ label: '结算金额(含税)', prop: 'settlementAmountTax', minWidth: 155, money: true },
|
||||||
{ label: '结算金额(不含税)', prop: 'settlementAmountNoTax', minWidth: 170, money: true },
|
|
||||||
{ label: '备注', prop: 'remark', minWidth: 180 },
|
{ label: '备注', prop: 'remark', minWidth: 180 },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -66,7 +72,7 @@ export const summaryColumns = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const candidateColumns = [
|
export const candidateColumns = [
|
||||||
{ label: '预结算单号', prop: 'preSettlementNo', minWidth: 170 },
|
{ label: '预付结算单号', prop: 'preSettlementNo', minWidth: 170 },
|
||||||
{ label: '项目名称', prop: 'projectName', minWidth: 140 },
|
{ label: '项目名称', prop: 'projectName', minWidth: 140 },
|
||||||
{ label: '所属组织', prop: 'deptName', minWidth: 140 },
|
{ label: '所属组织', prop: 'deptName', minWidth: 140 },
|
||||||
{ label: '合同编号', prop: 'contractNo', minWidth: 150 },
|
{ label: '合同编号', prop: 'contractNo', minWidth: 150 },
|
||||||
@@ -86,7 +92,7 @@ export const candidateDetailColumns = [
|
|||||||
{ label: '合同编号', prop: 'contractNo', minWidth: 150 },
|
{ label: '合同编号', prop: 'contractNo', minWidth: 150 },
|
||||||
{ label: '合同名称', prop: 'contractName', minWidth: 170 },
|
{ label: '合同名称', prop: 'contractName', minWidth: 170 },
|
||||||
{ label: '来源', prop: 'sourceType', minWidth: 110 },
|
{ label: '来源', prop: 'sourceType', minWidth: 110 },
|
||||||
{ label: '预结算单号', prop: 'preSettlementNo', minWidth: 160 },
|
{ label: '预付结算单号', prop: 'preSettlementNo', minWidth: 160 },
|
||||||
{ label: '正式结算单号', prop: 'formalSettlementNo', minWidth: 160 },
|
{ label: '正式结算单号', prop: 'formalSettlementNo', minWidth: 160 },
|
||||||
{ label: '运单号', prop: 'waybillNo', minWidth: 150 },
|
{ label: '运单号', prop: 'waybillNo', minWidth: 150 },
|
||||||
{ label: '车号', prop: 'vehicleNo', minWidth: 130 },
|
{ label: '车号', prop: 'vehicleNo', minWidth: 130 },
|
||||||
@@ -94,6 +100,7 @@ export const candidateDetailColumns = [
|
|||||||
{ label: '货物名称', prop: 'cargoName', minWidth: 140 },
|
{ label: '货物名称', prop: 'cargoName', minWidth: 140 },
|
||||||
{ label: '货物类型', prop: 'cargoType', minWidth: 130 },
|
{ label: '货物类型', prop: 'cargoType', minWidth: 130 },
|
||||||
{ label: '批次号', prop: 'batchNo', minWidth: 120 },
|
{ label: '批次号', prop: 'batchNo', minWidth: 120 },
|
||||||
|
{ label: '计费方式', prop: 'billingType', minWidth: 130 },
|
||||||
{ label: '应收应付合计', prop: 'totalAmount', minWidth: 140, money: true },
|
{ label: '应收应付合计', prop: 'totalAmount', minWidth: 140, money: true },
|
||||||
{ label: '状态', prop: 'settlementStatusName', minWidth: 110 },
|
{ label: '状态', prop: 'settlementStatusName', minWidth: 110 },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -4,14 +4,28 @@ export const settlementTypeOptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const preSettlementFormFields = [
|
export const preSettlementFormFields = [
|
||||||
{ label: '预结算单号', prop: 'preSettlementNo', readonly: true },
|
{ label: '预付结算单号', prop: 'preSettlementNo', readonly: true },
|
||||||
{ label: '合同名称', prop: 'contractId', type: 'contract', required: true },
|
{ label: '合同名称', prop: 'contractId', type: 'contract', required: true },
|
||||||
{ label: '合同编号', prop: 'contractNo', readonly: true },
|
{ label: '合同编号', prop: 'contractNo', readonly: true },
|
||||||
{ label: '项目名称', prop: 'projectName', readonly: true },
|
{ label: '项目名称', prop: 'projectName', readonly: true },
|
||||||
{ label: '收款方', prop: 'payeeName', readonly: true },
|
{
|
||||||
{ label: '付款方', prop: 'payerName', readonly: true },
|
label: '收款方',
|
||||||
|
prop: 'payeeName',
|
||||||
|
type: 'select',
|
||||||
|
optionsKey: 'payeeOptions',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '付款方',
|
||||||
|
prop: 'payerName',
|
||||||
|
type: 'select',
|
||||||
|
optionsKey: 'payerOptions',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
{ label: '结算类型', prop: 'settlementType', readonly: true },
|
{ label: '结算类型', prop: 'settlementType', readonly: true },
|
||||||
{ label: '结算金额', prop: 'settlementAmount', readonly: true, money: true },
|
{ label: '结算金额', prop: 'settlementAmount', readonly: true, money: true },
|
||||||
|
{ label: '业务模式', prop: 'businessModel', type: 'select', optionsKey: 'businessModelOptions' },
|
||||||
|
{ label: '运输方式', prop: 'transportType', type: 'select', optionsKey: 'transportTypeOptions' },
|
||||||
{ label: '汇率日期', prop: 'exchangeRateDate', type: 'date' },
|
{ label: '汇率日期', prop: 'exchangeRateDate', type: 'date' },
|
||||||
{ label: '结算汇率', prop: 'exchangeRate', type: 'number', class: 'exchange-rate-input' },
|
{ label: '结算汇率', prop: 'exchangeRate', type: 'number', class: 'exchange-rate-input' },
|
||||||
{ label: '本位币合计', prop: 'localSettlementAmount', readonly: true, money: true },
|
{ label: '本位币合计', prop: 'localSettlementAmount', readonly: true, money: true },
|
||||||
@@ -22,6 +36,8 @@ export const preSettlementFormFields = [
|
|||||||
|
|
||||||
export const preSettlementFormRules = {
|
export const preSettlementFormRules = {
|
||||||
contractId: [{ required: true, message: '请选择合同名称', trigger: 'change' }],
|
contractId: [{ required: true, message: '请选择合同名称', trigger: 'change' }],
|
||||||
|
payeeName: [{ required: true, message: '请选择收款方', trigger: 'change' }],
|
||||||
|
payerName: [{ required: true, message: '请选择付款方', trigger: 'change' }],
|
||||||
exchangeRateDate: [
|
exchangeRateDate: [
|
||||||
{
|
{
|
||||||
validator: (_rule, value, callback, source) => {
|
validator: (_rule, value, callback, source) => {
|
||||||
@@ -64,6 +80,8 @@ export const emptyPreSettlementForm = () => ({
|
|||||||
settlementType: 'payable',
|
settlementType: 'payable',
|
||||||
currency: 'RMB',
|
currency: 'RMB',
|
||||||
settlementAmount: 0,
|
settlementAmount: 0,
|
||||||
|
businessModel: '',
|
||||||
|
transportType: '',
|
||||||
localCurrency: 'RMB',
|
localCurrency: 'RMB',
|
||||||
localSettlementAmount: 0,
|
localSettlementAmount: 0,
|
||||||
exchangeRateDate: '',
|
exchangeRateDate: '',
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const approvalStatusOptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const preSettlementSearchFields = [
|
export const preSettlementSearchFields = [
|
||||||
{ label: '预结算单号', prop: 'preSettlementNo', type: 'input' },
|
{ label: '预付结算单号', prop: 'preSettlementNo', type: 'input' },
|
||||||
{ label: '预付单号', prop: 'advanceNo', type: 'input' },
|
{ label: '预付单号', prop: 'advanceNo', type: 'input' },
|
||||||
{ label: '项目名称', prop: 'projectName', type: 'input' },
|
{ label: '项目名称', prop: 'projectName', type: 'input' },
|
||||||
{ label: '所属组织', prop: 'deptName', type: 'cascader' },
|
{ label: '所属组织', prop: 'deptName', type: 'cascader' },
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export const preSettlementTableColumns = [
|
export const preSettlementTableColumns = [
|
||||||
{ label: '预结算单号', prop: 'preSettlementNo', minWidth: 150, link: true, fixed: 'left' },
|
{ label: '预付结算单号', prop: 'preSettlementNo', minWidth: 150, link: true, fixed: 'left' },
|
||||||
{ label: '来源', prop: 'sourceType', minWidth: 100 },
|
{ label: '来源', prop: 'sourceType', minWidth: 100 },
|
||||||
{ label: '付款方', prop: 'payerName', minWidth: 160 },
|
{ label: '付款方', prop: 'payerName', minWidth: 160 },
|
||||||
{ label: '收款方', prop: 'payeeName', minWidth: 160 },
|
{ label: '收款方', prop: 'payeeName', minWidth: 160 },
|
||||||
@@ -8,6 +8,8 @@ export const preSettlementTableColumns = [
|
|||||||
{ label: '合同编号', prop: 'contractNo', minWidth: 140 },
|
{ label: '合同编号', prop: 'contractNo', minWidth: 140 },
|
||||||
{ label: '合同名称', prop: 'contractName', minWidth: 160 },
|
{ label: '合同名称', prop: 'contractName', minWidth: 160 },
|
||||||
{ label: '原币结算金额', prop: 'settlementAmount', minWidth: 140, money: true, precision: 2 },
|
{ label: '原币结算金额', prop: 'settlementAmount', minWidth: 140, money: true, precision: 2 },
|
||||||
|
{ label: '业务模式', prop: 'businessModelName', minWidth: 120 },
|
||||||
|
{ label: '运输方式', prop: 'transportTypeName', minWidth: 120 },
|
||||||
{ label: '本位币结算金额', prop: 'localSettlementAmount', minWidth: 150, money: true, precision: 2 },
|
{ label: '本位币结算金额', prop: 'localSettlementAmount', minWidth: 150, money: true, precision: 2 },
|
||||||
{ label: '结算汇率', prop: 'exchangeRate', minWidth: 110, precision: 2 },
|
{ label: '结算汇率', prop: 'exchangeRate', minWidth: 110, precision: 2 },
|
||||||
{
|
{
|
||||||
@@ -40,7 +42,7 @@ export const settlementSummaryColumns = [
|
|||||||
|
|
||||||
export const settlementDetailColumns = [
|
export const settlementDetailColumns = [
|
||||||
{ label: '单据号', prop: 'documentNo', minWidth: 180, link: true },
|
{ label: '单据号', prop: 'documentNo', minWidth: 180, link: true },
|
||||||
{ label: '运单号', prop: 'waybillNo', minWidth: 160 },
|
{ label: '运单号', prop: 'waybillNo', minWidth: 160, link: true },
|
||||||
{ label: '车号', prop: 'vehicleNo', minWidth: 130 },
|
{ label: '车号', prop: 'vehicleNo', minWidth: 130 },
|
||||||
{ label: '发货地址', prop: 'departureAddress', minWidth: 180 },
|
{ label: '发货地址', prop: 'departureAddress', minWidth: 180 },
|
||||||
{ label: '到货地址', prop: 'arrivalAddress', minWidth: 180 },
|
{ label: '到货地址', prop: 'arrivalAddress', minWidth: 180 },
|
||||||
@@ -52,6 +54,7 @@ export const settlementDetailColumns = [
|
|||||||
{ label: '运输总量', prop: 'transportQuantityText', minWidth: 120 },
|
{ label: '运输总量', prop: 'transportQuantityText', minWidth: 120 },
|
||||||
{ label: '里程(KM)', prop: 'mileage', minWidth: 120 },
|
{ label: '里程(KM)', prop: 'mileage', minWidth: 120 },
|
||||||
{ label: '批次号', prop: 'batchNo', minWidth: 130 },
|
{ label: '批次号', prop: 'batchNo', minWidth: 130 },
|
||||||
|
{ label: '计费方式', prop: 'billingType', minWidth: 130 },
|
||||||
{ label: '运输单价', prop: 'unitPrice', minWidth: 120, money: true },
|
{ label: '运输单价', prop: 'unitPrice', minWidth: 120, money: true },
|
||||||
{ label: '运费', prop: 'freightAmount', minWidth: 120, money: true },
|
{ label: '运费', prop: 'freightAmount', minWidth: 120, money: true },
|
||||||
{ label: '原金额', prop: 'originalAmount', minWidth: 120, money: true },
|
{ label: '原金额', prop: 'originalAmount', minWidth: 120, money: true },
|
||||||
@@ -94,5 +97,6 @@ export const candidateDetailColumns = [
|
|||||||
{ label: '货物名称', prop: 'cargoName', minWidth: 140 },
|
{ label: '货物名称', prop: 'cargoName', minWidth: 140 },
|
||||||
{ label: '货物类型', prop: 'cargoType', minWidth: 130 },
|
{ label: '货物类型', prop: 'cargoType', minWidth: 130 },
|
||||||
{ label: '批次号', prop: 'batchNo', minWidth: 120 },
|
{ label: '批次号', prop: 'batchNo', minWidth: 120 },
|
||||||
|
{ label: '计费方式', prop: 'billingType', minWidth: 130 },
|
||||||
{ label: '结算金额', prop: 'totalAmount', minWidth: 130, money: true },
|
{ label: '结算金额', prop: 'totalAmount', minWidth: 130, money: true },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const searchFields = [
|
|||||||
{ label: '货物名称', prop: 'cargoName', type: 'input' },
|
{ label: '货物名称', prop: 'cargoName', type: 'input' },
|
||||||
{ label: '合同编号', prop: 'contractNo', type: 'input' },
|
{ label: '合同编号', prop: 'contractNo', type: 'input' },
|
||||||
{ label: '合同名称', prop: 'contractName', type: 'input' },
|
{ label: '合同名称', prop: 'contractName', type: 'input' },
|
||||||
{ label: '预结算单号', prop: 'preSettlementNo', type: 'input' },
|
{ label: '预付结算单号', prop: 'preSettlementNo', type: 'input' },
|
||||||
{ label: '正式结算单号', prop: 'formalSettlementNo', type: 'input' },
|
{ label: '正式结算单号', prop: 'formalSettlementNo', type: 'input' },
|
||||||
{ label: '批次号', prop: 'batchNo', type: 'input' },
|
{ label: '批次号', prop: 'batchNo', type: 'input' },
|
||||||
{ label: '车号', prop: 'vehicleNo', type: 'input' },
|
{ label: '车号', prop: 'vehicleNo', type: 'input' },
|
||||||
@@ -35,7 +35,7 @@ export const tableColumns = [
|
|||||||
{ label: '合同编号', prop: 'contractNo', minWidth: 140 },
|
{ label: '合同编号', prop: 'contractNo', minWidth: 140 },
|
||||||
{ label: '合同名称', prop: 'contractName', minWidth: 140 },
|
{ label: '合同名称', prop: 'contractName', minWidth: 140 },
|
||||||
{ label: '来源', prop: 'sourceType', minWidth: 110 },
|
{ label: '来源', prop: 'sourceType', minWidth: 110 },
|
||||||
{ label: '预结算单号', prop: 'preSettlementNo', minWidth: 140, link: true },
|
{ label: '预付结算单号', prop: 'preSettlementNo', minWidth: 140, link: true },
|
||||||
{ label: '正式结算单号', prop: 'formalSettlementNo', minWidth: 140, link: true },
|
{ label: '正式结算单号', prop: 'formalSettlementNo', minWidth: 140, link: true },
|
||||||
{ label: '运单号', prop: 'waybillNo', minWidth: 140, link: true },
|
{ label: '运单号', prop: 'waybillNo', minWidth: 140, link: true },
|
||||||
{ label: '车号', prop: 'vehicleNo', minWidth: 120 },
|
{ label: '车号', prop: 'vehicleNo', minWidth: 120 },
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export const settlementAdjustmentTableColumns = [
|
export const settlementAdjustmentTableColumns = [
|
||||||
{ label: '单据号', prop: 'adjustmentNo', minWidth: 160, link: true, fixed: 'left' },
|
{ label: '单据号', prop: 'adjustmentNo', minWidth: 160, link: true, fixed: 'left' },
|
||||||
{ label: '结算单号', prop: 'formalSettlementNo', minWidth: 160 },
|
{ label: '结算单号', prop: 'formalSettlementNo', minWidth: 160, link: true },
|
||||||
{ label: '结算单类型', prop: 'settlementTypeName', minWidth: 110 },
|
{ label: '结算单类型', prop: 'settlementTypeName', minWidth: 110 },
|
||||||
{ label: '项目名称', prop: 'projectName', minWidth: 140 },
|
{ label: '项目名称', prop: 'projectName', minWidth: 140 },
|
||||||
{ label: '所属组织', prop: 'deptName', minWidth: 140 },
|
{ label: '所属组织', prop: 'deptName', minWidth: 140 },
|
||||||
@@ -9,6 +9,8 @@ export const settlementAdjustmentTableColumns = [
|
|||||||
{ label: '合同名称', prop: 'contractName', minWidth: 170 },
|
{ label: '合同名称', prop: 'contractName', minWidth: 170 },
|
||||||
{ label: '调整金额', prop: 'adjustmentAmount', minWidth: 130, money: true },
|
{ label: '调整金额', prop: 'adjustmentAmount', minWidth: 130, money: true },
|
||||||
{ label: '审核状态', prop: 'approvalStatusName', minWidth: 110, status: true },
|
{ label: '审核状态', prop: 'approvalStatusName', minWidth: 110, status: true },
|
||||||
|
{ label: '金蝶单据状态', prop: 'kingdeeSyncStatus', minWidth: 130, kingdee: true },
|
||||||
|
{ label: '金蝶单据号', prop: 'kingdeeBillNo', minWidth: 150 },
|
||||||
{ label: '当前节点', prop: 'currentNode', minWidth: 120 },
|
{ label: '当前节点', prop: 'currentNode', minWidth: 120 },
|
||||||
{ label: '当前处理人', prop: 'currentProcessor', minWidth: 130 },
|
{ label: '当前处理人', prop: 'currentProcessor', minWidth: 130 },
|
||||||
{ label: '创建人', prop: 'createUserName', minWidth: 110 },
|
{ label: '创建人', prop: 'createUserName', minWidth: 110 },
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
/**
|
||||||
|
* 导入结算单列表(avue-crud)配置
|
||||||
|
* ------------------------------------------------------------------
|
||||||
|
* 列表页与其它模块统一使用 avue-crud,头部 4 个按钮(刷新 / 列显隐 / 搜索显隐 /
|
||||||
|
* 显示方式)由 avue-crud 自带,不做二次封装。
|
||||||
|
*
|
||||||
|
* ⚠️ searchOrder 为降序排序,值越大越靠前。
|
||||||
|
* ⚠️ 仅用于搜索的列必须 hide + showColumn: false,否则会混进「列显隐」抽屉。
|
||||||
|
*/
|
||||||
|
|
||||||
|
const IMPORT_STATUS_OPTIONS = [
|
||||||
|
{ label: '草稿', value: 'draft' },
|
||||||
|
{ label: '已完成', value: 'completed' },
|
||||||
|
{ label: '已作废', value: 'voided' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const SETTLEMENT_TYPE_OPTIONS = [
|
||||||
|
{ label: '应收', value: 'receivable' },
|
||||||
|
{ label: '应付', value: 'payable' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const textFormatter = (row, value) =>
|
||||||
|
value === null || value === undefined || value === '' ? '-' : value;
|
||||||
|
|
||||||
|
const pickLabel = (options, value) =>
|
||||||
|
options.find(item => item.value === value)?.label || value || '-';
|
||||||
|
|
||||||
|
const settlementTypeLabel = value => pickLabel(SETTLEMENT_TYPE_OPTIONS, value);
|
||||||
|
|
||||||
|
const billTypeLabel = value => (value === 'pre' ? '预结算单' : value ? '正式结算单' : '-');
|
||||||
|
|
||||||
|
export const importStatusLabel = value => pickLabel(IMPORT_STATUS_OPTIONS, value);
|
||||||
|
|
||||||
|
export const settlementImportOption = () => ({
|
||||||
|
height: 'auto',
|
||||||
|
calcHeight: 32,
|
||||||
|
tip: false,
|
||||||
|
searchBtnText: '查询',
|
||||||
|
emptyBtnText: '重置',
|
||||||
|
searchShow: true,
|
||||||
|
searchIcon: true,
|
||||||
|
searchLabelWidth: 88,
|
||||||
|
// 查询/重置紧跟首行 4 个条件(4×5 + 菜单 4 = 24),不再独占下一整行
|
||||||
|
searchMenuSpan: 4,
|
||||||
|
searchIndex: 4,
|
||||||
|
searchMenuPosition: 'right',
|
||||||
|
border: true,
|
||||||
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
|
indexWidth: 64,
|
||||||
|
indexFixed: 'left',
|
||||||
|
selection: false,
|
||||||
|
addBtn: false,
|
||||||
|
viewBtn: false,
|
||||||
|
delBtn: false,
|
||||||
|
editBtn: false,
|
||||||
|
menuWidth: 220,
|
||||||
|
menuFixed: 'right',
|
||||||
|
column: [
|
||||||
|
// ---------- 搜索项(前 4 项默认展示,其余折叠;searchOrder 越大越靠前) ----------
|
||||||
|
{
|
||||||
|
label: '状态',
|
||||||
|
prop: 'importStatus',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchSpan: 5,
|
||||||
|
searchOrder: 6,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
dicData: IMPORT_STATUS_OPTIONS,
|
||||||
|
hide: true,
|
||||||
|
showColumn: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '导入类型',
|
||||||
|
prop: 'settlementType',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchSpan: 5,
|
||||||
|
searchOrder: 5,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
dicData: SETTLEMENT_TYPE_OPTIONS,
|
||||||
|
hide: true,
|
||||||
|
showColumn: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
// ---------- 表格列 ----------
|
||||||
|
{
|
||||||
|
label: '导入批次号',
|
||||||
|
prop: 'batchNo',
|
||||||
|
slot: true,
|
||||||
|
search: true,
|
||||||
|
searchSpan: 5,
|
||||||
|
searchOrder: 7,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{ label: '状态', prop: 'importStatusName', slot: true, width: 100, align: 'center' },
|
||||||
|
{
|
||||||
|
label: '导入类型',
|
||||||
|
prop: 'settlementTypeName',
|
||||||
|
minWidth: 100,
|
||||||
|
align: 'center',
|
||||||
|
formatter: (row, value) => value || settlementTypeLabel(row.settlementType),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '结算单',
|
||||||
|
prop: 'settlementBillTypeName',
|
||||||
|
minWidth: 110,
|
||||||
|
align: 'center',
|
||||||
|
formatter: (row, value) => value || billTypeLabel(row.settlementBillType),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目',
|
||||||
|
prop: 'projectName',
|
||||||
|
search: true,
|
||||||
|
searchSpan: 5,
|
||||||
|
searchOrder: 4,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
minWidth: 140,
|
||||||
|
formatter: textFormatter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '客户',
|
||||||
|
prop: 'customerName',
|
||||||
|
search: true,
|
||||||
|
searchSpan: 5,
|
||||||
|
searchOrder: 3,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
minWidth: 140,
|
||||||
|
formatter: textFormatter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '承运商',
|
||||||
|
prop: 'carrierName',
|
||||||
|
search: true,
|
||||||
|
searchSpan: 5,
|
||||||
|
searchOrder: 2,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
minWidth: 140,
|
||||||
|
formatter: textFormatter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '明细行数',
|
||||||
|
prop: 'detailCount',
|
||||||
|
width: 100,
|
||||||
|
align: 'center',
|
||||||
|
formatter: row => row.detailCount ?? row.waybillCount ?? 0,
|
||||||
|
},
|
||||||
|
{ label: '创建时间', prop: 'createTime', width: 180, align: 'center', formatter: textFormatter },
|
||||||
|
{ label: '创建人', prop: 'createUserName', minWidth: 110, formatter: textFormatter },
|
||||||
|
],
|
||||||
|
});
|
||||||
@@ -13,7 +13,7 @@ export const reconciliationStatusOptions = [
|
|||||||
|
|
||||||
export const transportReconciliationSearchFields = [
|
export const transportReconciliationSearchFields = [
|
||||||
{ prop: 'reconciliationNo', label: '对账单号', type: 'input' },
|
{ prop: 'reconciliationNo', label: '对账单号', type: 'input' },
|
||||||
{ prop: 'preSettlementNos', label: '预结算单号', type: 'input' },
|
{ prop: 'preSettlementNos', label: '预付结算单号', type: 'input' },
|
||||||
{ prop: 'projectName', label: '项目', type: 'input' },
|
{ prop: 'projectName', label: '项目', type: 'input' },
|
||||||
{ prop: 'deptName', label: '所属组织', type: 'cascader' },
|
{ prop: 'deptName', label: '所属组织', type: 'cascader' },
|
||||||
{ prop: 'contractNo', label: '合同编号', type: 'input' },
|
{ prop: 'contractNo', label: '合同编号', type: 'input' },
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ const validatePhone = (rule, value, callback) => {
|
|||||||
callback(new Error('请输入手机号'));
|
callback(new Error('请输入手机号'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 详情回显为脱敏手机号(含 *)时放行,未修改则提交时剔除该字段
|
||||||
|
if (phone.includes('*')) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!/^1\d{10}$/.test(phone)) {
|
if (!/^1\d{10}$/.test(phone)) {
|
||||||
callback(new Error('请输入正确的手机号'));
|
callback(new Error('请输入正确的手机号'));
|
||||||
return;
|
return;
|
||||||
@@ -121,6 +126,62 @@ export default {
|
|||||||
order: 60,
|
order: 60,
|
||||||
rules: [{ required: true, message: '请选择小程序身份', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择小程序身份', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '所属组织',
|
||||||
|
prop: 'deptId',
|
||||||
|
formslot: true,
|
||||||
|
hide: true,
|
||||||
|
span: 24,
|
||||||
|
order: 55,
|
||||||
|
// 所属组织可为空:为空表示未分配组织,账号的数据权限为空集
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属组织',
|
||||||
|
prop: 'deptName',
|
||||||
|
minWidth: 180,
|
||||||
|
overHidden: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
order: 54,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '数据权限范围',
|
||||||
|
prop: 'dataScopeRange',
|
||||||
|
type: 'radio',
|
||||||
|
span: 24,
|
||||||
|
hide: true,
|
||||||
|
order: 53,
|
||||||
|
value: 1,
|
||||||
|
dicData: [
|
||||||
|
{ label: '仅所属组织', value: 1 },
|
||||||
|
{ label: '全部组织', value: 2 },
|
||||||
|
{ label: '自定义', value: 3 },
|
||||||
|
],
|
||||||
|
rules: [{ required: true, message: '请选择数据权限范围', trigger: 'change' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '数据层级范围',
|
||||||
|
prop: 'dataLevelRange',
|
||||||
|
type: 'radio',
|
||||||
|
span: 24,
|
||||||
|
hide: true,
|
||||||
|
order: 52,
|
||||||
|
value: 1,
|
||||||
|
dicData: [
|
||||||
|
{ label: '包含下级', value: 1 },
|
||||||
|
{ label: '仅本级', value: 2 },
|
||||||
|
],
|
||||||
|
rules: [{ required: true, message: '请选择数据层级范围', trigger: 'change' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '数据权限',
|
||||||
|
prop: 'dataScopeDeptIds',
|
||||||
|
formslot: true,
|
||||||
|
span: 24,
|
||||||
|
hide: true,
|
||||||
|
order: 51,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '性别',
|
label: '性别',
|
||||||
prop: 'sex',
|
prop: 'sex',
|
||||||
@@ -142,10 +203,9 @@ export default {
|
|||||||
overHidden: true,
|
overHidden: true,
|
||||||
hide: true,
|
hide: true,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: true,
|
editDisplay: false,
|
||||||
viewDisplay: true,
|
viewDisplay: true,
|
||||||
order: 40,
|
order: 40,
|
||||||
placeholder: '可清空以解绑微信',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '状态',
|
label: '状态',
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ export const userOption = safe => {
|
|||||||
},
|
},
|
||||||
{ label: '岗位', prop: 'postName', overHidden: true, display: false },
|
{ label: '岗位', prop: 'postName', overHidden: true, display: false },
|
||||||
{ label: '性别', prop: 'sexName', width: 80, display: false },
|
{ label: '性别', prop: 'sexName', width: 80, display: false },
|
||||||
|
{ label: 'OA登录名', prop: 'oaLoginId', minWidth: 140, overHidden: true, display: false },
|
||||||
{ label: 'OA人员id', prop: 'oaPersonId', minWidth: 120, overHidden: true, display: false },
|
{ label: 'OA人员id', prop: 'oaPersonId', minWidth: 120, overHidden: true, display: false },
|
||||||
{ label: '备注', prop: 'remark', minWidth: 160, overHidden: true, display: false },
|
{ label: '备注', prop: 'remark', minWidth: 160, overHidden: true, display: false },
|
||||||
{
|
{
|
||||||
@@ -314,29 +315,6 @@ export const userOption = safe => {
|
|||||||
{ label: '承运商', value: 2 },
|
{ label: '承运商', value: 2 },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '数据权限范围',
|
|
||||||
prop: 'dataScopeRange',
|
|
||||||
type: 'radio',
|
|
||||||
span: 24,
|
|
||||||
value: 1,
|
|
||||||
dicData: [
|
|
||||||
{ label: '仅所属组织', value: 1 },
|
|
||||||
{ label: '全部组织', value: 2 },
|
|
||||||
{ label: '自定义', value: 3 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '数据层级范围',
|
|
||||||
prop: 'dataLevelRange',
|
|
||||||
type: 'radio',
|
|
||||||
span: 24,
|
|
||||||
value: 1,
|
|
||||||
dicData: [
|
|
||||||
{ label: '包含下级', value: 1 },
|
|
||||||
{ label: '仅本级', value: 2 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '备注',
|
label: '备注',
|
||||||
prop: 'remark',
|
prop: 'remark',
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export const option = {
|
|||||||
searchOrder: 1,
|
searchOrder: 1,
|
||||||
searchslot: true,
|
searchslot: true,
|
||||||
slot: true,
|
slot: true,
|
||||||
|
overHidden: true,
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -55,6 +56,8 @@ export const option = {
|
|||||||
prop: 'useDepartment',
|
prop: 'useDepartment',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 3,
|
searchOrder: 3,
|
||||||
|
slot: true,
|
||||||
|
overHidden: true,
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,6 +95,17 @@ export default [
|
|||||||
bizType: 'project-apply',
|
bizType: 'project-apply',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/business/project-change/public-view',
|
||||||
|
name: '查看项目变更信息',
|
||||||
|
component: () => import('@/views/business/project-apply-public-view.vue'),
|
||||||
|
meta: {
|
||||||
|
keepAlive: false,
|
||||||
|
isTab: false,
|
||||||
|
isAuth: false,
|
||||||
|
bizType: 'project-change',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/business/contract-manage/public-view',
|
path: '/business/contract-manage/public-view',
|
||||||
name: '查看合同信息',
|
name: '查看合同信息',
|
||||||
@@ -106,9 +117,20 @@ export default [
|
|||||||
bizType: 'contract-manage',
|
bizType: 'contract-manage',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/business/contract-change/public-view',
|
||||||
|
name: '查看合同变更信息',
|
||||||
|
component: () => import('@/views/business/contract-change-public-view.vue'),
|
||||||
|
meta: {
|
||||||
|
keepAlive: false,
|
||||||
|
isTab: false,
|
||||||
|
isAuth: false,
|
||||||
|
bizType: 'contract-change',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/settlement/pre-settlement/public-view',
|
path: '/settlement/pre-settlement/public-view',
|
||||||
name: '查看预结算信息',
|
name: '查看预付结算单信息',
|
||||||
component: () => import('@/views/settlement/pre-settlement-public-view.vue'),
|
component: () => import('@/views/settlement/pre-settlement-public-view.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
keepAlive: false,
|
keepAlive: false,
|
||||||
@@ -119,7 +141,7 @@ export default [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/settlement/formal-settlement/public-view',
|
path: '/settlement/formal-settlement/public-view',
|
||||||
name: '查看正式结算信息',
|
name: '查看结算单信息',
|
||||||
component: () => import('@/views/settlement/formal-settlement-public-view.vue'),
|
component: () => import('@/views/settlement/formal-settlement-public-view.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
keepAlive: false,
|
keepAlive: false,
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export default [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
name: '新增编辑预结算',
|
name: '新增编辑预付结算单',
|
||||||
meta: {
|
meta: {
|
||||||
keepAlive: false,
|
keepAlive: false,
|
||||||
activeMenu: '/settlement/pre-settlement',
|
activeMenu: '/settlement/pre-settlement',
|
||||||
@@ -104,21 +104,85 @@ export default [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// 兼容旧菜单路径:按 detailNo 解析应付/应收后跳转到拆分后的列表页
|
||||||
|
path: '/settlement/formal-settlement',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: '正式结算单兼容跳转',
|
||||||
|
meta: {
|
||||||
|
keepAlive: false,
|
||||||
|
activeMenu: '/settlement/payment-settlement',
|
||||||
|
},
|
||||||
|
component: loadView(() => import('@/views/settlement/formal-settlement-redirect.vue')),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/settlement/formal-settlement/form',
|
path: '/settlement/formal-settlement/form',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
name: '新增编辑正式结算',
|
name: '新增编辑结算单',
|
||||||
meta: {
|
meta: {
|
||||||
keepAlive: false,
|
keepAlive: false,
|
||||||
activeMenu: '/settlement/formal-settlement',
|
// 付款结算单表单入口,高亮付款结算单菜单
|
||||||
|
activeMenu: '/settlement/payment-settlement',
|
||||||
},
|
},
|
||||||
component: loadView(() => import('@/views/settlement/formal-settlement-form.vue')),
|
component: loadView(() => import('@/views/settlement/formal-settlement-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// 收款结算单表单入口:与付款结算单共用表单组件,仅高亮菜单不同
|
||||||
|
path: '/settlement/receipt-settlement/form',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: '新增编辑收款结算单',
|
||||||
|
meta: {
|
||||||
|
keepAlive: false,
|
||||||
|
activeMenu: '/settlement/receipt-settlement',
|
||||||
|
},
|
||||||
|
component: loadView(() => import('@/views/settlement/formal-settlement-form.vue')),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 付款结算单表单入口:与 settlementListPath('payable') + '/form' 对应
|
||||||
|
path: '/settlement/payment-settlement/form',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: '新增编辑付款结算单',
|
||||||
|
meta: {
|
||||||
|
keepAlive: false,
|
||||||
|
activeMenu: '/settlement/payment-settlement',
|
||||||
|
},
|
||||||
|
component: loadView(() => import('@/views/settlement/formal-settlement-form.vue')),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settlement/settlement-import/form',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: '新增导入结算单',
|
||||||
|
meta: {
|
||||||
|
keepAlive: false,
|
||||||
|
activeMenu: '/settlement/settlement-import',
|
||||||
|
},
|
||||||
|
component: loadView(() => import('@/views/settlement/settlement-import-form.vue')),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/settlement/transport-reconciliation/form',
|
path: '/settlement/transport-reconciliation/form',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
@@ -182,6 +246,18 @@ export default [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/business/project-change/form',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: '项目变更表单',
|
||||||
|
meta: { keepAlive: false, activeMenu: '/business/project-change' },
|
||||||
|
component: loadView(() => import('@/views/business/project-apply.vue')),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/business/waybill-manage/form',
|
path: '/business/waybill-manage/form',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
@@ -326,6 +402,18 @@ export default [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/business/contract-change/form',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: '合同变更表单',
|
||||||
|
meta: { keepAlive: false, activeMenu: '/business/contract-change' },
|
||||||
|
component: loadView(() => import('@/views/business/contract-manage-change.vue')),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/wel',
|
path: '/wel',
|
||||||
component: () =>
|
component: () =>
|
||||||
|
|||||||
@@ -622,7 +622,7 @@
|
|||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 合同管理新增/编辑弹窗(business-crud-page 封装 → avue-crud,弹窗带 avue-crud__dialog class)
|
// 合同管理新增/编辑弹窗(avue-crud,弹窗带 avue-crud__dialog class)
|
||||||
// 复刻 waybill-manage 方案:接近全屏、压过库内置 .avue-dialog 的 calc(100% - 200px),
|
// 复刻 waybill-manage 方案:接近全屏、压过库内置 .avue-dialog 的 calc(100% - 200px),
|
||||||
// 并解开 body 的 200px 上限、抵消全局 footer 的 -30px 上移
|
// 并解开 body 的 200px 上限、抵消全局 footer 的 -30px 上移
|
||||||
.contract-manage-dialog.el-dialog {
|
.contract-manage-dialog.el-dialog {
|
||||||
|
|||||||
@@ -26,6 +26,35 @@ const uniqueOrgNames = (values = []) => {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 候选司机取数上限:超出后只能靠关键字缩小范围
|
||||||
|
const DRIVER_CANDIDATE_MAX_SIZE = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 派单候选司机:租户内的司机档案,按岗位等条件过滤。
|
||||||
|
*
|
||||||
|
* 与组织、承运商都无关——司机档案与组织树、承运商之间没有外键,`organization_name`
|
||||||
|
* 只是自由文本,用它做匹配会让小程序自动建档的司机永远进不了候选。
|
||||||
|
*/
|
||||||
|
export const fetchDriverCandidates = async (query = {}) => {
|
||||||
|
const params = { ...query };
|
||||||
|
const size = Math.min(Math.max(Number(params.size) || 50, 50), DRIVER_CANDIDATE_MAX_SIZE);
|
||||||
|
delete params.size;
|
||||||
|
const res = await getDriverList(1, size, params);
|
||||||
|
return extractRecords(res).slice(0, size);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 司机候选项的展示文本:姓名(手机尾号后 4 位)。
|
||||||
|
*
|
||||||
|
* 只用于下拉渲染。写回表单的仍是姓名本身,别把带尾号的文本当值用。
|
||||||
|
*/
|
||||||
|
export const driverOptionText = (item = {}) => {
|
||||||
|
const name = normalizeOrgName(item.driverName || item.name);
|
||||||
|
const mobile = String(item.mobile || item.phone || item.driverPhone || '').trim();
|
||||||
|
if (!name) return '';
|
||||||
|
return mobile.length >= 4 ? `${name}(${mobile.slice(-4)})` : name;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析承运商客商档案上联系人的所属组织(branchName),无联系人时回退客商所属组织。
|
* 解析承运商客商档案上联系人的所属组织(branchName),无联系人时回退客商所属组织。
|
||||||
*/
|
*/
|
||||||
@@ -72,13 +101,6 @@ export const resolveCarrierOrganizationNames = async ({ carrierId, carrierName }
|
|||||||
return orgNames;
|
return orgNames;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const clearCarrierOrganizationCache = (carrier = {}) => {
|
|
||||||
const id = String(carrier.carrierId || '').trim();
|
|
||||||
const name = normalizeOrgName(carrier.carrierName);
|
|
||||||
if (id) orgNameCache.delete(id);
|
|
||||||
if (name) orgNameCache.delete(name);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const matchOrganizationName = (value, orgNames = []) => {
|
export const matchOrganizationName = (value, orgNames = []) => {
|
||||||
const text = normalizeOrgName(value);
|
const text = normalizeOrgName(value);
|
||||||
if (!text || !orgNames.length) return false;
|
if (!text || !orgNames.length) return false;
|
||||||
@@ -90,34 +112,9 @@ const filterByOrganizations = (records = [], orgNames = []) => {
|
|||||||
return records.filter(item => matchOrganizationName(item.organizationName, orgNames));
|
return records.filter(item => matchOrganizationName(item.organizationName, orgNames));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 按承运商联系人所属组织筛选司机。
|
|
||||||
* 未选择承运商时返回空列表(需先选承运商)。
|
|
||||||
*/
|
|
||||||
export const fetchDriversByCarrierOrganizations = async (
|
|
||||||
query = {},
|
|
||||||
{ carrierId, carrierName } = {}
|
|
||||||
) => {
|
|
||||||
if (!String(carrierId || '').trim() && !normalizeOrgName(carrierName)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const orgNames = await resolveCarrierOrganizationNames({ carrierId, carrierName });
|
|
||||||
if (!orgNames.length) return [];
|
|
||||||
|
|
||||||
const size = Math.max(Number(query.size) || 50, 50);
|
|
||||||
const params = { ...query };
|
|
||||||
delete params.size;
|
|
||||||
// 单组织时用后端模糊条件缩小范围;多组织再前端精确过滤
|
|
||||||
if (orgNames.length === 1) {
|
|
||||||
params.organizationName = orgNames[0];
|
|
||||||
}
|
|
||||||
const res = await getDriverList(1, Math.min(size * 5, 200), params);
|
|
||||||
return filterByOrganizations(extractRecords(res), orgNames).slice(0, size);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按承运商联系人所属组织筛选车辆。
|
* 按承运商联系人所属组织筛选车辆。
|
||||||
* 未选择承运商时返回空列表。
|
* 未选择承运商时返回空列表(需先选承运商)。
|
||||||
*/
|
*/
|
||||||
export const fetchVehiclesByCarrierOrganizations = async (
|
export const fetchVehiclesByCarrierOrganizations = async (
|
||||||
query = {},
|
query = {},
|
||||||
|
|||||||
@@ -106,6 +106,9 @@ const CERT_SNAPSHOT_GROUPS = {
|
|||||||
fields: [
|
fields: [
|
||||||
{ key: 'realName', label: '真实姓名' },
|
{ key: 'realName', label: '真实姓名' },
|
||||||
{ key: 'idCardNo', label: '身份证号' },
|
{ key: 'idCardNo', label: '身份证号' },
|
||||||
|
{ key: 'birthday', label: '出生年月', type: TYPE_DATE },
|
||||||
|
{ key: 'addressRegion', label: '住址' },
|
||||||
|
{ key: 'address', label: '详细地址' },
|
||||||
{ key: 'idCardFrontUrl', label: '身份证正面照', type: TYPE_IMAGE },
|
{ key: 'idCardFrontUrl', label: '身份证正面照', type: TYPE_IMAGE },
|
||||||
{ key: 'idCardBackUrl', label: '身份证反面照', type: TYPE_IMAGE },
|
{ key: 'idCardBackUrl', label: '身份证反面照', type: TYPE_IMAGE },
|
||||||
{ key: 'idCardValidStart', label: '身份证有效期起', type: TYPE_DATE },
|
{ key: 'idCardValidStart', label: '身份证有效期起', type: TYPE_DATE },
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'nprogress/nprogress.css';
|
|||||||
const excelPattern = /\.(xls|xlsx)$/;
|
const excelPattern = /\.(xls|xlsx)$/;
|
||||||
|
|
||||||
/** 是否为浏览器 Blob(含跨 realm 的 Blob-like) */
|
/** 是否为浏览器 Blob(含跨 realm 的 Blob-like) */
|
||||||
const isBlobLike = value =>
|
export const isBlobLike = value =>
|
||||||
value != null &&
|
value != null &&
|
||||||
typeof value === 'object' &&
|
typeof value === 'object' &&
|
||||||
typeof value.size === 'number' &&
|
typeof value.size === 'number' &&
|
||||||
@@ -15,14 +15,14 @@ const isBlobLike = value =>
|
|||||||
(typeof value.text === 'function' || typeof value.arrayBuffer === 'function');
|
(typeof value.text === 'function' || typeof value.arrayBuffer === 'function');
|
||||||
|
|
||||||
/** axios 拦截器已把 JSON Blob 解析成的业务对象 */
|
/** axios 拦截器已把 JSON Blob 解析成的业务对象 */
|
||||||
const isBusinessJson = value =>
|
export const isBusinessJson = value =>
|
||||||
value != null &&
|
value != null &&
|
||||||
typeof value === 'object' &&
|
typeof value === 'object' &&
|
||||||
!isBlobLike(value) &&
|
!isBlobLike(value) &&
|
||||||
!(value instanceof ArrayBuffer) &&
|
!(value instanceof ArrayBuffer) &&
|
||||||
('code' in value || 'success' in value || 'msg' in value);
|
('code' in value || 'success' in value || 'msg' in value);
|
||||||
|
|
||||||
const isExcelResponse = res => {
|
export const isExcelResponse = res => {
|
||||||
// 已是业务 JSON(导入成功/失败提示)时,绝不能当失败明细 Excel 处理
|
// 已是业务 JSON(导入成功/失败提示)时,绝不能当失败明细 Excel 处理
|
||||||
if (isBusinessJson(res?.data)) {
|
if (isBusinessJson(res?.data)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -54,7 +54,7 @@ const isExcelResponse = res => {
|
|||||||
* 提前解析成普通对象;此处需同时兼容 Blob / 字符串 / 已解析对象,避免再调
|
* 提前解析成普通对象;此处需同时兼容 Blob / 字符串 / 已解析对象,避免再调
|
||||||
* `blob.text()` 时出现「blob.text is not a function」。
|
* `blob.text()` 时出现「blob.text is not a function」。
|
||||||
*/
|
*/
|
||||||
const parseBlobJson = async data => {
|
export const parseBlobJson = async data => {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ const parseBlobJson = async data => {
|
|||||||
*
|
*
|
||||||
* 这里补上这一步:从错误响应的 Blob 里取出后端 `msg`,取不到再退回通用文案。
|
* 这里补上这一步:从错误响应的 Blob 里取出后端 `msg`,取不到再退回通用文案。
|
||||||
*/
|
*/
|
||||||
const resolveErrorMessage = async error => {
|
export const resolveImportErrorMessage = async error => {
|
||||||
const payload = error?.response?.data ?? error?.data;
|
const payload = error?.response?.data ?? error?.data;
|
||||||
if (isBusinessJson(payload) && payload.msg) {
|
if (isBusinessJson(payload) && payload.msg) {
|
||||||
return payload.msg;
|
return payload.msg;
|
||||||
@@ -109,6 +109,26 @@ const resolveErrorMessage = async error => {
|
|||||||
return fallback;
|
return fallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一消费导入接口响应:成功 JSON / 失败 Excel 流。
|
||||||
|
* 兼容 axios 已把 JSON Blob 解析成对象的情况,禁止再对普通对象调 .text()。
|
||||||
|
*/
|
||||||
|
export const consumeImportResponse = async (res, options = {}) => {
|
||||||
|
const { businessName = '导入', dayjsFormat } = options;
|
||||||
|
if (isExcelResponse(res)) {
|
||||||
|
return {
|
||||||
|
kind: 'excel',
|
||||||
|
blob: res?.data,
|
||||||
|
fileName: `${businessName}导入失败明细${dayjsFormat || ''}.xlsx`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const result = isBusinessJson(res?.data) ? res.data : await parseBlobJson(res?.data);
|
||||||
|
if (Number(result?.code) !== 200) {
|
||||||
|
throw new Error(result?.msg || '导入失败');
|
||||||
|
}
|
||||||
|
return { kind: 'success', result };
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加工后端返回的导入失败明细 Excel。
|
* 加工后端返回的导入失败明细 Excel。
|
||||||
* 若传入 failDetailDecorator(函数),则动态加载 exceljs 读取 blob 流,
|
* 若传入 failDetailDecorator(函数),则动态加载 exceljs 读取 blob 流,
|
||||||
@@ -235,7 +255,7 @@ export const handleImportExcel = async (vm, option, column, businessName, onSucc
|
|||||||
// 拦截器已提示过的错误(如后端 400 返回的业务提示)不再重复弹一次,
|
// 拦截器已提示过的错误(如后端 400 返回的业务提示)不再重复弹一次,
|
||||||
// 只保留一次清晰的中文提示。
|
// 只保留一次清晰的中文提示。
|
||||||
if (!error?._notified) {
|
if (!error?._notified) {
|
||||||
vm.$message.error(await resolveErrorMessage(error));
|
vm.$message.error(await resolveImportErrorMessage(error));
|
||||||
}
|
}
|
||||||
notifyUploadError(option, error);
|
notifyUploadError(option, error);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* 金蝶单据状态公共映射
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 金蝶单据状态 → el-tag 颜色类型(failed 状态列表页悬浮展示失败原因) */
|
||||||
|
export const KINGDEE_STATUS_TAG_TYPES = {
|
||||||
|
synced: 'success',
|
||||||
|
paid: 'success',
|
||||||
|
invoiced: 'success',
|
||||||
|
paying: 'warning',
|
||||||
|
failed: 'danger',
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 金蝶单据状态 → el-tag 颜色类型,未映射状态返回 info */
|
||||||
|
export const kingdeeStatusType = status => KINGDEE_STATUS_TAG_TYPES[status] || 'info';
|
||||||
|
|
||||||
|
/** 金蝶冲销状态 → el-tag 颜色类型(已冲销=绿、未冲销=黄) */
|
||||||
|
export const KINGDEE_WRITEOFF_TAG_TYPES = {
|
||||||
|
writtenoff: 'success',
|
||||||
|
unwrittenoff: 'warning',
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 金蝶冲销状态 → el-tag 颜色类型,未映射状态(null=未校验)返回 info */
|
||||||
|
export const kingdeeWriteOffTagType = status => KINGDEE_WRITEOFF_TAG_TYPES[status] || 'info';
|
||||||
+85
-15
@@ -15,15 +15,27 @@ export const MK_BIZ = {
|
|||||||
rejected: ['rejected', 'change_rejected', 'withdrawn'],
|
rejected: ['rejected', 'change_rejected', 'withdrawn'],
|
||||||
approved: ['approved', 'change_approved'],
|
approved: ['approved', 'change_approved'],
|
||||||
},
|
},
|
||||||
|
'project-change': {
|
||||||
|
dictName: '提交项目变更审核流',
|
||||||
|
subjectPrefix: '项目变更审批',
|
||||||
|
rejected: ['rejected', 'withdrawn'],
|
||||||
|
approved: ['approved'],
|
||||||
|
},
|
||||||
'contract-manage': {
|
'contract-manage': {
|
||||||
dictName: '提交合同审核流',
|
dictName: '提交合同审核流',
|
||||||
subjectPrefix: '合同审批',
|
subjectPrefix: '合同审批',
|
||||||
rejected: ['rejected', 'change_rejected', 'withdrawn'],
|
rejected: ['rejected', 'change_rejected', 'withdrawn'],
|
||||||
approved: ['approved', 'change_approved'],
|
approved: ['approved', 'change_approved'],
|
||||||
},
|
},
|
||||||
|
'contract-change': {
|
||||||
|
dictName: '提交合同变更审核流',
|
||||||
|
subjectPrefix: '合同变更审批',
|
||||||
|
rejected: ['rejected', 'withdrawn'],
|
||||||
|
approved: ['approved'],
|
||||||
|
},
|
||||||
'pre-settlement': {
|
'pre-settlement': {
|
||||||
dictName: '提交预结算审核流',
|
dictName: '提交预结算审核流',
|
||||||
subjectPrefix: '预结算审批',
|
subjectPrefix: '预付结算审批',
|
||||||
rejected: ['returned'],
|
rejected: ['returned'],
|
||||||
approved: ['approved'],
|
approved: ['approved'],
|
||||||
},
|
},
|
||||||
@@ -61,9 +73,18 @@ export const MK_BIZ = {
|
|||||||
|
|
||||||
const MK_SWITCH_NAME = '开启MK';
|
const MK_SWITCH_NAME = '开启MK';
|
||||||
|
|
||||||
async function loadMkTemplateList() {
|
/** 进程内缓存,避免每次提交都打字典;登录后同一会话开关一般不变 */
|
||||||
|
let mkEnabledCache = null;
|
||||||
|
let mkEnabledPromise = null;
|
||||||
|
let mkTemplateListCache = null;
|
||||||
|
|
||||||
|
async function loadMkTemplateList(force = false) {
|
||||||
|
if (!force && mkTemplateListCache) {
|
||||||
|
return mkTemplateListCache;
|
||||||
|
}
|
||||||
const res = await getDictionary({ code: 'mk_template' });
|
const res = await getDictionary({ code: 'mk_template' });
|
||||||
return res?.data?.data || [];
|
mkTemplateListCache = res?.data?.data || [];
|
||||||
|
return mkTemplateListCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 业务字典 mk_template:名称「开启MK」且键值为 1 时才请求 MK */
|
/** 业务字典 mk_template:名称「开启MK」且键值为 1 时才请求 MK */
|
||||||
@@ -72,10 +93,37 @@ export function isMkEnabled(list = []) {
|
|||||||
return String(matched?.dictKey ?? '').trim() === '1';
|
return String(matched?.dictKey ?? '').trim() === '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 加载业务字典并判断是否开启 MK */
|
/** 清除 MK 开关缓存(字典变更后可调用) */
|
||||||
export async function loadMkEnabled() {
|
export function clearMkEnabledCache() {
|
||||||
const list = await loadMkTemplateList();
|
mkEnabledCache = null;
|
||||||
return isMkEnabled(list);
|
mkEnabledPromise = null;
|
||||||
|
mkTemplateListCache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载业务字典并判断是否开启 MK
|
||||||
|
* @param {boolean} [force=false] 是否强制刷新缓存
|
||||||
|
*/
|
||||||
|
export async function loadMkEnabled(force = false) {
|
||||||
|
if (!force && mkEnabledCache !== null) {
|
||||||
|
return mkEnabledCache;
|
||||||
|
}
|
||||||
|
if (!force && mkEnabledPromise) {
|
||||||
|
return mkEnabledPromise;
|
||||||
|
}
|
||||||
|
mkEnabledPromise = loadMkTemplateList(force)
|
||||||
|
.then(list => {
|
||||||
|
mkEnabledCache = isMkEnabled(list);
|
||||||
|
return mkEnabledCache;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
mkEnabledCache = false;
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
mkEnabledPromise = null;
|
||||||
|
});
|
||||||
|
return mkEnabledPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveMkTemplateCode(dictName, list) {
|
export async function resolveMkTemplateCode(dictName, list) {
|
||||||
@@ -99,19 +147,24 @@ export function isMkApprovedStatus(bizType, approvalStatus) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交 MK 审核流
|
* 提交 MK 审核流。未开启 MK 时直接跳过,不请求流程实例相关接口。
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
* @param {string} options.bizType 业务类型
|
* @param {string} options.bizType 业务类型
|
||||||
* @param {string|number} options.bizId 业务主键(后端据此生成/复用 formInstanceId)
|
* @param {string|number} options.bizId 业务主键
|
||||||
* @param {string} [options.subjectName] 标题后缀
|
* @param {string} [options.subjectName] 标题后缀
|
||||||
* @param {string} [options.approvalStatus] 提交前的审批状态(须在业务 submit 改状态前取值;通过态强制新建实例)
|
* @param {string} [options.approvalStatus] 提交前的审批状态
|
||||||
|
* @param {boolean} [options.mkEnabled] 调用方已知开关时传入,false 时立即跳过
|
||||||
|
* @param {Object} [options.tempVarData] 传给 MK 的临时变量(如项目类型 projectType)
|
||||||
|
* @returns {Promise<boolean>} true=已发起/复用 MK 流程,false=未开启或已跳过
|
||||||
*/
|
*/
|
||||||
export async function submitMkApprovalFlow({
|
export async function submitMkApprovalFlow({
|
||||||
bizType,
|
bizType,
|
||||||
bizId,
|
bizId,
|
||||||
subjectName = '',
|
subjectName = '',
|
||||||
approvalStatus = '',
|
approvalStatus = '',
|
||||||
}) {
|
mkEnabled,
|
||||||
|
tempVarData,
|
||||||
|
} = {}) {
|
||||||
const conf = MK_BIZ[bizType];
|
const conf = MK_BIZ[bizType];
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return Promise.reject(new Error(`不支持的MK业务类型:${bizType}`));
|
return Promise.reject(new Error(`不支持的MK业务类型:${bizType}`));
|
||||||
@@ -119,17 +172,29 @@ export async function submitMkApprovalFlow({
|
|||||||
if (bizId == null || bizId === '') {
|
if (bizId == null || bizId === '') {
|
||||||
return Promise.reject(new Error('业务id不能为空'));
|
return Promise.reject(new Error('业务id不能为空'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 调用方显式关闭,或字典未开启:不请求 hasMkProcessInstance / processSubmit 等 MK 接口
|
||||||
|
if (mkEnabled === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const enabled = mkEnabled === true ? true : await loadMkEnabled();
|
||||||
|
if (!enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const list = await loadMkTemplateList();
|
const list = await loadMkTemplateList();
|
||||||
if (!isMkEnabled(list)) {
|
if (!isMkEnabled(list)) {
|
||||||
return;
|
mkEnabledCache = false;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bizIdText = String(bizId);
|
const bizIdText = String(bizId);
|
||||||
const forceNewFormInstance = isMkApprovedStatus(bizType, approvalStatus);
|
const forceNewFormInstance = isMkApprovedStatus(bizType, approvalStatus);
|
||||||
// 审核通过后再提交必须新建流程;其余场景已有有效实例则跳过
|
// 审核通过后再提交必须新建流程;其余场景已有有效实例则跳过
|
||||||
if (!forceNewFormInstance) {
|
if (!forceNewFormInstance) {
|
||||||
const existsRes = await hasMkProcessInstance({ bizId: bizIdText });
|
const existsRes = await hasMkProcessInstance({ bizId: bizIdText });
|
||||||
if (existsRes?.data?.data) {
|
if (existsRes?.data?.data) {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((conf.rejected || []).includes(approvalStatus)) {
|
if ((conf.rejected || []).includes(approvalStatus)) {
|
||||||
@@ -139,11 +204,16 @@ export async function submitMkApprovalFlow({
|
|||||||
const subject = subjectName
|
const subject = subjectName
|
||||||
? `${conf.subjectPrefix}:${subjectName}`
|
? `${conf.subjectPrefix}:${subjectName}`
|
||||||
: `${conf.subjectPrefix}:${bizIdText}`;
|
: `${conf.subjectPrefix}:${bizIdText}`;
|
||||||
return processSubmit({
|
const submitPayload = {
|
||||||
templateCode,
|
templateCode,
|
||||||
bizId: bizIdText,
|
bizId: bizIdText,
|
||||||
subject,
|
subject,
|
||||||
bizType,
|
bizType,
|
||||||
forceNewFormInstance,
|
forceNewFormInstance,
|
||||||
});
|
};
|
||||||
|
if (tempVarData != null && typeof tempVarData === 'object') {
|
||||||
|
submitPayload.tempVarData = tempVarData;
|
||||||
|
}
|
||||||
|
await processSubmit(submitPayload);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* 客商/合同风险标签公共展示逻辑(黑名单=金蝶黑名单 A801-5 命中,与后端 HcsCreditCheckSupport 口径一致):
|
||||||
|
* 等级与黑名单组合展示、等级在前;内部组织客商默认无风险
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 金蝶黑名单命中判定(客商档案行:失信类别/列入事由任一非空) */
|
||||||
|
export function isKingdeeBlack(category, reason) {
|
||||||
|
return !!(category || reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 合同行黑名单判定(推送链路按金蝶命中口径落库 kingdeeBlackStatus=yes) */
|
||||||
|
export function isContractBlack(blackStatus) {
|
||||||
|
return String(blackStatus || '').toLowerCase() === 'yes';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 风险标签文案:riskLevel=C101-1 等级(0/1/2);isBlack=金蝶黑名单命中;customerKind=internal 显示"无风险" */
|
||||||
|
export function resolveRiskTagName(riskLevel, isBlack, customerKind) {
|
||||||
|
const levelName = { 2: '高风险', 1: '中风险', 0: '低风险' }[riskLevel] || '';
|
||||||
|
if (isBlack) return levelName ? `${levelName}、黑名单` : '黑名单';
|
||||||
|
if (levelName) return levelName;
|
||||||
|
if (customerKind === 'internal') return '无风险';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否红色风险标签(黑名单命中或高风险) */
|
||||||
|
export function isRiskyTag(riskLevel, isBlack) {
|
||||||
|
return isBlack || riskLevel === '2';
|
||||||
|
}
|
||||||
@@ -1,3 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* 合并列表搜索条件:新条件覆盖旧条件,本次显式清空的字段从查询中移除。
|
||||||
|
*/
|
||||||
|
export const applyIncomingSearch = (current = {}, incoming = {}) => {
|
||||||
|
const merged = { ...current, ...incoming };
|
||||||
|
Object.keys(incoming || {}).forEach(key => {
|
||||||
|
const value = incoming[key];
|
||||||
|
if (
|
||||||
|
value === '' ||
|
||||||
|
value === null ||
|
||||||
|
value === undefined ||
|
||||||
|
(Array.isArray(value) && value.length === 0)
|
||||||
|
) {
|
||||||
|
delete merged[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return merged;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启停状态下拉「全部」在数字类型下会被转成 0/-1,不能当作查询条件。
|
||||||
|
* 状态 0 表示草稿等有效值的页面不要调用。
|
||||||
|
*/
|
||||||
|
export const omitInvalidListStatus = (params = {}) => {
|
||||||
|
const values = { ...params };
|
||||||
|
const status = values.status;
|
||||||
|
if (status === 0 || status === '0' || status === -1 || status === '-1') {
|
||||||
|
delete values.status;
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
|
||||||
export const normalizeSearchRangeParams = (params = {}, rangeMap = {}) => {
|
export const normalizeSearchRangeParams = (params = {}, rangeMap = {}) => {
|
||||||
const values = { ...params };
|
const values = { ...params };
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
export function isFreightFeeName(name) {
|
||||||
|
const text = String(name || '');
|
||||||
|
return text.includes('运费') || text.includes('运输费');
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseBillingRules(row = {}) {
|
||||||
|
const rule = row.billingRule || {};
|
||||||
|
const nested = Array.isArray(rule.rules) ? rule.rules : [];
|
||||||
|
if (nested.length) return nested;
|
||||||
|
const raw = row.billingRulesJson ?? row.billingRules;
|
||||||
|
if (Array.isArray(raw)) return raw.filter(item => item && typeof item === 'object');
|
||||||
|
if (typeof raw === 'string' && raw.trim()) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
return Array.isArray(parsed) ? parsed.filter(item => item && typeof item === 'object') : [];
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 运输单价对应的运费计费类型。 */
|
||||||
|
export function freightBillingType(row = {}) {
|
||||||
|
const rule = row.billingRule || {};
|
||||||
|
const rules = parseBillingRules(row);
|
||||||
|
const freightRule = rules.find(
|
||||||
|
item => isFreightFeeName(item?.feeItem) || isFreightFeeName(item?.feeType)
|
||||||
|
);
|
||||||
|
return freightRule?.billingType || row.billingType || rule.billingType || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTierUnitPrice(row) {
|
||||||
|
return freightBillingType(row) === '阶梯单价';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isIntervalBilling(row) {
|
||||||
|
const type = freightBillingType(row);
|
||||||
|
return type === '区间单价' || (type.includes('区间') && type.includes('一口价'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 阶梯单价、区间单价、区间一口价的运输单价不开放手工调整。 */
|
||||||
|
export function isUnitPriceAdjustable(row) {
|
||||||
|
const type = freightBillingType(row);
|
||||||
|
if (!type) return true;
|
||||||
|
return !isTierUnitPrice(row) && !isIntervalBilling(row);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/** 审批通过、驳回等审批流转类变更内容,不在结算单变更记录中展示。 */
|
||||||
|
export function isApprovalSettlementChange(content) {
|
||||||
|
const text = String(content || '').trim();
|
||||||
|
if (!text) return false;
|
||||||
|
return text.includes('审批通过') || text.includes('审批驳回') || text === '已驳回';
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { getList as getReceivablePayableDetailList } from '@/api/settlement/receivable-payable-detail';
|
||||||
|
import { getList as getWaybillList } from '@/api/business/waybill-manage';
|
||||||
|
|
||||||
|
// 结算明细的「单据号」是应收应付明细单据号(应收 YS…/应付 YF…),按结算类型落到对应菜单页
|
||||||
|
const SETTLEMENT_DETAIL_PATHS = {
|
||||||
|
receivable: '/settlement/receivable-detail',
|
||||||
|
payable: '/settlement/payable-detail',
|
||||||
|
};
|
||||||
|
|
||||||
|
const unwrapPage = response => {
|
||||||
|
const body = response?.data || response || {};
|
||||||
|
return body?.data || body;
|
||||||
|
};
|
||||||
|
|
||||||
|
const firstRecordId = data => (Array.isArray(data) ? data : data?.records || [])[0]?.id || '';
|
||||||
|
|
||||||
|
export const settlementDetailPath = settlementType =>
|
||||||
|
SETTLEMENT_DETAIL_PATHS[settlementType] || SETTLEMENT_DETAIL_PATHS.payable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结算明细行「单据号」对应的应收应付明细ID:已落库的明细自带 sourceDetailId,未落库的行按单据号回查。
|
||||||
|
*/
|
||||||
|
export const resolveReceivablePayableDetailId = async (row = {}, settlementType) => {
|
||||||
|
if (row.sourceDetailId) return row.sourceDetailId;
|
||||||
|
if (!row.documentNo) return '';
|
||||||
|
try {
|
||||||
|
const data = unwrapPage(
|
||||||
|
await getReceivablePayableDetailList(1, 1, {
|
||||||
|
documentNo: row.documentNo,
|
||||||
|
settlementType,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return firstRecordId(data);
|
||||||
|
} catch (error) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结算明细行「运单号」对应的运单ID:总单来源的明细没有 waybillId(运单号列存的是总单号),按运单号回查。
|
||||||
|
*/
|
||||||
|
export const resolveWaybillId = async (row = {}) => {
|
||||||
|
if (row.waybillId) return row.waybillId;
|
||||||
|
if (!row.waybillNo) return '';
|
||||||
|
try {
|
||||||
|
const data = unwrapPage(await getWaybillList(1, 1, { waybillNo: row.waybillNo }));
|
||||||
|
return firstRecordId(data);
|
||||||
|
} catch (error) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/** 结算菜单拆分后的展示名与权限前缀 */
|
||||||
|
|
||||||
|
export const SETTLEMENT_TYPE_PAYABLE = 'payable';
|
||||||
|
export const SETTLEMENT_TYPE_RECEIVABLE = 'receivable';
|
||||||
|
|
||||||
|
export function settlementBillLabel(settlementType) {
|
||||||
|
return settlementType === SETTLEMENT_TYPE_RECEIVABLE ? '收款结算单' : '付款结算单';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function settlementPermissionPrefix(settlementType) {
|
||||||
|
return settlementType === SETTLEMENT_TYPE_RECEIVABLE
|
||||||
|
? 'receipt_settlement'
|
||||||
|
: 'payment_settlement';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function settlementListPath(settlementType) {
|
||||||
|
return settlementType === SETTLEMENT_TYPE_RECEIVABLE
|
||||||
|
? '/settlement/receipt-settlement'
|
||||||
|
: '/settlement/payment-settlement';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限判断:优先新菜单码,兼容旧 formal_settlement_*。
|
||||||
|
* @param {Object} ctx 组件实例(需含 permission、isAdmin、validData)
|
||||||
|
* @param {string} settlementType payable|receivable
|
||||||
|
* @param {string} action add|edit|view...
|
||||||
|
*/
|
||||||
|
export function hasSettlementPermission(ctx, settlementType, action) {
|
||||||
|
if (ctx?.isAdmin) return true;
|
||||||
|
const prefix = settlementPermissionPrefix(settlementType);
|
||||||
|
const codes = [`${prefix}_${action}`, `formal_settlement_${action}`];
|
||||||
|
return codes.some(code => {
|
||||||
|
const value = ctx?.permission?.[code];
|
||||||
|
if (typeof ctx?.validData === 'function') {
|
||||||
|
return ctx.validData(value, false);
|
||||||
|
}
|
||||||
|
return value === true;
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* 结算单预付记录单据状态名(预结算编辑器与正式结算编辑器共用,避免两页状态名不一致)
|
||||||
|
*/
|
||||||
|
export function settlementStatusName(status, displayValue) {
|
||||||
|
const labels = {
|
||||||
|
reviewing: '审批中',
|
||||||
|
approved: '审批通过',
|
||||||
|
paid: '已付款',
|
||||||
|
returned: '已驳回',
|
||||||
|
voided: '已作废',
|
||||||
|
draft: '草稿',
|
||||||
|
};
|
||||||
|
const name = labels[status];
|
||||||
|
if (name) return name;
|
||||||
|
return typeof displayValue === 'function' ? displayValue(status) : status || '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一预付付款记录类型名
|
||||||
|
*/
|
||||||
|
export function settlementRecordTypeName(recordType) {
|
||||||
|
return { progress_advance: '进度预付', project_advance: '项目预付核销' }[recordType] || '';
|
||||||
|
}
|
||||||
+190
-100
@@ -50,7 +50,7 @@
|
|||||||
title="角色权限配置"
|
title="角色权限配置"
|
||||||
append-to-body
|
append-to-body
|
||||||
v-model="box"
|
v-model="box"
|
||||||
width="345px"
|
width="960px"
|
||||||
@close="handleDialogClose"
|
@close="handleDialogClose"
|
||||||
>
|
>
|
||||||
<el-tabs type="border-card">
|
<el-tabs type="border-card">
|
||||||
@@ -100,41 +100,26 @@
|
|||||||
align="middle"
|
align="middle"
|
||||||
style="margin-bottom: 12px; background: #f5f7fa; padding: 6px 10px; border-radius: 4px"
|
style="margin-bottom: 12px; background: #f5f7fa; padding: 6px 10px; border-radius: 4px"
|
||||||
>
|
>
|
||||||
<span style="display: inline-flex; align-items: center">
|
<span style="color: #606266; font-size: 13px"
|
||||||
<el-switch
|
>勾选多个菜单后点击「设置」,可批量配置数据权限;设置后菜单旁展示当前范围</span
|
||||||
v-model="dataScopeLinked"
|
>
|
||||||
active-text="节点联动"
|
<el-button type="primary" size="small" @click="openDataScopeSetting">设置</el-button>
|
||||||
size="small"
|
|
||||||
@change="handleLinkedChange('treeDataScope')"
|
|
||||||
/>
|
|
||||||
<el-tooltip content="开启后勾选父节点会自动勾选所有子节点,关闭则可独立勾选任意节点" placement="top">
|
|
||||||
<el-icon style="margin-left: 4px; color: #909399; cursor: pointer"><el-icon-question-filled /></el-icon>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
<el-button-group>
|
|
||||||
<el-button
|
|
||||||
size="small"
|
|
||||||
plain
|
|
||||||
@click="handleSelectAll('treeDataScope', dataScopeGrantList)"
|
|
||||||
>全选</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
size="small"
|
|
||||||
plain
|
|
||||||
@click="handleInvertSelect('treeDataScope', dataScopeGrantList, dataScopeLinked)"
|
|
||||||
>反选</el-button
|
|
||||||
>
|
|
||||||
</el-button-group>
|
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-tree
|
<el-tree
|
||||||
:data="dataScopeGrantList"
|
:data="roleDataScopeMenuTree"
|
||||||
show-checkbox
|
show-checkbox
|
||||||
:check-strictly="!dataScopeLinked"
|
|
||||||
node-key="id"
|
node-key="id"
|
||||||
ref="treeDataScope"
|
ref="treeRoleDataScope"
|
||||||
:default-checked-keys="dataScopeTreeObj"
|
|
||||||
:props="props"
|
:props="props"
|
||||||
>
|
>
|
||||||
|
<template #default="{ data }">
|
||||||
|
<span class="role-data-scope-node">
|
||||||
|
<span>{{ data.title }}</span>
|
||||||
|
<span v-if="getMenuScopeLabel(data.id)" class="role-data-scope-tag"
|
||||||
|
>【{{ getMenuScopeLabel(data.id) }}】</span
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
</el-tree>
|
</el-tree>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="接口权限">
|
<el-tab-pane label="接口权限">
|
||||||
@@ -188,6 +173,45 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
title="数据权限设置"
|
||||||
|
append-to-body
|
||||||
|
v-model="dataScopeSettingBox"
|
||||||
|
width="560px"
|
||||||
|
class="role-data-scope-setting-dialog"
|
||||||
|
>
|
||||||
|
<el-form label-position="right" label-width="auto">
|
||||||
|
<el-form-item label="角色名称">
|
||||||
|
<el-input v-model="dataScopeSetting.roleName" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="数据权限">
|
||||||
|
<el-radio-group v-model="dataScopeSetting.scopeType">
|
||||||
|
<el-radio :value="1">所在部门及下级</el-radio>
|
||||||
|
<el-radio :value="2">全部组织</el-radio>
|
||||||
|
<el-radio :value="3">本人创建</el-radio>
|
||||||
|
<el-radio :value="4">自定义组织</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="Number(dataScopeSetting.scopeType) === 4" label="组织">
|
||||||
|
<el-tree
|
||||||
|
ref="treeCustomDept"
|
||||||
|
:data="deptTree"
|
||||||
|
show-checkbox
|
||||||
|
node-key="id"
|
||||||
|
default-expand-all
|
||||||
|
:props="{ label: 'title', children: 'children' }"
|
||||||
|
style="width: 100%; max-height: 320px; overflow: auto; border: 1px solid #ebeef5; padding: 8px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="dataScopeSettingBox = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitDataScopeSetting">保存</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</basic-container>
|
</basic-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -196,37 +220,44 @@ import {
|
|||||||
add,
|
add,
|
||||||
getList,
|
getList,
|
||||||
getRole,
|
getRole,
|
||||||
getRoleAlias,
|
|
||||||
getRoleTreeById,
|
getRoleTreeById,
|
||||||
grant,
|
grant,
|
||||||
grantTree,
|
grantTree,
|
||||||
remove,
|
remove,
|
||||||
update,
|
update,
|
||||||
} from '@/api/system/role';
|
} from '@/api/system/role';
|
||||||
|
import { getRoleMenuDataScopeTree, submitRoleMenuDataScope } from '@/api/system/roleDataScope';
|
||||||
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import website from '@/config/website';
|
import website from '@/config/website';
|
||||||
import { validatenull } from '@/utils/validate';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {},
|
form: {},
|
||||||
box: false,
|
box: false,
|
||||||
|
dataScopeSettingBox: false,
|
||||||
props: {
|
props: {
|
||||||
label: 'title',
|
label: 'title',
|
||||||
value: 'key',
|
value: 'key',
|
||||||
},
|
},
|
||||||
menuGrantList: [],
|
menuGrantList: [],
|
||||||
dataScopeGrantList: [],
|
|
||||||
apiScopeGrantList: [],
|
apiScopeGrantList: [],
|
||||||
apiGrantList: [],
|
apiGrantList: [],
|
||||||
menuTreeObj: [],
|
menuTreeObj: [],
|
||||||
dataScopeTreeObj: [],
|
|
||||||
apiScopeTreeObj: [],
|
apiScopeTreeObj: [],
|
||||||
menuLinked: false,
|
menuLinked: false,
|
||||||
dataScopeLinked: false,
|
|
||||||
apiScopeLinked: false,
|
apiScopeLinked: false,
|
||||||
currentRoleIds: [],
|
currentRoleIds: [],
|
||||||
|
currentRoleName: '',
|
||||||
|
roleDataScopeMenuTree: [],
|
||||||
|
roleDataScopeMap: {},
|
||||||
|
deptTree: [],
|
||||||
|
dataScopeSetting: {
|
||||||
|
roleName: '',
|
||||||
|
scopeType: 2,
|
||||||
|
menuIds: [],
|
||||||
|
},
|
||||||
selectionList: [],
|
selectionList: [],
|
||||||
query: {},
|
query: {},
|
||||||
loading: true,
|
loading: true,
|
||||||
@@ -309,32 +340,19 @@ export default {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '角色别名',
|
label: '角色标识',
|
||||||
labelTip: '用于权限校验与标注的属性,可手动录入也可点击现有别名快速录入',
|
labelTip: '用于权限校验与标注的属性',
|
||||||
prop: 'roleAlias',
|
prop: 'roleAlias',
|
||||||
search: true,
|
search: true,
|
||||||
span: 24,
|
span: 24,
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入角色别名',
|
message: '请输入角色标识',
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '现有别名',
|
|
||||||
labelTip: '当前系统已存在的角色别名,点击可快速录入',
|
|
||||||
prop: 'currentAlias',
|
|
||||||
type: 'radio',
|
|
||||||
dicData: [],
|
|
||||||
props: {
|
|
||||||
label: 'roleName',
|
|
||||||
value: 'roleAlias',
|
|
||||||
},
|
|
||||||
hide: true,
|
|
||||||
span: 24,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '角色排序',
|
label: '角色排序',
|
||||||
prop: 'sort',
|
prop: 'sort',
|
||||||
@@ -378,14 +396,6 @@ export default {
|
|||||||
return ids;
|
return ids;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
'form.currentAlias'() {
|
|
||||||
const alias = this.form.currentAlias;
|
|
||||||
if (!validatenull(alias)) {
|
|
||||||
this.form.roleAlias = alias;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
initData(roleId) {
|
initData(roleId) {
|
||||||
getRoleTreeById(roleId).then(res => {
|
getRoleTreeById(roleId).then(res => {
|
||||||
@@ -452,9 +462,9 @@ export default {
|
|||||||
},
|
},
|
||||||
submit() {
|
submit() {
|
||||||
const menuList = this.$refs.treeMenu.getCheckedKeys();
|
const menuList = this.$refs.treeMenu.getCheckedKeys();
|
||||||
const dataScopeList = this.$refs.treeDataScope.getCheckedKeys();
|
|
||||||
const apiScopeList = this.$refs.treeApiScope.getCheckedKeys();
|
const apiScopeList = this.$refs.treeApiScope.getCheckedKeys();
|
||||||
grant(this.currentRoleIds, menuList, dataScopeList, apiScopeList).then(() => {
|
// 数据权限已改为角色菜单配置;传 null 跳过原生 dataScope 更新,避免误清历史配置
|
||||||
|
grant(this.currentRoleIds, menuList, null, apiScopeList).then(() => {
|
||||||
this.box = false;
|
this.box = false;
|
||||||
this.$message({
|
this.$message({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
@@ -465,6 +475,84 @@ export default {
|
|||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
getMenuScopeLabel(menuId) {
|
||||||
|
const scope = this.roleDataScopeMap[String(menuId)];
|
||||||
|
return scope ? scope.scopeTypeName : '';
|
||||||
|
},
|
||||||
|
loadRoleDataScopeTree(roleId) {
|
||||||
|
return getRoleMenuDataScopeTree(roleId).then(res => {
|
||||||
|
const data = res.data.data || {};
|
||||||
|
this.currentRoleName = data.roleName || '';
|
||||||
|
this.roleDataScopeMenuTree = data.menuTree || [];
|
||||||
|
const scopeMap = {};
|
||||||
|
(data.scopes || []).forEach(item => {
|
||||||
|
scopeMap[String(item.menuId)] = item;
|
||||||
|
});
|
||||||
|
this.roleDataScopeMap = scopeMap;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openDataScopeSetting() {
|
||||||
|
const tree = this.$refs.treeRoleDataScope;
|
||||||
|
if (!tree) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const menuIds = tree.getCheckedKeys();
|
||||||
|
if (!menuIds || menuIds.length === 0) {
|
||||||
|
this.$message.warning('请先勾选要设置的菜单');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.dataScopeSetting = {
|
||||||
|
roleName: this.currentRoleName,
|
||||||
|
scopeType: 2,
|
||||||
|
menuIds,
|
||||||
|
};
|
||||||
|
const loadDept =
|
||||||
|
this.deptTree && this.deptTree.length
|
||||||
|
? Promise.resolve()
|
||||||
|
: getDeptTree(this.userInfo.tenantId).then(res => {
|
||||||
|
this.deptTree = res.data.data || [];
|
||||||
|
});
|
||||||
|
loadDept.then(() => {
|
||||||
|
this.dataScopeSettingBox = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.treeCustomDept) {
|
||||||
|
this.$refs.treeCustomDept.setCheckedKeys([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
submitDataScopeSetting() {
|
||||||
|
const roleId = this.currentRoleIds && this.currentRoleIds[0];
|
||||||
|
if (!roleId) {
|
||||||
|
this.$message.warning('角色信息异常,请重新打开权限配置');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const scopeType = Number(this.dataScopeSetting.scopeType || 2);
|
||||||
|
let deptIds = [];
|
||||||
|
if (scopeType === 4) {
|
||||||
|
deptIds = this.$refs.treeCustomDept ? this.$refs.treeCustomDept.getCheckedKeys() : [];
|
||||||
|
if (!deptIds.length) {
|
||||||
|
this.$message.warning('自定义组织时请勾选组织');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
submitRoleMenuDataScope({
|
||||||
|
roleId,
|
||||||
|
menuIds: this.dataScopeSetting.menuIds,
|
||||||
|
scopeType,
|
||||||
|
deptIds,
|
||||||
|
}).then(() => {
|
||||||
|
this.$message.success('数据权限设置成功');
|
||||||
|
this.dataScopeSettingBox = false;
|
||||||
|
this.loadRoleDataScopeTree(roleId).then(() => {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.treeRoleDataScope) {
|
||||||
|
this.$refs.treeRoleDataScope.setCheckedKeys([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
rowSave(row, done, loading) {
|
rowSave(row, done, loading) {
|
||||||
add(this.withTenantId(row)).then(
|
add(this.withTenantId(row)).then(
|
||||||
() => {
|
() => {
|
||||||
@@ -547,10 +635,6 @@ export default {
|
|||||||
this.form.parentId = '';
|
this.form.parentId = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getRoleAlias().then(res => {
|
|
||||||
const column = this.findColumn(this.option.column, 'currentAlias');
|
|
||||||
column.dicData = res.data.data;
|
|
||||||
});
|
|
||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
handleRole() {
|
handleRole() {
|
||||||
@@ -563,58 +647,52 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.menuTreeObj = [];
|
this.menuTreeObj = [];
|
||||||
this.dataScopeTreeObj = [];
|
|
||||||
this.apiScopeTreeObj = [];
|
this.apiScopeTreeObj = [];
|
||||||
// 保存当前要配置权限的角色ID
|
|
||||||
this.currentRoleIds = this.idsArray;
|
this.currentRoleIds = this.idsArray;
|
||||||
grantTree().then(res => {
|
this.currentRoleName = (this.selectionList[0] && this.selectionList[0].roleName) || '';
|
||||||
this.menuGrantList = res.data.data.menu;
|
const roleId = this.currentRoleIds[0];
|
||||||
this.dataScopeGrantList = res.data.data.dataScope;
|
Promise.all([grantTree(), getRole(this.ids), this.loadRoleDataScopeTree(roleId)]).then(results => {
|
||||||
this.apiScopeGrantList = res.data.data.apiScope;
|
const grantRes = results[0];
|
||||||
getRole(this.ids).then(res => {
|
const roleRes = results[1];
|
||||||
this.menuTreeObj = res.data.data.menu;
|
this.menuGrantList = grantRes.data.data.menu;
|
||||||
this.dataScopeTreeObj = res.data.data.dataScope;
|
this.apiScopeGrantList = grantRes.data.data.apiScope;
|
||||||
this.apiScopeTreeObj = res.data.data.apiScope;
|
this.menuTreeObj = roleRes.data.data.menu;
|
||||||
this.box = true;
|
this.apiScopeTreeObj = roleRes.data.data.apiScope;
|
||||||
this.$nextTick(() => {
|
this.box = true;
|
||||||
this.applyCheckedKeys('treeMenu', this.menuTreeObj);
|
this.$nextTick(() => {
|
||||||
this.applyCheckedKeys('treeDataScope', this.dataScopeTreeObj);
|
this.applyCheckedKeys('treeMenu', this.menuTreeObj);
|
||||||
this.applyCheckedKeys('treeApiScope', this.apiScopeTreeObj);
|
this.applyCheckedKeys('treeApiScope', this.apiScopeTreeObj);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleRowRole(row) {
|
handleRowRole(row) {
|
||||||
this.menuTreeObj = [];
|
this.menuTreeObj = [];
|
||||||
this.dataScopeTreeObj = [];
|
|
||||||
this.apiScopeTreeObj = [];
|
this.apiScopeTreeObj = [];
|
||||||
// 保存当前要配置权限的角色ID(单个行操作)
|
|
||||||
this.currentRoleIds = [row.id];
|
this.currentRoleIds = [row.id];
|
||||||
grantTree().then(res => {
|
this.currentRoleName = row.roleName || '';
|
||||||
this.menuGrantList = res.data.data.menu;
|
Promise.all([grantTree(), getRole(row.id), this.loadRoleDataScopeTree(row.id)]).then(results => {
|
||||||
this.dataScopeGrantList = res.data.data.dataScope;
|
const grantRes = results[0];
|
||||||
this.apiScopeGrantList = res.data.data.apiScope;
|
const roleRes = results[1];
|
||||||
getRole(row.id).then(res => {
|
this.menuGrantList = grantRes.data.data.menu;
|
||||||
this.menuTreeObj = res.data.data.menu;
|
this.apiScopeGrantList = grantRes.data.data.apiScope;
|
||||||
this.dataScopeTreeObj = res.data.data.dataScope;
|
this.menuTreeObj = roleRes.data.data.menu;
|
||||||
this.apiScopeTreeObj = res.data.data.apiScope;
|
this.apiScopeTreeObj = roleRes.data.data.apiScope;
|
||||||
this.box = true;
|
this.box = true;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.applyCheckedKeys('treeMenu', this.menuTreeObj);
|
this.applyCheckedKeys('treeMenu', this.menuTreeObj);
|
||||||
this.applyCheckedKeys('treeDataScope', this.dataScopeTreeObj);
|
this.applyCheckedKeys('treeApiScope', this.apiScopeTreeObj);
|
||||||
this.applyCheckedKeys('treeApiScope', this.apiScopeTreeObj);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleDialogClose() {
|
handleDialogClose() {
|
||||||
// 对话框关闭时清空选择状态和权限树数据
|
|
||||||
this.menuTreeObj = [];
|
this.menuTreeObj = [];
|
||||||
this.dataScopeTreeObj = [];
|
|
||||||
this.apiScopeTreeObj = [];
|
this.apiScopeTreeObj = [];
|
||||||
this.menuLinked = false;
|
this.menuLinked = false;
|
||||||
this.dataScopeLinked = false;
|
|
||||||
this.apiScopeLinked = false;
|
this.apiScopeLinked = false;
|
||||||
|
this.roleDataScopeMenuTree = [];
|
||||||
|
this.roleDataScopeMap = {};
|
||||||
|
this.currentRoleName = '';
|
||||||
|
this.dataScopeSettingBox = false;
|
||||||
this.selectionClear();
|
this.selectionClear();
|
||||||
},
|
},
|
||||||
handleDelete() {
|
handleDelete() {
|
||||||
@@ -659,3 +737,15 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.role-data-scope-node {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.role-data-scope-tag {
|
||||||
|
color: #409eff;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -60,6 +60,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="hasPermission('airport_master_view')"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="hasPermission('airport_master_edit')"
|
v-if="hasPermission('airport_master_edit')"
|
||||||
@@ -150,6 +157,7 @@ import { mapGetters } from 'vuex';
|
|||||||
import { downloadXls } from '@/utils/util';
|
import { downloadXls } from '@/utils/util';
|
||||||
import { openImportDialog } from '@/utils/import-excel';
|
import { openImportDialog } from '@/utils/import-excel';
|
||||||
import { formatUpdateUserName } from '@/utils/audit';
|
import { formatUpdateUserName } from '@/utils/audit';
|
||||||
|
import { omitInvalidListStatus } from '@/utils/search-range';
|
||||||
import { getToken, isAdministrator } from '@/utils/auth';
|
import { getToken, isAdministrator } from '@/utils/auth';
|
||||||
import { getCoordinateValidationMessage, normalizeCoordinateInput } from '@/utils/coordinate';
|
import { getCoordinateValidationMessage, normalizeCoordinateInput } from '@/utils/coordinate';
|
||||||
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
||||||
@@ -278,7 +286,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '编码',
|
label: '编码',
|
||||||
@@ -1182,7 +1190,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onLoad(page, params = {}) {
|
onLoad(page, params = {}) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
getList(page.currentPage, page.pageSize, { ...params, ...this.query })
|
getList(page.currentPage, page.pageSize, omitInvalidListStatus({ ...params, ...this.query }))
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const data = res.data.data;
|
const data = res.data.data;
|
||||||
this.page.total = data.total;
|
this.page.total = data.total;
|
||||||
|
|||||||
@@ -68,6 +68,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="permission.currency_view"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="permission.currency_edit"
|
v-if="permission.currency_edit"
|
||||||
@@ -104,6 +111,7 @@ import { mapGetters } from 'vuex';
|
|||||||
import { downloadXls } from '@/utils/util';
|
import { downloadXls } from '@/utils/util';
|
||||||
import { openImportDialog } from '@/utils/import-excel';
|
import { openImportDialog } from '@/utils/import-excel';
|
||||||
import { formatUpdateUserName } from '@/utils/audit';
|
import { formatUpdateUserName } from '@/utils/audit';
|
||||||
|
import { omitInvalidListStatus } from '@/utils/search-range';
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
import NProgress from 'nprogress';
|
import NProgress from 'nprogress';
|
||||||
import 'nprogress/nprogress.css';
|
import 'nprogress/nprogress.css';
|
||||||
@@ -170,7 +178,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
@@ -507,7 +515,7 @@ export default {
|
|||||||
this.onLoad(this.page, this.query);
|
this.onLoad(this.page, this.query);
|
||||||
},
|
},
|
||||||
buildQuery(params = {}) {
|
buildQuery(params = {}) {
|
||||||
const values = { ...params, ...this.query };
|
const values = omitInvalidListStatus({ ...params, ...this.query });
|
||||||
const rangeMap = {
|
const rangeMap = {
|
||||||
effectiveDateRange: ['effectiveDateStart', 'effectiveDateEnd'],
|
effectiveDateRange: ['effectiveDateStart', 'effectiveDateEnd'],
|
||||||
expiryDateRange: ['expiryDateStart', 'expiryDateEnd'],
|
expiryDateRange: ['expiryDateStart', 'expiryDateEnd'],
|
||||||
|
|||||||
@@ -36,6 +36,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="permission.customer_type_view"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="permission.customer_type_edit"
|
v-if="permission.customer_type_edit"
|
||||||
@@ -63,6 +70,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getList, getDetail, submit, remove, changeStatus } from '@/api/base/customer-type';
|
import { getList, getDetail, submit, remove, changeStatus } from '@/api/base/customer-type';
|
||||||
|
import { omitInvalidListStatus } from '@/utils/search-range';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -101,7 +109,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '中文名称',
|
label: '中文名称',
|
||||||
@@ -290,7 +298,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onLoad(page, params = {}) {
|
onLoad(page, params = {}) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
getList(page.currentPage, page.pageSize, omitInvalidListStatus(Object.assign(params, this.query))).then(res => {
|
||||||
const data = res.data.data;
|
const data = res.data.data;
|
||||||
this.page.total = data.total;
|
this.page.total = data.total;
|
||||||
this.data = data.records;
|
this.data = data.records;
|
||||||
|
|||||||
@@ -76,6 +76,13 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="permission.fee_item_view"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="permission.fee_item_edit"
|
v-if="permission.fee_item_edit"
|
||||||
@@ -97,6 +104,7 @@ import { exportBlob } from '@/api/common';
|
|||||||
import { getDictionaryAll } from '@/api/system/dictbiz';
|
import { getDictionaryAll } from '@/api/system/dictbiz';
|
||||||
import { getDeptTree } from '@/api/system/dept';
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
import { downloadXls } from '@/utils/util';
|
import { downloadXls } from '@/utils/util';
|
||||||
|
import { omitInvalidListStatus } from '@/utils/search-range';
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
import { Download } from '@element-plus/icons-vue';
|
import { Download } from '@element-plus/icons-vue';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
@@ -140,7 +148,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '费用类型',
|
label: '费用类型',
|
||||||
@@ -569,7 +577,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onLoad(page, params = {}) {
|
onLoad(page, params = {}) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
getList(page.currentPage, page.pageSize, omitInvalidListStatus(Object.assign(params, this.query))).then(res => {
|
||||||
const data = res.data.data;
|
const data = res.data.data;
|
||||||
this.page.total = data.total;
|
this.page.total = data.total;
|
||||||
this.data = data.records;
|
this.data = data.records;
|
||||||
|
|||||||
@@ -46,6 +46,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
v-if="hasPermission('measurement_unit_view')"
|
||||||
|
type="primary"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
v-if="hasPermission('measurement_unit_edit')"
|
v-if="hasPermission('measurement_unit_edit')"
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -82,6 +89,7 @@
|
|||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { changeStatus, getDetail, getList, remove, submit } from '@/api/base/measurement-unit';
|
import { changeStatus, getDetail, getList, remove, submit } from '@/api/base/measurement-unit';
|
||||||
import { createOption } from '@/option/base/measurement-unit';
|
import { createOption } from '@/option/base/measurement-unit';
|
||||||
|
import { omitInvalidListStatus } from '@/utils/search-range';
|
||||||
import { isAdministrator } from '@/utils/auth';
|
import { isAdministrator } from '@/utils/auth';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -218,7 +226,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onLoad(page = this.page, params = this.query) {
|
onLoad(page = this.page, params = this.query) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
return getList(page.currentPage, page.pageSize, params)
|
return getList(page.currentPage, page.pageSize, omitInvalidListStatus(params))
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const pageData = res.data.data || {};
|
const pageData = res.data.data || {};
|
||||||
this.data = pageData.records || [];
|
this.data = pageData.records || [];
|
||||||
|
|||||||
@@ -134,6 +134,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="hasPermission('port_terminal_view')"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="hasPermission('port_terminal_edit')"
|
v-if="hasPermission('port_terminal_edit')"
|
||||||
@@ -270,6 +277,7 @@ import { mapGetters } from 'vuex';
|
|||||||
import { downloadXls } from '@/utils/util';
|
import { downloadXls } from '@/utils/util';
|
||||||
import { openImportDialog } from '@/utils/import-excel';
|
import { openImportDialog } from '@/utils/import-excel';
|
||||||
import { formatUpdateUserName } from '@/utils/audit';
|
import { formatUpdateUserName } from '@/utils/audit';
|
||||||
|
import { omitInvalidListStatus } from '@/utils/search-range';
|
||||||
import { getToken, isAdministrator } from '@/utils/auth';
|
import { getToken, isAdministrator } from '@/utils/auth';
|
||||||
import { getCoordinateValidationMessage, normalizeCoordinateInput } from '@/utils/coordinate';
|
import { getCoordinateValidationMessage, normalizeCoordinateInput } from '@/utils/coordinate';
|
||||||
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
||||||
@@ -369,7 +377,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '编码',
|
label: '编码',
|
||||||
@@ -1636,7 +1644,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onLoad(page, params = {}) {
|
onLoad(page, params = {}) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
getList(page.currentPage, page.pageSize, { ...params, ...this.query })
|
getList(page.currentPage, page.pageSize, omitInvalidListStatus({ ...params, ...this.query }))
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const data = res.data.data;
|
const data = res.data.data;
|
||||||
this.page.total = data.total;
|
this.page.total = data.total;
|
||||||
|
|||||||
@@ -60,6 +60,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="hasPermission('railway_station_view')"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="hasPermission('railway_station_edit')"
|
v-if="hasPermission('railway_station_edit')"
|
||||||
@@ -150,6 +157,7 @@ import { mapGetters } from 'vuex';
|
|||||||
import { downloadXls } from '@/utils/util';
|
import { downloadXls } from '@/utils/util';
|
||||||
import { openImportDialog } from '@/utils/import-excel';
|
import { openImportDialog } from '@/utils/import-excel';
|
||||||
import { formatUpdateUserName } from '@/utils/audit';
|
import { formatUpdateUserName } from '@/utils/audit';
|
||||||
|
import { omitInvalidListStatus } from '@/utils/search-range';
|
||||||
import { getToken, isAdministrator } from '@/utils/auth';
|
import { getToken, isAdministrator } from '@/utils/auth';
|
||||||
import { getCoordinateValidationMessage, normalizeCoordinateInput } from '@/utils/coordinate';
|
import { getCoordinateValidationMessage, normalizeCoordinateInput } from '@/utils/coordinate';
|
||||||
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
||||||
@@ -249,7 +257,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '编码',
|
label: '编码',
|
||||||
@@ -1157,7 +1165,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onLoad(page, params = {}) {
|
onLoad(page, params = {}) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
getList(page.currentPage, page.pageSize, { ...params, ...this.query })
|
getList(page.currentPage, page.pageSize, omitInvalidListStatus({ ...params, ...this.query }))
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const data = res.data.data;
|
const data = res.data.data;
|
||||||
this.page.total = data.total;
|
this.page.total = data.total;
|
||||||
|
|||||||
@@ -280,6 +280,23 @@ export default {
|
|||||||
.filter(Boolean)[0] || '';
|
.filter(Boolean)[0] || '';
|
||||||
},
|
},
|
||||||
applyDefaultDeptSearch() {
|
applyDefaultDeptSearch() {
|
||||||
|
// 超管默认不限组织,避免预填当前组织后看不到其他组织/无组织数据。
|
||||||
|
if (this.isAdmin) {
|
||||||
|
const deptColumn = this.findColumn(this.option.column, 'searchDeptId');
|
||||||
|
if (deptColumn) {
|
||||||
|
deptColumn.searchValue = undefined;
|
||||||
|
}
|
||||||
|
const nextQuery = { ...this.query };
|
||||||
|
delete nextQuery.deptId;
|
||||||
|
delete nextQuery.searchDeptId;
|
||||||
|
this.query = nextQuery;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.crud?.searchForm) {
|
||||||
|
this.$refs.crud.searchForm.searchDeptId = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
const deptId = this.defaultDeptId();
|
const deptId = this.defaultDeptId();
|
||||||
const deptColumn = this.findColumn(this.option.column, 'searchDeptId');
|
const deptColumn = this.findColumn(this.option.column, 'searchDeptId');
|
||||||
if (!deptId || !deptColumn) return;
|
if (!deptId || !deptColumn) return;
|
||||||
@@ -298,7 +315,8 @@ export default {
|
|||||||
if (deptColumn) {
|
if (deptColumn) {
|
||||||
deptColumn.dicData = this.deptOptions;
|
deptColumn.dicData = this.deptOptions;
|
||||||
}
|
}
|
||||||
// dicData 异步到位后再回填,避免下拉选项为空时清空已选组织,导致请求丢失 deptId。
|
// 超管不回填默认组织;普通用户在 dicData 到位后再回填,避免下拉清空已选组织。
|
||||||
|
if (this.isAdmin) return;
|
||||||
const deptId = String(this.query.deptId || this.defaultDeptId() || '');
|
const deptId = String(this.query.deptId || this.defaultDeptId() || '');
|
||||||
if (!deptId) return;
|
if (!deptId) return;
|
||||||
if (deptColumn) {
|
if (deptColumn) {
|
||||||
|
|||||||
@@ -396,8 +396,11 @@ export default {
|
|||||||
return this.selectionList.map(item => item.id).join(',');
|
return this.selectionList.map(item => item.id).join(',');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.applyDefaultDeptSearch();
|
// 超管默认查全部组织,不预填组织筛选;普通用户预填当前组织。
|
||||||
|
if (!this.isAdmin) {
|
||||||
|
this.applyDefaultDeptSearch();
|
||||||
|
}
|
||||||
this.initDeptTree();
|
this.initDeptTree();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -455,10 +458,23 @@ export default {
|
|||||||
normalizeListQuery(params = {}) {
|
normalizeListQuery(params = {}) {
|
||||||
// 搜索条件优先于缓存的 query,避免默认组织 ID 覆盖用户新选择的组织。
|
// 搜索条件优先于缓存的 query,避免默认组织 ID 覆盖用户新选择的组织。
|
||||||
const query = { ...this.query, ...params };
|
const query = { ...this.query, ...params };
|
||||||
const rawDeptId = query.deptId ?? query.searchDeptId;
|
// 本次搜索显式带了组织字段时,以本次为准(含清空);否则沿用缓存。
|
||||||
|
const hasDeptInParams =
|
||||||
|
Object.prototype.hasOwnProperty.call(params, 'deptId') ||
|
||||||
|
Object.prototype.hasOwnProperty.call(params, 'searchDeptId');
|
||||||
|
const rawDeptId = hasDeptInParams
|
||||||
|
? params.deptId ?? params.searchDeptId
|
||||||
|
: query.deptId ?? query.searchDeptId;
|
||||||
delete query.searchDeptId;
|
delete query.searchDeptId;
|
||||||
if (rawDeptId !== undefined && rawDeptId !== null && String(rawDeptId).trim() !== '') {
|
if (rawDeptId !== undefined && rawDeptId !== null && String(rawDeptId).trim() !== '') {
|
||||||
query.deptId = String(rawDeptId).split(',')[0].trim();
|
// 级联可能回传路径数组,统一取末级并保持字符串,避免雪花 ID 精度丢失。
|
||||||
|
const deptValue = Array.isArray(rawDeptId) ? rawDeptId.at(-1) : rawDeptId;
|
||||||
|
query.deptId = String(deptValue ?? '')
|
||||||
|
.split(',')[0]
|
||||||
|
.trim();
|
||||||
|
if (!query.deptId) {
|
||||||
|
delete query.deptId;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
delete query.deptId;
|
delete query.deptId;
|
||||||
}
|
}
|
||||||
@@ -466,6 +482,23 @@ export default {
|
|||||||
return query;
|
return query;
|
||||||
},
|
},
|
||||||
applyDefaultDeptSearch() {
|
applyDefaultDeptSearch() {
|
||||||
|
// 超管默认不限组织,避免预填组织后新增落在其他组织时列表看不见。
|
||||||
|
if (this.isAdmin) {
|
||||||
|
const deptColumn = this.findColumn(this.option.column, 'searchDeptId');
|
||||||
|
if (deptColumn) {
|
||||||
|
deptColumn.searchValue = undefined;
|
||||||
|
}
|
||||||
|
const nextQuery = { ...this.query };
|
||||||
|
delete nextQuery.deptId;
|
||||||
|
delete nextQuery.searchDeptId;
|
||||||
|
this.query = nextQuery;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.crud?.searchForm) {
|
||||||
|
this.$refs.crud.searchForm.searchDeptId = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
const deptId = this.defaultDeptId();
|
const deptId = this.defaultDeptId();
|
||||||
const deptColumn = this.findColumn(this.option.column, 'searchDeptId');
|
const deptColumn = this.findColumn(this.option.column, 'searchDeptId');
|
||||||
if (!deptId || !deptColumn) return;
|
if (!deptId || !deptColumn) return;
|
||||||
@@ -477,6 +510,11 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
resolveDeptName(deptId) {
|
||||||
|
if (!deptId) return '';
|
||||||
|
const matched = this.deptOptions.find(item => String(item.value) === String(deptId));
|
||||||
|
return matched ? String(matched.label || '').trim() : '';
|
||||||
|
},
|
||||||
resetAddressQuery() {
|
resetAddressQuery() {
|
||||||
this.addressQuery = {
|
this.addressQuery = {
|
||||||
addressName: '',
|
addressName: '',
|
||||||
@@ -933,7 +971,8 @@ export default {
|
|||||||
}
|
}
|
||||||
api.submit(submitRow).then(
|
api.submit(submitRow).then(
|
||||||
() => {
|
() => {
|
||||||
this.onLoad(this.page);
|
this.page.currentPage = 1;
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
this.$message({ type: 'success', message: '操作成功!' });
|
this.$message({ type: 'success', message: '操作成功!' });
|
||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
@@ -951,7 +990,7 @@ export default {
|
|||||||
}
|
}
|
||||||
api.submit(submitRow).then(
|
api.submit(submitRow).then(
|
||||||
() => {
|
() => {
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page, this.query);
|
||||||
this.$message({ type: 'success', message: '操作成功!' });
|
this.$message({ type: 'success', message: '操作成功!' });
|
||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
@@ -1006,7 +1045,13 @@ export default {
|
|||||||
beforeOpen(done, type) {
|
beforeOpen(done, type) {
|
||||||
this.dialogReadonly = type === 'view';
|
this.dialogReadonly = type === 'view';
|
||||||
if (type === 'add') {
|
if (type === 'add') {
|
||||||
this.form = {};
|
const form = {};
|
||||||
|
// 超管若当前按某组织筛选,新增默认归属该组织,避免保存后被筛选条件滤掉。
|
||||||
|
if (this.isAdmin && this.query.deptId) {
|
||||||
|
form.deptId = String(this.query.deptId);
|
||||||
|
form.deptName = this.resolveDeptName(form.deptId);
|
||||||
|
}
|
||||||
|
this.form = form;
|
||||||
done();
|
done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,12 @@
|
|||||||
<el-descriptions-item label="方案名称">{{
|
<el-descriptions-item label="方案名称">{{
|
||||||
displayValue(draft.planName)
|
displayValue(draft.planName)
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="适用客商">{{
|
||||||
|
displayValue(draft.customerName || partyOptionLabel(draft.partyRowId))
|
||||||
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="运输方式">{{
|
<el-descriptions-item label="运输方式">{{
|
||||||
transportModeLabel(draft.transportMode)
|
transportModeLabel(draft.transportMode)
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="默认方案">{{
|
|
||||||
isDefaultPlan(draft) ? '是' : '否'
|
|
||||||
}}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="备注">{{ displayValue(draft.remark) }}</el-descriptions-item>
|
<el-descriptions-item label="备注">{{ displayValue(draft.remark) }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<el-form
|
<el-form
|
||||||
@@ -37,6 +37,20 @@
|
|||||||
:disabled="readonly" /></el-form-item
|
:disabled="readonly" /></el-form-item
|
||||||
></el-col>
|
></el-col>
|
||||||
<el-col :span="8"
|
<el-col :span="8"
|
||||||
|
><el-form-item label="适用客商" prop="partyRowId"
|
||||||
|
><el-select
|
||||||
|
v-model="draft.partyRowId"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
placeholder="请选择适用客商"
|
||||||
|
@change="handlePartyChange"
|
||||||
|
><el-option
|
||||||
|
v-for="item in partyOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value" /></el-select></el-form-item
|
||||||
|
></el-col>
|
||||||
|
<el-col :span="8"
|
||||||
><el-form-item label="运输方式" prop="transportMode"
|
><el-form-item label="运输方式" prop="transportMode"
|
||||||
><el-select
|
><el-select
|
||||||
v-model="draft.transportMode"
|
v-model="draft.transportMode"
|
||||||
@@ -51,16 +65,6 @@
|
|||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value" /></el-select></el-form-item
|
:value="item.value" /></el-select></el-form-item
|
||||||
></el-col>
|
></el-col>
|
||||||
<el-col :span="8"
|
|
||||||
><el-form-item
|
|
||||||
><el-checkbox v-model="draft.defaultPlan" :disabled="readonly">默认方案</el-checkbox
|
|
||||||
><el-tooltip content="同一运输方式仅支持配置一个默认计费方案" placement="top">
|
|
||||||
<el-icon class="billing-plan-editor__default-tip"
|
|
||||||
><InfoFilled
|
|
||||||
/></el-icon> </el-tooltip
|
|
||||||
></el-form-item
|
|
||||||
></el-col
|
|
||||||
>
|
|
||||||
<el-col :span="24"
|
<el-col :span="24"
|
||||||
><el-form-item label="备注"
|
><el-form-item label="备注"
|
||||||
><el-input
|
><el-input
|
||||||
@@ -380,6 +384,7 @@ import { InfoFilled } from '@element-plus/icons-vue';
|
|||||||
import { getDictionary } from '@/api/system/dictbiz';
|
import { getDictionary } from '@/api/system/dictbiz';
|
||||||
import SectionCard from '@/components/section-card/main.vue';
|
import SectionCard from '@/components/section-card/main.vue';
|
||||||
import { currencyUnit } from '@/utils/currency';
|
import { currencyUnit } from '@/utils/currency';
|
||||||
|
// InfoFilled 仅用于保底计费重量列头提示
|
||||||
|
|
||||||
const clone = value => JSON.parse(JSON.stringify(value));
|
const clone = value => JSON.parse(JSON.stringify(value));
|
||||||
/** 计费要素与计量单位维度的对应关系(这些要素可选计费单位) */
|
/** 计费要素与计量单位维度的对应关系(这些要素可选计费单位) */
|
||||||
@@ -433,6 +438,7 @@ export default {
|
|||||||
index: { type: Number, default: -1 },
|
index: { type: Number, default: -1 },
|
||||||
readonly: Boolean,
|
readonly: Boolean,
|
||||||
settlementCurrency: { type: String, default: 'RMB' },
|
settlementCurrency: { type: String, default: 'RMB' },
|
||||||
|
partyOptions: { type: Array, default: () => [] },
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue', 'save'],
|
emits: ['update:modelValue', 'save'],
|
||||||
data() {
|
data() {
|
||||||
@@ -476,6 +482,7 @@ export default {
|
|||||||
cargoRequest: null,
|
cargoRequest: null,
|
||||||
formRules: {
|
formRules: {
|
||||||
planName: [{ required: true, message: '请输入方案名称', trigger: 'blur' }],
|
planName: [{ required: true, message: '请输入方案名称', trigger: 'blur' }],
|
||||||
|
partyRowId: [{ required: true, message: '请选择适用客商', trigger: 'change' }],
|
||||||
transportMode: [{ required: true, message: '请选择运输方式', trigger: 'change' }],
|
transportMode: [{ required: true, message: '请选择运输方式', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -516,10 +523,24 @@ export default {
|
|||||||
handler(value) {
|
handler(value) {
|
||||||
if (this.modelValue) {
|
if (this.modelValue) {
|
||||||
this.draft = this.normalizePlan(value);
|
this.draft = this.normalizePlan(value);
|
||||||
|
this.applyDefaultPartySelection();
|
||||||
this.loadRuleItems();
|
this.loadRuleItems();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
modelValue(visible) {
|
||||||
|
if (visible) {
|
||||||
|
this.$nextTick(() => this.applyDefaultPartySelection());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
partyOptions: {
|
||||||
|
deep: true,
|
||||||
|
handler() {
|
||||||
|
if (this.modelValue) {
|
||||||
|
this.applyDefaultPartySelection();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
displayValue(value) {
|
displayValue(value) {
|
||||||
@@ -539,27 +560,62 @@ export default {
|
|||||||
);
|
);
|
||||||
return this.displayValue(option?.label || this.draft.transportModeLabel || value);
|
return this.displayValue(option?.label || this.draft.transportModeLabel || value);
|
||||||
},
|
},
|
||||||
isDefaultPlan(plan) {
|
|
||||||
return (
|
|
||||||
plan?.defaultPlan === true ||
|
|
||||||
plan?.defaultPlan === 1 ||
|
|
||||||
['true', '1'].includes(String(plan?.defaultPlan).toLowerCase())
|
|
||||||
);
|
|
||||||
},
|
|
||||||
normalizePlan(value = {}) {
|
normalizePlan(value = {}) {
|
||||||
const plan = {
|
const plan = {
|
||||||
planName: '',
|
planName: '',
|
||||||
|
partyRowId: '',
|
||||||
|
partyRole: '',
|
||||||
|
customerId: '',
|
||||||
|
customerName: '',
|
||||||
transportMode: '',
|
transportMode: '',
|
||||||
transportModeLabel: '',
|
transportModeLabel: '',
|
||||||
defaultPlan: false,
|
|
||||||
remark: '',
|
remark: '',
|
||||||
...clone(value || {}),
|
...clone(value || {}),
|
||||||
};
|
};
|
||||||
|
// 一个客商对应一个方案,不再维护默认方案字段
|
||||||
|
delete plan.defaultPlan;
|
||||||
plan.rules = (value?.rules?.length ? value.rules : [defaultRule()]).map(rule =>
|
plan.rules = (value?.rules?.length ? value.rules : [defaultRule()]).map(rule =>
|
||||||
this.normalizeRule(rule)
|
this.normalizeRule(rule)
|
||||||
);
|
);
|
||||||
return plan;
|
return plan;
|
||||||
},
|
},
|
||||||
|
partyOptionLabel(partyRowId) {
|
||||||
|
const matched = (this.partyOptions || []).find(
|
||||||
|
item => String(item.value) === String(partyRowId)
|
||||||
|
);
|
||||||
|
return matched?.label || '';
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 仅一个可选客商时默认选中(客户合同仅一个甲方的常见场景)
|
||||||
|
*/
|
||||||
|
applyDefaultPartySelection() {
|
||||||
|
if (this.readonly) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const options = this.partyOptions || [];
|
||||||
|
if (options.length !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const current = String(this.draft.partyRowId || '');
|
||||||
|
const only = options[0];
|
||||||
|
const onlyValue = String(only?.value || only?.partyRowId || '');
|
||||||
|
if (!onlyValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (current && current === onlyValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.handlePartyChange(only.value || only.partyRowId);
|
||||||
|
},
|
||||||
|
handlePartyChange(partyRowId) {
|
||||||
|
const matched = (this.partyOptions || []).find(
|
||||||
|
item => String(item.value) === String(partyRowId)
|
||||||
|
);
|
||||||
|
this.draft.partyRowId = matched?.partyRowId || matched?.value || '';
|
||||||
|
this.draft.partyRole = matched?.partyRole || '';
|
||||||
|
this.draft.customerId = matched?.customerId || '';
|
||||||
|
this.draft.customerName = matched?.customerName || '';
|
||||||
|
},
|
||||||
normalizeRule(rule = {}) {
|
normalizeRule(rule = {}) {
|
||||||
const next = { ...defaultRule(), ...clone(rule) };
|
const next = { ...defaultRule(), ...clone(rule) };
|
||||||
if (next.billingType === '阶梯单价' && next.minimumBillingWeight === '') {
|
if (next.billingType === '阶梯单价' && next.minimumBillingWeight === '') {
|
||||||
@@ -1032,6 +1088,11 @@ export default {
|
|||||||
this.$refs.formRef.validate(valid => {
|
this.$refs.formRef.validate(valid => {
|
||||||
if (!valid || !this.validateRules()) return;
|
if (!valid || !this.validateRules()) return;
|
||||||
const plan = clone(this.draft);
|
const plan = clone(this.draft);
|
||||||
|
this.handlePartyChange(plan.partyRowId);
|
||||||
|
plan.partyRowId = this.draft.partyRowId;
|
||||||
|
plan.partyRole = this.draft.partyRole;
|
||||||
|
plan.customerId = this.draft.customerId;
|
||||||
|
plan.customerName = this.draft.customerName;
|
||||||
const transportMode = this.transportModeOptions.find(
|
const transportMode = this.transportModeOptions.find(
|
||||||
item => String(item.value) === String(plan.transportMode)
|
item => String(item.value) === String(plan.transportMode)
|
||||||
);
|
);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -205,7 +205,9 @@ export const defaultContractAttachmentTypeOptions = [
|
|||||||
{ label: '双章归档文件', value: '双章归档文件' },
|
{ label: '双章归档文件', value: '双章归档文件' },
|
||||||
{ label: '其他文件', value: CONTRACT_ATTACHMENT_TYPE_OTHER },
|
{ label: '其他文件', value: CONTRACT_ATTACHMENT_TYPE_OTHER },
|
||||||
];
|
];
|
||||||
|
// 特批附件归口附件(佐证材料等)区上传:高风险/黑名单客商合同必传,后端按 fileType=特批附件 校验并挂特批面板(与后端 HcsSyncConstant.ATTACHMENT_TYPE_SPEC_EXPLANATION 对齐)
|
||||||
export const defaultContractSupportingAttachmentTypeOptions = [
|
export const defaultContractSupportingAttachmentTypeOptions = [
|
||||||
|
{ label: '特批附件', value: '特批附件' },
|
||||||
{ label: '其他文件', value: CONTRACT_ATTACHMENT_TYPE_OTHER },
|
{ label: '其他文件', value: CONTRACT_ATTACHMENT_TYPE_OTHER },
|
||||||
];
|
];
|
||||||
/** @deprecated 兼容旧引用,实际选项由业务字典动态加载 */
|
/** @deprecated 兼容旧引用,实际选项由业务字典动态加载 */
|
||||||
@@ -299,6 +301,8 @@ export const resolveContractAttachmentType = (
|
|||||||
item => String(item.label) === aliasedFileType || String(item.label) === rawFileType
|
item => String(item.label) === aliasedFileType || String(item.label) === rawFileType
|
||||||
);
|
);
|
||||||
if (matchedByLabel) return matchedByLabel.value;
|
if (matchedByLabel) return matchedByLabel.value;
|
||||||
|
// 行已带类型但字典未命中(如历史保存值、字典缺失)时保留原值,避免重开页面时被降级为其他文件
|
||||||
|
if (rawFileType) return aliasedFileType;
|
||||||
const fileName = normalizeAttachmentTypeText(attachmentName(row));
|
const fileName = normalizeAttachmentTypeText(attachmentName(row));
|
||||||
if (!fileName) return otherType;
|
if (!fileName) return otherType;
|
||||||
const matched = list
|
const matched = list
|
||||||
@@ -641,7 +645,7 @@ export default {
|
|||||||
this.contractAttachmentTypeOptions
|
this.contractAttachmentTypeOptions
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.uploadDialogType = this.defaultAttachmentType;
|
this.uploadDialogType = this.uploadDialogType || this.defaultAttachmentType;
|
||||||
}
|
}
|
||||||
this.$message.success('上传成功');
|
this.$message.success('上传成功');
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,271 @@
|
|||||||
|
<template>
|
||||||
|
<section class="contract-manage-form__section contract-manage-form__section--panel hcs-contract-panel">
|
||||||
|
<div class="contract-manage-form__attachment-head">
|
||||||
|
<div class="dialog-section-title">合规信息</div>
|
||||||
|
<div>
|
||||||
|
<el-button
|
||||||
|
v-if="canApplySpec"
|
||||||
|
type="warning"
|
||||||
|
plain
|
||||||
|
:loading="specApplying"
|
||||||
|
@click="openSpecDialog"
|
||||||
|
>
|
||||||
|
发起特批
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="isSpecProcessing"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
@click="confirmSpecResult"
|
||||||
|
>
|
||||||
|
确认特批结果
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-descriptions :column="3" class="contract-manage-detail__descriptions">
|
||||||
|
<el-descriptions-item label="合规同步状态">
|
||||||
|
<el-tooltip
|
||||||
|
v-if="hcsSyncMsg"
|
||||||
|
placement="top"
|
||||||
|
:content="hcsSyncMsg"
|
||||||
|
>
|
||||||
|
<el-tag :type="syncTagType" class="status-text">{{ syncLabel }}</el-tag>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tag v-else :type="syncTagType" class="status-text">{{ syncLabel }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="合规合同ID">{{
|
||||||
|
contract.hcsFdId || '-'
|
||||||
|
}}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="客商风险">
|
||||||
|
<template v-if="contract.hcsRiskLevel || contract.kingdeeBlackStatus">
|
||||||
|
<el-tag
|
||||||
|
v-if="isBlacklist"
|
||||||
|
type="danger"
|
||||||
|
class="status-text"
|
||||||
|
>黑名单</el-tag
|
||||||
|
>
|
||||||
|
<span v-if="contract.hcsRiskLevel" class="hcs-contract-panel__risk">{{
|
||||||
|
`风险等级:${contract.hcsRiskLevel}`
|
||||||
|
}}</span>
|
||||||
|
<span v-if="!contract.hcsRiskLevel && !isBlacklist">-</span>
|
||||||
|
</template>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="特批状态">
|
||||||
|
<el-tag v-if="specLabel" :type="specTagType" class="status-text">{{ specLabel }}</el-tag>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="特批说明" :span="2">{{
|
||||||
|
contract.hcsSpecMsg || '-'
|
||||||
|
}}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
v-model="specDialogVisible"
|
||||||
|
title="发起合同特批"
|
||||||
|
width="640px"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
class="hcs-contract-panel__spec-dialog"
|
||||||
|
@closed="resetSpecDialog"
|
||||||
|
>
|
||||||
|
<el-alert
|
||||||
|
title="高风险客商合同需经集团特批后方可签约推送;请上传特批申请材料及内部审批流程附件。"
|
||||||
|
type="warning"
|
||||||
|
:closable="false"
|
||||||
|
class="hcs-contract-panel__spec-alert"
|
||||||
|
/>
|
||||||
|
<el-upload
|
||||||
|
drag
|
||||||
|
multiple
|
||||||
|
:show-file-list="false"
|
||||||
|
:http-request="uploadMaterial"
|
||||||
|
:on-error="() => uploadFailed()"
|
||||||
|
class="hcs-contract-panel__spec-upload"
|
||||||
|
>
|
||||||
|
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||||
|
<div class="el-upload__text">将特批材料拖到此处,或<em>点击上传到合同系统</em></div>
|
||||||
|
</el-upload>
|
||||||
|
<el-table :data="materials" border class="hcs-contract-panel__spec-table">
|
||||||
|
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||||
|
<el-table-column prop="name" label="文件名" min-width="220" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="fdId" label="合规附件ID" min-width="240" show-overflow-tooltip />
|
||||||
|
<el-table-column label="操作" width="90" align="center" fixed="right">
|
||||||
|
<template #default="{ $index }">
|
||||||
|
<el-link type="danger" @click="materials.splice($index, 1)">删除</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<template #footer>
|
||||||
|
<el-button type="primary" :loading="specApplying" @click="submitSpec">确认发起</el-button>
|
||||||
|
<el-button @click="specDialogVisible = false">取消</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { UploadFilled } from '@element-plus/icons-vue';
|
||||||
|
import {
|
||||||
|
applyContractSpec,
|
||||||
|
confirmContractSpec,
|
||||||
|
uploadAttachment,
|
||||||
|
} from '@/api/business/hcs';
|
||||||
|
|
||||||
|
const SYNC_STATUS_OPTIONS = [
|
||||||
|
{ label: '待推送', value: 'unsynced', type: 'info' },
|
||||||
|
{ label: '已推送', value: 'synced', type: 'success' },
|
||||||
|
{ label: '推送失败', value: 'failed', type: 'danger' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const SPEC_STATUS_OPTIONS = [
|
||||||
|
{ label: '待特批', value: 'need', type: 'warning' },
|
||||||
|
{ label: '特批中', value: 'processing', type: 'warning' },
|
||||||
|
{ label: '特批通过', value: 'approved', type: 'success' },
|
||||||
|
{ label: '特批驳回', value: 'rejected', type: 'danger' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HcsContractPanel',
|
||||||
|
components: { UploadFilled },
|
||||||
|
props: {
|
||||||
|
// 合同详情行(须含 id/hcsSyncStatus/hcsFdId/hcsRiskLevel/kingdeeBlackStatus/hcsSpecStatus 等)
|
||||||
|
contract: { type: Object, required: true },
|
||||||
|
},
|
||||||
|
emits: ['refresh'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
specDialogVisible: false,
|
||||||
|
specApplying: false,
|
||||||
|
materials: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
syncLabel() {
|
||||||
|
return SYNC_STATUS_OPTIONS.find(item => item.value === this.contract.hcsSyncStatus)?.label || '-';
|
||||||
|
},
|
||||||
|
syncTagType() {
|
||||||
|
return SYNC_STATUS_OPTIONS.find(item => item.value === this.contract.hcsSyncStatus)?.type || 'info';
|
||||||
|
},
|
||||||
|
hcsSyncMsg() {
|
||||||
|
return this.contract.hcsSyncMsg || '';
|
||||||
|
},
|
||||||
|
isBlacklist() {
|
||||||
|
return String(this.contract.kingdeeBlackStatus || '').toLowerCase() === 'yes';
|
||||||
|
},
|
||||||
|
specLabel() {
|
||||||
|
return SPEC_STATUS_OPTIONS.find(item => item.value === this.contract.hcsSpecStatus)?.label || '';
|
||||||
|
},
|
||||||
|
specTagType() {
|
||||||
|
return SPEC_STATUS_OPTIONS.find(item => item.value === this.contract.hcsSpecStatus)?.type || 'info';
|
||||||
|
},
|
||||||
|
isSpecProcessing() {
|
||||||
|
return this.contract.hcsSpecStatus === 'processing';
|
||||||
|
},
|
||||||
|
canApplySpec() {
|
||||||
|
return ['need', 'rejected'].includes(this.contract.hcsSpecStatus);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openSpecDialog() {
|
||||||
|
this.specDialogVisible = true;
|
||||||
|
},
|
||||||
|
resetSpecDialog() {
|
||||||
|
this.materials = [];
|
||||||
|
},
|
||||||
|
// 自定义上传:直传合同合规系统(C103-2),成功记录合规附件ID
|
||||||
|
uploadMaterial(options) {
|
||||||
|
const file = options.file;
|
||||||
|
if (file.size / 1024 / 1024 > 50) {
|
||||||
|
this.$message.warning('单文件大小不能超过 50MB');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('fdFile', file);
|
||||||
|
uploadAttachment(formData)
|
||||||
|
.then(response => {
|
||||||
|
const fdId = response?.data?.data || response?.data;
|
||||||
|
if (!fdId || typeof fdId !== 'string') {
|
||||||
|
this.$message.error(response?.data?.msg || '上传合同系统失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.materials.push({ fdId, name: file.name });
|
||||||
|
this.$message.success(`已上传合同系统:${file.name}`);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$message.error(error?.response?.data?.msg || '上传合同系统失败');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
uploadFailed() {
|
||||||
|
this.$message.error('上传合同系统失败');
|
||||||
|
},
|
||||||
|
submitSpec() {
|
||||||
|
if (!this.materials.length) {
|
||||||
|
this.$message.warning('请先上传特批申请材料');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.specApplying = true;
|
||||||
|
applyContractSpec({
|
||||||
|
contractId: this.contract.id,
|
||||||
|
attachments: this.materials.map(item => ({ fdId: item.fdId, name: item.name })),
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response?.data?.success === false) {
|
||||||
|
this.$message.error(response?.data?.msg || '特批发起失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$message.success(response?.data?.data || '特批发起成功,等待集团审批');
|
||||||
|
this.specDialogVisible = false;
|
||||||
|
this.$emit('refresh');
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$message.error(error?.response?.data?.msg || '特批发起失败');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.specApplying = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
confirmSpecResult() {
|
||||||
|
this.$prompt('请输入集团特批结果(approved=通过 / rejected=驳回)', '确认特批结果', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
inputPattern: /^(approved|rejected)$/,
|
||||||
|
inputErrorMessage: '请输入 approved 或 rejected',
|
||||||
|
}).then(({ value }) => {
|
||||||
|
confirmContractSpec(this.contract.id, value).then(() => {
|
||||||
|
this.$message.success('特批结果已确认');
|
||||||
|
this.$emit('refresh');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.hcs-contract-panel__risk {
|
||||||
|
margin-left: 8px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hcs-contract-panel__spec-alert {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hcs-contract-panel__spec-upload {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
:deep(.el-upload) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-upload-dragger) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hcs-contract-panel__spec-table {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -294,8 +294,8 @@ export default {
|
|||||||
query: { id: String(customerId), name: '查看客商档案', view: '1' },
|
query: { id: String(customerId), name: '查看客商档案', view: '1' },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
waybillStatusName(value) { return ({ pending: '待执行', waiting: '待执行', running: '进行中', processing: '进行中', completed: '已完成', cancelled: '已取消' })[value] || value || '-'; },
|
waybillStatusName(value) { return ({ pending: '待执行', waiting: '待执行', running: '进行中', processing: '进行中', pending_return_confirm: '待回单确认', completed: '已完成', cancelled: '已取消' })[value] || value || '-'; },
|
||||||
waybillStatusType(value) { return ({ pending: 'info', waiting: 'info', running: 'warning', processing: 'warning', completed: 'success', cancelled: 'danger' })[value] || 'info'; },
|
waybillStatusType(value) { return ({ pending: 'info', waiting: 'info', running: 'warning', processing: 'warning', pending_return_confirm: 'warning', completed: 'success', cancelled: 'danger' })[value] || 'info'; },
|
||||||
statusName(value) { return ({ waiting_dispatch: '待调度', dispatching: '调度中', completed: '调度完成', closed: '调度关闭' })[value] || value || '-'; },
|
statusName(value) { return ({ waiting_dispatch: '待调度', dispatching: '调度中', completed: '调度完成', closed: '调度关闭' })[value] || value || '-'; },
|
||||||
statusType(value) { return ({ waiting_dispatch: 'warning', dispatching: 'success', completed: 'primary', closed: 'danger' })[value] || 'info'; },
|
statusType(value) { return ({ waiting_dispatch: 'warning', dispatching: 'success', completed: 'primary', closed: 'danger' })[value] || 'info'; },
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -195,7 +195,7 @@
|
|||||||
<el-form :model="route" label-position="right" label-width="auto" class="dispatch-form carrier-form">
|
<el-form :model="route" label-position="right" label-width="auto" class="dispatch-form carrier-form">
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<template v-if="isRoad(route)">
|
<template v-if="isRoad(route)">
|
||||||
<el-col :span="6"><el-form-item label="承运商" :required="route.carrierType !== '自运'"><el-select :model-value="route.carrierType !== '自运' ? route.carrierContractId : route.carrierName" filterable clearable placeholder="请选择" :loading="carrierLoading" @change="value => handleCarrierContractChange(route, value)"><el-option v-for="item in carrierOptions" :key="carrierOptionValue(item)" :label="carrierOptionLabel(item)" :value="route.carrierType !== '自运' ? carrierOptionValue(item) : item.carrierName" /></el-select></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="承运商" :required="route.carrierType !== '自运'"><el-select :model-value="route.carrierType !== '自运' ? carrierSelectedValue(route) : route.carrierName" filterable clearable placeholder="请选择" :loading="carrierLoading" @change="value => handleCarrierContractChange(route, value)"><el-option v-for="item in carrierOptions" :key="carrierOptionValue(item)" :label="carrierOptionLabel(item)" :value="route.carrierType !== '自运' ? carrierOptionValue(item) : item.carrierName" /></el-select></el-form-item></el-col>
|
||||||
<el-col :span="6"
|
<el-col :span="6"
|
||||||
><el-form-item label="司机" :required="route.carrierType !== '承运商'"
|
><el-form-item label="司机" :required="route.carrierType !== '承运商'"
|
||||||
><el-autocomplete
|
><el-autocomplete
|
||||||
@@ -210,7 +210,11 @@
|
|||||||
@mousedown="() => handleDriverFocus(route)"
|
@mousedown="() => handleDriverFocus(route)"
|
||||||
@focus="() => handleDriverFocus(route)"
|
@focus="() => handleDriverFocus(route)"
|
||||||
@select="handleDriverSuggestionSelect"
|
@select="handleDriverSuggestionSelect"
|
||||||
/></el-form-item
|
>
|
||||||
|
<template #default="{ item }">
|
||||||
|
<span>{{ driverOptionText(item) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-autocomplete></el-form-item
|
||||||
></el-col>
|
></el-col>
|
||||||
<el-col :span="6"
|
<el-col :span="6"
|
||||||
><el-form-item
|
><el-form-item
|
||||||
@@ -239,7 +243,11 @@
|
|||||||
@mousedown="() => handleDriverFocus(route)"
|
@mousedown="() => handleDriverFocus(route)"
|
||||||
@focus="() => handleDriverFocus(route)"
|
@focus="() => handleDriverFocus(route)"
|
||||||
@select="handleEscortSuggestionSelect"
|
@select="handleEscortSuggestionSelect"
|
||||||
/></el-form-item
|
>
|
||||||
|
<template #default="{ item }">
|
||||||
|
<span>{{ driverOptionText(item) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-autocomplete></el-form-item
|
||||||
></el-col>
|
></el-col>
|
||||||
<el-col v-if="route.carrierType !== '承运商'" :span="6"
|
<el-col v-if="route.carrierType !== '承运商'" :span="6"
|
||||||
><el-form-item label="押运人手机号"
|
><el-form-item label="押运人手机号"
|
||||||
@@ -247,7 +255,7 @@
|
|||||||
></el-col>
|
></el-col>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-col :span="6"><el-form-item label="承运商" :required="route.carrierType !== '自运'"><el-select :model-value="route.carrierType !== '自运' ? route.carrierContractId : route.carrierName" filterable clearable placeholder="请选择" :loading="carrierLoading" @change="value => handleCarrierContractChange(route, value)"><el-option v-for="item in carrierOptions" :key="carrierOptionValue(item)" :label="carrierOptionLabel(item)" :value="route.carrierType !== '自运' ? carrierOptionValue(item) : item.carrierName" /></el-select></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="承运商" :required="route.carrierType !== '自运'"><el-select :model-value="route.carrierType !== '自运' ? carrierSelectedValue(route) : route.carrierName" filterable clearable placeholder="请选择" :loading="carrierLoading" @change="value => handleCarrierContractChange(route, value)"><el-option v-for="item in carrierOptions" :key="carrierOptionValue(item)" :label="carrierOptionLabel(item)" :value="route.carrierType !== '自运' ? carrierOptionValue(item) : item.carrierName" /></el-select></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="船班号/船次号/班次号" required><el-input v-model="route.vehicleNo" placeholder="请输入" /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="船班号/船次号/班次号" required><el-input v-model="route.vehicleNo" placeholder="请输入" /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="船长"><el-input v-model="route.captainName" placeholder="请输入" /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="船长"><el-input v-model="route.captainName" placeholder="请输入" /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="联系电话"><el-input v-model="route.driverPhone" placeholder="请输入" /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="联系电话"><el-input v-model="route.driverPhone" placeholder="请输入" /></el-form-item></el-col>
|
||||||
@@ -316,7 +324,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as api from '@/api/business/master-order';
|
import * as api from '@/api/business/master-order';
|
||||||
import { fetchDriversByCarrierOrganizations } from '@/utils/carrier-org-resource';
|
import { fetchDriverCandidates, driverOptionText } from '@/utils/carrier-org-resource';
|
||||||
import { formatContractOptionLabel } from '@/utils/contract';
|
import { formatContractOptionLabel } from '@/utils/contract';
|
||||||
import {
|
import {
|
||||||
currencyUnit,
|
currencyUnit,
|
||||||
@@ -403,6 +411,7 @@ export default {
|
|||||||
this.applySelfOperatedCarrierDefaults();
|
this.applySelfOperatedCarrierDefaults();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
driverOptionText,
|
||||||
loadQuantityUnitOptions() {
|
loadQuantityUnitOptions() {
|
||||||
if (this.quantityUnitLoading) return this.quantityUnitLoadPromise;
|
if (this.quantityUnitLoading) return this.quantityUnitLoadPromise;
|
||||||
this.quantityUnitLoading = true;
|
this.quantityUnitLoading = true;
|
||||||
@@ -911,6 +920,8 @@ export default {
|
|||||||
route.carrierName = '';
|
route.carrierName = '';
|
||||||
route.carrierId = '';
|
route.carrierId = '';
|
||||||
route.carrierContractId = '';
|
route.carrierContractId = '';
|
||||||
|
route.carrierPartyId = '';
|
||||||
|
route.carrierPartyRole = '';
|
||||||
this.clearRouteDriverVehicleFields(route);
|
this.clearRouteDriverVehicleFields(route);
|
||||||
if (value === '承运商') {
|
if (value === '承运商') {
|
||||||
route.trailerVehicleNo = '';
|
route.trailerVehicleNo = '';
|
||||||
@@ -921,15 +932,18 @@ export default {
|
|||||||
if (value === '自运') this.applySelfOperatedCarrierDefaults(route);
|
if (value === '自运') this.applySelfOperatedCarrierDefaults(route);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleCarrierContractChange(route, contractId) {
|
handleCarrierContractChange(route, selectedValue) {
|
||||||
const contract = this.carrierOptions.find(
|
const contract = this.carrierOptions.find(
|
||||||
item =>
|
item =>
|
||||||
|
this.carrierOptionValue(item) === String(selectedValue || '') ||
|
||||||
[item.contractId, item.carrierName, item.id].some(
|
[item.contractId, item.carrierName, item.id].some(
|
||||||
value => String(value || '') === String(contractId || '')
|
value => String(value || '') === String(selectedValue || '')
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
route.carrierContractId = route.carrierType !== '自运' ? contract?.contractId || '' : '';
|
route.carrierContractId = route.carrierType !== '自运' ? contract?.contractId || '' : '';
|
||||||
route.carrierId = route.carrierType !== '自运' ? contract?.carrierId || '' : '';
|
route.carrierPartyId = route.carrierType !== '自运' ? contract?.carrierPartyId || '' : '';
|
||||||
|
route.carrierPartyRole = route.carrierType !== '自运' ? contract?.carrierPartyRole || '' : '';
|
||||||
|
route.carrierId = route.carrierType !== '自运' ? contract?.carrierId || contract?.customerId || '' : '';
|
||||||
route.carrierName = contract?.carrierName || '';
|
route.carrierName = contract?.carrierName || '';
|
||||||
this.clearRouteDriverVehicleFields(route);
|
this.clearRouteDriverVehicleFields(route);
|
||||||
},
|
},
|
||||||
@@ -944,22 +958,24 @@ export default {
|
|||||||
route.escortPhone = '';
|
route.escortPhone = '';
|
||||||
this.driverOptions = [];
|
this.driverOptions = [];
|
||||||
},
|
},
|
||||||
getRouteCarrierFilter(route = {}) {
|
|
||||||
return {
|
|
||||||
carrierId: route.carrierId || '',
|
|
||||||
carrierName: route.carrierName || '',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
carrierOptionValue(item = {}) {
|
carrierOptionValue(item = {}) {
|
||||||
return item.contractId || item.id || item.value || item.carrierName || '';
|
return [item.contractId || item.id || '', item.carrierPartyId || '', item.carrierName || ''].join(
|
||||||
|
'__'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
carrierSelectedValue(route = {}) {
|
||||||
|
return this.carrierOptionValue({
|
||||||
|
contractId: route.carrierContractId,
|
||||||
|
carrierPartyId: route.carrierPartyId,
|
||||||
|
carrierName: route.carrierName,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
carrierOptionLabel(item) {
|
carrierOptionLabel(item) {
|
||||||
const duplicateCount = this.carrierOptions.filter(option => option.carrierName === item.carrierName).length;
|
const roleLabel = item.carrierPartyRole === 'C' ? '丙方' : item.carrierPartyRole === 'B' ? '乙方' : '';
|
||||||
if (duplicateCount <= 1) {
|
const nameWithRole =
|
||||||
return item.carrierName;
|
roleLabel && item.carrierName ? `${item.carrierName}(${roleLabel})` : item.carrierName;
|
||||||
}
|
|
||||||
const contractLabel = formatContractOptionLabel(item);
|
const contractLabel = formatContractOptionLabel(item);
|
||||||
return contractLabel ? `${item.carrierName}(${contractLabel})` : item.carrierName;
|
return contractLabel ? `${nameWithRole} - ${contractLabel}` : nameWithRole;
|
||||||
},
|
},
|
||||||
driverOptionLabel(item) { return item.driverName || item.name || ''; },
|
driverOptionLabel(item) { return item.driverName || item.name || ''; },
|
||||||
driverOptionKey(item) { return item.id || item.driverId || this.driverOptionLabel(item) || item.mobile; },
|
driverOptionKey(item) { return item.id || item.driverId || this.driverOptionLabel(item) || item.mobile; },
|
||||||
@@ -980,19 +996,22 @@ export default {
|
|||||||
...item,
|
...item,
|
||||||
contractId: item.contractId || item.carrierContractId || item.id || '',
|
contractId: item.contractId || item.carrierContractId || item.id || '',
|
||||||
carrierName:
|
carrierName:
|
||||||
|
item.carrierName ||
|
||||||
item.partyB ||
|
item.partyB ||
|
||||||
item.partyBName ||
|
item.partyBName ||
|
||||||
item.contractPartyB ||
|
item.contractPartyB ||
|
||||||
item.customerContractPartyB ||
|
item.customerContractPartyB ||
|
||||||
item.carrierName ||
|
|
||||||
'',
|
'',
|
||||||
carrierId:
|
carrierId:
|
||||||
|
item.customerId ||
|
||||||
item.partyBId ||
|
item.partyBId ||
|
||||||
item.partyBUserId ||
|
item.partyBUserId ||
|
||||||
item.contractPartyBId ||
|
item.contractPartyBId ||
|
||||||
item.customerContractPartyBId ||
|
item.customerContractPartyBId ||
|
||||||
item.carrierId ||
|
item.carrierId ||
|
||||||
'',
|
'',
|
||||||
|
carrierPartyId: item.carrierPartyId || '',
|
||||||
|
carrierPartyRole: item.carrierPartyRole || '',
|
||||||
}))
|
}))
|
||||||
.filter(item => item.carrierName);
|
.filter(item => item.carrierName);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -1026,36 +1045,22 @@ export default {
|
|||||||
this.activeSuggestRoute = route;
|
this.activeSuggestRoute = route;
|
||||||
},
|
},
|
||||||
async loadDriverOptions(route = {}, keyword = '') {
|
async loadDriverOptions(route = {}, keyword = '') {
|
||||||
const carrier = this.getRouteCarrierFilter(route);
|
|
||||||
if (!carrier.carrierId && !carrier.carrierName) {
|
|
||||||
this.driverOptions = [];
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
this.driverLoading = true;
|
this.driverLoading = true;
|
||||||
try {
|
try {
|
||||||
this.driverOptions = await fetchDriversByCarrierOrganizations(
|
this.driverOptions = await fetchDriverCandidates({
|
||||||
{ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '司机' },
|
size: 20,
|
||||||
carrier
|
...(keyword ? { driverName: keyword } : {}),
|
||||||
);
|
posts: '司机',
|
||||||
|
});
|
||||||
return this.driverOptions;
|
return this.driverOptions;
|
||||||
} finally {
|
} finally {
|
||||||
this.driverLoading = false;
|
this.driverLoading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetchDriverSuggestions(queryString, callback) {
|
fetchDriverSuggestions(queryString, callback) {
|
||||||
const route = this.activeSuggestRoute || {};
|
|
||||||
const carrier = this.getRouteCarrierFilter(route);
|
|
||||||
const keyword = String(queryString || '').trim();
|
const keyword = String(queryString || '').trim();
|
||||||
if (!carrier.carrierId && !carrier.carrierName) {
|
|
||||||
callback([]);
|
|
||||||
if (!keyword) this.$message.warning('请先选择承运商');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.driverLoading = true;
|
this.driverLoading = true;
|
||||||
fetchDriversByCarrierOrganizations(
|
fetchDriverCandidates({ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '司机' })
|
||||||
{ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '司机' },
|
|
||||||
carrier
|
|
||||||
)
|
|
||||||
.then(records => {
|
.then(records => {
|
||||||
this.driverOptions = records;
|
this.driverOptions = records;
|
||||||
callback(
|
callback(
|
||||||
@@ -1080,19 +1085,13 @@ export default {
|
|||||||
if (drivingVehicle) route.vehicleNo = drivingVehicle;
|
if (drivingVehicle) route.vehicleNo = drivingVehicle;
|
||||||
},
|
},
|
||||||
fetchEscortSuggestions(queryString, callback) {
|
fetchEscortSuggestions(queryString, callback) {
|
||||||
const route = this.activeSuggestRoute || {};
|
|
||||||
const keyword = String(queryString || '').trim();
|
const keyword = String(queryString || '').trim();
|
||||||
const carrier = this.getRouteCarrierFilter(route);
|
|
||||||
if (!carrier.carrierId && !carrier.carrierName) {
|
|
||||||
callback([]);
|
|
||||||
if (!keyword) this.$message.warning('请先选择承运商');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.escortLoading = true;
|
this.escortLoading = true;
|
||||||
fetchDriversByCarrierOrganizations(
|
fetchDriverCandidates({
|
||||||
{ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '押运员' },
|
size: 20,
|
||||||
carrier
|
...(keyword ? { driverName: keyword } : {}),
|
||||||
)
|
posts: '押运员',
|
||||||
|
})
|
||||||
.then(records => {
|
.then(records => {
|
||||||
callback(
|
callback(
|
||||||
records.map(item => ({
|
records.map(item => ({
|
||||||
@@ -1154,7 +1153,7 @@ export default {
|
|||||||
id: `${route.segmentNo}-${item.cargoName}-${Date.now()}-${Math.random()}`,
|
id: `${route.segmentNo}-${item.cargoName}-${Date.now()}-${Math.random()}`,
|
||||||
batchNo,
|
batchNo,
|
||||||
segmentNo: route.segmentNo, relationNo: route.segmentNo, documentType: route.documentType, transportType: route.transportType, carrierType: route.carrierType,
|
segmentNo: route.segmentNo, relationNo: route.segmentNo, documentType: route.documentType, transportType: route.transportType, carrierType: route.carrierType,
|
||||||
carrierContractId: route.carrierContractId, carrierName: route.carrierName, driverName: route.driverName, driverPhone: route.driverPhone, vehicleNo: route.vehicleNo, captainName: route.captainName, cabinNo: route.cabinNo, containerNo: route.containerNo, trailerVehicleNo: route.trailerVehicleNo, escortName: route.escortName, escortPhone: route.escortPhone, mileage: this.normalizeMileage(route.mileage), unitPrice: this.freightItemsForGoods(route, item).unitPrice || '', priceUnit: this.freightItemsForGoods(route, item).priceUnit || '', currency: route.currency || 'RMB', freightAmount: this.freightAmount(this.freightItemsForGoods(route, item)), freightTotal: this.freightTotal(route), otherFeeTotal: route.otherFeeTotal || '', freightJson: this.buildFreightJson(route), routeRemark: route.remark,
|
carrierContractId: route.carrierContractId, carrierPartyId: route.carrierPartyId, carrierPartyRole: route.carrierPartyRole, carrierName: route.carrierName, driverName: route.driverName, driverPhone: route.driverPhone, vehicleNo: route.vehicleNo, captainName: route.captainName, cabinNo: route.cabinNo, containerNo: route.containerNo, trailerVehicleNo: route.trailerVehicleNo, escortName: route.escortName, escortPhone: route.escortPhone, mileage: this.normalizeMileage(route.mileage), unitPrice: this.freightItemsForGoods(route, item).unitPrice || '', priceUnit: this.freightItemsForGoods(route, item).priceUnit || '', currency: route.currency || 'RMB', freightAmount: this.freightAmount(this.freightItemsForGoods(route, item)), freightTotal: this.freightTotal(route), otherFeeTotal: route.otherFeeTotal || '', freightJson: this.buildFreightJson(route), routeRemark: route.remark,
|
||||||
departureName: route.departureName, departureAddress: route.departureAddress, departureContact: route.departureContact, departurePhone: route.departurePhone,
|
departureName: route.departureName, departureAddress: route.departureAddress, departureContact: route.departureContact, departurePhone: route.departurePhone,
|
||||||
arrivalName: route.arrivalName, arrivalAddress: route.arrivalAddress, arrivalContact: route.arrivalContact, arrivalPhone: route.arrivalPhone,
|
arrivalName: route.arrivalName, arrivalAddress: route.arrivalAddress, arrivalContact: route.arrivalContact, arrivalPhone: route.arrivalPhone,
|
||||||
estimatedStartTime: route.estimatedStartTime, estimatedEndTime: route.estimatedEndTime,
|
estimatedStartTime: route.estimatedStartTime, estimatedEndTime: route.estimatedEndTime,
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
<div class="route-node-form">
|
<div class="route-node-form">
|
||||||
<el-form-item label="途经地" required class="route-address-form-item"
|
<el-form-item label="途经地" required class="route-address-form-item"
|
||||||
><div class="route-address-inputs"
|
><div class="route-address-inputs"
|
||||||
><el-input v-if="isNonRoadAddress(`route-${index}`)" v-model="route.departureName" class="route-address-name" readonly :disabled="isBasicRouteReadonly || !route.transportType" placeholder="请先选择运输方式" /><el-cascader v-else v-model="addressRegionPaths[`route-${index}`]" class="route-address-name" :options="regionOptions" :props="regionCascaderProps" :loading="regionLoading" :disabled="isBasicRouteReadonly || !route.transportType" placeholder="请选择省市区" clearable filterable @visible-change="visible => visible && loadRegionOptions()" @change="value => handleAddressRegionChange(`route-${index}`, value)" /><el-input v-model="route.departureAddress" class="route-address-detail" readonly :disabled="isBasicRouteReadonly || !route.transportType" placeholder="请先选择运输方式" @click="handleAddressDetailClick(`route-${index}`)" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="OfficeBuilding" :disabled="isBasicRouteReadonly || !route.transportType" @click="openCommonAddress(`route-${index}`)" /></el-tooltip></div
|
><el-input v-if="isNonRoadAddress(`route-${index}`)" v-model="route.departureName" class="route-address-name" readonly :disabled="isBasicRouteReadonly" placeholder="请选择站点" /><el-cascader v-else v-model="addressRegionPaths[`route-${index}`]" class="route-address-name" :options="regionOptions" :props="regionCascaderProps" :loading="regionLoading" :disabled="isBasicRouteReadonly" placeholder="请选择省市区" clearable filterable @visible-change="visible => visible && loadRegionOptions()" @change="value => handleAddressRegionChange(`route-${index}`, value)" /><el-input v-model="route.departureAddress" class="route-address-detail" readonly :disabled="isBasicRouteReadonly" placeholder="请输入详细地址" @click="handleAddressDetailClick(`route-${index}`)" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="OfficeBuilding" :disabled="isBasicRouteReadonly" @click="openCommonAddress(`route-${index}`)" /></el-tooltip></div
|
||||||
></el-form-item>
|
></el-form-item>
|
||||||
<el-form-item label="联系人" class="route-contact-form-item"><el-input v-model="route.departureContact" :disabled="isBasicRouteReadonly" placeholder="请输入" /></el-form-item>
|
<el-form-item label="联系人" class="route-contact-form-item"><el-input v-model="route.departureContact" :disabled="isBasicRouteReadonly" placeholder="请输入" /></el-form-item>
|
||||||
<el-form-item label="联系方式" class="route-phone-form-item"><div class="route-contact-actions"><el-input v-model="route.departurePhone" :disabled="isBasicRouteReadonly" placeholder="请输入" /><template v-if="!isBasicRouteReadonly"><el-tooltip v-if="index === form.routes.length - 1" content="新增途经点" placement="top"><el-button class="route-action-button" type="primary" link @click="addRoute"><el-icon><CirclePlus /></el-icon></el-button></el-tooltip><el-tooltip content="删除途经点" placement="top"><el-button class="route-action-button" type="danger" link @click="removeRoute(index)"><el-icon><Remove /></el-icon></el-button></el-tooltip></template></div></el-form-item>
|
<el-form-item label="联系方式" class="route-phone-form-item"><div class="route-contact-actions"><el-input v-model="route.departurePhone" :disabled="isBasicRouteReadonly" placeholder="请输入" /><template v-if="!isBasicRouteReadonly"><el-tooltip v-if="index === form.routes.length - 1" content="新增途经点" placement="top"><el-button class="route-action-button" type="primary" link @click="addRoute"><el-icon><CirclePlus /></el-icon></el-button></el-tooltip><el-tooltip content="删除途经点" placement="top"><el-button class="route-action-button" type="danger" link @click="removeRoute(index)"><el-icon><Remove /></el-icon></el-button></el-tooltip></template></div></el-form-item>
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
<div class="route-node-form">
|
<div class="route-node-form">
|
||||||
<el-form-item label="收货地" required class="route-address-form-item"
|
<el-form-item label="收货地" required class="route-address-form-item"
|
||||||
><div class="route-address-inputs"
|
><div class="route-address-inputs"
|
||||||
><el-input v-if="isNonRoadAddress('arrival')" v-model="form.arrivalName" class="route-address-name" readonly :disabled="isBasicRouteReadonly || !form.finalTransportType" placeholder="请先选择运输方式" /><el-cascader v-else v-model="addressRegionPaths.arrival" class="route-address-name" :options="regionOptions" :props="regionCascaderProps" :loading="regionLoading" :disabled="isBasicRouteReadonly || !form.finalTransportType" placeholder="请选择省市区" clearable filterable @visible-change="visible => visible && loadRegionOptions()" @change="value => handleAddressRegionChange('arrival', value)" /><el-input v-model="form.arrivalAddress" class="route-address-detail" readonly :disabled="isBasicRouteReadonly || !form.finalTransportType" placeholder="请先选择运输方式" @click="handleAddressDetailClick('arrival')" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="OfficeBuilding" :disabled="isBasicRouteReadonly || !form.finalTransportType" @click="openCommonAddress('arrival')" /></el-tooltip></div
|
><el-input v-if="isNonRoadAddress('arrival')" v-model="form.arrivalName" class="route-address-name" readonly :disabled="isBasicRouteReadonly" placeholder="请选择站点" /><el-cascader v-else v-model="addressRegionPaths.arrival" class="route-address-name" :options="regionOptions" :props="regionCascaderProps" :loading="regionLoading" :disabled="isBasicRouteReadonly" placeholder="请选择省市区" clearable filterable @visible-change="visible => visible && loadRegionOptions()" @change="value => handleAddressRegionChange('arrival', value)" /><el-input v-model="form.arrivalAddress" class="route-address-detail" readonly :disabled="isBasicRouteReadonly" placeholder="请输入详细地址" @click="handleAddressDetailClick('arrival')" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="OfficeBuilding" :disabled="isBasicRouteReadonly" @click="openCommonAddress('arrival')" /></el-tooltip></div
|
||||||
></el-form-item>
|
></el-form-item>
|
||||||
<el-form-item label="联系人" class="route-contact-form-item"
|
<el-form-item label="联系人" class="route-contact-form-item"
|
||||||
><el-input v-model="form.arrivalContact" :disabled="isBasicRouteReadonly" placeholder="请输入" /></el-form-item>
|
><el-input v-model="form.arrivalContact" :disabled="isBasicRouteReadonly" placeholder="请输入" /></el-form-item>
|
||||||
@@ -352,7 +352,12 @@
|
|||||||
@opened="loadAddressList"
|
@opened="loadAddressList"
|
||||||
>
|
>
|
||||||
<div class="route-dialog__search common-address-dialog__search">
|
<div class="route-dialog__search common-address-dialog__search">
|
||||||
<el-form :model="addressQuery" label-position="right" label-width="auto">
|
<el-form
|
||||||
|
class="dialog-form-label-fixed"
|
||||||
|
:model="addressQuery"
|
||||||
|
label-position="right"
|
||||||
|
label-width="96px"
|
||||||
|
>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="地址名称">
|
<el-form-item label="地址名称">
|
||||||
@@ -446,7 +451,12 @@
|
|||||||
@opened="loadStationList"
|
@opened="loadStationList"
|
||||||
>
|
>
|
||||||
<div class="route-dialog__search">
|
<div class="route-dialog__search">
|
||||||
<el-form :model="stationQuery" label-position="right" label-width="auto">
|
<el-form
|
||||||
|
class="dialog-form-label-fixed"
|
||||||
|
:model="stationQuery"
|
||||||
|
label-position="right"
|
||||||
|
label-width="96px"
|
||||||
|
>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="8"><el-form-item label="站点名称"><el-input v-model="stationQuery.name" clearable placeholder="请输入" /></el-form-item></el-col>
|
<el-col :span="8"><el-form-item label="站点名称"><el-input v-model="stationQuery.name" clearable placeholder="请输入" /></el-form-item></el-col>
|
||||||
<el-col :span="8"><el-form-item label="详细地址"><el-input v-model="stationQuery.detailAddress" clearable placeholder="请输入" /></el-form-item></el-col>
|
<el-col :span="8"><el-form-item label="详细地址"><el-input v-model="stationQuery.detailAddress" clearable placeholder="请输入" /></el-form-item></el-col>
|
||||||
@@ -652,6 +662,8 @@ export default {
|
|||||||
addressQuery: {},
|
addressQuery: {},
|
||||||
addressPage: { current: 1, size: 10, total: 0 },
|
addressPage: { current: 1, size: 10, total: 0 },
|
||||||
addressRegionPaths: { departure: [], arrival: [] },
|
addressRegionPaths: { departure: [], arrival: [] },
|
||||||
|
// 程序回填省市区时抑制 cascader @change,避免空值回调把已填地址清空
|
||||||
|
suppressAddressRegionChange: false,
|
||||||
regionOptions: [],
|
regionOptions: [],
|
||||||
regionLoading: false,
|
regionLoading: false,
|
||||||
regionRequest: null,
|
regionRequest: null,
|
||||||
@@ -714,7 +726,7 @@ export default {
|
|||||||
'msg',
|
'msg',
|
||||||
'zip',
|
'zip',
|
||||||
],
|
],
|
||||||
transports: ['公路运输', '铁路运输', '水路运输', '航空运输'],
|
transports: ['铁路运输', '水路运输', '航空运输', '公路运输'],
|
||||||
quantityUnitOptions: [],
|
quantityUnitOptions: [],
|
||||||
quantityUnitLoading: false,
|
quantityUnitLoading: false,
|
||||||
form: {
|
form: {
|
||||||
@@ -798,6 +810,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
formatContractOptionLabel,
|
formatContractOptionLabel,
|
||||||
defaultQuantityUnit() {
|
defaultQuantityUnit() {
|
||||||
|
if (this.quantityUnitOptions.includes('吨')) return '吨';
|
||||||
return this.quantityUnitOptions[0] || '吨';
|
return this.quantityUnitOptions[0] || '吨';
|
||||||
},
|
},
|
||||||
loadQuantityUnitOptions() {
|
loadQuantityUnitOptions() {
|
||||||
@@ -888,26 +901,63 @@ export default {
|
|||||||
findRegionPathByName(options = [], regionName = '', parents = []) {
|
findRegionPathByName(options = [], regionName = '', parents = []) {
|
||||||
const target = String(regionName || '').replace(/\s+/g, '');
|
const target = String(regionName || '').replace(/\s+/g, '');
|
||||||
if (!target) return [];
|
if (!target) return [];
|
||||||
|
let suffixMatch = [];
|
||||||
for (const item of options) {
|
for (const item of options) {
|
||||||
const nextParents = [...parents, item];
|
const nextParents = [...parents, item];
|
||||||
const name = nextParents.map(region => region.title || region.name || '').join('');
|
const name = nextParents.map(region => region.title || region.name || '').join('');
|
||||||
if (name === target) return nextParents.map(region => region.id);
|
if (name === target) return nextParents.map(region => region.id);
|
||||||
|
// 常用地址可能缺省名,允许「市+区」后缀命中完整省市区路径
|
||||||
|
if (!suffixMatch.length && name.endsWith(target) && target.length >= 2) {
|
||||||
|
suffixMatch = nextParents.map(region => region.id);
|
||||||
|
}
|
||||||
const path = this.findRegionPathByName(item.children, target, nextParents);
|
const path = this.findRegionPathByName(item.children, target, nextParents);
|
||||||
if (path.length) return path;
|
if (path.length) return path;
|
||||||
}
|
}
|
||||||
return [];
|
return suffixMatch;
|
||||||
},
|
},
|
||||||
findRegionPathByCode(options = [], regionCode = '', parents = []) {
|
findRegionPathByCode(options = [], regionCode = '', parents = []) {
|
||||||
const target = String(regionCode || '').trim();
|
const target = String(regionCode || '').trim();
|
||||||
if (!target) return [];
|
if (!target) return [];
|
||||||
for (const item of options) {
|
for (const item of options) {
|
||||||
const nextParents = [...parents, item];
|
const nextParents = [...parents, item];
|
||||||
if (String(item.id) === target) return nextParents.map(region => region.id);
|
if (String(item.id) === target || String(item.value || '') === target) {
|
||||||
|
return nextParents.map(region => region.id);
|
||||||
|
}
|
||||||
const path = this.findRegionPathByCode(item.children, target, nextParents);
|
const path = this.findRegionPathByCode(item.children, target, nextParents);
|
||||||
if (path.length) return path;
|
if (path.length) return path;
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
},
|
},
|
||||||
|
resolveRegionPath(field) {
|
||||||
|
if (!field) return [];
|
||||||
|
const codePath = this.findRegionPathByCode(
|
||||||
|
this.regionOptions,
|
||||||
|
field.model[field.regionCode]
|
||||||
|
);
|
||||||
|
if (codePath.length) return codePath;
|
||||||
|
const namePath = this.findRegionPathByName(this.regionOptions, field.model[field.name]);
|
||||||
|
if (namePath.length) return namePath;
|
||||||
|
const composed = [field.model[field.provinceName], field.model[field.cityName], field.model[field.districtName]]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('');
|
||||||
|
return this.findRegionPathByName(this.regionOptions, composed);
|
||||||
|
},
|
||||||
|
setAddressRegionPath(target, path = []) {
|
||||||
|
const nextPath = Array.isArray(path) ? path.map(item => String(item)) : [];
|
||||||
|
const current = this.addressRegionPaths[target] || [];
|
||||||
|
if (
|
||||||
|
current.length === nextPath.length &&
|
||||||
|
current.every((item, index) => String(item) === String(nextPath[index]))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.suppressAddressRegionChange = true;
|
||||||
|
// Vue3 直接写动态 key,避免整体替换对象导致其它 cascader 重建并触发空 @change
|
||||||
|
this.addressRegionPaths[target] = nextPath;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.suppressAddressRegionChange = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
regionLabels(path = []) {
|
regionLabels(path = []) {
|
||||||
let options = this.regionOptions;
|
let options = this.regionOptions;
|
||||||
const labels = [];
|
const labels = [];
|
||||||
@@ -946,10 +996,22 @@ export default {
|
|||||||
this.setAddressRegionNames(field, [provinceMatch?.[0], cityMatch?.[0], districtMatch?.[0]]);
|
this.setAddressRegionNames(field, [provinceMatch?.[0], cityMatch?.[0], districtMatch?.[0]]);
|
||||||
},
|
},
|
||||||
handleAddressRegionChange(target, value) {
|
handleAddressRegionChange(target, value) {
|
||||||
|
if (this.suppressAddressRegionChange) return;
|
||||||
const field = this.addressModel(target);
|
const field = this.addressModel(target);
|
||||||
const path = Array.isArray(value) ? value.map(item => String(item)) : [];
|
const path = Array.isArray(value) ? value.map(item => String(item)) : [];
|
||||||
this.addressRegionPaths = { ...this.addressRegionPaths, [target]: path };
|
this.setAddressRegionPath(target, path);
|
||||||
if (!field) return;
|
if (!field) return;
|
||||||
|
// 程序回填/重建过程中 cascader 可能短暂抛出空值,不能据此清空已选常用地址
|
||||||
|
if (!path.length) {
|
||||||
|
const hasExisting =
|
||||||
|
String(field.model[field.name] || '').trim() ||
|
||||||
|
String(field.model[field.address] || '').trim() ||
|
||||||
|
String(field.model[field.regionCode] || '').trim();
|
||||||
|
if (hasExisting) {
|
||||||
|
this.$nextTick(() => this.syncAddressRegionPath(target));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
const labels = this.regionLabels(path);
|
const labels = this.regionLabels(path);
|
||||||
field.model[field.name] = labels.join('');
|
field.model[field.name] = labels.join('');
|
||||||
field.model[field.regionCode] = path.at(-1) || '';
|
field.model[field.regionCode] = path.at(-1) || '';
|
||||||
@@ -958,19 +1020,29 @@ export default {
|
|||||||
},
|
},
|
||||||
syncAddressRegionPath(target) {
|
syncAddressRegionPath(target) {
|
||||||
const field = this.addressModel(target);
|
const field = this.addressModel(target);
|
||||||
if (!field) return;
|
if (!field || !this.regionOptions.length) return;
|
||||||
const codePath = this.findRegionPathByCode(this.regionOptions, field.model[field.regionCode]);
|
const path = this.resolveRegionPath(field);
|
||||||
const path = codePath.length
|
this.setAddressRegionPath(target, path);
|
||||||
? codePath
|
|
||||||
: this.findRegionPathByName(this.regionOptions, field.model[field.name]);
|
|
||||||
this.addressRegionPaths = { ...this.addressRegionPaths, [target]: path };
|
|
||||||
if (path.length) this.setAddressRegionNames(field, this.regionLabels(path));
|
if (path.length) this.setAddressRegionNames(field, this.regionLabels(path));
|
||||||
},
|
},
|
||||||
syncAddressRegionPaths() {
|
syncAddressRegionPaths() {
|
||||||
if (!this.regionOptions.length) return;
|
if (!this.regionOptions.length) return;
|
||||||
['departure', 'arrival', ...this.form.routes.map((route, index) => `route-${index}`)].forEach(target => {
|
this.suppressAddressRegionChange = true;
|
||||||
this.syncAddressRegionPath(target);
|
try {
|
||||||
});
|
['departure', 'arrival', ...this.form.routes.map((route, index) => `route-${index}`)].forEach(
|
||||||
|
target => {
|
||||||
|
const field = this.addressModel(target);
|
||||||
|
if (!field) return;
|
||||||
|
const path = this.resolveRegionPath(field);
|
||||||
|
this.addressRegionPaths[target] = path;
|
||||||
|
if (path.length) this.setAddressRegionNames(field, this.regionLabels(path));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.suppressAddressRegionChange = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async loadDetail(id) {
|
async loadDetail(id) {
|
||||||
const res = await api.getDetail(id);
|
const res = await api.getDetail(id);
|
||||||
@@ -1144,13 +1216,15 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
addressTransportType(target) {
|
addressTransportType(target) {
|
||||||
if (target.startsWith('route-')) {
|
const key = String(target || '');
|
||||||
return this.form.routes[Number(target.slice(6))]?.transportType || '';
|
if (key.startsWith('route-')) {
|
||||||
|
return String(this.form.routes[Number(key.slice(6))]?.transportType || '');
|
||||||
}
|
}
|
||||||
return target === 'arrival' ? this.form.finalTransportType : this.form.routes[0]?.transportType || '';
|
if (key === 'arrival') return String(this.form.finalTransportType || '');
|
||||||
|
return String(this.form.routes[0]?.transportType || '');
|
||||||
},
|
},
|
||||||
addressTransportMode(target) {
|
addressTransportMode(target) {
|
||||||
const type = this.addressTransportType(target);
|
const type = String(this.addressTransportType(target) || '');
|
||||||
if (type.includes('铁路')) return 'rail';
|
if (type.includes('铁路')) return 'rail';
|
||||||
if (type.includes('水路') || type.includes('水运') || type.includes('海运')) return 'water';
|
if (type.includes('水路') || type.includes('水运') || type.includes('海运')) return 'water';
|
||||||
if (type.includes('航空') || type.includes('空运')) return 'air';
|
if (type.includes('航空') || type.includes('空运')) return 'air';
|
||||||
@@ -1164,8 +1238,7 @@ export default {
|
|||||||
const field = this.addressModel(target);
|
const field = this.addressModel(target);
|
||||||
if (!field) return false;
|
if (!field) return false;
|
||||||
const siteCode = String(field.model[field.siteCode] || '').trim();
|
const siteCode = String(field.model[field.siteCode] || '').trim();
|
||||||
// 地址展示模式由实际选择的数据决定:有站点编码表示非公路站点名称,
|
// 展示模式由已选数据决定:有站点编码则显示站点名,否则省市区;暂不按运输方式强制站点限制。
|
||||||
// 没有站点编码则保留省市区级联,避免切换运输方式时改写已有地址。
|
|
||||||
return Boolean(siteCode && siteCode !== '/');
|
return Boolean(siteCode && siteCode !== '/');
|
||||||
},
|
},
|
||||||
resolveAddressRegionCode(row = {}) {
|
resolveAddressRegionCode(row = {}) {
|
||||||
@@ -1174,12 +1247,7 @@ export default {
|
|||||||
openCommonAddress(target) {
|
openCommonAddress(target) {
|
||||||
if (this.isBasicRouteReadonly) return;
|
if (this.isBasicRouteReadonly) return;
|
||||||
this.addressTarget = target;
|
this.addressTarget = target;
|
||||||
if (this.addressTransportMode(target) !== 'road') {
|
// 暂不按运输方式限制站点:统一走常用地址选择。
|
||||||
this.stationQuery = {};
|
|
||||||
this.stationPage.current = 1;
|
|
||||||
this.stationDialogVisible = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.addressQuery = {};
|
this.addressQuery = {};
|
||||||
this.addressPage.current = 1;
|
this.addressPage.current = 1;
|
||||||
this.addressDialogVisible = true;
|
this.addressDialogVisible = true;
|
||||||
@@ -1224,8 +1292,9 @@ export default {
|
|||||||
this.stationPage.current = 1;
|
this.stationPage.current = 1;
|
||||||
this.loadStationList();
|
this.loadStationList();
|
||||||
},
|
},
|
||||||
selectStation(row) {
|
async selectStation(row) {
|
||||||
const target = this.addressModel(this.addressTarget);
|
const targetKey = this.addressTarget;
|
||||||
|
const target = this.addressModel(targetKey);
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
const station = this.normalizeStation(row);
|
const station = this.normalizeStation(row);
|
||||||
target.model[target.name] = station.stationName || station.regionName;
|
target.model[target.name] = station.stationName || station.regionName;
|
||||||
@@ -1236,7 +1305,9 @@ export default {
|
|||||||
target.model[target.siteCode] = station.stationCode;
|
target.model[target.siteCode] = station.stationCode;
|
||||||
this.setAddressRegionNamesFromRow(target, station);
|
this.setAddressRegionNamesFromRow(target, station);
|
||||||
this.stationDialogVisible = false;
|
this.stationDialogVisible = false;
|
||||||
this.loadRegionOptions().then(() => this.syncAddressRegionPath(this.addressTarget));
|
await this.loadRegionOptions();
|
||||||
|
await this.$nextTick();
|
||||||
|
this.syncAddressRegionPath(targetKey);
|
||||||
},
|
},
|
||||||
async loadAddressList() {
|
async loadAddressList() {
|
||||||
this.addressLoading = true;
|
this.addressLoading = true;
|
||||||
@@ -1262,8 +1333,9 @@ export default {
|
|||||||
this.addressPage.current = 1;
|
this.addressPage.current = 1;
|
||||||
this.loadAddressList();
|
this.loadAddressList();
|
||||||
},
|
},
|
||||||
selectAddress(row) {
|
async selectAddress(row) {
|
||||||
const target = this.addressModel(this.addressTarget);
|
const targetKey = this.addressTarget;
|
||||||
|
const target = this.addressModel(targetKey);
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
target.model[target.name] = row.regionName || row.addressName || '';
|
target.model[target.name] = row.regionName || row.addressName || '';
|
||||||
target.model[target.address] = row.detailAddress || row.address || '';
|
target.model[target.address] = row.detailAddress || row.address || '';
|
||||||
@@ -1275,22 +1347,17 @@ export default {
|
|||||||
target.model[target.siteCode] = '';
|
target.model[target.siteCode] = '';
|
||||||
this.setAddressRegionNamesFromRow(target, row);
|
this.setAddressRegionNamesFromRow(target, row);
|
||||||
this.addressDialogVisible = false;
|
this.addressDialogVisible = false;
|
||||||
this.loadRegionOptions().then(() => this.syncAddressRegionPath(this.addressTarget));
|
await this.loadRegionOptions();
|
||||||
|
// nextTick 确保途经点动态 key 已挂载 cascader 后再回填路径
|
||||||
|
await this.$nextTick();
|
||||||
|
this.syncAddressRegionPath(targetKey);
|
||||||
},
|
},
|
||||||
handleAddressDetailClick(target) {
|
handleAddressDetailClick(target) {
|
||||||
if (this.isBasicRouteReadonly) return;
|
if (this.isBasicRouteReadonly) return;
|
||||||
if (this.addressTransportMode(target) !== 'road') {
|
|
||||||
this.openCommonAddress(target);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.openAddressMap(target);
|
this.openAddressMap(target);
|
||||||
},
|
},
|
||||||
openAddressMap(target) {
|
openAddressMap(target) {
|
||||||
if (this.isBasicRouteReadonly) return;
|
if (this.isBasicRouteReadonly) return;
|
||||||
if (this.addressTransportMode(target) !== 'road') {
|
|
||||||
this.$message.info('非公路运输地址不能使用地图选择');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const field = this.addressModel(target);
|
const field = this.addressModel(target);
|
||||||
if (!field) return;
|
if (!field) return;
|
||||||
this.mapTarget = target;
|
this.mapTarget = target;
|
||||||
@@ -1690,7 +1757,11 @@ export default {
|
|||||||
'',
|
'',
|
||||||
cargoTypePath,
|
cargoTypePath,
|
||||||
quantity: row.quantity || '',
|
quantity: row.quantity || '',
|
||||||
quantityUnit: row.quantityUnit || this.defaultQuantityUnit(),
|
// 常用货物单位若为空或「个」,新建总单统一默认「吨」
|
||||||
|
quantityUnit:
|
||||||
|
!row.quantityUnit || String(row.quantityUnit).trim() === '个'
|
||||||
|
? this.defaultQuantityUnit()
|
||||||
|
: row.quantityUnit,
|
||||||
packageType: row.packageType || row.package || '',
|
packageType: row.packageType || row.package || '',
|
||||||
brand: row.brand || '',
|
brand: row.brand || '',
|
||||||
specification: row.specification || row.spec || '',
|
specification: row.specification || row.spec || '',
|
||||||
@@ -1775,17 +1846,21 @@ export default {
|
|||||||
return formatUpdateUserName(row);
|
return formatUpdateUserName(row);
|
||||||
},
|
},
|
||||||
selectRoute(route) {
|
selectRoute(route) {
|
||||||
|
// 先写入运输方式(会触发地点清空),再回填线路地址,避免被清空逻辑覆盖。
|
||||||
|
this.form.finalTransportType = '公路运输';
|
||||||
|
if (!this.form.routes.length) this.addRoute();
|
||||||
|
if (this.form.routes[0]) this.form.routes[0].transportType = '公路运输';
|
||||||
this.form.departureName = route.departureName || '';
|
this.form.departureName = route.departureName || '';
|
||||||
this.form.departureAddress = route.departureAddress || '';
|
this.form.departureAddress = route.departureAddress || '';
|
||||||
this.form.departureContact = route.departureContact || '';
|
this.form.departureContact = route.departureContact || '';
|
||||||
this.form.departurePhone = route.departurePhone || '';
|
this.form.departurePhone = route.departurePhone || '';
|
||||||
|
this.form.departureSiteCode = '';
|
||||||
this.form.arrivalName = route.arrivalName || '';
|
this.form.arrivalName = route.arrivalName || '';
|
||||||
this.form.arrivalAddress = route.arrivalAddress || '';
|
this.form.arrivalAddress = route.arrivalAddress || '';
|
||||||
this.form.arrivalContact = route.arrivalContact || '';
|
this.form.arrivalContact = route.arrivalContact || '';
|
||||||
this.form.arrivalPhone = route.arrivalPhone || '';
|
this.form.arrivalPhone = route.arrivalPhone || '';
|
||||||
|
this.form.arrivalSiteCode = '';
|
||||||
this.syncAddressRegionPaths();
|
this.syncAddressRegionPaths();
|
||||||
this.form.finalTransportType = '公路运输';
|
|
||||||
if (!this.form.routes.length) this.addRoute();
|
|
||||||
this.routeDialogVisible = false;
|
this.routeDialogVisible = false;
|
||||||
},
|
},
|
||||||
createRoute(index = this.form.routes.length) {
|
createRoute(index = this.form.routes.length) {
|
||||||
@@ -1793,12 +1868,23 @@ export default {
|
|||||||
},
|
},
|
||||||
addRoute() {
|
addRoute() {
|
||||||
if (this.isBasicRouteReadonly) return;
|
if (this.isBasicRouteReadonly) return;
|
||||||
this.form.routes.push(this.createRoute());
|
const index = this.form.routes.length;
|
||||||
|
this.form.routes.push(this.createRoute(index));
|
||||||
|
this.addressRegionPaths[`route-${index}`] = [];
|
||||||
},
|
},
|
||||||
removeRoute(index) {
|
removeRoute(index) {
|
||||||
if (this.isBasicRouteReadonly) return;
|
if (this.isBasicRouteReadonly) return;
|
||||||
this.form.routes.splice(index, 1);
|
this.form.routes.splice(index, 1);
|
||||||
this.syncAddressRegionPaths();
|
const nextPaths = { departure: this.addressRegionPaths.departure || [], arrival: this.addressRegionPaths.arrival || [] };
|
||||||
|
this.form.routes.forEach((route, routeIndex) => {
|
||||||
|
nextPaths[`route-${routeIndex}`] = this.addressRegionPaths[`route-${routeIndex >= index ? routeIndex + 1 : routeIndex}`] || [];
|
||||||
|
});
|
||||||
|
this.suppressAddressRegionChange = true;
|
||||||
|
this.addressRegionPaths = nextPaths;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.suppressAddressRegionChange = false;
|
||||||
|
this.syncAddressRegionPaths();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
goodsKey(row = {}) {
|
goodsKey(row = {}) {
|
||||||
return `${row.cargoName || ''}\u0000${row.cargoType || ''}`;
|
return `${row.cargoName || ''}\u0000${row.cargoType || ''}`;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
:class="{ 'punch-record-photos__grid--edit': editable }"
|
:class="{ 'punch-record-photos__grid--edit': editable }"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(item, groupIndex) in group.items"
|
v-for="item in group.items"
|
||||||
:key="`${item.photo.url}-${item.index}`"
|
:key="`${item.photo.url}-${item.index}`"
|
||||||
class="punch-record-photos__item"
|
class="punch-record-photos__item"
|
||||||
@click="handlePreview(item.index)"
|
@click="handlePreview(item.index)"
|
||||||
@@ -23,8 +23,6 @@
|
|||||||
:lazy="lazy"
|
:lazy="lazy"
|
||||||
fit="cover"
|
fit="cover"
|
||||||
/>
|
/>
|
||||||
<!-- 主图 = 该类型的第一张,按上传顺序取;没有独立字段,也不可切换 -->
|
|
||||||
<div v-if="groupIndex === 0" class="punch-record-photos__badge">主图</div>
|
|
||||||
<el-link
|
<el-link
|
||||||
v-if="editable"
|
v-if="editable"
|
||||||
class="punch-record-photos__remove"
|
class="punch-record-photos__remove"
|
||||||
@@ -59,7 +57,7 @@
|
|||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
// 打卡照片是每个打卡节点必有的一个照片类型,不由过程配置的凭证类型决定;
|
// 打卡照片是每个打卡节点必有的一个照片类型,不由过程配置的凭证类型决定;
|
||||||
// 它与各凭证类型各自最多 9 张,同一类型下第一张即界面上的「主图」。
|
// 它与各凭证类型各自最多 9 张。
|
||||||
const PUNCH_PHOTO_TYPE = '打卡照片';
|
const PUNCH_PHOTO_TYPE = '打卡照片';
|
||||||
// 照片没带类型时的兜底名称,与后端落库时的兜底口径一致
|
// 照片没带类型时的兜底名称,与后端落库时的兜底口径一致
|
||||||
const PHOTO_TYPE_FALLBACK = '凭证';
|
const PHOTO_TYPE_FALLBACK = '凭证';
|
||||||
@@ -252,18 +250,6 @@ const countText = group =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__badge {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
padding: 0 6px;
|
|
||||||
border-radius: 4px 0 4px 0;
|
|
||||||
background: rgba(64, 158, 255, 0.9);
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 18px;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__remove {
|
&__remove {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@@ -388,7 +388,7 @@
|
|||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
@visible-change="visible => visible && loadFeeUnitOptions()"
|
@visible-change="visible => visible && loadFeeUnitOptions()"
|
||||||
><el-option
|
><el-option
|
||||||
v-for="unit in feeUnitOptions"
|
v-for="unit in feeUnitSelectOptions"
|
||||||
:key="unit.value"
|
:key="unit.value"
|
||||||
:label="unit.label"
|
:label="unit.label"
|
||||||
:value="unit.value" /></el-select
|
:value="unit.value" /></el-select
|
||||||
@@ -1124,6 +1124,10 @@ import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
|||||||
import { getDictionary } from '@/api/system/dictbiz';
|
import { getDictionary } from '@/api/system/dictbiz';
|
||||||
import { packageOptions } from '@/option/business/common';
|
import { packageOptions } from '@/option/business/common';
|
||||||
import { formatContractOptionLabel } from '@/utils/contract';
|
import { formatContractOptionLabel } from '@/utils/contract';
|
||||||
|
import {
|
||||||
|
mapFeeUnitOptions,
|
||||||
|
resolvePriceUnitByQuantityUnit,
|
||||||
|
} from '@/utils/currency';
|
||||||
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||||
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
||||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||||
@@ -1264,6 +1268,10 @@ const PageAvueForm = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const shippingTemplateListRoute = '/business/shipping-template';
|
||||||
|
const shippingTemplateFormRoute = '/business/shipping-template/form';
|
||||||
|
const shippingTemplateListRefreshKey = 'shipping-template-list-refresh';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ShippingTemplatePage',
|
name: 'ShippingTemplatePage',
|
||||||
components: { PageAvueForm, ElImageViewer, OpenFileViewer },
|
components: { PageAvueForm, ElImageViewer, OpenFileViewer },
|
||||||
@@ -1280,6 +1288,9 @@ export default {
|
|||||||
return {
|
return {
|
||||||
Location,
|
Location,
|
||||||
OfficeBuilding,
|
OfficeBuilding,
|
||||||
|
// 实例所属路由快照,避免 keep-alive 列表实例被全局 $route 误判成表单页。
|
||||||
|
routePathLocked: this.$route.path,
|
||||||
|
isFormPageInstance: this.$route.path === shippingTemplateFormRoute,
|
||||||
form: {},
|
form: {},
|
||||||
query: {},
|
query: {},
|
||||||
loading: true,
|
loading: true,
|
||||||
@@ -1401,13 +1412,18 @@ export default {
|
|||||||
isStandaloneBusinessPage() {
|
isStandaloneBusinessPage() {
|
||||||
return (
|
return (
|
||||||
this.standaloneFormPage &&
|
this.standaloneFormPage &&
|
||||||
['/business/shipping-template', '/business/shipping-template/form'].includes(
|
(this.isFormPageInstance ||
|
||||||
this.$route.path
|
[shippingTemplateListRoute, shippingTemplateFormRoute].includes(this.routePathLocked) ||
|
||||||
)
|
[shippingTemplateListRoute, shippingTemplateFormRoute].includes(this.$route.path))
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
isStandaloneFormPage() {
|
isStandaloneFormPage() {
|
||||||
return this.isStandaloneBusinessPage && ['add', 'edit'].includes(this.$route.query.mode);
|
// 用实例锁定标志,避免列表 keep-alive 实例被全局路由误判成表单页。
|
||||||
|
return (
|
||||||
|
this.standaloneFormPage &&
|
||||||
|
this.isFormPageInstance &&
|
||||||
|
['add', 'edit'].includes(this.$route.query.mode)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
formPageTitle() {
|
formPageTitle() {
|
||||||
return this.isStandaloneFormPage
|
return this.isStandaloneFormPage
|
||||||
@@ -1464,6 +1480,12 @@ export default {
|
|||||||
);
|
);
|
||||||
return this.currencyUnit(option?.label || this.shippingTemplateFreight.currency);
|
return this.currencyUnit(option?.label || this.shippingTemplateFreight.currency);
|
||||||
},
|
},
|
||||||
|
feeUnitSelectOptions() {
|
||||||
|
return mapFeeUnitOptions(
|
||||||
|
this.feeUnitOptions,
|
||||||
|
this.shippingTemplateFreight.currency || 'RMB'
|
||||||
|
);
|
||||||
|
},
|
||||||
roadFreightTotal() {
|
roadFreightTotal() {
|
||||||
const total = this.shippingTemplateFreight.freightItems.reduce(
|
const total = this.shippingTemplateFreight.freightItems.reduce(
|
||||||
(sum, item) => sum + Number(this.freightAmount(item) || 0),
|
(sum, item) => sum + Number(this.freightAmount(item) || 0),
|
||||||
@@ -1530,6 +1552,18 @@ export default {
|
|||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route(to, from) {
|
$route(to, from) {
|
||||||
|
// 列表实例:从其他页进入列表时刷新(activated 负责标签切回)。
|
||||||
|
if (!this.isFormPageInstance) {
|
||||||
|
const enteringList =
|
||||||
|
(to.path === this.routePathLocked || to.path === shippingTemplateListRoute) &&
|
||||||
|
from?.path &&
|
||||||
|
from.path !== to.path;
|
||||||
|
if (enteringList) {
|
||||||
|
sessionStorage.removeItem(shippingTemplateListRefreshKey);
|
||||||
|
this.$nextTick(() => this.onLoad(this.page, this.query));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
this.isStandaloneFormPage &&
|
this.isStandaloneFormPage &&
|
||||||
(to.query.mode !== from?.query?.mode ||
|
(to.query.mode !== from?.query?.mode ||
|
||||||
@@ -1550,6 +1584,10 @@ export default {
|
|||||||
this.handleTransportTypeChange(value);
|
this.handleTransportTypeChange(value);
|
||||||
this.syncFreightItems();
|
this.syncFreightItems();
|
||||||
},
|
},
|
||||||
|
'form.templateType'() {
|
||||||
|
// 切换到运单模板时立即按货物数量单位生成公路运费明细。
|
||||||
|
this.$nextTick(() => this.syncFreightItems());
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.loadProjectOptions();
|
this.loadProjectOptions();
|
||||||
@@ -1559,8 +1597,16 @@ export default {
|
|||||||
this.loadCurrencyOptions();
|
this.loadCurrencyOptions();
|
||||||
if (this.isStandaloneFormPage) this.$nextTick(() => this.initStandaloneFormPage());
|
if (this.isStandaloneFormPage) this.$nextTick(() => this.initStandaloneFormPage());
|
||||||
},
|
},
|
||||||
|
activated() {
|
||||||
|
if (this.isFormPageInstance) return;
|
||||||
|
sessionStorage.removeItem(shippingTemplateListRefreshKey);
|
||||||
|
this.$nextTick(() => this.onLoad(this.page, this.query));
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatContractOptionLabel,
|
formatContractOptionLabel,
|
||||||
|
markShippingTemplateListNeedRefresh() {
|
||||||
|
sessionStorage.setItem(shippingTemplateListRefreshKey, '1');
|
||||||
|
},
|
||||||
loadQuantityUnitOptions() {
|
loadQuantityUnitOptions() {
|
||||||
if (this.quantityUnitLoading) return this.quantityUnitLoadPromise;
|
if (this.quantityUnitLoading) return this.quantityUnitLoadPromise;
|
||||||
this.quantityUnitLoading = true;
|
this.quantityUnitLoading = true;
|
||||||
@@ -1591,12 +1637,8 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (this.menuWidth != null) next.menuWidth = this.menuWidth;
|
if (this.menuWidth != null) next.menuWidth = this.menuWidth;
|
||||||
if (
|
// 仅表单页实例套用全屏表单弹窗样式,避免列表页误用后表格区域异常。
|
||||||
this.standaloneFormPage &&
|
if (this.standaloneFormPage && this.$route.path === shippingTemplateFormRoute) {
|
||||||
['/business/shipping-template', '/business/shipping-template/form'].includes(
|
|
||||||
this.$route.path
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
next.dialogAppendToBody = false;
|
next.dialogAppendToBody = false;
|
||||||
next.dialogModal = false;
|
next.dialogModal = false;
|
||||||
next.dialogCustomClass = 'shipping-template-form-page-dialog';
|
next.dialogCustomClass = 'shipping-template-form-page-dialog';
|
||||||
@@ -1776,13 +1818,22 @@ export default {
|
|||||||
this.onLoad(this.page, this.query);
|
this.onLoad(this.page, this.query);
|
||||||
},
|
},
|
||||||
onLoad(page, params = {}) {
|
onLoad(page, params = {}) {
|
||||||
|
if (this.isFormPageInstance) return;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
const currentPage = page?.currentPage || this.page.currentPage || 1;
|
||||||
|
const pageSize = page?.pageSize || this.page.pageSize || 10;
|
||||||
this.api
|
this.api
|
||||||
.getList(page.currentPage, page.pageSize, { ...this.query, ...params })
|
.getList(currentPage, pageSize, { ...this.query, ...params })
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const data = res?.data?.data || {};
|
const data = res?.data?.data || res?.data || {};
|
||||||
this.data = extractRecords(res);
|
const records = extractRecords(res);
|
||||||
this.page.total = data.total || this.data.length;
|
this.data = records;
|
||||||
|
this.page.total = Number(data.total ?? records.length) || 0;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
window.console.error(error);
|
||||||
|
this.data = [];
|
||||||
|
this.page.total = 0;
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
@@ -1821,9 +1872,10 @@ export default {
|
|||||||
.submit(submit)
|
.submit(submit)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$message.success('操作成功');
|
this.$message.success('操作成功');
|
||||||
|
this.markShippingTemplateListNeedRefresh();
|
||||||
done?.();
|
done?.();
|
||||||
this.closeCrudDialog();
|
this.closeCrudDialog();
|
||||||
this.onLoad(this.page, this.query);
|
if (!this.isFormPageInstance) this.onLoad(this.page, this.query);
|
||||||
})
|
})
|
||||||
.catch(() => loading?.());
|
.catch(() => loading?.());
|
||||||
},
|
},
|
||||||
@@ -1837,9 +1889,10 @@ export default {
|
|||||||
.submit(submit)
|
.submit(submit)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$message.success('操作成功');
|
this.$message.success('操作成功');
|
||||||
|
this.markShippingTemplateListNeedRefresh();
|
||||||
done?.();
|
done?.();
|
||||||
this.closeCrudDialog();
|
this.closeCrudDialog();
|
||||||
this.onLoad(this.page, this.query);
|
if (!this.isFormPageInstance) this.onLoad(this.page, this.query);
|
||||||
})
|
})
|
||||||
.catch(() => loading?.());
|
.catch(() => loading?.());
|
||||||
},
|
},
|
||||||
@@ -1883,6 +1936,8 @@ export default {
|
|||||||
this.attachmentRows = [];
|
this.attachmentRows = [];
|
||||||
this.shippingTemplateFreight = defaultFreight();
|
this.shippingTemplateFreight = defaultFreight();
|
||||||
this.loadCurrencyOptions();
|
this.loadCurrencyOptions();
|
||||||
|
this.loadFeeUnitOptions();
|
||||||
|
this.$nextTick(() => this.syncFreightItems());
|
||||||
if (typeof this.api.nextCode === 'function')
|
if (typeof this.api.nextCode === 'function')
|
||||||
this.api
|
this.api
|
||||||
.nextCode()
|
.nextCode()
|
||||||
@@ -2005,20 +2060,47 @@ export default {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.transportMode === 'road') {
|
if (this.transportMode === 'road') {
|
||||||
const invalid = this.shippingTemplateFreight.freightItems.findIndex(
|
if (!this.shippingTemplateFreight.freightItems.length) {
|
||||||
item =>
|
this.$message.warning('请先完善货物数量单位,以便生成运费明细');
|
||||||
Number(item.unitPrice || 0) < 0 ||
|
|
||||||
!item.priceUnit ||
|
|
||||||
(!this.isFreightAutoCalculable(item) &&
|
|
||||||
(item.freightAmount === '' ||
|
|
||||||
item.freightAmount === null ||
|
|
||||||
item.freightAmount === undefined)) ||
|
|
||||||
Number(item.freightAmount || 0) < 0
|
|
||||||
);
|
|
||||||
if (invalid > -1) {
|
|
||||||
this.$message.warning(`第${invalid + 1}条货物的单价、计价单位或运费无效`);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
for (const [index, item] of this.shippingTemplateFreight.freightItems.entries()) {
|
||||||
|
const label = `第${index + 1}条运费明细`;
|
||||||
|
if (
|
||||||
|
item.unitPrice === '' ||
|
||||||
|
item.unitPrice === null ||
|
||||||
|
item.unitPrice === undefined
|
||||||
|
) {
|
||||||
|
this.$message.warning(`请填写${label}的单价`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Number(item.unitPrice) < 0) {
|
||||||
|
this.$message.warning(`${label}的单价不能小于0`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!String(item.priceUnit || '').trim()) {
|
||||||
|
this.$message.warning(`请选择${label}的计价单位`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.isFreightAutoCalculable(item)) {
|
||||||
|
if (!item.freightAmountManual) {
|
||||||
|
item.freightAmount = this.freightAmount(item);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
item.freightAmount === '' ||
|
||||||
|
item.freightAmount === null ||
|
||||||
|
item.freightAmount === undefined
|
||||||
|
) {
|
||||||
|
this.$message.warning(
|
||||||
|
`${label}的计价单位与货物数量单位不匹配,无法自动计算运费,请手动填写运费`
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Number(item.freightAmount || 0) < 0) {
|
||||||
|
this.$message.warning(`${label}的运费不能小于0`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (Number(this.shippingTemplateFreight.freightAmount || 0) < 0) {
|
} else if (Number(this.shippingTemplateFreight.freightAmount || 0) < 0) {
|
||||||
this.$message.warning('运费不能小于0');
|
this.$message.warning('运费不能小于0');
|
||||||
return false;
|
return false;
|
||||||
@@ -2033,8 +2115,11 @@ export default {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
closeCrudDialog() {
|
closeCrudDialog() {
|
||||||
if (this.isStandaloneBusinessPage) {
|
if (this.isStandaloneBusinessPage || this.isFormPageInstance) {
|
||||||
this.$router.push({ path: '/business/shipping-template', query: {} });
|
// 关闭独立表单页时标记列表需刷新(含直接点关闭未保存的场景)
|
||||||
|
this.markShippingTemplateListNeedRefresh();
|
||||||
|
this.$router.$avueRouter?.closeTag?.();
|
||||||
|
this.$router.push({ path: shippingTemplateListRoute, query: {} });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.$refs.crud?.closeDialog?.();
|
this.$refs.crud?.closeDialog?.();
|
||||||
@@ -2294,7 +2379,16 @@ export default {
|
|||||||
},
|
},
|
||||||
loadFeeUnitOptions() {
|
loadFeeUnitOptions() {
|
||||||
getDictionary({ code: 'unit_fee' }).then(res => {
|
getDictionary({ code: 'unit_fee' }).then(res => {
|
||||||
this.feeUnitOptions = this.normalizeDictOptions(res?.data?.data || []);
|
// 计价单位必须保存可读文案(如 元/吨),才能与货物数量单位匹配并自动计算运费。
|
||||||
|
this.feeUnitOptions = (res?.data?.data || []).map(item => {
|
||||||
|
const label = String(item.dictValue || item.label || item.value || '').trim();
|
||||||
|
const key = String(item.dictKey || item.value || '').trim();
|
||||||
|
return {
|
||||||
|
label: label || key,
|
||||||
|
value: label.includes('/') ? label : key || label,
|
||||||
|
remark: item.remark || '',
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
loadCurrencyOptions() {
|
loadCurrencyOptions() {
|
||||||
@@ -3098,24 +3192,53 @@ export default {
|
|||||||
: [];
|
: [];
|
||||||
const quantityUnits = [];
|
const quantityUnits = [];
|
||||||
this.transportCargoRows.forEach(row => {
|
this.transportCargoRows.forEach(row => {
|
||||||
const quantityUnit = row.quantityUnit || '';
|
const quantityUnit = String(row.quantityUnit || '').trim();
|
||||||
|
if (!quantityUnit) return;
|
||||||
if (!quantityUnits.some(unit => unit === quantityUnit)) quantityUnits.push(quantityUnit);
|
if (!quantityUnits.some(unit => unit === quantityUnit)) quantityUnits.push(quantityUnit);
|
||||||
});
|
});
|
||||||
|
const currency = this.shippingTemplateFreight.currency || 'RMB';
|
||||||
this.shippingTemplateFreight.freightItems = quantityUnits.map((quantityUnit, index) => {
|
this.shippingTemplateFreight.freightItems = quantityUnits.map((quantityUnit, index) => {
|
||||||
const matched =
|
const matched =
|
||||||
previousItems.find(item => String(item.quantityUnit || '') === String(quantityUnit)) ||
|
previousItems.find(item => String(item.quantityUnit || '') === String(quantityUnit)) ||
|
||||||
previousItems[index] ||
|
previousItems[index] ||
|
||||||
{};
|
{};
|
||||||
|
const defaultPriceUnit = resolvePriceUnitByQuantityUnit(quantityUnit, currency);
|
||||||
|
const priceUnit = this.normalizeFreightPriceUnit(
|
||||||
|
matched.priceUnit || defaultPriceUnit || '',
|
||||||
|
quantityUnit,
|
||||||
|
currency
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
quantityUnit,
|
quantityUnit,
|
||||||
unitPrice: matched.unitPrice || '',
|
unitPrice: matched.unitPrice || '',
|
||||||
priceUnit: matched.priceUnit || '',
|
priceUnit,
|
||||||
freightAmount: matched.freightAmount ?? '',
|
freightAmount: matched.freightAmount ?? '',
|
||||||
freightAmountManual:
|
freightAmountManual:
|
||||||
matched.freightAmountManual === true || matched.manualFreightAmount === true,
|
matched.freightAmountManual === true || matched.manualFreightAmount === true,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
normalizeFreightPriceUnit(priceUnit, quantityUnit, currency = 'RMB') {
|
||||||
|
const text = this.resolvePriceUnitText(priceUnit);
|
||||||
|
if (text && this.priceUnitMatchesQuantity(text, quantityUnit)) return text;
|
||||||
|
return (
|
||||||
|
resolvePriceUnitByQuantityUnit(quantityUnit, currency) ||
|
||||||
|
text ||
|
||||||
|
String(priceUnit || '').trim()
|
||||||
|
);
|
||||||
|
},
|
||||||
|
resolvePriceUnitText(priceUnit) {
|
||||||
|
const raw = String(priceUnit || '').trim();
|
||||||
|
if (!raw) return '';
|
||||||
|
if (raw.includes('/')) return raw;
|
||||||
|
const options = this.feeUnitSelectOptions.length
|
||||||
|
? this.feeUnitSelectOptions
|
||||||
|
: this.feeUnitOptions;
|
||||||
|
const matched = options.find(
|
||||||
|
item => String(item.value) === raw || String(item.label) === raw
|
||||||
|
);
|
||||||
|
return matched?.label || raw;
|
||||||
|
},
|
||||||
quantityUnits() {
|
quantityUnits() {
|
||||||
return [
|
return [
|
||||||
...new Set(
|
...new Set(
|
||||||
@@ -3131,7 +3254,7 @@ export default {
|
|||||||
.replace(/\s+/g, '')
|
.replace(/\s+/g, '')
|
||||||
.replace(/立方米|立方公尺|方/g, '立方');
|
.replace(/立方米|立方公尺|方/g, '立方');
|
||||||
const unit = normalizeUnit(quantityUnit).replace(/[·*.]/g, '');
|
const unit = normalizeUnit(quantityUnit).replace(/[·*.]/g, '');
|
||||||
const value = String(priceUnit || '')
|
const value = String(this.resolvePriceUnitText(priceUnit) || '')
|
||||||
.trim()
|
.trim()
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/\s+/g, '');
|
.replace(/\s+/g, '');
|
||||||
@@ -3163,6 +3286,10 @@ export default {
|
|||||||
return this.formatFreightNumber(item.freightAmount);
|
return this.formatFreightNumber(item.freightAmount);
|
||||||
}
|
}
|
||||||
if (!this.isFreightAutoCalculable(item)) {
|
if (!this.isFreightAutoCalculable(item)) {
|
||||||
|
// 无法自动计算且未手工填写时返回空,避免把空值显示成 0 造成“已填写”的错觉。
|
||||||
|
if (item.freightAmount === '' || item.freightAmount === null || item.freightAmount === undefined) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
return this.formatFreightNumber(item.freightAmount);
|
return this.formatFreightNumber(item.freightAmount);
|
||||||
}
|
}
|
||||||
return this.formatFreightNumber(
|
return this.formatFreightNumber(
|
||||||
|
|||||||
@@ -1677,7 +1677,7 @@
|
|||||||
{{
|
{{
|
||||||
isDispatchPlanQuantityUnlimited(row)
|
isDispatchPlanQuantityUnlimited(row)
|
||||||
? '-'
|
? '-'
|
||||||
: formatDispatchQuantity(dispatchItemRemainingQuantity(row))
|
: formatDispatchQuantity(dispatchItemDisplayRemainingQuantity(row))
|
||||||
}}
|
}}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -1861,7 +1861,7 @@
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="司机" :required="dispatchItemForm.carrierType !== '承运商'">
|
<el-form-item label="司机" required>
|
||||||
<el-autocomplete
|
<el-autocomplete
|
||||||
v-model="dispatchItemForm.driverName"
|
v-model="dispatchItemForm.driverName"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
@@ -1870,11 +1870,15 @@
|
|||||||
:fetch-suggestions="fetchTaskDriverSuggestions"
|
:fetch-suggestions="fetchTaskDriverSuggestions"
|
||||||
:loading="taskDriverLoading"
|
:loading="taskDriverLoading"
|
||||||
@select="item => handleTaskDriverSelect('dispatch', item)"
|
@select="item => handleTaskDriverSelect('dispatch', item)"
|
||||||
/>
|
>
|
||||||
|
<template #default="{ item }">
|
||||||
|
<span>{{ driverOptionText(item) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-autocomplete>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="dispatchItemForm.carrierType === '承运商' ? '手机号' : '司机手机号'"
|
:label="dispatchItemForm.carrierType === '承运商' ? '手机号' : '司机手机号'"
|
||||||
:required="dispatchItemForm.carrierType !== '承运商'"
|
required
|
||||||
>
|
>
|
||||||
<el-input v-model="dispatchItemForm.driverPhone" placeholder="请输入" />
|
<el-input v-model="dispatchItemForm.driverPhone" placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -1893,7 +1897,11 @@
|
|||||||
:fetch-suggestions="fetchTaskEscortSuggestions"
|
:fetch-suggestions="fetchTaskEscortSuggestions"
|
||||||
:loading="taskEscortLoading"
|
:loading="taskEscortLoading"
|
||||||
@select="handleTaskEscortSelect"
|
@select="handleTaskEscortSelect"
|
||||||
/>
|
>
|
||||||
|
<template #default="{ item }">
|
||||||
|
<span>{{ driverOptionText(item) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-autocomplete>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="dispatchItemForm.carrierType !== '承运商'" label="押运人手机号">
|
<el-form-item v-if="dispatchItemForm.carrierType !== '承运商'" label="押运人手机号">
|
||||||
<el-input v-model="dispatchItemForm.escortPhone" placeholder="请输入" />
|
<el-input v-model="dispatchItemForm.escortPhone" placeholder="请输入" />
|
||||||
@@ -1955,7 +1963,7 @@
|
|||||||
class="transport-plan-page__dispatch-quantity-hint"
|
class="transport-plan-page__dispatch-quantity-hint"
|
||||||
>
|
>
|
||||||
剩余数量:{{
|
剩余数量:{{
|
||||||
formatDispatchQuantity(dispatchItemHintRemainingQuantity(dispatchItemForm))
|
formatDispatchQuantity(dispatchItemDisplayRemainingQuantity(dispatchItemForm))
|
||||||
}}
|
}}
|
||||||
{{ dispatchItemForm.quantityUnit || '吨' }}
|
{{ dispatchItemForm.quantityUnit || '吨' }}
|
||||||
</div>
|
</div>
|
||||||
@@ -2096,11 +2104,7 @@
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item v-if="dispatchIsRoadTransport" label="司机" required>
|
||||||
v-if="dispatchIsRoadTransport"
|
|
||||||
label="司机"
|
|
||||||
:required="dispatchItemForm.carrierType === '自运'"
|
|
||||||
>
|
|
||||||
<el-autocomplete
|
<el-autocomplete
|
||||||
v-model="dispatchItemForm.driverName"
|
v-model="dispatchItemForm.driverName"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
@@ -2111,11 +2115,7 @@
|
|||||||
@select="item => handleTaskDriverSelect('dispatch', item)"
|
@select="item => handleTaskDriverSelect('dispatch', item)"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item v-if="dispatchIsRoadTransport" label="手机号" required>
|
||||||
v-if="dispatchIsRoadTransport"
|
|
||||||
label="手机号"
|
|
||||||
:required="dispatchItemForm.carrierType === '自运'"
|
|
||||||
>
|
|
||||||
<el-input v-model="dispatchItemForm.driverPhone" placeholder="请输入" />
|
<el-input v-model="dispatchItemForm.driverPhone" placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
@@ -2768,7 +2768,7 @@ import {
|
|||||||
getList as getProjectList,
|
getList as getProjectList,
|
||||||
} from '@/api/business/project-apply';
|
} from '@/api/business/project-apply';
|
||||||
import { getList as getCommonRouteList } from '@/api/business/common-route';
|
import { getList as getCommonRouteList } from '@/api/business/common-route';
|
||||||
import { fetchDriversByCarrierOrganizations } from '@/utils/carrier-org-resource';
|
import { fetchDriverCandidates, driverOptionText } from '@/utils/carrier-org-resource';
|
||||||
import { getDictionary } from '@/api/system/dictbiz';
|
import { getDictionary } from '@/api/system/dictbiz';
|
||||||
import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
||||||
import { addressTypeOptions } from '@/option/base/common-address';
|
import { addressTypeOptions } from '@/option/base/common-address';
|
||||||
@@ -2807,8 +2807,11 @@ import 'nprogress/nprogress.css';
|
|||||||
const AMAP_KEY = '653b7cf105ad7fb8ec9b2f5198ade315';
|
const AMAP_KEY = '653b7cf105ad7fb8ec9b2f5198ade315';
|
||||||
const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a';
|
const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a';
|
||||||
let amapLoader;
|
let amapLoader;
|
||||||
|
const transportPlanListRoute = '/business/transport-plan';
|
||||||
|
const transportPlanFormRoute = '/business/transport-plan/form';
|
||||||
|
const transportPlanListRefreshKey = 'transport-plan-list-refresh';
|
||||||
const standaloneTransportPlanFormRoutes = {
|
const standaloneTransportPlanFormRoutes = {
|
||||||
'/business/transport-plan': '/business/transport-plan/form',
|
[transportPlanListRoute]: transportPlanFormRoute,
|
||||||
};
|
};
|
||||||
const standaloneTransportPlanFormPaths = [
|
const standaloneTransportPlanFormPaths = [
|
||||||
...Object.keys(standaloneTransportPlanFormRoutes),
|
...Object.keys(standaloneTransportPlanFormRoutes),
|
||||||
@@ -3072,6 +3075,10 @@ export default {
|
|||||||
// 必须放 data:Options API 的顺序是 data → computed → watch(immediate) → created,
|
// 必须放 data:Options API 的顺序是 data → computed → watch(immediate) → created,
|
||||||
// 放 created 的话首个 immediate watcher 会读到空值,把首次加载也挡掉。
|
// 放 created 的话首个 immediate watcher 会读到空值,把首次加载也挡掉。
|
||||||
routePathLocked: this.$route.path,
|
routePathLocked: this.$route.path,
|
||||||
|
// 表单页实例在创建时锁定,避免 keep-alive 列表实例随全局 $route 误切到表单态。
|
||||||
|
isFormPageInstance: Object.values(standaloneTransportPlanFormRoutes).includes(
|
||||||
|
this.$route.path
|
||||||
|
),
|
||||||
form: {},
|
form: {},
|
||||||
suppressTransportTypeClear: false,
|
suppressTransportTypeClear: false,
|
||||||
query: {},
|
query: {},
|
||||||
@@ -3112,10 +3119,11 @@ export default {
|
|||||||
option: (() => {
|
option: (() => {
|
||||||
const opt = this.cloneOption(this.crudOption, estimateMenuButtonCount(this.config));
|
const opt = this.cloneOption(this.crudOption, estimateMenuButtonCount(this.config));
|
||||||
if (this.menuWidth != null) opt.menuWidth = this.menuWidth;
|
if (this.menuWidth != null) opt.menuWidth = this.menuWidth;
|
||||||
if (
|
// 仅表单页实例套用全屏表单弹窗样式,避免列表页误用后表格区域异常。
|
||||||
this.standaloneFormPage &&
|
const isFormInstance = Object.values(standaloneTransportPlanFormRoutes).includes(
|
||||||
standaloneTransportPlanFormPaths.includes(this.$route.path)
|
this.$route.path
|
||||||
) {
|
);
|
||||||
|
if (this.standaloneFormPage && isFormInstance) {
|
||||||
opt.dialogAppendToBody = false;
|
opt.dialogAppendToBody = false;
|
||||||
opt.dialogModal = false;
|
opt.dialogModal = false;
|
||||||
opt.dialogCustomClass = 'transport-plan-form-page-dialog';
|
opt.dialogCustomClass = 'transport-plan-form-page-dialog';
|
||||||
@@ -3150,6 +3158,8 @@ export default {
|
|||||||
dispatchItemIndex: -1,
|
dispatchItemIndex: -1,
|
||||||
dispatchItemForm: defaultDispatchRow(),
|
dispatchItemForm: defaultDispatchRow(),
|
||||||
dispatchItemCargoRows: [],
|
dispatchItemCargoRows: [],
|
||||||
|
// 本次数量变更版本号:驱动同表其他行「剩余数量」同步重算
|
||||||
|
dispatchCargoQuantityVersion: 0,
|
||||||
dispatchItemAttachmentRows: [],
|
dispatchItemAttachmentRows: [],
|
||||||
selectedDispatchItemAttachmentRows: [],
|
selectedDispatchItemAttachmentRows: [],
|
||||||
attachmentRows: [],
|
attachmentRows: [],
|
||||||
@@ -3289,6 +3299,12 @@ export default {
|
|||||||
}
|
}
|
||||||
this.loadTaskQuantityUnitOptions();
|
this.loadTaskQuantityUnitOptions();
|
||||||
},
|
},
|
||||||
|
// keep-alive 重新激活列表时强制刷新,避免缓存脏数据;标记位用于兼容旧跳转逻辑。
|
||||||
|
activated() {
|
||||||
|
if (this.isFormPageInstance) return;
|
||||||
|
sessionStorage.removeItem(transportPlanListRefreshKey);
|
||||||
|
this.$nextTick(() => this.onLoad(this.page, this.query));
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['permission', 'userInfo']),
|
...mapGetters(['permission', 'userInfo']),
|
||||||
permissionList() {
|
permissionList() {
|
||||||
@@ -3300,10 +3316,20 @@ export default {
|
|||||||
return this.config.detailSections || [];
|
return this.config.detailSections || [];
|
||||||
},
|
},
|
||||||
isStandaloneBusinessPage() {
|
isStandaloneBusinessPage() {
|
||||||
return this.standaloneFormPage && standaloneTransportPlanFormPaths.includes(this.$route.path);
|
return (
|
||||||
|
this.standaloneFormPage &&
|
||||||
|
(this.isFormPageInstance ||
|
||||||
|
standaloneTransportPlanFormPaths.includes(this.routePathLocked) ||
|
||||||
|
standaloneTransportPlanFormPaths.includes(this.$route.path))
|
||||||
|
);
|
||||||
},
|
},
|
||||||
isStandaloneFormPage() {
|
isStandaloneFormPage() {
|
||||||
return this.isStandaloneBusinessPage && ['add', 'edit'].includes(this.$route.query.mode);
|
// 用实例锁定标志,避免列表 keep-alive 实例被全局路由误判成表单页。
|
||||||
|
return (
|
||||||
|
this.standaloneFormPage &&
|
||||||
|
this.isFormPageInstance &&
|
||||||
|
['add', 'edit'].includes(this.$route.query.mode)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
formPageTitle() {
|
formPageTitle() {
|
||||||
if (this.isStandaloneFormPage) {
|
if (this.isStandaloneFormPage) {
|
||||||
@@ -3752,6 +3778,18 @@ export default {
|
|||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route(to, from) {
|
$route(to, from) {
|
||||||
|
// 列表实例:从其他页进入列表时刷新(activated 负责标签切回)。
|
||||||
|
if (!this.isFormPageInstance) {
|
||||||
|
const enteringList =
|
||||||
|
(to.path === this.routePathLocked || to.path === transportPlanListRoute) &&
|
||||||
|
from?.path &&
|
||||||
|
from.path !== to.path;
|
||||||
|
if (enteringList) {
|
||||||
|
sessionStorage.removeItem(transportPlanListRefreshKey);
|
||||||
|
this.$nextTick(() => this.onLoad(this.page, this.query));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!this.isStandaloneFormPage) return;
|
if (!this.isStandaloneFormPage) return;
|
||||||
if (
|
if (
|
||||||
to.query.mode !== from?.query?.mode ||
|
to.query.mode !== from?.query?.mode ||
|
||||||
@@ -3779,6 +3817,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatContractOptionLabel,
|
formatContractOptionLabel,
|
||||||
|
driverOptionText,
|
||||||
initStandaloneFormPage() {
|
initStandaloneFormPage() {
|
||||||
if (!this.isStandaloneFormPage) return;
|
if (!this.isStandaloneFormPage) return;
|
||||||
const mode = this.$route.query.mode === 'edit' ? 'edit' : 'add';
|
const mode = this.$route.query.mode === 'edit' ? 'edit' : 'add';
|
||||||
@@ -3910,9 +3949,9 @@ export default {
|
|||||||
return Object.values(groups)
|
return Object.values(groups)
|
||||||
.map(group => {
|
.map(group => {
|
||||||
const quantity = this.formatDispatchQuantity(group.quantity);
|
const quantity = this.formatDispatchQuantity(group.quantity);
|
||||||
return `${group.typeName}等${group.count}种货物 | ${quantity}${
|
const typeName =
|
||||||
group.unit ? ` ${group.unit}` : ''
|
group.count > 1 ? `${group.typeName}等${group.count}种货物` : group.typeName;
|
||||||
}`;
|
return `${typeName} | ${quantity}${group.unit ? ` ${group.unit}` : ''}`;
|
||||||
})
|
})
|
||||||
.join('; ');
|
.join('; ');
|
||||||
},
|
},
|
||||||
@@ -4148,6 +4187,7 @@ export default {
|
|||||||
waiting: ['待执行', 'is-pending'],
|
waiting: ['待执行', 'is-pending'],
|
||||||
processing: ['进行中', 'is-processing'],
|
processing: ['进行中', 'is-processing'],
|
||||||
running: ['进行中', 'is-processing'],
|
running: ['进行中', 'is-processing'],
|
||||||
|
pending_return_confirm: ['待回单确认', 'is-pending'],
|
||||||
completed: ['已完成', 'is-completed'],
|
completed: ['已完成', 'is-completed'],
|
||||||
cancelled: ['已取消', 'is-cancelled'],
|
cancelled: ['已取消', 'is-cancelled'],
|
||||||
};
|
};
|
||||||
@@ -4484,6 +4524,9 @@ export default {
|
|||||||
loading();
|
loading();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
markTransportPlanListNeedRefresh() {
|
||||||
|
sessionStorage.setItem(transportPlanListRefreshKey, '1');
|
||||||
|
},
|
||||||
rowSave(row, done, loading) {
|
rowSave(row, done, loading) {
|
||||||
const submitRow = this.normalizeRow(row);
|
const submitRow = this.normalizeRow(row);
|
||||||
if (!submitRow) {
|
if (!submitRow) {
|
||||||
@@ -4492,6 +4535,7 @@ export default {
|
|||||||
}
|
}
|
||||||
this.getSaveRequest()(submitRow).then(
|
this.getSaveRequest()(submitRow).then(
|
||||||
() => {
|
() => {
|
||||||
|
this.markTransportPlanListNeedRefresh();
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
this.$message({ type: 'success', message: '操作成功!' });
|
this.$message({ type: 'success', message: '操作成功!' });
|
||||||
done();
|
done();
|
||||||
@@ -4511,6 +4555,7 @@ export default {
|
|||||||
}
|
}
|
||||||
this.getSaveRequest()(submitRow).then(
|
this.getSaveRequest()(submitRow).then(
|
||||||
() => {
|
() => {
|
||||||
|
this.markTransportPlanListNeedRefresh();
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
this.$message({ type: 'success', message: '操作成功!' });
|
this.$message({ type: 'success', message: '操作成功!' });
|
||||||
done();
|
done();
|
||||||
@@ -4540,7 +4585,7 @@ export default {
|
|||||||
.submit(submitRow)
|
.submit(submitRow)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$message.success(action === 'draft' ? '暂存成功' : '创建成功');
|
this.$message.success(action === 'draft' ? '暂存成功' : '创建成功');
|
||||||
this.onLoad(this.page, this.query);
|
this.markTransportPlanListNeedRefresh();
|
||||||
this.closeCrudDialog();
|
this.closeCrudDialog();
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@@ -4548,12 +4593,14 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
closeCrudDialog() {
|
closeCrudDialog() {
|
||||||
if (this.isStandaloneBusinessPage) {
|
if (this.isStandaloneBusinessPage || this.isFormPageInstance) {
|
||||||
|
// 关闭独立表单页时标记列表需刷新(含直接点关闭未保存的场景)
|
||||||
|
this.markTransportPlanListNeedRefresh();
|
||||||
this.$router.$avueRouter?.closeTag?.();
|
this.$router.$avueRouter?.closeTag?.();
|
||||||
const listPath =
|
const listPath =
|
||||||
Object.entries(standaloneTransportPlanFormRoutes).find(
|
Object.entries(standaloneTransportPlanFormRoutes).find(
|
||||||
([, formPath]) => formPath === this.$route.path
|
([, formPath]) => formPath === this.$route.path || formPath === this.routePathLocked
|
||||||
)?.[0] || this.$route.path;
|
)?.[0] || transportPlanListRoute;
|
||||||
this.$router.push({ path: listPath, query: {} });
|
this.$router.push({ path: listPath, query: {} });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -4951,16 +4998,8 @@ export default {
|
|||||||
},
|
},
|
||||||
fetchTaskDriverSuggestions(queryString, callback) {
|
fetchTaskDriverSuggestions(queryString, callback) {
|
||||||
const keyword = String(queryString || '').trim();
|
const keyword = String(queryString || '').trim();
|
||||||
const carrier = this.getDispatchCarrierFilter();
|
|
||||||
if (!carrier.carrierId && !carrier.carrierName) {
|
|
||||||
callback([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.taskDriverLoading = true;
|
this.taskDriverLoading = true;
|
||||||
fetchDriversByCarrierOrganizations(
|
fetchDriverCandidates({ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '司机' })
|
||||||
{ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '司机' },
|
|
||||||
carrier
|
|
||||||
)
|
|
||||||
.then(records => {
|
.then(records => {
|
||||||
this.taskDriverOptions = records;
|
this.taskDriverOptions = records;
|
||||||
callback(
|
callback(
|
||||||
@@ -4980,16 +5019,12 @@ export default {
|
|||||||
},
|
},
|
||||||
fetchTaskEscortSuggestions(queryString, callback) {
|
fetchTaskEscortSuggestions(queryString, callback) {
|
||||||
const keyword = String(queryString || '').trim();
|
const keyword = String(queryString || '').trim();
|
||||||
const carrier = this.getDispatchCarrierFilter();
|
|
||||||
if (!carrier.carrierId && !carrier.carrierName) {
|
|
||||||
callback([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.taskEscortLoading = true;
|
this.taskEscortLoading = true;
|
||||||
fetchDriversByCarrierOrganizations(
|
fetchDriverCandidates({
|
||||||
{ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '押运员' },
|
size: 20,
|
||||||
carrier
|
...(keyword ? { driverName: keyword } : {}),
|
||||||
)
|
posts: '押运员',
|
||||||
|
})
|
||||||
.then(records => {
|
.then(records => {
|
||||||
this.taskEscortOptions = records;
|
this.taskEscortOptions = records;
|
||||||
callback(records.map(item => ({ ...item, value: item.driverName || item.name || '' })));
|
callback(records.map(item => ({ ...item, value: item.driverName || item.name || '' })));
|
||||||
@@ -6634,20 +6669,33 @@ export default {
|
|||||||
return query;
|
return query;
|
||||||
},
|
},
|
||||||
onLoad(page, params = {}) {
|
onLoad(page, params = {}) {
|
||||||
|
if (this.isFormPageInstance) return;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
const currentPage = page?.currentPage || this.page.currentPage || 1;
|
||||||
|
const pageSize = page?.pageSize || this.page.pageSize || 10;
|
||||||
const query = this.normalizeQueryParams({
|
const query = this.normalizeQueryParams({
|
||||||
...params,
|
...params,
|
||||||
...this.query,
|
...this.query,
|
||||||
allDept: 0,
|
allDept: 0,
|
||||||
});
|
});
|
||||||
this.api
|
this.api
|
||||||
.getList(page.currentPage, page.pageSize, query)
|
.getList(currentPage, pageSize, query)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const result = res.data.data;
|
const result = res?.data?.data || res?.data || {};
|
||||||
this.page.total = result.total;
|
const records = Array.isArray(result.records)
|
||||||
this.data = result.records;
|
? result.records
|
||||||
|
: Array.isArray(result)
|
||||||
|
? result
|
||||||
|
: [];
|
||||||
|
this.page.total = Number(result.total ?? records.length) || 0;
|
||||||
|
this.data = records;
|
||||||
this.selectionClear();
|
this.selectionClear();
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
window.console.error(error);
|
||||||
|
this.data = [];
|
||||||
|
this.page.total = 0;
|
||||||
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
@@ -7501,12 +7549,13 @@ export default {
|
|||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const cargoInfo = Object.values(groups)
|
const cargoInfo = Object.values(groups)
|
||||||
.map(
|
.map(group => {
|
||||||
group =>
|
const typeName =
|
||||||
`${group.cargoType}等${group.count}种货物 | ${this.formatDispatchQuantity(
|
group.count > 1 ? `${group.cargoType}等${group.count}种货物` : group.cargoType;
|
||||||
group.quantity
|
return `${typeName} | ${this.formatDispatchQuantity(group.quantity)}${
|
||||||
)}${group.unit ? ` ${group.unit}` : ''}`
|
group.unit ? ` ${group.unit}` : ''
|
||||||
)
|
}`;
|
||||||
|
})
|
||||||
.join('; ');
|
.join('; ');
|
||||||
return cargoInfo || plan.goodsInfo || '';
|
return cargoInfo || plan.goodsInfo || '';
|
||||||
},
|
},
|
||||||
@@ -7652,6 +7701,7 @@ export default {
|
|||||||
row.cargoName = '';
|
row.cargoName = '';
|
||||||
row.specification = '';
|
row.specification = '';
|
||||||
row.model = '';
|
row.model = '';
|
||||||
|
this.dispatchCargoQuantityVersion += 1;
|
||||||
},
|
},
|
||||||
handleDispatchConfiguredCargoNameChange(row, value) {
|
handleDispatchConfiguredCargoNameChange(row, value) {
|
||||||
const nextValue = String(value ?? row.cargoName ?? '').trim();
|
const nextValue = String(value ?? row.cargoName ?? '').trim();
|
||||||
@@ -7660,6 +7710,7 @@ export default {
|
|||||||
);
|
);
|
||||||
if (!option) {
|
if (!option) {
|
||||||
row.cargoName = nextValue;
|
row.cargoName = nextValue;
|
||||||
|
this.dispatchCargoQuantityVersion += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const previousType = String(row.cargoType || '').trim();
|
const previousType = String(row.cargoType || '').trim();
|
||||||
@@ -7674,6 +7725,7 @@ export default {
|
|||||||
}
|
}
|
||||||
row.specification = option.specification || row.specification || '';
|
row.specification = option.specification || row.specification || '';
|
||||||
row.model = option.model || row.model || '';
|
row.model = option.model || row.model || '';
|
||||||
|
this.dispatchCargoQuantityVersion += 1;
|
||||||
},
|
},
|
||||||
openDispatchItemDialog(index = -1, row = defaultDispatchRow()) {
|
openDispatchItemDialog(index = -1, row = defaultDispatchRow()) {
|
||||||
const defaultSummaryItem =
|
const defaultSummaryItem =
|
||||||
@@ -7991,17 +8043,12 @@ export default {
|
|||||||
this.taskDriverOptions = [];
|
this.taskDriverOptions = [];
|
||||||
this.taskEscortOptions = [];
|
this.taskEscortOptions = [];
|
||||||
},
|
},
|
||||||
getDispatchCarrierFilter() {
|
|
||||||
return {
|
|
||||||
carrierId: this.dispatchItemForm.carrierId || '',
|
|
||||||
carrierName: this.dispatchItemForm.carrierName || '',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
handleDispatchCargoQuantityInput(row, value) {
|
handleDispatchCargoQuantityInput(row, value) {
|
||||||
const text = String(value || '').replace(/[^\d.]/g, '');
|
const text = String(value || '').replace(/[^\d.]/g, '');
|
||||||
const parts = text.split('.');
|
const parts = text.split('.');
|
||||||
row.quantity =
|
row.quantity =
|
||||||
parts.length > 1 ? `${parts[0]}.${parts.slice(1).join('').slice(0, 3)}` : parts[0];
|
parts.length > 1 ? `${parts[0]}.${parts.slice(1).join('').slice(0, 3)}` : parts[0];
|
||||||
|
this.dispatchCargoQuantityVersion += 1;
|
||||||
},
|
},
|
||||||
handleDispatchCargoNumberInput(row, prop, value) {
|
handleDispatchCargoNumberInput(row, prop, value) {
|
||||||
this.handleFreightNumberInput(row, prop, value);
|
this.handleFreightNumberInput(row, prop, value);
|
||||||
@@ -8021,12 +8068,14 @@ export default {
|
|||||||
const nextRow = this.normalizeTransportCargoRow({ priceUnit: this.defaultPriceUnit });
|
const nextRow = this.normalizeTransportCargoRow({ priceUnit: this.defaultPriceUnit });
|
||||||
if (index > -1) this.dispatchItemCargoRows.splice(index + 1, 0, nextRow);
|
if (index > -1) this.dispatchItemCargoRows.splice(index + 1, 0, nextRow);
|
||||||
else this.dispatchItemCargoRows.push(nextRow);
|
else this.dispatchItemCargoRows.push(nextRow);
|
||||||
|
this.dispatchCargoQuantityVersion += 1;
|
||||||
},
|
},
|
||||||
removeDispatchCargoRow(index) {
|
removeDispatchCargoRow(index) {
|
||||||
this.dispatchItemCargoRows.splice(index, 1);
|
this.dispatchItemCargoRows.splice(index, 1);
|
||||||
if (!this.dispatchItemCargoRows.length) {
|
if (!this.dispatchItemCargoRows.length) {
|
||||||
this.dispatchItemCargoRows.push(this.normalizeTransportCargoRow());
|
this.dispatchItemCargoRows.push(this.normalizeTransportCargoRow());
|
||||||
}
|
}
|
||||||
|
this.dispatchCargoQuantityVersion += 1;
|
||||||
},
|
},
|
||||||
dispatchCargoFreightAmount(cargo = {}) {
|
dispatchCargoFreightAmount(cargo = {}) {
|
||||||
if (cargo.freightAmount !== undefined && cargo.freightAmount !== null) {
|
if (cargo.freightAmount !== undefined && cargo.freightAmount !== null) {
|
||||||
@@ -8176,11 +8225,50 @@ export default {
|
|||||||
}, 0)
|
}, 0)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
/** 精简录入提示:可调度余量扣减当前本次数量后的剩余 */
|
/**
|
||||||
dispatchItemHintRemainingQuantity(row = {}) {
|
* 当前编辑表单中,与指定行同货物(有身份)或同单位(无身份)已占用的本次数量合计。
|
||||||
|
* 用于剩余数量展示联动,不参与提交校验(校验仍按整单合计对比计划余量)。
|
||||||
|
*/
|
||||||
|
getDispatchFormOccupiedQuantity(row = {}) {
|
||||||
|
const goodsRows =
|
||||||
|
this.dispatchItemForm?.taskEntryMode === 'full'
|
||||||
|
? this.dispatchItemCargoRows || []
|
||||||
|
: [this.dispatchItemForm || row];
|
||||||
|
const hasCargoIdentity = Boolean(
|
||||||
|
String(row.cargoName || row.goodsName || row.name || '').trim() ||
|
||||||
|
String(row.cargoType || row.secondCargoTypeName || row.goodsType || row.type || '').trim()
|
||||||
|
);
|
||||||
|
const unit = this.getDispatchQuantityUnit(row);
|
||||||
|
const cargoKey = this.getDispatchCargoIdentity(row);
|
||||||
|
return goodsRows.reduce((sum, goods) => {
|
||||||
|
if (!goods) return sum;
|
||||||
|
if (hasCargoIdentity) {
|
||||||
|
const goodsHasIdentity = Boolean(
|
||||||
|
String(goods.cargoName || goods.goodsName || goods.name || '').trim() ||
|
||||||
|
String(
|
||||||
|
goods.cargoType || goods.secondCargoTypeName || goods.goodsType || goods.type || ''
|
||||||
|
).trim()
|
||||||
|
);
|
||||||
|
if (!goodsHasIdentity || this.getDispatchCargoIdentity(goods) !== cargoKey) {
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
} else if (this.getDispatchQuantityUnit(goods) !== unit) {
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
return sum + this.parseDispatchQuantity(goods.quantity);
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
/** 展示用剩余数量:计划可调度余量扣减本单已填本次数量(含当前行) */
|
||||||
|
dispatchItemDisplayRemainingQuantity(row = {}) {
|
||||||
|
// 依赖版本号,确保一行本次数量变化后其他行剩余数量一并刷新
|
||||||
|
void this.dispatchCargoQuantityVersion;
|
||||||
const available = this.dispatchItemRemainingQuantity(row);
|
const available = this.dispatchItemRemainingQuantity(row);
|
||||||
const current = this.parseDispatchQuantity(row.quantity);
|
const occupied = this.getDispatchFormOccupiedQuantity(row);
|
||||||
return Math.max(available - current, 0);
|
return Math.max(available - occupied, 0);
|
||||||
|
},
|
||||||
|
/** 精简录入提示:与完整录入剩余数量展示规则一致 */
|
||||||
|
dispatchItemHintRemainingQuantity(row = {}) {
|
||||||
|
return this.dispatchItemDisplayRemainingQuantity(row);
|
||||||
},
|
},
|
||||||
pruneDispatchPendingRows(rows = []) {
|
pruneDispatchPendingRows(rows = []) {
|
||||||
const planQuantities = new Map();
|
const planQuantities = new Map();
|
||||||
@@ -8278,13 +8366,17 @@ export default {
|
|||||||
const fullEntry = row.taskEntryMode === 'full';
|
const fullEntry = row.taskEntryMode === 'full';
|
||||||
const roadTransport = this.resolveTransportMode(row.transportType) === 'road';
|
const roadTransport = this.resolveTransportMode(row.transportType) === 'road';
|
||||||
if (fullEntry) {
|
if (fullEntry) {
|
||||||
if (roadTransport && row.carrierType === '自运') {
|
// 公路运输时司机/手机号一律必填(含承运类型为承运商)
|
||||||
|
if (roadTransport && row.carrierType) {
|
||||||
requiredFields.push(['driverName', '司机']);
|
requiredFields.push(['driverName', '司机']);
|
||||||
requiredFields.push(['driverPhone', '手机号']);
|
requiredFields.push(['driverPhone', '手机号']);
|
||||||
}
|
}
|
||||||
} else if (row.carrierType && row.carrierType !== '承运商') {
|
} else if (row.carrierType) {
|
||||||
requiredFields.push(['driverName', '司机']);
|
requiredFields.push(['driverName', '司机']);
|
||||||
requiredFields.push(['driverPhone', '司机手机号']);
|
requiredFields.push([
|
||||||
|
'driverPhone',
|
||||||
|
row.carrierType === '承运商' ? '手机号' : '司机手机号',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
const emptyField = requiredFields.find(([prop]) => this.isBillingFieldEmpty(row[prop]));
|
const emptyField = requiredFields.find(([prop]) => this.isBillingFieldEmpty(row[prop]));
|
||||||
if (emptyField) return requiredMessage(emptyField[1]);
|
if (emptyField) return requiredMessage(emptyField[1]);
|
||||||
|
|||||||
@@ -96,22 +96,12 @@
|
|||||||
prop="carrierName"
|
prop="carrierName"
|
||||||
label="承运商"
|
label="承运商"
|
||||||
min-width="140"
|
min-width="140"
|
||||||
/><el-table-column
|
|
||||||
v-if="columnVisible.carrierType"
|
|
||||||
prop="carrierType"
|
|
||||||
label="承运类型"
|
|
||||||
min-width="120"
|
|
||||||
/>
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-if="columnVisible.waybillCount"
|
v-if="columnVisible.waybillCount"
|
||||||
prop="waybillCount"
|
prop="waybillCount"
|
||||||
label="运单数"
|
label="运单数"
|
||||||
width="90"
|
width="90"
|
||||||
/> <el-table-column
|
|
||||||
v-if="columnVisible.importTypeName"
|
|
||||||
prop="importTypeName"
|
|
||||||
label="导入方式"
|
|
||||||
width="100"
|
|
||||||
/>
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-if="columnVisible.statusName"
|
v-if="columnVisible.statusName"
|
||||||
@@ -119,6 +109,12 @@
|
|||||||
label="状态"
|
label="状态"
|
||||||
width="100"
|
width="100"
|
||||||
/>
|
/>
|
||||||
|
<el-table-column
|
||||||
|
v-if="columnVisible.settlementStatusName"
|
||||||
|
prop="settlementStatusName"
|
||||||
|
label="结算状态"
|
||||||
|
width="110"
|
||||||
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-if="columnVisible.createUserName"
|
v-if="columnVisible.createUserName"
|
||||||
prop="createUserName"
|
prop="createUserName"
|
||||||
@@ -159,7 +155,7 @@
|
|||||||
>编辑</el-link
|
>编辑</el-link
|
||||||
>
|
>
|
||||||
<el-link
|
<el-link
|
||||||
v-if="row.importStatus === 'draft'"
|
v-if="canRemoveBatch(row)"
|
||||||
type="danger"
|
type="danger"
|
||||||
@click="removeBatch(row)"
|
@click="removeBatch(row)"
|
||||||
>删除</el-link
|
>删除</el-link
|
||||||
@@ -488,20 +484,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<el-tabs v-model="previewTab"
|
<el-tabs v-model="previewTab"
|
||||||
><el-tab-pane :label="`运单数(${rows.length})`" name="all" /><el-tab-pane
|
><el-tab-pane :label="`运单数(${rows.length})`" name="all" /><el-tab-pane
|
||||||
:label="`疑似重复(${duplicateRows.length})`"
|
:label="`Excel内重复(${duplicateRows.length})`"
|
||||||
name="duplicate" /></el-tabs
|
name="duplicate" /><el-tab-pane
|
||||||
|
:label="`与已有运单重复(${historyDuplicateRows.length})`"
|
||||||
|
name="history" /></el-tabs
|
||||||
><el-table
|
><el-table
|
||||||
:data="previewRows"
|
:data="previewRows"
|
||||||
border
|
border
|
||||||
max-height="440"
|
max-height="440"
|
||||||
:row-class-name="({ row }) => (row._duplicate ? 'is-duplicate-row' : '')"
|
:row-class-name="
|
||||||
|
({ row }) => (row._duplicate || row._historyWaybillNo ? 'is-duplicate-row' : '')
|
||||||
|
"
|
||||||
@selection-change="rowSelection = $event"
|
@selection-change="rowSelection = $event"
|
||||||
><el-table-column type="selection" width="55" /><el-table-column
|
><el-table-column type="selection" width="55" /><el-table-column
|
||||||
type="index"
|
type="index"
|
||||||
label="序号"
|
label="序号"
|
||||||
width="65"
|
width="65"
|
||||||
/><el-table-column
|
/><el-table-column
|
||||||
v-for="column in detailColumns"
|
v-for="column in previewColumns"
|
||||||
:key="column.prop"
|
:key="column.prop"
|
||||||
:prop="column.prop"
|
:prop="column.prop"
|
||||||
:label="column.label"
|
:label="column.label"
|
||||||
@@ -587,8 +587,6 @@
|
|||||||
><el-link type="primary" @click="saveRow(row)">保存</el-link
|
><el-link type="primary" @click="saveRow(row)">保存</el-link
|
||||||
><el-link type="primary" @click="cancelRow(row)">取消</el-link></template
|
><el-link type="primary" @click="cancelRow(row)">取消</el-link></template
|
||||||
><template v-else
|
><template v-else
|
||||||
><el-link v-if="row._duplicate" type="primary" @click="confirmDuplicateRow(row)"
|
|
||||||
>确认</el-link
|
|
||||||
><el-link type="primary" @click="editRow(row)">编辑</el-link
|
><el-link type="primary" @click="editRow(row)">编辑</el-link
|
||||||
><el-link type="danger" @click="deleteRow(row)">删除</el-link></template
|
><el-link type="danger" @click="deleteRow(row)">删除</el-link></template
|
||||||
></div
|
></div
|
||||||
@@ -641,10 +639,9 @@ const columnOptions = [
|
|||||||
{ prop: 'batchNo', label: '运单批次号' },
|
{ prop: 'batchNo', label: '运单批次号' },
|
||||||
{ prop: 'projectName', label: '项目名称' },
|
{ prop: 'projectName', label: '项目名称' },
|
||||||
{ prop: 'carrierName', label: '承运商' },
|
{ prop: 'carrierName', label: '承运商' },
|
||||||
{ prop: 'carrierType', label: '承运类型' },
|
|
||||||
{ prop: 'waybillCount', label: '运单数' },
|
{ prop: 'waybillCount', label: '运单数' },
|
||||||
{ prop: 'importTypeName', label: '导入方式' },
|
|
||||||
{ prop: 'statusName', label: '状态' },
|
{ prop: 'statusName', label: '状态' },
|
||||||
|
{ prop: 'settlementStatusName', label: '结算状态' },
|
||||||
{ prop: 'createUserName', label: '创建人' },
|
{ prop: 'createUserName', label: '创建人' },
|
||||||
{ prop: 'createTime', label: '创建时间' },
|
{ prop: 'createTime', label: '创建时间' },
|
||||||
{ prop: 'updateTime', label: '更新时间' },
|
{ prop: 'updateTime', label: '更新时间' },
|
||||||
@@ -721,9 +718,12 @@ const transportTypeOptions = ref([]),
|
|||||||
const rowSelection = ref([]),
|
const rowSelection = ref([]),
|
||||||
previewTab = ref('all');
|
previewTab = ref('all');
|
||||||
const duplicateRows = computed(() => rows.value.filter(row => row._duplicate));
|
const duplicateRows = computed(() => rows.value.filter(row => row._duplicate));
|
||||||
const previewRows = computed(() =>
|
const historyDuplicateRows = computed(() => rows.value.filter(row => row._historyWaybillNo));
|
||||||
previewTab.value === 'duplicate' ? duplicateRows.value : rows.value
|
const previewRows = computed(() => {
|
||||||
);
|
if (previewTab.value === 'duplicate') return duplicateRows.value;
|
||||||
|
if (previewTab.value === 'history') return historyDuplicateRows.value;
|
||||||
|
return rows.value;
|
||||||
|
});
|
||||||
const carrierContractsLoaded = ref(false),
|
const carrierContractsLoaded = ref(false),
|
||||||
hasCarrierContracts = ref(null);
|
hasCarrierContracts = ref(null);
|
||||||
const carrierTypes = ['承运商', '自运'];
|
const carrierTypes = ['承运商', '自运'];
|
||||||
@@ -800,6 +800,16 @@ const detailColumns = [
|
|||||||
{ prop: 'remark', label: '备注', editor: 'textarea', minWidth: 200 },
|
{ prop: 'remark', label: '备注', editor: 'textarea', minWidth: 200 },
|
||||||
{ prop: 'waybillIdentifier', label: '同一运单标识号', editor: 'input', minWidth: 150 },
|
{ prop: 'waybillIdentifier', label: '同一运单标识号', editor: 'input', minWidth: 150 },
|
||||||
];
|
];
|
||||||
|
// 与已有运单重复页签的列与明细一致,只在运单批次号后多一列已有运单号。
|
||||||
|
const previewColumns = computed(() =>
|
||||||
|
previewTab.value === 'history'
|
||||||
|
? [
|
||||||
|
detailColumns[0],
|
||||||
|
{ prop: '_historyWaybillNo', label: '已有运单号', minWidth: 220 },
|
||||||
|
...detailColumns.slice(1),
|
||||||
|
]
|
||||||
|
: detailColumns
|
||||||
|
);
|
||||||
const requiredDetailFields = [
|
const requiredDetailFields = [
|
||||||
{ prop: 'vehicleNo', label: '车牌号/船班号/船次号/班次号' },
|
{ prop: 'vehicleNo', label: '车牌号/船班号/船次号/班次号' },
|
||||||
{ prop: 'transportType', label: '运输方式' },
|
{ prop: 'transportType', label: '运输方式' },
|
||||||
@@ -1192,6 +1202,7 @@ const loadBatchRows = async batchId => {
|
|||||||
batchNo: item.batchNo || form.batchNo,
|
batchNo: item.batchNo || form.batchNo,
|
||||||
}));
|
}));
|
||||||
refreshDuplicateFlags();
|
refreshDuplicateFlags();
|
||||||
|
await refreshHistoryDuplicates();
|
||||||
rowSelection.value = [];
|
rowSelection.value = [];
|
||||||
previewTab.value = 'all';
|
previewTab.value = 'all';
|
||||||
};
|
};
|
||||||
@@ -1266,9 +1277,47 @@ const fillEditForm = async row => {
|
|||||||
if (carrierValue) carrierChange(carrierValue);
|
if (carrierValue) carrierChange(carrierValue);
|
||||||
await loadBatchRows(snapshot.id);
|
await loadBatchRows(snapshot.id);
|
||||||
};
|
};
|
||||||
const removeBatches = () =>
|
/** 与后端一致:仅未结算批次可整批删除 */
|
||||||
api.removeImportBatches(selected.value.map(item => item.id).join(',')).then(loadBatches);
|
const canRemoveBatch = row => String(row?.settlementStatus || 'unsettled') === 'unsettled';
|
||||||
const removeBatch = row => api.removeImportBatches(row.id).then(loadBatches);
|
const removeBatches = async () => {
|
||||||
|
if (!selected.value.length) {
|
||||||
|
ElMessage.warning('请选择至少一条数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 选中含部分结算/已结算时整批拦截,不静默跳过
|
||||||
|
if (selected.value.some(row => !canRemoveBatch(row))) {
|
||||||
|
ElMessage.warning('仅未结算的运单批次可以删除');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm('确认删除选中的运单批次?删除后不可恢复。', '提示', {
|
||||||
|
type: 'warning',
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await api.removeImportBatches(selected.value.map(item => item.id).join(','));
|
||||||
|
ElMessage.success('删除成功');
|
||||||
|
return loadBatches();
|
||||||
|
};
|
||||||
|
const removeBatch = async row => {
|
||||||
|
if (!canRemoveBatch(row)) {
|
||||||
|
ElMessage.warning('仅未结算的运单批次可以删除');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确认删除运单批次「${row.batchNo || ''}」?删除后不可恢复。`,
|
||||||
|
'提示',
|
||||||
|
{ type: 'warning' }
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await api.removeImportBatches(row.id);
|
||||||
|
ElMessage.success('删除成功');
|
||||||
|
return loadBatches();
|
||||||
|
};
|
||||||
const projectChange = async id => {
|
const projectChange = async id => {
|
||||||
const requestId = ++projectRequestId;
|
const requestId = ++projectRequestId;
|
||||||
const item = projects.value.find(row => String(row.id) === String(id));
|
const item = projects.value.find(row => String(row.id) === String(id));
|
||||||
@@ -1348,11 +1397,23 @@ const formatOptionalNumber = value => {
|
|||||||
const normalized = normalizeOptionalImportNumber(value);
|
const normalized = normalizeOptionalImportNumber(value);
|
||||||
return normalized === null || normalized === undefined ? '' : normalized;
|
return normalized === null || normalized === undefined ? '' : normalized;
|
||||||
};
|
};
|
||||||
|
// 明细接口返回运单实体字段 startDate/endDate/estimatedStartTime/estimatedEndTime,
|
||||||
|
// 而明细表与编辑回填按导入列字段名 actualStartDate 等读取,重载后在此对齐,否则实际/预计时间列为空。
|
||||||
|
const detailDateAliases = {
|
||||||
|
actualStartDate: 'startDate',
|
||||||
|
actualEndDate: 'endDate',
|
||||||
|
planStartDate: 'estimatedStartTime',
|
||||||
|
planEndDate: 'estimatedEndTime',
|
||||||
|
};
|
||||||
const normalizeDetailRow = row => {
|
const normalizeDetailRow = row => {
|
||||||
const next = { ...(row || {}) };
|
const next = { ...(row || {}) };
|
||||||
OPTIONAL_NUMBER_PROPS.forEach(prop => {
|
OPTIONAL_NUMBER_PROPS.forEach(prop => {
|
||||||
next[prop] = formatOptionalNumber(next[prop]);
|
next[prop] = formatOptionalNumber(next[prop]);
|
||||||
});
|
});
|
||||||
|
Object.entries(detailDateAliases).forEach(([prop, source]) => {
|
||||||
|
if (String(next[prop] ?? '').trim()) return;
|
||||||
|
if (String(next[source] ?? '').trim()) next[prop] = next[source];
|
||||||
|
});
|
||||||
return next;
|
return next;
|
||||||
};
|
};
|
||||||
const normalizeImportRow = row => ({
|
const normalizeImportRow = row => ({
|
||||||
@@ -1464,6 +1525,8 @@ const fileChange = async (file, list) => {
|
|||||||
if (isValid) {
|
if (isValid) {
|
||||||
// 校验通过,填充表格数据
|
// 校验通过,填充表格数据
|
||||||
rows.value = parsedRows;
|
rows.value = parsedRows;
|
||||||
|
// 传 rows.value(响应式代理),否则后续写入不触发重新渲染
|
||||||
|
await refreshHistoryDuplicates(rows.value);
|
||||||
} else {
|
} else {
|
||||||
// 校验失败,清空数据
|
// 校验失败,清空数据
|
||||||
rows.value = [];
|
rows.value = [];
|
||||||
@@ -1481,16 +1544,12 @@ const IMPORT_BATCH_SIZE = 100;
|
|||||||
|
|
||||||
const importFieldText = value => String(value ?? '').trim();
|
const importFieldText = value => String(value ?? '').trim();
|
||||||
|
|
||||||
/** 同一运单批次号下,全部导入字段一致时标记为疑似重复。已在线确认的行不再标为重复。 */
|
/** 同一运单批次号下,全部导入字段一致时标记为 Excel 内重复。 */
|
||||||
const refreshDuplicateFlags = (list = rows.value) => {
|
const refreshDuplicateFlags = (list = rows.value) => {
|
||||||
const groups = new Map();
|
const groups = new Map();
|
||||||
list.forEach(row => {
|
list.forEach(row => {
|
||||||
const signature = detailColumns.map(column => importFieldText(row[column.prop])).join('\u0001');
|
const signature = detailColumns.map(column => importFieldText(row[column.prop])).join('\u0001');
|
||||||
const batchNo = importFieldText(row.batchNo || form.batchNo);
|
const batchNo = importFieldText(row.batchNo || form.batchNo);
|
||||||
if (row._duplicateConfirmed && row._duplicateSignature !== signature) {
|
|
||||||
row._duplicateConfirmed = false;
|
|
||||||
}
|
|
||||||
row._duplicateSignature = signature;
|
|
||||||
const groupKey = `${batchNo}\u0002${signature}`;
|
const groupKey = `${batchNo}\u0002${signature}`;
|
||||||
const group = groups.get(groupKey) || [];
|
const group = groups.get(groupKey) || [];
|
||||||
group.push(row);
|
group.push(row);
|
||||||
@@ -1499,19 +1558,39 @@ const refreshDuplicateFlags = (list = rows.value) => {
|
|||||||
groups.forEach(group => {
|
groups.forEach(group => {
|
||||||
const duplicated = group.length > 1;
|
const duplicated = group.length > 1;
|
||||||
group.forEach(row => {
|
group.forEach(row => {
|
||||||
row._duplicate = duplicated && !row._duplicateConfirmed;
|
row._duplicate = duplicated;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const confirmDuplicateRow = row => {
|
/** 逐行提交给后端与项目下已有运单比对,命中的行带上已有运单号。比对失败不影响导入。 */
|
||||||
row._duplicateConfirmed = true;
|
const refreshHistoryDuplicates = async (list = rows.value) => {
|
||||||
refreshDuplicateFlags();
|
if (!list.length || !form.projectId) {
|
||||||
ElMessage.success('已确认,该行将按正常数据导入');
|
list.forEach(row => {
|
||||||
|
row._historyWaybillNo = '';
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let duplicates = [];
|
||||||
|
try {
|
||||||
|
const res = await api.checkImportDuplicates(buildImportPayload(form.status, list));
|
||||||
|
const data = res?.data?.data ?? res?.data ?? res;
|
||||||
|
duplicates = Array.isArray(data) ? data : [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('与已有运单重复校验失败:', error);
|
||||||
|
duplicates = [];
|
||||||
|
}
|
||||||
|
const numbersByRow = new Map(
|
||||||
|
duplicates.map(item => [item.rowIndex, (item.waybillNos || []).filter(Boolean)])
|
||||||
|
);
|
||||||
|
list.forEach((row, index) => {
|
||||||
|
row._historyWaybillNo = (numbersByRow.get(index) || []).join('、');
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const stripInternalRowFields = row => {
|
const stripInternalRowFields = row => {
|
||||||
const { _key, _duplicate, _duplicateKey, _duplicateConfirmed, _duplicateSignature, _editing, _editSnapshot, ...data } = row;
|
const { _key, _duplicate, _duplicateKey, _editing, _editSnapshot, _historyWaybillNo, ...data } =
|
||||||
|
row;
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1726,6 +1805,7 @@ const saveRow = row => {
|
|||||||
row._editing = false;
|
row._editing = false;
|
||||||
delete row._editSnapshot;
|
delete row._editSnapshot;
|
||||||
refreshDuplicateFlags();
|
refreshDuplicateFlags();
|
||||||
|
refreshHistoryDuplicates();
|
||||||
};
|
};
|
||||||
const cancelRow = row => {
|
const cancelRow = row => {
|
||||||
if (row._editSnapshot) Object.assign(row, row._editSnapshot);
|
if (row._editSnapshot) Object.assign(row, row._editSnapshot);
|
||||||
@@ -1735,12 +1815,14 @@ const cancelRow = row => {
|
|||||||
const deleteRow = row => {
|
const deleteRow = row => {
|
||||||
rows.value = rows.value.filter(item => item !== row);
|
rows.value = rows.value.filter(item => item !== row);
|
||||||
refreshDuplicateFlags();
|
refreshDuplicateFlags();
|
||||||
|
refreshHistoryDuplicates();
|
||||||
};
|
};
|
||||||
const removeSelectedRows = () => {
|
const removeSelectedRows = () => {
|
||||||
const keys = new Set(rowSelection.value.map(row => row._key));
|
const keys = new Set(rowSelection.value.map(row => row._key));
|
||||||
rows.value = rows.value.filter(row => !keys.has(row._key));
|
rows.value = rows.value.filter(row => !keys.has(row._key));
|
||||||
rowSelection.value = [];
|
rowSelection.value = [];
|
||||||
refreshDuplicateFlags();
|
refreshDuplicateFlags();
|
||||||
|
refreshHistoryDuplicates();
|
||||||
};
|
};
|
||||||
const normalizeOptionalPlanId = value => {
|
const normalizeOptionalPlanId = value => {
|
||||||
if (value === undefined || value === null || value === '') return null;
|
if (value === undefined || value === null || value === '') return null;
|
||||||
@@ -1804,7 +1886,11 @@ const confirmImport = async () => {
|
|||||||
await formRef.value?.validate();
|
await formRef.value?.validate();
|
||||||
if (!validateImportRows()) return;
|
if (!validateImportRows()) return;
|
||||||
const count = rows.value.filter(row => row._duplicate).length;
|
const count = rows.value.filter(row => row._duplicate).length;
|
||||||
if (count) await ElMessageBox.confirm(`当前导入有${count}条疑似重复数据,是否确认导入?`, '提示');
|
if (count)
|
||||||
|
await ElMessageBox.confirm(`当前导入有${count}条Excel内重复数据,是否确认导入?`, '提示');
|
||||||
|
const historyCount = rows.value.filter(row => row._historyWaybillNo).length;
|
||||||
|
if (historyCount)
|
||||||
|
await ElMessageBox.confirm(`当前导入有${historyCount}条与已有运单重复,是否确认导入?`, '提示');
|
||||||
if (form.importType === 'settlement' && form.status === 'completed')
|
if (form.importType === 'settlement' && form.status === 'completed')
|
||||||
await ElMessageBox.confirm('确认后将同时生成运单、应收应付明细、计结算单,是否继续?', '提示');
|
await ElMessageBox.confirm('确认后将同时生成运单、应收应付明细、计结算单,是否继续?', '提示');
|
||||||
|
|
||||||
|
|||||||
@@ -1200,7 +1200,11 @@
|
|||||||
:loading="taskDriverLoading"
|
:loading="taskDriverLoading"
|
||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
@select="handleTaskDriverSelect"
|
@select="handleTaskDriverSelect"
|
||||||
/>
|
>
|
||||||
|
<template #default="{ item }">
|
||||||
|
<span>{{ driverOptionText(item) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-autocomplete>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="isRoadTransport"
|
v-if="isRoadTransport"
|
||||||
@@ -1279,7 +1283,11 @@
|
|||||||
:loading="taskEscortLoading"
|
:loading="taskEscortLoading"
|
||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
@select="handleTaskEscortSelect"
|
@select="handleTaskEscortSelect"
|
||||||
/>
|
>
|
||||||
|
<template #default="{ item }">
|
||||||
|
<span>{{ driverOptionText(item) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-autocomplete>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="showRoadEscortFields" label="押运人手机号">
|
<el-form-item v-if="showRoadEscortFields" label="押运人手机号">
|
||||||
<el-input
|
<el-input
|
||||||
@@ -1594,6 +1602,13 @@
|
|||||||
<el-link type="primary" v-if="canComplete(row)" @click="handleAction('complete', row)">
|
<el-link type="primary" v-if="canComplete(row)" @click="handleAction('complete', row)">
|
||||||
{{ completeActionLabel }}
|
{{ completeActionLabel }}
|
||||||
</el-link>
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="canConfirmReturn(row)"
|
||||||
|
@click="handleAction('confirmReturn', row)"
|
||||||
|
>
|
||||||
|
{{ completeActionLabel }}
|
||||||
|
</el-link>
|
||||||
<el-link type="primary" v-if="canMaintainMileage(row)" @click="openMileageDialog(row)">
|
<el-link type="primary" v-if="canMaintainMileage(row)" @click="openMileageDialog(row)">
|
||||||
维护里程
|
维护里程
|
||||||
</el-link>
|
</el-link>
|
||||||
@@ -1653,7 +1668,11 @@
|
|||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@select="handleReassignDriverSelect"
|
@select="handleReassignDriverSelect"
|
||||||
@change="handleReassignDriverChange"
|
@change="handleReassignDriverChange"
|
||||||
/>
|
>
|
||||||
|
<template #default="{ item }">
|
||||||
|
<span>{{ driverOptionText(item) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-autocomplete>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="手机号"
|
label="手机号"
|
||||||
@@ -2252,6 +2271,13 @@
|
|||||||
<span v-if="record.volume">体积 {{ record.volume }}方</span>
|
<span v-if="record.volume">体积 {{ record.volume }}方</span>
|
||||||
<span v-if="record.quantity">数量 {{ record.quantity }}</span>
|
<span v-if="record.quantity">数量 {{ record.quantity }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 里程只挂在末位节点上(needMileage 由后端下发),显示的是运单里程 -->
|
||||||
|
<div
|
||||||
|
v-if="record.needMileage && Number(record.mileage) > 0"
|
||||||
|
class="waybill-manage-page__punch-record-line"
|
||||||
|
>
|
||||||
|
里程 {{ record.mileage }} 公里
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="record.remark"
|
v-if="record.remark"
|
||||||
class="waybill-manage-page__punch-record-line"
|
class="waybill-manage-page__punch-record-line"
|
||||||
@@ -2848,6 +2874,20 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<!-- 里程只在末位打卡节点出现:后端按「末位 + 计费规则含里程」下发 needMileage,前端不自己推 -->
|
||||||
|
<el-col v-if="waybillPunchEditMileageVisible" :span="8">
|
||||||
|
<el-form-item label="里程">
|
||||||
|
<el-input
|
||||||
|
v-model="waybillPunchEditForm.mileage"
|
||||||
|
maxlength="10"
|
||||||
|
:disabled="waybillPunchEditMileageLocked"
|
||||||
|
placeholder="请输入"
|
||||||
|
@input="handleWaybillPunchMileageInput"
|
||||||
|
>
|
||||||
|
<template #append>公里</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="备注">
|
<el-form-item label="备注">
|
||||||
<el-input
|
<el-input
|
||||||
@@ -3683,6 +3723,7 @@ import {
|
|||||||
getVoucherImages as getProcessConfigVoucherImages,
|
getVoucherImages as getProcessConfigVoucherImages,
|
||||||
} from '@/api/business/process-config';
|
} from '@/api/business/process-config';
|
||||||
import {
|
import {
|
||||||
|
getList as getWaybillList,
|
||||||
getPunchRecords as getWaybillPunchRecords,
|
getPunchRecords as getWaybillPunchRecords,
|
||||||
locateVehicle,
|
locateVehicle,
|
||||||
savePunchRecord,
|
savePunchRecord,
|
||||||
@@ -3692,9 +3733,7 @@ import VoucherExecutionDetail from './voucher-execution-detail.vue';
|
|||||||
import PunchRecordPhotos from './punch-record-photos.vue';
|
import PunchRecordPhotos from './punch-record-photos.vue';
|
||||||
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
||||||
import { getList as getDriverList } from '@/api/transportCapacity/driver';
|
import { getList as getDriverList } from '@/api/transportCapacity/driver';
|
||||||
import {
|
import { fetchDriverCandidates, driverOptionText } from '@/utils/carrier-org-resource';
|
||||||
fetchDriversByCarrierOrganizations,
|
|
||||||
} from '@/utils/carrier-org-resource';
|
|
||||||
import { getDictionary } from '@/api/system/dictbiz';
|
import { getDictionary } from '@/api/system/dictbiz';
|
||||||
import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
||||||
import { addressTypeOptions } from '@/option/base/common-address';
|
import { addressTypeOptions } from '@/option/base/common-address';
|
||||||
@@ -4011,6 +4050,7 @@ export default {
|
|||||||
weight: '',
|
weight: '',
|
||||||
volume: '',
|
volume: '',
|
||||||
quantity: '',
|
quantity: '',
|
||||||
|
mileage: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
photos: [],
|
photos: [],
|
||||||
},
|
},
|
||||||
@@ -4370,9 +4410,15 @@ export default {
|
|||||||
addBtn: this.canCreate,
|
addBtn: this.canCreate,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// 打卡记录编辑入口与运单编辑同权限:能改运单的人才能订正它的打卡流水
|
// 打卡记录编辑入口与运单编辑同权限:能改运单的人才能订正它的打卡流水。
|
||||||
|
// 时间轴的「编辑打卡 / 补卡」链接是本页唯一写入入口,提交固定 punched=true。
|
||||||
|
// 取消打卡不在本页;待回单确认的运单不显示该链接。
|
||||||
canEditWaybillPunchRecord() {
|
canEditWaybillPunchRecord() {
|
||||||
return this.hasPermission(`${this.config.permission}_edit`) && !this.readonlyScope;
|
return (
|
||||||
|
this.hasPermission(`${this.config.permission}_edit`) &&
|
||||||
|
!this.readonlyScope &&
|
||||||
|
this.statusValue(this.detailRow) !== 'pending_return_confirm'
|
||||||
|
);
|
||||||
},
|
},
|
||||||
waybillPunchEditNode() {
|
waybillPunchEditNode() {
|
||||||
return this.findWaybillPunchEditNodeConfig(this.waybillPunchEditRecord);
|
return this.findWaybillPunchEditNodeConfig(this.waybillPunchEditRecord);
|
||||||
@@ -4407,6 +4453,15 @@ export default {
|
|||||||
waybillPunchEditPunchDisabled() {
|
waybillPunchEditPunchDisabled() {
|
||||||
return this.waybillPunchEditNode?.punch === false;
|
return this.waybillPunchEditNode?.punch === false;
|
||||||
},
|
},
|
||||||
|
// 里程:后端下发 needMileage 才出现(末位打卡节点 + 计费规则含里程);在途打卡不采集里程
|
||||||
|
waybillPunchEditMileageVisible() {
|
||||||
|
const record = this.waybillPunchEditRecord || {};
|
||||||
|
return record.needMileage === true && record.type !== 'enroute';
|
||||||
|
},
|
||||||
|
// 已生成结算单的运单里程冻结:输入框置灰,改动由后端拒绝
|
||||||
|
waybillPunchEditMileageLocked() {
|
||||||
|
return this.waybillPunchEditRecord?.mileageLocked === true;
|
||||||
|
},
|
||||||
waybillPunchEditRules() {
|
waybillPunchEditRules() {
|
||||||
return { punchTime: [{ required: true, message: '请选择打卡时间', trigger: 'change' }] };
|
return { punchTime: [{ required: true, message: '请选择打卡时间', trigger: 'change' }] };
|
||||||
},
|
},
|
||||||
@@ -4595,9 +4650,14 @@ export default {
|
|||||||
},
|
},
|
||||||
taskCarrierValue: {
|
taskCarrierValue: {
|
||||||
get() {
|
get() {
|
||||||
return this.form.carrierType === '自运'
|
if (this.form.carrierType === '自运') {
|
||||||
? this.form.carrierName || ''
|
return this.form.carrierName || '';
|
||||||
: this.form.carrierContractId || this.form.carrierName || '';
|
}
|
||||||
|
return this.taskCarrierOptionValue({
|
||||||
|
carrierContractId: this.form.carrierContractId,
|
||||||
|
carrierPartyId: this.form.carrierPartyId,
|
||||||
|
carrierName: this.form.carrierName,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
this.handleTaskCarrierChange(value);
|
this.handleTaskCarrierChange(value);
|
||||||
@@ -4800,6 +4860,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatContractOptionLabel,
|
formatContractOptionLabel,
|
||||||
|
driverOptionText,
|
||||||
parseRouteChangeContent,
|
parseRouteChangeContent,
|
||||||
// 页面被 keep-alive 缓存/卸载时调用,关闭本页所有 append-to-body 的弹窗,
|
// 页面被 keep-alive 缓存/卸载时调用,关闭本页所有 append-to-body 的弹窗,
|
||||||
// 避免 Teleport 出去的 DOM 残留在 body 上盖住后续页面(详见 data 里的说明)。
|
// 避免 Teleport 出去的 DOM 残留在 body 上盖住后续页面(详见 data 里的说明)。
|
||||||
@@ -4957,9 +5018,9 @@ export default {
|
|||||||
return Object.values(groups)
|
return Object.values(groups)
|
||||||
.map(group => {
|
.map(group => {
|
||||||
const quantity = this.formatQuantity(group.quantity);
|
const quantity = this.formatQuantity(group.quantity);
|
||||||
return `${group.typeName}等${group.count}种货物 | ${quantity}${
|
const typeName =
|
||||||
group.unit ? ` ${group.unit}` : ''
|
group.count > 1 ? `${group.typeName}等${group.count}种货物` : group.typeName;
|
||||||
}`;
|
return `${typeName} | ${quantity}${group.unit ? ` ${group.unit}` : ''}`;
|
||||||
})
|
})
|
||||||
.join('; ');
|
.join('; ');
|
||||||
},
|
},
|
||||||
@@ -5060,11 +5121,16 @@ export default {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
canCopy(row) {
|
canCopy(row) {
|
||||||
|
if (!row) return false;
|
||||||
|
// 归属本账号可见范围的运单允许复制。跨组织但项目归属本账号的记录会被标成只读,
|
||||||
|
// 只读仅拦截编辑/删除,不拦截复制。具备查看、新增、编辑或复制权限即可使用。
|
||||||
return (
|
return (
|
||||||
this.hasAction('copy') &&
|
this.hasAction('copy') &&
|
||||||
this.hasPermission(`${this.config.permission}_copy`) &&
|
|
||||||
!this.readonlyScope &&
|
!this.readonlyScope &&
|
||||||
!row.readonly
|
(this.hasPermission(`${this.config.permission}_copy`) ||
|
||||||
|
this.hasPermission(`${this.config.permission}_add`) ||
|
||||||
|
this.hasPermission(`${this.config.permission}_edit`) ||
|
||||||
|
this.hasPermission(`${this.config.permission}_view`))
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
canEnable(row) {
|
canEnable(row) {
|
||||||
@@ -5099,7 +5165,8 @@ export default {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const status = this.statusValue(row);
|
const status = this.statusValue(row);
|
||||||
return status === 'pending';
|
// 待回单确认可取消,取消不生成应收应付
|
||||||
|
return status === 'pending' || status === 'pending_return_confirm';
|
||||||
},
|
},
|
||||||
canComplete(row) {
|
canComplete(row) {
|
||||||
if (
|
if (
|
||||||
@@ -5111,8 +5178,22 @@ export default {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const status = this.statusValue(row);
|
const status = this.statusValue(row);
|
||||||
|
// 待回单确认的「完成」由确认回单入口承担(走打卡节点与未了结异常校验);
|
||||||
|
// 只有确认回单不可用时才退回这里的普通完成
|
||||||
|
if (status === 'pending_return_confirm') {
|
||||||
|
return !this.canConfirmReturn(row);
|
||||||
|
}
|
||||||
return status === 'processing' || status === 'running';
|
return status === 'processing' || status === 'running';
|
||||||
},
|
},
|
||||||
|
canConfirmReturn(row) {
|
||||||
|
return (
|
||||||
|
this.hasAction('confirmReturn') &&
|
||||||
|
this.hasPermission(`${this.config.permission}_complete`) &&
|
||||||
|
!this.readonlyScope &&
|
||||||
|
!row.readonly &&
|
||||||
|
this.statusValue(row) === 'pending_return_confirm'
|
||||||
|
);
|
||||||
|
},
|
||||||
canMaintainMileage(row) {
|
canMaintainMileage(row) {
|
||||||
return (
|
return (
|
||||||
this.config.permission === 'waybill_manage' &&
|
this.config.permission === 'waybill_manage' &&
|
||||||
@@ -5926,6 +6007,8 @@ export default {
|
|||||||
weight: record.weight || '',
|
weight: record.weight || '',
|
||||||
volume: record.volume || '',
|
volume: record.volume || '',
|
||||||
quantity: record.quantity || '',
|
quantity: record.quantity || '',
|
||||||
|
// 里程只有正整数口径,后端若仍下发 "200.00" 会过不了提交时的正整数校验
|
||||||
|
mileage: Number(record.mileage) > 0 ? String(Number(record.mileage)) : '',
|
||||||
remark: record.remark || '',
|
remark: record.remark || '',
|
||||||
photos: (record.photos || [])
|
photos: (record.photos || [])
|
||||||
.filter(photo => photo?.url)
|
.filter(photo => photo?.url)
|
||||||
@@ -6001,10 +6084,22 @@ export default {
|
|||||||
photos.splice(index, 1);
|
photos.splice(index, 1);
|
||||||
this.waybillPunchEditForm.photos = photos;
|
this.waybillPunchEditForm.photos = photos;
|
||||||
},
|
},
|
||||||
|
// 里程只收整数:非数字直接丢掉,长度与「维护里程」一致(≤10 位)
|
||||||
|
handleWaybillPunchMileageInput(value) {
|
||||||
|
this.waybillPunchEditForm.mileage = String(value || '')
|
||||||
|
.replace(/\D/g, '')
|
||||||
|
.slice(0, 10);
|
||||||
|
},
|
||||||
async submitWaybillPunchRecordEdit() {
|
async submitWaybillPunchRecordEdit() {
|
||||||
await this.$refs.waybillPunchRecordEditFormRef.validate();
|
await this.$refs.waybillPunchRecordEditFormRef.validate();
|
||||||
const record = this.waybillPunchEditRecord;
|
const record = this.waybillPunchEditRecord;
|
||||||
const form = this.waybillPunchEditForm;
|
const form = this.waybillPunchEditForm;
|
||||||
|
// 管理端里程选填:留空表示不改动运单里程,所以只校验填了值的情况
|
||||||
|
const mileageText = String(form.mileage || '').trim();
|
||||||
|
if (this.waybillPunchEditMileageVisible && mileageText && !/^[1-9]\d{0,9}$/.test(mileageText)) {
|
||||||
|
this.$message.warning('里程必须为不超过10位的正整数');
|
||||||
|
return;
|
||||||
|
}
|
||||||
const submit =
|
const submit =
|
||||||
typeof this.api?.savePunchRecord === 'function' ? this.api.savePunchRecord : savePunchRecord;
|
typeof this.api?.savePunchRecord === 'function' ? this.api.savePunchRecord : savePunchRecord;
|
||||||
this.waybillPunchRecordEditDialog.submitting = true;
|
this.waybillPunchRecordEditDialog.submitting = true;
|
||||||
@@ -6023,6 +6118,8 @@ export default {
|
|||||||
weight: form.weight,
|
weight: form.weight,
|
||||||
volume: form.volume,
|
volume: form.volume,
|
||||||
quantity: form.quantity,
|
quantity: form.quantity,
|
||||||
|
// 不传代表不改;后端按 null 处理
|
||||||
|
mileage: mileageText ? Number(mileageText) : undefined,
|
||||||
remark: form.remark,
|
remark: form.remark,
|
||||||
photos: form.photos.map(photo => ({ url: photo.url, type: photo.type })),
|
photos: form.photos.map(photo => ({ url: photo.url, type: photo.type })),
|
||||||
});
|
});
|
||||||
@@ -6543,6 +6640,9 @@ export default {
|
|||||||
if (status === 'completed') {
|
if (status === 'completed') {
|
||||||
return 'primary';
|
return 'primary';
|
||||||
}
|
}
|
||||||
|
if (status === 'pending_return_confirm') {
|
||||||
|
return 'warning';
|
||||||
|
}
|
||||||
return 'warning';
|
return 'warning';
|
||||||
},
|
},
|
||||||
normalizeRow(row, saveAsDraft = false) {
|
normalizeRow(row, saveAsDraft = false) {
|
||||||
@@ -7195,6 +7295,8 @@ export default {
|
|||||||
this.form.carrierName = '';
|
this.form.carrierName = '';
|
||||||
this.form.carrierId = '';
|
this.form.carrierId = '';
|
||||||
this.form.carrierContractId = '';
|
this.form.carrierContractId = '';
|
||||||
|
this.form.carrierPartyId = '';
|
||||||
|
this.form.carrierPartyRole = '';
|
||||||
this.hasProjectProcessConfig = false;
|
this.hasProjectProcessConfig = false;
|
||||||
this.waybillProcessConfigRows = [];
|
this.waybillProcessConfigRows = [];
|
||||||
return;
|
return;
|
||||||
@@ -7209,6 +7311,8 @@ export default {
|
|||||||
this.form.carrierName = '';
|
this.form.carrierName = '';
|
||||||
this.form.carrierId = '';
|
this.form.carrierId = '';
|
||||||
this.form.carrierContractId = '';
|
this.form.carrierContractId = '';
|
||||||
|
this.form.carrierPartyId = '';
|
||||||
|
this.form.carrierPartyRole = '';
|
||||||
this.loadProjectProcessConfigState();
|
this.loadProjectProcessConfigState();
|
||||||
this.loadTaskCarrierOptions(project);
|
this.loadTaskCarrierOptions(project);
|
||||||
if (this.contractSelectEnabled) {
|
if (this.contractSelectEnabled) {
|
||||||
@@ -7665,6 +7769,8 @@ export default {
|
|||||||
this.form.carrierName = '';
|
this.form.carrierName = '';
|
||||||
this.form.carrierId = '';
|
this.form.carrierId = '';
|
||||||
this.form.carrierContractId = '';
|
this.form.carrierContractId = '';
|
||||||
|
this.form.carrierPartyId = '';
|
||||||
|
this.form.carrierPartyRole = '';
|
||||||
this.form.driverId = '';
|
this.form.driverId = '';
|
||||||
this.form.driverName = '';
|
this.form.driverName = '';
|
||||||
this.form.driverPhone = '';
|
this.form.driverPhone = '';
|
||||||
@@ -7719,7 +7825,9 @@ export default {
|
|||||||
},
|
},
|
||||||
taskCarrierOptionValue(item = {}) {
|
taskCarrierOptionValue(item = {}) {
|
||||||
if (this.form.carrierType !== '自运') {
|
if (this.form.carrierType !== '自运') {
|
||||||
return item.carrierContractId || item.value || item.id || '';
|
if (item.value) return item.value;
|
||||||
|
return [item.carrierContractId || item.id || '', item.carrierPartyId || '', item.carrierName || '']
|
||||||
|
.join('__');
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
item.carrierName ||
|
item.carrierName ||
|
||||||
@@ -7757,55 +7865,76 @@ export default {
|
|||||||
names.forEach(append);
|
names.forEach(append);
|
||||||
return options;
|
return options;
|
||||||
},
|
},
|
||||||
|
parseContractPartyRows(partyJson, fallbackName = '', partyRole = 'B') {
|
||||||
|
const rows = this.parseJsonArray(partyJson)
|
||||||
|
.map(item => ({
|
||||||
|
id: item.id || '',
|
||||||
|
customerId: item.customerId || '',
|
||||||
|
customerName: String(item.customerName || '').trim(),
|
||||||
|
creditCode: item.creditCode || '',
|
||||||
|
partyRole,
|
||||||
|
}))
|
||||||
|
.filter(item => item.customerName);
|
||||||
|
if (rows.length) return rows;
|
||||||
|
return String(fallbackName || '')
|
||||||
|
.split(/[、,,]/)
|
||||||
|
.map(name => name.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(name => ({
|
||||||
|
id: '',
|
||||||
|
customerId: '',
|
||||||
|
customerName: name,
|
||||||
|
creditCode: '',
|
||||||
|
partyRole,
|
||||||
|
}));
|
||||||
|
},
|
||||||
getWaybillCarrierContractOptions(contracts = []) {
|
getWaybillCarrierContractOptions(contracts = []) {
|
||||||
const carrierNameCounts = contracts.reduce((counts, contract) => {
|
const options = [];
|
||||||
const carrierName = String(
|
contracts.forEach(contract => {
|
||||||
contract.partyB ||
|
if (!contract?.id) return;
|
||||||
contract.partyBName ||
|
const parties = [
|
||||||
contract.contractPartyB ||
|
...this.parseContractPartyRows(contract.partyBJson, contract.partyB, 'B'),
|
||||||
contract.customerContractPartyB ||
|
...this.parseContractPartyRows(contract.partyCJson, contract.partyC, 'C'),
|
||||||
contract.secondParty ||
|
];
|
||||||
contract.secondPartyName ||
|
if (!parties.length) {
|
||||||
''
|
const fallbackName = String(
|
||||||
).trim();
|
|
||||||
if (carrierName) counts[carrierName] = (counts[carrierName] || 0) + 1;
|
|
||||||
return counts;
|
|
||||||
}, {});
|
|
||||||
return contracts
|
|
||||||
.map(contract => {
|
|
||||||
const carrierName = String(
|
|
||||||
contract.partyB ||
|
contract.partyB ||
|
||||||
contract.partyBName ||
|
contract.partyBName ||
|
||||||
contract.contractPartyB ||
|
contract.contractPartyB ||
|
||||||
contract.customerContractPartyB ||
|
contract.customerContractPartyB ||
|
||||||
contract.secondParty ||
|
contract.secondParty ||
|
||||||
contract.secondPartyName ||
|
contract.secondPartyName ||
|
||||||
''
|
''
|
||||||
).trim();
|
).trim();
|
||||||
if (!carrierName || !contract.id) return null;
|
if (fallbackName) {
|
||||||
const contractIdentifier = contract.contractName || contract.contractNo || contract.id;
|
parties.push({
|
||||||
return {
|
id: '',
|
||||||
|
customerId: '',
|
||||||
|
customerName: fallbackName,
|
||||||
|
creditCode: '',
|
||||||
|
partyRole: 'B',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const contractIdentifier = contract.contractName || contract.contractNo || contract.id;
|
||||||
|
parties.forEach(party => {
|
||||||
|
const roleLabel = party.partyRole === 'C' ? '丙方' : '乙方';
|
||||||
|
const optionValue = [contract.id, party.id || '', party.customerName].join('__');
|
||||||
|
options.push({
|
||||||
id: contract.id,
|
id: contract.id,
|
||||||
carrierId:
|
carrierId: party.customerId || '',
|
||||||
contract.partyBId ||
|
value: optionValue,
|
||||||
contract.partyBUserId ||
|
label: `${party.customerName}(${roleLabel}) - ${contractIdentifier}`,
|
||||||
contract.contractPartyBId ||
|
carrierName: party.customerName,
|
||||||
contract.customerContractPartyBId ||
|
fullName: party.customerName,
|
||||||
contract.secondPartyId ||
|
|
||||||
contract.secondPartyUserId ||
|
|
||||||
contract.carrierId ||
|
|
||||||
'',
|
|
||||||
value: contract.id,
|
|
||||||
label:
|
|
||||||
carrierNameCounts[carrierName] > 1
|
|
||||||
? `${carrierName}(${contractIdentifier})`
|
|
||||||
: carrierName,
|
|
||||||
carrierName,
|
|
||||||
fullName: carrierName,
|
|
||||||
carrierContractId: contract.id,
|
carrierContractId: contract.id,
|
||||||
};
|
carrierPartyId: party.id || '',
|
||||||
})
|
carrierPartyRole: party.partyRole,
|
||||||
.filter(Boolean);
|
creditCode: party.creditCode || '',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return options;
|
||||||
},
|
},
|
||||||
resetWaybillCarrierContractState() {
|
resetWaybillCarrierContractState() {
|
||||||
this.waybillCarrierContractRequestId += 1;
|
this.waybillCarrierContractRequestId += 1;
|
||||||
@@ -7835,6 +7964,8 @@ export default {
|
|||||||
this.form.carrierName = '';
|
this.form.carrierName = '';
|
||||||
this.form.carrierId = '';
|
this.form.carrierId = '';
|
||||||
this.form.carrierContractId = '';
|
this.form.carrierContractId = '';
|
||||||
|
this.form.carrierPartyId = '';
|
||||||
|
this.form.carrierPartyRole = '';
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
})
|
})
|
||||||
@@ -7925,10 +8056,14 @@ export default {
|
|||||||
);
|
);
|
||||||
if (this.form.carrierType !== '自运') {
|
if (this.form.carrierType !== '自运') {
|
||||||
this.form.carrierContractId = carrier?.carrierContractId || '';
|
this.form.carrierContractId = carrier?.carrierContractId || '';
|
||||||
|
this.form.carrierPartyId = carrier?.carrierPartyId || '';
|
||||||
|
this.form.carrierPartyRole = carrier?.carrierPartyRole || '';
|
||||||
this.form.carrierId = carrier?.carrierId || '';
|
this.form.carrierId = carrier?.carrierId || '';
|
||||||
this.form.carrierName = carrier?.carrierName || '';
|
this.form.carrierName = carrier?.carrierName || '';
|
||||||
} else {
|
} else {
|
||||||
this.form.carrierId = carrier?.carrierContractId ? '' : carrier?.id || '';
|
this.form.carrierId = carrier?.carrierContractId ? '' : carrier?.id || '';
|
||||||
|
this.form.carrierPartyId = '';
|
||||||
|
this.form.carrierPartyRole = '';
|
||||||
this.form.carrierName = value || '';
|
this.form.carrierName = value || '';
|
||||||
}
|
}
|
||||||
// 承运商变更后清空司机/车辆,避免跨组织脏数据
|
// 承运商变更后清空司机/车辆,避免跨组织脏数据
|
||||||
@@ -7942,19 +8077,10 @@ export default {
|
|||||||
this.taskDriverOptions = [];
|
this.taskDriverOptions = [];
|
||||||
this.taskEscortOptions = [];
|
this.taskEscortOptions = [];
|
||||||
},
|
},
|
||||||
getTaskCarrierFilter() {
|
|
||||||
return {
|
|
||||||
carrierId: this.form.carrierId || '',
|
|
||||||
carrierName: this.form.carrierName || '',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
loadTaskDriverOptions() {
|
loadTaskDriverOptions() {
|
||||||
if (!this.taskInfoFormEnabled || this.taskDriverLoading) return Promise.resolve([]);
|
if (!this.taskInfoFormEnabled || this.taskDriverLoading) return Promise.resolve([]);
|
||||||
this.taskDriverLoading = true;
|
this.taskDriverLoading = true;
|
||||||
return fetchDriversByCarrierOrganizations(
|
return fetchDriverCandidates({ size: 9999, posts: '司机' })
|
||||||
{ size: 9999, posts: '司机' },
|
|
||||||
this.getTaskCarrierFilter()
|
|
||||||
)
|
|
||||||
.then(records => {
|
.then(records => {
|
||||||
this.taskDriverOptions = records;
|
this.taskDriverOptions = records;
|
||||||
return this.taskDriverOptions;
|
return this.taskDriverOptions;
|
||||||
@@ -7965,16 +8091,8 @@ export default {
|
|||||||
},
|
},
|
||||||
fetchTaskDriverSuggestions(queryString, callback) {
|
fetchTaskDriverSuggestions(queryString, callback) {
|
||||||
const keyword = String(queryString || '').trim();
|
const keyword = String(queryString || '').trim();
|
||||||
const carrier = this.getTaskCarrierFilter();
|
|
||||||
if (!carrier.carrierId && !carrier.carrierName) {
|
|
||||||
callback([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.taskDriverLoading = true;
|
this.taskDriverLoading = true;
|
||||||
fetchDriversByCarrierOrganizations(
|
fetchDriverCandidates({ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '司机' })
|
||||||
{ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '司机' },
|
|
||||||
carrier
|
|
||||||
)
|
|
||||||
.then(records => {
|
.then(records => {
|
||||||
this.taskDriverOptions = records;
|
this.taskDriverOptions = records;
|
||||||
callback(
|
callback(
|
||||||
@@ -7994,16 +8112,12 @@ export default {
|
|||||||
},
|
},
|
||||||
fetchTaskEscortSuggestions(queryString, callback) {
|
fetchTaskEscortSuggestions(queryString, callback) {
|
||||||
const keyword = String(queryString || '').trim();
|
const keyword = String(queryString || '').trim();
|
||||||
const carrier = this.getTaskCarrierFilter();
|
|
||||||
if (!carrier.carrierId && !carrier.carrierName) {
|
|
||||||
callback([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.taskEscortLoading = true;
|
this.taskEscortLoading = true;
|
||||||
fetchDriversByCarrierOrganizations(
|
fetchDriverCandidates({
|
||||||
{ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '押运员' },
|
size: 20,
|
||||||
carrier
|
...(keyword ? { driverName: keyword } : {}),
|
||||||
)
|
posts: '押运员',
|
||||||
|
})
|
||||||
.then(records => {
|
.then(records => {
|
||||||
this.taskEscortOptions = records;
|
this.taskEscortOptions = records;
|
||||||
callback(records.map(item => ({ ...item, value: item.driverName || item.name || '' })));
|
callback(records.map(item => ({ ...item, value: item.driverName || item.name || '' })));
|
||||||
@@ -10150,8 +10264,14 @@ export default {
|
|||||||
cancel: '取消',
|
cancel: '取消',
|
||||||
complete: this.completeActionLabel,
|
complete: this.completeActionLabel,
|
||||||
reassign: '重新派单',
|
reassign: '重新派单',
|
||||||
|
confirmReturn: '完成',
|
||||||
}[action];
|
}[action];
|
||||||
this.$confirm(`确定${actionName}该${this.config.title}?`, '提示', {
|
// 回单确认是终态动作(本轮不做撤销),把后果写在提示里,别让人以为还能退回
|
||||||
|
const confirmText =
|
||||||
|
action === 'confirmReturn'
|
||||||
|
? '回单确认后该运单将置为已完成,且不可撤销。是否继续?'
|
||||||
|
: `确定${actionName}该${this.config.title}?`;
|
||||||
|
this.$confirm(confirmText, '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
@@ -10204,20 +10324,8 @@ export default {
|
|||||||
},
|
},
|
||||||
fetchReassignDriverSuggestions(queryString, callback) {
|
fetchReassignDriverSuggestions(queryString, callback) {
|
||||||
const keyword = String(queryString || '').trim();
|
const keyword = String(queryString || '').trim();
|
||||||
const row = this.reassignDrawer.row || {};
|
|
||||||
const carrier = {
|
|
||||||
carrierId: row.carrierId || '',
|
|
||||||
carrierName: row.carrierName || '',
|
|
||||||
};
|
|
||||||
if (!carrier.carrierId && !carrier.carrierName) {
|
|
||||||
callback([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.reassignDrawer.driverLoading = true;
|
this.reassignDrawer.driverLoading = true;
|
||||||
fetchDriversByCarrierOrganizations(
|
fetchDriverCandidates({ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '司机' })
|
||||||
{ size: 20, ...(keyword ? { driverName: keyword } : {}), posts: '司机' },
|
|
||||||
carrier
|
|
||||||
)
|
|
||||||
.then(records => {
|
.then(records => {
|
||||||
this.reassignDriverOptions = records;
|
this.reassignDriverOptions = records;
|
||||||
callback(
|
callback(
|
||||||
@@ -10356,7 +10464,14 @@ export default {
|
|||||||
this.$message.warning('请选择至少一条数据');
|
this.$message.warning('请选择至少一条数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.$confirm('确定完成选中的运单?', '提示', {
|
const pendingReturnCount = this.selectionList.filter(
|
||||||
|
row => this.statusValue(row) === 'pending_return_confirm'
|
||||||
|
).length;
|
||||||
|
const tip =
|
||||||
|
pendingReturnCount > 0
|
||||||
|
? `确定完成选中的运单?其中 ${pendingReturnCount} 条为待回单确认,确认后将转为已完成。`
|
||||||
|
: '确定完成选中的运单?';
|
||||||
|
this.$confirm(tip, '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
@@ -10370,25 +10485,38 @@ export default {
|
|||||||
this.onLoad(this.page, this.query);
|
this.onLoad(this.page, this.query);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleRoadLoading() {
|
async handleRoadLoading() {
|
||||||
if (!this.selectionList.length) {
|
if (!this.selectionList.length) {
|
||||||
this.$message.warning('请选择至少一条数据');
|
this.$message.warning('请选择至少一条数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const nonRoadWaybills = this.selectionList.filter(row => !this.waybillIsRoadTransport(row));
|
const selectedIds = this.selectionList.map(row => row.id).filter(Boolean);
|
||||||
if (nonRoadWaybills.length) {
|
if (!selectedIds.length) {
|
||||||
this.$message.warning('公路配载仅支持运输方式为“公路运输”的运单');
|
this.$message.warning('请选择至少一条数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const unavailableWaybills = this.selectionList.filter(
|
// 可配载与否只看后端查询结果
|
||||||
row =>
|
let loadableIds;
|
||||||
!['processing', 'running'].includes(this.statusValue(row)) ||
|
try {
|
||||||
row.loadingId ||
|
const res = await getWaybillList(1, selectedIds.length, {
|
||||||
row.loadingManageId ||
|
loadableOnly: 1,
|
||||||
row.loadingNo
|
ids: selectedIds.join(','),
|
||||||
);
|
});
|
||||||
if (unavailableWaybills.length) {
|
loadableIds = new Set(extractRecords(res).map(row => String(row.id)));
|
||||||
this.$message.warning('公路配载仅支持进行中且未配载的运单');
|
} catch (error) {
|
||||||
|
this.$message.error('校验运单可配载状态失败,请重试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rejectedRows = this.selectionList.filter(row => !loadableIds.has(String(row.id)));
|
||||||
|
if (rejectedRows.length) {
|
||||||
|
const rejectedText = rejectedRows
|
||||||
|
.map(row => {
|
||||||
|
const reason = this.roadLoadingRejectReasonText(row);
|
||||||
|
const no = row.waybillNo || row.id || '';
|
||||||
|
return `${no}(${reason})`;
|
||||||
|
})
|
||||||
|
.join('、');
|
||||||
|
this.$message.warning(`${rejectedText};公路配载仅支持公路、待执行且未配载的运单`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -10411,6 +10539,13 @@ export default {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// 只给后端判定为不可配载的运单生成可读原因,本身不参与准入判定
|
||||||
|
roadLoadingRejectReasonText(row = {}) {
|
||||||
|
if (!this.waybillIsRoadTransport(row)) return '非公路运输';
|
||||||
|
if (String(row.businessStatus || '') !== 'pending') return '状态不是待执行';
|
||||||
|
if (row.loadingNo) return '已关联配载单';
|
||||||
|
return '运单数据可能已变化,请刷新后重试';
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<mk-public-shell biz-type="contract-change" :get-form="getForm">
|
||||||
|
<contract-manage-change ref="page" />
|
||||||
|
</mk-public-shell>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MkPublicShell from '@/views/mk/mk-public-shell.vue';
|
||||||
|
import ContractManageChange from '@/views/business/contract-manage-change.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ContractChangePublicView',
|
||||||
|
components: { MkPublicShell, ContractManageChange },
|
||||||
|
methods: {
|
||||||
|
getForm() {
|
||||||
|
const row = this.$refs.page?.form || {};
|
||||||
|
return { ...row, subject: row.contractName || row.contractNo || '' };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,407 @@
|
|||||||
|
<template>
|
||||||
|
<basic-container class="contract-change-page">
|
||||||
|
<avue-crud
|
||||||
|
:option="tableOption"
|
||||||
|
:table-loading="loading"
|
||||||
|
:data="data"
|
||||||
|
v-model:page="page"
|
||||||
|
v-model="tableForm"
|
||||||
|
ref="crud"
|
||||||
|
:permission="permissionList"
|
||||||
|
@search-change="searchChange"
|
||||||
|
@search-reset="searchReset"
|
||||||
|
@selection-change="selectionChange"
|
||||||
|
@current-change="currentChange"
|
||||||
|
@size-change="sizeChange"
|
||||||
|
@refresh-change="refreshChange"
|
||||||
|
@on-load="onLoad"
|
||||||
|
>
|
||||||
|
<template #menu-left>
|
||||||
|
<el-button type="primary" plain :loading="hcsRepushingId === 'batch'" @click="handleHcsBatchRepush">
|
||||||
|
批量同步
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
icon="el-icon-delete"
|
||||||
|
plain
|
||||||
|
v-if="hasPermission(`${config.permission}_delete`)"
|
||||||
|
@click="handleDelete"
|
||||||
|
>
|
||||||
|
批量删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #approvalStatus="{ row }">
|
||||||
|
{{ row.approvalStatusName || statusLabel(row.approvalStatus) }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #syncStatus="{ row }">
|
||||||
|
<el-tag v-if="row.syncStatus" :type="syncTagType(row.syncStatus)" class="status-text">
|
||||||
|
{{ syncLabel(row.syncStatus) }}
|
||||||
|
</el-tag>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #menu="{ row }">
|
||||||
|
<el-link type="primary" v-if="canView(row)" @click="openForm('view', row)"> 查看 </el-link>
|
||||||
|
<el-link type="primary" v-if="canEdit(row)" @click="openForm('edit', row)"> 编辑 </el-link>
|
||||||
|
<el-link type="danger" v-if="canDelete(row)" @click="rowDel(row)"> 删除 </el-link>
|
||||||
|
<el-link
|
||||||
|
v-for="operation in customOperations(row)"
|
||||||
|
:key="operation.action"
|
||||||
|
:type="
|
||||||
|
operation.type === 'warning'
|
||||||
|
? 'warning'
|
||||||
|
: operation.type === 'success'
|
||||||
|
? 'success'
|
||||||
|
: 'primary'
|
||||||
|
"
|
||||||
|
@click="handleCustomOperation(operation, row)"
|
||||||
|
>
|
||||||
|
{{ operation.label }}
|
||||||
|
</el-link>
|
||||||
|
</template>
|
||||||
|
</avue-crud>
|
||||||
|
</basic-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as api from '@/api/business/contract-change';
|
||||||
|
import { repushBatch as hcsRepushBatch } from '@/api/business/hcs';
|
||||||
|
import { getMKApprovalUrl } from '@/api/system/business-process';
|
||||||
|
import { config, option } from '@/option/business/contract-change';
|
||||||
|
import { approvalStatusOptions } from '@/option/business/common';
|
||||||
|
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||||
|
import { isAdministrator } from '@/utils/auth';
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
const contractChangeFormRoute = '/business/contract-change/form';
|
||||||
|
const contractChangeListRefreshKey = 'contract-change-list-refresh';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ContractChange',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
api,
|
||||||
|
config,
|
||||||
|
tableForm: {},
|
||||||
|
tableOption: this.buildTableOption(),
|
||||||
|
loading: true,
|
||||||
|
data: [],
|
||||||
|
page: {
|
||||||
|
pageSize: 10,
|
||||||
|
currentPage: 1,
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
query: {},
|
||||||
|
selectionList: [],
|
||||||
|
mkEnabled: false,
|
||||||
|
hcsRepushingId: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['permission', 'userInfo', 'website']),
|
||||||
|
permissionList() {
|
||||||
|
return {
|
||||||
|
addBtn: false,
|
||||||
|
viewBtn: false,
|
||||||
|
delBtn: false,
|
||||||
|
editBtn: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
isAdmin() {
|
||||||
|
return isAdministrator(this.userInfo);
|
||||||
|
},
|
||||||
|
ids() {
|
||||||
|
return this.selectionList.map(item => item.id).join(',');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
loadMkEnabled()
|
||||||
|
.then(enabled => {
|
||||||
|
this.mkEnabled = enabled;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.mkEnabled = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
if (sessionStorage.getItem(contractChangeListRefreshKey)) {
|
||||||
|
sessionStorage.removeItem(contractChangeListRefreshKey);
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
buildTableOption() {
|
||||||
|
return {
|
||||||
|
...option,
|
||||||
|
addBtn: false,
|
||||||
|
viewBtn: false,
|
||||||
|
editBtn: false,
|
||||||
|
delBtn: false,
|
||||||
|
menuWidth: 320,
|
||||||
|
column: (option.column || []).map(column => ({
|
||||||
|
...column,
|
||||||
|
display: false,
|
||||||
|
align: 'center',
|
||||||
|
headerAlign: 'center',
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
hasPermission(code) {
|
||||||
|
return this.isAdmin || this.validData(this.permission && this.permission[code], false);
|
||||||
|
},
|
||||||
|
statusLabel(status) {
|
||||||
|
return approvalStatusOptions.find(item => item.value === status)?.label || status || '-';
|
||||||
|
},
|
||||||
|
syncLabel(value) {
|
||||||
|
return { unsynced: '待推送', synced: '已推送', failed: '推送失败' }[value] || value;
|
||||||
|
},
|
||||||
|
syncTagType(value) {
|
||||||
|
return { unsynced: 'info', synced: 'success', failed: 'danger' }[value] || 'info';
|
||||||
|
},
|
||||||
|
canHcsRepush(row) {
|
||||||
|
return row.approvalStatus === 'approved' && row.contractId && row.syncStatus !== 'synced';
|
||||||
|
},
|
||||||
|
handleHcsBatchRepush() {
|
||||||
|
if (this.hcsRepushingId) return;
|
||||||
|
if (!this.selectionList.length) {
|
||||||
|
this.$message.warning('请选择至少一条数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rows = this.selectionList.filter(item => this.canHcsRepush(item));
|
||||||
|
if (!rows.length) {
|
||||||
|
this.$message.warning('请选择审批通过且未同步成功的变更单');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$confirm(`确定同步选中的${rows.length}条合同变更到合规系统?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => {
|
||||||
|
const loading = this.$loading({
|
||||||
|
lock: true,
|
||||||
|
text: '正在推送合规,请稍候…',
|
||||||
|
background: 'rgba(255, 255, 255, 0.6)',
|
||||||
|
});
|
||||||
|
this.hcsRepushingId = 'batch';
|
||||||
|
const contractIds = [...new Set(rows.map(item => item.contractId))];
|
||||||
|
const changeIds = rows.map(item => item.id).join(',');
|
||||||
|
hcsRepushBatch('contract', contractIds)
|
||||||
|
.then(res => {
|
||||||
|
if (res.data?.success === false) {
|
||||||
|
this.$message.error(res.data?.msg || '批量同步失败');
|
||||||
|
return api.markSyncStatus(changeIds, 'failed');
|
||||||
|
}
|
||||||
|
return api.markSyncStatus(changeIds, 'synced').then(() => {
|
||||||
|
this.$message.success(res.data?.data || '批量同步成功');
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => api.markSyncStatus(changeIds, 'failed'))
|
||||||
|
.finally(() => {
|
||||||
|
this.hcsRepushingId = null;
|
||||||
|
loading.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
inStatus(row, statusList) {
|
||||||
|
if (!statusList || !statusList.length) return true;
|
||||||
|
return statusList.includes(row.approvalStatus);
|
||||||
|
},
|
||||||
|
canEdit(row) {
|
||||||
|
return (
|
||||||
|
this.hasPermission(`${this.config.permission}_edit`) &&
|
||||||
|
!row.readonly &&
|
||||||
|
this.inStatus(row, this.config.editStatus)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
canDelete(row) {
|
||||||
|
return (
|
||||||
|
this.hasPermission(`${this.config.permission}_delete`) &&
|
||||||
|
!row.readonly &&
|
||||||
|
this.inStatus(row, this.config.deleteStatus)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
canView(row) {
|
||||||
|
return (
|
||||||
|
this.hasPermission(`${this.config.permission}_view`) &&
|
||||||
|
this.inStatus(row, this.config.viewStatus)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
canOperation(operation, row) {
|
||||||
|
if (operation.permission && !this.hasPermission(operation.permission)) return false;
|
||||||
|
if (
|
||||||
|
row.readonly &&
|
||||||
|
['submitApproval', 'withdraw', 'approve', 'reject'].includes(operation.action)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.inStatus(row, operation.status);
|
||||||
|
},
|
||||||
|
customOperations(row) {
|
||||||
|
return (this.config.operations || []).filter(operation => {
|
||||||
|
if (operation.mkOnly && !this.mkEnabled) return false;
|
||||||
|
if (operation.localOnly && this.mkEnabled) return false;
|
||||||
|
return this.canOperation(operation, row);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openForm(mode, row = {}) {
|
||||||
|
const query = { mode, id: row.id };
|
||||||
|
if (mode === 'edit') query.name = '编辑合同变更';
|
||||||
|
else if (mode === 'view') query.name = '查看合同变更';
|
||||||
|
this.$router.push({ path: contractChangeFormRoute, query });
|
||||||
|
},
|
||||||
|
handleCustomOperation(operation, row) {
|
||||||
|
if (operation.action === 'mkAudit') {
|
||||||
|
this.handleMkAudit(row);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const run = () => {
|
||||||
|
const request = () => this.api[operation.action](row.id);
|
||||||
|
const afterMk =
|
||||||
|
operation.action === 'submitApproval'
|
||||||
|
? submitMkApprovalFlow({
|
||||||
|
bizType: 'contract-change',
|
||||||
|
bizId: row.id,
|
||||||
|
subjectName: row.contractName || '',
|
||||||
|
approvalStatus: row.approvalStatus || '',
|
||||||
|
mkEnabled: this.mkEnabled,
|
||||||
|
}).then(() => request())
|
||||||
|
: request();
|
||||||
|
const loading =
|
||||||
|
operation.action === 'approve'
|
||||||
|
? this.$loading({
|
||||||
|
lock: true,
|
||||||
|
text: '正在推送合规,请稍候…',
|
||||||
|
background: 'rgba(255, 255, 255, 0.6)',
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
afterMk
|
||||||
|
.then(res => {
|
||||||
|
if (operation.action === 'approve' && res.data?.data === false) {
|
||||||
|
this.$message.warning(res.data?.msg);
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res.data?.success === false) {
|
||||||
|
this.$message.error(res.data?.msg || `${operation.label}失败,请联系管理员`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$message.success(`${operation.label}成功`);
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
})
|
||||||
|
.finally(() => loading && loading.close());
|
||||||
|
};
|
||||||
|
this.$confirm(operation.confirm || `确定${operation.label}该${this.config.title}?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => run());
|
||||||
|
},
|
||||||
|
handleMkAudit(row) {
|
||||||
|
if (!row?.id) {
|
||||||
|
this.$message.warning('变更单ID为空,无法打开审核页');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getMKApprovalUrl({ bizId: String(row.id) })
|
||||||
|
.then(res => {
|
||||||
|
const url = res?.data?.data;
|
||||||
|
if (!url) {
|
||||||
|
this.$message.error('获取审核跳转地址失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.open(url, '_blank');
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.$message.error('获取审核跳转地址失败');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
searchReset() {
|
||||||
|
this.query = {};
|
||||||
|
this.onLoad(this.page);
|
||||||
|
},
|
||||||
|
searchChange(params, done) {
|
||||||
|
this.query = params;
|
||||||
|
this.page.currentPage = 1;
|
||||||
|
this.onLoad(this.page, params);
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
selectionChange(list) {
|
||||||
|
this.selectionList = list;
|
||||||
|
},
|
||||||
|
selectionClear() {
|
||||||
|
this.selectionList = [];
|
||||||
|
this.$refs.crud?.toggleSelection?.();
|
||||||
|
},
|
||||||
|
currentChange(currentPage) {
|
||||||
|
this.page.currentPage = currentPage;
|
||||||
|
},
|
||||||
|
sizeChange(pageSize) {
|
||||||
|
this.page.pageSize = pageSize;
|
||||||
|
},
|
||||||
|
refreshChange() {
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
},
|
||||||
|
rowDel(row) {
|
||||||
|
this.$confirm('确定将选择数据删除?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => {
|
||||||
|
this.api.remove(row.id).then(() => {
|
||||||
|
this.$message.success('删除成功!');
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleDelete() {
|
||||||
|
if (!this.selectionList.length) {
|
||||||
|
this.$message.warning('请选择至少一条数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$confirm('确定将选择数据删除?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => {
|
||||||
|
this.api.remove(this.ids).then(() => {
|
||||||
|
this.$message.success('删除成功!');
|
||||||
|
this.selectionClear();
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onLoad(page, params = {}) {
|
||||||
|
this.loading = true;
|
||||||
|
const values = {
|
||||||
|
...this.query,
|
||||||
|
...params,
|
||||||
|
};
|
||||||
|
this.api
|
||||||
|
.getList(page.currentPage, page.pageSize, values)
|
||||||
|
.then(res => {
|
||||||
|
const data = res.data.data || {};
|
||||||
|
this.page.total = data.total || 0;
|
||||||
|
this.data = data.records || [];
|
||||||
|
this.loading = false;
|
||||||
|
this.selectionClear();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.contract-change-page {
|
||||||
|
:deep(.avue-crud__menu) {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,18 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
<basic-container class="contract-change-page">
|
<basic-container class="contract-change-page">
|
||||||
<div class="archive-page-form__title">{{ pageTitle }}</div>
|
<div class="archive-page-form__title">{{ pageTitle }}</div>
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="right" label-width="auto" class="contract-change-form">
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
:disabled="pageReadonly"
|
||||||
|
label-position="right"
|
||||||
|
label-width="auto"
|
||||||
|
class="contract-change-form"
|
||||||
|
>
|
||||||
<section class="change-section contract-basic-section">
|
<section class="change-section contract-basic-section">
|
||||||
<div class="dialog-section-title">基本信息</div>
|
<div class="dialog-section-title">基本信息</div>
|
||||||
<div class="contract-basic-section__grid">
|
<div class="contract-basic-section__grid">
|
||||||
<el-form-item label="变更类型" class="contract-basic-section__change-type">
|
<el-form-item label="变更类型" class="contract-basic-section__change-type">
|
||||||
<el-radio-group v-model="form.changeType">
|
<el-radio-group v-model="form.changeType" :disabled="pageReadonly">
|
||||||
<el-radio label="合同信息变更" />
|
<el-radio label="合同信息变更" />
|
||||||
|
<el-radio label="结算规则变更" />
|
||||||
<el-radio label="终止合同" />
|
<el-radio label="终止合同" />
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="签约类型" prop="signType">
|
<el-form-item label="签约类型" prop="signType">
|
||||||
<el-select v-model="form.signType" placeholder="请选择签约类型" clearable>
|
<el-select
|
||||||
|
v-model="form.signType"
|
||||||
|
placeholder="请选择签约类型"
|
||||||
|
clearable
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in signTypeOptions"
|
v-for="item in signTypeOptions"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
@@ -21,8 +35,14 @@
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="合同编号">
|
<el-form-item label="合同编号" prop="contractNo">
|
||||||
<el-input v-model="form.contractNo" disabled />
|
<el-input
|
||||||
|
v-model="form.contractNo"
|
||||||
|
maxlength="100"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入合同编号"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="合同名称" prop="contractName">
|
<el-form-item label="合同名称" prop="contractName">
|
||||||
<el-input
|
<el-input
|
||||||
@@ -30,6 +50,7 @@
|
|||||||
maxlength="100"
|
maxlength="100"
|
||||||
show-word-limit
|
show-word-limit
|
||||||
placeholder="请输入合同名称"
|
placeholder="请输入合同名称"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="合同类型">
|
<el-form-item label="合同类型">
|
||||||
@@ -80,6 +101,7 @@
|
|||||||
format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
||||||
value-format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
/>
|
/>
|
||||||
<span>至</span>
|
<span>至</span>
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
@@ -88,6 +110,7 @@
|
|||||||
format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
||||||
value-format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -95,6 +118,7 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-model="form.paymentDays"
|
v-model="form.paymentDays"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
@input="value => positiveIntegerInput('paymentDays', value)"
|
@input="value => positiveIntegerInput('paymentDays', value)"
|
||||||
>
|
>
|
||||||
<template #suffix>天</template>
|
<template #suffix>天</template>
|
||||||
@@ -105,22 +129,36 @@
|
|||||||
:model-value="contractAmountDisplay"
|
:model-value="contractAmountDisplay"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
clearable
|
clearable
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
@input="handleContractAmountInput"
|
@input="handleContractAmountInput"
|
||||||
@blur="formatContractAmountField"
|
@blur="formatContractAmountField"
|
||||||
@clear="form.contractAmount = null"
|
@clear="form.contractAmount = null"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="是否范本">
|
<el-form-item label="是否范本">
|
||||||
<el-select v-model="form.templateFlag" placeholder="请选择">
|
<el-select
|
||||||
|
v-model="form.templateFlag"
|
||||||
|
placeholder="请选择"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
>
|
||||||
<el-option label="否" :value="0" />
|
<el-option label="否" :value="0" />
|
||||||
<el-option label="是" :value="1" />
|
<el-option label="是" :value="1" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="原件合同编号">
|
<el-form-item label="原件合同编号">
|
||||||
<el-input v-model="form.originalContractNo" maxlength="100" placeholder="请输入" />
|
<el-input
|
||||||
|
v-model="form.originalContractNo"
|
||||||
|
maxlength="100"
|
||||||
|
placeholder="请输入"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="是否电子章">
|
<el-form-item label="是否电子章">
|
||||||
<el-select v-model="form.electronicSealFlag" placeholder="请选择">
|
<el-select
|
||||||
|
v-model="form.electronicSealFlag"
|
||||||
|
placeholder="请选择"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
>
|
||||||
<el-option label="否" :value="0" />
|
<el-option label="否" :value="0" />
|
||||||
<el-option label="是" :value="1" />
|
<el-option label="是" :value="1" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@@ -129,13 +167,19 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-model="form.invoiceCycle"
|
v-model="form.invoiceCycle"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
@input="value => positiveIntegerInput('invoiceCycle', value)"
|
@input="value => positiveIntegerInput('invoiceCycle', value)"
|
||||||
>
|
>
|
||||||
<template #suffix>天</template>
|
<template #suffix>天</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="结算币种" prop="settlementCurrency">
|
<el-form-item label="结算币种" prop="settlementCurrency">
|
||||||
<el-select v-model="form.settlementCurrency" placeholder="请选择结算币种" clearable>
|
<el-select
|
||||||
|
v-model="form.settlementCurrency"
|
||||||
|
placeholder="请选择结算币种"
|
||||||
|
clearable
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in settlementCurrencyOptions"
|
v-for="item in settlementCurrencyOptions"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
@@ -145,7 +189,12 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="合同格式">
|
<el-form-item label="合同格式">
|
||||||
<el-select v-model="form.contractFormat" placeholder="请选择合同格式" clearable>
|
<el-select
|
||||||
|
v-model="form.contractFormat"
|
||||||
|
placeholder="请选择合同格式"
|
||||||
|
clearable
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in contractFormatOptions"
|
v-for="item in contractFormatOptions"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
@@ -158,19 +207,30 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-model="form.copyCount"
|
v-model="form.copyCount"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
@input="value => positiveIntegerInput('copyCount', value)"
|
@input="value => positiveIntegerInput('copyCount', value)"
|
||||||
>
|
>
|
||||||
<template #suffix>份</template>
|
<template #suffix>份</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="是否需要加盖法人章">
|
<el-form-item label="是否需要加盖法人章">
|
||||||
<el-select v-model="form.legalSealFlag" placeholder="请选择" clearable>
|
<el-select
|
||||||
|
v-model="form.legalSealFlag"
|
||||||
|
placeholder="请选择"
|
||||||
|
clearable
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
>
|
||||||
<el-option label="否" :value="0" />
|
<el-option label="否" :value="0" />
|
||||||
<el-option label="是" :value="1" />
|
<el-option label="是" :value="1" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="结算方式">
|
<el-form-item label="结算方式">
|
||||||
<el-select v-model="form.settlementMode" placeholder="请选择结算方式" clearable>
|
<el-select
|
||||||
|
v-model="form.settlementMode"
|
||||||
|
placeholder="请选择结算方式"
|
||||||
|
clearable
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in settlementModeOptions"
|
v-for="item in settlementModeOptions"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
@@ -191,6 +251,7 @@
|
|||||||
maxlength="1000"
|
maxlength="1000"
|
||||||
show-word-limit
|
show-word-limit
|
||||||
placeholder="请输入合同主要内容"
|
placeholder="请输入合同主要内容"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="其他事项说明" class="contract-basic-section__remark">
|
<el-form-item label="其他事项说明" class="contract-basic-section__remark">
|
||||||
@@ -201,14 +262,21 @@
|
|||||||
maxlength="200"
|
maxlength="200"
|
||||||
show-word-limit
|
show-word-limit
|
||||||
placeholder="请输入其他事项说明"
|
placeholder="请输入其他事项说明"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<!-- 风险客商提示:合同已推送合规并留痕高风险/黑名单时展示,变更提交同样要求特批附件 -->
|
||||||
|
<div v-if="riskTipText" class="contract-manage-form__risk-tip">
|
||||||
|
<div class="contract-manage-form__risk-tip-title">风险客商提示:</div>
|
||||||
|
<div class="contract-manage-form__risk-tip-content">{{ riskTipText }}</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<contract-attachment-section
|
<contract-attachment-section
|
||||||
title="用印材料"
|
title="用印材料"
|
||||||
description
|
description
|
||||||
attachment-type
|
attachment-type
|
||||||
|
:readonly="isSettlementRuleChange"
|
||||||
:attachment-location-options="changeAttachmentLocationOptions"
|
:attachment-location-options="changeAttachmentLocationOptions"
|
||||||
:rows="contractFileRows"
|
:rows="contractFileRows"
|
||||||
:preview="previewAttachment"
|
:preview="previewAttachment"
|
||||||
@@ -217,9 +285,41 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<section class="change-section">
|
<section class="change-section">
|
||||||
<div class="section-head"><div class="dialog-section-title">计费信息</div><el-button type="primary" plain @click="addPlan">添加</el-button></div>
|
<div class="section-head">
|
||||||
<el-radio-group v-model="feeGenerationMode"><el-radio label="system">系统生成</el-radio><el-radio label="manual">账单导入生成</el-radio></el-radio-group>
|
<div class="dialog-section-title">计费信息</div>
|
||||||
<el-table :data="plans" border class="change-table"><el-table-column type="index" label="序号" width="70" /><el-table-column prop="planName" label="方案名称" min-width="220" /><el-table-column label="默认方案" min-width="120"><template #default="{ row }">{{ row.defaultPlan ? '是' : '否' }}</template></el-table-column><el-table-column prop="remark" label="备注" min-width="260" /><el-table-column label="操作" width="180"><template #default="{ row, $index }"><el-link type="primary" @click="editPlan(row, $index)">编辑</el-link><el-link type="danger" @click="plans.splice($index, 1)">删除</el-link></template></el-table-column></el-table>
|
<el-button
|
||||||
|
v-if="!pageReadonly && feeGenerationMode !== 'manual'"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
@click="addPlan"
|
||||||
|
>添加</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<el-radio-group v-model="feeGenerationMode"
|
||||||
|
><el-radio label="system">系统生成</el-radio
|
||||||
|
><el-radio label="manual">账单导入生成</el-radio></el-radio-group
|
||||||
|
>
|
||||||
|
<el-table :data="plans" border class="change-table">
|
||||||
|
<el-table-column type="index" label="序号" width="70" />
|
||||||
|
<el-table-column prop="planName" label="方案名称" min-width="180" />
|
||||||
|
<el-table-column label="适用客商" min-width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.customerName || billingPlanCustomerLabel(row) || '-' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="remark" label="备注" min-width="200" />
|
||||||
|
<el-table-column v-if="!pageReadonly" label="操作" width="180">
|
||||||
|
<template #default="{ row, $index }">
|
||||||
|
<el-link type="primary" @click="editPlan(row, $index)">编辑</el-link>
|
||||||
|
<el-link type="danger" @click="plans.splice($index, 1)">删除</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-else label="操作" width="100">
|
||||||
|
<template #default="{ row, $index }">
|
||||||
|
<el-link type="primary" @click="editPlan(row, $index)">查看</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="change-section">
|
<section class="change-section">
|
||||||
@@ -238,19 +338,106 @@
|
|||||||
<el-radio :label="0">关闭</el-radio>
|
<el-radio :label="0">关闭</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<el-form v-if="settlementRule.autoGenerate === 1" :model="settlementRule" label-position="right" label-width="auto" class="settlement-form">
|
<el-form
|
||||||
<el-form-item label="账单起始日" required><el-date-picker v-model="settlementRule.billStartDate" type="date" placeholder="请选择账单起始日" format="YYYY-MM-DD" value-format="YYYY-MM-DD" /></el-form-item>
|
v-if="settlementRule.autoGenerate === 1"
|
||||||
<el-form-item label="结算类型" required><el-select v-model="settlementRule.settlementType" placeholder="请选择结算类型" @change="handleSettlementTypeChange"><el-option v-for="item in settlementTypeOptions" :key="item" :label="item" :value="item" /></el-select></el-form-item>
|
:model="settlementRule"
|
||||||
<el-form-item v-if="showSettlementBillCycleType" label="结算周期" required><el-select v-model="settlementRule.billCycleType" placeholder="请选择结算周期" @change="handleCycleTypeChange"><el-option v-for="item in billCycleTypeOptions" :key="item" :label="item" :value="item" /></el-select></el-form-item>
|
label-position="right"
|
||||||
<el-form-item v-if="showSettlementBillCutoffDay" label="账单截单日" required><el-select v-model="settlementRule.billCutoffDay" placeholder="请选择账单截单日"><el-option v-for="item in billCutoffDayOptions" :key="item.value" :label="item.label" :value="item.value" /></el-select></el-form-item>
|
label-width="auto"
|
||||||
<el-form-item v-if="showSettlementCycleDays" label="周期天数" required><el-select v-model="settlementRule.cycleDays" placeholder="请选择周期天数"><el-option v-for="item in cycleDayOptions" :key="item.value" :label="item.label" :value="item.value" /></el-select></el-form-item>
|
class="settlement-form"
|
||||||
|
>
|
||||||
|
<el-form-item label="账单起始日" required
|
||||||
|
><el-date-picker
|
||||||
|
v-model="settlementRule.billStartDate"
|
||||||
|
type="date"
|
||||||
|
placeholder="请选择账单起始日"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
/></el-form-item>
|
||||||
|
<el-form-item label="结算类型" required
|
||||||
|
><el-select
|
||||||
|
v-model="settlementRule.settlementType"
|
||||||
|
placeholder="请选择结算类型"
|
||||||
|
@change="handleSettlementTypeChange"
|
||||||
|
><el-option
|
||||||
|
v-for="item in settlementTypeOptions"
|
||||||
|
:key="item"
|
||||||
|
:label="item"
|
||||||
|
:value="item"
|
||||||
|
/></el-select></el-form-item>
|
||||||
|
<el-form-item v-if="showSettlementBillCycleType" label="结算周期" required
|
||||||
|
><el-select
|
||||||
|
v-model="settlementRule.billCycleType"
|
||||||
|
placeholder="请选择结算周期"
|
||||||
|
@change="handleCycleTypeChange"
|
||||||
|
><el-option
|
||||||
|
v-for="item in billCycleTypeOptions"
|
||||||
|
:key="item"
|
||||||
|
:label="item"
|
||||||
|
:value="item"
|
||||||
|
/></el-select></el-form-item>
|
||||||
|
<el-form-item v-if="showSettlementBillCutoffDay" label="账单截单日" required
|
||||||
|
><el-select v-model="settlementRule.billCutoffDay" placeholder="请选择账单截单日"
|
||||||
|
><el-option
|
||||||
|
v-for="item in billCutoffDayOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/></el-select></el-form-item>
|
||||||
|
<el-form-item v-if="showSettlementCycleDays" label="周期天数" required
|
||||||
|
><el-select v-model="settlementRule.cycleDays" placeholder="请选择周期天数"
|
||||||
|
><el-option
|
||||||
|
v-for="item in cycleDayOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/></el-select></el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<el-table v-if="settlementRule.autoGenerate === 1 && showSettlementCustomPeriods" :data="settlementRule.customPeriods || []" border class="change-table custom-periods-table">
|
<el-table
|
||||||
|
v-if="settlementRule.autoGenerate === 1 && showSettlementCustomPeriods"
|
||||||
|
:data="settlementRule.customPeriods || []"
|
||||||
|
border
|
||||||
|
class="change-table custom-periods-table"
|
||||||
|
>
|
||||||
<el-table-column type="index" label="序号" width="70" />
|
<el-table-column type="index" label="序号" width="70" />
|
||||||
<el-table-column label="运单区间-开始日" min-width="180"><template #default="{ row, $index }"><el-select :model-value="row.startDay" placeholder="请选择" clearable @update:model-value="value => handleCustomPeriodStartDayChange($index, value)"><el-option v-for="item in billCutoffDayOptions" :key="`start-${item.value}`" :label="item.label" :value="item.value" /></el-select></template></el-table-column>
|
<el-table-column label="运单区间-开始日" min-width="180"
|
||||||
<el-table-column label="运单区间-结束日" min-width="200"><template #default="{ row, $index }"><el-select :model-value="row.endDay" placeholder="请选择" clearable @update:model-value="value => handleCustomPeriodEndDayChange($index, value)"><el-option v-for="item in customPeriodEndDayOptions(row)" :key="item.value" :label="item.label" :value="item.value" /></el-select></template></el-table-column>
|
><template #default="{ row, $index }"
|
||||||
<el-table-column label="操作" width="100"><template #default="{ $index }"><el-link v-if="$index === 0" type="primary" @click="addCustomPeriodRow">添加</el-link><el-link v-else type="danger" @click="removeCustomPeriodRow($index)">删除</el-link></template></el-table-column>
|
><el-select
|
||||||
<template #empty><el-link type="primary" @click="addCustomPeriodRow">添加</el-link></template>
|
:model-value="row.startDay"
|
||||||
|
placeholder="请选择"
|
||||||
|
clearable
|
||||||
|
@update:model-value="value => handleCustomPeriodStartDayChange($index, value)"
|
||||||
|
><el-option
|
||||||
|
v-for="item in billCutoffDayOptions"
|
||||||
|
:key="`start-${item.value}`"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/></el-select></template
|
||||||
|
></el-table-column>
|
||||||
|
<el-table-column label="运单区间-结束日" min-width="200"
|
||||||
|
><template #default="{ row, $index }"
|
||||||
|
><el-select
|
||||||
|
:model-value="row.endDay"
|
||||||
|
placeholder="请选择"
|
||||||
|
clearable
|
||||||
|
@update:model-value="value => handleCustomPeriodEndDayChange($index, value)"
|
||||||
|
><el-option
|
||||||
|
v-for="item in customPeriodEndDayOptions(row)"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/></el-select></template
|
||||||
|
></el-table-column>
|
||||||
|
<el-table-column v-if="!pageReadonly" label="操作" width="100"
|
||||||
|
><template #default="{ $index }"
|
||||||
|
><el-link v-if="$index === 0" type="primary" @click="addCustomPeriodRow">添加</el-link
|
||||||
|
><el-link v-else type="danger" @click="removeCustomPeriodRow($index)"
|
||||||
|
>删除</el-link
|
||||||
|
></template
|
||||||
|
></el-table-column
|
||||||
|
>
|
||||||
|
<template #empty
|
||||||
|
><el-link v-if="!pageReadonly" type="primary" @click="addCustomPeriodRow">添加</el-link></template
|
||||||
|
>
|
||||||
</el-table>
|
</el-table>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -258,24 +445,57 @@
|
|||||||
<div class="dialog-section-title">
|
<div class="dialog-section-title">
|
||||||
付款比例设置
|
付款比例设置
|
||||||
<el-tooltip content="非必填;配置付款比例时,合计必须等于100%。" placement="top">
|
<el-tooltip content="非必填;配置付款比例时,合计必须等于100%。" placement="top">
|
||||||
<el-icon style="margin-left: 4px; color: #909399; cursor: pointer"><el-icon-question-filled /></el-icon>
|
<el-icon style="margin-left: 4px; color: #909399; cursor: pointer"
|
||||||
|
><el-icon-question-filled
|
||||||
|
/></el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="paymentRatioRows" border class="change-table">
|
<el-table :data="paymentRatioRows" border class="change-table">
|
||||||
<el-table-column type="index" label="序号" width="70" />
|
<el-table-column type="index" label="序号" width="70" />
|
||||||
<el-table-column prop="paymentTerm" label="付款笔数" min-width="180" />
|
<el-table-column prop="paymentTerm" label="付款笔数" min-width="180" />
|
||||||
<el-table-column label="付款比例上限(%)" min-width="220"><template #default="{ row }"><el-input-number v-model="row.ratioLimit" :min="0" :max="100" :precision="2" controls-position="right" /></template></el-table-column>
|
<el-table-column label="付款比例上限(%)" min-width="220"
|
||||||
<el-table-column label="备注" min-width="220"><template #default="{ row }"><el-input v-model="row.remark" maxlength="200" /></template></el-table-column>
|
><template #default="{ row }"
|
||||||
<el-table-column label="操作" width="100"><template #default="{ $index }"><el-link type="danger" @click="paymentRatioRows.splice($index, 1)">删除</el-link></template></el-table-column>
|
><el-input-number
|
||||||
|
v-model="row.ratioLimit"
|
||||||
|
:min="0"
|
||||||
|
:max="100"
|
||||||
|
:precision="2"
|
||||||
|
controls-position="right"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
/></template
|
||||||
|
></el-table-column>
|
||||||
|
<el-table-column label="备注" min-width="220"
|
||||||
|
><template #default="{ row }"
|
||||||
|
><el-input
|
||||||
|
v-model="row.remark"
|
||||||
|
maxlength="200"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
/></template
|
||||||
|
></el-table-column>
|
||||||
|
<el-table-column v-if="!pageReadonly && !isSettlementRuleChange" label="操作" width="100"
|
||||||
|
><template #default="{ $index }"
|
||||||
|
><el-link type="danger" @click="paymentRatioRows.splice($index, 1)"
|
||||||
|
>删除</el-link
|
||||||
|
></template
|
||||||
|
></el-table-column
|
||||||
|
>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-button type="primary" plain @click="addPaymentRatioRow">添加</el-button>
|
<el-button
|
||||||
|
v-if="!pageReadonly && !isSettlementRuleChange"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
@click="addPaymentRatioRow"
|
||||||
|
>添加</el-button
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<billing-plan-editor
|
<billing-plan-editor
|
||||||
v-model="planDialogVisible"
|
v-model="planDialogVisible"
|
||||||
:value="planEditor"
|
:value="planEditor"
|
||||||
:index="planEditorIndex"
|
:index="planEditorIndex"
|
||||||
|
:readonly="pageReadonly"
|
||||||
:settlement-currency="form.settlementCurrency"
|
:settlement-currency="form.settlementCurrency"
|
||||||
|
:party-options="billingPartyOptions"
|
||||||
@save="savePlan"
|
@save="savePlan"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -285,6 +505,7 @@
|
|||||||
attachment-type
|
attachment-type
|
||||||
attachment-location="附件(佐证材料等)"
|
attachment-location="附件(佐证材料等)"
|
||||||
attachment-type-dict-code="contract_supporting_attachment_type"
|
attachment-type-dict-code="contract_supporting_attachment_type"
|
||||||
|
:readonly="isSettlementRuleChange"
|
||||||
:attachment-location-options="changeAttachmentLocationOptions"
|
:attachment-location-options="changeAttachmentLocationOptions"
|
||||||
:rows="attachments"
|
:rows="attachments"
|
||||||
:preview="previewAttachment"
|
:preview="previewAttachment"
|
||||||
@@ -317,8 +538,9 @@
|
|||||||
@update:rows="changeMaterials = $event"
|
@update:rows="changeMaterials = $event"
|
||||||
@upload-to-location="handleAttachmentUploadToLocation"
|
@upload-to-location="handleAttachmentUploadToLocation"
|
||||||
/>
|
/>
|
||||||
<div class="page-footer">
|
<div v-if="!pageReadonly" class="page-footer">
|
||||||
<el-button @click="$router.back()">取消</el-button>
|
<el-button @click="goBack">取消</el-button>
|
||||||
|
<el-button v-if="isContractChangeModule" @click="saveDraft">保存草稿</el-button>
|
||||||
<el-button type="primary" @click="submit">提交</el-button>
|
<el-button type="primary" @click="submit">提交</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -331,8 +553,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as api from '@/api/business/contract-manage';
|
import * as contractApi from '@/api/business/contract-manage';
|
||||||
import { submitMkApprovalFlow } from '@/utils/mk-approval';
|
import * as changeApi from '@/api/business/contract-change';
|
||||||
|
import { getMkPublicDetail } from '@/api/mk-process';
|
||||||
|
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||||
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
||||||
import ContractAttachmentSection, {
|
import ContractAttachmentSection, {
|
||||||
isContractSealMaterialLocation,
|
isContractSealMaterialLocation,
|
||||||
@@ -369,6 +593,8 @@ const defaultContractFormatOptions = [
|
|||||||
{ label: '电子合同', value: '电子合同' },
|
{ label: '电子合同', value: '电子合同' },
|
||||||
{ label: '纸质合同', value: '纸质合同' },
|
{ label: '纸质合同', value: '纸质合同' },
|
||||||
];
|
];
|
||||||
|
const contractChangeListRoute = '/business/contract-change';
|
||||||
|
const contractChangeListRefreshKey = 'contract-change-list-refresh';
|
||||||
const normalizeOptionalPositiveInteger = value => {
|
const normalizeOptionalPositiveInteger = value => {
|
||||||
if (value === undefined || value === null || value === '') return null;
|
if (value === undefined || value === null || value === '') return null;
|
||||||
const number = Number(value);
|
const number = Number(value);
|
||||||
@@ -408,6 +634,45 @@ const normalizeCustomPeriods = (periods = []) =>
|
|||||||
endDay: Number(item?.endDay) > 0 ? Number(item.endDay) : '',
|
endDay: Number(item?.endDay) > 0 ? Number(item.endDay) : '',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const createPartyRow = (row = {}) => ({
|
||||||
|
id: row.id || `${Date.now()}${Math.floor(Math.random() * 1000)}`,
|
||||||
|
customerId: row.customerId || '',
|
||||||
|
customerName: row.customerName || '',
|
||||||
|
creditCode: row.creditCode || row.unifiedCreditCode || '',
|
||||||
|
contactId: row.contactId || '',
|
||||||
|
contactName: row.contactName || '',
|
||||||
|
contactPhone: row.contactPhone || '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const partyRoleLabel = role => {
|
||||||
|
if (role === 'A') return '甲方';
|
||||||
|
if (role === 'B') return '乙方';
|
||||||
|
if (role === 'C') return '丙方';
|
||||||
|
return role || '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizePartyRows = (partyJson, fallbackName, requireOne) => {
|
||||||
|
const rows = (() => {
|
||||||
|
if (Array.isArray(partyJson)) return partyJson;
|
||||||
|
if (!partyJson) return [];
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(partyJson);
|
||||||
|
return Array.isArray(data) ? data : [];
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
})().map(item => createPartyRow(item));
|
||||||
|
if (rows.length) return rows;
|
||||||
|
if (fallbackName) {
|
||||||
|
return String(fallbackName)
|
||||||
|
.split(/[、,]/)
|
||||||
|
.map(name => name.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(name => createPartyRow({ customerName: name }));
|
||||||
|
}
|
||||||
|
return requireOne ? [createPartyRow()] : [];
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { BillingPlanEditor, ContractAttachmentSection, ElImageViewer, OpenFileViewer },
|
components: { BillingPlanEditor, ContractAttachmentSection, ElImageViewer, OpenFileViewer },
|
||||||
data() {
|
data() {
|
||||||
@@ -415,6 +680,9 @@ export default {
|
|||||||
form: {},
|
form: {},
|
||||||
period: [],
|
period: [],
|
||||||
plans: [],
|
plans: [],
|
||||||
|
partyARows: [],
|
||||||
|
partyBRows: [],
|
||||||
|
partyCRows: [],
|
||||||
attachments: [],
|
attachments: [],
|
||||||
contractFiles: [],
|
contractFiles: [],
|
||||||
contractFileRows: [],
|
contractFileRows: [],
|
||||||
@@ -440,7 +708,7 @@ export default {
|
|||||||
},
|
},
|
||||||
preSettlementConfig: {},
|
preSettlementConfig: {},
|
||||||
formalSettlementConfig: {},
|
formalSettlementConfig: {},
|
||||||
settlementTypeOptions: ['月结', '日结', '周结', '半月结', '固定天数周期结算'],
|
settlementTypeOptions: ['月结', '日结', '周结', '固定天数周期结算'],
|
||||||
billCycleTypeOptions: ['固定截单日', '自然月', '自定义多周期'],
|
billCycleTypeOptions: ['固定截单日', '自然月', '自定义多周期'],
|
||||||
billCutoffDayOptions: Array.from({ length: 31 }, (_, index) => ({
|
billCutoffDayOptions: Array.from({ length: 31 }, (_, index) => ({
|
||||||
label: `${index + 1}日`,
|
label: `${index + 1}日`,
|
||||||
@@ -453,7 +721,7 @@ export default {
|
|||||||
settlementModeDictOptions: [],
|
settlementModeDictOptions: [],
|
||||||
contractFormatDictOptions: [],
|
contractFormatDictOptions: [],
|
||||||
planDialogVisible: false,
|
planDialogVisible: false,
|
||||||
planEditor: { planName: '', defaultPlan: false, remark: '', rules: [] },
|
planEditor: { planName: '', remark: '', rules: [] },
|
||||||
planEditorIndex: -1,
|
planEditorIndex: -1,
|
||||||
billingElements: [
|
billingElements: [
|
||||||
'按重量',
|
'按重量',
|
||||||
@@ -465,6 +733,24 @@ export default {
|
|||||||
'按数量',
|
'按数量',
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
|
contractNo: [
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (this.isSettlementRuleChange) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
const contractNo = String(value || '').trim();
|
||||||
|
if (!contractNo) {
|
||||||
|
return callback(new Error('请输入合同编号'));
|
||||||
|
}
|
||||||
|
if (contractNo.length > 100) {
|
||||||
|
return callback(new Error('合同编号不能超过100个字符'));
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
],
|
||||||
contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
|
contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
|
||||||
contractAmount: [
|
contractAmount: [
|
||||||
{ required: true, message: '请输入合同金额', trigger: 'blur' },
|
{ required: true, message: '请输入合同金额', trigger: 'blur' },
|
||||||
@@ -487,9 +773,62 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
pageTitle() {
|
pageTitle() {
|
||||||
|
if (this.pageReadonly) return this.$route.query.name || '查看合同变更';
|
||||||
return this.$route.query.name || '合同变更';
|
return this.$route.query.name || '合同变更';
|
||||||
},
|
},
|
||||||
|
isContractChangeModule() {
|
||||||
|
return (
|
||||||
|
this.$route.path === '/business/contract-change/form' ||
|
||||||
|
this.$route.path === '/business/contract-change/public-view'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
isPublicViewPage() {
|
||||||
|
return this.$route.path === '/business/contract-change/public-view';
|
||||||
|
},
|
||||||
|
pageReadonly() {
|
||||||
|
return this.isPublicViewPage || this.$route.query.mode === 'view';
|
||||||
|
},
|
||||||
|
// 高风险/黑名单客商提示:按合同推送合规留痕 hcs_risk_level/hcs_black_status 判定(与合同详情口径一致)
|
||||||
|
riskTipText() {
|
||||||
|
const riskLevel = String(this.form.hcsRiskLevel || '').trim();
|
||||||
|
const blacklist = String(this.form.kingdeeBlackStatus || '').toLowerCase() === 'yes';
|
||||||
|
if (riskLevel !== '2' && !blacklist) return '';
|
||||||
|
const parties = [this.form.partyA, this.form.partyB]
|
||||||
|
.map(name => String(name || '').trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('、');
|
||||||
|
return `【${parties || '相对方'}】:被列入外部黑名单;涉贪污受贿裁判相关提及方(3年以上及其他);被执行人信息;买卖合同纠纷;劳动纠纷;重大纠纷。提交变更前须上传「特批附件」类型附件`;
|
||||||
|
},
|
||||||
|
isSettlementRuleChange() {
|
||||||
|
return this.form.changeType === '结算规则变更';
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 计费方案适用客商:客户合同仅甲方;承运商合同仅乙方、丙方
|
||||||
|
*/
|
||||||
|
billingPartyOptions() {
|
||||||
|
const category = String(this.form.contractCategory || '').trim();
|
||||||
|
const allowedRoles =
|
||||||
|
category === '承运商合同' ? ['B', 'C'] : category === '客户合同' ? ['A'] : ['A', 'B', 'C'];
|
||||||
|
return [
|
||||||
|
...this.partyARows.map(row => ({ ...row, partyRole: 'A' })),
|
||||||
|
...this.partyBRows.map(row => ({ ...row, partyRole: 'B' })),
|
||||||
|
...this.partyCRows.map(row => ({ ...row, partyRole: 'C' })),
|
||||||
|
]
|
||||||
|
.filter(row => allowedRoles.includes(row.partyRole))
|
||||||
|
.filter(row => row.customerName || row.customerId)
|
||||||
|
.map(row => ({
|
||||||
|
value: row.id,
|
||||||
|
label: `${partyRoleLabel(row.partyRole)}-${row.customerName || row.customerId}`,
|
||||||
|
partyRole: row.partyRole,
|
||||||
|
partyRowId: row.id,
|
||||||
|
customerId: row.customerId,
|
||||||
|
customerName: row.customerName,
|
||||||
|
}));
|
||||||
|
},
|
||||||
changeAttachmentLocationOptions() {
|
changeAttachmentLocationOptions() {
|
||||||
|
if (this.isSettlementRuleChange) {
|
||||||
|
return ['变更材料'];
|
||||||
|
}
|
||||||
return ['用印材料', '附件(佐证材料等)', '变更材料'];
|
return ['用印材料', '附件(佐证材料等)', '变更材料'];
|
||||||
},
|
},
|
||||||
contractAmountDisplay() {
|
contractAmountDisplay() {
|
||||||
@@ -590,13 +929,25 @@ export default {
|
|||||||
async load() {
|
async load() {
|
||||||
const id = this.$route.query.id;
|
const id = this.$route.query.id;
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
const res = await api.getDetail(id);
|
let data = {};
|
||||||
const data = res.data?.data || res.data || {};
|
if (this.isPublicViewPage) {
|
||||||
|
const res = await getMkPublicDetail('contract-change', id);
|
||||||
|
data = res.data?.data || res.data || {};
|
||||||
|
} else if (this.isContractChangeModule) {
|
||||||
|
const res = await changeApi.getDetail(id);
|
||||||
|
data = res.data?.data || res.data || {};
|
||||||
|
} else {
|
||||||
|
const res = await contractApi.getDetail(id);
|
||||||
|
data = res.data?.data || res.data || {};
|
||||||
|
}
|
||||||
|
const isChangeRecord = this.isContractChangeModule || this.isPublicViewPage;
|
||||||
this.form = {
|
this.form = {
|
||||||
...data,
|
...data,
|
||||||
changeContent: '',
|
// 独立变更单保留 contractId;旧路由以合同 id 作为主键
|
||||||
changeReason: '',
|
contractId: data.contractId || (isChangeRecord ? data.contractId : data.id),
|
||||||
changeAttachmentsJson: '',
|
changeContent: isChangeRecord ? data.changeContent || '' : '',
|
||||||
|
changeReason: isChangeRecord ? data.changeReason || '' : '',
|
||||||
|
changeAttachmentsJson: data.changeAttachmentsJson || '',
|
||||||
copyCount: normalizeOptionalPositiveInteger(data.copyCount),
|
copyCount: normalizeOptionalPositiveInteger(data.copyCount),
|
||||||
invoiceCycle: normalizeOptionalPositiveInteger(data.invoiceCycle),
|
invoiceCycle: normalizeOptionalPositiveInteger(data.invoiceCycle),
|
||||||
paymentDays: normalizeOptionalPositiveInteger(data.paymentDays),
|
paymentDays: normalizeOptionalPositiveInteger(data.paymentDays),
|
||||||
@@ -604,14 +955,17 @@ export default {
|
|||||||
templateFlag: data.templateFlag ?? 0,
|
templateFlag: data.templateFlag ?? 0,
|
||||||
electronicSealFlag: data.electronicSealFlag ?? 0,
|
electronicSealFlag: data.electronicSealFlag ?? 0,
|
||||||
archiveStatus: data.archiveStatus || '未归档',
|
archiveStatus: data.archiveStatus || '未归档',
|
||||||
changeType: '合同信息变更',
|
changeType: data.changeType || '合同信息变更',
|
||||||
};
|
};
|
||||||
this.changeMaterials = [];
|
this.changeMaterials = this.parse(data.changeAttachmentsJson);
|
||||||
this.period = data.startDate && data.endDate ? [data.startDate, data.endDate] : [];
|
this.period = data.startDate && data.endDate ? [data.startDate, data.endDate] : [];
|
||||||
|
this.partyARows = normalizePartyRows(data.partyAJson, data.partyA, true);
|
||||||
|
this.partyBRows = normalizePartyRows(data.partyBJson, data.partyB, true);
|
||||||
|
this.partyCRows = normalizePartyRows(data.partyCJson, data.partyC, false);
|
||||||
this.plans = this.parse(data.billingPlanJson);
|
this.plans = this.parse(data.billingPlanJson);
|
||||||
this.attachments = this.mergeChangeAttachments(
|
this.attachments = this.mergeChangeAttachments(
|
||||||
this.parse(data.attachmentsJson),
|
this.parse(data.attachmentsJson),
|
||||||
this.parse(data.changeAttachmentsJson)
|
isChangeRecord ? [] : this.parse(data.changeAttachmentsJson)
|
||||||
);
|
);
|
||||||
this.contractFileRows = normalizeContractFileRows(this.parse(data.contractFileJson));
|
this.contractFileRows = normalizeContractFileRows(this.parse(data.contractFileJson));
|
||||||
const rules = this.parseObject(data.settlementRuleJson);
|
const rules = this.parseObject(data.settlementRuleJson);
|
||||||
@@ -653,6 +1007,70 @@ export default {
|
|||||||
data.feeGenerationMode || (Number(data.billingEnabled) === 0 ? 'manual' : 'system');
|
data.feeGenerationMode || (Number(data.billingEnabled) === 0 ? 'manual' : 'system');
|
||||||
this.paymentRatioRows = this.parse(data.paymentRatioJson);
|
this.paymentRatioRows = this.parse(data.paymentRatioJson);
|
||||||
},
|
},
|
||||||
|
goBack() {
|
||||||
|
if (this.isContractChangeModule) {
|
||||||
|
this.$router.push(contractChangeListRoute);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$router.back();
|
||||||
|
},
|
||||||
|
buildChangePayload() {
|
||||||
|
if (this.settlementConfigTab === 'pre') this.preSettlementConfig = { ...this.settlementRule };
|
||||||
|
else this.formalSettlementConfig = { ...this.settlementRule };
|
||||||
|
const settlementRule = {
|
||||||
|
preSettlementConfig: this.preSettlementConfig,
|
||||||
|
formalSettlementConfig: this.formalSettlementConfig,
|
||||||
|
};
|
||||||
|
if (this.isSettlementRuleChange) {
|
||||||
|
return {
|
||||||
|
id: this.form.id,
|
||||||
|
contractId: this.form.contractId,
|
||||||
|
changeType: this.form.changeType,
|
||||||
|
changeContent: this.form.changeContent,
|
||||||
|
changeReason: this.form.changeReason,
|
||||||
|
feeGenerationMode: this.feeGenerationMode,
|
||||||
|
billingEnabled: this.feeGenerationMode === 'system' ? 1 : 0,
|
||||||
|
billingPlanJson: JSON.stringify(this.plans),
|
||||||
|
settlementRuleJson: JSON.stringify(settlementRule),
|
||||||
|
preSettlementConfigJson: JSON.stringify(this.preSettlementConfig),
|
||||||
|
formalSettlementConfigJson: JSON.stringify(this.formalSettlementConfig),
|
||||||
|
changeAttachmentsJson: JSON.stringify(this.changeMaterials),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...this.form,
|
||||||
|
contractId: this.form.contractId,
|
||||||
|
changeType: this.form.changeType || '合同信息变更',
|
||||||
|
settlementCurrency: String(this.form.settlementCurrency || '').trim() || 'RMB',
|
||||||
|
copyCount: normalizeOptionalPositiveInteger(this.form.copyCount),
|
||||||
|
invoiceCycle: normalizeOptionalPositiveInteger(this.form.invoiceCycle),
|
||||||
|
paymentDays: normalizeOptionalPositiveInteger(this.form.paymentDays),
|
||||||
|
contractAmount: normalizeOptionalAmount(this.form.contractAmount),
|
||||||
|
startDate: this.period[0],
|
||||||
|
endDate: this.period[1],
|
||||||
|
feeGenerationMode: this.feeGenerationMode,
|
||||||
|
billingEnabled: this.feeGenerationMode === 'system' ? 1 : 0,
|
||||||
|
billingPlanJson: JSON.stringify(this.plans),
|
||||||
|
settlementRuleJson: JSON.stringify(settlementRule),
|
||||||
|
preSettlementConfigJson: JSON.stringify(this.preSettlementConfig),
|
||||||
|
formalSettlementConfigJson: JSON.stringify(this.formalSettlementConfig),
|
||||||
|
paymentRatioJson: JSON.stringify(this.paymentRatioRows),
|
||||||
|
contractFileJson: JSON.stringify(this.contractFileRows),
|
||||||
|
attachmentsJson: JSON.stringify(this.attachments),
|
||||||
|
changeContent: this.form.changeContent,
|
||||||
|
changeReason: this.form.changeReason,
|
||||||
|
changeAttachmentsJson: JSON.stringify(this.changeMaterials),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async saveDraft() {
|
||||||
|
if (this.form.changeType === '终止合同') {
|
||||||
|
this.$message.warning('终止合同无需保存草稿,请直接提交');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const payload = this.buildChangePayload();
|
||||||
|
await changeApi.saveDraft(payload);
|
||||||
|
this.$message.success('草稿已保存');
|
||||||
|
},
|
||||||
parse(value) {
|
parse(value) {
|
||||||
try {
|
try {
|
||||||
const result = JSON.parse(value || '[]');
|
const result = JSON.parse(value || '[]');
|
||||||
@@ -702,10 +1120,32 @@ export default {
|
|||||||
.replace(/\D/g, '')
|
.replace(/\D/g, '')
|
||||||
.replace(/^0+/, '');
|
.replace(/^0+/, '');
|
||||||
},
|
},
|
||||||
addPlan() { this.planEditorIndex = -1; this.planEditor = { planName: `计费方案${this.plans.length + 1}`, defaultPlan: !this.plans.length, remark: '', rules: [{}] }; this.planDialogVisible = true; },
|
addPlan() {
|
||||||
editPlan(row, index) { this.planEditorIndex = index; this.planEditor = JSON.parse(JSON.stringify(row)); this.planDialogVisible = true; },
|
this.planEditorIndex = -1;
|
||||||
toggleDefaultPlan(value) { if (value) this.plans.forEach(item => { item.defaultPlan = false; }); },
|
this.planEditor = {
|
||||||
savePlan(value, index) { if (index < 0) this.plans.push(value); else this.plans.splice(index, 1, value); if (value.defaultPlan) this.plans.forEach((item, current) => { if (current !== (index < 0 ? this.plans.length - 1 : index)) item.defaultPlan = false; }); },
|
planName: `计费方案${this.plans.length + 1}`,
|
||||||
|
remark: '',
|
||||||
|
rules: [{}],
|
||||||
|
};
|
||||||
|
this.planDialogVisible = true;
|
||||||
|
},
|
||||||
|
editPlan(row, index) {
|
||||||
|
this.planEditorIndex = index;
|
||||||
|
this.planEditor = JSON.parse(JSON.stringify(row));
|
||||||
|
this.planDialogVisible = true;
|
||||||
|
},
|
||||||
|
billingPlanCustomerLabel(row) {
|
||||||
|
const matched = this.billingPartyOptions.find(
|
||||||
|
item => String(item.partyRowId) === String(row.partyRowId)
|
||||||
|
);
|
||||||
|
return matched?.label || row.customerName || '';
|
||||||
|
},
|
||||||
|
savePlan(value, index) {
|
||||||
|
const nextPlan = { ...value };
|
||||||
|
delete nextPlan.defaultPlan;
|
||||||
|
if (index < 0) this.plans.push(nextPlan);
|
||||||
|
else this.plans.splice(index, 1, nextPlan);
|
||||||
|
},
|
||||||
handleSettlementTypeChange(value) { if (value !== '月结') { this.settlementRule.billCycleType = ''; this.settlementRule.billCutoffDay = ''; this.settlementRule.customPeriods = []; } else if (this.settlementRule.billCycleType === '自定义多周期') this.settlementRule.customPeriods = normalizeCustomPeriods(this.settlementRule.customPeriods || []); else this.settlementRule.customPeriods = []; if (value !== '固定天数周期结算') this.settlementRule.cycleDays = ''; },
|
handleSettlementTypeChange(value) { if (value !== '月结') { this.settlementRule.billCycleType = ''; this.settlementRule.billCutoffDay = ''; this.settlementRule.customPeriods = []; } else if (this.settlementRule.billCycleType === '自定义多周期') this.settlementRule.customPeriods = normalizeCustomPeriods(this.settlementRule.customPeriods || []); else this.settlementRule.customPeriods = []; if (value !== '固定天数周期结算') this.settlementRule.cycleDays = ''; },
|
||||||
handleCycleTypeChange(value) { if (value !== '固定截单日') this.settlementRule.billCutoffDay = ''; if (value === '自定义多周期') this.settlementRule.customPeriods = normalizeCustomPeriods(this.settlementRule.customPeriods || []); else this.settlementRule.customPeriods = []; },
|
handleCycleTypeChange(value) { if (value !== '固定截单日') this.settlementRule.billCutoffDay = ''; if (value === '自定义多周期') this.settlementRule.customPeriods = normalizeCustomPeriods(this.settlementRule.customPeriods || []); else this.settlementRule.customPeriods = []; },
|
||||||
attachmentUrl(row = {}) { return row.url || row.link || row.fileUrl || row.downloadUrl || row.domain || ''; },
|
attachmentUrl(row = {}) { return row.url || row.link || row.fileUrl || row.downloadUrl || row.domain || ''; },
|
||||||
@@ -715,6 +1155,12 @@ export default {
|
|||||||
previewAttachment(row, rows = this.attachments) { const url = this.attachmentUrl(row); if (!url) { this.$message.warning('附件地址为空,无法预览'); return; } if (this.isAttachmentImage(row)) { this.imagePreviewUrls = (rows || []).filter(item => this.isAttachmentImage(item) && this.attachmentUrl(item)).map(item => this.attachmentUrl(item)); this.imagePreviewIndex = Math.max(this.imagePreviewUrls.indexOf(url), 0); this.imagePreviewVisible = true; return; } this.previewFile = { name: this.attachmentName(row), url, mimeType: row.mimeType || row.contentType || '' }; this.documentPreviewVisible = true; },
|
previewAttachment(row, rows = this.attachments) { const url = this.attachmentUrl(row); if (!url) { this.$message.warning('附件地址为空,无法预览'); return; } if (this.isAttachmentImage(row)) { this.imagePreviewUrls = (rows || []).filter(item => this.isAttachmentImage(item) && this.attachmentUrl(item)).map(item => this.attachmentUrl(item)); this.imagePreviewIndex = Math.max(this.imagePreviewUrls.indexOf(url), 0); this.imagePreviewVisible = true; return; } this.previewFile = { name: this.attachmentName(row), url, mimeType: row.mimeType || row.contentType || '' }; this.documentPreviewVisible = true; },
|
||||||
handleAttachmentUploadToLocation({ location, rows = [] }) {
|
handleAttachmentUploadToLocation({ location, rows = [] }) {
|
||||||
if (!rows.length) return;
|
if (!rows.length) return;
|
||||||
|
if (this.isSettlementRuleChange) {
|
||||||
|
if (location === '变更材料') {
|
||||||
|
this.changeMaterials = [...(this.changeMaterials || []), ...rows];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isContractSealMaterialLocation(location)) {
|
if (isContractSealMaterialLocation(location)) {
|
||||||
this.contractFileRows = [...(this.contractFileRows || []), ...rows];
|
this.contractFileRows = [...(this.contractFileRows || []), ...rows];
|
||||||
return;
|
return;
|
||||||
@@ -738,7 +1184,66 @@ export default {
|
|||||||
removeCustomPeriodRow(index) { if (index <= 0) return; const periods = [...(this.settlementRule.customPeriods || [])]; periods.splice(index, 1); this.settlementRule.customPeriods = normalizeCustomPeriods(periods); },
|
removeCustomPeriodRow(index) { if (index <= 0) return; const periods = [...(this.settlementRule.customPeriods || [])]; periods.splice(index, 1); this.settlementRule.customPeriods = normalizeCustomPeriods(periods); },
|
||||||
validateCustomPeriods(periods = [], label) { const rows = normalizeCustomPeriods(periods); if (!rows.length) { this.$message.warning(`${label}:请至少配置一段自定义周期`); return false; } for (let index = 0; index < rows.length; index += 1) { const row = rows[index]; const startDay = Number(row.startDay); const endDay = Number(row.endDay); if (!Number.isFinite(startDay) || startDay < 1 || startDay > 31) { this.$message.warning(`${label}:请选择第${index + 1}行运单区间开始日`); return false; } if (!Number.isFinite(endDay) || endDay < 1 || endDay > 31) { this.$message.warning(`${label}:请选择第${index + 1}行运单区间结束日`); return false; } if (endDay < startDay) { this.$message.warning(`${label}:第${index + 1}行结束日不能早于开始日`); return false; } if (index > 0 && startDay !== Number(rows[index - 1].endDay) + 1) { this.$message.warning(`${label}:自定义多周期区间必须连续,不允许重叠或存在日期缺口`); return false; } } return true; },
|
validateCustomPeriods(periods = [], label) { const rows = normalizeCustomPeriods(periods); if (!rows.length) { this.$message.warning(`${label}:请至少配置一段自定义周期`); return false; } for (let index = 0; index < rows.length; index += 1) { const row = rows[index]; const startDay = Number(row.startDay); const endDay = Number(row.endDay); if (!Number.isFinite(startDay) || startDay < 1 || startDay > 31) { this.$message.warning(`${label}:请选择第${index + 1}行运单区间开始日`); return false; } if (!Number.isFinite(endDay) || endDay < 1 || endDay > 31) { this.$message.warning(`${label}:请选择第${index + 1}行运单区间结束日`); return false; } if (endDay < startDay) { this.$message.warning(`${label}:第${index + 1}行结束日不能早于开始日`); return false; } if (index > 0 && startDay !== Number(rows[index - 1].endDay) + 1) { this.$message.warning(`${label}:自定义多周期区间必须连续,不允许重叠或存在日期缺口`); return false; } } return true; },
|
||||||
validateSettlementRule(rule, label) { if (Number(rule.autoGenerate) !== 1) return true; if (!rule.billStartDate || !rule.settlementType) { this.$message.warning(`${label}:请完整填写账单起始日和结算类型`); return false; } if (rule.settlementType === '月结' && !rule.billCycleType) { this.$message.warning(`${label}:请选择结算周期`); return false; } if (rule.settlementType === '月结' && rule.billCycleType === '固定截单日' && !rule.billCutoffDay) { this.$message.warning(`${label}:请选择账单截单日`); return false; } if (rule.settlementType === '月结' && rule.billCycleType === '自定义多周期') return this.validateCustomPeriods(rule.customPeriods, label); if (rule.settlementType === '固定天数周期结算' && !rule.cycleDays) { this.$message.warning(`${label}:请选择周期天数`); return false; } return true; },
|
validateSettlementRule(rule, label) { if (Number(rule.autoGenerate) !== 1) return true; if (!rule.billStartDate || !rule.settlementType) { this.$message.warning(`${label}:请完整填写账单起始日和结算类型`); return false; } if (rule.settlementType === '月结' && !rule.billCycleType) { this.$message.warning(`${label}:请选择结算周期`); return false; } if (rule.settlementType === '月结' && rule.billCycleType === '固定截单日' && !rule.billCutoffDay) { this.$message.warning(`${label}:请选择账单截单日`); return false; } if (rule.settlementType === '月结' && rule.billCycleType === '自定义多周期') return this.validateCustomPeriods(rule.customPeriods, label); if (rule.settlementType === '固定天数周期结算' && !rule.cycleDays) { this.$message.warning(`${label}:请选择周期天数`); return false; } return true; },
|
||||||
async submit() { await this.$refs.formRef.validate(); const total = this.paymentRatioRows.reduce((sum, row) => sum + Number(row.ratioLimit || 0), 0); if (this.paymentRatioRows.length && Math.abs(total - 100) > 0.0001) { this.$message.warning('付款比例上限合计必须等于100%'); return; } if (this.settlementConfigTab === 'pre') this.preSettlementConfig = { ...this.settlementRule }; else this.formalSettlementConfig = { ...this.settlementRule }; if (!this.validateSettlementRule(this.preSettlementConfig, '预结算配置') || !this.validateSettlementRule(this.formalSettlementConfig, '正式结算配置')) return; const settlementRule = { preSettlementConfig: this.preSettlementConfig, formalSettlementConfig: this.formalSettlementConfig }; await api.submitChange({ ...this.form, settlementCurrency: String(this.form.settlementCurrency || '').trim() || 'RMB', copyCount: normalizeOptionalPositiveInteger(this.form.copyCount), invoiceCycle: normalizeOptionalPositiveInteger(this.form.invoiceCycle), paymentDays: normalizeOptionalPositiveInteger(this.form.paymentDays), contractAmount: normalizeOptionalAmount(this.form.contractAmount), startDate: this.period[0], endDate: this.period[1], feeGenerationMode: this.feeGenerationMode, billingEnabled: this.feeGenerationMode === 'system' ? 1 : 0, billingPlanJson: JSON.stringify(this.plans), settlementRuleJson: JSON.stringify(settlementRule), preSettlementConfigJson: JSON.stringify(this.preSettlementConfig), formalSettlementConfigJson: JSON.stringify(this.formalSettlementConfig), paymentRatioJson: JSON.stringify(this.paymentRatioRows), contractFileJson: JSON.stringify(this.contractFileRows), attachmentsJson: JSON.stringify(this.attachments), changeContent: this.form.changeContent, changeReason: this.form.changeReason, changeAttachmentsJson: JSON.stringify(this.changeMaterials) }); await submitMkApprovalFlow({ bizType: 'contract-manage', bizId: this.form.id, subjectName: this.form.contractName || '', approvalStatus: this.form.approvalStatus || 'change_rejected' }); this.$message.success('变更已提交'); this.$router.back(); },
|
async submit() {
|
||||||
|
if (this.form.changeType === '终止合同') {
|
||||||
|
const contractId = this.form.contractId || this.form.id;
|
||||||
|
await contractApi.terminate(contractId, this.form.changeReason);
|
||||||
|
this.$message.success('合同已终止');
|
||||||
|
this.goBack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.$refs.formRef.validate();
|
||||||
|
if (!this.isSettlementRuleChange) {
|
||||||
|
const contractNo = String(this.form.contractNo || '').trim();
|
||||||
|
if (!contractNo) {
|
||||||
|
this.$message.warning('请输入合同编号');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (contractNo.length > 100) {
|
||||||
|
this.$message.warning('合同编号不能超过100个字符');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.form.contractNo = contractNo;
|
||||||
|
const total = this.paymentRatioRows.reduce((sum, row) => sum + Number(row.ratioLimit || 0), 0);
|
||||||
|
if (this.paymentRatioRows.length && Math.abs(total - 100) > 0.0001) {
|
||||||
|
this.$message.warning('付款比例上限合计必须等于100%');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.settlementConfigTab === 'pre') this.preSettlementConfig = { ...this.settlementRule };
|
||||||
|
else this.formalSettlementConfig = { ...this.settlementRule };
|
||||||
|
if (
|
||||||
|
!this.validateSettlementRule(this.preSettlementConfig, '预结算配置') ||
|
||||||
|
!this.validateSettlementRule(this.formalSettlementConfig, '正式结算配置')
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const payload = this.buildChangePayload();
|
||||||
|
if (this.isContractChangeModule) {
|
||||||
|
await changeApi.submit(payload);
|
||||||
|
await submitMkApprovalFlow({
|
||||||
|
bizType: 'contract-change',
|
||||||
|
bizId: this.form.id,
|
||||||
|
subjectName: this.form.contractName || '',
|
||||||
|
approvalStatus: this.form.approvalStatus || '',
|
||||||
|
mkEnabled: await loadMkEnabled().catch(() => false),
|
||||||
|
});
|
||||||
|
sessionStorage.setItem(contractChangeListRefreshKey, '1');
|
||||||
|
this.$message.success('变更已提交');
|
||||||
|
this.$router.push(contractChangeListRoute);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await contractApi.submitChange(payload);
|
||||||
|
await submitMkApprovalFlow({
|
||||||
|
bizType: 'contract-manage',
|
||||||
|
bizId: this.form.id,
|
||||||
|
subjectName: this.form.contractName || '',
|
||||||
|
approvalStatus: this.form.approvalStatus || 'change_rejected',
|
||||||
|
mkEnabled: await loadMkEnabled().catch(() => false),
|
||||||
|
});
|
||||||
|
this.$message.success('变更已提交');
|
||||||
|
this.$router.back();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -762,6 +1267,10 @@ export default {
|
|||||||
}
|
}
|
||||||
.contract-basic-section__date-range { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 8px; width: 360px; max-width: 100%; }
|
.contract-basic-section__date-range { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 8px; width: 360px; max-width: 100%; }
|
||||||
.contract-basic-section__date-range span { color: #606266; }
|
.contract-basic-section__date-range span { color: #606266; }
|
||||||
|
// 风险客商提示条(基本信息备注后):橙黄背景 + 红色文字,与合同新增页一致
|
||||||
|
.contract-manage-form__risk-tip { margin: 0 0 18px; padding: 10px 16px; background: #faecd8; border-radius: 4px; }
|
||||||
|
.contract-manage-form__risk-tip-title { color: #f56c6c; font-weight: 600; line-height: 22px; }
|
||||||
|
.contract-manage-form__risk-tip-content { color: #f56c6c; line-height: 22px; }
|
||||||
.contract-basic-section__date-range :deep(.el-date-editor) { width: auto; min-width: 0; }
|
.contract-basic-section__date-range :deep(.el-date-editor) { width: auto; min-width: 0; }
|
||||||
.contract-basic-section :deep(.el-form-item) { align-items: center; }
|
.contract-basic-section :deep(.el-form-item) { align-items: center; }
|
||||||
.contract-basic-section :deep(.el-form-item__label) { flex: 0 0 96px !important; width: 96px !important; height: auto; padding-right: 12px; white-space: normal; word-break: break-all; line-height: 18px; }
|
.contract-basic-section :deep(.el-form-item__label) { flex: 0 0 96px !important; width: 96px !important; height: auto; padding-right: 12px; white-space: normal; word-break: break-all; line-height: 18px; }
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<basic-container class="hcs-master-data-page">
|
||||||
|
<div class="hcs-master-data-page__head">
|
||||||
|
<div class="dialog-section-title">合规主数据(HCS)</div>
|
||||||
|
<el-button type="primary" :loading="refreshing" @click="handleRefresh">刷新缓存</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-tabs v-model="activeTab">
|
||||||
|
<el-tab-pane label="合同模板" name="template" />
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="templates" border>
|
||||||
|
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||||
|
<el-table-column prop="fdId" label="模板ID(fdTemplateId)" min-width="320" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="fdName" label="模板名称" min-width="220" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="fdStatus" label="状态" width="100" align="center" />
|
||||||
|
<el-table-column prop="fdContractCharacter" label="合同性质" min-width="140" align="center" />
|
||||||
|
<el-table-column label="创建时间" min-width="170" align="center">
|
||||||
|
<template #default="{ row }">{{ formatTime(row.fdCreateTime) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-alert
|
||||||
|
class="hcs-master-data-page__tip"
|
||||||
|
title="合同类别与合规模板的对应关系由 Nacos 配置 thirdParty.hcs.contract.template-mapping 维护;此列表用于核对映射的模板ID 是否存在。"
|
||||||
|
type="info"
|
||||||
|
:closable="false"
|
||||||
|
/>
|
||||||
|
</basic-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getTemplates, refreshMasterData } from '@/api/business/hcs';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HcsMasterData',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeTab: 'template',
|
||||||
|
loading: false,
|
||||||
|
refreshing: false,
|
||||||
|
templates: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadTemplates();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadTemplates() {
|
||||||
|
this.loading = true;
|
||||||
|
getTemplates()
|
||||||
|
.then(response => {
|
||||||
|
const data = response?.data?.data ?? response?.data;
|
||||||
|
this.templates = Array.isArray(data) ? data : [];
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.$message.error('合规模板列表加载失败');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleRefresh() {
|
||||||
|
this.refreshing = true;
|
||||||
|
refreshMasterData()
|
||||||
|
.then(response => {
|
||||||
|
this.$message.success(response?.data?.data || '合规主数据缓存已刷新');
|
||||||
|
this.loadTemplates();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$message.error(error?.response?.data?.msg || '刷新失败');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.refreshing = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
formatTime(value) {
|
||||||
|
if (!value) return '-';
|
||||||
|
return this.$dayjs(Number(value)).format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.hcs-master-data-page__head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.dialog-section-title {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hcs-master-data-page__tip {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user