Compare commits
30 Commits
e5a7aca09e
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 5aefa23f50 | |||
| c92d2a405a | |||
| be4ccc89f6 | |||
| 565553b3f7 | |||
| 52d4b6b486 | |||
| 6a02e9126b | |||
| 6364b593ce | |||
| bb580b2bfc | |||
| 6c91889e33 | |||
| 4bef3430e0 | |||
| 17d12d279d | |||
| 9cf005cece | |||
| d8db9b1edd | |||
| cf04d48010 | |||
| 454608d7be | |||
| d82d06dc78 | |||
| f03f764472 | |||
| 1e4de76978 | |||
| e6d4edf362 | |||
| 1862115e1d | |||
| 49236cad56 | |||
| 02b2e3b673 | |||
| 53676a1150 | |||
| 5e92124710 | |||
| 8a262d9d41 | |||
| badfed7ff1 | |||
| c339852e04 | |||
| 819a59e6fc | |||
| f663098b4a | |||
| ef417a0290 |
@@ -28,3 +28,36 @@
|
|||||||
- 样式:新增 `.archive-form__group`(#fafafa 背景、8px 圆角、16px/20px 内边距、组间距 16px),子标题复用 `.dialog-section-title`(14px/500)。
|
- 样式:新增 `.archive-form__group`(#fafafa 背景、8px 圆角、16px/20px 内边距、组间距 16px),子标题复用 `.dialog-section-title`(14px/500)。
|
||||||
- 校验:@vue/compiler-sfc 解析 0 错误;标签闭合平衡。
|
- 校验:@vue/compiler-sfc 解析 0 错误;标签闭合平衡。
|
||||||
- 注:此前讨论中提及的「Tab 内容加内边距」「材料区标题竖条」未纳入本次(材料区已用 dialog-section-title);如需可后续追加。
|
- 注:此前讨论中提及的「Tab 内容加内边距」「材料区标题竖条」未纳入本次(材料区已用 dialog-section-title);如需可后续追加。
|
||||||
|
|
||||||
|
## 排查:分页「上一页/下一页原生箭头」样式被还原
|
||||||
|
|
||||||
|
- 现象:昨日(08-04)已对 `src/styles/element-ui.scss` 三处历史遗留规则做删除(隐藏 `.el-icon` 箭头、用 `::before` 注入「上一页/下一页」文字、整体 `display:none` 隐藏 `.btn-prev/.btn-next`),今早用户反馈效果被覆盖。
|
||||||
|
- 排查:重新 Grep 确认 `element-ui.scss` 三处原隐藏规则全部恢复成原始状态;而 `src/utils/pagination.js` 的注释("统一展示为原生箭头图标")未被还原,说明只有该样式文件被外部覆盖(疑似 git 还原 / 重新拉取 / 某生成流程),并非逻辑层问题。
|
||||||
|
- 已重新逐条应用三处删除(单条提交,避开并行编辑的缓存冲突),并验证无遗留 `display:none`/`content:'上一页'`;`pagination.js` 无需再改。
|
||||||
|
- 提醒:`element-ui.scss` 若处于版本控制或生成流程中,可能被再次还原;如需长期生效,建议把该改动提交入 git,或排查是否有自动覆盖该文件的脚本。
|
||||||
|
|
||||||
|
## UI 调整:Avue CRUD 弹窗内容区背景改为灰色 #f5f6fa
|
||||||
|
|
||||||
|
- 文件:`src/styles/element-ui.scss` 第 225 行附近 `.avue-crud__dialog .el-dialog__body`
|
||||||
|
- 改动:在原 `max-height`/`overflow-y` 规则中新增 `background: #f5f6fa;`
|
||||||
|
- 范围:**全局生效**(所有 Avue CRUD 弹窗的内容区都会变灰)。起因是用户想在货物类型(cargo-type)新增弹窗用灰底衬托。
|
||||||
|
- 注意:弹窗默认 `append-to-body`,scoped 样式选不到;如需仅货物类型单页变灰,需给 option 加 `dialogCustomClass` 再单独写选择器。用户未要求收窄,暂保持全局。
|
||||||
|
|
||||||
|
## UI 改造:project-apply 弹窗灰底+白卡片布局
|
||||||
|
|
||||||
|
- 文件:`src/views/business/project-apply.vue`
|
||||||
|
- 需求:弹窗背景色 `#f5f6fa`,每个分组区域用白色卡片
|
||||||
|
- 改动:
|
||||||
|
- 弹窗 body(global 选择器):加 `background: #f5f6fa`
|
||||||
|
- `__grid`、`__table`、`__textarea-list`、`__material-head`、`__upload`、`__change-textarea` 统一加白底 + 6px 圆角 + 极淡阴影 + 内边距
|
||||||
|
- 效果:灰蓝底弹窗上浮白色分组卡片,与客商档案弹窗的「灰色分组块+白色内层卡片」方案一致
|
||||||
|
|
||||||
|
## 二次优化:project-apply 分区标题也包进白色卡片
|
||||||
|
|
||||||
|
- 文件:`src/views/business/project-apply.vue`
|
||||||
|
- 需求:把「项目基本信息」这类分区标题也装进白色卡片内(标题+内容合一张白卡)
|
||||||
|
- 改动:
|
||||||
|
- `.dialog-section-title`(排除 material 标题)加白底 + 上圆角 `6px 6px 0 0` + `z-index:1`,紧接内容块
|
||||||
|
- `__grid`/`__table`/`__textarea-list`/`__change-textarea` 圆角改为下圆角 `0 0 6px 6px`,与标题拼接成完整白卡
|
||||||
|
- 材料区(`__material-head`/`__upload`)标题与按钮本就在白卡内,不受影响
|
||||||
|
- 纯 CSS 改动,未动模板结构;用 `:not()` 排除材料标题避免破坏既有布局
|
||||||
|
|||||||
116
.workbuddy/memory/2026-08-06.md
Normal file
116
.workbuddy/memory/2026-08-06.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# 2026-08-06 工作日志
|
||||||
|
|
||||||
|
## 全站表格操作列文字链接统一为蓝色
|
||||||
|
- 需求:客户档案页(/vehicle/customer-archive)操作列颜色统一蓝色,且全站统一风格。
|
||||||
|
- 实现:在 `src/styles/element-ui.scss` 新增全局规则,覆盖 Avue `#menu` 槽位(`.avue-crud__menu .el-link`)与手写表格操作列(`.el-table .el-table__body .cell:has(.el-link) .el-link`)中所有 `el-link` 的 `--el-link-text-color` / hover / active / disabled 变量为主色 `#409eff` 及其浅/深色,从而把 warning/success/danger 等类型强制转蓝。
|
||||||
|
- 单点生效,无需逐页改 `type`。dev server(2888) 已运行会热更新。
|
||||||
|
- 注意:选择器以「表格体内含 el-link 的单元格」为目标,本仓库表格内 el-link 仅用于操作列,无副作用;若未来某数据单元格用 el-link 作强调色需另行排除。
|
||||||
|
|
||||||
|
## 运输计划调度弹窗 UX 分析
|
||||||
|
- 完成 `/business/transport-plan` 调度弹窗的 UX 审查,对比 project-apply 页面风格
|
||||||
|
- 输出 6 项改进方案(P0-P5),核心问题为缺少灰底(#f5f6fa)+白卡(section-card)分组设计模式
|
||||||
|
- 所有改动集中在 `business-crud-page.vue` 一个文件
|
||||||
|
- 待用户确认后实施第一阶段(P0灰底 + P1白卡分组)
|
||||||
|
|
||||||
|
## 已实施的改进(全部在 business-crud-page.vue)
|
||||||
|
- P0: `__dispatch-dialog` 的 `.el-dialog__body` 改为 `padding:16px; background:#f5f6fa; overflow-y:auto`(原 padding:0)
|
||||||
|
- P1: 调度弹窗三块分区用全局 `<section-card>` 包裹:基本信息 / 收发货路线 / 待调度列表;"新增"按钮+汇总文字移入列表卡 `#extra` slot
|
||||||
|
- P2: `__dispatch-route-line` 由黑色实线改为 `#409EFF` 虚线 + 箭头(主色方向感)
|
||||||
|
- P3: 待调度列表纳入白卡容器(随 P1 完成)
|
||||||
|
- P4: 调度表操作列 `width` 180→220 预留扩展
|
||||||
|
- P5: `__dispatch-footer` 增加 `border-top` + padding/margin-top 分隔
|
||||||
|
- 旧 `__dispatch-list` / `__dispatch-top`(border-bottom/32px padding) 样式已清理;section-card 已全局注册,无需 import
|
||||||
|
- 验证:SFC 模板单独编译通过(6 处 section-card 引用配对平衡);完整 vite build 仍因预存 `xlsx` 幽灵依赖(pnpm 未装)失败,与本次改动无关
|
||||||
|
- 注意:本项目完整 build 依赖 `xlsx@0.18.5`(package.json 有声明但 node_modules 缺失),属环境预存问题,非本次引入
|
||||||
|
|
||||||
|
## 运输计划调度弹窗二次视觉紧凑化
|
||||||
|
- 客户反馈:弹窗“空、不紧凑、内容多但不好看”
|
||||||
|
- 改动仍集中在 `business-crud-page.vue`
|
||||||
|
- 模板:
|
||||||
|
- 标题与单号/状态标签合并到同一行,移除 `|` 分隔符
|
||||||
|
- 基本信息与收发货路线由左右双列改为上下堆叠的白卡,各自独占一行
|
||||||
|
- 基本信息网格改为 4 列:客户 / 项目 / 合同编号 / 计划执行时间;货物信息占 2 列;附件独占一行
|
||||||
|
- 日期展示由 `-` 改为 ` ~ `,更明确是区间
|
||||||
|
- 路线改为“横向节点 + 下方双列明细”:起点/终点徽章+名称居中,发货地址/收货地址左对齐分两列,避免居中留白
|
||||||
|
- 样式:
|
||||||
|
- 顶部标题字号 22px→18px,顶部 padding 22px→0
|
||||||
|
- 信息标签字号 14px→12px、颜色 #666→#909399,值行高 1.45→1.4
|
||||||
|
- 基本信息网格 3 列/48px 列间距/18px 行间距 → 4 列/24px 列间距/12px 行间距
|
||||||
|
- 路线徽章 46px→32px、字号 16px→13px、圆角 6px→4px
|
||||||
|
- 路线标题字号 22px→16px,取消居中,最长名称省略
|
||||||
|
- 路线区域取消 `min-height:200px` 和居中,改为紧凑堆叠
|
||||||
|
- 卡片间统一 `margin-bottom: 12px`
|
||||||
|
- 验证:`npm run build` 成功
|
||||||
|
|
||||||
|
## /business/project-apply 主表操作列收窄
|
||||||
|
- 需求:project-apply 主表(avue-crud #menu)操作列太宽,缩小一点。
|
||||||
|
- 原:`buildTableOption()` 调用 `applyTableMenuWidth(option, 4)` → 强制 `menuWidth: 320`(four 档),因按钮数≥4。
|
||||||
|
- 改动:`src/views/business/project-apply.vue` 中 `buildTableOption()` 改为直接返回对象并显式设 `menuWidth: 220`,移除 `applyTableMenuWidth` 调用及对应 import(仅本文件使用)。
|
||||||
|
- 说明:220 低于 AGENTS.md「>3 按钮≥320px」约定,但属用户明确要求;操作列链接已全局支持 flex-wrap,按钮多时会自动换行,不会裁切。
|
||||||
|
- 影响范围:仅 project-apply 主表;子表(附件/变更/用户权限)操作列 width 维持 110/100/100 不变;全局 `TABLE_MENU_WIDTH` 未改。
|
||||||
|
|
||||||
|
## /business/temporary-credit-limit 操作列宽度固定为 180
|
||||||
|
- 需求:该页操作列宽度也给 180。
|
||||||
|
- 背景:该页用共享组件 `business-crud-page.vue`,其 `option` 在 data() 中由 `cloneOption(crudOption, estimateMenuButtonCount(config))` 生成,菜单宽度按按钮数估算(≥4 按钮→320),option 文件本身无 menuWidth。
|
||||||
|
- 改动:
|
||||||
|
1. `business-crud-page.vue` 新增可选 prop `menuWidth`(Number,默认 null);data() 中生成 `option` 时若 `menuWidth != null` 则强制覆盖 `opt.menuWidth`。默认 null 不影响其他页面。
|
||||||
|
2. `temporary-credit-limit.vue` 调用处加 `:menu-width="180"`。
|
||||||
|
- 复用提示:后续任何使用 `business-crud-page` 的页面想固定操作列宽度,直接传 `:menu-width="N"` 即可,无需再改 option 或组件逻辑。
|
||||||
|
- 注意:180 同样低于 AGENTS「>3 按钮≥320」约定,按用户明确要求;链接支持换行兜底。
|
||||||
|
|
||||||
|
## /base/common-address 操作列宽度 220 → 180
|
||||||
|
- 需求:「这个也调一下宽度」。上一条刚把 temporary-credit-limit 设为 180,用户用「也」字,故对齐为 180。
|
||||||
|
- 机制:该页是独立 `avue-crud`,`option` 来自 `@/option/base/common-address.js` 的 `createOption()`,其中已显式设 `menuWidth: 220`。
|
||||||
|
- 改动:将 `src/option/base/common-address.js` 的 `menuWidth: 220` → `180`。操作列仅 3 个链接(查看/编辑/删除)。
|
||||||
|
- 说明:低于 AGENTS「>3 按钮≥320」约定,按用户明确要求;链接支持换行兜底。
|
||||||
|
|
||||||
|
## 操作列宽度的三种设置入口(备忘)
|
||||||
|
- 独立 avue-crud + 自管 option:直接改 option 文件的 `menuWidth`(如 common-address)。
|
||||||
|
- 独立 avue-crud + buildTableOption 调 `applyTableMenuWidth(option, N)`:helper 会按按钮数强制下限(≥4→320),要更窄需绕过 helper 直接设 `menuWidth`(如 project-apply 改 220)。
|
||||||
|
- 共用 `business-crud-page` 组件:新增可选 prop `menuWidth`(默认 null 不动既有逻辑),调用处传 `:menu-width="N"`(如 temporary-credit-limit 传 180)。
|
||||||
|
|
||||||
|
## /business/process-config 操作列宽度 320 → 180
|
||||||
|
- 需求:「这个也调一下宽度」。延续上几条把操作列设 180 的系列要求。
|
||||||
|
- 机制:该页是独立 `avue-crud`,`option` 来自 `@/option/business/process-config.js`,原先包在 `applyTableMenuWidth({...}, 5)` 中(five 档→强制 `menuWidth: 320`,因菜单有 6 个链接:查看/编辑/复制/启用/停用/删除)。
|
||||||
|
- 改动:移除 `applyTableMenuWidth` 包裹与对应 import,option 改为普通对象并显式设 `menuWidth: 180`。
|
||||||
|
- 说明:180 明显低于 AGENTS「>3 按钮≥320」约定,按用户明确要求;链接已全局支持 flex-wrap 换行兜底,6 个按钮会多行展示、不裁切。
|
||||||
|
|
||||||
|
## 修复 process-config.js 末尾语法错误(红色警)
|
||||||
|
- 现象:用户反馈 `src/option/business/process-config.js` 最后一行有红色警。
|
||||||
|
- 根因:上一轮把 `applyTableMenuWidth({...}, 5)` 去掉外层函数包裹时,结尾 `}, 5);` 被改成 `});`,多留了一个 `)`(因 `export const option = {` 本身没有左括号),导致括号不匹配。
|
||||||
|
- 改动:末尾 `});` → `};`。移除 `applyTableMenuWidth` import 时无误。
|
||||||
|
- 验证:node 动态 import 不再报 SyntaxError(仅剩 node 无法解析 extensionless `./common` 的模块解析提示,与语法无关),说明语法已恢复。
|
||||||
|
|
||||||
|
## /vehicle/insurance-record 操作列宽度 160 → 140(紧凑)
|
||||||
|
- 需求:「这个也调一下宽度,紧凑一点」。本页与上几条不同,用户明确要求更紧凑(其他页给的 180 比这页还宽)。
|
||||||
|
- 机制:独立 `avue-crud`,`option` 来自 `@/option/vehicle/insurance-record.js`;无自定义 `#menu` 槽,行菜单用 Avue 内置(仅显式 `viewBtn: true`,edit/del 默认开启→3 个链接:查看/编辑/删除)。原已显式 `menuWidth: 160`。
|
||||||
|
- 改动:将 `menuWidth: 160` → `140`。
|
||||||
|
- 说明:低于 AGENTS「>3 按钮≥320」约定,按用户明确要求;链接已全局支持 flex-wrap 换行兜底。
|
||||||
|
|
||||||
|
## 车/船务管理模块下所有记录页操作列宽度统一为 160
|
||||||
|
- 需求:用户截图列出「车/船务管理」下 11 个子菜单,要求操作栏宽度都设为 160。
|
||||||
|
- 对应页面/option 文件:
|
||||||
|
- 保险记录 insurance-record:option → `src/option/vehicle/insurance-record.js`(由 140 改回 160)
|
||||||
|
- 违章记录 violation-record:option → `src/option/vehicle/violation-record.js`(原 160,无需改动)
|
||||||
|
- 维修记录 maintenance-record:inline option → `src/views/vehicle/maintenance-record.vue`(原 160,无需改动)
|
||||||
|
- 保养记录 maintenance-plan:inline option → `src/views/vehicle/maintenance-plan.vue`(原 160,无需改动)
|
||||||
|
- 换胎记录 tire-replacement-record:option → `src/option/vehicle/tire-replacement-record.js`(原 160,无需改动)
|
||||||
|
- 事故记录 accident-record:option → `src/option/vehicle/accident-record.js`(原 160,无需改动)
|
||||||
|
- 年检记录 annual-inspection-record:option → `src/option/vehicle/annual-inspection-record.js`(原 160,无需改动)
|
||||||
|
- 里程记录 mileage-record:option → `src/option/vehicle/mileage-record.js`(原 160,无需改动)
|
||||||
|
- 变更记录 transport-change-record:option → `src/option/vehicle/transport-change-record.js`(原 160,无需改动)
|
||||||
|
- 油电记录 oil-electric-record:option → `src/option/vehicle/oil-electric-record.js`(原 160,无需改动)
|
||||||
|
- ETC记录 etc-record:option → `src/option/vehicle/etc-record.js`(原 160,无需改动)
|
||||||
|
- 实际改动:仅 `insurance-record.js` 从 140 恢复到 160,其余 10 个已经是 160。
|
||||||
|
- 注意:`src/option/vehicle/other-expense-record.js` 不在截图菜单内,保持不动。
|
||||||
|
|
||||||
|
## 车/船务管理模块操作列宽度 160 → 180(用户反馈 160 偏小)
|
||||||
|
- 需求:上一轮统一 160 后,用户觉得还是小,全部改成 180。
|
||||||
|
- 改动:11 个文件 `menuWidth: 160` → `180`(9 个 option 文件 + maintenance-record.vue / maintenance-plan.vue 两处 inline option)。
|
||||||
|
- 现状:车/船务管理模块全部 11 个记录页操作列均为 180。
|
||||||
|
|
||||||
|
## 操作列文字链接间距过宽问题
|
||||||
|
- 现象:用户截图反馈操作列文字链接之间间距太宽,要求统一风格。
|
||||||
|
- 根因:全局已设 `.avue-crud .avue-crud__menu { gap: 8px; }` 与手写表格操作列 `gap: 8px`,但 Avue 默认 `.el-link` 或 `.cell` 上可能存在 `margin-right`,与 gap 叠加后显得过宽。
|
||||||
|
- 改动:`src/styles/element-ui.scss` 新增规则,对 `.avue-crud .avue-crud__menu .el-link` 和手写表格操作列 `.el-link` 强制 `margin: 0`,使间距完全由 8px gap 控制,不再叠加。
|
||||||
|
- 影响范围:全站表格操作列(Avue #menu 与手写操作列),仅作用于操作列链接,不修改普通数据单元格。
|
||||||
110
.workbuddy/memory/2026-08-07.md
Normal file
110
.workbuddy/memory/2026-08-07.md
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
# 2026-08-07 工作日志
|
||||||
|
|
||||||
|
## 运输计划调度弹窗恢复左右分栏布局
|
||||||
|
- 需求:客户提供「计划详情」参考截图,要求调度弹窗改回「左侧基本信息卡 + 右侧收发货路线卡」的左右分栏布局。
|
||||||
|
- 改动:`src/views/business/components/business-crud-page.vue`
|
||||||
|
- 模板:把基本信息与收发货路线重新包进 `business-crud-page__dispatch-summary` 双列容器;左侧 `section-card` 内恢复 3 列网格(客户/项目/合同编号),货物信息占 2 列、计划执行时间占 1 列、附件独占一行;右侧 `section-card` 内恢复左右排列的起点/终点(徽章+名称+地址+联系人),中间用方向虚线连接。
|
||||||
|
- 样式:
|
||||||
|
- 外容器恢复 `grid-template-columns: minmax(0, 1.25fr) minmax(420px, 1fr)`,gap 16px,卡片等高拉伸。
|
||||||
|
- 基本信息网格恢复 3 列,列间距 16px、行间距 12px。
|
||||||
|
- 路线区恢复 `grid-template-columns: 1fr 56px 1fr`,徽章 32px,标题 16px,地址/联系人 13px,连接线 56px。
|
||||||
|
- 保留紧凑化后的字号/间距(标签 12px、值 14px),避免回到原先过松的状态。
|
||||||
|
- 验证:`npm run build` 成功。
|
||||||
|
|
||||||
|
## 运输计划调度弹窗基本信息改为 2 列
|
||||||
|
- 需求:客户截图反馈左侧「基本信息」还嫌松,要求改为 2 列更紧凑。
|
||||||
|
- 改动:`src/views/business/components/business-crud-page.vue`
|
||||||
|
- 模板:调整基本信息字段顺序为 客户/项目、合同编号/计划执行时间、货物信息(占满 2 列)、附件(占满 2 列)。
|
||||||
|
- 样式:`business-crud-page__dispatch-summary-grid` 从 `repeat(3, minmax(0, 1fr))` 改为 `repeat(2, minmax(0, 1fr))`,保持 gap 12px 16px。
|
||||||
|
- 验证:`npm run build` 成功。
|
||||||
|
|
||||||
|
## 运输计划调度弹窗路线连接改为车辆图标
|
||||||
|
- 需求:客户希望把收发货路线中间的方向虚线换成车辆图标。
|
||||||
|
- 改动:`src/views/business/components/business-crud-page.vue`
|
||||||
|
- 模板:把 `<div class="business-crud-page__dispatch-route-line" />` 替换为 `<div class="business-crud-page__dispatch-route-vehicle"><el-icon><Van /></el-icon></div>`。
|
||||||
|
- 样式:删除原 `&__dispatch-route-line` 虚线箭头样式,新增 `&__dispatch-route-vehicle`,使用主色圆形背景、白色 `Van` 图标,尺寸 36×36px,居中与路线节点对齐。
|
||||||
|
- 验证:`npm run build` 成功。
|
||||||
|
|
||||||
|
## 运输计划调度弹窗收发货路线视觉美化
|
||||||
|
- 需求:客户反馈右上角「收发货路线」卡片仍不够美观,要求继续优化。
|
||||||
|
- 改动:`src/views/business/components/business-crud-page.vue`
|
||||||
|
- 样式:
|
||||||
|
- 路线容器去掉 `padding-top`,改为 `align-items: center` 垂直居中。
|
||||||
|
- 起点/终点 item 改为 `align-items: center`,徽章从方角改为圆形,并加轻微阴影。
|
||||||
|
- 车辆图标改为白底 + 主色边框 + 主色 `Van` 图标,尺寸加大到 44×44px,两侧各延伸 20px 虚线,形成「路线」流动感。
|
||||||
|
- 城市名称限制单行并溢出省略,地址/联系人间距收紧、颜色变淡。
|
||||||
|
- 验证:`npm run build` 成功。
|
||||||
|
|
||||||
|
## 通知公告 /desk/notice 操作列加宽
|
||||||
|
- 需求:客户截图反馈操作列中「查看、编辑、删除」三个文字链接被挤成两行,要求加宽。
|
||||||
|
- 改动:`src/views/desk/notice.vue`
|
||||||
|
- 在 Avue CRUD option 中新增 `menuWidth: 220`,使操作列可在一行容纳三个操作链接;符合项目样式规范「三个操作按钮时宽度不小于 220px」。
|
||||||
|
|
||||||
|
## 全仓表格操作列宽度统一(≤3 按钮统一 180)
|
||||||
|
- 需求:客户提供新截图,要求所有操作按钮 ≤3 个的表格操作列统一宽度为 180;>3 个按钮保持 320。
|
||||||
|
- 核心改动:
|
||||||
|
- `src/utils/table-menu.js`:`TABLE_MENU_WIDTH` 的 `default` 与 `three` 都从 160/220 统一改为 180,`four` 保持 320;`resolveTableMenuWidth` 逻辑不变。
|
||||||
|
- `src/main.js`:全局 `crudOption.menuWidth` 从 160 改为 180,覆盖未显式设置 menuWidth 的 Avue CRUD 页面。
|
||||||
|
- `src/views/desk/notice.vue`:`menuWidth` 从 220 改为 180。
|
||||||
|
- `src/option/business/process-config.js`:`menuWidth` 从 200 改为 180。
|
||||||
|
- `src/views/system/param.vue`:手写 el-table 操作列宽度从 220 改为 180。
|
||||||
|
- 批量替换:对 44 个显式设置 `menuWidth: 160` 的 `.vue` / `.js` / `const/*.js` 文件统一改为 180(含部分文件内多处)。
|
||||||
|
- 验证:`npm run build` 成功(exit code 0)。
|
||||||
|
|
||||||
|
## 角色管理 /authority/role 操作列改 180
|
||||||
|
- 需求:用户明确要求把 /authority/role 页面操作列宽度设为 180(该页面此前设为 320,因含「查看/编辑/删除 + 权限设置」自定义菜单)。
|
||||||
|
- 改动:`src/views/authority/role.vue`
|
||||||
|
- option 内联 `menuWidth: 320` 改为 `menuWidth: 180`。
|
||||||
|
|
||||||
|
## 全站操作列按钮统一为链接(el-link)风格
|
||||||
|
- 需求:用户要求「操作栏里的按钮改成链接的方案,全站风格统一」,并先确认了对功能是否有影响。
|
||||||
|
- 调研结论(关键):全仓手写 el-table 操作列(10 个文件、约 28 列)与 53 个 avue-crud 自定义 `#menu` 插槽**已全部是 `<el-link>`**,全库 `type="text"` 残留为 0;真正未链接化的只剩下 **Avue 内置 viewBtn/editBtn/delBtn**(渲染为 `<el-button is-text>`,包在 `div.avue-crud__menu` 内,且自带 `permission` 指令与 `rowView/rowEdit/rowDel` 事件)。
|
||||||
|
- 实施手法:采用「方案 A:纯 CSS 视觉对齐」(零功能影响、不动事件与权限,符合用户「不要影响功能」的诉求)。
|
||||||
|
- 改动:`src/styles/element-ui.scss`
|
||||||
|
- 新增 `.avue-crud__menu > .el-button.is-text` 规则,把 Avue 内置行操作按钮外观对齐为 el-link:主色文字、无边框/无背景、hover 下划线 + 浅色、禁用态浅色无下划线、`height:auto / padding:0`(配合父级 `inline-flex; gap:8px` 与已存在的主色/间距覆盖规则)。
|
||||||
|
- 选择器仅命中行操作列 `.avue-crud__menu` 内的 `is-text` 按钮,不误伤顶部工具栏(`.avue-crud__header`)与弹窗按钮(`.avue-crud__dialog__menu`)。
|
||||||
|
- 注意:现有全局规则 `.avue-crud__menu .el-link` 会强制操作列内所有 el-link(含 `type="danger"` 的删除)显示为主色蓝。如需删除按钮保留红色告警,需单独调整该覆盖规则(本次未改,保持统一蓝)。
|
||||||
|
- 验证:`npm run build` 成功(exit code 0);构建日志中的 CSS `*` 告警来自第三方库压缩,与本次无关(历史既有)。
|
||||||
|
|
||||||
|
## 操作列文字取消加粗(统一常规字重)
|
||||||
|
- 需求:用户要求操作栏下的按钮字体都不要加粗,统一风格。
|
||||||
|
- 根因:Element Plus `el-link` 默认 `font-weight: var(--el-font-weight-primary)`(500 中等粗),导致操作列里的链接(查看/编辑/删除等)显示为加粗;而 Avue 内置 `is-text` 按钮此前已被规则设为 normal。
|
||||||
|
- 改动:`src/styles/element-ui.scss`
|
||||||
|
- 在既有 `.avue-crud__menu .el-link, .el-table ... .cell:has(.el-link) .el-link` 统一规则中增加 `font-weight: normal;`((0,2,0) 优先级高于 el-link 自身 (0,1,0) 的默认字重,可覆盖)。
|
||||||
|
- 覆盖范围:Avue 行菜单内的 el-link + 任意含 el-link 的表格体单元格(手写操作列),一次统一全站操作列字重;Avue 内置 `is-text` 按钮与顶部工具栏/弹窗按钮字重保持原样不受影响。
|
||||||
|
- 验证:`npm run build` 成功(exit code 0)。
|
||||||
|
|
||||||
|
## 全站表格省略文字 hover tooltip 提示统一
|
||||||
|
- 需求:用户截图反馈合同管理等页面中「所属项目」等列文字被省略,要求像 `/base/common-address` 一样,鼠标移上去显示完整提示;全站统一加,改完列出文件。
|
||||||
|
- 参考实现:`src/option/base/common-address.js` 中 Avue 列配置使用 `showOverflowTooltip: true`。
|
||||||
|
- 调研结论:全站表格可见列约 848 个(Avue)+ 424 个手写 `<el-table-column>`,其中 801 个 Avue 列、268 个手写列未开启 tooltip。Element Plus 支持全局 `table: { showOverflowTooltip: true }` 配置,Avue 3.9.2 完整透传,可一行代码覆盖全站。
|
||||||
|
- 改动文件清单:
|
||||||
|
- `src/main.js`
|
||||||
|
- Element Plus 全局配置新增 `table: { showOverflowTooltip: true }`,一次性覆盖所有 Avue CRUD 与手写 el-table。
|
||||||
|
- Avue 全局 `crudOption` 新增 `showOverflowTooltip: true` 作为双保险,避免页面级 option 被错误覆盖时失效。
|
||||||
|
- `src/styles/element-ui.scss`
|
||||||
|
- 新增 `.el-table .cell.avue-crud__menu, .el-table .el-table__body .cell.el-tooltip:has(> .el-link)` 规则,豁免操作列单元格的固定宽度与溢出隐藏,防止全局 tooltip 导致操作列内 el-link 换行后被裁切,保持原有 8px gap 与自动换行。
|
||||||
|
- `src/option/business/common.js`
|
||||||
|
- 共享工厂函数 `createCrudOption` 新增 `showOverflowTooltip: true`,覆盖 business 模块通过该工厂生成的所有 CRUD option。
|
||||||
|
- 覆盖范围:全站所有表格可见文本列(含 Avue 与手写 el-table),`type="selection"` 选择列由 Element Plus 自动豁免;操作列通过 CSS 豁免不被影响。
|
||||||
|
- 验证:`npm run build` 成功(exit code 0);构建日志中 CSS `*` 告警来自第三方库压缩,与本次无关(历史既有)。
|
||||||
|
|
||||||
|
## 修复 /system/dept 操作栏错位(链接竖排)
|
||||||
|
- 现象:用户截图反馈机构管理页操作列「查看 / 编辑 / 删除 / 新增子项」竖排且偏右错位。
|
||||||
|
- 根因:Avue 自带默认样式 `.avue-crud .avue-crud__menu{display:block}`(特异性 0,2,0)与项目全局覆盖样式选择器完全相同;项目原规则虽带 `!important`,但在 dev 模式 CSS 注入时序或浏览器缓存旧 element-ui.scss 时,`.avue-crud__menu` 退化成 block,导致内部按钮/链接竖排。
|
||||||
|
- 修复:
|
||||||
|
- `src/styles/element-ui.scss`:把 `.avue-crud .avue-crud__menu` 改为重复类名 `.avue-crud .avue-crud__menu.avue-crud__menu`(特异性升到 0,3,0),并新增 `width: 100% !important` 让操作列容器占满单元格、左对齐横排更稳。
|
||||||
|
- `src/views/system/dept.vue`:scoped 样式新增 `:deep(.avue-crud__menu)` 兜底(inline-flex + gap 8px + 子元素 inline-flex),双保险确保本页操作列横排。
|
||||||
|
- 验证:dev server 已热更新,curl 确认两处编译结果均含 `display: inline-flex !important`;构建需用户硬刷新浏览器清旧 CSS 缓存。
|
||||||
|
|
||||||
|
## 客商档案 /vehicle/customer-archive 弹窗风格统一为 section-card
|
||||||
|
- 需求:用户截图反馈弹窗有「双层灰色背景」,且「工商信息」等标题没有放到卡片里面;要求改成和 `/business/project-apply` 一致的白卡风格。
|
||||||
|
- 根因:原页面主表单使用 `.archive-form__group` 灰色容器,内部再包一层白色 `.el-row` 卡片,标题坐在灰色背景上,形成外层 dialog body 灰 + 分组灰的「双层灰」;客商材料、变更记录、评分材料、发票/邮寄信息也沿用旧的分节标题样式。
|
||||||
|
- 改动:`src/views/vehicle/customer-archive.vue`
|
||||||
|
- 主表单 4 个分组改为 `<section-card title="工商信息 / 联系信息 / 财务/信用信息 / 其他信息">` 全局白卡组件,删除外层「基本信息」大标题。
|
||||||
|
- 评分/联系人/收款/发票 4 个 Tab 内容改为 `<section-card>` + `<template #extra>`,按钮组进入卡头右侧。
|
||||||
|
- 客商材料改为 `<section-card title="客商材料" #extra>`,变更记录改为 `<section-card title="变更记录">`。
|
||||||
|
- 发票信息弹窗的「发票信息 / 邮寄信息」改为两张 `<section-card>`。
|
||||||
|
- 评分详情弹窗的「证明材料」改为 `<section-card title="证明材料" class="score-material-card">`。
|
||||||
|
- 清理不再使用的样式:`.archive-form__group`、`.section-title`、`.section-head`、`.customer-material-section`、`.change-record-section`、`.invoice-form__section-title`、`.score-material-section` 等。
|
||||||
|
- 验证:`npm run build` 成功(exit code 0)。
|
||||||
@@ -1,16 +1,66 @@
|
|||||||
# 项目长期记忆(tms-erp-web-ws / Saber3 客商模块)
|
# 项目长期记忆(tms-erp-web-ws / Saber3 客商模块)
|
||||||
|
|
||||||
## 设计约定(经用户确认的决策)
|
## 设计约定(经用户确认的决策)
|
||||||
- 弹窗内多字段表单分组:**「灰色分组块 + 白色内层卡片」双色方案**(用户最终确认)。
|
|
||||||
- 外层 `.archive-form__group`:灰底 `#f0f2f5` + 8px 圆角 + `16px 20px` 内边距,分组标题(`.dialog-section-title`,自带 4px 主色竖条)浮于灰底上。
|
### 弹窗内多字段表单分组:使用全局 `<section-card>` 组件(项目统一标准)
|
||||||
- 内层字段区:直接把分组内唯一的 `> .el-row` 设为白底(`#fff` + 6px 圆角 + 极淡阴影 `0 1px 2px rgba(0,0,0,.04)` + `18px 16px 4px` 内边距),形成「白卡片浮于灰底」的层次,而非逐个输入框强制白底。
|
|
||||||
- 理由:契合 AGENTS.md「去卡片化」哲学(不嵌套 `el-card`),同时用户明确要灰底+白内容对比,全局 `.dialog-section-title` 直接复用即可。
|
**整体结构**:
|
||||||
- 适用:新增/编辑弹窗中字段超过 ~10 个、需按业务语义分组时。
|
- 整个弹窗 body 由 `src/styles/element-ui.scss` 全局 `.el-dialog__body { background: #f5f6fa; padding: 16px }` 统一灰底(无需页面再覆盖)。
|
||||||
|
- 每个业务分组 = 一张白底卡片。用全局组件 `<section-card title="分组名">...</section-card>`,自动渲染 4px 主色竖条 + 8px 间距的卡头与白底 body(圆角 6px + 极淡阴影),与 `loading-manage.vue` / `customer-archive.vue` 等已落地页面一致。
|
||||||
|
- 严禁再手写 `.xxx-form__block` + `.dialog-section-title` override 拼凑卡片(项目已有 `<section-card>` 标准组件)。
|
||||||
|
|
||||||
|
**HTML 结构**(每组三件套):
|
||||||
|
```vue
|
||||||
|
<section-card title="分组标题">
|
||||||
|
<el-row :gutter="18">
|
||||||
|
<el-col :span="8">...</el-col>
|
||||||
|
</el-row>
|
||||||
|
<!-- 同一组的所有 row 都放同一张白卡内 -->
|
||||||
|
</section-card>
|
||||||
|
```
|
||||||
|
|
||||||
|
**适用**:新增/编辑弹窗中字段超过 ~10 个、需按业务语义分组时。
|
||||||
|
|
||||||
|
### 简单分组(仅 3 项)
|
||||||
- 联系信息等仅 3 项的分组,可用 `el-col :span="8"` 让三项均分一行,避免 4 列网格留白。
|
- 联系信息等仅 3 项的分组,可用 `el-col :span="8"` 让三项均分一行,避免 4 列网格留白。
|
||||||
|
|
||||||
|
### 上传证件区域尺寸规范(transportCapacity 模块强制)
|
||||||
|
- **比例**:中国二代身份证标准尺寸 85.6 × 53.98 mm → 宽:高 = **1.586 : 1**(横放)
|
||||||
|
- **尺寸**:取真实身份证的 ~75% → 固定 **240 × 151 px**(1.586:1 精确:151 × 1.586 ≈ 240)
|
||||||
|
- **位置**:在 el-col 列内 `margin: 0` 左对齐显示(不再 `width: 100%` 占满整栏,也不再居中)
|
||||||
|
- **适用范围**:所有 `<image-upload-field large>` 上传区,包括身份证正反面、大头照、机动车行驶证主页正/反面/副页正/反面、道路运输证、机动车登记本、船舶所有权/安全环保/国籍/最低安全配员/光船租赁/营业运输 等所有 cert 图片
|
||||||
|
- **实现方式**:在每个页面 scoped 样式里覆盖 class-prefix 对应的 `--large` 选择器(`.driver-uploader--large` / `.vehicle-uploader--large` / `.ship-uploader--large`):
|
||||||
|
```scss
|
||||||
|
:deep(.xxx-uploader) { display: block; } // 不再 width:100%
|
||||||
|
:deep(.xxx-uploader--large) {
|
||||||
|
display: block;
|
||||||
|
width: 240px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
:deep(.xxx-uploader--large .el-upload),
|
||||||
|
:deep(.xxx-uploader--large.el-upload) {
|
||||||
|
width: 100%;
|
||||||
|
height: 151px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **CSS 顺序要点**:`.xxx-uploader`(特定性 0,0,1,0)必须写在 `.xxx-uploader--large`(同为 0,0,1,0)之前,源码位置决定覆盖生效。
|
||||||
|
|
||||||
|
### 上传图片点击放大预览(全局组件 `image-upload-field` 已实现)
|
||||||
|
- **组件**:`src/components/image-upload-field/main.vue`。原裸 `<img>` 改为 `<el-image :preview-src-list="[value]" fit="contain" preview-teleported :z-index="3000" @click.stop>`。点击图片即全屏预览(滚轮缩放 / 旋转 / 下载),零额外依赖。
|
||||||
|
- **预览与上传分离**:图片 `@click.stop` 阻止冒泡到 `el-upload`(否则会触发重传);"更换"入口(form 模式图片下方 `el-link`、card 模式 head 的 `actionText`)通过 `el-upload` 内部隐藏 `input.el-upload__input` 的 `.click()` 触发文件框。
|
||||||
|
- **为什么用 DOM click**:Element Plus `el-upload` 仅 expose `abort/submit/clearFiles/handleStart/handleRemove`,**没有** `openFileDialog`,故用 `this.$refs.uploadRef.$el.querySelector('.el-upload__input').click()`。
|
||||||
|
- **readonly 模式**:仅渲染 `el-image` 预览,不显示上传入口(查看档案时也能放大看证件)。
|
||||||
|
- **z-index 注意**:务必 `preview-teleported`(预览层挂 body)+ `:z-index="3000"`,否则会被 `el-dialog` 遮罩(2000 区间)盖住。
|
||||||
|
- **适用范围**:全仓通用组件,driver / vehicle / ship 三个页面自动获得该能力(改动一次组件即可)。
|
||||||
|
|
||||||
## 关键文件
|
## 关键文件
|
||||||
- 客商档案弹窗:`src/views/vehicle/customer-archive.vue`(手写 `el-form`,非 Avue option 驱动;分组结构见 `.archive-form__group`)。
|
- 通用分组白卡组件:`src/components/section-card/main.vue`(已全局注册为 `<section-card>`,支持 `title` / `#title` / `#extra` slot)。
|
||||||
- 全局弹窗分区标题规范:`src/styles/element-ui.scss` 的 `.dialog-section-title`。
|
- 弹窗灰底 body + section-card 全局样式:`src/styles/element-ui.scss`(`.el-dialog__body`、`.section-card { &__header / &__bar / &__title / &__extra / &__body }`)。
|
||||||
|
- 司机档案弹窗:`src/views/transportCapacity/driver.vue`(手写 `el-form` + `<section-card>` 4 大分组:基础身份信息 / 驾驶证信息 / 从业资格证信息 / 司机联系信息)。
|
||||||
|
- 车辆档案弹窗:`src/views/transportCapacity/vehicle.vue`(手写 `el-form` + `<section-card>` 2 大分组:基础车辆信息 / 车辆资质图片;6 张大图按身份证比例 240×151 左对齐)。
|
||||||
|
- 船舶档案弹窗:`src/views/transportCapacity/ship.vue`(手写 `el-form` + `<section-card>` 2 大分组:基础船舶信息 / 船舶证书信息;内部 6 张 cert 图片按身份证比例 240×151 左对齐;子证书分段用 `.cert-block` + border-top)。
|
||||||
|
- 客商档案弹窗:`src/views/vehicle/customer-archive.vue`(工商信息 / 联系信息 / 财务/信用信息 / 其他信息 等分组也用 `<section-card>`)。
|
||||||
|
- 项目补录弹窗:`src/views/business/project-apply.vue`(手写 `__grid` / `__table` / `__textarea-list` 同款白卡结构,先于 `<section-card>` 组件化之前落地,可视为视觉参照)。
|
||||||
|
|
||||||
## 环境注意
|
## 环境注意
|
||||||
- Vite 代理跨域:Saber3 axios 开 `withCredentials=true`,直连绝对地址后端须让 CORS `Allow-Origin` 为具体域名(不能用 `*`),否则浏览器拒绝。改 `.env`/`vite.config.mjs` 必须重启 dev。
|
- Vite 代理跨域:Saber3 axios 开 `withCredentials=true`,直连绝对地址后端须让 CORS `Allow-Origin` 为具体域名(不能用 `*`),否则浏览器拒绝。改 `.env`/`vite.config.mjs` 必须重启 dev。
|
||||||
|
|||||||
@@ -170,12 +170,14 @@ Avue 表格/表单配置独立存放于 `src/option/` 目录,与 `views` 和 `
|
|||||||
- 表格操作列同时展示“查看、编辑、删除”等三个按钮时,操作列宽度统一不小于 `220px`;操作列最大按钮数量超过 3 个时,操作列宽度统一加宽到不小于 `320px`;最大按钮数量超过 4 个时,仍按 `320px` 保持列宽,并从第 5 个按钮开始换行展示,禁止出现按钮裁切或显示不全。
|
- 表格操作列同时展示“查看、编辑、删除”等三个按钮时,操作列宽度统一不小于 `220px`;操作列最大按钮数量超过 3 个时,操作列宽度统一加宽到不小于 `320px`;最大按钮数量超过 4 个时,仍按 `320px` 保持列宽,并从第 5 个按钮开始换行展示,禁止出现按钮裁切或显示不全。
|
||||||
- 表格操作列按钮统一仅展示文字,禁止配置 `icon` / `:icon` 或在操作按钮、操作下拉项中嵌入图标;顶部工具栏按钮不受此条限制。
|
- 表格操作列按钮统一仅展示文字,禁止配置 `icon` / `:icon` 或在操作按钮、操作下拉项中嵌入图标;顶部工具栏按钮不受此条限制。
|
||||||
- 纯文字操作入口统一使用 `<el-link>`,禁止使用带 `text` 属性的 `<el-button>`;提交、确认、上传等具有明确命令语义或需要加载状态的按钮可继续使用 `<el-button>`。
|
- 纯文字操作入口统一使用 `<el-link>`,禁止使用带 `text` 属性的 `<el-button>`;提交、确认、上传等具有明确命令语义或需要加载状态的按钮可继续使用 `<el-button>`。
|
||||||
|
- 所有表格操作列中的文字链接统一保持 `8px` 间距;操作按钮超过操作列可用宽度时必须自动换行,禁止链接连续粘连或被裁切。Avue 自定义 `#menu` 插槽和手写 `el-table-column` 操作列均适用。
|
||||||
- `.avue-crud__header` 顶部间距统一为 `12px`。
|
- `.avue-crud__header` 顶部间距统一为 `12px`。
|
||||||
- 分页组件整体靠右展示,必须展示接口返回的数据总条数,`X条/页` 的页容量选择器必须放在总条数右侧。
|
- 分页组件整体靠右展示,必须展示接口返回的数据总条数,`X条/页` 的页容量选择器必须放在总条数右侧。
|
||||||
- `.basic-container__card` 的直接子级 `.el-card__body` 内边距统一去除,保持 `padding: 0`
|
- `.basic-container__card` 的直接子级 `.el-card__body` 内边距统一去除,保持 `padding: 0`
|
||||||
- 所有 CRUD 页面搜索栏需与下方表格拆分为独立区域,两者垂直间距统一为 `8px`。
|
- 所有 CRUD 页面搜索栏需与下方表格拆分为独立区域,两者垂直间距统一为 `8px`。
|
||||||
- 所有 CRUD 页面搜索栏操作按钮(搜索、清空等)需在搜索表单下方独占一行并放置在最右侧;搜索条件超过一行时必须显示“展开/折叠”,默认折叠且仅展示一行搜索条件;一行布局默认展示 4 个筛选项,Avue 配置统一使用 `searchIndex: 4`。
|
- 所有 CRUD 页面搜索栏操作按钮(搜索、清空等)需在搜索表单下方独占一行并放置在最右侧;搜索条件超过一行时必须显示“展开/折叠”,默认折叠且仅展示一行搜索条件;一行布局默认展示 4 个筛选项,Avue 配置统一使用 `searchIndex: 4`。
|
||||||
- 所有 CRUD 页面中新增、批量导入等顶部按钮组行不需要背景色,应保持透明背景。
|
- 所有 CRUD 页面中新增、批量导入等顶部按钮组行不需要背景色,应保持透明背景。
|
||||||
|
- 所有 CRUD 页面顶部工具栏的“新增/新建”主操作按钮统一使用蓝底白字的实心主按钮(`type="primary"` 且不使用 `plain`),视觉标准与“新建运单”一致;批量导入、导出等辅助工具按钮仍使用描边样式。
|
||||||
- 所有 `.basic-container__card` 内的 Avue 内层 `el-card` 需去卡片化,仅保留外层容器卡片样式,禁止出现二级卡片边框、阴影或额外内边距。
|
- 所有 `.basic-container__card` 内的 Avue 内层 `el-card` 需去卡片化,仅保留外层容器卡片样式,禁止出现二级卡片边框、阴影或额外内边距。
|
||||||
|
|
||||||
### 4.5 全局注册组件
|
### 4.5 全局注册组件
|
||||||
|
|||||||
@@ -45,6 +45,13 @@ export const reject = id =>
|
|||||||
params: { id },
|
params: { id },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const updateAttachments = row =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/update-attachments`,
|
||||||
|
method: 'post',
|
||||||
|
data: row,
|
||||||
|
});
|
||||||
|
|
||||||
export const withdraw = id =>
|
export const withdraw = id =>
|
||||||
request({
|
request({
|
||||||
url: `${baseUrl}/withdraw`,
|
url: `${baseUrl}/withdraw`,
|
||||||
|
|||||||
@@ -61,6 +61,13 @@ export const getUser = id => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getCustomerOptions = () => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-system/user/customer-options',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const getUserPlatform = id => {
|
export const getUserPlatform = id => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-system/user/platform-detail',
|
url: '/blade-system/user/platform-detail',
|
||||||
|
|||||||
@@ -51,6 +51,14 @@ export const changeStatus = (id, status) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const auditCertification = (id, certificationStatus, rejectReason) => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-transport/transport-vehicle/audit-certification',
|
||||||
|
method: 'post',
|
||||||
|
params: { id, certificationStatus, rejectReason },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const getExpiryStat = params => {
|
export const getExpiryStat = params => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-transport/transport-vehicle/expiry-stat',
|
url: '/blade-transport/transport-vehicle/expiry-stat',
|
||||||
|
|||||||
@@ -40,6 +40,16 @@ export const submitApproval = id => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const withdrawApproval = id => {
|
||||||
|
return request({
|
||||||
|
url: '/blade-transport/customer-archive/withdraw-approval',
|
||||||
|
method: 'post',
|
||||||
|
params: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const approve = id => {
|
export const approve = id => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-transport/customer-archive/approve',
|
url: '/blade-transport/customer-archive/approve',
|
||||||
|
|||||||
23
src/api/vehicle/equipment-ledger.js
Normal file
23
src/api/vehicle/equipment-ledger.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import request from '@/axios';
|
||||||
|
|
||||||
|
export const getList = (current, size, params) =>
|
||||||
|
request({
|
||||||
|
url: '/blade-transport/equipment-ledger/list',
|
||||||
|
method: 'get',
|
||||||
|
params: { ...params, current, size },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getDetail = id =>
|
||||||
|
request({ url: '/blade-transport/equipment-ledger/detail', method: 'get', params: { id } });
|
||||||
|
|
||||||
|
export const getNextEquipmentCode = () =>
|
||||||
|
request({ url: '/blade-transport/equipment-ledger/next-equipment-code', method: 'get' });
|
||||||
|
|
||||||
|
export const add = row =>
|
||||||
|
request({ url: '/blade-transport/equipment-ledger/submit', method: 'post', data: row });
|
||||||
|
|
||||||
|
export const update = row =>
|
||||||
|
request({ url: '/blade-transport/equipment-ledger/submit', method: 'post', data: row });
|
||||||
|
|
||||||
|
export const remove = ids =>
|
||||||
|
request({ url: '/blade-transport/equipment-ledger/remove', method: 'post', params: { ids } });
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form-item v-if="mode === 'form'" :label="label" :prop="prop">
|
<el-form-item v-if="mode === 'form'" :label="label" :prop="prop">
|
||||||
|
<div :class="[`${classPrefix}-uploader`, { [`${classPrefix}-uploader--large`]: large }]">
|
||||||
<el-upload
|
<el-upload
|
||||||
:class="[`${classPrefix}-uploader`, { [`${classPrefix}-uploader--large`]: large }]"
|
ref="uploadRef"
|
||||||
|
class="upload-inner"
|
||||||
action="/api/blade-resource/oss/endpoint/put-file"
|
action="/api/blade-resource/oss/endpoint/put-file"
|
||||||
name="file"
|
name="file"
|
||||||
:headers="uploadHeaders"
|
:headers="uploadHeaders"
|
||||||
@@ -12,17 +14,44 @@
|
|||||||
:on-success="handleSuccess"
|
:on-success="handleSuccess"
|
||||||
:on-error="handleError"
|
:on-error="handleError"
|
||||||
>
|
>
|
||||||
<img v-if="value" :src="value" :class="`${classPrefix}-uploader__image`" />
|
<el-image
|
||||||
|
v-if="value"
|
||||||
|
:src="value"
|
||||||
|
:class="`${classPrefix}-uploader__image`"
|
||||||
|
:preview-src-list="[value]"
|
||||||
|
fit="contain"
|
||||||
|
preview-teleported
|
||||||
|
:z-index="3000"
|
||||||
|
@click.stop
|
||||||
|
/>
|
||||||
<div v-else :class="`${classPrefix}-uploader__empty`">{{ emptyText }}</div>
|
<div v-else :class="`${classPrefix}-uploader__empty`">{{ emptyText }}</div>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
|
<el-link
|
||||||
|
v-if="value && !readonly"
|
||||||
|
type="primary"
|
||||||
|
class="upload-replace-link"
|
||||||
|
@click.stop="triggerUpload"
|
||||||
|
>
|
||||||
|
更换
|
||||||
|
</el-link>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-else :prop="prop" :class="`${classPrefix}-upload-item`">
|
<el-form-item v-else :prop="prop" :class="`${classPrefix}-upload-item`">
|
||||||
<div :class="[`${classPrefix}-upload-card`, { [`${classPrefix}-upload-card--large`]: large }]">
|
<div :class="[`${classPrefix}-upload-card`, { [`${classPrefix}-upload-card--large`]: large }]">
|
||||||
<div v-if="label" :class="`${classPrefix}-upload-card__head`">
|
<div v-if="label" :class="`${classPrefix}-upload-card__head`">
|
||||||
<span :class="`${classPrefix}-upload-card__label`">{{ label }}</span>
|
<span :class="`${classPrefix}-upload-card__label`">{{ label }}</span>
|
||||||
<span :class="`${classPrefix}-upload-card__action`">{{ actionText }}</span>
|
<el-link
|
||||||
|
v-if="!readonly"
|
||||||
|
type="primary"
|
||||||
|
:class="`${classPrefix}-upload-card__action`"
|
||||||
|
@click.stop="triggerUpload"
|
||||||
|
>
|
||||||
|
{{ actionText }}
|
||||||
|
</el-link>
|
||||||
|
<span v-else :class="`${classPrefix}-upload-card__action`">{{ actionText }}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-upload
|
<el-upload
|
||||||
|
ref="uploadRef"
|
||||||
:class="`${classPrefix}-upload-card__uploader`"
|
:class="`${classPrefix}-upload-card__uploader`"
|
||||||
action="/api/blade-resource/oss/endpoint/put-file"
|
action="/api/blade-resource/oss/endpoint/put-file"
|
||||||
name="file"
|
name="file"
|
||||||
@@ -34,7 +63,16 @@
|
|||||||
:on-success="handleSuccess"
|
:on-success="handleSuccess"
|
||||||
:on-error="handleError"
|
:on-error="handleError"
|
||||||
>
|
>
|
||||||
<img v-if="value" :src="value" :class="`${classPrefix}-upload-card__image`" />
|
<el-image
|
||||||
|
v-if="value"
|
||||||
|
:src="value"
|
||||||
|
:class="`${classPrefix}-upload-card__image`"
|
||||||
|
:preview-src-list="[value]"
|
||||||
|
fit="contain"
|
||||||
|
preview-teleported
|
||||||
|
:z-index="3000"
|
||||||
|
@click.stop
|
||||||
|
/>
|
||||||
<div v-else :class="`${classPrefix}-upload-card__empty`">{{ emptyText }}</div>
|
<div v-else :class="`${classPrefix}-upload-card__empty`">{{ emptyText }}</div>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,6 +124,11 @@ export default {
|
|||||||
this.closeUploadLoading();
|
this.closeUploadLoading();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
triggerUpload() {
|
||||||
|
const uploadEl = this.$refs.uploadRef && this.$refs.uploadRef.$el;
|
||||||
|
const input = uploadEl && uploadEl.querySelector('.el-upload__input');
|
||||||
|
if (input) input.click();
|
||||||
|
},
|
||||||
showUploadLoading() {
|
showUploadLoading() {
|
||||||
if (this.uploadLoading) {
|
if (this.uploadLoading) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
28
src/components/section-card/main.vue
Normal file
28
src/components/section-card/main.vue
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<template>
|
||||||
|
<div class="section-card">
|
||||||
|
<div v-if="title || $slots.title || $slots.extra" class="section-card__header">
|
||||||
|
<span class="section-card__bar" />
|
||||||
|
<span class="section-card__title">
|
||||||
|
<slot name="title">{{ title }}</slot>
|
||||||
|
</span>
|
||||||
|
<span class="section-card__extra">
|
||||||
|
<slot name="extra" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="section-card__body">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'SectionCard',
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -85,6 +85,9 @@ const MIME_MAP = {
|
|||||||
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
ppt: 'application/vnd.ms-powerpoint',
|
ppt: 'application/vnd.ms-powerpoint',
|
||||||
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||||
|
eml: 'message/rfc822',
|
||||||
|
msg: 'application/vnd.ms-outlook',
|
||||||
|
zip: 'application/zip',
|
||||||
txt: 'text/plain',
|
txt: 'text/plain',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ export const option = {
|
|||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
grid: true,
|
grid: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '数据源',
|
label: '数据源',
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ import codeSetting from './views/tool/codesetting.vue';
|
|||||||
import formSetting from './views/tool/formsetting.vue';
|
import formSetting from './views/tool/formsetting.vue';
|
||||||
import tenantPackage from './views/system/tenantpackage.vue';
|
import tenantPackage from './views/system/tenantpackage.vue';
|
||||||
import tenantDatasource from './views/system/tenantdatasource.vue';
|
import tenantDatasource from './views/system/tenantdatasource.vue';
|
||||||
|
// 通用弹窗分组白卡(灰底弹窗内使用,标题在卡内)
|
||||||
|
import sectionCard from './components/section-card/main.vue';
|
||||||
|
|
||||||
window.$crudCommon = crudCommon;
|
window.$crudCommon = crudCommon;
|
||||||
debug();
|
debug();
|
||||||
@@ -61,6 +63,7 @@ app.component('codeSetting', codeSetting);
|
|||||||
app.component('formSetting', formSetting);
|
app.component('formSetting', formSetting);
|
||||||
app.component('tenantPackage', tenantPackage);
|
app.component('tenantPackage', tenantPackage);
|
||||||
app.component('tenantDatasource', tenantDatasource);
|
app.component('tenantDatasource', tenantDatasource);
|
||||||
|
app.component('sectionCard', sectionCard);
|
||||||
app.config.globalProperties.$app = app;
|
app.config.globalProperties.$app = app;
|
||||||
app.config.globalProperties.$dayjs = dayjs;
|
app.config.globalProperties.$dayjs = dayjs;
|
||||||
app.config.globalProperties.website = website;
|
app.config.globalProperties.website = website;
|
||||||
@@ -72,6 +75,7 @@ app.use(store);
|
|||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(ElementPlus, {
|
app.use(ElementPlus, {
|
||||||
locale: messages[language],
|
locale: messages[language],
|
||||||
|
table: { showOverflowTooltip: true },
|
||||||
});
|
});
|
||||||
app.use(Avue, {
|
app.use(Avue, {
|
||||||
axios,
|
axios,
|
||||||
@@ -82,7 +86,8 @@ app.use(Avue, {
|
|||||||
searchLabelWidth: 160,
|
searchLabelWidth: 160,
|
||||||
searchMenuSpan: 24,
|
searchMenuSpan: 24,
|
||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
|
showOverflowTooltip: true,
|
||||||
viewBtnIcon: ' ',
|
viewBtnIcon: ' ',
|
||||||
editBtnIcon: ' ',
|
editBtnIcon: ' ',
|
||||||
copyBtnIcon: ' ',
|
copyBtnIcon: ' ',
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export const getCargoTypeOption = ctx => ({
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '类型',
|
label: '类型',
|
||||||
@@ -56,10 +56,10 @@ export const getCargoTypeOption = ctx => ({
|
|||||||
type: 'radio',
|
type: 'radio',
|
||||||
dataType: 'number',
|
dataType: 'number',
|
||||||
dicData: typeLevelDic,
|
dicData: typeLevelDic,
|
||||||
search: true,
|
search: false,
|
||||||
searchSpan: 6,
|
|
||||||
value: 2,
|
value: 2,
|
||||||
span: 24,
|
span: 24,
|
||||||
|
order: 100,
|
||||||
hide: true,
|
hide: true,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
editDisabled: true,
|
editDisabled: true,
|
||||||
@@ -70,20 +70,34 @@ export const getCargoTypeOption = ctx => ({
|
|||||||
label: '货物类型',
|
label: '货物类型',
|
||||||
prop: 'cargoName',
|
prop: 'cargoName',
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchSpan: 6,
|
||||||
|
searchOrder: 2,
|
||||||
|
order: 70,
|
||||||
|
placeholder: '请输入',
|
||||||
maxlength: 50,
|
maxlength: 50,
|
||||||
showWordLimit: true,
|
showWordLimit: true,
|
||||||
showOverflowTooltip: true,
|
showOverflowTooltip: true,
|
||||||
rules: [{ validator: validateCargoName, trigger: 'blur' }],
|
rules: [
|
||||||
|
{ required: true, message: '请输入货物类型名称', trigger: 'blur' },
|
||||||
|
{ validator: validateCargoName, trigger: 'blur' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '货物类型编码',
|
label: '货物类型编码',
|
||||||
prop: 'cargoCode',
|
prop: 'cargoCode',
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
search: true,
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
searchSpan: 6,
|
searchSpan: 6,
|
||||||
|
searchOrder: 1,
|
||||||
maxlength: 4,
|
maxlength: 4,
|
||||||
|
order: 60,
|
||||||
|
placeholder: '请输入',
|
||||||
editDisabled: true,
|
editDisabled: true,
|
||||||
rules: [
|
rules: [
|
||||||
|
{ required: true, message: '请输入货物类型编码', trigger: 'blur' },
|
||||||
{
|
{
|
||||||
validator: (rule, value, callback) => {
|
validator: (rule, value, callback) => {
|
||||||
const form = ctx.form || {};
|
const form = ctx.form || {};
|
||||||
@@ -115,6 +129,8 @@ export const getCargoTypeOption = ctx => ({
|
|||||||
hide: true,
|
hide: true,
|
||||||
display: false,
|
display: false,
|
||||||
span: 12,
|
span: 12,
|
||||||
|
order: 90,
|
||||||
|
placeholder: '请输入',
|
||||||
rules: [{ required: true, message: '请选择上级货物类型', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择上级货物类型', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -128,16 +144,19 @@ export const getCargoTypeOption = ctx => ({
|
|||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '上级货物编码',
|
label: '上级货物类型编码',
|
||||||
prop: 'parentCargoCode',
|
prop: 'parentCargoCode',
|
||||||
slot: true,
|
slot: true,
|
||||||
readonly: true,
|
readonly: true,
|
||||||
editDisabled: true,
|
editDisabled: true,
|
||||||
|
addDisabled: true,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
display: false,
|
display: false,
|
||||||
span: 12,
|
span: 12,
|
||||||
|
order: 80,
|
||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
|
placeholder: '请输入',
|
||||||
rules: [{ required: true, message: '请选择上级货物类型', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择上级货物类型', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -156,6 +175,7 @@ export const getCargoTypeOption = ctx => ({
|
|||||||
minRows: 4,
|
minRows: 4,
|
||||||
span: 24,
|
span: 24,
|
||||||
minWidth: 180,
|
minWidth: 180,
|
||||||
|
placeholder: '请输入',
|
||||||
maxlength: 200,
|
maxlength: 200,
|
||||||
showWordLimit: true,
|
showWordLimit: true,
|
||||||
overHidden: true,
|
overHidden: true,
|
||||||
|
|||||||
@@ -27,18 +27,154 @@ export const createOption = () => ({
|
|||||||
delBtn: false,
|
delBtn: false,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuFixed: 'right',
|
||||||
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
|
{
|
||||||
|
label: '地址名称',
|
||||||
|
prop: 'addressName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 8,
|
||||||
|
span: 24,
|
||||||
|
minWidth: 150,
|
||||||
|
showOverflowTooltip: true,
|
||||||
|
placeholder: '请输入',
|
||||||
|
maxlength: 100,
|
||||||
|
showWordLimit: true,
|
||||||
|
rules: [
|
||||||
|
{ required: true, message: '请输入地址名称', trigger: 'blur' },
|
||||||
|
{ max: 100, message: '地址名称不能超过100个字', trigger: 'blur' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '地址编号',
|
||||||
|
prop: 'addressCode',
|
||||||
|
minWidth: 120,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '类型',
|
label: '类型',
|
||||||
prop: 'addressType',
|
prop: 'addressType',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 7,
|
||||||
span: 24,
|
span: 24,
|
||||||
|
minWidth: 140,
|
||||||
dicData: addressTypeOptions,
|
dicData: addressTypeOptions,
|
||||||
rules: [{ required: true, message: '请选择类型', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择类型', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '站点编码',
|
||||||
|
prop: 'siteCodeDisplay',
|
||||||
|
search: false,
|
||||||
|
minWidth: 120,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '详细地址',
|
||||||
|
prop: 'detailAddress',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 5,
|
||||||
|
formslot: true,
|
||||||
|
type: 'textarea',
|
||||||
|
minRows: 3,
|
||||||
|
span: 24,
|
||||||
|
minWidth: 220,
|
||||||
|
showOverflowTooltip: true,
|
||||||
|
rules: [
|
||||||
|
{ required: true, message: '请输入详细地址', trigger: 'blur' },
|
||||||
|
{ max: 255, message: '详细地址不能超过255个字', trigger: 'blur' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '经度',
|
||||||
|
prop: 'longitude',
|
||||||
|
minWidth: 120,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '纬度',
|
||||||
|
prop: 'latitude',
|
||||||
|
minWidth: 120,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '行政区划',
|
||||||
|
prop: 'regionName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 4,
|
||||||
|
display: false,
|
||||||
|
minWidth: 150,
|
||||||
|
rules: [{ required: true, message: '请选择行政区划', trigger: 'change' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '联系人',
|
||||||
|
prop: 'contactName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 2,
|
||||||
|
minWidth: 110,
|
||||||
|
placeholder: '请输入',
|
||||||
|
maxlength: 50,
|
||||||
|
rules: [{ max: 50, message: '联系人不能超过50个字', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '联系方式',
|
||||||
|
prop: 'contactPhone',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 1,
|
||||||
|
minWidth: 130,
|
||||||
|
placeholder: '请输入',
|
||||||
|
maxlength: 20,
|
||||||
|
rules: [{ max: 20, message: '联系方式不能超过20个字', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '组织',
|
||||||
|
prop: 'deptName',
|
||||||
|
minWidth: 150,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '备注',
|
||||||
|
prop: 'remark',
|
||||||
|
type: 'textarea',
|
||||||
|
minRows: 4,
|
||||||
|
span: 24,
|
||||||
|
minWidth: 160,
|
||||||
|
overHidden: true,
|
||||||
|
showOverflowTooltip: true,
|
||||||
|
placeholder: '请输入',
|
||||||
|
maxlength: 200,
|
||||||
|
showWordLimit: true,
|
||||||
|
rules: [{ max: 200, message: '备注不能超过200个字', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '更新时间',
|
||||||
|
prop: 'updateTime',
|
||||||
|
type: 'datetime',
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
width: 180,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '创建时间',
|
||||||
|
prop: 'createTime',
|
||||||
|
type: 'datetime',
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
width: 180,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '港口',
|
label: '港口',
|
||||||
prop: 'portId',
|
prop: 'portId',
|
||||||
@@ -75,133 +211,24 @@ export const createOption = () => ({
|
|||||||
span: 24,
|
span: 24,
|
||||||
rules: [{ required: true, message: '请选择机场标准名称', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择机场标准名称', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '地址名称',
|
|
||||||
prop: 'addressName',
|
|
||||||
search: true,
|
|
||||||
span: 24,
|
|
||||||
minWidth: 150,
|
|
||||||
maxlength: 100,
|
|
||||||
showWordLimit: true,
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: '请输入地址名称', trigger: 'blur' },
|
|
||||||
{ max: 100, message: '地址名称不能超过100个字', trigger: 'blur' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '地址编号',
|
|
||||||
prop: 'addressCode',
|
|
||||||
minWidth: 120,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '站点编码',
|
|
||||||
prop: 'siteCodeDisplay',
|
|
||||||
search: false,
|
|
||||||
minWidth: 120,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '站点编码',
|
label: '站点编码',
|
||||||
prop: 'siteCode',
|
prop: 'siteCode',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 6,
|
||||||
hide: true,
|
hide: true,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '行政区划',
|
|
||||||
prop: 'regionName',
|
|
||||||
search: true,
|
|
||||||
display: false,
|
|
||||||
minWidth: 150,
|
|
||||||
rules: [{ required: true, message: '请选择行政区划', trigger: 'change' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '详细地址',
|
|
||||||
prop: 'detailAddress',
|
|
||||||
search: true,
|
|
||||||
formslot: true,
|
|
||||||
type: 'textarea',
|
|
||||||
minRows: 3,
|
|
||||||
span: 24,
|
|
||||||
minWidth: 220,
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: '请输入详细地址', trigger: 'blur' },
|
|
||||||
{ max: 255, message: '详细地址不能超过255个字', trigger: 'blur' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '组织',
|
label: '组织',
|
||||||
prop: 'deptId',
|
prop: 'deptId',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 3,
|
||||||
hide: true,
|
hide: true,
|
||||||
display: false,
|
display: false,
|
||||||
dicData: [],
|
dicData: [],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '组织',
|
|
||||||
prop: 'deptName',
|
|
||||||
minWidth: 150,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '联系人',
|
|
||||||
prop: 'contactName',
|
|
||||||
search: true,
|
|
||||||
minWidth: 110,
|
|
||||||
maxlength: 50,
|
|
||||||
rules: [{ max: 50, message: '联系人不能超过50个字', trigger: 'blur' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '联系方式',
|
|
||||||
prop: 'contactPhone',
|
|
||||||
search: true,
|
|
||||||
minWidth: 130,
|
|
||||||
maxlength: 20,
|
|
||||||
rules: [{ max: 20, message: '联系方式不能超过20个字', trigger: 'blur' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '备注',
|
|
||||||
prop: 'remark',
|
|
||||||
type: 'textarea',
|
|
||||||
minRows: 4,
|
|
||||||
span: 24,
|
|
||||||
hide: true,
|
|
||||||
maxlength: 200,
|
|
||||||
showWordLimit: true,
|
|
||||||
rules: [{ max: 200, message: '备注不能超过200个字', trigger: 'blur' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '更新人',
|
|
||||||
prop: 'updateUserName',
|
|
||||||
minWidth: 120,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '更新时间',
|
|
||||||
prop: 'updateTime',
|
|
||||||
type: 'datetime',
|
|
||||||
format: 'YYYY-MM-DD HH:mm:ss',
|
|
||||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
|
||||||
minWidth: 160,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '创建时间',
|
|
||||||
prop: 'createTime',
|
|
||||||
type: 'datetime',
|
|
||||||
format: 'YYYY-MM-DD HH:mm:ss',
|
|
||||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
|
||||||
minWidth: 160,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,6 +6,15 @@ import {
|
|||||||
textRule,
|
textRule,
|
||||||
} from './common';
|
} 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 [];
|
||||||
|
};
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
title: '常用货物',
|
title: '常用货物',
|
||||||
permission: 'common_cargo',
|
permission: 'common_cargo',
|
||||||
@@ -17,12 +26,29 @@ export const config = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const option = createCrudOption([
|
export const option = createCrudOption([
|
||||||
|
{
|
||||||
|
label: '货物名称',
|
||||||
|
prop: 'cargoName',
|
||||||
|
minWidth: 150,
|
||||||
|
placeholder: '请输入',
|
||||||
|
rules: textRule('货物名称', 100, true),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '货物编号',
|
||||||
|
prop: 'cargoCode',
|
||||||
|
formslot: true,
|
||||||
|
minWidth: 120,
|
||||||
|
maxlength: 20,
|
||||||
|
showWordLimit: true,
|
||||||
|
rules: [
|
||||||
|
{ required: true, message: '请输入货物编号', trigger: 'blur' },
|
||||||
|
{ max: 20, message: '货物编号不能超过20个字符', trigger: 'blur' },
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '一级货物类型',
|
label: '一级货物类型',
|
||||||
prop: 'firstCargoTypeName',
|
prop: 'firstCargoTypeName',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
search: true,
|
|
||||||
searchOrder: 3,
|
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
editDisabled: true,
|
editDisabled: true,
|
||||||
rules: [{ required: true, message: '请选择一级货物类型', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择一级货物类型', trigger: 'change' }],
|
||||||
@@ -39,8 +65,6 @@ export const option = createCrudOption([
|
|||||||
label: '二级货物类型',
|
label: '二级货物类型',
|
||||||
prop: 'secondCargoTypeName',
|
prop: 'secondCargoTypeName',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
search: true,
|
|
||||||
searchOrder: 4,
|
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
editDisabled: true,
|
editDisabled: true,
|
||||||
rules: [{ required: true, message: '请选择二级货物类型', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择二级货物类型', trigger: 'change' }],
|
||||||
@@ -48,47 +72,118 @@ export const option = createCrudOption([
|
|||||||
{
|
{
|
||||||
label: '二级货物类型编码',
|
label: '二级货物类型编码',
|
||||||
prop: 'secondCargoTypeCode',
|
prop: 'secondCargoTypeCode',
|
||||||
hide: true,
|
|
||||||
display: false,
|
display: false,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisabled: true,
|
editDisabled: true,
|
||||||
},
|
},
|
||||||
|
// 搜索字段与表格、表单字段独立,避免筛选配置影响数据展示和编辑布局。
|
||||||
{
|
{
|
||||||
label: '货物名称',
|
label: '货物名称',
|
||||||
prop: 'cargoName',
|
prop: 'searchCargoName',
|
||||||
|
searchProp: 'cargoName',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 1,
|
searchOrder: 5,
|
||||||
minWidth: 150,
|
searchPlaceholder: '请输入',
|
||||||
rules: textRule('货物名称', 100, true),
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '货物编号',
|
label: '货物编号',
|
||||||
prop: 'cargoCode',
|
prop: 'searchCargoCode',
|
||||||
formslot: true,
|
searchProp: 'cargoCode',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 4,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '一级货物类型',
|
||||||
|
prop: 'searchFirstCargoTypeName',
|
||||||
|
searchProp: 'firstCargoTypeName',
|
||||||
|
type: 'select',
|
||||||
|
searchType: 'select',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 3,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
dicUrl: '/blade-system/cargo-type/list?current=1&size=9999&typeLevel=1',
|
||||||
|
dicFormatter: listDicFormatter,
|
||||||
|
props: {
|
||||||
|
label: 'cargoName',
|
||||||
|
value: 'cargoName',
|
||||||
|
},
|
||||||
|
filterable: true,
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '二级货物类型',
|
||||||
|
prop: 'searchSecondCargoTypeName',
|
||||||
|
searchProp: 'secondCargoTypeName',
|
||||||
|
type: 'select',
|
||||||
|
searchType: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 2,
|
searchOrder: 2,
|
||||||
minWidth: 120,
|
searchPlaceholder: '请选择',
|
||||||
maxlength: 20,
|
dicUrl: '/blade-system/cargo-type/list?current=1&size=9999&typeLevel=2',
|
||||||
showWordLimit: true,
|
dicFormatter: listDicFormatter,
|
||||||
rules: [
|
props: {
|
||||||
{ required: true, message: '请输入货物编号', trigger: 'blur' },
|
label: 'cargoName',
|
||||||
{ max: 20, message: '货物编号不能超过20个字符', trigger: 'blur' },
|
value: 'cargoName',
|
||||||
],
|
},
|
||||||
|
filterable: true,
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '组织',
|
label: '组织',
|
||||||
prop: 'deptName',
|
prop: 'searchDeptId',
|
||||||
|
searchProp: 'deptId',
|
||||||
|
type: 'select',
|
||||||
|
searchType: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 5,
|
searchOrder: 1,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
dicData: [],
|
||||||
|
props: {
|
||||||
|
label: 'label',
|
||||||
|
value: 'value',
|
||||||
|
},
|
||||||
|
filterable: true,
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '包装品牌',
|
||||||
|
prop: 'packageBrand',
|
||||||
|
slot: true,
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '品牌',
|
label: '品牌',
|
||||||
prop: 'brand',
|
prop: 'brand',
|
||||||
search: false,
|
search: false,
|
||||||
|
hide: true,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
|
placeholder: '请输入',
|
||||||
rules: textRule('品牌', 50),
|
rules: textRule('品牌', 50),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -96,10 +191,25 @@ export const option = createCrudOption([
|
|||||||
prop: 'packageType',
|
prop: 'packageType',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
dicData: packageOptions,
|
dicData: packageOptions,
|
||||||
|
hide: true,
|
||||||
minWidth: 100,
|
minWidth: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '货值',
|
label: '规格',
|
||||||
|
prop: 'specification',
|
||||||
|
minWidth: 120,
|
||||||
|
placeholder: '请输入',
|
||||||
|
rules: textRule('规格', 50),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '型号',
|
||||||
|
prop: 'model',
|
||||||
|
minWidth: 120,
|
||||||
|
placeholder: '请输入',
|
||||||
|
rules: textRule('型号', 50),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '单价',
|
||||||
prop: 'cargoValue',
|
prop: 'cargoValue',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
@@ -129,29 +239,26 @@ export const option = createCrudOption([
|
|||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '规格',
|
label: '尺寸',
|
||||||
prop: 'specification',
|
prop: 'sizeText',
|
||||||
minWidth: 120,
|
|
||||||
rules: textRule('规格', 50),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '型号',
|
|
||||||
prop: 'model',
|
|
||||||
minWidth: 120,
|
|
||||||
rules: textRule('型号', 50),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '说明',
|
|
||||||
prop: 'descriptionOne',
|
|
||||||
minWidth: 160,
|
|
||||||
rules: textRule('说明', 100),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '数据来源',
|
|
||||||
prop: 'dataSource',
|
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
|
rules: textRule('尺寸', 100),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '其他说明1',
|
||||||
|
prop: 'descriptionOne',
|
||||||
|
minWidth: 160,
|
||||||
|
placeholder: '请输入',
|
||||||
|
rules: textRule('其他说明1', 100),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '其他说明2',
|
||||||
|
prop: 'descriptionTwo',
|
||||||
|
minWidth: 160,
|
||||||
|
placeholder: '请输入',
|
||||||
|
rules: textRule('其他说明2', 100),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '备注',
|
label: '备注',
|
||||||
@@ -159,12 +266,25 @@ export const option = createCrudOption([
|
|||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
minRows: 4,
|
minRows: 4,
|
||||||
span: 24,
|
span: 24,
|
||||||
hide: true,
|
|
||||||
maxlength: 200,
|
maxlength: 200,
|
||||||
showWordLimit: true,
|
showWordLimit: true,
|
||||||
|
placeholder: '请输入',
|
||||||
rules: textRule('备注', 200),
|
rules: textRule('备注', 200),
|
||||||
},
|
},
|
||||||
...auditColumns,
|
{
|
||||||
|
label: '组织',
|
||||||
|
prop: 'deptName',
|
||||||
|
minWidth: 150,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
...auditColumns
|
||||||
|
.filter(column => ['updateTime', 'createTime'].includes(column.prop))
|
||||||
|
.sort(
|
||||||
|
(first, second) =>
|
||||||
|
['updateTime', 'createTime'].indexOf(first.prop) -
|
||||||
|
['updateTime', 'createTime'].indexOf(second.prop)
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const excelOption = {
|
export const excelOption = {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ export const config = {
|
|||||||
permission: 'common_route',
|
permission: 'common_route',
|
||||||
exportUrl: '/blade-transport/common-route/export-common-route',
|
exportUrl: '/blade-transport/common-route/export-common-route',
|
||||||
exportName: '常用线路',
|
exportName: '常用线路',
|
||||||
|
importUrl: '/blade-transport/common-route/import-common-route',
|
||||||
|
templateUrl: '/blade-transport/common-route/export-template',
|
||||||
enableAllDept: false,
|
enableAllDept: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -12,17 +14,14 @@ export const option = createCrudOption([
|
|||||||
{
|
{
|
||||||
label: '线路名称',
|
label: '线路名称',
|
||||||
prop: 'routeName',
|
prop: 'routeName',
|
||||||
search: true,
|
span: 12,
|
||||||
searchOrder: 1,
|
|
||||||
span: 24,
|
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
|
overHidden: true,
|
||||||
rules: textRule('线路名称', 100, true),
|
rules: textRule('线路名称', 100, true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '线路编号',
|
label: '线路编号',
|
||||||
prop: 'routeCode',
|
prop: 'routeCode',
|
||||||
search: true,
|
|
||||||
searchOrder: 2,
|
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisabled: true,
|
editDisabled: true,
|
||||||
@@ -30,8 +29,6 @@ export const option = createCrudOption([
|
|||||||
{
|
{
|
||||||
label: '发货地',
|
label: '发货地',
|
||||||
prop: 'departureName',
|
prop: 'departureName',
|
||||||
search: true,
|
|
||||||
searchOrder: 3,
|
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
@@ -40,10 +37,9 @@ export const option = createCrudOption([
|
|||||||
label: '发货地址',
|
label: '发货地址',
|
||||||
prop: 'departureAddress',
|
prop: 'departureAddress',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
search: true,
|
|
||||||
searchOrder: 4,
|
|
||||||
span: 24,
|
span: 24,
|
||||||
minWidth: 220,
|
minWidth: 220,
|
||||||
|
overHidden: true,
|
||||||
rules: textRule('发货地址', 255, true),
|
rules: textRule('发货地址', 255, true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -53,6 +49,8 @@ export const option = createCrudOption([
|
|||||||
precision: 6,
|
precision: 6,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
hide: true,
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '发货纬度',
|
label: '发货纬度',
|
||||||
@@ -61,6 +59,8 @@ export const option = createCrudOption([
|
|||||||
precision: 6,
|
precision: 6,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
hide: true,
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '发货联系人',
|
label: '发货联系人',
|
||||||
@@ -77,8 +77,6 @@ export const option = createCrudOption([
|
|||||||
{
|
{
|
||||||
label: '收货地',
|
label: '收货地',
|
||||||
prop: 'arrivalName',
|
prop: 'arrivalName',
|
||||||
search: true,
|
|
||||||
searchOrder: 5,
|
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
@@ -87,10 +85,9 @@ export const option = createCrudOption([
|
|||||||
label: '收货地址',
|
label: '收货地址',
|
||||||
prop: 'arrivalAddress',
|
prop: 'arrivalAddress',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
search: true,
|
|
||||||
searchOrder: 6,
|
|
||||||
span: 24,
|
span: 24,
|
||||||
minWidth: 220,
|
minWidth: 220,
|
||||||
|
overHidden: true,
|
||||||
rules: textRule('收货地址', 255, true),
|
rules: textRule('收货地址', 255, true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -100,6 +97,8 @@ export const option = createCrudOption([
|
|||||||
precision: 6,
|
precision: 6,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
hide: true,
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '收货纬度',
|
label: '收货纬度',
|
||||||
@@ -108,6 +107,8 @@ export const option = createCrudOption([
|
|||||||
precision: 6,
|
precision: 6,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
hide: true,
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '收货联系人',
|
label: '收货联系人',
|
||||||
@@ -121,25 +122,160 @@ export const option = createCrudOption([
|
|||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
rules: [phoneRule('收货联系方式'), ...textRule('收货联系方式', 50)],
|
rules: [phoneRule('收货联系方式'), ...textRule('收货联系方式', 50)],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '组织',
|
|
||||||
prop: 'deptName',
|
|
||||||
search: true,
|
|
||||||
searchOrder: 7,
|
|
||||||
minWidth: 150,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '备注',
|
label: '备注',
|
||||||
prop: 'remark',
|
prop: 'remark',
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
minRows: 4,
|
minRows: 4,
|
||||||
span: 24,
|
span: 24,
|
||||||
hide: true,
|
minWidth: 180,
|
||||||
maxlength: 500,
|
maxlength: 500,
|
||||||
showWordLimit: true,
|
showWordLimit: true,
|
||||||
rules: textRule('备注', 500),
|
rules: textRule('备注', 500),
|
||||||
},
|
},
|
||||||
...auditColumns,
|
{
|
||||||
|
label: '组织',
|
||||||
|
prop: 'deptName',
|
||||||
|
minWidth: 150,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
// 搜索字段独立于表格和表单字段,避免筛选配置影响数据展示和编辑布局。
|
||||||
|
{
|
||||||
|
label: '线路名称',
|
||||||
|
prop: 'searchRouteName',
|
||||||
|
searchProp: 'routeName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 7,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '线路编号',
|
||||||
|
prop: 'searchRouteCode',
|
||||||
|
searchProp: 'routeCode',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 6,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '发货地',
|
||||||
|
prop: 'searchDepartureName',
|
||||||
|
searchProp: 'departureName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 5,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '发货地址',
|
||||||
|
prop: 'searchDepartureAddress',
|
||||||
|
searchProp: 'departureAddress',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 4,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '收货地',
|
||||||
|
prop: 'searchArrivalName',
|
||||||
|
searchProp: 'arrivalName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 3,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '收货地址',
|
||||||
|
prop: 'searchArrivalAddress',
|
||||||
|
searchProp: 'arrivalAddress',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 2,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '组织',
|
||||||
|
prop: 'searchDeptId',
|
||||||
|
searchProp: 'deptId',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 1,
|
||||||
|
searchType: 'cascader',
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
dicData: [],
|
||||||
|
props: {
|
||||||
|
label: 'label',
|
||||||
|
value: 'value',
|
||||||
|
children: 'children',
|
||||||
|
},
|
||||||
|
checkStrictly: true,
|
||||||
|
emitPath: false,
|
||||||
|
showAllLevels: false,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
...auditColumns
|
||||||
|
.filter(column => column.prop !== 'createUserName')
|
||||||
|
.map(column =>
|
||||||
|
['createTime', 'updateTime'].includes(column.prop) ? { ...column, minWidth: 190 } : column
|
||||||
|
)
|
||||||
|
.sort(
|
||||||
|
(first, second) =>
|
||||||
|
['updateUserName', 'updateTime', 'createTime'].indexOf(first.prop) -
|
||||||
|
['updateUserName', 'updateTime', 'createTime'].indexOf(second.prop)
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
export const excelOption = {
|
||||||
|
submitBtn: false,
|
||||||
|
emptyBtn: false,
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '导入模板',
|
||||||
|
prop: 'excelTemplate',
|
||||||
|
formslot: true,
|
||||||
|
span: 24,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Excel文件',
|
||||||
|
prop: 'excelFile',
|
||||||
|
type: 'upload',
|
||||||
|
drag: true,
|
||||||
|
loadText: '模板上传中,请稍等',
|
||||||
|
span: 24,
|
||||||
|
propsHttp: {
|
||||||
|
res: 'data',
|
||||||
|
},
|
||||||
|
tip: '请上传 .xls,.xlsx 标准格式文件',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|||||||
@@ -87,8 +87,10 @@ export const approvalStatusOptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const effectiveTypeOptions = [
|
export const effectiveTypeOptions = [
|
||||||
{ label: '临时', value: 'temporary' },
|
{ label: '未生效', value: 'not_effective' },
|
||||||
{ label: '正式', value: 'formal' },
|
{ label: '临时生效', value: 'temporary_effective' },
|
||||||
|
{ label: '正式生效', value: 'formal_effective' },
|
||||||
|
{ label: '已过期', value: 'expired' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const businessTypeOptions = [
|
export const businessTypeOptions = [
|
||||||
@@ -202,7 +204,8 @@ export const createCrudOption = columns => ({
|
|||||||
delBtn: false,
|
delBtn: false,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
|
showOverflowTooltip: true,
|
||||||
column: columns,
|
column: columns,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,18 @@ import {
|
|||||||
createCrudOption,
|
createCrudOption,
|
||||||
effectiveTypeOptions,
|
effectiveTypeOptions,
|
||||||
selectRule,
|
selectRule,
|
||||||
settlementModeOptions,
|
|
||||||
signTypeOptions,
|
signTypeOptions,
|
||||||
textRule,
|
textRule,
|
||||||
} from './common';
|
} from './common';
|
||||||
|
|
||||||
|
const contractSettlementModeOptions = [
|
||||||
|
{ label: '现结', value: '现结' },
|
||||||
|
{ label: '日结', value: '日结' },
|
||||||
|
{ label: '周结', value: '周结' },
|
||||||
|
{ label: '月结', value: '月结' },
|
||||||
|
{ label: '按固定天数周期', value: '按固定天数周期' },
|
||||||
|
];
|
||||||
|
|
||||||
const listDicFormatter = res => {
|
const listDicFormatter = res => {
|
||||||
const data = res?.data || res;
|
const data = res?.data || res;
|
||||||
if (Array.isArray(data)) return data;
|
if (Array.isArray(data)) return data;
|
||||||
@@ -25,7 +32,13 @@ export const config = {
|
|||||||
permission: 'contract_manage',
|
permission: 'contract_manage',
|
||||||
exportUrl: '/blade-transport/contract-manage/export-contract-manage',
|
exportUrl: '/blade-transport/contract-manage/export-contract-manage',
|
||||||
exportName: '合同管理',
|
exportName: '合同管理',
|
||||||
enableAllDept: false,
|
defaultForm: {
|
||||||
|
contractCategory: '客户合同',
|
||||||
|
},
|
||||||
|
projectPlaceholder: '请选择',
|
||||||
|
organizationPlaceholder: '请选择',
|
||||||
|
enableAllDept: true,
|
||||||
|
allDeptReadonly: false,
|
||||||
batchDelete: false,
|
batchDelete: false,
|
||||||
enableContractForm: true,
|
enableContractForm: true,
|
||||||
enableProjectSelect: true,
|
enableProjectSelect: true,
|
||||||
@@ -39,6 +52,7 @@ export const config = {
|
|||||||
enableChangeRecord: true,
|
enableChangeRecord: true,
|
||||||
enableOrganizationSelect: true,
|
enableOrganizationSelect: true,
|
||||||
enableContractCreateActions: true,
|
enableContractCreateActions: true,
|
||||||
|
enableContractExpiryTags: true,
|
||||||
actions: ['copy'],
|
actions: ['copy'],
|
||||||
statusProp: 'approvalStatus',
|
statusProp: 'approvalStatus',
|
||||||
statusTextProp: 'approvalStatusName',
|
statusTextProp: 'approvalStatusName',
|
||||||
@@ -63,9 +77,25 @@ export const config = {
|
|||||||
label: '撤回',
|
label: '撤回',
|
||||||
statusProp: 'approvalStatus',
|
statusProp: 'approvalStatus',
|
||||||
status: ['reviewing'],
|
status: ['reviewing'],
|
||||||
stage: ['temporary'],
|
stage: ['temporary', 'formal'],
|
||||||
permission: 'contract_manage_withdraw',
|
permission: 'contract_manage_withdraw',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
action: 'approve',
|
||||||
|
label: '通过',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
stage: ['temporary', 'formal'],
|
||||||
|
permission: 'contract_manage_approve',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'reject',
|
||||||
|
label: '驳回',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
stage: ['temporary', 'formal'],
|
||||||
|
permission: 'contract_manage_reject',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
action: 'submitFormal',
|
action: 'submitFormal',
|
||||||
label: '重新提交转正',
|
label: '重新提交转正',
|
||||||
@@ -143,16 +173,18 @@ export const option = createCrudOption([
|
|||||||
prop: 'contractNo',
|
prop: 'contractNo',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 6,
|
searchOrder: 6,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
order: 185,
|
order: 185,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
placeholder: '不填写,则系统自动生成',
|
placeholder: '不填写,则系统自动生成',
|
||||||
minWidth: 160,
|
minWidth: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '合同名称',
|
label: '合同名称',
|
||||||
prop: 'contractName',
|
prop: 'contractName',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 7,
|
searchOrder: 7,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
order: 180,
|
order: 180,
|
||||||
minWidth: 180,
|
minWidth: 180,
|
||||||
rules: textRule('合同名称', 100, true),
|
rules: textRule('合同名称', 100, true),
|
||||||
@@ -163,6 +195,7 @@ export const option = createCrudOption([
|
|||||||
search: true,
|
search: true,
|
||||||
searchOrder: 8,
|
searchOrder: 8,
|
||||||
searchType: 'select',
|
searchType: 'select',
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
order: 140,
|
order: 140,
|
||||||
dicUrl: '/blade-transport/project-apply/list?current=1&size=9999',
|
dicUrl: '/blade-transport/project-apply/list?current=1&size=9999',
|
||||||
@@ -187,6 +220,7 @@ export const option = createCrudOption([
|
|||||||
search: true,
|
search: true,
|
||||||
searchOrder: 3,
|
searchOrder: 3,
|
||||||
searchType: 'cascader',
|
searchType: 'cascader',
|
||||||
|
searchPlaceholder: '全部',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
order: 120,
|
order: 120,
|
||||||
dicData: [],
|
dicData: [],
|
||||||
@@ -208,6 +242,7 @@ export const option = createCrudOption([
|
|||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 9,
|
searchOrder: 9,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
order: 170,
|
order: 170,
|
||||||
dicData: contractCategoryOptions,
|
dicData: contractCategoryOptions,
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
@@ -217,10 +252,8 @@ export const option = createCrudOption([
|
|||||||
label: '签约类型',
|
label: '签约类型',
|
||||||
prop: 'signType',
|
prop: 'signType',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: false,
|
||||||
searchOrder: 1,
|
|
||||||
span: 6,
|
span: 6,
|
||||||
row: true,
|
|
||||||
order: 190,
|
order: 190,
|
||||||
dicData: signTypeOptions,
|
dicData: signTypeOptions,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
@@ -232,6 +265,7 @@ export const option = createCrudOption([
|
|||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 5,
|
searchOrder: 5,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
dicData: effectiveTypeOptions,
|
dicData: effectiveTypeOptions,
|
||||||
hide: true,
|
hide: true,
|
||||||
display: false,
|
display: false,
|
||||||
@@ -241,7 +275,8 @@ export const option = createCrudOption([
|
|||||||
prop: 'partyA',
|
prop: 'partyA',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
order: 160,
|
order: 160,
|
||||||
dicUrl: '/blade-transport/customer-archive/list?current=1&size=9999&approvalStatus=approved',
|
dicUrl:
|
||||||
|
'/blade-transport/customer-archive/list?current=1&size=9999&customerType=客户&approvalStatus=approved&status=1',
|
||||||
dicFormatter: listDicFormatter,
|
dicFormatter: listDicFormatter,
|
||||||
props: {
|
props: {
|
||||||
label: 'fullName',
|
label: 'fullName',
|
||||||
@@ -256,7 +291,8 @@ export const option = createCrudOption([
|
|||||||
prop: 'partyB',
|
prop: 'partyB',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
order: 150,
|
order: 150,
|
||||||
dicUrl: '/blade-transport/customer-archive/list?current=1&size=9999&approvalStatus=approved',
|
dicUrl:
|
||||||
|
'/blade-transport/customer-archive/list?current=1&size=9999&customerType=承运商&approvalStatus=approved&status=1',
|
||||||
dicFormatter: listDicFormatter,
|
dicFormatter: listDicFormatter,
|
||||||
props: {
|
props: {
|
||||||
label: 'fullName',
|
label: 'fullName',
|
||||||
@@ -334,14 +370,14 @@ export const option = createCrudOption([
|
|||||||
rules: [{ required: true, message: '请选择签订日期', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择签订日期', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '结算方式',
|
label: '结算类型',
|
||||||
prop: 'settlementMode',
|
prop: 'settlementMode',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
dicData: settlementModeOptions,
|
dicData: contractSettlementModeOptions,
|
||||||
hide: true,
|
hide: true,
|
||||||
order: 90,
|
order: 90,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
rules: selectRule('结算方式'),
|
rules: selectRule('结算类型'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '合同格式',
|
label: '合同格式',
|
||||||
@@ -392,7 +428,7 @@ export const option = createCrudOption([
|
|||||||
type: 'datetime',
|
type: 'datetime',
|
||||||
format: 'YYYY-MM-DD HH:mm:ss',
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
minWidth: 160,
|
minWidth: 190,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
@@ -402,6 +438,7 @@ export const option = createCrudOption([
|
|||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 2,
|
searchOrder: 2,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
slot: true,
|
slot: true,
|
||||||
dicData: contractStageOptions,
|
dicData: contractStageOptions,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
@@ -414,6 +451,7 @@ export const option = createCrudOption([
|
|||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 4,
|
searchOrder: 4,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
slot: true,
|
slot: true,
|
||||||
dicData: contractApprovalStatusOptions,
|
dicData: contractApprovalStatusOptions,
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
@@ -572,3 +610,6 @@ export const option = createCrudOption([
|
|||||||
|
|
||||||
option.span = 8;
|
option.span = 8;
|
||||||
option.dialogWidth = 1480;
|
option.dialogWidth = 1480;
|
||||||
|
option.dialogTop = '10px';
|
||||||
|
option.dialogCloseBtn = true;
|
||||||
|
option.menuWidth = 320;
|
||||||
|
|||||||
@@ -6,21 +6,20 @@ import {
|
|||||||
selectRule,
|
selectRule,
|
||||||
textRule,
|
textRule,
|
||||||
} from './common';
|
} from './common';
|
||||||
import { applyTableMenuWidth } from '@/utils/table-menu';
|
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
title: '过程配置',
|
title: '过程配置',
|
||||||
permission: 'process_config',
|
permission: 'process_config',
|
||||||
exportUrl: '/blade-transport/process-config/export-process-config',
|
exportUrl: '/blade-transport/process-config/export-process-config',
|
||||||
exportName: '过程配置',
|
exportName: '过程配置',
|
||||||
enableAllDept: false,
|
enableAllDept: true,
|
||||||
actions: ['copy', 'enable', 'disable'],
|
actions: ['copy', 'enable', 'disable'],
|
||||||
statusProp: 'status',
|
statusProp: 'status',
|
||||||
statusTextProp: 'statusName',
|
statusTextProp: 'statusName',
|
||||||
deleteStatus: [0, 2],
|
deleteStatus: [0, 2],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const option = applyTableMenuWidth({
|
export const option = {
|
||||||
...createCrudOption([
|
...createCrudOption([
|
||||||
{
|
{
|
||||||
label: '',
|
label: '',
|
||||||
@@ -29,21 +28,13 @@ export const option = applyTableMenuWidth({
|
|||||||
span: 24,
|
span: 24,
|
||||||
hide: true,
|
hide: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '配置编号',
|
|
||||||
prop: 'configCode',
|
|
||||||
search: true,
|
|
||||||
searchOrder: 4,
|
|
||||||
minWidth: 130,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
editDisabled: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '配置名称',
|
label: '配置名称',
|
||||||
prop: 'configName',
|
prop: 'configName',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 6,
|
searchOrder: 6,
|
||||||
|
searchSpan: 6,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
span: 12,
|
span: 12,
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
@@ -51,13 +42,16 @@ export const option = applyTableMenuWidth({
|
|||||||
rules: textRule('配置名称', 100, true),
|
rules: textRule('配置名称', 100, true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '项目ID集合',
|
label: '配置编号',
|
||||||
prop: 'projectIds',
|
prop: 'configCode',
|
||||||
hide: true,
|
search: true,
|
||||||
display: false,
|
searchOrder: 4,
|
||||||
|
searchSpan: 6,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
minWidth: 130,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
rules: textRule('项目ID集合', 1000, true),
|
editDisabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '项目',
|
label: '项目',
|
||||||
@@ -65,7 +59,9 @@ export const option = applyTableMenuWidth({
|
|||||||
formslot: true,
|
formslot: true,
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 5,
|
searchOrder: 5,
|
||||||
searchType: 'select',
|
searchType: 'input',
|
||||||
|
searchSpan: 6,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
minRows: 2,
|
minRows: 2,
|
||||||
span: 12,
|
span: 12,
|
||||||
@@ -77,48 +73,98 @@ export const option = applyTableMenuWidth({
|
|||||||
rules: textRule('项目', 1000, true),
|
rules: textRule('项目', 1000, true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '包含过程节点',
|
label: '过程节点',
|
||||||
prop: 'includedNodes',
|
prop: 'includedNodes',
|
||||||
search: true,
|
|
||||||
searchOrder: 3,
|
|
||||||
type: 'select',
|
type: 'select',
|
||||||
multiple: true,
|
multiple: true,
|
||||||
dicData: nodeOptions,
|
dicData: nodeOptions,
|
||||||
minWidth: 180,
|
minWidth: 260,
|
||||||
rules: selectRule('包含过程节点'),
|
overHidden: false,
|
||||||
|
slot: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
rules: selectRule('过程节点'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '默认完成运输天数',
|
label: '默认运输完成天数',
|
||||||
prop: 'defaultFinishDays',
|
prop: 'defaultFinishDays',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
type: 'number',
|
type: 'number',
|
||||||
min: 1,
|
min: 0,
|
||||||
max: 999,
|
max: 999,
|
||||||
span: 12,
|
span: 12,
|
||||||
|
minWidth: 170,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '备注',
|
||||||
|
prop: 'remark',
|
||||||
|
type: 'textarea',
|
||||||
|
minRows: 4,
|
||||||
|
span: 24,
|
||||||
|
minWidth: 180,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
maxlength: 500,
|
||||||
|
showWordLimit: true,
|
||||||
|
rules: textRule('备注', 500),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '组织',
|
||||||
|
prop: 'deptName',
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
|
...auditColumns
|
||||||
|
.filter(column => ['updateTime', 'createTime'].includes(column.prop))
|
||||||
|
.map(column => ({ ...column, minWidth: 190 }))
|
||||||
|
.sort(
|
||||||
|
(first, second) =>
|
||||||
|
['updateTime', 'createTime'].indexOf(first.prop) -
|
||||||
|
['updateTime', 'createTime'].indexOf(second.prop)
|
||||||
|
),
|
||||||
|
{
|
||||||
|
label: '项目ID集合',
|
||||||
|
prop: 'projectIds',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
rules: textRule('项目ID集合', 1000, true),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '状态',
|
label: '状态',
|
||||||
prop: 'status',
|
prop: 'status',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 1,
|
searchOrder: 1,
|
||||||
|
searchSpan: 6,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
dicData: processStatusOptions,
|
dicData: processStatusOptions,
|
||||||
slot: true,
|
slot: true,
|
||||||
minWidth: 100,
|
hide: true,
|
||||||
|
fixed: false,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '组织',
|
label: '组织',
|
||||||
prop: 'deptName',
|
prop: 'searchDeptId',
|
||||||
|
searchProp: 'deptId',
|
||||||
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 2,
|
searchOrder: 2,
|
||||||
minWidth: 150,
|
searchSpan: 6,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
dicData: [],
|
||||||
|
filterable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '',
|
label: '',
|
||||||
@@ -127,22 +173,10 @@ export const option = applyTableMenuWidth({
|
|||||||
span: 24,
|
span: 24,
|
||||||
hide: true,
|
hide: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '备注',
|
|
||||||
prop: 'remark',
|
|
||||||
type: 'textarea',
|
|
||||||
minRows: 4,
|
|
||||||
span: 24,
|
|
||||||
hide: true,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
maxlength: 500,
|
|
||||||
showWordLimit: true,
|
|
||||||
rules: textRule('备注', 500),
|
|
||||||
},
|
|
||||||
...auditColumns,
|
|
||||||
]),
|
]),
|
||||||
|
saveBtnText: '保存',
|
||||||
|
updateBtnText: '保存',
|
||||||
dialogTop: '10px',
|
dialogTop: '10px',
|
||||||
dialogWidth: '96%',
|
dialogWidth: '96%',
|
||||||
searchSpan: 8,
|
menuWidth: 220,
|
||||||
}, 5);
|
};
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ const userDicFormatter = res => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formatUserRealName = (row, role) =>
|
||||||
|
row[`${role}RealName`] ||
|
||||||
|
row[`${role}UserRealName`] ||
|
||||||
|
row[`${role}User`]?.realName ||
|
||||||
|
row[role]?.realName ||
|
||||||
|
row[`${role}UserName`] ||
|
||||||
|
'';
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
title: '项目管理',
|
title: '项目管理',
|
||||||
permission: 'project_apply',
|
permission: 'project_apply',
|
||||||
@@ -94,8 +102,9 @@ export const option = createCrudOption([
|
|||||||
label: '立项申请单号',
|
label: '立项申请单号',
|
||||||
prop: 'applyNo',
|
prop: 'applyNo',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
searchOrder: 7,
|
searchOrder: 7,
|
||||||
minWidth: 160,
|
minWidth: 220,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisabled: true,
|
editDisabled: true,
|
||||||
},
|
},
|
||||||
@@ -110,6 +119,7 @@ export const option = createCrudOption([
|
|||||||
label: '项目名称',
|
label: '项目名称',
|
||||||
prop: 'projectName',
|
prop: 'projectName',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
searchOrder: 6,
|
searchOrder: 6,
|
||||||
minWidth: 180,
|
minWidth: 180,
|
||||||
maxlength: 50,
|
maxlength: 50,
|
||||||
@@ -128,6 +138,7 @@ export const option = createCrudOption([
|
|||||||
prop: 'projectType',
|
prop: 'projectType',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
searchOrder: 3,
|
searchOrder: 3,
|
||||||
dicData: projectTypeOptions,
|
dicData: projectTypeOptions,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
@@ -156,7 +167,7 @@ export const option = createCrudOption([
|
|||||||
label: '承办部门',
|
label: '承办部门',
|
||||||
prop: 'undertakeDeptName',
|
prop: 'undertakeDeptName',
|
||||||
search: true,
|
search: true,
|
||||||
searchLabel: '承办单位',
|
searchPlaceholder: '请输入',
|
||||||
searchOrder: 5,
|
searchOrder: 5,
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
rules: textRule('承办部门', 50, true),
|
rules: textRule('承办部门', 50, true),
|
||||||
@@ -170,6 +181,7 @@ export const option = createCrudOption([
|
|||||||
label: '项目负责人',
|
label: '项目负责人',
|
||||||
prop: 'principalUserName',
|
prop: 'principalUserName',
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
|
formatter: row => formatUserRealName(row, 'principal'),
|
||||||
rules: textRule('项目负责人', 50, true),
|
rules: textRule('项目负责人', 50, true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -177,6 +189,7 @@ export const option = createCrudOption([
|
|||||||
prop: 'principalUserId',
|
prop: 'principalUserId',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
searchOrder: 4,
|
searchOrder: 4,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
dicUrl: '/blade-system/user/user-list',
|
dicUrl: '/blade-system/user/user-list',
|
||||||
@@ -193,6 +206,7 @@ export const option = createCrudOption([
|
|||||||
prop: 'handlerUserName',
|
prop: 'handlerUserName',
|
||||||
hide: true,
|
hide: true,
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
|
formatter: row => formatUserRealName(row, 'handler'),
|
||||||
rules: textRule('项目经办人', 50, true),
|
rules: textRule('项目经办人', 50, true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -336,6 +350,7 @@ export const option = createCrudOption([
|
|||||||
prop: 'approvalStatus',
|
prop: 'approvalStatus',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
searchOrder: 2,
|
searchOrder: 2,
|
||||||
slot: true,
|
slot: true,
|
||||||
dicData: projectApprovalStatusOptions,
|
dicData: projectApprovalStatusOptions,
|
||||||
@@ -362,6 +377,7 @@ export const option = createCrudOption([
|
|||||||
prop: 'effectiveType',
|
prop: 'effectiveType',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
searchOrder: 1,
|
searchOrder: 1,
|
||||||
dicData: effectiveTypeOptions,
|
dicData: effectiveTypeOptions,
|
||||||
value: 'temporary',
|
value: 'temporary',
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ export const config = {
|
|||||||
exportName: '临时额度申请',
|
exportName: '临时额度申请',
|
||||||
enableAllDept: false,
|
enableAllDept: false,
|
||||||
enableProjectSelect: true,
|
enableProjectSelect: true,
|
||||||
|
projectQueryParams: {
|
||||||
|
temporaryCreditLimitSelectable: true,
|
||||||
|
},
|
||||||
enableAttachmentTable: true,
|
enableAttachmentTable: true,
|
||||||
enableDraftSave: true,
|
enableDraftSave: true,
|
||||||
saveAsDraft: true,
|
saveAsDraft: true,
|
||||||
@@ -108,6 +111,7 @@ export const option = {
|
|||||||
value: 'projectName',
|
value: 'projectName',
|
||||||
},
|
},
|
||||||
filterable: true,
|
filterable: true,
|
||||||
|
span: 12,
|
||||||
minWidth: 180,
|
minWidth: 180,
|
||||||
rules: textRule('项目名称', 100, true),
|
rules: textRule('项目名称', 100, true),
|
||||||
},
|
},
|
||||||
@@ -122,14 +126,16 @@ export const option = {
|
|||||||
prop: 'projectCode',
|
prop: 'projectCode',
|
||||||
hide: true,
|
hide: true,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
|
span: 12,
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
rules: textRule('项目编号', 50, true),
|
rules: textRule('项目编号', 50),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '承办部门',
|
label: '承办部门',
|
||||||
prop: 'undertakeDeptName',
|
prop: 'undertakeDeptName',
|
||||||
hide: true,
|
hide: true,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
|
span: 12,
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
rules: textRule('承办部门', 50, true),
|
rules: textRule('承办部门', 50, true),
|
||||||
},
|
},
|
||||||
@@ -138,6 +144,7 @@ export const option = {
|
|||||||
prop: 'projectFundLimit',
|
prop: 'projectFundLimit',
|
||||||
hide: true,
|
hide: true,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
|
span: 12,
|
||||||
minWidth: 200,
|
minWidth: 200,
|
||||||
rules: [nonNegativeRule('项目资金使用额度')],
|
rules: [nonNegativeRule('项目资金使用额度')],
|
||||||
},
|
},
|
||||||
@@ -146,6 +153,7 @@ export const option = {
|
|||||||
prop: 'usedFundLimit',
|
prop: 'usedFundLimit',
|
||||||
hide: true,
|
hide: true,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
|
span: 12,
|
||||||
minWidth: 220,
|
minWidth: 220,
|
||||||
value: 0,
|
value: 0,
|
||||||
rules: [nonNegativeRule('已使用项目资金额度')],
|
rules: [nonNegativeRule('已使用项目资金额度')],
|
||||||
@@ -155,6 +163,7 @@ export const option = {
|
|||||||
prop: 'remainingFundLimit',
|
prop: 'remainingFundLimit',
|
||||||
hide: true,
|
hide: true,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
|
span: 12,
|
||||||
minWidth: 230,
|
minWidth: 230,
|
||||||
value: 0,
|
value: 0,
|
||||||
rules: [nonNegativeRule('剩余项目资金使用额度')],
|
rules: [nonNegativeRule('剩余项目资金使用额度')],
|
||||||
@@ -163,6 +172,7 @@ export const option = {
|
|||||||
label: '申请临时额度(万元)',
|
label: '申请临时额度(万元)',
|
||||||
prop: 'applyLimit',
|
prop: 'applyLimit',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
|
span: 12,
|
||||||
minWidth: 180,
|
minWidth: 180,
|
||||||
rules: [
|
rules: [
|
||||||
{ required: true, message: '请输入申请临时额度', trigger: 'blur' },
|
{ required: true, message: '请输入申请临时额度', trigger: 'blur' },
|
||||||
@@ -175,6 +185,7 @@ export const option = {
|
|||||||
type: 'date',
|
type: 'date',
|
||||||
format: 'YYYY-MM-DD',
|
format: 'YYYY-MM-DD',
|
||||||
valueFormat: 'YYYY-MM-DD',
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
span: 12,
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
rules: [{ required: true, message: '请选择申请有效期至', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择申请有效期至', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
@@ -260,6 +271,6 @@ export const option = {
|
|||||||
},
|
},
|
||||||
...auditColumns.map(column => ({ ...column, hide: true })),
|
...auditColumns.map(column => ({ ...column, hide: true })),
|
||||||
]),
|
]),
|
||||||
dialogWidth: 1480,
|
dialogWidth: 1010,
|
||||||
index: false,
|
index: false,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -718,5 +718,5 @@ export const option = {
|
|||||||
]),
|
]),
|
||||||
dialogWidth: '96%',
|
dialogWidth: '96%',
|
||||||
dialogTop: '10px',
|
dialogTop: '10px',
|
||||||
menuWidth: 320,
|
menuWidth: 280,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ export default {
|
|||||||
selection: true,
|
selection: true,
|
||||||
grid: true,
|
grid: true,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 1200,
|
dialogWidth: 1200,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
tabs: true,
|
tabs: true,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default {
|
|||||||
selection: true,
|
selection: true,
|
||||||
grid: true,
|
grid: true,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export const authLockOption = {
|
|||||||
viewBtn: false,
|
viewBtn: false,
|
||||||
editBtn: false,
|
editBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogType: 'drawer',
|
dialogType: 'drawer',
|
||||||
dialogWidth: 800,
|
dialogWidth: 800,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const authLogOption = {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
menu: true,
|
menu: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogType: 'drawer',
|
dialogType: 'drawer',
|
||||||
dialogWidth: 800,
|
dialogWidth: 800,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const optionParent = {
|
|||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 880,
|
dialogWidth: 880,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
@@ -104,7 +104,7 @@ export const optionChild = {
|
|||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 880,
|
dialogWidth: 880,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const optionParent = {
|
|||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 880,
|
dialogWidth: 880,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
@@ -105,7 +105,7 @@ export const optionChild = {
|
|||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 880,
|
dialogWidth: 880,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import website from '@/config/website';
|
|
||||||
import { getDeptLazyTree } from '@/api/system/dept';
|
import { getDeptLazyTree } from '@/api/system/dept';
|
||||||
|
|
||||||
export const userOption = safe => {
|
export const userOption = safe => {
|
||||||
@@ -25,42 +24,41 @@ export const userOption = safe => {
|
|||||||
searchShow: true,
|
searchShow: true,
|
||||||
searchMenuSpan: 24,
|
searchMenuSpan: 24,
|
||||||
searchIcon: true,
|
searchIcon: true,
|
||||||
searchIndex: 8,
|
searchIndex: 4,
|
||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
dialogType: 'drawer',
|
dialogType: 'dialog',
|
||||||
dialogWidth: 1000,
|
dialogWidth: '90%',
|
||||||
|
labelPosition: 'right',
|
||||||
|
labelWidth: 120,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '登录账号',
|
label: '账号名',
|
||||||
prop: 'account',
|
prop: 'account',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 2,
|
||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '所属租户',
|
label: '姓名',
|
||||||
prop: 'tenantName',
|
|
||||||
slot: true,
|
|
||||||
display: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '用户姓名',
|
|
||||||
prop: 'realName',
|
prop: 'realName',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 4,
|
||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '所属角色',
|
label: '手机号',
|
||||||
prop: 'roleName',
|
prop: 'phone',
|
||||||
slot: true,
|
search: true,
|
||||||
overHidden: true,
|
searchOrder: 3,
|
||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
|
{ label: '工号', prop: 'code', display: false },
|
||||||
{
|
{
|
||||||
label: '所属部门',
|
label: '所属部门',
|
||||||
prop: 'deptName',
|
prop: 'deptName',
|
||||||
@@ -68,33 +66,22 @@ export const userOption = safe => {
|
|||||||
overHidden: true,
|
overHidden: true,
|
||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
|
{ label: '岗位', prop: 'postName', overHidden: true, display: false },
|
||||||
|
{ label: '性别', prop: 'sexName', width: 80, display: false },
|
||||||
|
{ label: 'OA人员id', prop: 'oaPersonId', minWidth: 120, overHidden: true, display: false },
|
||||||
|
{ label: '备注', prop: 'remark', minWidth: 160, overHidden: true, display: false },
|
||||||
{
|
{
|
||||||
label: '用户平台',
|
label: '状态',
|
||||||
prop: 'userTypeName',
|
prop: 'status',
|
||||||
width: 100,
|
|
||||||
slot: true,
|
|
||||||
display: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '用户平台',
|
|
||||||
type: 'select',
|
type: 'select',
|
||||||
dicUrl: '/blade-system/dict/dictionary?code=user_type',
|
dicData: [
|
||||||
props: {
|
{ label: '启用', value: 1 },
|
||||||
label: 'dictValue',
|
{ label: '禁用', value: 0 },
|
||||||
value: 'dictKey',
|
],
|
||||||
},
|
|
||||||
dataType: 'number',
|
dataType: 'number',
|
||||||
search: true,
|
search: true,
|
||||||
hide: true,
|
searchOrder: 1,
|
||||||
display: false,
|
display: false,
|
||||||
prop: 'userType',
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请选择用户平台',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
group: [
|
group: [
|
||||||
@@ -104,53 +91,13 @@ export const userOption = safe => {
|
|||||||
icon: 'el-icon-user-solid',
|
icon: 'el-icon-user-solid',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '所属租户',
|
label: '账号名',
|
||||||
prop: 'tenantId',
|
|
||||||
type: 'tree',
|
|
||||||
dicUrl: '/blade-system/tenant/select',
|
|
||||||
props: {
|
|
||||||
label: 'tenantName',
|
|
||||||
value: 'tenantId',
|
|
||||||
},
|
|
||||||
hide: !website.tenantMode,
|
|
||||||
addDisplay: website.tenantMode,
|
|
||||||
editDisplay: website.tenantMode,
|
|
||||||
viewDisplay: website.tenantMode,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入所属租户',
|
|
||||||
trigger: 'click',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
span: 24,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '登录账号',
|
|
||||||
prop: 'account',
|
prop: 'account',
|
||||||
|
span: 6,
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入登录账号',
|
message: '请输入账号名',
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '用户平台',
|
|
||||||
type: 'select',
|
|
||||||
dicUrl: '/blade-system/dict/dictionary?code=user_type',
|
|
||||||
props: {
|
|
||||||
label: 'dictValue',
|
|
||||||
value: 'dictKey',
|
|
||||||
},
|
|
||||||
dataType: 'number',
|
|
||||||
slot: true,
|
|
||||||
prop: 'userType',
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请选择用户平台',
|
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -161,6 +108,7 @@ export const userOption = safe => {
|
|||||||
hide: true,
|
hide: true,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
viewDisplay: false,
|
viewDisplay: false,
|
||||||
|
addDisplay: false,
|
||||||
rules: [{ required: true, validator: validatePass, trigger: 'blur' }],
|
rules: [{ required: true, validator: validatePass, trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -169,6 +117,7 @@ export const userOption = safe => {
|
|||||||
hide: true,
|
hide: true,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
viewDisplay: false,
|
viewDisplay: false,
|
||||||
|
addDisplay: false,
|
||||||
rules: [{ required: true, validator: validatePass2, trigger: 'blur' }],
|
rules: [{ required: true, validator: validatePass2, trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -191,12 +140,13 @@ export const userOption = safe => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '用户姓名',
|
label: '姓名',
|
||||||
prop: 'realName',
|
prop: 'realName',
|
||||||
|
span: 6,
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入用户姓名',
|
message: '请输入姓名',
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -209,12 +159,14 @@ export const userOption = safe => {
|
|||||||
{
|
{
|
||||||
label: '手机号码',
|
label: '手机号码',
|
||||||
prop: 'phone',
|
prop: 'phone',
|
||||||
|
span: 6,
|
||||||
|
rules: [{ required: true, message: '请输入手机号码', trigger: 'blur' }],
|
||||||
overHidden: true,
|
overHidden: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '电子邮箱',
|
label: '电子邮箱',
|
||||||
prop: 'email',
|
prop: 'email',
|
||||||
hide: true,
|
span: 6,
|
||||||
overHidden: true,
|
overHidden: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -235,7 +187,7 @@ export const userOption = safe => {
|
|||||||
value: 3,
|
value: 3,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
hide: true,
|
span: 6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '用户生日',
|
label: '用户生日',
|
||||||
@@ -261,6 +213,8 @@ export const userOption = safe => {
|
|||||||
{
|
{
|
||||||
label: '用户编号',
|
label: '用户编号',
|
||||||
prop: 'code',
|
prop: 'code',
|
||||||
|
label: '工号',
|
||||||
|
span: 6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '所属角色',
|
label: '所属角色',
|
||||||
@@ -273,13 +227,7 @@ export const userOption = safe => {
|
|||||||
},
|
},
|
||||||
checkStrictly: true,
|
checkStrictly: true,
|
||||||
slot: true,
|
slot: true,
|
||||||
rules: [
|
display: false,
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请选择所属角色',
|
|
||||||
trigger: 'click',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '所属部门',
|
label: '所属部门',
|
||||||
@@ -292,6 +240,7 @@ export const userOption = safe => {
|
|||||||
},
|
},
|
||||||
checkStrictly: true,
|
checkStrictly: true,
|
||||||
slot: true,
|
slot: true,
|
||||||
|
span: 6,
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -304,7 +253,7 @@ export const userOption = safe => {
|
|||||||
label: '所属岗位',
|
label: '所属岗位',
|
||||||
prop: 'postId',
|
prop: 'postId',
|
||||||
type: 'tree',
|
type: 'tree',
|
||||||
multiple: true,
|
multiple: false,
|
||||||
dicData: [],
|
dicData: [],
|
||||||
props: {
|
props: {
|
||||||
label: 'postName',
|
label: 'postName',
|
||||||
@@ -317,6 +266,7 @@ export const userOption = safe => {
|
|||||||
trigger: 'click',
|
trigger: 'click',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
span: 6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '直属主管',
|
label: '直属主管',
|
||||||
@@ -330,6 +280,7 @@ export const userOption = safe => {
|
|||||||
value: 'id',
|
value: 'id',
|
||||||
},
|
},
|
||||||
clearable: true,
|
clearable: true,
|
||||||
|
display: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '是否主管',
|
label: '是否主管',
|
||||||
@@ -346,6 +297,49 @@ export const userOption = safe => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
value: 0,
|
value: 0,
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '人员类别',
|
||||||
|
prop: 'personCategory',
|
||||||
|
type: 'select',
|
||||||
|
span: 6,
|
||||||
|
value: 1,
|
||||||
|
dicData: [
|
||||||
|
{ label: '内部员工', value: 1 },
|
||||||
|
{ 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: '备注',
|
||||||
|
prop: 'remark',
|
||||||
|
type: 'textarea',
|
||||||
|
span: 24,
|
||||||
|
maxlength: 200,
|
||||||
|
showWordLimit: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -365,7 +359,7 @@ export const platformOption = {
|
|||||||
selection: true,
|
selection: true,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
editBtnText: '配置',
|
editBtnText: '配置',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const codeOption = {
|
|||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
tabs: true,
|
tabs: true,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default {
|
|||||||
selection: true,
|
selection: true,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
searchLabelWidth: 160,
|
searchLabelWidth: 160,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default {
|
|||||||
selection: true,
|
selection: true,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
searchLabelWidth: 160,
|
searchLabelWidth: 160,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 500,
|
dialogWidth: 500,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
|
|||||||
@@ -16,62 +16,67 @@ export const option = {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
viewBtn: false,
|
viewBtn: false,
|
||||||
menuWidth: 220,
|
menuWidth: 180,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '姓名',
|
label: '姓名身份证号',
|
||||||
prop: 'driverName',
|
prop: 'driverName',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 7,
|
searchOrder: 7,
|
||||||
slot: true,
|
slot: true,
|
||||||
minWidth: 120,
|
minWidth: 220,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '手机号',
|
label: '手机号码',
|
||||||
prop: 'mobile',
|
prop: 'mobile',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 6,
|
searchOrder: 6,
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '准驾车型',
|
label: '性别',
|
||||||
prop: 'drivingType',
|
prop: 'gender',
|
||||||
|
width: 80,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '司机类型',
|
||||||
|
prop: 'driverType',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 5,
|
searchOrder: 3,
|
||||||
hide: true,
|
|
||||||
type: 'select',
|
type: 'select',
|
||||||
dicData: [
|
dicData: [
|
||||||
{
|
{
|
||||||
label: 'A1',
|
label: '自有员工',
|
||||||
value: 'A1',
|
value: '自有',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'A2',
|
label: '外协',
|
||||||
value: 'A2',
|
value: '外协',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'A3',
|
label: '承运管理员',
|
||||||
value: 'A3',
|
value: '承运管理员',
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'B1',
|
|
||||||
value: 'B1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'B2',
|
|
||||||
value: 'B2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'C1',
|
|
||||||
value: 'C1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'C2',
|
|
||||||
value: 'C2',
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
minWidth: 110,
|
minWidth: 110,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '岗位',
|
||||||
|
prop: 'posts',
|
||||||
|
minWidth: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属组织',
|
||||||
|
prop: 'organizationName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 1,
|
||||||
|
type: 'select',
|
||||||
|
filterable: true,
|
||||||
|
dicData: [],
|
||||||
|
minWidth: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '状态',
|
label: '状态',
|
||||||
@@ -94,65 +99,52 @@ export const option = {
|
|||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '司机类型',
|
label: '驾驶认证(日期)',
|
||||||
prop: 'driverType',
|
|
||||||
search: true,
|
|
||||||
searchOrder: 3,
|
|
||||||
type: 'select',
|
|
||||||
dicData: [
|
|
||||||
{
|
|
||||||
label: '自有员工',
|
|
||||||
value: '自有',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '外协',
|
|
||||||
value: '外协',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
minWidth: 110,
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '身份证号',
|
|
||||||
prop: 'idCardNo',
|
|
||||||
search: true,
|
|
||||||
searchOrder: 2,
|
|
||||||
minWidth: 190,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '所属组织',
|
|
||||||
prop: 'organizationName',
|
|
||||||
search: true,
|
|
||||||
searchOrder: 1,
|
|
||||||
type: 'select',
|
|
||||||
filterable: true,
|
|
||||||
dicData: [],
|
|
||||||
minWidth: 160,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '性别',
|
|
||||||
prop: 'gender',
|
|
||||||
width: 80,
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '岗位',
|
|
||||||
prop: 'posts',
|
|
||||||
minWidth: 150,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '驾驶认证',
|
|
||||||
prop: 'drivingLicenseEndDate',
|
prop: 'drivingLicenseEndDate',
|
||||||
slot: true,
|
slot: true,
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '从业资格认证',
|
label: '从业资格认证(日期)',
|
||||||
prop: 'qualificationEndDate',
|
prop: 'qualificationEndDate',
|
||||||
slot: true,
|
slot: true,
|
||||||
minWidth: 150,
|
minWidth: 160,
|
||||||
align: 'center',
|
},
|
||||||
|
{
|
||||||
|
label: '身份证号',
|
||||||
|
prop: 'idCardNo',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 2,
|
||||||
|
hide: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '准驾车型',
|
||||||
|
prop: 'drivingType',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 5,
|
||||||
|
hide: true,
|
||||||
|
type: 'select',
|
||||||
|
dicData: [
|
||||||
|
{ label: 'A1', value: 'A1' },
|
||||||
|
{ label: 'A2', value: 'A2' },
|
||||||
|
{ label: 'A3', value: 'A3' },
|
||||||
|
{ label: 'B1', value: 'B1' },
|
||||||
|
{ label: 'B2', value: 'B2' },
|
||||||
|
{ label: 'C1', value: 'C1' },
|
||||||
|
{ label: 'C2', value: 'C2' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
prop: 'expireStatus',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 0,
|
||||||
|
searchSpan: 6,
|
||||||
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,23 +14,40 @@ export const option = {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
viewBtn: false,
|
viewBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{ label: '船舶名', prop: 'shipName', search: true, searchOrder: 5, slot: true, width: 130 },
|
{
|
||||||
|
label: '船舶名',
|
||||||
|
prop: 'shipName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 5,
|
||||||
|
slot: true,
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '船舶识别号',
|
label: '船舶识别号',
|
||||||
prop: 'shipIdentifierNo',
|
prop: 'shipIdentifierNo',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 4,
|
searchOrder: 4,
|
||||||
width: 140,
|
minWidth: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属组织',
|
||||||
|
prop: 'organizationName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 1,
|
||||||
|
type: 'select',
|
||||||
|
filterable: true,
|
||||||
|
dicData: [],
|
||||||
|
minWidth: 160,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '船检登记号',
|
label: '船检登记号',
|
||||||
prop: 'shipInspectionNo',
|
prop: 'shipInspectionNo',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 3,
|
searchOrder: 3,
|
||||||
width: 130,
|
minWidth: 130,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '船舶类型',
|
label: '船舶类型',
|
||||||
@@ -44,52 +61,47 @@ export const option = {
|
|||||||
{ label: '杂货船', value: '杂货船' },
|
{ label: '杂货船', value: '杂货船' },
|
||||||
{ label: '油船', value: '油船' },
|
{ label: '油船', value: '油船' },
|
||||||
],
|
],
|
||||||
width: 110,
|
minWidth: 110,
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '所属组织',
|
|
||||||
prop: 'organizationName',
|
|
||||||
search: true,
|
|
||||||
searchOrder: 1,
|
|
||||||
type: 'select',
|
|
||||||
filterable: true,
|
|
||||||
dicData: [],
|
|
||||||
width: 160,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '状态',
|
|
||||||
prop: 'status',
|
|
||||||
type: 'select',
|
|
||||||
slot: true,
|
|
||||||
dicData: [
|
|
||||||
{ label: '启用', value: 1 },
|
|
||||||
{ label: '停用', value: 2 },
|
|
||||||
],
|
|
||||||
width: 90,
|
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '国籍证有效期至',
|
label: '国籍证有效期至',
|
||||||
prop: 'nationalityCertEndDate',
|
prop: 'nationalityCertEndDate',
|
||||||
slot: true,
|
slot: true,
|
||||||
width: 150,
|
minWidth: 150,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '最低安全配员证书有效期至',
|
label: '最低安全配员证书有效期至',
|
||||||
prop: 'safeManningCertEndDate',
|
prop: 'safeManningCertEndDate',
|
||||||
slot: true,
|
slot: true,
|
||||||
width: 210,
|
minWidth: 210,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '营业运输证有效期至',
|
label: '营业运输证有效期至',
|
||||||
prop: 'businessTransportCertEndDate',
|
prop: 'businessTransportCertEndDate',
|
||||||
slot: true,
|
slot: true,
|
||||||
width: 170,
|
minWidth: 170,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{ label: '承租有效期至', prop: 'leaseEndDate', slot: true, width: 140, align: 'center' },
|
{
|
||||||
|
label: '承租有效期至',
|
||||||
|
prop: 'leaseEndDate',
|
||||||
|
slot: true,
|
||||||
|
minWidth: 140,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
prop: 'expireStatus',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 0,
|
||||||
|
searchSpan: 6,
|
||||||
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,21 +9,37 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: false,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
editBtn: false,
|
editBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
viewBtn: false,
|
viewBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 320,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '车牌号',
|
label: '车牌号',
|
||||||
prop: 'plateNo',
|
prop: 'plateNo',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 5,
|
searchOrder: 6,
|
||||||
slot: true,
|
slot: true,
|
||||||
width: 120,
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '业务关系',
|
||||||
|
prop: 'businessRelation',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 5,
|
||||||
|
searchValue: '',
|
||||||
|
type: 'select',
|
||||||
|
dicData: [
|
||||||
|
{ label: '全部', value: '' },
|
||||||
|
{ label: '自有', value: '自有' },
|
||||||
|
{ label: '管理挂靠', value: '管理挂靠' },
|
||||||
|
{ label: '业务合作', value: '业务合作' },
|
||||||
|
],
|
||||||
|
minWidth: 120,
|
||||||
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '所属组织',
|
label: '所属组织',
|
||||||
@@ -33,28 +49,13 @@ export const option = {
|
|||||||
type: 'select',
|
type: 'select',
|
||||||
filterable: true,
|
filterable: true,
|
||||||
dicData: [],
|
dicData: [],
|
||||||
width: 150,
|
minWidth: 150,
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '业务关系',
|
|
||||||
prop: 'businessRelation',
|
|
||||||
search: true,
|
|
||||||
searchOrder: 4,
|
|
||||||
type: 'select',
|
|
||||||
dicData: [
|
|
||||||
{ label: '全部', value: '' },
|
|
||||||
{ label: '自有', value: '自有' },
|
|
||||||
{ label: '管理挂靠', value: '管理挂靠' },
|
|
||||||
{ label: '业务合作', value: '业务合作' },
|
|
||||||
],
|
|
||||||
width: 120,
|
|
||||||
align: 'center',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '车辆类型',
|
label: '车辆类型',
|
||||||
prop: 'vehicleType',
|
prop: 'vehicleType',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 3,
|
searchOrder: 4,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
dicData: [
|
dicData: [
|
||||||
{ label: '全部', value: '' },
|
{ label: '全部', value: '' },
|
||||||
@@ -65,49 +66,95 @@ export const option = {
|
|||||||
{ label: '拖挂车', value: '拖挂' },
|
{ label: '拖挂车', value: '拖挂' },
|
||||||
{ label: '半挂车', value: '半挂' },
|
{ label: '半挂车', value: '半挂' },
|
||||||
],
|
],
|
||||||
width: 110,
|
minWidth: 110,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '核定载质量(KG)',
|
label: '核定载质量(KG)',
|
||||||
prop: 'approvedLoadKg',
|
prop: 'approvedLoadKg',
|
||||||
width: 140,
|
minWidth: 140,
|
||||||
align: 'right',
|
align: 'right',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '绑定司机',
|
||||||
|
prop: 'boundDriver',
|
||||||
|
slot: true,
|
||||||
|
minWidth: 120,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '车辆类型',
|
||||||
|
prop: 'vehicleType',
|
||||||
|
minWidth: 110,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '认证状态',
|
||||||
|
prop: 'certificationStatus',
|
||||||
|
slot: true,
|
||||||
|
search: true,
|
||||||
|
searchOrder: 2,
|
||||||
|
searchValue: '',
|
||||||
|
type: 'select',
|
||||||
|
dicData: [
|
||||||
|
{ label: '全部', value: '' },
|
||||||
|
{ label: '认证中', value: 0 },
|
||||||
|
{ label: '已认证', value: 1 },
|
||||||
|
{ label: '已驳回', value: 2 },
|
||||||
|
],
|
||||||
|
minWidth: 110,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '车辆状态',
|
label: '车辆状态',
|
||||||
prop: 'status',
|
prop: 'status',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 2,
|
searchOrder: 3,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
slot: true,
|
slot: true,
|
||||||
dicData: [
|
dicData: [
|
||||||
{ label: '启用', value: 1 },
|
{ label: '启用', value: 1 },
|
||||||
{ label: '停用', value: 2 },
|
{ label: '停用', value: 2 },
|
||||||
],
|
],
|
||||||
width: 90,
|
minWidth: 90,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '行驶证有效期',
|
label: '道路运输证号',
|
||||||
|
prop: 'roadTransportCertNo',
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '行驶证认证',
|
||||||
prop: 'drivingLicenseEndDate',
|
prop: 'drivingLicenseEndDate',
|
||||||
slot: true,
|
slot: true,
|
||||||
width: 140,
|
minWidth: 140,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '道路运输证有效期',
|
label: '道路运输证认证',
|
||||||
prop: 'roadTransportCertEndDate',
|
prop: 'roadTransportCertEndDate',
|
||||||
slot: true,
|
slot: true,
|
||||||
width: 160,
|
minWidth: 160,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '年审有效期',
|
label: '道路运输证年审',
|
||||||
prop: 'annualReviewEndDate',
|
prop: 'annualReviewEndDate',
|
||||||
slot: true,
|
slot: true,
|
||||||
width: 130,
|
minWidth: 130,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
prop: 'expireStatus',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 0,
|
||||||
|
searchSpan: 6,
|
||||||
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,10 +49,11 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '车船类型',
|
label: '车船类型',
|
||||||
@@ -124,9 +125,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '直接经济损失',
|
label: '直接经济损失',
|
||||||
prop: 'directEconomicLoss',
|
prop: 'directEconomicLoss',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '元',
|
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
@@ -135,9 +135,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '保险理赔金额',
|
label: '保险理赔金额',
|
||||||
prop: 'insuranceClaimAmount',
|
prop: 'insuranceClaimAmount',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '元',
|
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
|
|||||||
@@ -48,10 +48,11 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '车船类型',
|
label: '车船类型',
|
||||||
@@ -140,9 +141,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '费用',
|
label: '费用',
|
||||||
prop: 'fee',
|
prop: 'fee',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '元',
|
|
||||||
minWidth: 100,
|
minWidth: 100,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
@@ -155,6 +155,7 @@ export const option = {
|
|||||||
label: '评定(复核)单位',
|
label: '评定(复核)单位',
|
||||||
prop: 'assessmentUnit',
|
prop: 'assessmentUnit',
|
||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
|
overHidden: true,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
rules: [{ max: 50, message: '最多 50 个字符', trigger: 'blur' }],
|
rules: [{ max: 50, message: '最多 50 个字符', trigger: 'blur' }],
|
||||||
|
|||||||
226
src/option/vehicle/equipment-ledger.js
Normal file
226
src/option/vehicle/equipment-ledger.js
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
import { formatUpdateUserName } from '@/utils/audit';
|
||||||
|
|
||||||
|
export const vehicleTypeDic = [
|
||||||
|
{ label: '车辆', value: '车辆' },
|
||||||
|
{ label: '船舶', value: '船舶' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const onlineStatusDic = [
|
||||||
|
{ label: '否', value: 0 },
|
||||||
|
{ label: '是', value: 1 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const option = {
|
||||||
|
height: 'auto',
|
||||||
|
calcHeight: 32,
|
||||||
|
dialogWidth: 960,
|
||||||
|
labelPosition: 'right',
|
||||||
|
labelWidth: 'auto',
|
||||||
|
searchLabelWidth: 160,
|
||||||
|
tip: false,
|
||||||
|
searchBtnText: '查询',
|
||||||
|
emptyBtnText: '重置',
|
||||||
|
saveBtnText: '提交',
|
||||||
|
updateBtnText: '提交',
|
||||||
|
searchShow: true,
|
||||||
|
searchMenuSpan: 24,
|
||||||
|
searchIcon: true,
|
||||||
|
searchIndex: 4,
|
||||||
|
searchMenuPosition: 'right',
|
||||||
|
border: true,
|
||||||
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
|
viewBtn: true,
|
||||||
|
selection: true,
|
||||||
|
dialogClickModal: false,
|
||||||
|
menuWidth: 160,
|
||||||
|
menuFixed: 'right',
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '车船类型',
|
||||||
|
prop: 'vehicleType',
|
||||||
|
type: 'radio',
|
||||||
|
dicData: vehicleTypeDic,
|
||||||
|
value: '车辆',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 3,
|
||||||
|
span: 24,
|
||||||
|
order: 1,
|
||||||
|
minWidth: 110,
|
||||||
|
rules: [{ required: true, message: '请选择车船类型', trigger: 'change' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '车牌号/船号',
|
||||||
|
prop: 'vehicleNo',
|
||||||
|
slot: true,
|
||||||
|
formslot: true,
|
||||||
|
search: true,
|
||||||
|
searchOrder: 4,
|
||||||
|
span: 12,
|
||||||
|
order: 2,
|
||||||
|
minWidth: 140,
|
||||||
|
rules: [{ required: true, message: '请输入车牌号/船号', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备号',
|
||||||
|
prop: 'equipmentCode',
|
||||||
|
formslot: true,
|
||||||
|
search: true,
|
||||||
|
searchOrder: 2,
|
||||||
|
span: 12,
|
||||||
|
order: 3,
|
||||||
|
minWidth: 150,
|
||||||
|
rules: [{ required: true, message: '设备编号由系统生成', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备名称',
|
||||||
|
prop: 'equipmentName',
|
||||||
|
span: 12,
|
||||||
|
order: 4,
|
||||||
|
minWidth: 150,
|
||||||
|
rules: [
|
||||||
|
{ required: true, message: '请输入设备名称', trigger: 'blur' },
|
||||||
|
{ max: 100, message: '最多 100 个字符', trigger: 'blur' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '出厂日期',
|
||||||
|
prop: 'factoryDate',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
span: 12,
|
||||||
|
order: 8,
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备品牌',
|
||||||
|
prop: 'equipmentBrand',
|
||||||
|
span: 12,
|
||||||
|
order: 5,
|
||||||
|
minWidth: 130,
|
||||||
|
rules: [{ max: 50, message: '最多 50 个字符', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备类型',
|
||||||
|
prop: 'equipmentType',
|
||||||
|
type: 'select',
|
||||||
|
dicData: [],
|
||||||
|
span: 12,
|
||||||
|
order: 6,
|
||||||
|
minWidth: 130,
|
||||||
|
rules: [{ max: 50, message: '最多 50 个字符', trigger: 'change' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '规格型号',
|
||||||
|
prop: 'specificationModel',
|
||||||
|
span: 12,
|
||||||
|
order: 7,
|
||||||
|
minWidth: 150,
|
||||||
|
rules: [{ max: 100, message: '最多 100 个字符', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '备注',
|
||||||
|
prop: 'remark',
|
||||||
|
type: 'textarea',
|
||||||
|
minRows: 3,
|
||||||
|
span: 24,
|
||||||
|
order: 10,
|
||||||
|
minWidth: 180,
|
||||||
|
overHidden: true,
|
||||||
|
rules: [{ max: 200, message: '最多 200 个字符', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '更新时间',
|
||||||
|
prop: 'updateTime',
|
||||||
|
type: 'datetime',
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
minWidth: 170,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '创建时间',
|
||||||
|
prop: 'createTime',
|
||||||
|
type: 'datetime',
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
minWidth: 170,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否在线',
|
||||||
|
prop: 'onlineStatus',
|
||||||
|
type: 'select',
|
||||||
|
dicData: onlineStatusDic,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
minWidth: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '原厂设备号',
|
||||||
|
prop: 'originalEquipmentNo',
|
||||||
|
span: 12,
|
||||||
|
order: 9,
|
||||||
|
hide: true,
|
||||||
|
rules: [{ max: 100, message: '最多 100 个字符', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '附件',
|
||||||
|
prop: 'attachments',
|
||||||
|
slot: true,
|
||||||
|
formslot: true,
|
||||||
|
span: 24,
|
||||||
|
order: 11,
|
||||||
|
hide: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '组织',
|
||||||
|
prop: 'createDept',
|
||||||
|
type: 'tree',
|
||||||
|
dicData: [],
|
||||||
|
props: { label: 'title', value: 'id' },
|
||||||
|
checkStrictly: true,
|
||||||
|
search: true,
|
||||||
|
searchOrder: 1,
|
||||||
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '更新人',
|
||||||
|
prop: 'updateUserName',
|
||||||
|
formatter: formatUpdateUserName,
|
||||||
|
display: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const excelOption = {
|
||||||
|
labelPosition: 'right',
|
||||||
|
submitBtn: false,
|
||||||
|
emptyBtn: false,
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '模板上传',
|
||||||
|
prop: 'excelFile',
|
||||||
|
type: 'upload',
|
||||||
|
drag: true,
|
||||||
|
loadText: '模板上传中,请稍等',
|
||||||
|
span: 24,
|
||||||
|
propsHttp: { res: 'data' },
|
||||||
|
tip: '请上传 .xls,.xlsx 标准格式文件',
|
||||||
|
action: '/blade-transport/equipment-ledger/import-equipment-ledger',
|
||||||
|
},
|
||||||
|
{ label: '模板下载', prop: 'excelTemplate', formslot: true, span: 24 },
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -38,10 +38,11 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
@@ -103,9 +104,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '交易金额',
|
label: '交易金额',
|
||||||
prop: 'transactionAmount',
|
prop: 'transactionAmount',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '元',
|
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
|
|||||||
@@ -46,10 +46,11 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '车船类型',
|
label: '车船类型',
|
||||||
@@ -128,8 +129,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '保额',
|
label: '保额',
|
||||||
prop: 'insuredAmount',
|
prop: 'insuredAmount',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '元',
|
append: '元',
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||||
@@ -137,8 +138,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '保费',
|
label: '保费',
|
||||||
prop: 'premium',
|
prop: 'premium',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '元',
|
append: '元',
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
rules: [
|
rules: [
|
||||||
@@ -181,19 +182,6 @@ export const option = {
|
|||||||
display: false,
|
display: false,
|
||||||
minWidth: 170,
|
minWidth: 170,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '创建时间',
|
|
||||||
prop: 'createTimeRange',
|
|
||||||
type: 'date',
|
|
||||||
format: 'YYYY-MM-DD',
|
|
||||||
valueFormat: 'YYYY-MM-DD',
|
|
||||||
searchRange: true,
|
|
||||||
search: true,
|
|
||||||
hide: true,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
viewDisplay: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '组织',
|
label: '组织',
|
||||||
prop: 'createDept',
|
prop: 'createDept',
|
||||||
@@ -210,6 +198,19 @@ export const option = {
|
|||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
viewDisplay: false,
|
viewDisplay: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '创建时间',
|
||||||
|
prop: 'createTimeRange',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
searchRange: true,
|
||||||
|
search: true,
|
||||||
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '更新人',
|
label: '更新人',
|
||||||
prop: 'updateUserName',
|
prop: 'updateUserName',
|
||||||
|
|||||||
@@ -34,10 +34,11 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
@@ -67,9 +68,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '上月统计里程数',
|
label: '上月统计里程数',
|
||||||
prop: 'previousMonthMileage',
|
prop: 'previousMonthMileage',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '公里',
|
|
||||||
minWidth: 210,
|
minWidth: 210,
|
||||||
slot: true,
|
slot: true,
|
||||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||||
@@ -77,9 +77,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '本月统计里程数',
|
label: '本月统计里程数',
|
||||||
prop: 'currentMonthMileage',
|
prop: 'currentMonthMileage',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '公里',
|
|
||||||
minWidth: 210,
|
minWidth: 210,
|
||||||
slot: true,
|
slot: true,
|
||||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||||
@@ -87,9 +86,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '本月行驶里程数',
|
label: '本月行驶里程数',
|
||||||
prop: 'monthlyMileage',
|
prop: 'monthlyMileage',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '公里',
|
|
||||||
minWidth: 170,
|
minWidth: 170,
|
||||||
slot: true,
|
slot: true,
|
||||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||||
@@ -97,9 +95,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '累计行驶里程数',
|
label: '累计行驶里程数',
|
||||||
prop: 'totalMileage',
|
prop: 'totalMileage',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '公里',
|
|
||||||
minWidth: 170,
|
minWidth: 170,
|
||||||
slot: true,
|
slot: true,
|
||||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||||
|
|||||||
@@ -35,10 +35,11 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
@@ -111,25 +112,24 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '数量',
|
label: '数量',
|
||||||
prop: 'quantity',
|
prop: 'quantity',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
minWidth: 110,
|
minWidth: 110,
|
||||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '单价',
|
label: '单价',
|
||||||
prop: 'unitPrice',
|
prop: 'unitPrice',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
append: '元/升',
|
|
||||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '交易金额',
|
label: '交易金额',
|
||||||
prop: 'transactionAmount',
|
prop: 'transactionAmount',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
rules: [
|
rules: [
|
||||||
{ required: true, message: '请输入交易金额', trigger: 'blur' },
|
{ required: true, message: '请输入交易金额', trigger: 'blur' },
|
||||||
@@ -139,8 +139,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '余额',
|
label: '余额',
|
||||||
prop: 'balance',
|
prop: 'balance',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
minWidth: 110,
|
minWidth: 110,
|
||||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -46,10 +46,11 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
@@ -102,9 +103,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '金额',
|
label: '金额',
|
||||||
prop: 'amount',
|
prop: 'amount',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '元',
|
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
|
|||||||
@@ -39,10 +39,11 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '车牌号',
|
label: '车牌号',
|
||||||
@@ -88,8 +89,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '换胎数量',
|
label: '换胎数量',
|
||||||
prop: 'tireQuantity',
|
prop: 'tireQuantity',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 0,
|
formslot: true,
|
||||||
minWidth: 110,
|
minWidth: 110,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
@@ -98,9 +99,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '换胎费用',
|
label: '换胎费用',
|
||||||
prop: 'replacementCost',
|
prop: 'replacementCost',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '元',
|
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
|
|||||||
@@ -26,10 +26,11 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,14 +25,6 @@ export const vehicleTypeDic = [
|
|||||||
{ label: '船舶', value: '船舶' },
|
{ label: '船舶', value: '船舶' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const violationTypeDic = [
|
|
||||||
{ label: '闯红灯', value: '闯红灯' },
|
|
||||||
{ label: '超速', value: '超速' },
|
|
||||||
{ label: '违停', value: '违停' },
|
|
||||||
{ label: '压线', value: '压线' },
|
|
||||||
{ label: '其他', value: '其他' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const processStatusDic = [
|
export const processStatusDic = [
|
||||||
{ label: '未处理', value: '未处理' },
|
{ label: '未处理', value: '未处理' },
|
||||||
{ label: '已处理', value: '已处理' },
|
{ label: '已处理', value: '已处理' },
|
||||||
@@ -57,10 +49,11 @@ export const option = {
|
|||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
|
indexLabel: '序号',
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '车船类型',
|
label: '车船类型',
|
||||||
@@ -104,11 +97,11 @@ export const option = {
|
|||||||
label: '类型',
|
label: '类型',
|
||||||
prop: 'violationType',
|
prop: 'violationType',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
dicData: violationTypeDic,
|
dicData: [],
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请选择',
|
placeholder: '请选择',
|
||||||
rules: [{ required: true, message: '请选择类型', trigger: 'change' }],
|
rules: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '事项',
|
label: '事项',
|
||||||
@@ -118,10 +111,7 @@ export const option = {
|
|||||||
display: false,
|
display: false,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
rules: [
|
rules: [{ max: 100, message: '最多 100 个字符', trigger: 'blur' }],
|
||||||
{ required: true, message: '请输入事项', trigger: 'blur' },
|
|
||||||
{ max: 100, message: '最多 100 个字符', trigger: 'blur' },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '日期',
|
label: '日期',
|
||||||
@@ -149,8 +139,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '罚款',
|
label: '罚款',
|
||||||
prop: 'fineAmount',
|
prop: 'fineAmount',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 2,
|
formslot: true,
|
||||||
append: '元',
|
append: '元',
|
||||||
minWidth: 100,
|
minWidth: 100,
|
||||||
span: 12,
|
span: 12,
|
||||||
@@ -160,8 +150,8 @@ export const option = {
|
|||||||
{
|
{
|
||||||
label: '被扣分数',
|
label: '被扣分数',
|
||||||
prop: 'deductPoints',
|
prop: 'deductPoints',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
precision: 0,
|
formslot: true,
|
||||||
minWidth: 110,
|
minWidth: 110,
|
||||||
span: 12,
|
span: 12,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export default {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.logo-img {
|
.logo-img {
|
||||||
width: 40px;
|
width: 30px;
|
||||||
margin-top: 5px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -207,6 +207,102 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
// 弹窗标准(与 business/project-apply 弹窗视觉一致)
|
||||||
|
// 灰底弹窗体 + 分组白卡(标题融入卡头,4px 主色竖条 + 8px 间距)
|
||||||
|
// =====================================================================
|
||||||
|
|
||||||
|
// 1) 所有弹窗内容区统一灰底 + 16px 内边距(与 project-apply 一致,避免内容贴边)
|
||||||
|
.el-dialog__body {
|
||||||
|
background-color: #f5f6fa;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Avue 默认弹窗表单自动包成白卡,无需逐页改 option 即统一标准
|
||||||
|
.el-dialog .avue-form {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Avue 弹窗内分组(option.group)渲染为白卡,标题在卡内
|
||||||
|
.el-dialog .avue-form__group {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.avue-group__header {
|
||||||
|
border-bottom: none;
|
||||||
|
padding: 14px 16px 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avue-group__item {
|
||||||
|
padding: 14px 16px 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4) 弹窗内表单项默认上下间距 16px(覆盖默认 18px / 22px)
|
||||||
|
.el-dialog .el-form-item {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5) 通用分组白卡组件(<section-card>):标题融入卡头
|
||||||
|
.section-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 14px 16px 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__bar {
|
||||||
|
flex: none;
|
||||||
|
width: 4px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__extra {
|
||||||
|
margin-left: auto;
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__body {
|
||||||
|
padding: 14px 16px 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6) 弹窗内两列表单栅格工具类(与 project-apply 一致)
|
||||||
|
.form-grid-2 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||||
|
column-gap: 72px;
|
||||||
|
row-gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.avue-crud__dialog .avue-dialog__footer > .el-button {
|
.avue-crud__dialog .avue-dialog__footer > .el-button {
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
}
|
}
|
||||||
@@ -225,6 +321,7 @@
|
|||||||
.avue-crud__dialog .el-dialog__body {
|
.avue-crud__dialog .el-dialog__body {
|
||||||
max-height: calc(100vh - 200px);
|
max-height: calc(100vh - 200px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
//background: #f5f6fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统一表格线条颜色
|
// 统一表格线条颜色
|
||||||
@@ -267,6 +364,19 @@
|
|||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 统一 CRUD 顶部新增按钮为蓝底白字,保留其他工具按钮的描边样式
|
||||||
|
.avue-crud__header .el-button--primary.is-plain:has(.el-icon-plus) {
|
||||||
|
--el-button-bg-color: #409eff;
|
||||||
|
--el-button-border-color: #409eff;
|
||||||
|
--el-button-hover-bg-color: #66b1ff;
|
||||||
|
--el-button-hover-border-color: #66b1ff;
|
||||||
|
--el-button-active-bg-color: #337ecc;
|
||||||
|
--el-button-active-border-color: #337ecc;
|
||||||
|
--el-button-text-color: #fff;
|
||||||
|
--el-button-hover-text-color: #fff;
|
||||||
|
--el-button-active-text-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
// 统一分页为按钮样式并靠右展示
|
// 统一分页为按钮样式并靠右展示
|
||||||
.avue-crud__pagination,
|
.avue-crud__pagination,
|
||||||
.empty-pagination {
|
.empty-pagination {
|
||||||
@@ -337,12 +447,7 @@
|
|||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-pagination .btn-prev,
|
// 上一页 / 下一页 箭头按钮与页码按钮等宽,不再单独加宽
|
||||||
.el-pagination .btn-next,
|
|
||||||
.erp-pagination-first,
|
|
||||||
.erp-pagination-last {
|
|
||||||
min-width: 54px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-pagination .el-pager {
|
.el-pagination .el-pager {
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
@@ -350,18 +455,7 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-pagination .btn-prev .el-icon,
|
// 上一页 / 下一页 改为原生箭头图标:不再隐藏原生图标,也不再注入「上一页 / 下一页」文字
|
||||||
.el-pagination .btn-next .el-icon {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-pagination .btn-prev::before {
|
|
||||||
content: '上一页';
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-pagination .btn-next::before {
|
|
||||||
content: '下一页';
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-pagination.is-background .el-pager li.is-active,
|
.el-pagination.is-background .el-pager li.is-active,
|
||||||
.el-pagination .el-pager li.is-active {
|
.el-pagination .el-pager li.is-active {
|
||||||
@@ -447,14 +541,7 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全站统一:隐藏分页的「上一页 / 下一页」原生导航按钮
|
// 全站统一:分页展示「上一页 / 下一页」原生箭头图标(不再隐藏;首页 / 尾页仍不注入)
|
||||||
// (「首页 / 尾页」由 src/utils/pagination.js 的全局增强器统一不再注入)
|
|
||||||
.el-pagination {
|
|
||||||
.btn-prev,
|
|
||||||
.btn-next {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 全站统一:隐藏操作栏按钮前的图标
|
// 全站统一:隐藏操作栏按钮前的图标
|
||||||
.avue-crud__menu .el-button--text i,
|
.avue-crud__menu .el-button--text i,
|
||||||
@@ -462,16 +549,49 @@
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全站统一:操作列最多一行展示 4 个按钮,第 5 个开始自动换行
|
// 全站统一:Avue 操作列文字链接保持间距并支持自动换行
|
||||||
.avue-crud .el-table td .cell.avue-crud__menu {
|
// 注意:Avue 自带 .avue-crud .avue-crud__menu{display:block}(特异性同为 0,2,0)。
|
||||||
display: inline-grid;
|
// 此处重复类名升至 0,3,0 并强制 display:inline-flex !important,彻底压过 Avue 内置样式,
|
||||||
grid-template-columns: repeat(4, max-content);
|
// 避免 dev 模式下 CSS 注入顺序导致 .avue-crud__menu 退化成 block 而让操作项竖排错位。
|
||||||
gap: 4px;
|
.avue-crud .avue-crud__menu.avue-crud__menu {
|
||||||
|
display: inline-flex !important;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
|
width: 100% !important;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 全站统一:手写表格操作列中的文字链接保持间距并支持自动换行
|
||||||
|
.el-table .el-table__body .cell:not(.avue-crud__menu):has(> .el-link) {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全站统一:表格操作列文字链接统一为主色(蓝色)
|
||||||
|
// 覆盖 Avue #menu 槽位与手写表格操作列中 el-link 的 warning / success / danger 等类型,
|
||||||
|
// 同时统一 hover / active / disabled 态,保证全站操作列风格一致。
|
||||||
|
// 选择器同时覆盖 Avue 行菜单(.avue-crud__menu)与任意含 el-link 的表格体单元格(手写操作列)。
|
||||||
|
.avue-crud__menu .el-link,
|
||||||
|
.el-table .el-table__body .cell:has(.el-link) .el-link {
|
||||||
|
// 覆盖 Element Plus el-link 默认的 font-weight: var(--el-font-weight-primary)(500 中等粗),
|
||||||
|
// 操作列文字统一为常规字重,避免「查看/编辑/删除」等链接显得加粗。
|
||||||
|
font-weight: normal;
|
||||||
|
--el-link-text-color: var(--el-color-primary);
|
||||||
|
--el-link-hover-text-color: var(--el-color-primary-light-3);
|
||||||
|
--el-link-active-text-color: var(--el-color-primary-dark-2);
|
||||||
|
--el-link-disabled-text-color: var(--el-color-primary-light-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全站统一:去除操作列 el-link 默认 margin,避免与 8px gap 叠加导致文字间距过宽
|
||||||
|
.avue-crud .avue-crud__menu .el-link,
|
||||||
|
.el-table .el-table__body .cell:not(.avue-crud__menu):has(> .el-link) .el-link {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.avue-crud__menu > .el-button,
|
.avue-crud__menu > .el-button,
|
||||||
.avue-crud__menu > .el-dropdown {
|
.avue-crud__menu > .el-dropdown {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -483,6 +603,44 @@
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 全站统一:Element Plus 全局开启 show-overflow-tooltip 后,
|
||||||
|
// 操作列单元格会被加上 .el-tooltip 类并写死宽度,导致内部 el-link 换行后被裁切。
|
||||||
|
// 此处豁免操作列单元格:让 Avue 行菜单与手写表格操作列保持原有 flex 自动换行,不被固定宽度裁切。
|
||||||
|
.el-table .cell.avue-crud__menu,
|
||||||
|
.el-table .el-table__body .cell.el-tooltip:has(> .el-link) {
|
||||||
|
width: auto !important;
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全站统一:Avue 内置行操作按钮(查看 / 编辑 / 删除 / 复制等)视觉对齐为 el-link 链接样式。
|
||||||
|
// 选择器仅命中表格行操作列 .avue-crud__menu 内的 is-text 按钮,不误伤顶部工具栏(.avue-crud__header)
|
||||||
|
// 与弹窗按钮(.avue-crud__dialog__menu)。事件(rowView/rowEdit/rowDel)与权限(permission 指令)
|
||||||
|
// 由 Avue 自带,此处只改外观,零功能影响。
|
||||||
|
.avue-crud__menu > .el-button.is-text {
|
||||||
|
height: auto;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
font-weight: normal;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--el-color-primary-light-3);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-disabled,
|
||||||
|
&.is-disabled:hover {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--el-color-primary-light-5);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.avue-crud__pagination .el-pagination,
|
.avue-crud__pagination .el-pagination,
|
||||||
.empty-pagination .el-pagination,
|
.empty-pagination .el-pagination,
|
||||||
|
|||||||
@@ -47,7 +47,12 @@ const decorateFailExcel = async (blob, businessName, failDetailDecorator) => {
|
|||||||
*/
|
*/
|
||||||
export const openImportDialog = (vm, businessName, onSuccess, options = {}) => {
|
export const openImportDialog = (vm, businessName, onSuccess, options = {}) => {
|
||||||
const { failDetailDecorator } = options;
|
const { failDetailDecorator } = options;
|
||||||
const column = vm.findColumn(vm.excelOption.column, 'excelFile');
|
const excelOption = vm.excelOption || vm.excelOptionConfig;
|
||||||
|
const column = vm.findColumn(excelOption?.column || [], 'excelFile');
|
||||||
|
if (!column) {
|
||||||
|
vm.$message.error('导入配置异常,请稍后重试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
column.httpRequest = (option, uploadColumn) =>
|
column.httpRequest = (option, uploadColumn) =>
|
||||||
handleImportExcel(vm, option, uploadColumn, businessName, onSuccess, { failDetailDecorator });
|
handleImportExcel(vm, option, uploadColumn, businessName, onSuccess, { failDetailDecorator });
|
||||||
vm.excelBox = true;
|
vm.excelBox = true;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export const TABLE_MENU_WIDTH = {
|
export const TABLE_MENU_WIDTH = {
|
||||||
default: 160,
|
default: 180,
|
||||||
three: 220,
|
three: 180,
|
||||||
four: 320,
|
four: 320,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ export default {
|
|||||||
height: 'auto',
|
height: 'auto',
|
||||||
calcHeight: 32,
|
calcHeight: 32,
|
||||||
dialogWidth: 700,
|
dialogWidth: 700,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
tip: false,
|
tip: false,
|
||||||
searchShow: true,
|
searchShow: true,
|
||||||
searchMenuSpan: 24,
|
searchMenuSpan: 24,
|
||||||
@@ -500,7 +500,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogType: 'drawer',
|
dialogType: 'drawer',
|
||||||
dialogWidth: 800,
|
dialogWidth: 800,
|
||||||
column: [
|
column: [
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ export default {
|
|||||||
selection: true,
|
selection: true,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
searchLabelWidth: 160,
|
searchLabelWidth: 160,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 900,
|
dialogWidth: 900,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
@@ -275,7 +275,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
@@ -336,7 +336,7 @@ export default {
|
|||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 900,
|
dialogWidth: 900,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ export default {
|
|||||||
selection: true,
|
selection: true,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
searchLabelWidth: 160,
|
searchLabelWidth: 160,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 900,
|
dialogWidth: 900,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
@@ -312,7 +312,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
@@ -375,7 +375,7 @@ export default {
|
|||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 900,
|
dialogWidth: 900,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ export default {
|
|||||||
index: true,
|
index: true,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
@@ -366,7 +366,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogType: 'drawer',
|
dialogType: 'drawer',
|
||||||
dialogWidth: 800,
|
dialogWidth: 800,
|
||||||
column: [
|
column: [
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ export default {
|
|||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
searchLabelWidth: 160,
|
searchLabelWidth: 160,
|
||||||
menuWidth: 160,
|
menuWidth: 240,
|
||||||
dialogWidth: 600,
|
dialogWidth: 600,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
@@ -466,7 +466,7 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
rowSave(row, done, loading) {
|
rowSave(row, done, loading) {
|
||||||
add(row).then(
|
add(this.withTenantId(row)).then(
|
||||||
() => {
|
() => {
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -482,7 +482,7 @@ export default {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
rowUpdate(row, index, done, loading) {
|
rowUpdate(row, index, done, loading) {
|
||||||
update(row).then(
|
update(this.withTenantId(row)).then(
|
||||||
() => {
|
() => {
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -497,6 +497,12 @@ export default {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
withTenantId(row) {
|
||||||
|
return {
|
||||||
|
...row,
|
||||||
|
tenantId: row.tenantId || this.userInfo.tenantId || website.tenantId,
|
||||||
|
};
|
||||||
|
},
|
||||||
rowDel(row) {
|
rowDel(row) {
|
||||||
this.$confirm('确定将选择数据删除?', {
|
this.$confirm('确定将选择数据删除?', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '编码',
|
label: '编码',
|
||||||
@@ -366,15 +366,6 @@ export default {
|
|||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '行政区划编号',
|
|
||||||
prop: 'regionCode',
|
|
||||||
minWidth: 160,
|
|
||||||
overHidden: false,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
rules: [{ max: 32, message: '行政区划编码不能超过32字', trigger: 'blur' }],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '详细地址',
|
label: '详细地址',
|
||||||
prop: 'detailAddress',
|
prop: 'detailAddress',
|
||||||
@@ -409,6 +400,15 @@ export default {
|
|||||||
{ validator: validateLatitude, trigger: 'blur' },
|
{ validator: validateLatitude, trigger: 'blur' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '行政区划编号',
|
||||||
|
prop: 'regionCode',
|
||||||
|
minWidth: 160,
|
||||||
|
overHidden: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
rules: [{ max: 32, message: '行政区划编码不能超过32字', trigger: 'blur' }],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '数据来源',
|
label: '数据来源',
|
||||||
prop: 'dataSource',
|
prop: 'dataSource',
|
||||||
@@ -425,23 +425,6 @@ export default {
|
|||||||
{ label: '手动录入', value: '手动录入' },
|
{ label: '手动录入', value: '手动录入' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '启停状态',
|
|
||||||
prop: 'status',
|
|
||||||
type: 'select',
|
|
||||||
search: true,
|
|
||||||
slot: true,
|
|
||||||
dataType: 'number',
|
|
||||||
minWidth: 110,
|
|
||||||
overHidden: false,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
dicData: [
|
|
||||||
{ label: '全部', value: '' },
|
|
||||||
{ label: '启用', value: 1 },
|
|
||||||
{ label: '停用', value: 2 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '备注',
|
label: '备注',
|
||||||
prop: 'remark',
|
prop: 'remark',
|
||||||
@@ -483,6 +466,23 @@ export default {
|
|||||||
display: false,
|
display: false,
|
||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '启停状态',
|
||||||
|
prop: 'status',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
slot: true,
|
||||||
|
dataType: 'number',
|
||||||
|
minWidth: 110,
|
||||||
|
overHidden: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
dicData: [
|
||||||
|
{ label: '全部', value: '' },
|
||||||
|
{ label: '启用', value: 1 },
|
||||||
|
{ label: '停用', value: 2 },
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
excelOption: {
|
excelOption: {
|
||||||
@@ -869,17 +869,12 @@ export default {
|
|||||||
type: 'warning',
|
type: 'warning',
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
NProgress.start();
|
NProgress.start();
|
||||||
exportBlob(
|
exportBlob('/blade-system/airport-master/export-airport-master', this.buildExportParams(), {
|
||||||
'/blade-system/airport-master/export-airport-master',
|
feedback: true,
|
||||||
this.buildExportParams(),
|
})
|
||||||
{ feedback: true }
|
|
||||||
)
|
|
||||||
.then(async res => {
|
.then(async res => {
|
||||||
const blob = await addExcelRequiredHeaderMarks(res.data);
|
const blob = await addExcelRequiredHeaderMarks(res.data);
|
||||||
downloadXls(
|
downloadXls(blob, `空港机场主数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
|
||||||
blob,
|
|
||||||
`空港机场主数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
:table-loading="loading"
|
:table-loading="loading"
|
||||||
:data="data"
|
:data="data"
|
||||||
v-model:page="page"
|
v-model:page="page"
|
||||||
v-model:form="form"
|
v-model="form"
|
||||||
ref="crud"
|
ref="crud"
|
||||||
:permission="permissionList"
|
:permission="permissionList"
|
||||||
:before-open="beforeOpen"
|
:before-open="beforeOpen"
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
>
|
>
|
||||||
<template #menu-left>
|
<template #menu-left>
|
||||||
<el-button type="primary" v-if="permission.cargo_type_add" @click="$refs.crud.rowAdd()">
|
<el-button type="primary" v-if="permission.cargo_type_add" @click="$refs.crud.rowAdd()">
|
||||||
<el-icon class="el-icon--left"><Plus /></el-icon>新增
|
<el-icon class="el-icon--left"><Plus /></el-icon>新建货物类型
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" plain v-if="permission.cargo_type_import" @click="handleImport"
|
<el-button type="primary" plain v-if="permission.cargo_type_import" @click="handleImport"
|
||||||
><el-icon class="el-icon--left"><Upload /></el-icon>批量导入</el-button
|
><el-icon class="el-icon--left"><Upload /></el-icon>批量导入</el-button
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
:remote-method="loadParentOptions"
|
:remote-method="loadParentOptions"
|
||||||
:loading="parentLoading"
|
:loading="parentLoading"
|
||||||
:disabled="dialogType === 'view' || form.typeLevel !== 2"
|
:disabled="dialogType === 'view' || form.typeLevel !== 2"
|
||||||
placeholder="请输入名称或编码搜索"
|
placeholder="请输入"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@change="handleParentChange"
|
@change="handleParentChange"
|
||||||
>
|
>
|
||||||
@@ -348,6 +348,11 @@ export default {
|
|||||||
const parent = this.parentOptions.find(item => String(item.id) === String(value));
|
const parent = this.parentOptions.find(item => String(item.id) === String(value));
|
||||||
this.form.parentCargoName = parent ? parent.cargoName : '';
|
this.form.parentCargoName = parent ? parent.cargoName : '';
|
||||||
this.form.parentCargoCode = parent ? parent.cargoCode || parent.code || '' : '';
|
this.form.parentCargoCode = parent ? parent.cargoCode || parent.code || '' : '';
|
||||||
|
if (parent) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.crud?.clearValidate?.(['parentId', 'parentCargoCode']);
|
||||||
|
});
|
||||||
|
}
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
this.form.cargoCode = '';
|
this.form.cargoCode = '';
|
||||||
return;
|
return;
|
||||||
@@ -540,7 +545,10 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
buildExportParams() {
|
buildExportParams() {
|
||||||
return { ...this.query };
|
return {
|
||||||
|
...this.query,
|
||||||
|
...(this.ids ? { ids: this.ids } : {}),
|
||||||
|
};
|
||||||
},
|
},
|
||||||
handleExport() {
|
handleExport() {
|
||||||
this.$confirm('是否导出货物类型数据?', '提示', {
|
this.$confirm('是否导出货物类型数据?', '提示', {
|
||||||
@@ -564,16 +572,9 @@ export default {
|
|||||||
},
|
},
|
||||||
handleTemplate() {
|
handleTemplate() {
|
||||||
NProgress.start();
|
NProgress.start();
|
||||||
// 直接下载工程内置的标准导入模板(public 目录静态资源),表头与可正常导入的模板一致,
|
exportBlob('/blade-system/cargo-type/export-template', {}, { feedback: true })
|
||||||
// 含一级(19 类)及全部二级示例,便于用户参照填写层级关系与编码规则
|
|
||||||
const templateUrl = `${import.meta.env.BASE_URL}cargo-type-import-template.xlsx`;
|
|
||||||
fetch(templateUrl)
|
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (!res.ok) throw new Error('模板文件不存在');
|
downloadXls(res.data, '货物类型导入模板.xlsx');
|
||||||
return res.blob();
|
|
||||||
})
|
|
||||||
.then(blob => {
|
|
||||||
downloadXls(blob, '货物类型导入模板.xlsx');
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
this.$message.error('模板下载失败,请稍后重试');
|
this.$message.error('模板下载失败,请稍后重试');
|
||||||
|
|||||||
@@ -24,10 +24,9 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
plain
|
|
||||||
v-if="hasPermission('common_address_add')"
|
v-if="hasPermission('common_address_add')"
|
||||||
@click="$refs.crud.rowAdd()"
|
@click="$refs.crud.rowAdd()"
|
||||||
>新增
|
>新建常用地址
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -188,7 +187,6 @@
|
|||||||
/>
|
/>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.detailAddress"
|
v-model="form.detailAddress"
|
||||||
readonly
|
|
||||||
maxlength="255"
|
maxlength="255"
|
||||||
placeholder="点击后弹出地图组件"
|
placeholder="点击后弹出地图组件"
|
||||||
suffix-icon="el-icon-location"
|
suffix-icon="el-icon-location"
|
||||||
@@ -389,10 +387,96 @@ export default {
|
|||||||
column.rules = rules;
|
column.rules = rules;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setColumnSpan(prop, span) {
|
||||||
|
const column = this.findColumn(this.option.column, prop);
|
||||||
|
if (column) {
|
||||||
|
column.span = span;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setColumnRow(prop, row) {
|
||||||
|
const column = this.findColumn(this.option.column, prop);
|
||||||
|
if (column) {
|
||||||
|
column.row = row;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setColumnOrder(prop, order) {
|
||||||
|
const column = this.findColumn(this.option.column, prop);
|
||||||
|
if (column) {
|
||||||
|
column.order = order;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
syncSourceFormLayout(addressType) {
|
||||||
|
const isPortTerminal = addressType === '港口/码头';
|
||||||
|
const isRailwayStation = addressType === '铁路车站';
|
||||||
|
const isAirport = addressType === '空港机场';
|
||||||
|
const isRegularAddress = addressType === '常规地址';
|
||||||
|
this.setColumnSpan(
|
||||||
|
'addressName',
|
||||||
|
isRegularAddress || isPortTerminal || isRailwayStation || isAirport ? 12 : 24
|
||||||
|
);
|
||||||
|
this.setColumnRow('addressName', true);
|
||||||
|
this.setColumnSpan('stationId', isRailwayStation ? 12 : 24);
|
||||||
|
this.setColumnSpan('airportId', isAirport ? 12 : 24);
|
||||||
|
this.setColumnRow('stationId', isRailwayStation);
|
||||||
|
this.setColumnRow('airportId', isAirport);
|
||||||
|
const formOrders = {
|
||||||
|
addressType: 100,
|
||||||
|
addressName: 70,
|
||||||
|
contactName: 60,
|
||||||
|
contactPhone: 50,
|
||||||
|
detailAddress: 40,
|
||||||
|
remark: 30,
|
||||||
|
};
|
||||||
|
if (isPortTerminal) {
|
||||||
|
Object.assign(formOrders, {
|
||||||
|
addressType: 80,
|
||||||
|
portId: 70,
|
||||||
|
terminalId: 60,
|
||||||
|
addressName: 50,
|
||||||
|
contactName: 40,
|
||||||
|
contactPhone: 30,
|
||||||
|
detailAddress: 20,
|
||||||
|
remark: 10,
|
||||||
|
});
|
||||||
|
} else if (isRailwayStation) {
|
||||||
|
Object.assign(formOrders, {
|
||||||
|
addressType: 80,
|
||||||
|
stationId: 70,
|
||||||
|
addressName: 60,
|
||||||
|
contactName: 50,
|
||||||
|
contactPhone: 40,
|
||||||
|
detailAddress: 30,
|
||||||
|
remark: 20,
|
||||||
|
});
|
||||||
|
} else if (isAirport) {
|
||||||
|
Object.assign(formOrders, {
|
||||||
|
addressType: 80,
|
||||||
|
airportId: 70,
|
||||||
|
addressName: 60,
|
||||||
|
contactName: 50,
|
||||||
|
contactPhone: 40,
|
||||||
|
detailAddress: 30,
|
||||||
|
remark: 20,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
[
|
||||||
|
'addressType',
|
||||||
|
'portId',
|
||||||
|
'terminalId',
|
||||||
|
'stationId',
|
||||||
|
'airportId',
|
||||||
|
'addressName',
|
||||||
|
'contactName',
|
||||||
|
'contactPhone',
|
||||||
|
'detailAddress',
|
||||||
|
'remark',
|
||||||
|
].forEach(prop => this.setColumnOrder(prop, formOrders[prop]));
|
||||||
|
},
|
||||||
syncSourceColumnDisplay(addressType) {
|
syncSourceColumnDisplay(addressType) {
|
||||||
const isPortTerminal = addressType === '港口/码头';
|
const isPortTerminal = addressType === '港口/码头';
|
||||||
const isRailwayStation = addressType === '铁路车站';
|
const isRailwayStation = addressType === '铁路车站';
|
||||||
const isAirport = addressType === '空港机场';
|
const isAirport = addressType === '空港机场';
|
||||||
|
this.syncSourceFormLayout(addressType);
|
||||||
this.setColumnDisplay('portId', isPortTerminal);
|
this.setColumnDisplay('portId', isPortTerminal);
|
||||||
this.setColumnDisplay('terminalId', isPortTerminal);
|
this.setColumnDisplay('terminalId', isPortTerminal);
|
||||||
this.setColumnDisplay('stationId', isRailwayStation);
|
this.setColumnDisplay('stationId', isRailwayStation);
|
||||||
@@ -1183,6 +1267,17 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.common-address-page :deep(.avue-crud__dialog .avue-form__row),
|
||||||
|
.common-address-page :deep(.avue-crud__dialog .el-row) {
|
||||||
|
margin-right: -16px;
|
||||||
|
margin-left: -16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.common-address-page :deep(.avue-crud__dialog .el-col) {
|
||||||
|
padding-right: 16px;
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.common-address-page {
|
.common-address-page {
|
||||||
&__map-address {
|
&__map-address {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '中文名称',
|
label: '中文名称',
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: false,
|
selection: false,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '费用类型',
|
label: '费用类型',
|
||||||
|
|||||||
@@ -229,7 +229,15 @@ import 'nprogress/nprogress.css';
|
|||||||
|
|
||||||
const DEFAULT_COUNTRY_CODE = '+86';
|
const DEFAULT_COUNTRY_CODE = '+86';
|
||||||
const EXCLUDED_EXCEL_HEADERS = ['数据来源', '启停状态'];
|
const EXCLUDED_EXCEL_HEADERS = ['数据来源', '启停状态'];
|
||||||
const REQUIRED_EXPORT_HEADERS = ['港口码头名称', '港口/码头名称', '类型', '国家', '城市', '经度', '纬度'];
|
const REQUIRED_EXPORT_HEADERS = [
|
||||||
|
'港口码头名称',
|
||||||
|
'港口/码头名称',
|
||||||
|
'类型',
|
||||||
|
'国家',
|
||||||
|
'城市',
|
||||||
|
'经度',
|
||||||
|
'纬度',
|
||||||
|
];
|
||||||
|
|
||||||
const getExcelCellText = value => {
|
const getExcelCellText = value => {
|
||||||
if (value === undefined || value === null) return '';
|
if (value === undefined || value === null) return '';
|
||||||
@@ -256,9 +264,7 @@ const removeWorkbookColumnsByHeaders = workbook => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (indexes.length) {
|
if (indexes.length) {
|
||||||
indexes
|
indexes.sort((a, b) => b - a).forEach(colNumber => worksheet.spliceColumns(colNumber, 1));
|
||||||
.sort((a, b) => b - a)
|
|
||||||
.forEach(colNumber => worksheet.spliceColumns(colNumber, 1));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,15 +387,44 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
|
{
|
||||||
|
label: '编码',
|
||||||
|
prop: 'code',
|
||||||
|
search: true,
|
||||||
|
formslot: true,
|
||||||
|
width: 140,
|
||||||
|
span: 12,
|
||||||
|
order: 70,
|
||||||
|
placeholder: '请输入编码',
|
||||||
|
rules: [
|
||||||
|
{ required: true, message: '请输入编码', trigger: 'blur' },
|
||||||
|
{ validator: validateCode, trigger: 'blur' },
|
||||||
|
],
|
||||||
|
change: ({ value }) => this.handleCodeChange(value),
|
||||||
|
blur: ({ value }) => this.handleCodeChange(value),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '港口/码头名称',
|
||||||
|
prop: 'name',
|
||||||
|
minWidth: 140,
|
||||||
|
search: true,
|
||||||
|
searchOrder: 7,
|
||||||
|
span: 12,
|
||||||
|
order: 80,
|
||||||
|
placeholder: '请输入',
|
||||||
|
rules: [{ required: true, message: '请输入港口/码头名称', trigger: 'blur' }],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '类型',
|
label: '类型',
|
||||||
prop: 'category',
|
prop: 'category',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 6,
|
||||||
formslot: true,
|
formslot: true,
|
||||||
span: 24,
|
span: 24,
|
||||||
|
order: 100,
|
||||||
dicData: [
|
dicData: [
|
||||||
{ label: '全部', value: '' },
|
{ label: '全部', value: '' },
|
||||||
{ label: '港口', value: '港口' },
|
{ label: '港口', value: '港口' },
|
||||||
@@ -409,6 +444,7 @@ export default {
|
|||||||
dicData: [],
|
dicData: [],
|
||||||
hide: true,
|
hide: true,
|
||||||
span: 12,
|
span: 12,
|
||||||
|
order: 90,
|
||||||
placeholder: '请选择',
|
placeholder: '请选择',
|
||||||
rules: [{ required: false, message: '请选择上级港口', trigger: 'change' }],
|
rules: [{ required: false, message: '请选择上级港口', trigger: 'change' }],
|
||||||
change: ({ value }) => this.handleParentChange(value),
|
change: ({ value }) => this.handleParentChange(value),
|
||||||
@@ -416,7 +452,7 @@ export default {
|
|||||||
{
|
{
|
||||||
label: '上级港口',
|
label: '上级港口',
|
||||||
prop: 'parentName',
|
prop: 'parentName',
|
||||||
minWidth: 120,
|
minWidth: 140,
|
||||||
slot: true,
|
slot: true,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
@@ -432,39 +468,17 @@ export default {
|
|||||||
placeholder: '自动带出',
|
placeholder: '自动带出',
|
||||||
rules: [{ required: false, message: '请选择上级港口', trigger: 'change' }],
|
rules: [{ required: false, message: '请选择上级港口', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '港口/码头名称',
|
|
||||||
prop: 'name',
|
|
||||||
minWidth: 140,
|
|
||||||
search: true,
|
|
||||||
span: 12,
|
|
||||||
placeholder: '请输入',
|
|
||||||
rules: [{ required: true, message: '请输入港口/码头名称', trigger: 'blur' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '编码',
|
|
||||||
prop: 'code',
|
|
||||||
search: true,
|
|
||||||
formslot: true,
|
|
||||||
width: 140,
|
|
||||||
span: 12,
|
|
||||||
placeholder: '请输入编码',
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: '请输入编码', trigger: 'blur' },
|
|
||||||
{ validator: validateCode, trigger: 'blur' },
|
|
||||||
],
|
|
||||||
change: ({ value }) => this.handleCodeChange(value),
|
|
||||||
blur: ({ value }) => this.handleCodeChange(value),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '国家',
|
label: '国家',
|
||||||
prop: 'country',
|
prop: 'country',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 5,
|
||||||
formslot: true,
|
formslot: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
dicData: [],
|
dicData: [],
|
||||||
span: 12,
|
span: 12,
|
||||||
|
order: 60,
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
overHidden: false,
|
overHidden: false,
|
||||||
placeholder: '自动带出',
|
placeholder: '自动带出',
|
||||||
@@ -478,6 +492,7 @@ export default {
|
|||||||
formslot: true,
|
formslot: true,
|
||||||
hide: true,
|
hide: true,
|
||||||
span: 12,
|
span: 12,
|
||||||
|
order: 50,
|
||||||
placeholder: '自动带出',
|
placeholder: '自动带出',
|
||||||
rules: [{ required: true, message: '请选择所属城市', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择所属城市', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
@@ -486,6 +501,7 @@ export default {
|
|||||||
prop: 'city',
|
prop: 'city',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 4,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
dicData: [],
|
dicData: [],
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
@@ -513,14 +529,44 @@ export default {
|
|||||||
prop: 'districtName',
|
prop: 'districtName',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 3,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
dicData: [],
|
dicData: [],
|
||||||
minWidth: 100,
|
minWidth: 100,
|
||||||
|
hide: true,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '行政区划编号',
|
label: '经度',
|
||||||
|
prop: 'longitude',
|
||||||
|
formslot: true,
|
||||||
|
minWidth: 130,
|
||||||
|
span: 12,
|
||||||
|
order: 20,
|
||||||
|
placeholder: '请输入',
|
||||||
|
overHidden: false,
|
||||||
|
rules: [
|
||||||
|
{ required: true, message: '请输入经度', trigger: 'blur' },
|
||||||
|
{ validator: validateLongitude, trigger: 'blur' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '纬度',
|
||||||
|
prop: 'latitude',
|
||||||
|
formslot: true,
|
||||||
|
minWidth: 130,
|
||||||
|
span: 12,
|
||||||
|
order: 10,
|
||||||
|
placeholder: '请输入',
|
||||||
|
overHidden: false,
|
||||||
|
rules: [
|
||||||
|
{ required: true, message: '请输入纬度', trigger: 'blur' },
|
||||||
|
{ validator: validateLatitude, trigger: 'blur' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '行政区划编码',
|
||||||
prop: 'regionCode',
|
prop: 'regionCode',
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
span: 12,
|
span: 12,
|
||||||
@@ -538,42 +584,18 @@ export default {
|
|||||||
span: 24,
|
span: 24,
|
||||||
minWidth: 220,
|
minWidth: 220,
|
||||||
overHidden: false,
|
overHidden: false,
|
||||||
|
order: 30,
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
maxlength: 255,
|
maxlength: 255,
|
||||||
showWordLimit: true,
|
showWordLimit: true,
|
||||||
rules: [{ max: 255, message: '详细地址不能超过255字', trigger: 'blur' }],
|
rules: [{ max: 255, message: '详细地址不能超过255字', trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '经度',
|
|
||||||
prop: 'longitude',
|
|
||||||
formslot: true,
|
|
||||||
minWidth: 130,
|
|
||||||
span: 12,
|
|
||||||
placeholder: '请输入',
|
|
||||||
overHidden: false,
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: '请输入经度', trigger: 'blur' },
|
|
||||||
{ validator: validateLongitude, trigger: 'blur' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '纬度',
|
|
||||||
prop: 'latitude',
|
|
||||||
formslot: true,
|
|
||||||
minWidth: 130,
|
|
||||||
span: 12,
|
|
||||||
placeholder: '请输入',
|
|
||||||
overHidden: false,
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: '请输入纬度', trigger: 'blur' },
|
|
||||||
{ validator: validateLatitude, trigger: 'blur' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '数据来源',
|
label: '数据来源',
|
||||||
prop: 'dataSource',
|
prop: 'dataSource',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 2,
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
overHidden: false,
|
overHidden: false,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
@@ -585,23 +607,6 @@ export default {
|
|||||||
{ label: '手工导入', value: '手工导入' },
|
{ label: '手工导入', value: '手工导入' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '启停状态',
|
|
||||||
prop: 'status',
|
|
||||||
type: 'select',
|
|
||||||
search: true,
|
|
||||||
slot: true,
|
|
||||||
dataType: 'number',
|
|
||||||
minWidth: 110,
|
|
||||||
overHidden: false,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
dicData: [
|
|
||||||
{ label: '全部', value: '' },
|
|
||||||
{ label: '启用', value: 1 },
|
|
||||||
{ label: '停用', value: 2 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '备注',
|
label: '备注',
|
||||||
prop: 'remark',
|
prop: 'remark',
|
||||||
@@ -639,9 +644,26 @@ export default {
|
|||||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
display: false,
|
|
||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '状态',
|
||||||
|
prop: 'status',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 1,
|
||||||
|
slot: true,
|
||||||
|
dataType: 'number',
|
||||||
|
minWidth: 110,
|
||||||
|
overHidden: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
dicData: [
|
||||||
|
{ label: '全部', value: '' },
|
||||||
|
{ label: '启用', value: 1 },
|
||||||
|
{ label: '停用', value: 2 },
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
excelOption: {
|
excelOption: {
|
||||||
@@ -1270,19 +1292,14 @@ export default {
|
|||||||
type: 'warning',
|
type: 'warning',
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
NProgress.start();
|
NProgress.start();
|
||||||
exportBlob(
|
exportBlob('/blade-system/port-terminal/export-port-terminal', this.buildExportParams(), {
|
||||||
'/blade-system/port-terminal/export-port-terminal',
|
feedback: true,
|
||||||
this.buildExportParams(),
|
})
|
||||||
{ feedback: true }
|
|
||||||
)
|
|
||||||
.then(async res => {
|
.then(async res => {
|
||||||
const blob = await removeExcelColumnsByHeaders(res.data, {
|
const blob = await removeExcelColumnsByHeaders(res.data, {
|
||||||
markRequiredHeaders: true,
|
markRequiredHeaders: true,
|
||||||
});
|
});
|
||||||
downloadXls(
|
downloadXls(blob, `港口码头主数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
|
||||||
blob,
|
|
||||||
`港口码头主数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '编码',
|
label: '编码',
|
||||||
@@ -335,15 +335,6 @@ export default {
|
|||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '行政区划编号',
|
|
||||||
prop: 'regionCode',
|
|
||||||
minWidth: 160,
|
|
||||||
overHidden: false,
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
rules: [{ max: 32, message: '行政区划编码不能超过32字', trigger: 'blur' }],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '详细地址',
|
label: '详细地址',
|
||||||
prop: 'detailAddress',
|
prop: 'detailAddress',
|
||||||
@@ -373,20 +364,13 @@ export default {
|
|||||||
rules: [{ validator: validateLatitude, trigger: 'blur' }],
|
rules: [{ validator: validateLatitude, trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '数据来源',
|
label: '行政区划编号',
|
||||||
prop: 'dataSource',
|
prop: 'regionCode',
|
||||||
type: 'select',
|
minWidth: 160,
|
||||||
search: true,
|
|
||||||
minWidth: 120,
|
|
||||||
overHidden: false,
|
overHidden: false,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
dicData: [
|
rules: [{ max: 32, message: '行政区划编码不能超过32字', trigger: 'blur' }],
|
||||||
{ label: '全部', value: '' },
|
|
||||||
{ label: '初始化导入', value: '初始化导入' },
|
|
||||||
{ label: '批量', value: '批量' },
|
|
||||||
{ label: '手动', value: '手动' },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '启停状态',
|
label: '启停状态',
|
||||||
@@ -446,6 +430,22 @@ export default {
|
|||||||
display: false,
|
display: false,
|
||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '数据来源',
|
||||||
|
prop: 'dataSource',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
minWidth: 120,
|
||||||
|
overHidden: false,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
dicData: [
|
||||||
|
{ label: '全部', value: '' },
|
||||||
|
{ label: '初始化导入', value: '初始化导入' },
|
||||||
|
{ label: '批量', value: '批量' },
|
||||||
|
{ label: '手动', value: '手动' },
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
excelOption: {
|
excelOption: {
|
||||||
|
|||||||
@@ -11,6 +11,37 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col class="region-page__form-panel" :span="18">
|
<el-col class="region-page__form-panel" :span="18">
|
||||||
<basic-container>
|
<basic-container>
|
||||||
|
<el-form class="region-page__search" :model="searchForm" inline>
|
||||||
|
<el-form-item label="区域编码">
|
||||||
|
<el-input v-model="searchForm.code" clearable placeholder="请输入区域编码" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="区域名称">
|
||||||
|
<el-input v-model="searchForm.name" clearable placeholder="请输入区域名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="区域层级">
|
||||||
|
<el-select v-model="searchForm.regionLevel" clearable placeholder="请选择区域层级">
|
||||||
|
<el-option label="省份" :value="1" />
|
||||||
|
<el-option label="省市" :value="2" />
|
||||||
|
<el-option label="区县" :value="3" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="数据来源">
|
||||||
|
<el-select v-model="searchForm.dataSource" clearable placeholder="请选择数据来源">
|
||||||
|
<el-option label="手动录入" value="手动录入" />
|
||||||
|
<el-option label="初始化导入" value="初始化导入" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="启停状态">
|
||||||
|
<el-select v-model="searchForm.status" clearable placeholder="请选择启停状态">
|
||||||
|
<el-option label="启用" :value="1" />
|
||||||
|
<el-option label="停用" :value="2" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="region-page__search-actions">
|
||||||
|
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||||||
|
<el-button @click="handleSearchReset">清空</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
<el-button-group>
|
<el-button-group>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="permission.region_add"
|
v-if="permission.region_add"
|
||||||
@@ -136,14 +167,21 @@ export default {
|
|||||||
treeCode: '',
|
treeCode: '',
|
||||||
treeParentCode: '',
|
treeParentCode: '',
|
||||||
treeData: [],
|
treeData: [],
|
||||||
|
searchForm: {
|
||||||
|
code: '',
|
||||||
|
name: '',
|
||||||
|
regionLevel: undefined,
|
||||||
|
dataSource: '',
|
||||||
|
status: undefined,
|
||||||
|
},
|
||||||
parentOptions: [],
|
parentOptions: [],
|
||||||
syncLoading: false,
|
syncLoading: false,
|
||||||
treeOption: {
|
treeOption: {
|
||||||
nodeKey: 'id',
|
nodeKey: 'id',
|
||||||
lazy: true,
|
lazy: true,
|
||||||
treeLoad: function (node, resolve) {
|
treeLoad: (node, resolve) => {
|
||||||
const parentCode = node.level === 0 ? ROOT_PARENT_CODE : node.data.id;
|
const parentCode = node.level === 0 ? ROOT_PARENT_CODE : node.data.id;
|
||||||
getLazyTree(parentCode).then(res => {
|
getLazyTree(parentCode, this.searchForm).then(res => {
|
||||||
resolve(
|
resolve(
|
||||||
res.data.data.map(item => {
|
res.data.data.map(item => {
|
||||||
return {
|
return {
|
||||||
@@ -402,7 +440,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
initTree() {
|
initTree() {
|
||||||
this.treeData = [];
|
this.treeData = [];
|
||||||
getLazyTree(this.topCode).then(res => {
|
getLazyTree(this.topCode, this.searchForm).then(res => {
|
||||||
this.treeData = res.data.data.map(item => {
|
this.treeData = res.data.data.map(item => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -411,6 +449,20 @@ export default {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleSearch() {
|
||||||
|
this.initTree();
|
||||||
|
this.regionForm = {};
|
||||||
|
},
|
||||||
|
handleSearchReset() {
|
||||||
|
this.searchForm = {
|
||||||
|
code: '',
|
||||||
|
name: '',
|
||||||
|
regionLevel: undefined,
|
||||||
|
dataSource: '',
|
||||||
|
status: undefined,
|
||||||
|
};
|
||||||
|
this.handleSearch();
|
||||||
|
},
|
||||||
nodeClick(data) {
|
nodeClick(data) {
|
||||||
this.setRegionColumnDisplay('code', true);
|
this.setRegionColumnDisplay('code', true);
|
||||||
this.treeCode = data.id;
|
this.treeCode = data.id;
|
||||||
@@ -624,20 +676,18 @@ export default {
|
|||||||
type: 'warning',
|
type: 'warning',
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
NProgress.start();
|
NProgress.start();
|
||||||
exportBlob(
|
exportBlob(`/blade-system/region/export-region?${this.website.tokenHeader}=${getToken()}`, {
|
||||||
`/blade-system/region/export-region?${this.website.tokenHeader}=${getToken()}`,
|
feedback: true,
|
||||||
{ feedback: true }
|
}).then(res => {
|
||||||
).then(res => {
|
|
||||||
downloadXls(res.data, `行政区划数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
|
downloadXls(res.data, `行政区划数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleTemplate() {
|
handleTemplate() {
|
||||||
exportBlob(
|
exportBlob(`/blade-system/region/export-template?${this.website.tokenHeader}=${getToken()}`, {
|
||||||
`/blade-system/region/export-template?${this.website.tokenHeader}=${getToken()}`,
|
feedback: true,
|
||||||
{ feedback: true }
|
}).then(res => {
|
||||||
).then(res => {
|
|
||||||
downloadXls(res.data, '行政区划模板.xlsx');
|
downloadXls(res.data, '行政区划模板.xlsx');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,10 +24,9 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
plain
|
|
||||||
v-if="hasPermission('common_cargo_add')"
|
v-if="hasPermission('common_cargo_add')"
|
||||||
@click="$refs.crud.rowAdd()"
|
@click="$refs.crud.rowAdd()"
|
||||||
>新增
|
>新建常用货物
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -113,7 +112,7 @@
|
|||||||
clearable
|
clearable
|
||||||
maxlength="20"
|
maxlength="20"
|
||||||
show-word-limit
|
show-word-limit
|
||||||
placeholder="请输入货物编号"
|
placeholder="请输入"
|
||||||
:disabled="dialogReadonly || dialogType === 'edit'"
|
:disabled="dialogReadonly || dialogType === 'edit'"
|
||||||
@input="handleCargoCodeInput"
|
@input="handleCargoCodeInput"
|
||||||
/>
|
/>
|
||||||
@@ -144,6 +143,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #packageBrand="{ row }">
|
||||||
|
{{ [row.packageType, row.brand].filter(Boolean).join(' / ') || '-' }}
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -192,6 +195,7 @@
|
|||||||
import * as api from '@/api/business/common-cargo';
|
import * as api from '@/api/business/common-cargo';
|
||||||
import { getList as getCargoTypeList } from '@/api/base/cargo-type';
|
import { getList as getCargoTypeList } from '@/api/base/cargo-type';
|
||||||
import { exportBlob } from '@/api/common';
|
import { exportBlob } from '@/api/common';
|
||||||
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
import { config, excelOption, option } from '@/option/business/common-cargo';
|
import { config, excelOption, option } from '@/option/business/common-cargo';
|
||||||
import { priceUnitOptions } from '@/option/business/common';
|
import { priceUnitOptions } from '@/option/business/common';
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
@@ -221,6 +225,7 @@ export default {
|
|||||||
secondCargoTypeLoading: false,
|
secondCargoTypeLoading: false,
|
||||||
firstCargoTypeOptions: [],
|
firstCargoTypeOptions: [],
|
||||||
secondCargoTypeOptions: [],
|
secondCargoTypeOptions: [],
|
||||||
|
deptOptions: [],
|
||||||
page: {
|
page: {
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
pageSizes: [10, 20, 50, 100],
|
pageSizes: [10, 20, 50, 100],
|
||||||
@@ -247,6 +252,9 @@ export default {
|
|||||||
return this.selectionList.map(item => item.id).join(',');
|
return this.selectionList.map(item => item.id).join(',');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
this.initDeptTree();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
hasPermission(code) {
|
hasPermission(code) {
|
||||||
return this.isAdmin || this.validData(this.permission && this.permission[code], false);
|
return this.isAdmin || this.validData(this.permission && this.permission[code], false);
|
||||||
@@ -256,6 +264,28 @@ export default {
|
|||||||
if (Array.isArray(data)) return data;
|
if (Array.isArray(data)) return data;
|
||||||
return (data && data.records) || [];
|
return (data && data.records) || [];
|
||||||
},
|
},
|
||||||
|
initDeptTree() {
|
||||||
|
getDeptTree(this.userInfo.tenantId).then(res => {
|
||||||
|
this.deptOptions = this.flattenDept(res.data.data || []);
|
||||||
|
const deptColumn = this.findColumn(this.option.column, 'searchDeptId');
|
||||||
|
if (deptColumn) {
|
||||||
|
deptColumn.dicData = this.deptOptions;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
flattenDept(tree, level = 0) {
|
||||||
|
const result = [];
|
||||||
|
tree.forEach(item => {
|
||||||
|
result.push({
|
||||||
|
label: `${' '.repeat(level)}${item.title || item.deptName || item.name}`,
|
||||||
|
value: item.id,
|
||||||
|
});
|
||||||
|
if (item.children && item.children.length) {
|
||||||
|
result.push(...this.flattenDept(item.children, level + 1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
},
|
||||||
normalizeCargoTypeOptions(list = []) {
|
normalizeCargoTypeOptions(list = []) {
|
||||||
return list
|
return list
|
||||||
.map(item => ({
|
.map(item => ({
|
||||||
@@ -319,11 +349,12 @@ export default {
|
|||||||
const second = this.secondCargoTypeOptions.find(item => item.cargoCode === value);
|
const second = this.secondCargoTypeOptions.find(item => item.cargoCode === value);
|
||||||
this.form.secondCargoTypeName = second ? second.cargoName : '';
|
this.form.secondCargoTypeName = second ? second.cargoName : '';
|
||||||
this.form.secondCargoTypeCode = second ? second.cargoCode : '';
|
this.form.secondCargoTypeCode = second ? second.cargoCode : '';
|
||||||
|
this.form.cargoCode = second ? String(second.cargoCode).slice(0, 4) : '';
|
||||||
this.syncCargoCodePrefix();
|
this.syncCargoCodePrefix();
|
||||||
},
|
},
|
||||||
getCargoCodePrefix() {
|
getCargoCodePrefix() {
|
||||||
return this.form.secondCargoTypeCode && this.form.firstCargoTypeCode
|
return this.form.secondCargoTypeCode
|
||||||
? this.form.firstCargoTypeCode
|
? String(this.form.secondCargoTypeCode).slice(0, 4)
|
||||||
: '';
|
: '';
|
||||||
},
|
},
|
||||||
syncCargoCodePrefix() {
|
syncCargoCodePrefix() {
|
||||||
@@ -383,13 +414,13 @@ export default {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const cargoCode = String(row.cargoCode || '');
|
const cargoCode = String(row.cargoCode || '');
|
||||||
const prefix = row.firstCargoTypeCode;
|
const prefix = String(row.secondCargoTypeCode || '').slice(0, 4);
|
||||||
if (!cargoCode || cargoCode === prefix) {
|
if (!cargoCode || cargoCode === prefix) {
|
||||||
this.$message.warning('请输入货物编号');
|
this.$message.warning('请输入货物编号');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!cargoCode.startsWith(prefix)) {
|
if (!cargoCode.startsWith(prefix)) {
|
||||||
this.$message.warning('货物编号需拼接一级货物类型编号在前面');
|
this.$message.warning('货物编号需拼接二级货物类型编号在前面');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (cargoCode.length > 20) {
|
if (cargoCode.length > 20) {
|
||||||
|
|||||||
@@ -24,10 +24,25 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
plain
|
|
||||||
v-if="hasPermission('common_route_add')"
|
v-if="hasPermission('common_route_add')"
|
||||||
@click="$refs.crud.rowAdd()"
|
@click="$refs.crud.rowAdd()"
|
||||||
>新增
|
>新建路线
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-upload"
|
||||||
|
plain
|
||||||
|
v-if="config.importUrl && hasPermission('common_route_import')"
|
||||||
|
@click="handleImport"
|
||||||
|
>批量导入
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-download"
|
||||||
|
plain
|
||||||
|
v-if="config.templateUrl && hasPermission('common_route_template')"
|
||||||
|
@click="handleTemplate"
|
||||||
|
>下载模板
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -57,10 +72,10 @@
|
|||||||
/>
|
/>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.departureAddress"
|
v-model="form.departureAddress"
|
||||||
readonly
|
|
||||||
placeholder="请输入并选择地址"
|
placeholder="请输入并选择地址"
|
||||||
suffix-icon="el-icon-location"
|
suffix-icon="el-icon-location"
|
||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
|
@click="openRouteMapDialog('departure')"
|
||||||
/>
|
/>
|
||||||
<el-tooltip content="选择常用地址" placement="top">
|
<el-tooltip content="选择常用地址" placement="top">
|
||||||
<el-button
|
<el-button
|
||||||
@@ -84,10 +99,10 @@
|
|||||||
/>
|
/>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.arrivalAddress"
|
v-model="form.arrivalAddress"
|
||||||
readonly
|
|
||||||
placeholder="请输入并选择地址"
|
placeholder="请输入并选择地址"
|
||||||
suffix-icon="el-icon-location"
|
suffix-icon="el-icon-location"
|
||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
|
@click="openRouteMapDialog('arrival')"
|
||||||
/>
|
/>
|
||||||
<el-tooltip content="选择常用地址" placement="top">
|
<el-tooltip content="选择常用地址" placement="top">
|
||||||
<el-button
|
<el-button
|
||||||
@@ -133,6 +148,16 @@
|
|||||||
@load="onLoad(page, query)"
|
@load="onLoad(page, query)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<el-dialog :title="`${config.title}导入`" append-to-body v-model="excelBox" width="555px">
|
||||||
|
<avue-form :option="excelOptionConfig" v-model="excelForm">
|
||||||
|
<template #excelTemplate>
|
||||||
|
<el-button type="primary" @click="handleTemplate">
|
||||||
|
点击下载<i class="el-icon-download el-icon--right"></i>
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</avue-form>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
title="选择常用地址"
|
title="选择常用地址"
|
||||||
append-to-body
|
append-to-body
|
||||||
@@ -141,6 +166,7 @@
|
|||||||
class="common-route-page__address-dialog"
|
class="common-route-page__address-dialog"
|
||||||
@opened="loadAddressList"
|
@opened="loadAddressList"
|
||||||
>
|
>
|
||||||
|
<section-card title="查询条件">
|
||||||
<div class="common-route-page__address-search">
|
<div class="common-route-page__address-search">
|
||||||
<el-form :model="addressQuery" label-position="right" label-width="86px">
|
<el-form :model="addressQuery" label-position="right" label-width="86px">
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
@@ -196,7 +222,9 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
|
<section-card title="常用地址">
|
||||||
<el-table
|
<el-table
|
||||||
border
|
border
|
||||||
:data="addressData"
|
:data="addressData"
|
||||||
@@ -233,11 +261,54 @@
|
|||||||
@current-change="handleAddressCurrentChange"
|
@current-change="handleAddressCurrentChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="addressDialogVisible = false">关闭</el-button>
|
<el-button @click="addressDialogVisible = false">关闭</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
title="地图选择地址"
|
||||||
|
append-to-body
|
||||||
|
v-model="routeMapVisible"
|
||||||
|
width="920px"
|
||||||
|
@opened="initRouteAmap"
|
||||||
|
>
|
||||||
|
<div class="common-route-page__map-toolbar">
|
||||||
|
<el-input
|
||||||
|
v-model="routeMapKeyword"
|
||||||
|
clearable
|
||||||
|
placeholder="输入地址关键词"
|
||||||
|
@keyup.enter="searchRouteMapKeyword"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
:icon="Search"
|
||||||
|
:loading="routeMapLoading"
|
||||||
|
@click="searchRouteMapKeyword"
|
||||||
|
>
|
||||||
|
搜索
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div ref="routeAmap" class="common-route-page__map"></div>
|
||||||
|
<div class="common-route-page__map-info">
|
||||||
|
<span>{{ routeMapStatus }}</span>
|
||||||
|
<span v-if="routeMapSelected.regionName"
|
||||||
|
>发货/收货地:{{ routeMapSelected.regionName }}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="routeMapVisible = false">取消</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
:disabled="!routeMapSelected.longitude"
|
||||||
|
@click="confirmRouteMapPick"
|
||||||
|
>
|
||||||
|
确定
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</basic-container>
|
</basic-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -247,18 +318,24 @@ import { getList as getCommonAddressList } from '@/api/base/common-address';
|
|||||||
import { exportBlob } from '@/api/common';
|
import { exportBlob } from '@/api/common';
|
||||||
import { getDeptTree } from '@/api/system/dept';
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
import { addressTypeOptions } from '@/option/base/common-address';
|
import { addressTypeOptions } from '@/option/base/common-address';
|
||||||
import { config, option } from '@/option/business/common-route';
|
import { config, excelOption, option } from '@/option/business/common-route';
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
|
import { openImportDialog } from '@/utils/import-excel';
|
||||||
import { downloadXls } from '@/utils/util';
|
import { downloadXls } from '@/utils/util';
|
||||||
import { List } from '@element-plus/icons-vue';
|
import { List, Search } from '@element-plus/icons-vue';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import NProgress from 'nprogress';
|
import NProgress from 'nprogress';
|
||||||
import 'nprogress/nprogress.css';
|
import 'nprogress/nprogress.css';
|
||||||
|
|
||||||
|
const AMAP_KEY = '653b7cf105ad7fb8ec9b2f5198ade315';
|
||||||
|
const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a';
|
||||||
|
let amapLoader;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
List,
|
List,
|
||||||
|
Search,
|
||||||
config,
|
config,
|
||||||
option,
|
option,
|
||||||
form: {},
|
form: {},
|
||||||
@@ -266,12 +343,24 @@ export default {
|
|||||||
loading: true,
|
loading: true,
|
||||||
data: [],
|
data: [],
|
||||||
dialogReadonly: false,
|
dialogReadonly: false,
|
||||||
|
excelBox: false,
|
||||||
|
excelForm: {},
|
||||||
|
excelOptionConfig: excelOption,
|
||||||
addressTypeOptions,
|
addressTypeOptions,
|
||||||
addressDialogVisible: false,
|
addressDialogVisible: false,
|
||||||
addressTarget: '',
|
addressTarget: '',
|
||||||
addressQuery: {},
|
addressQuery: {},
|
||||||
addressData: [],
|
addressData: [],
|
||||||
addressLoading: false,
|
addressLoading: false,
|
||||||
|
routeMapVisible: false,
|
||||||
|
routeMapTarget: '',
|
||||||
|
routeMapLoading: false,
|
||||||
|
routeMapKeyword: '',
|
||||||
|
routeMapStatus: '可搜索地址或点击地图选点',
|
||||||
|
routeMapSelected: {},
|
||||||
|
routeAmap: null,
|
||||||
|
routeAmapMarker: null,
|
||||||
|
routeAmapGeocoder: null,
|
||||||
deptOptions: [],
|
deptOptions: [],
|
||||||
page: {
|
page: {
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -313,9 +402,22 @@ export default {
|
|||||||
},
|
},
|
||||||
initDeptTree() {
|
initDeptTree() {
|
||||||
getDeptTree(this.userInfo.tenantId).then(res => {
|
getDeptTree(this.userInfo.tenantId).then(res => {
|
||||||
this.deptOptions = this.flattenDept(res.data.data || []);
|
const deptTree = res.data.data || [];
|
||||||
|
this.deptOptions = this.flattenDept(deptTree);
|
||||||
|
const deptColumn = this.findColumn(this.option.column, 'searchDeptId');
|
||||||
|
if (deptColumn) {
|
||||||
|
deptColumn.dicData = this.buildDeptTree(deptTree);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
buildDeptTree(tree) {
|
||||||
|
return tree.map(item => ({
|
||||||
|
label: item.title || item.deptName || item.name,
|
||||||
|
value: item.id,
|
||||||
|
children:
|
||||||
|
item.children && item.children.length ? this.buildDeptTree(item.children) : undefined,
|
||||||
|
}));
|
||||||
|
},
|
||||||
flattenDept(tree, level = 0) {
|
flattenDept(tree, level = 0) {
|
||||||
const result = [];
|
const result = [];
|
||||||
tree.forEach(item => {
|
tree.forEach(item => {
|
||||||
@@ -400,6 +502,246 @@ export default {
|
|||||||
this.form[`${prefix}Contact`] = address.contactName || this.form[`${prefix}Contact`] || '';
|
this.form[`${prefix}Contact`] = address.contactName || this.form[`${prefix}Contact`] || '';
|
||||||
this.form[`${prefix}Phone`] = address.contactPhone || this.form[`${prefix}Phone`] || '';
|
this.form[`${prefix}Phone`] = address.contactPhone || this.form[`${prefix}Phone`] || '';
|
||||||
},
|
},
|
||||||
|
openRouteMapDialog(target) {
|
||||||
|
if (this.dialogReadonly) return;
|
||||||
|
const prefix = target === 'departure' ? 'departure' : 'arrival';
|
||||||
|
this.routeMapTarget = prefix;
|
||||||
|
this.routeMapKeyword = this.form[`${prefix}Address`] || this.form[`${prefix}Name`] || '';
|
||||||
|
this.routeMapSelected = this.buildRouteMapSelection({
|
||||||
|
lng: this.form[`${prefix}Longitude`],
|
||||||
|
lat: this.form[`${prefix}Latitude`],
|
||||||
|
address: this.form[`${prefix}Address`],
|
||||||
|
regionName: this.form[`${prefix}Name`],
|
||||||
|
});
|
||||||
|
this.routeMapStatus = this.routeMapSelected.longitude
|
||||||
|
? '已加载当前选点,可重新选点'
|
||||||
|
: '可搜索地址或点击地图选点';
|
||||||
|
this.routeMapVisible = true;
|
||||||
|
},
|
||||||
|
loadAmap() {
|
||||||
|
if (window.AMap && window.AMap.Map) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
if (!amapLoader) {
|
||||||
|
amapLoader = new Promise((resolve, reject) => {
|
||||||
|
window._AMapSecurityConfig = {
|
||||||
|
securityJsCode: AMAP_SECURITY_CODE,
|
||||||
|
};
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = `https://webapi.amap.com/maps?v=2.0&key=${AMAP_KEY}`;
|
||||||
|
script.async = true;
|
||||||
|
script.onload = resolve;
|
||||||
|
script.onerror = () => reject(new Error('高德地图组件加载失败'));
|
||||||
|
document.body.appendChild(script);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return amapLoader;
|
||||||
|
},
|
||||||
|
initRouteAmap() {
|
||||||
|
this.loadAmap()
|
||||||
|
.then(() => {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (!this.routeAmap) {
|
||||||
|
const center = this.toLngLat(
|
||||||
|
this.routeMapSelected.longitude || 116.40769,
|
||||||
|
this.routeMapSelected.latitude || 39.89945
|
||||||
|
);
|
||||||
|
this.routeAmap = new window.AMap.Map(this.$refs.routeAmap, {
|
||||||
|
center,
|
||||||
|
zoom: this.routeMapSelected.longitude ? 14 : 11,
|
||||||
|
});
|
||||||
|
window.AMap.plugin(['AMap.ToolBar', 'AMap.Geocoder'], () => {
|
||||||
|
this.routeAmap.addControl(new window.AMap.ToolBar());
|
||||||
|
if (!this.routeAmapGeocoder) {
|
||||||
|
this.routeAmapGeocoder = new window.AMap.Geocoder();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.routeAmap.on('click', event => this.pickRouteMapPoint(event.lnglat));
|
||||||
|
} else if (typeof this.routeAmap.resize === 'function') {
|
||||||
|
this.routeAmap.resize();
|
||||||
|
}
|
||||||
|
if (this.routeMapSelected.longitude) {
|
||||||
|
this.renderRouteMapMarker(
|
||||||
|
this.toLngLat(this.routeMapSelected.longitude, this.routeMapSelected.latitude)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.$message.error('高德地图组件加载失败,请稍后重试或重新打开弹窗');
|
||||||
|
this.routeMapVisible = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
searchRouteMapKeyword() {
|
||||||
|
const keyword = String(this.routeMapKeyword || '').trim();
|
||||||
|
if (!keyword) {
|
||||||
|
this.$message.warning('请输入地址关键词');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.loadAmap()
|
||||||
|
.then(() => {
|
||||||
|
this.routeMapLoading = true;
|
||||||
|
return this.ensureRouteAmapGeocoder();
|
||||||
|
})
|
||||||
|
.then(() => this.runAmapGeocode('location', keyword))
|
||||||
|
.then(result => {
|
||||||
|
const point = this.resolveMapPoint(result);
|
||||||
|
if (!point) {
|
||||||
|
this.routeMapStatus = '未找到匹配地址';
|
||||||
|
this.$message.warning('地图搜索无匹配地址');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.pickRouteMapPoint(point, keyword);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.routeMapStatus = '地图搜索失败';
|
||||||
|
this.$message.error('地图搜索失败,请稍后重试');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.routeMapLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
pickRouteMapPoint(lnglat, keyword) {
|
||||||
|
const longitude = this.getPointLng(lnglat);
|
||||||
|
const latitude = this.getPointLat(lnglat);
|
||||||
|
if (longitude === undefined || latitude === undefined) {
|
||||||
|
this.$message.warning('选点坐标无效');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const point = this.toLngLat(longitude, latitude);
|
||||||
|
this.renderRouteMapMarker(point);
|
||||||
|
this.routeMapSelected = this.buildRouteMapSelection({
|
||||||
|
lng: longitude,
|
||||||
|
lat: latitude,
|
||||||
|
address: keyword,
|
||||||
|
});
|
||||||
|
this.routeMapStatus = '正在反查地址...';
|
||||||
|
this.ensureRouteAmapGeocoder()
|
||||||
|
.then(() => this.runAmapGeocode('address', point))
|
||||||
|
.then(result => {
|
||||||
|
const address = this.resolveMapAddress(result);
|
||||||
|
this.routeMapSelected = {
|
||||||
|
...this.routeMapSelected,
|
||||||
|
detailAddress: address.detailAddress || this.routeMapSelected.detailAddress,
|
||||||
|
regionName: address.regionName || this.routeMapSelected.regionName,
|
||||||
|
};
|
||||||
|
this.routeMapKeyword = this.routeMapSelected.detailAddress || this.routeMapKeyword;
|
||||||
|
this.routeMapStatus = this.routeMapSelected.detailAddress || '已选点,可确认回填';
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.routeMapStatus = '反查地址失败';
|
||||||
|
this.$message.error('反查地址失败,请重新选点');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
renderRouteMapMarker(point) {
|
||||||
|
if (!this.routeAmap || !window.AMap) return;
|
||||||
|
if (this.routeAmapMarker) {
|
||||||
|
this.routeAmapMarker.setMap(null);
|
||||||
|
}
|
||||||
|
this.routeAmapMarker = new window.AMap.Marker({ position: point });
|
||||||
|
this.routeAmapMarker.setMap(this.routeAmap);
|
||||||
|
this.routeAmap.setCenter(point);
|
||||||
|
},
|
||||||
|
confirmRouteMapPick() {
|
||||||
|
if (!this.routeMapSelected.longitude) {
|
||||||
|
this.$message.warning('请先搜索或点击地图完成选点');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const prefix = this.routeMapTarget;
|
||||||
|
this.form[`${prefix}Address`] =
|
||||||
|
this.routeMapSelected.detailAddress || this.form[`${prefix}Address`];
|
||||||
|
this.form[`${prefix}Name`] = this.routeMapSelected.regionName || this.form[`${prefix}Name`];
|
||||||
|
this.form[`${prefix}Longitude`] = this.routeMapSelected.longitude;
|
||||||
|
this.form[`${prefix}Latitude`] = this.routeMapSelected.latitude;
|
||||||
|
this.routeMapVisible = false;
|
||||||
|
this.$refs.crud?.validateField?.(`${prefix}Address`);
|
||||||
|
},
|
||||||
|
buildRouteMapSelection({ lng, lat, address, regionName }) {
|
||||||
|
return {
|
||||||
|
longitude: this.formatCoordinate(lng),
|
||||||
|
latitude: this.formatCoordinate(lat),
|
||||||
|
detailAddress: address || '',
|
||||||
|
regionName: regionName || '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
formatCoordinate(value) {
|
||||||
|
if (value === undefined || value === null || value === '') return '';
|
||||||
|
const numberValue = Number(value);
|
||||||
|
return Number.isFinite(numberValue) ? numberValue.toFixed(6) : '';
|
||||||
|
},
|
||||||
|
toLngLat(lng, lat) {
|
||||||
|
return new window.AMap.LngLat(Number(lng), Number(lat));
|
||||||
|
},
|
||||||
|
getPointLng(point) {
|
||||||
|
if (!point) return undefined;
|
||||||
|
if (typeof point.getLng === 'function') return point.getLng();
|
||||||
|
return point.lng ?? point.lon;
|
||||||
|
},
|
||||||
|
getPointLat(point) {
|
||||||
|
if (!point) return undefined;
|
||||||
|
if (typeof point.getLat === 'function') return point.getLat();
|
||||||
|
return point.lat;
|
||||||
|
},
|
||||||
|
ensureRouteAmapGeocoder() {
|
||||||
|
if (this.routeAmapGeocoder) return Promise.resolve(this.routeAmapGeocoder);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!window.AMap || !window.AMap.plugin) {
|
||||||
|
reject(new Error('高德地图组件未就绪'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.AMap.plugin(['AMap.Geocoder'], () => {
|
||||||
|
try {
|
||||||
|
this.routeAmapGeocoder = new window.AMap.Geocoder();
|
||||||
|
resolve(this.routeAmapGeocoder);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
runAmapGeocode(action, input) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const timer = window.setTimeout(() => {
|
||||||
|
reject(new Error('高德地图请求超时'));
|
||||||
|
}, 10000);
|
||||||
|
const done = (status, result) => {
|
||||||
|
window.clearTimeout(timer);
|
||||||
|
if (status === 'complete' && result) {
|
||||||
|
resolve(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reject(new Error('高德地图请求失败'));
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
if (action === 'location') {
|
||||||
|
this.routeAmapGeocoder.getLocation(input, done);
|
||||||
|
} else {
|
||||||
|
this.routeAmapGeocoder.getAddress(input, done);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
window.clearTimeout(timer);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resolveMapPoint(result) {
|
||||||
|
if (!result) return null;
|
||||||
|
const geocode = Array.isArray(result.geocodes) ? result.geocodes[0] : null;
|
||||||
|
if (geocode && geocode.location) return geocode.location;
|
||||||
|
if (result.location) return result.location;
|
||||||
|
if (result.lnglat) return result.lnglat;
|
||||||
|
if (result.getLng || result.lng || result.lon) return result;
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
resolveMapAddress(result = {}) {
|
||||||
|
const regeocode = result.regeocode || {};
|
||||||
|
const component = regeocode.addressComponent || {};
|
||||||
|
const city = Array.isArray(component.city) ? '' : component.city;
|
||||||
|
return {
|
||||||
|
detailAddress: regeocode.formattedAddress || '',
|
||||||
|
regionName: [component.province, city, component.district].filter(Boolean).join(''),
|
||||||
|
};
|
||||||
|
},
|
||||||
normalizeRow(row) {
|
normalizeRow(row) {
|
||||||
const submitRow = { ...row };
|
const submitRow = { ...row };
|
||||||
Object.keys(submitRow).forEach(key => {
|
Object.keys(submitRow).forEach(key => {
|
||||||
@@ -609,6 +951,27 @@ export default {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleTemplate() {
|
||||||
|
NProgress.start();
|
||||||
|
exportBlob(
|
||||||
|
config.templateUrl,
|
||||||
|
{
|
||||||
|
[this.website.tokenHeader]: getToken(),
|
||||||
|
},
|
||||||
|
{ feedback: true }
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
downloadXls(res.data, `${config.title}模板.xlsx`);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
NProgress.done();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleImport() {
|
||||||
|
const column = this.excelOptionConfig.column.find(item => item.prop === 'excelFile');
|
||||||
|
column.action = config.importUrl;
|
||||||
|
openImportDialog(this, config.title, () => this.onLoad(this.page, this.query));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -650,5 +1013,31 @@ export default {
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
margin-top: 14px;
|
margin-top: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__map-toolbar {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__map {
|
||||||
|
width: 100%;
|
||||||
|
height: 420px;
|
||||||
|
border: 1px solid #eff1f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__map-info {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #606266;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -18,13 +18,13 @@
|
|||||||
@current-change="currentChange"
|
@current-change="currentChange"
|
||||||
@size-change="sizeChange"
|
@size-change="sizeChange"
|
||||||
@refresh-change="refreshChange"
|
@refresh-change="refreshChange"
|
||||||
|
@search-icon-change="handleSearchIconChange"
|
||||||
@on-load="onLoad"
|
@on-load="onLoad"
|
||||||
>
|
>
|
||||||
<template #menu-left>
|
<template #menu-left>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
:icon="actionButtonLikeSearch ? undefined : 'el-icon-plus'"
|
:icon="actionButtonLikeSearch ? undefined : 'el-icon-plus'"
|
||||||
:plain="!actionButtonLikeSearch"
|
|
||||||
v-if="canCreate"
|
v-if="canCreate"
|
||||||
@click="$refs.crud.rowAdd()"
|
@click="$refs.crud.rowAdd()"
|
||||||
>{{ config.createText || '新增' }}
|
>{{ config.createText || '新增' }}
|
||||||
@@ -114,11 +114,35 @@
|
|||||||
|
|
||||||
<template #contractCategory-label>合同类型</template>
|
<template #contractCategory-label>合同类型</template>
|
||||||
|
|
||||||
|
<template v-if="config.enableContractExpiryTags" #search-menu>
|
||||||
|
<div v-show="searchExpanded" class="business-crud-page__contract-expiry-search">
|
||||||
|
<span class="business-crud-page__contract-expiry-label">签约类型:</span>
|
||||||
|
<el-select v-model="contractSignType" clearable placeholder="请选择">
|
||||||
|
<el-option
|
||||||
|
v-for="item in contractSignTypeOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<div class="business-crud-page__contract-expiry-tags">
|
||||||
|
<el-check-tag
|
||||||
|
v-for="item in contractExpiryTagOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:checked="contractExpiryScope === item.value"
|
||||||
|
@change="handleContractExpiryScopeChange(item.value)"
|
||||||
|
>
|
||||||
|
{{ item.label }}({{ contractExpiryStats[item.statKey] || 0 }})
|
||||||
|
</el-check-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #projectName-form>
|
<template #projectName-form>
|
||||||
<el-select
|
<el-select
|
||||||
v-model="selectedProjectId"
|
v-model="selectedProjectId"
|
||||||
class="business-crud-page__field"
|
class="business-crud-page__field"
|
||||||
placeholder="请选择项目名称"
|
:placeholder="config.projectPlaceholder || '请选择项目名称'"
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
:loading="projectLoading"
|
:loading="projectLoading"
|
||||||
@@ -1221,7 +1245,7 @@
|
|||||||
<el-cascader
|
<el-cascader
|
||||||
v-model="selectedOrganizationId"
|
v-model="selectedOrganizationId"
|
||||||
class="business-crud-page__field"
|
class="business-crud-page__field"
|
||||||
placeholder="请选择所属组织"
|
:placeholder="config.organizationPlaceholder || '请选择所属组织'"
|
||||||
:options="organizationOptions"
|
:options="organizationOptions"
|
||||||
:props="organizationCascaderProps"
|
:props="organizationCascaderProps"
|
||||||
clearable
|
clearable
|
||||||
@@ -1402,12 +1426,17 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<el-form
|
<el-form
|
||||||
|
v-if="settlementRuleEnabled"
|
||||||
:model="settlementRuleForm"
|
:model="settlementRuleForm"
|
||||||
label-position="right"
|
label-position="right"
|
||||||
label-width="auto"
|
label-width="auto"
|
||||||
class="business-crud-page__module-form business-crud-page__module-form--three"
|
class="business-crud-page__module-form business-crud-page__module-form--three"
|
||||||
>
|
>
|
||||||
<el-form-item label="账单起始日期" required>
|
<el-form-item
|
||||||
|
label="账单起始日期"
|
||||||
|
required
|
||||||
|
:error="settlementRuleErrors.billStartDate"
|
||||||
|
>
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="settlementRuleForm.billStartDate"
|
v-model="settlementRuleForm.billStartDate"
|
||||||
type="date"
|
type="date"
|
||||||
@@ -1415,9 +1444,10 @@
|
|||||||
format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
||||||
value-format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
|
@change="clearSettlementRuleError('billStartDate')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="结算类型" required>
|
<el-form-item label="结算类型" required :error="settlementRuleErrors.settlementType">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="settlementRuleForm.settlementType"
|
v-model="settlementRuleForm.settlementType"
|
||||||
placeholder="请选择结算类型"
|
placeholder="请选择结算类型"
|
||||||
@@ -1432,7 +1462,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="showSettlementBillCycleType" label="账单周期类型" required>
|
<el-form-item
|
||||||
|
v-if="showSettlementBillCycleType"
|
||||||
|
label="账单周期类型"
|
||||||
|
required
|
||||||
|
:error="settlementRuleErrors.billCycleType"
|
||||||
|
>
|
||||||
<el-select
|
<el-select
|
||||||
v-model="settlementRuleForm.billCycleType"
|
v-model="settlementRuleForm.billCycleType"
|
||||||
placeholder="请选择账单周期类型"
|
placeholder="请选择账单周期类型"
|
||||||
@@ -1447,11 +1482,17 @@
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="showSettlementBillCutoffDay" label="账单截单日">
|
<el-form-item
|
||||||
|
v-if="showSettlementBillCutoffDay"
|
||||||
|
label="账单截单日"
|
||||||
|
required
|
||||||
|
:error="settlementRuleErrors.billCutoffDay"
|
||||||
|
>
|
||||||
<el-select
|
<el-select
|
||||||
v-model="settlementRuleForm.billCutoffDay"
|
v-model="settlementRuleForm.billCutoffDay"
|
||||||
placeholder="请选择账单截单日"
|
placeholder="请选择账单截单日"
|
||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
|
@change="clearSettlementRuleError('billCutoffDay')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in billCutoffDayOptions"
|
v-for="item in billCutoffDayOptions"
|
||||||
@@ -1461,11 +1502,17 @@
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="showSettlementCycleDays" label="周期天数" required>
|
<el-form-item
|
||||||
|
v-if="showSettlementCycleDays"
|
||||||
|
label="周期天数"
|
||||||
|
required
|
||||||
|
:error="settlementRuleErrors.cycleDays"
|
||||||
|
>
|
||||||
<el-select
|
<el-select
|
||||||
v-model="settlementRuleForm.cycleDays"
|
v-model="settlementRuleForm.cycleDays"
|
||||||
placeholder="请选择周期天数"
|
placeholder="请选择周期天数"
|
||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
|
@change="clearSettlementRuleError('cycleDays')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in cycleDayOptions"
|
v-for="item in cycleDayOptions"
|
||||||
@@ -2055,7 +2102,6 @@
|
|||||||
<span class="business-crud-page__dispatch-heading-name">
|
<span class="business-crud-page__dispatch-heading-name">
|
||||||
{{ dispatchDialogTitle }}
|
{{ dispatchDialogTitle }}
|
||||||
</span>
|
</span>
|
||||||
<span class="business-crud-page__dispatch-heading-split">|</span>
|
|
||||||
<span class="business-crud-page__dispatch-heading-no">
|
<span class="business-crud-page__dispatch-heading-no">
|
||||||
{{ dispatchDialogNo || '-' }}
|
{{ dispatchDialogNo || '-' }}
|
||||||
</span>
|
</span>
|
||||||
@@ -2067,8 +2113,9 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="business-crud-page__dispatch-summary">
|
<div class="business-crud-page__dispatch-summary">
|
||||||
<div class="business-crud-page__dispatch-summary-left">
|
<section-card title="基本信息" class="business-crud-page__dispatch-summary-card">
|
||||||
<div class="business-crud-page__dispatch-summary-grid">
|
<div class="business-crud-page__dispatch-summary-grid">
|
||||||
<div class="business-crud-page__dispatch-summary-item">
|
<div class="business-crud-page__dispatch-summary-item">
|
||||||
<div class="business-crud-page__dispatch-summary-label">客户</div>
|
<div class="business-crud-page__dispatch-summary-label">客户</div>
|
||||||
@@ -2088,22 +2135,22 @@
|
|||||||
{{ dispatchRow.contractName || dispatchRow.contractNo || '-' }}
|
{{ dispatchRow.contractName || dispatchRow.contractNo || '-' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="business-crud-page__dispatch-summary-item">
|
|
||||||
<div class="business-crud-page__dispatch-summary-label">货物信息</div>
|
|
||||||
<div class="business-crud-page__dispatch-summary-value">
|
|
||||||
{{ dispatchPlanCargoInfo || '-' }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="business-crud-page__dispatch-summary-item">
|
<div class="business-crud-page__dispatch-summary-item">
|
||||||
<div class="business-crud-page__dispatch-summary-label">计划执行时间</div>
|
<div class="business-crud-page__dispatch-summary-label">计划执行时间</div>
|
||||||
<div class="business-crud-page__dispatch-summary-value">
|
<div class="business-crud-page__dispatch-summary-value">
|
||||||
{{
|
{{
|
||||||
[dispatchRow.planStartDate, dispatchRow.planEndDate]
|
[dispatchRow.planStartDate, dispatchRow.planEndDate]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join('-') || '-'
|
.join(' ~ ') || '-'
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="business-crud-page__dispatch-summary-item is-wide">
|
||||||
|
<div class="business-crud-page__dispatch-summary-label">货物信息</div>
|
||||||
|
<div class="business-crud-page__dispatch-summary-value">
|
||||||
|
{{ dispatchPlanCargoInfo || '-' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="business-crud-page__dispatch-summary-item business-crud-page__dispatch-summary-item--attachments"
|
class="business-crud-page__dispatch-summary-item business-crud-page__dispatch-summary-item--attachments"
|
||||||
>
|
>
|
||||||
@@ -2124,7 +2171,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section-card>
|
||||||
|
|
||||||
|
<section-card title="收发货路线" class="business-crud-page__dispatch-route-card">
|
||||||
<div class="business-crud-page__dispatch-route">
|
<div class="business-crud-page__dispatch-route">
|
||||||
<div class="business-crud-page__dispatch-route-item">
|
<div class="business-crud-page__dispatch-route-item">
|
||||||
<span class="business-crud-page__dispatch-route-badge is-start">起</span>
|
<span class="business-crud-page__dispatch-route-badge is-start">起</span>
|
||||||
@@ -2140,7 +2189,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="business-crud-page__dispatch-route-line" />
|
<div class="business-crud-page__dispatch-route-vehicle">
|
||||||
|
<el-icon><Van /></el-icon>
|
||||||
|
</div>
|
||||||
<div class="business-crud-page__dispatch-route-item">
|
<div class="business-crud-page__dispatch-route-item">
|
||||||
<span class="business-crud-page__dispatch-route-badge is-end">终</span>
|
<span class="business-crud-page__dispatch-route-badge is-end">终</span>
|
||||||
<div class="business-crud-page__dispatch-route-body">
|
<div class="business-crud-page__dispatch-route-body">
|
||||||
@@ -2156,12 +2207,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="business-crud-page__dispatch-list">
|
<section-card title="待调度列表">
|
||||||
<div class="business-crud-page__dispatch-list-head">
|
<template #extra>
|
||||||
<div class="business-crud-page__dispatch-list-title">待调度列表</div>
|
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
:disabled="dispatchSummaryRemainingQuantity <= 0"
|
:disabled="dispatchSummaryRemainingQuantity <= 0"
|
||||||
@@ -2169,10 +2220,10 @@
|
|||||||
>
|
>
|
||||||
新增
|
新增
|
||||||
</el-button>
|
</el-button>
|
||||||
<div class="business-crud-page__dispatch-list-summary">
|
<span class="business-crud-page__dispatch-list-summary">
|
||||||
{{ dispatchSummaryText }}
|
{{ dispatchSummaryText }}
|
||||||
</div>
|
</span>
|
||||||
</div>
|
</template>
|
||||||
<el-table
|
<el-table
|
||||||
:data="dispatchRows"
|
:data="dispatchRows"
|
||||||
border
|
border
|
||||||
@@ -2265,7 +2316,7 @@
|
|||||||
align="center"
|
align="center"
|
||||||
show-overflow-tooltip
|
show-overflow-tooltip
|
||||||
/>
|
/>
|
||||||
<el-table-column label="操作" width="180" align="center" fixed="right">
|
<el-table-column label="操作" width="220" align="center" fixed="right">
|
||||||
<template #default="{ row, $index }">
|
<template #default="{ row, $index }">
|
||||||
<div class="business-crud-page__dispatch-actions">
|
<div class="business-crud-page__dispatch-actions">
|
||||||
<el-link type="primary" @click="handleDispatchEditRow(row, $index)">编辑</el-link>
|
<el-link type="primary" @click="handleDispatchEditRow(row, $index)">编辑</el-link>
|
||||||
@@ -2274,7 +2325,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</section-card>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="business-crud-page__dispatch-footer">
|
<div class="business-crud-page__dispatch-footer">
|
||||||
@@ -2799,7 +2850,7 @@
|
|||||||
:title="billingPlanMode === 'edit' ? '编辑计费方案' : '添加计费方案'"
|
:title="billingPlanMode === 'edit' ? '编辑计费方案' : '添加计费方案'"
|
||||||
append-to-body
|
append-to-body
|
||||||
v-model="billingPlanBox"
|
v-model="billingPlanBox"
|
||||||
width="96%"
|
width="90%"
|
||||||
class="business-crud-page__billing-dialog"
|
class="business-crud-page__billing-dialog"
|
||||||
>
|
>
|
||||||
<el-form
|
<el-form
|
||||||
@@ -2826,6 +2877,7 @@
|
|||||||
<el-form-item label="备注">
|
<el-form-item label="备注">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="billingPlanForm.remark"
|
v-model="billingPlanForm.remark"
|
||||||
|
class="business-crud-page__billing-plan-remark"
|
||||||
maxlength="100"
|
maxlength="100"
|
||||||
show-word-limit
|
show-word-limit
|
||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
@@ -3817,6 +3869,11 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({ column: [] }),
|
default: () => ({ column: [] }),
|
||||||
},
|
},
|
||||||
|
// 可选:固定操作列宽度;不传则按按钮数量自动估算(沿用既有逻辑)
|
||||||
|
menuWidth: {
|
||||||
|
type: Number,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -3864,7 +3921,11 @@ export default {
|
|||||||
defaultDialogButtons: null,
|
defaultDialogButtons: null,
|
||||||
contractCreateActionLoading: '',
|
contractCreateActionLoading: '',
|
||||||
transportPlanCreateActionLoading: '',
|
transportPlanCreateActionLoading: '',
|
||||||
option: this.cloneOption(this.crudOption, estimateMenuButtonCount(this.config)),
|
option: (() => {
|
||||||
|
const opt = this.cloneOption(this.crudOption, estimateMenuButtonCount(this.config));
|
||||||
|
if (this.menuWidth != null) opt.menuWidth = this.menuWidth;
|
||||||
|
return opt;
|
||||||
|
})(),
|
||||||
selectedProjectId: '',
|
selectedProjectId: '',
|
||||||
projectOptions: [],
|
projectOptions: [],
|
||||||
projectLoading: false,
|
projectLoading: false,
|
||||||
@@ -3957,6 +4018,7 @@ export default {
|
|||||||
cargoImportLoading: false,
|
cargoImportLoading: false,
|
||||||
billingPlanRows: [],
|
billingPlanRows: [],
|
||||||
settlementRuleForm: defaultSettlementRule(),
|
settlementRuleForm: defaultSettlementRule(),
|
||||||
|
settlementRuleErrors: {},
|
||||||
reconciliationForm: defaultReconciliation(),
|
reconciliationForm: defaultReconciliation(),
|
||||||
changeRecordRows: [],
|
changeRecordRows: [],
|
||||||
billingPlanBox: false,
|
billingPlanBox: false,
|
||||||
@@ -4034,9 +4096,23 @@ export default {
|
|||||||
total: 0,
|
total: 0,
|
||||||
},
|
},
|
||||||
selectionList: [],
|
selectionList: [],
|
||||||
|
contractExpiryScope: '',
|
||||||
|
contractSignType: '',
|
||||||
|
searchExpanded: false,
|
||||||
|
attachmentUploadMode: false,
|
||||||
|
contractExpiryStats: {
|
||||||
|
all: 0,
|
||||||
|
within30: 0,
|
||||||
|
within90: 0,
|
||||||
|
over90: 0,
|
||||||
|
expired: 0,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
if (this.config.enableAllDept && this.isAdmin) {
|
||||||
|
this.allDept = 1;
|
||||||
|
}
|
||||||
if (this.config.enableProjectSelect) {
|
if (this.config.enableProjectSelect) {
|
||||||
this.loadProjectOptions();
|
this.loadProjectOptions();
|
||||||
}
|
}
|
||||||
@@ -4075,6 +4151,18 @@ export default {
|
|||||||
actionButtonLikeSearch() {
|
actionButtonLikeSearch() {
|
||||||
return this.config.actionButtonLikeSearch === true;
|
return this.config.actionButtonLikeSearch === true;
|
||||||
},
|
},
|
||||||
|
contractSignTypeOptions() {
|
||||||
|
return this.option.column?.find(column => column.prop === 'signType')?.dicData || [];
|
||||||
|
},
|
||||||
|
contractExpiryTagOptions() {
|
||||||
|
return [
|
||||||
|
{ label: '全部', value: '', statKey: 'all' },
|
||||||
|
{ label: '30天内到期', value: 'within30', statKey: 'within30' },
|
||||||
|
{ label: '90天内到期', value: 'within90', statKey: 'within90' },
|
||||||
|
{ label: '90天以上', value: 'over90', statKey: 'over90' },
|
||||||
|
{ label: '已到期', value: 'expired', statKey: 'expired' },
|
||||||
|
];
|
||||||
|
},
|
||||||
contractSelectEnabled() {
|
contractSelectEnabled() {
|
||||||
return this.config.enableContractSelect || this.config.enableTransportPlanForm;
|
return this.config.enableContractSelect || this.config.enableTransportPlanForm;
|
||||||
},
|
},
|
||||||
@@ -4241,7 +4329,9 @@ export default {
|
|||||||
return this.isAdmin;
|
return this.isAdmin;
|
||||||
},
|
},
|
||||||
readonlyScope() {
|
readonlyScope() {
|
||||||
return this.config.enableAllDept && this.allDept === 1;
|
return (
|
||||||
|
this.config.enableAllDept && this.config.allDeptReadonly !== false && this.allDept === 1
|
||||||
|
);
|
||||||
},
|
},
|
||||||
canCreate() {
|
canCreate() {
|
||||||
return this.hasPermission(`${this.config.permission}_add`) && !this.readonlyScope;
|
return this.hasPermission(`${this.config.permission}_add`) && !this.readonlyScope;
|
||||||
@@ -4300,6 +4390,9 @@ export default {
|
|||||||
emitPath: true,
|
emitPath: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
settlementRuleEnabled() {
|
||||||
|
return Number(this.settlementRuleForm.autoGenerate) === 1;
|
||||||
|
},
|
||||||
showSettlementBillCycleType() {
|
showSettlementBillCycleType() {
|
||||||
return this.settlementRuleForm.settlementType === '月结';
|
return this.settlementRuleForm.settlementType === '月结';
|
||||||
},
|
},
|
||||||
@@ -4536,6 +4629,7 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (action.action === 'edit' || action.action === 'attachmentUpload') {
|
if (action.action === 'edit' || action.action === 'attachmentUpload') {
|
||||||
|
this.attachmentUploadMode = action.action === 'attachmentUpload';
|
||||||
this.$refs.crud.rowEdit(row, index);
|
this.$refs.crud.rowEdit(row, index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -4713,6 +4807,7 @@ export default {
|
|||||||
return rule.settlementType === '固定天数周期结算';
|
return rule.settlementType === '固定天数周期结算';
|
||||||
},
|
},
|
||||||
handleSettlementTypeChange(value) {
|
handleSettlementTypeChange(value) {
|
||||||
|
this.clearSettlementRuleError('settlementType');
|
||||||
if (value === '月结') {
|
if (value === '月结') {
|
||||||
if (!this.settlementRuleForm.billCycleType) {
|
if (!this.settlementRuleForm.billCycleType) {
|
||||||
this.settlementRuleForm.billCycleType = '固定截单日';
|
this.settlementRuleForm.billCycleType = '固定截单日';
|
||||||
@@ -4730,6 +4825,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleSettlementBillCycleTypeChange(value) {
|
handleSettlementBillCycleTypeChange(value) {
|
||||||
|
this.clearSettlementRuleError('billCycleType');
|
||||||
if (value === '固定截单日') {
|
if (value === '固定截单日') {
|
||||||
this.settlementRuleForm.billCutoffDay = this.settlementRuleForm.billCutoffDay || 25;
|
this.settlementRuleForm.billCutoffDay = this.settlementRuleForm.billCutoffDay || 25;
|
||||||
return;
|
return;
|
||||||
@@ -4752,23 +4848,40 @@ export default {
|
|||||||
}
|
}
|
||||||
return nextRule;
|
return nextRule;
|
||||||
},
|
},
|
||||||
|
clearSettlementRuleError(field) {
|
||||||
|
if (!this.settlementRuleErrors[field]) return;
|
||||||
|
this.settlementRuleErrors = {
|
||||||
|
...this.settlementRuleErrors,
|
||||||
|
[field]: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
validateSettlementRule() {
|
validateSettlementRule() {
|
||||||
const rule = this.normalizeSettlementRule(this.settlementRuleForm);
|
const rule = this.normalizeSettlementRule(this.settlementRuleForm);
|
||||||
|
this.settlementRuleErrors = {};
|
||||||
if (this.isBillingFieldEmpty(rule.billStartDate)) {
|
if (this.isBillingFieldEmpty(rule.billStartDate)) {
|
||||||
|
this.settlementRuleErrors = { billStartDate: '请选择账单起始日期' };
|
||||||
this.$message.warning('请选择账单起始日期');
|
this.$message.warning('请选择账单起始日期');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.isBillingFieldEmpty(rule.settlementType)) {
|
if (this.isBillingFieldEmpty(rule.settlementType)) {
|
||||||
|
this.settlementRuleErrors = { settlementType: '请选择结算类型' };
|
||||||
this.$message.warning('请选择结算类型');
|
this.$message.warning('请选择结算类型');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.isMonthlySettlement(rule) && this.isBillingFieldEmpty(rule.billCycleType)) {
|
if (this.isMonthlySettlement(rule) && this.isBillingFieldEmpty(rule.billCycleType)) {
|
||||||
|
this.settlementRuleErrors = { billCycleType: '请选择账单周期类型' };
|
||||||
this.$message.warning('请选择账单周期类型');
|
this.$message.warning('请选择账单周期类型');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.isFixedBillCutoffSettlement(rule)) {
|
if (this.isFixedBillCutoffSettlement(rule)) {
|
||||||
|
if (this.isBillingFieldEmpty(rule.billCutoffDay)) {
|
||||||
|
this.settlementRuleErrors = { billCutoffDay: '请选择账单截单日' };
|
||||||
|
this.$message.warning('请选择账单截单日');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const billCutoffDay = Number(rule.billCutoffDay);
|
const billCutoffDay = Number(rule.billCutoffDay);
|
||||||
if (!Number.isInteger(billCutoffDay) || billCutoffDay < 1 || billCutoffDay > 31) {
|
if (!Number.isInteger(billCutoffDay) || billCutoffDay < 1 || billCutoffDay > 31) {
|
||||||
|
this.settlementRuleErrors = { billCutoffDay: '账单截单日必须为1~31的整数' };
|
||||||
this.$message.warning('账单截单日必须为1~31的整数');
|
this.$message.warning('账单截单日必须为1~31的整数');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -4776,13 +4889,14 @@ export default {
|
|||||||
if (this.isFixedCycleSettlement(rule)) {
|
if (this.isFixedCycleSettlement(rule)) {
|
||||||
const cycleDays = Number(rule.cycleDays);
|
const cycleDays = Number(rule.cycleDays);
|
||||||
if (!Number.isInteger(cycleDays) || cycleDays < 1 || cycleDays > 365) {
|
if (!Number.isInteger(cycleDays) || cycleDays < 1 || cycleDays > 365) {
|
||||||
|
this.settlementRuleErrors = { cycleDays: '周期天数必须为1~365的整数' };
|
||||||
this.$message.warning('周期天数必须为1~365的整数');
|
this.$message.warning('周期天数必须为1~365的整数');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
normalizeRow(row) {
|
normalizeRow(row, saveAsDraft = false) {
|
||||||
const submitRow = { ...row };
|
const submitRow = { ...row };
|
||||||
if (this.config.enableTransportPlanForm) {
|
if (this.config.enableTransportPlanForm) {
|
||||||
if (!this.validateTransportPlanForm(submitRow)) return false;
|
if (!this.validateTransportPlanForm(submitRow)) return false;
|
||||||
@@ -4802,7 +4916,7 @@ export default {
|
|||||||
submitRow.billingPlanJson = JSON.stringify(this.billingPlanRows);
|
submitRow.billingPlanJson = JSON.stringify(this.billingPlanRows);
|
||||||
}
|
}
|
||||||
if (this.config.enableSettlementRule) {
|
if (this.config.enableSettlementRule) {
|
||||||
if (!this.validateSettlementRule()) return false;
|
if (this.settlementRuleEnabled && !this.validateSettlementRule()) return false;
|
||||||
submitRow.settlementRuleJson = JSON.stringify(this.normalizeSettlementRule());
|
submitRow.settlementRuleJson = JSON.stringify(this.normalizeSettlementRule());
|
||||||
}
|
}
|
||||||
if (this.config.enableReconciliation) {
|
if (this.config.enableReconciliation) {
|
||||||
@@ -4811,7 +4925,7 @@ export default {
|
|||||||
if (this.config.enableChangeRecord) {
|
if (this.config.enableChangeRecord) {
|
||||||
submitRow.changeRecordJson = JSON.stringify(this.changeRecordRows);
|
submitRow.changeRecordJson = JSON.stringify(this.changeRecordRows);
|
||||||
}
|
}
|
||||||
if (this.config.saveAsDraft) {
|
if (this.config.saveAsDraft && saveAsDraft) {
|
||||||
submitRow.approvalStatus = 'draft';
|
submitRow.approvalStatus = 'draft';
|
||||||
}
|
}
|
||||||
delete submitRow.basicInfoTitle;
|
delete submitRow.basicInfoTitle;
|
||||||
@@ -4895,22 +5009,25 @@ export default {
|
|||||||
this.stopSubmitLoading(loading);
|
this.stopSubmitLoading(loading);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.getSaveRequest()(submitRow).then(
|
const request =
|
||||||
|
this.attachmentUploadMode && typeof this.api.updateAttachments === 'function'
|
||||||
|
? this.api.updateAttachments
|
||||||
|
: this.getSaveRequest();
|
||||||
|
request(submitRow).then(
|
||||||
() => {
|
() => {
|
||||||
|
this.attachmentUploadMode = false;
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
this.$message({ type: 'success', message: '操作成功!' });
|
this.$message({ type: 'success', message: '操作成功!' });
|
||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
|
this.attachmentUploadMode = false;
|
||||||
window.console.log(error);
|
window.console.log(error);
|
||||||
this.stopSubmitLoading(loading);
|
this.stopSubmitLoading(loading);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
getSaveRequest() {
|
getSaveRequest() {
|
||||||
if (this.config.saveAsDraft && typeof this.api.saveDraft === 'function') {
|
|
||||||
return this.api.saveDraft;
|
|
||||||
}
|
|
||||||
return this.api.submit;
|
return this.api.submit;
|
||||||
},
|
},
|
||||||
buildContractCreateSubmitRow(action) {
|
buildContractCreateSubmitRow(action) {
|
||||||
@@ -5032,7 +5149,7 @@ export default {
|
|||||||
handleDraftSave() {
|
handleDraftSave() {
|
||||||
const request =
|
const request =
|
||||||
typeof this.api.saveDraft === 'function' ? this.api.saveDraft : this.api.submit;
|
typeof this.api.saveDraft === 'function' ? this.api.saveDraft : this.api.submit;
|
||||||
const submitRow = this.normalizeRow(this.form);
|
const submitRow = this.normalizeRow(this.form, true);
|
||||||
if (!submitRow) return;
|
if (!submitRow) return;
|
||||||
this.draftSaveLoading = true;
|
this.draftSaveLoading = true;
|
||||||
request(submitRow)
|
request(submitRow)
|
||||||
@@ -5095,6 +5212,7 @@ export default {
|
|||||||
},
|
},
|
||||||
beforeOpen(done, type) {
|
beforeOpen(done, type) {
|
||||||
this.crudDialogType = type;
|
this.crudDialogType = type;
|
||||||
|
this.settlementRuleErrors = {};
|
||||||
this.syncCustomCreateDialogButtons(type);
|
this.syncCustomCreateDialogButtons(type);
|
||||||
this.dialogReadonly = type === 'view';
|
this.dialogReadonly = type === 'view';
|
||||||
this.syncContractNoDisabled(type);
|
this.syncContractNoDisabled(type);
|
||||||
@@ -5176,8 +5294,7 @@ export default {
|
|||||||
this.syncCurrentOrganizationOption();
|
this.syncCurrentOrganizationOption();
|
||||||
}
|
}
|
||||||
if (this.config.enableProjectSelect) {
|
if (this.config.enableProjectSelect) {
|
||||||
this.form.usedFundLimit = 0;
|
this.form.remainingFundLimit = this.calculateRemainingFundLimit();
|
||||||
this.form.remainingFundLimit = 0;
|
|
||||||
this.syncCurrentProjectOption();
|
this.syncCurrentProjectOption();
|
||||||
}
|
}
|
||||||
if (this.contractSelectEnabled) {
|
if (this.contractSelectEnabled) {
|
||||||
@@ -5224,7 +5341,7 @@ export default {
|
|||||||
loadProjectOptions() {
|
loadProjectOptions() {
|
||||||
if (!this.config.enableProjectSelect || this.projectLoading) return;
|
if (!this.config.enableProjectSelect || this.projectLoading) return;
|
||||||
this.projectLoading = true;
|
this.projectLoading = true;
|
||||||
getProjectList(1, 9999, {})
|
getProjectList(1, 9999, this.config.projectQueryParams || {})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.projectOptions = extractRecords(res);
|
this.projectOptions = extractRecords(res);
|
||||||
this.syncCurrentProjectOption();
|
this.syncCurrentProjectOption();
|
||||||
@@ -5248,6 +5365,12 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
calculateRemainingFundLimit() {
|
||||||
|
const projectFundLimit = Number(this.form.projectFundLimit);
|
||||||
|
const usedFundLimit = Number(this.form.usedFundLimit);
|
||||||
|
if (!Number.isFinite(projectFundLimit) || !Number.isFinite(usedFundLimit)) return '';
|
||||||
|
return Math.round((projectFundLimit - usedFundLimit + Number.EPSILON) * 100) / 100;
|
||||||
|
},
|
||||||
handleProjectChange(projectId) {
|
handleProjectChange(projectId) {
|
||||||
const project = this.projectOptions.find(item => String(item.id) === String(projectId));
|
const project = this.projectOptions.find(item => String(item.id) === String(projectId));
|
||||||
if (!project) {
|
if (!project) {
|
||||||
@@ -5275,7 +5398,7 @@ export default {
|
|||||||
this.form.undertakeDeptName = project.undertakeDeptName || '';
|
this.form.undertakeDeptName = project.undertakeDeptName || '';
|
||||||
this.form.projectFundLimit = project.fundLimit || project.projectFundLimit || 0;
|
this.form.projectFundLimit = project.fundLimit || project.projectFundLimit || 0;
|
||||||
this.form.usedFundLimit = 0;
|
this.form.usedFundLimit = 0;
|
||||||
this.form.remainingFundLimit = 0;
|
this.form.remainingFundLimit = this.calculateRemainingFundLimit();
|
||||||
if (this.contractSelectEnabled || this.config.enableTransportPlanForm) {
|
if (this.contractSelectEnabled || this.config.enableTransportPlanForm) {
|
||||||
this.form.customerName =
|
this.form.customerName =
|
||||||
project.customerName ||
|
project.customerName ||
|
||||||
@@ -7617,11 +7740,16 @@ export default {
|
|||||||
},
|
},
|
||||||
searchReset() {
|
searchReset() {
|
||||||
this.query = {};
|
this.query = {};
|
||||||
|
this.contractExpiryScope = '';
|
||||||
|
this.contractSignType = '';
|
||||||
this.page.currentPage = 1;
|
this.page.currentPage = 1;
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
},
|
},
|
||||||
searchChange(params, done) {
|
searchChange(params, done) {
|
||||||
this.query = params;
|
this.query = {
|
||||||
|
...params,
|
||||||
|
...(this.contractSignType ? { signType: this.contractSignType } : {}),
|
||||||
|
};
|
||||||
this.page.currentPage = 1;
|
this.page.currentPage = 1;
|
||||||
this.onLoad(this.page, params);
|
this.onLoad(this.page, params);
|
||||||
done();
|
done();
|
||||||
@@ -7644,6 +7772,25 @@ export default {
|
|||||||
refreshChange() {
|
refreshChange() {
|
||||||
this.onLoad(this.page, this.query);
|
this.onLoad(this.page, this.query);
|
||||||
},
|
},
|
||||||
|
handleSearchIconChange(expanded) {
|
||||||
|
this.searchExpanded = expanded;
|
||||||
|
},
|
||||||
|
handleContractExpiryScopeChange(expireScope) {
|
||||||
|
this.contractExpiryScope = expireScope;
|
||||||
|
this.page.currentPage = 1;
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
},
|
||||||
|
refreshContractExpiryStats(query) {
|
||||||
|
if (!this.config.enableContractExpiryTags || typeof this.api.expireStats !== 'function') return;
|
||||||
|
const statsQuery = { ...query };
|
||||||
|
delete statsQuery.expireScope;
|
||||||
|
this.api.expireStats(statsQuery).then(res => {
|
||||||
|
this.contractExpiryStats = {
|
||||||
|
...this.contractExpiryStats,
|
||||||
|
...(res.data.data || {}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
handleScopeChange() {
|
handleScopeChange() {
|
||||||
if (!this.canViewAllDept) {
|
if (!this.canViewAllDept) {
|
||||||
this.allDept = 0;
|
this.allDept = 0;
|
||||||
@@ -7700,7 +7847,13 @@ export default {
|
|||||||
},
|
},
|
||||||
onLoad(page, params = {}) {
|
onLoad(page, params = {}) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const query = this.normalizeQueryParams({ ...params, ...this.query, allDept: this.allDept });
|
const query = this.normalizeQueryParams({
|
||||||
|
...params,
|
||||||
|
...this.query,
|
||||||
|
allDept: this.allDept,
|
||||||
|
...(this.contractSignType ? { signType: this.contractSignType } : {}),
|
||||||
|
...(this.contractExpiryScope ? { expireScope: this.contractExpiryScope } : {}),
|
||||||
|
});
|
||||||
this.api
|
this.api
|
||||||
.getList(page.currentPage, page.pageSize, query)
|
.getList(page.currentPage, page.pageSize, query)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@@ -7708,6 +7861,7 @@ export default {
|
|||||||
this.page.total = result.total;
|
this.page.total = result.total;
|
||||||
this.data = result.records;
|
this.data = result.records;
|
||||||
this.selectionClear();
|
this.selectionClear();
|
||||||
|
this.refreshContractExpiryStats(query);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
@@ -8611,6 +8765,38 @@ export default {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__contract-expiry-search {
|
||||||
|
display: flex;
|
||||||
|
order: -1;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-right: auto;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
:deep(.el-select) {
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contract-expiry-label {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
min-width: 140px;
|
||||||
|
color: #606266;
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contract-expiry-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
:deep(.el-check-tag) {
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.dialog-section-title {
|
.dialog-section-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -9131,7 +9317,10 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-dialog__body) {
|
:deep(.el-dialog__body) {
|
||||||
padding: 0;
|
padding: 16px;
|
||||||
|
background: #f5f6fa;
|
||||||
|
max-height: calc(100vh - 140px);
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9142,12 +9331,11 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-top {
|
&__dispatch-top {
|
||||||
padding: 22px 32px 14px;
|
padding: 0;
|
||||||
border-bottom: 1px solid #e9edf5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-heading {
|
&__dispatch-heading {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-heading-title {
|
&__dispatch-heading-title {
|
||||||
@@ -9158,51 +9346,60 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-heading-name {
|
&__dispatch-heading-name {
|
||||||
font-size: 22px;
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-heading-split {
|
|
||||||
font-size: 20px;
|
|
||||||
color: #606266;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__dispatch-heading-no {
|
&__dispatch-heading-no {
|
||||||
font-size: 15px;
|
font-size: 14px;
|
||||||
color: #303133;
|
color: #606266;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-summary {
|
&__dispatch-summary {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1.15fr) minmax(520px, 1fr);
|
grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
|
||||||
gap: 32px;
|
gap: 16px;
|
||||||
align-items: start;
|
align-items: stretch;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__dispatch-summary-card,
|
||||||
|
&__dispatch-route-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
:deep(.section-card__body) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-summary-grid {
|
&__dispatch-summary-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
column-gap: 48px;
|
gap: 12px 16px;
|
||||||
row-gap: 18px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-summary-item {
|
&__dispatch-summary-item {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
|
&.is-wide {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-summary-label {
|
&__dispatch-summary-label {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 4px;
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
color: #666;
|
color: #909399;
|
||||||
font-weight: 500;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-summary-value {
|
&__dispatch-summary-value {
|
||||||
min-height: 24px;
|
min-height: 20px;
|
||||||
font-size: 15px;
|
font-size: 14px;
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
color: #333;
|
color: #303133;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9212,24 +9409,30 @@ export default {
|
|||||||
|
|
||||||
&__dispatch-attachment-link {
|
&__dispatch-attachment-link {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 22px;
|
margin-right: 16px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 4px;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-route {
|
&__dispatch-route {
|
||||||
|
position: relative;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) 72px minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr) 56px minmax(0, 1fr);
|
||||||
gap: 24px;
|
gap: 40px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-items: center;
|
//height: 100%;
|
||||||
min-height: 200px;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-route-item {
|
&__dispatch-route-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
gap: 16px;
|
gap: 12px;
|
||||||
max-width: 100%;
|
max-width: 90%;
|
||||||
|
padding: 16px;
|
||||||
|
min-height: 80px;
|
||||||
|
border: 1px dashed #e3e4ec;
|
||||||
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-route-badge {
|
&__dispatch-route-badge {
|
||||||
@@ -9237,12 +9440,13 @@ export default {
|
|||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 46px;
|
width: 40px;
|
||||||
height: 46px;
|
height: 40px;
|
||||||
border-radius: 6px;
|
border-radius: 50%;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
&.is-start {
|
&.is-start {
|
||||||
background: #2a92ff;
|
background: #2a92ff;
|
||||||
@@ -9254,39 +9458,68 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-route-body {
|
&__dispatch-route-body {
|
||||||
max-width: 340px;
|
min-width: 0;
|
||||||
text-align: center;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-route-title {
|
&__dispatch-route-title {
|
||||||
font-size: 22px;
|
font-size: 18px;
|
||||||
line-height: 1.25;
|
line-height: 1.35;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-route-address {
|
&__dispatch-route-address {
|
||||||
margin-top: 12px;
|
margin-top: 4px;
|
||||||
font-size: 15px;
|
font-size: 13px;
|
||||||
line-height: 1.45;
|
line-height: 1.5;
|
||||||
color: #333;
|
color: #606266;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-route-contact {
|
&__dispatch-route-contact {
|
||||||
margin-top: 10px;
|
margin-top: 2px;
|
||||||
font-size: 15px;
|
font-size: 13px;
|
||||||
color: #333;
|
color: #909399;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-route-line {
|
&__dispatch-route-vehicle {
|
||||||
width: 72px;
|
position: relative;
|
||||||
height: 4px;
|
display: flex;
|
||||||
background: #3b3b3b;
|
align-items: center;
|
||||||
border-radius: 999px;
|
justify-content: center;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
margin: 0 auto;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #fff;
|
||||||
|
border: 2px solid var(--el-color-primary);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
font-size: 22px;
|
||||||
|
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.18);
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
width: 20px;
|
||||||
|
height: 0;
|
||||||
|
border-top: 2px dashed var(--el-color-primary-light-5);
|
||||||
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-list {
|
&::before {
|
||||||
padding: 12px 18px 18px;
|
right: 100%;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
left: 100%;
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-list-head {
|
&__dispatch-list-head {
|
||||||
@@ -9338,8 +9571,11 @@ export default {
|
|||||||
&__dispatch-footer {
|
&__dispatch-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 12px;
|
gap: 10px;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
|
padding-top: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
border-top: 1px solid #e9edf5;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dispatch-item-dialog {
|
&__dispatch-item-dialog {
|
||||||
@@ -9405,6 +9641,10 @@ export default {
|
|||||||
margin-bottom: 18px;
|
margin-bottom: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__billing-plan-remark {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
&__billing-rule-head {
|
&__billing-rule-head {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -9656,4 +9896,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.section-card{
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<business-crud-page :api="api" :config="config" :crud-option="option" />
|
<business-crud-page :api="api" :config="config" :crud-option="option" :menu-width="245" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -358,7 +358,7 @@
|
|||||||
label-width="auto"
|
label-width="auto"
|
||||||
class="loading-manage-dialog__form"
|
class="loading-manage-dialog__form"
|
||||||
>
|
>
|
||||||
<div class="dialog-section-title">配载基本信息</div>
|
<section-card title="配载基本信息">
|
||||||
<div class="loading-manage-dialog__grid">
|
<div class="loading-manage-dialog__grid">
|
||||||
<el-form-item label="配载单号">
|
<el-form-item label="配载单号">
|
||||||
<el-input v-model="dialogForm.loadingNo" disabled placeholder="系统自动生成" />
|
<el-input v-model="dialogForm.loadingNo" disabled placeholder="系统自动生成" />
|
||||||
@@ -449,11 +449,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<div class="dialog-section-title loading-manage-dialog__title-action">
|
<section-card title="筛选待配载运单">
|
||||||
<span>筛选待配载运单</span>
|
<template #extra>
|
||||||
<el-link v-if="!dialogReadonly" type="primary" @click="loadCandidateWaybills">筛选</el-link>
|
<el-link v-if="!dialogReadonly" type="primary" @click="loadCandidateWaybills">筛选</el-link>
|
||||||
</div>
|
</template>
|
||||||
<div class="loading-manage-dialog__candidate-search" v-if="candidateSearchVisible">
|
<div class="loading-manage-dialog__candidate-search" v-if="candidateSearchVisible">
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
@@ -733,8 +734,9 @@
|
|||||||
@current-change="handleCandidateCurrentChange"
|
@current-change="handleCandidateCurrentChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<div class="dialog-section-title">待配载列表</div>
|
<section-card title="待配载列表">
|
||||||
<el-table
|
<el-table
|
||||||
:data="selectedWaybillRows"
|
:data="selectedWaybillRows"
|
||||||
border
|
border
|
||||||
@@ -769,8 +771,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<div class="dialog-section-title">路线信息</div>
|
<section-card title="路线信息">
|
||||||
<div class="loading-manage-dialog__route-list" v-if="routeNodes.length">
|
<div class="loading-manage-dialog__route-list" v-if="routeNodes.length">
|
||||||
<div
|
<div
|
||||||
v-for="(node, index) in routeNodes"
|
v-for="(node, index) in routeNodes"
|
||||||
@@ -790,8 +793,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-empty v-else description="添加待配载运单后自动生成路线" :image-size="72" />
|
<el-empty v-else description="添加待配载运单后自动生成路线" :image-size="72" />
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<div class="dialog-section-title">货物信息</div>
|
<section-card title="货物信息">
|
||||||
<el-table :data="cargoRows" border class="loading-manage-dialog__cargo-table">
|
<el-table :data="cargoRows" border class="loading-manage-dialog__cargo-table">
|
||||||
<el-table-column type="index" label="序号" width="70" align="center" fixed="left" />
|
<el-table-column type="index" label="序号" width="70" align="center" fixed="left" />
|
||||||
<el-table-column prop="projectName" label="项目名称" min-width="150" />
|
<el-table-column prop="projectName" label="项目名称" min-width="150" />
|
||||||
@@ -807,8 +811,9 @@
|
|||||||
<el-table-column prop="equipmentCode" label="设备编码" min-width="130" />
|
<el-table-column prop="equipmentCode" label="设备编码" min-width="130" />
|
||||||
<el-table-column prop="remark" label="备注" min-width="180" show-overflow-tooltip />
|
<el-table-column prop="remark" label="备注" min-width="180" show-overflow-tooltip />
|
||||||
</el-table>
|
</el-table>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<div class="dialog-section-title">任务信息</div>
|
<section-card title="任务信息">
|
||||||
<div class="loading-manage-dialog__carrier-tabs">
|
<div class="loading-manage-dialog__carrier-tabs">
|
||||||
<el-segmented
|
<el-segmented
|
||||||
v-model="dialogForm.carrierType"
|
v-model="dialogForm.carrierType"
|
||||||
@@ -913,6 +918,7 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
</section-card>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1882,10 +1888,8 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.loading-manage-dialog__candidate-search {
|
.loading-manage-dialog__candidate-search {
|
||||||
padding: 12px 12px 4px;
|
padding: 4px 0;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
background: #fff;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-manage-dialog__candidate-actions,
|
.loading-manage-dialog__candidate-actions,
|
||||||
|
|||||||
@@ -24,10 +24,9 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
plain
|
|
||||||
v-if="hasPermission('process_config_add')"
|
v-if="hasPermission('process_config_add')"
|
||||||
@click="$refs.crud.rowAdd()"
|
@click="$refs.crud.rowAdd()"
|
||||||
>新增
|
>新建过程配置
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -53,13 +52,23 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #includedNodes="{ row }">
|
||||||
|
<span class="process-config-page__node-value">
|
||||||
|
{{ formatProcessNodes(row.includedNodes) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #basicInfo-form>
|
<template #basicInfo-form>
|
||||||
<div class="process-config-page__section">
|
<div class="process-config-page__section">
|
||||||
<div class="dialog-section-title">基本信息</div>
|
<div class="dialog-section-title">基本信息</div>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="12">
|
<el-col :span="8">
|
||||||
<div class="process-config-page__field">
|
<div class="process-config-page__field">
|
||||||
<span class="process-config-page__field-label">配置名称</span>
|
<span
|
||||||
|
class="process-config-page__field-label process-config-page__field-label--required"
|
||||||
|
>
|
||||||
|
配置名称
|
||||||
|
</span>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.configName"
|
v-model="form.configName"
|
||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
@@ -68,9 +77,13 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="8">
|
||||||
<div class="process-config-page__field">
|
<div class="process-config-page__field">
|
||||||
<span class="process-config-page__field-label">项目</span>
|
<span
|
||||||
|
class="process-config-page__field-label process-config-page__field-label--required"
|
||||||
|
>
|
||||||
|
项目
|
||||||
|
</span>
|
||||||
<el-select
|
<el-select
|
||||||
v-model="selectedProjectId"
|
v-model="selectedProjectId"
|
||||||
clearable
|
clearable
|
||||||
@@ -92,33 +105,33 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="8">
|
||||||
<div class="process-config-page__field">
|
<div class="process-config-page__field">
|
||||||
<span class="process-config-page__field-label">默认后台完成运输天数</span>
|
<span class="process-config-page__field-label">运输完成时限</span>
|
||||||
<div class="process-config-page__finish-days">
|
<div class="process-config-page__finish-days">
|
||||||
<span>默认</span>
|
<span>默认</span>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.defaultFinishDays"
|
v-model="form.defaultFinishDays"
|
||||||
:disabled="dialogReadonly"
|
:disabled="dialogReadonly"
|
||||||
maxlength="3"
|
maxlength="3"
|
||||||
placeholder="X"
|
placeholder="请输入"
|
||||||
@input="handleFinishDaysInput"
|
@input="handleFinishDaysInput"
|
||||||
/>
|
/>
|
||||||
<span>天后台完成运输</span>
|
<span>天后完成运输</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="24">
|
||||||
<div class="process-config-page__field">
|
<div class="process-config-page__field">
|
||||||
<span class="process-config-page__field-label">备注</span>
|
<span class="process-config-page__field-label">备注</span>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.remark"
|
v-model="form.remark"
|
||||||
:disabled="dialogReadonly"
|
|
||||||
:rows="3"
|
|
||||||
maxlength="500"
|
|
||||||
placeholder="请输入"
|
|
||||||
show-word-limit
|
|
||||||
type="textarea"
|
type="textarea"
|
||||||
|
:rows="4"
|
||||||
|
:disabled="dialogReadonly"
|
||||||
|
maxlength="500"
|
||||||
|
show-word-limit
|
||||||
|
placeholder="请输入"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -196,7 +209,7 @@
|
|||||||
<el-radio-group
|
<el-radio-group
|
||||||
v-model="row.confirmMode"
|
v-model="row.confirmMode"
|
||||||
:disabled="dialogReadonly || !row.enabled"
|
:disabled="dialogReadonly || !row.enabled"
|
||||||
@change="syncNodeFields"
|
@change="handleReturnConfirmChange(row)"
|
||||||
>
|
>
|
||||||
<el-radio label="yes">是</el-radio>
|
<el-radio label="yes">是</el-radio>
|
||||||
<el-radio label="no_confirm_complete">无需确认完成</el-radio>
|
<el-radio label="no_confirm_complete">无需确认完成</el-radio>
|
||||||
@@ -390,6 +403,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import * as api from '@/api/business/process-config';
|
import * as api from '@/api/business/process-config';
|
||||||
import { getList as getProjectList } from '@/api/business/project-apply';
|
import { getList as getProjectList } from '@/api/business/project-apply';
|
||||||
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
import { exportBlob } from '@/api/common';
|
import { exportBlob } from '@/api/common';
|
||||||
import { config, option } from '@/option/business/process-config';
|
import { config, option } from '@/option/business/process-config';
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
@@ -513,11 +527,35 @@ export default {
|
|||||||
created() {
|
created() {
|
||||||
this.resetNodeRows();
|
this.resetNodeRows();
|
||||||
this.loadProjectOptions('');
|
this.loadProjectOptions('');
|
||||||
|
this.initDeptOptions();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
hasPermission(code) {
|
hasPermission(code) {
|
||||||
return this.isAdmin || this.validData(this.permission && this.permission[code], false);
|
return this.isAdmin || this.validData(this.permission && this.permission[code], false);
|
||||||
},
|
},
|
||||||
|
handleReturnConfirmChange(row) {
|
||||||
|
row.confirmInternal = row.confirmMode === 'yes';
|
||||||
|
this.syncNodeFields();
|
||||||
|
},
|
||||||
|
initDeptOptions() {
|
||||||
|
getDeptTree(this.userInfo.tenantId).then(res => {
|
||||||
|
const deptColumn = this.findColumn(this.option.column, 'searchDeptId');
|
||||||
|
if (deptColumn) {
|
||||||
|
deptColumn.dicData = this.flattenDept(res.data.data || []);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
flattenDept(tree, level = 0) {
|
||||||
|
return tree.flatMap(item => [
|
||||||
|
{
|
||||||
|
label: `${' '.repeat(level)}${item.title || item.deptName || item.name}`,
|
||||||
|
value: item.id,
|
||||||
|
},
|
||||||
|
...(item.children && item.children.length
|
||||||
|
? this.flattenDept(item.children, level + 1)
|
||||||
|
: []),
|
||||||
|
]);
|
||||||
|
},
|
||||||
displayStatus(status) {
|
displayStatus(status) {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
0: '草稿',
|
0: '草稿',
|
||||||
@@ -526,6 +564,13 @@ export default {
|
|||||||
};
|
};
|
||||||
return statusMap[status] || status || '未知';
|
return statusMap[status] || status || '未知';
|
||||||
},
|
},
|
||||||
|
formatProcessNodes(nodes) {
|
||||||
|
return String(nodes || '')
|
||||||
|
.split(/[,,]/)
|
||||||
|
.map(item => item.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('-');
|
||||||
|
},
|
||||||
statusTagType(status) {
|
statusTagType(status) {
|
||||||
if (status === 1) return 'success';
|
if (status === 1) return 'success';
|
||||||
if (status === 2) return 'info';
|
if (status === 2) return 'info';
|
||||||
@@ -558,7 +603,7 @@ export default {
|
|||||||
voucherTypes: [],
|
voucherTypes: [],
|
||||||
frequencyDays: '1',
|
frequencyDays: '1',
|
||||||
timeStart: '00:00',
|
timeStart: '00:00',
|
||||||
timeEnd: '24:00',
|
timeEnd: '23:59',
|
||||||
supportCargo: false,
|
supportCargo: false,
|
||||||
supportVoucher: false,
|
supportVoucher: false,
|
||||||
voucherOptions: [],
|
voucherOptions: [],
|
||||||
@@ -705,7 +750,7 @@ export default {
|
|||||||
result.push(`打卡定位:${node.location ? '是' : '否'}`);
|
result.push(`打卡定位:${node.location ? '是' : '否'}`);
|
||||||
if (node.punch) {
|
if (node.punch) {
|
||||||
result.push(`打卡频次:每${node.frequencyDays || 1}天打卡1次`);
|
result.push(`打卡频次:每${node.frequencyDays || 1}天打卡1次`);
|
||||||
result.push(`打卡时段:${node.timeStart || '00:00'}-${node.timeEnd || '24:00'}`);
|
result.push(`打卡时段:${node.timeStart || '00:00'}-${node.timeEnd || '23:59'}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.push(`打卡操作:${node.punch ? '是' : '否'}`);
|
result.push(`打卡操作:${node.punch ? '是' : '否'}`);
|
||||||
@@ -744,10 +789,16 @@ export default {
|
|||||||
this.$message.warning('项目不能为空');
|
this.$message.warning('项目不能为空');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (row.defaultFinishDays && !/^[1-9]\d{0,2}$/.test(String(row.defaultFinishDays))) {
|
if (row.defaultFinishDays !== undefined && row.defaultFinishDays !== '') {
|
||||||
this.$message.warning('请输入正整数');
|
if (!Number.isInteger(Number(row.defaultFinishDays)) || Number(row.defaultFinishDays) < 0) {
|
||||||
|
this.$message.warning('完成天数不能小于0');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (Number(row.defaultFinishDays) > 999) {
|
||||||
|
this.$message.warning('完成天数不能超过999');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (row.remark && row.remark.length > 500) {
|
if (row.remark && row.remark.length > 500) {
|
||||||
this.$message.warning('备注不能超过500个字符');
|
this.$message.warning('备注不能超过500个字符');
|
||||||
return false;
|
return false;
|
||||||
@@ -774,43 +825,61 @@ export default {
|
|||||||
loading();
|
loading();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
rowSave(row, done, loading) {
|
needsDuplicateVoucherConfirm() {
|
||||||
|
const signNode = this.nodeRows.find(item => item.key === 'sign');
|
||||||
|
const returnNode = this.nodeRows.find(item => item.key === 'return');
|
||||||
|
const hasSignVoucher =
|
||||||
|
signNode &&
|
||||||
|
signNode.enabled &&
|
||||||
|
signNode.uploadVoucher &&
|
||||||
|
signNode.voucherTypes.includes('签收单');
|
||||||
|
const hasReturnVoucher =
|
||||||
|
returnNode &&
|
||||||
|
returnNode.enabled &&
|
||||||
|
returnNode.uploadVoucher &&
|
||||||
|
returnNode.voucherTypes.includes('签收单');
|
||||||
|
return hasSignVoucher && hasReturnVoucher;
|
||||||
|
},
|
||||||
|
confirmDuplicateVoucher() {
|
||||||
|
if (!this.needsDuplicateVoucherConfirm()) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
return this.$confirm(
|
||||||
|
'签收与回单同时勾选了上传凭证,司机将需重复上传凭证,是否确认?',
|
||||||
|
'提示',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确认',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
submitRow(row, done, loading) {
|
||||||
this.syncNodeFields();
|
this.syncNodeFields();
|
||||||
const submitRow = this.normalizeRow(row);
|
const submitRow = this.normalizeRow(row);
|
||||||
if (!this.validateRow(submitRow)) {
|
if (!this.validateRow(submitRow)) {
|
||||||
this.stopSubmitLoading(loading);
|
this.stopSubmitLoading(loading);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
api.submit(submitRow).then(
|
this.confirmDuplicateVoucher()
|
||||||
() => {
|
.then(() => api.submit(submitRow))
|
||||||
|
.then(() => {
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
this.$message({ type: 'success', message: '操作成功!' });
|
this.$message({ type: 'success', message: '操作成功!' });
|
||||||
done();
|
done();
|
||||||
},
|
})
|
||||||
error => {
|
.catch(error => {
|
||||||
|
if (error !== 'cancel' && error !== 'close') {
|
||||||
window.console.log(error);
|
window.console.log(error);
|
||||||
this.stopSubmitLoading(loading);
|
|
||||||
}
|
}
|
||||||
);
|
this.stopSubmitLoading(loading);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
rowSave(row, done, loading) {
|
||||||
|
this.submitRow(row, done, loading);
|
||||||
},
|
},
|
||||||
rowUpdate(row, index, done, loading) {
|
rowUpdate(row, index, done, loading) {
|
||||||
this.syncNodeFields();
|
this.submitRow(row, done, loading);
|
||||||
const submitRow = this.normalizeRow(row);
|
|
||||||
if (!this.validateRow(submitRow)) {
|
|
||||||
this.stopSubmitLoading(loading);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
api.submit(submitRow).then(
|
|
||||||
() => {
|
|
||||||
this.onLoad(this.page);
|
|
||||||
this.$message({ type: 'success', message: '操作成功!' });
|
|
||||||
done();
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
window.console.log(error);
|
|
||||||
this.stopSubmitLoading(loading);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
rowDel(row) {
|
rowDel(row) {
|
||||||
this.$confirm('确定将选择数据删除?', {
|
this.$confirm('确定将选择数据删除?', {
|
||||||
@@ -914,7 +983,11 @@ export default {
|
|||||||
onLoad(page, params = {}) {
|
onLoad(page, params = {}) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
api
|
api
|
||||||
.getList(page.currentPage, page.pageSize, { ...params, ...this.query, allDept: 0 })
|
.getList(page.currentPage, page.pageSize, {
|
||||||
|
...params,
|
||||||
|
...this.query,
|
||||||
|
allDept: this.isAdmin ? 1 : 0,
|
||||||
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const result = res.data.data || {};
|
const result = res.data.data || {};
|
||||||
this.page.total = result.total || 0;
|
this.page.total = result.total || 0;
|
||||||
@@ -928,7 +1001,7 @@ export default {
|
|||||||
buildExportParams() {
|
buildExportParams() {
|
||||||
return {
|
return {
|
||||||
...this.query,
|
...this.query,
|
||||||
allDept: 0,
|
allDept: this.isAdmin ? 1 : 0,
|
||||||
ids: this.ids,
|
ids: this.ids,
|
||||||
[this.website.tokenHeader]: getToken(),
|
[this.website.tokenHeader]: getToken(),
|
||||||
};
|
};
|
||||||
@@ -1004,6 +1077,17 @@ export default {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&--required::before {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: #f56c6c;
|
||||||
|
content: '*';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__node-value {
|
||||||
|
white-space: normal;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__finish-days {
|
&__finish-days {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
plain
|
|
||||||
v-if="canMajorProjectSupplement"
|
v-if="canMajorProjectSupplement"
|
||||||
@click="openProjectDialog('majorSupplement')"
|
@click="openProjectDialog('majorSupplement')"
|
||||||
>
|
>
|
||||||
@@ -29,7 +28,6 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
plain
|
|
||||||
v-if="canCreate"
|
v-if="canCreate"
|
||||||
@click="openProjectDialog('add')"
|
@click="openProjectDialog('add')"
|
||||||
>
|
>
|
||||||
@@ -176,21 +174,16 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="承办部门" prop="undertakeDeptId">
|
<el-form-item label="承办部门" prop="undertakeDeptId">
|
||||||
<el-select
|
<el-cascader
|
||||||
v-model="form.undertakeDeptId"
|
v-model="form.undertakeDeptId"
|
||||||
placeholder="请选择承办部门"
|
placeholder="请选择承办部门"
|
||||||
filterable
|
|
||||||
clearable
|
clearable
|
||||||
|
filterable
|
||||||
|
:options="deptTreeOptions"
|
||||||
|
:props="deptCascaderProps"
|
||||||
:disabled="isBasicInfoReadonly"
|
:disabled="isBasicInfoReadonly"
|
||||||
@change="handleUndertakeDeptChange"
|
@change="handleUndertakeDeptChange"
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in deptOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
/>
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="项目由来" prop="projectSource">
|
<el-form-item label="项目由来" prop="projectSource">
|
||||||
<el-select
|
<el-select
|
||||||
@@ -217,9 +210,11 @@
|
|||||||
<el-form-item label="客户名称" prop="customerNames">
|
<el-form-item label="客户名称" prop="customerNames">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="selectedCustomerId"
|
v-model="selectedCustomerId"
|
||||||
placeholder="搜索选择"
|
placeholder="支持多选,选择后下方列表展示"
|
||||||
|
multiple
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
|
collapse-tags
|
||||||
:loading="customerLoading"
|
:loading="customerLoading"
|
||||||
@visible-change="visible => visible && loadCustomerOptions('客户')"
|
@visible-change="visible => visible && loadCustomerOptions('客户')"
|
||||||
@change="handleCustomerChange"
|
@change="handleCustomerChange"
|
||||||
@@ -257,6 +252,7 @@
|
|||||||
v-model="form.fundLimit"
|
v-model="form.fundLimit"
|
||||||
placeholder="实际业务回款周期内付款额度"
|
placeholder="实际业务回款周期内付款额度"
|
||||||
@input="value => handleNumberInput('fundLimit', value)"
|
@input="value => handleNumberInput('fundLimit', value)"
|
||||||
|
@blur="formatAmountField('fundLimit')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="项目应收账款额度(万元)" prop="receivableLimit">
|
<el-form-item label="项目应收账款额度(万元)" prop="receivableLimit">
|
||||||
@@ -264,6 +260,7 @@
|
|||||||
v-model="form.receivableLimit"
|
v-model="form.receivableLimit"
|
||||||
placeholder="回款期内最大应收账款额度"
|
placeholder="回款期内最大应收账款额度"
|
||||||
@input="value => handleNumberInput('receivableLimit', value)"
|
@input="value => handleNumberInput('receivableLimit', value)"
|
||||||
|
@blur="formatAmountField('receivableLimit')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="应收账款回款期限" prop="receivableDays">
|
<el-form-item label="应收账款回款期限" prop="receivableDays">
|
||||||
@@ -466,13 +463,25 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="project-apply-form__material-card">
|
||||||
<div class="project-apply-form__material-head">
|
<div class="project-apply-form__material-head">
|
||||||
<div class="dialog-section-title project-apply-form__material-title">项目材料</div>
|
<div class="dialog-section-title project-apply-form__material-title">项目材料</div>
|
||||||
<el-button type="primary" :disabled="!attachmentRows.length" @click="handleBatchDownload"
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
:disabled="!attachmentRows.length"
|
||||||
|
@click="handleBatchDownload"
|
||||||
>批量下载</el-button
|
>批量下载</el-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="attachmentRows" border class="project-apply-form__table">
|
<el-alert
|
||||||
|
v-if="dialogReadonly && missingRequiredAttachmentTypes.length"
|
||||||
|
class="project-apply-form__material-warning"
|
||||||
|
type="warning"
|
||||||
|
:closable="false"
|
||||||
|
show-icon
|
||||||
|
:title="`缺少必需材料:${missingRequiredAttachmentTypes.join('、')}`"
|
||||||
|
/>
|
||||||
|
<el-table :data="attachmentRows" border class="project-apply-form__material-table">
|
||||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||||
<el-table-column label="附件类型" min-width="160" align="center">
|
<el-table-column label="附件类型" min-width="160" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
@@ -506,10 +515,7 @@
|
|||||||
<el-table-column label="操作" width="110" align="center">
|
<el-table-column label="操作" width="110" align="center">
|
||||||
<template #default="{ row, $index }">
|
<template #default="{ row, $index }">
|
||||||
<el-link type="primary" @click="downloadAttachment(row)">下载</el-link>
|
<el-link type="primary" @click="downloadAttachment(row)">下载</el-link>
|
||||||
<el-link
|
<el-link v-if="!dialogReadonly" type="primary" @click="removeAttachment($index)"
|
||||||
v-if="!dialogReadonly"
|
|
||||||
type="primary"
|
|
||||||
@click="removeAttachment($index)"
|
|
||||||
>删除</el-link
|
>删除</el-link
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
@@ -520,11 +526,12 @@
|
|||||||
class="project-apply-form__upload"
|
class="project-apply-form__upload"
|
||||||
:readonly="dialogReadonly"
|
:readonly="dialogReadonly"
|
||||||
:file-types="attachmentFileTypes"
|
:file-types="attachmentFileTypes"
|
||||||
:max-size="500"
|
:max-size="50"
|
||||||
button-text="上传附件"
|
button-text="上传附件"
|
||||||
tip="支持pdf、bmp、jpeg、png、jpg、doc、docx、ppt、pptx、xlsx、xls、eml、msg、zip的文件格式,单个文件大小限制500M"
|
tip="支持pdf、bmp、jpeg、png、jpg、doc、docx、ppt、pptx、xlsx、xls、eml、msg、zip的文件格式,单个文件大小限制50M"
|
||||||
@change="handleAttachmentChange"
|
@change="handleAttachmentChange"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="!isChangeDialog" class="dialog-section-title project-apply-form__table-title">
|
<div v-if="!isChangeDialog" class="dialog-section-title project-apply-form__table-title">
|
||||||
变更记录
|
变更记录
|
||||||
@@ -595,16 +602,24 @@
|
|||||||
:class="{ 'project-apply-dialog__footer--change': isChangeDialog }"
|
:class="{ 'project-apply-dialog__footer--change': isChangeDialog }"
|
||||||
>
|
>
|
||||||
<template v-if="isChangeDialog">
|
<template v-if="isChangeDialog">
|
||||||
<el-button type="primary" :loading="submitLoading" @click="submitChangeProject">
|
|
||||||
提交
|
|
||||||
</el-button>
|
|
||||||
<el-button type="primary" :loading="submitLoading" @click="saveChangeProject">
|
<el-button type="primary" :loading="submitLoading" @click="saveChangeProject">
|
||||||
保存
|
保存
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="projectBox = false">关闭</el-button>
|
<el-button type="primary" :loading="submitLoading" @click="submitChangeProject">
|
||||||
|
提交
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="handleCancelProject">取消</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-button @click="projectBox = false">取消</el-button>
|
<el-button @click="handleCancelProject">取消</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="!dialogReadonly"
|
||||||
|
type="primary"
|
||||||
|
:loading="submitLoading"
|
||||||
|
@click="saveProject"
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="!dialogReadonly"
|
v-if="!dialogReadonly"
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -680,7 +695,6 @@ import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
|||||||
import { getDictionary as getBizDictionary } from '@/api/system/dictbiz';
|
import { getDictionary as getBizDictionary } from '@/api/system/dictbiz';
|
||||||
import { getList as getUserList } from '@/api/system/user';
|
import { getList as getUserList } from '@/api/system/user';
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
import { applyTableMenuWidth } from '@/utils/table-menu';
|
|
||||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import NProgress from 'nprogress';
|
import NProgress from 'nprogress';
|
||||||
@@ -745,6 +759,7 @@ const changeTypeOptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const normalProjectAttachmentTypeOptions = [
|
const normalProjectAttachmentTypeOptions = [
|
||||||
|
'项目立项报告',
|
||||||
'利润测算表',
|
'利润测算表',
|
||||||
'单一来源供应商申请表/三方比价表',
|
'单一来源供应商申请表/三方比价表',
|
||||||
'合同模板',
|
'合同模板',
|
||||||
@@ -754,6 +769,7 @@ const normalProjectAttachmentTypeOptions = [
|
|||||||
].map(item => ({ label: item, value: item }));
|
].map(item => ({ label: item, value: item }));
|
||||||
|
|
||||||
const majorProjectAttachmentTypeOptions = [
|
const majorProjectAttachmentTypeOptions = [
|
||||||
|
'项目立项报告',
|
||||||
'会议纪要',
|
'会议纪要',
|
||||||
'评审表决票',
|
'评审表决票',
|
||||||
'利润测算表',
|
'利润测算表',
|
||||||
@@ -875,6 +891,8 @@ export default {
|
|||||||
fundDemand: [{ label: '资金需求', validator: validateAmount, trigger: 'blur' }],
|
fundDemand: [{ label: '资金需求', validator: validateAmount, trigger: 'blur' }],
|
||||||
handlerUserId: [
|
handlerUserId: [
|
||||||
{
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择项目经办人',
|
||||||
label: '项目经办人',
|
label: '项目经办人',
|
||||||
nameProp: 'handlerUserName',
|
nameProp: 'handlerUserName',
|
||||||
validator: validateUser,
|
validator: validateUser,
|
||||||
@@ -883,6 +901,8 @@ export default {
|
|||||||
],
|
],
|
||||||
principalUserId: [
|
principalUserId: [
|
||||||
{
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择项目负责人',
|
||||||
label: '项目负责人',
|
label: '项目负责人',
|
||||||
nameProp: 'principalUserName',
|
nameProp: 'principalUserName',
|
||||||
validator: validateUser,
|
validator: validateUser,
|
||||||
@@ -899,8 +919,16 @@ export default {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
deptOptions: [],
|
deptOptions: [],
|
||||||
|
deptTreeOptions: [],
|
||||||
|
deptCascaderProps: {
|
||||||
|
label: 'label',
|
||||||
|
value: 'value',
|
||||||
|
children: 'children',
|
||||||
|
emitPath: false,
|
||||||
|
checkStrictly: true,
|
||||||
|
},
|
||||||
cargoTypeOptions: [],
|
cargoTypeOptions: [],
|
||||||
selectedCustomerId: '',
|
selectedCustomerId: [],
|
||||||
selectedCarrierIds: [],
|
selectedCarrierIds: [],
|
||||||
customerOptions: [],
|
customerOptions: [],
|
||||||
carrierOptions: [],
|
carrierOptions: [],
|
||||||
@@ -993,6 +1021,12 @@ export default {
|
|||||||
? majorProjectAttachmentTypeOptions
|
? majorProjectAttachmentTypeOptions
|
||||||
: normalProjectAttachmentTypeOptions;
|
: normalProjectAttachmentTypeOptions;
|
||||||
},
|
},
|
||||||
|
missingRequiredAttachmentTypes() {
|
||||||
|
const uploadedTypes = new Set(this.attachmentRows.map(item => item.fileType).filter(Boolean));
|
||||||
|
return this.projectAttachmentTypeOptions
|
||||||
|
.map(item => item.value)
|
||||||
|
.filter(fileType => !uploadedTypes.has(fileType));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.loadDeptOptions();
|
this.loadDeptOptions();
|
||||||
@@ -1001,18 +1035,17 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
buildTableOption() {
|
buildTableOption() {
|
||||||
return applyTableMenuWidth(
|
return {
|
||||||
{
|
|
||||||
...option,
|
...option,
|
||||||
dialogType: 'dialog',
|
dialogType: 'dialog',
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
viewBtn: false,
|
viewBtn: false,
|
||||||
editBtn: false,
|
editBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
|
// 操作列收窄:本项目操作按钮较少,320px 过宽,调整为 220px(链接会自动换行兜底)
|
||||||
|
menuWidth: 180,
|
||||||
column: (option.column || []).map(column => ({ ...column, display: false })),
|
column: (option.column || []).map(column => ({ ...column, display: false })),
|
||||||
},
|
};
|
||||||
4
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
hasPermission(code) {
|
hasPermission(code) {
|
||||||
return this.isAdmin || this.validData(this.permission && this.permission[code], false);
|
return this.isAdmin || this.validData(this.permission && this.permission[code], false);
|
||||||
@@ -1233,7 +1266,7 @@ export default {
|
|||||||
if (type === 'add' || type === 'majorSupplement') {
|
if (type === 'add' || type === 'majorSupplement') {
|
||||||
this.applyProjectDetail({
|
this.applyProjectDetail({
|
||||||
...emptyForm(),
|
...emptyForm(),
|
||||||
projectType: type === 'majorSupplement' ? '重大项目' : '',
|
projectType: type === 'majorSupplement' ? '重大项目' : '普通项目',
|
||||||
});
|
});
|
||||||
this.fillDefaultUsers();
|
this.fillDefaultUsers();
|
||||||
return;
|
return;
|
||||||
@@ -1253,21 +1286,35 @@ export default {
|
|||||||
this.carrierRows = [];
|
this.carrierRows = [];
|
||||||
this.attachmentRows = [];
|
this.attachmentRows = [];
|
||||||
this.changeRows = [];
|
this.changeRows = [];
|
||||||
this.selectedCustomerId = '';
|
this.selectedCustomerId = [];
|
||||||
this.selectedCarrierIds = [];
|
this.selectedCarrierIds = [];
|
||||||
},
|
},
|
||||||
applyProjectDetail(row) {
|
applyProjectDetail(row) {
|
||||||
|
const displayRow = {
|
||||||
|
...row,
|
||||||
|
fundLimit: this.formatAmount(row.fundLimit),
|
||||||
|
receivableLimit: this.formatAmount(row.receivableLimit),
|
||||||
|
...(this.dialogReadonly
|
||||||
|
? {
|
||||||
|
projectScale: this.normalizeReadonlyAmount(row.projectScale),
|
||||||
|
estimatedProfit: this.normalizeReadonlyAmount(row.estimatedProfit),
|
||||||
|
fundDemand: this.normalizeReadonlyAmount(row.fundDemand),
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
const form = {
|
const form = {
|
||||||
...emptyForm(),
|
...emptyForm(),
|
||||||
...row,
|
...displayRow,
|
||||||
|
handlerUserName: this.resolveUserRealName(displayRow, 'handler'),
|
||||||
|
principalUserName: this.resolveUserRealName(displayRow, 'principal'),
|
||||||
businessDateRange:
|
businessDateRange:
|
||||||
row.businessStartDate && row.businessEndDate
|
displayRow.businessStartDate && displayRow.businessEndDate
|
||||||
? [row.businessStartDate, row.businessEndDate]
|
? [displayRow.businessStartDate, displayRow.businessEndDate]
|
||||||
: [],
|
: [],
|
||||||
};
|
};
|
||||||
const situation = this.parseSituation(row.situationRemark);
|
const situation = this.parseSituation(displayRow.situationRemark);
|
||||||
const customerRows = this.parseJsonArray(row.customerJson);
|
const customerRows = this.parseJsonArray(displayRow.customerJson);
|
||||||
const carrierRows = this.parseJsonArray(row.carrierJson);
|
const carrierRows = this.parseJsonArray(displayRow.carrierJson);
|
||||||
this.form = {
|
this.form = {
|
||||||
...form,
|
...form,
|
||||||
...situation,
|
...situation,
|
||||||
@@ -1276,9 +1323,11 @@ export default {
|
|||||||
};
|
};
|
||||||
this.customerRows = customerRows;
|
this.customerRows = customerRows;
|
||||||
this.carrierRows = carrierRows;
|
this.carrierRows = carrierRows;
|
||||||
this.attachmentRows = this.parseJsonArray(row.attachmentsJson);
|
this.attachmentRows = this.parseJsonArray(displayRow.attachmentsJson);
|
||||||
this.changeRows = this.buildChangeRows(row);
|
this.changeRows = this.buildChangeRows(displayRow);
|
||||||
this.selectedCustomerId = this.getCustomerRowId(this.customerRows[0]);
|
this.selectedCustomerId = this.customerRows
|
||||||
|
.map(item => this.getCustomerRowId(item))
|
||||||
|
.filter(Boolean);
|
||||||
this.selectedCarrierIds = this.carrierRows
|
this.selectedCarrierIds = this.carrierRows
|
||||||
.map(item => this.getCustomerRowId(item))
|
.map(item => this.getCustomerRowId(item))
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
@@ -1287,7 +1336,13 @@ export default {
|
|||||||
fillDefaultUsers() {
|
fillDefaultUsers() {
|
||||||
const userId = this.userInfo?.userId || this.userInfo?.id || '';
|
const userId = this.userInfo?.userId || this.userInfo?.id || '';
|
||||||
const userName =
|
const userName =
|
||||||
this.userInfo?.realName || this.userInfo?.userName || this.userInfo?.account || '';
|
this.userInfo?.realName ||
|
||||||
|
this.userInfo?.real_name ||
|
||||||
|
this.userInfo?.name ||
|
||||||
|
this.userInfo?.userName ||
|
||||||
|
this.userInfo?.user_name ||
|
||||||
|
this.userInfo?.account ||
|
||||||
|
'';
|
||||||
if (userId && userName) {
|
if (userId && userName) {
|
||||||
this.form.handlerUserId = userId;
|
this.form.handlerUserId = userId;
|
||||||
this.form.handlerUserName = userName;
|
this.form.handlerUserName = userName;
|
||||||
@@ -1295,6 +1350,16 @@ export default {
|
|||||||
this.form.principalUserName = userName;
|
this.form.principalUserName = userName;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
resolveUserRealName(row = {}, role) {
|
||||||
|
return (
|
||||||
|
row[`${role}RealName`] ||
|
||||||
|
row[`${role}UserRealName`] ||
|
||||||
|
row[`${role}User`]?.realName ||
|
||||||
|
row[role]?.realName ||
|
||||||
|
row[`${role}UserName`] ||
|
||||||
|
''
|
||||||
|
);
|
||||||
|
},
|
||||||
resolveChangeType(row = {}) {
|
resolveChangeType(row = {}) {
|
||||||
if (row.changeType) return row.changeType;
|
if (row.changeType) return row.changeType;
|
||||||
const node = row.currentNode || '';
|
const node = row.currentNode || '';
|
||||||
@@ -1330,6 +1395,36 @@ export default {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
saveProject() {
|
||||||
|
this.submitLoading = true;
|
||||||
|
this.api
|
||||||
|
.saveDraft(this.normalizeSubmitForm())
|
||||||
|
.then(res => {
|
||||||
|
if (res.data?.success === false || res.data?.data === false) {
|
||||||
|
this.$message.error(res.data?.msg || '保存失败,请联系管理员');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$message.success('保存成功!');
|
||||||
|
this.projectBox = false;
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.submitLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleCancelProject() {
|
||||||
|
if (!['add', 'majorSupplement', 'change'].includes(this.dialogType)) {
|
||||||
|
this.projectBox = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$confirm('确认后直接关闭弹窗,列表无数据变更,是否继续?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => {
|
||||||
|
this.projectBox = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
saveChangeProject() {
|
saveChangeProject() {
|
||||||
this.submitChangeForm(false);
|
this.submitChangeForm(false);
|
||||||
},
|
},
|
||||||
@@ -1366,6 +1461,8 @@ export default {
|
|||||||
const [businessStartDate, businessEndDate] = this.form.businessDateRange || [];
|
const [businessStartDate, businessEndDate] = this.form.businessDateRange || [];
|
||||||
const submitRow = {
|
const submitRow = {
|
||||||
...this.form,
|
...this.form,
|
||||||
|
fundLimit: this.formatAmount(this.form.fundLimit),
|
||||||
|
receivableLimit: this.formatAmount(this.form.receivableLimit),
|
||||||
businessStartDate,
|
businessStartDate,
|
||||||
businessEndDate,
|
businessEndDate,
|
||||||
customerJson: JSON.stringify(this.customerRows),
|
customerJson: JSON.stringify(this.customerRows),
|
||||||
@@ -1479,6 +1576,11 @@ export default {
|
|||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
},
|
},
|
||||||
|
normalizeReadonlyAmount(value) {
|
||||||
|
return value === null || value === undefined || value === '' || Number(value) === -1
|
||||||
|
? ''
|
||||||
|
: value;
|
||||||
|
},
|
||||||
mergeCustomerOptions(options = [], selectedOptions = []) {
|
mergeCustomerOptions(options = [], selectedOptions = []) {
|
||||||
const result = [...selectedOptions];
|
const result = [...selectedOptions];
|
||||||
options.forEach(option => {
|
options.forEach(option => {
|
||||||
@@ -1507,7 +1609,7 @@ export default {
|
|||||||
changeType:
|
changeType:
|
||||||
row.changeType ||
|
row.changeType ||
|
||||||
(String(row.currentNode || '').includes('备案') ? '项目备案调整' : '项目变更'),
|
(String(row.currentNode || '').includes('备案') ? '项目备案调整' : '项目变更'),
|
||||||
handler: row.handlerUserName || '',
|
handler: this.resolveUserRealName(row, 'handler'),
|
||||||
content: row.changeContent || '',
|
content: row.changeContent || '',
|
||||||
reason: row.changeReason || '',
|
reason: row.changeReason || '',
|
||||||
status: row.approvalStatusName || row.approvalStatus || '',
|
status: row.approvalStatusName || row.approvalStatus || '',
|
||||||
@@ -1531,9 +1633,18 @@ export default {
|
|||||||
},
|
},
|
||||||
loadDeptOptions() {
|
loadDeptOptions() {
|
||||||
getDeptTree().then(res => {
|
getDeptTree().then(res => {
|
||||||
this.deptOptions = this.flattenDept(res.data.data || []);
|
const deptTree = res.data.data || [];
|
||||||
|
this.deptOptions = this.flattenDept(deptTree);
|
||||||
|
this.deptTreeOptions = this.toDeptCascaderOptions(deptTree);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
toDeptCascaderOptions(list = []) {
|
||||||
|
return list.map(item => ({
|
||||||
|
label: item.title || item.deptName || item.name,
|
||||||
|
value: item.id,
|
||||||
|
children: item.children?.length ? this.toDeptCascaderOptions(item.children) : undefined,
|
||||||
|
}));
|
||||||
|
},
|
||||||
flattenDept(list = [], level = 0) {
|
flattenDept(list = [], level = 0) {
|
||||||
return list.reduce((result, item) => {
|
return list.reduce((result, item) => {
|
||||||
const label = item.title || item.deptName || item.name;
|
const label = item.title || item.deptName || item.name;
|
||||||
@@ -1568,7 +1679,11 @@ export default {
|
|||||||
const loadingKey = type === '客户' ? 'customerLoading' : 'carrierLoading';
|
const loadingKey = type === '客户' ? 'customerLoading' : 'carrierLoading';
|
||||||
const optionsKey = type === '客户' ? 'customerOptions' : 'carrierOptions';
|
const optionsKey = type === '客户' ? 'customerOptions' : 'carrierOptions';
|
||||||
this[loadingKey] = true;
|
this[loadingKey] = true;
|
||||||
getCustomerArchiveList(1, 100, { customerType: type, status: 1 })
|
getCustomerArchiveList(1, 100, {
|
||||||
|
customerType: type,
|
||||||
|
status: 1,
|
||||||
|
...(type === '客户' ? { approvalStatus: 'approved' } : {}),
|
||||||
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const records = (res.data.data && res.data.data.records) || [];
|
const records = (res.data.data && res.data.data.records) || [];
|
||||||
const selectedOptions = this.buildCustomerOptionsFromRows(
|
const selectedOptions = this.buildCustomerOptionsFromRows(
|
||||||
@@ -1592,16 +1707,16 @@ export default {
|
|||||||
raw: item,
|
raw: item,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
handleCustomerChange(id) {
|
handleCustomerChange(ids) {
|
||||||
if (!id) {
|
if (!ids || !ids.length) {
|
||||||
this.customerRows = [];
|
this.customerRows = [];
|
||||||
this.form.customerNames = '';
|
this.form.customerNames = '';
|
||||||
this.form.customerJson = '';
|
this.form.customerJson = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.loadCustomerDetailRow(id, 'customer').then(row => {
|
Promise.all(ids.map(id => this.loadCustomerDetailRow(id, 'customer'))).then(rows => {
|
||||||
this.customerRows = [row];
|
this.customerRows = rows;
|
||||||
this.form.customerNames = row.customer;
|
this.form.customerNames = rows.map(item => item.customer).join('、');
|
||||||
this.form.customerJson = JSON.stringify(this.customerRows);
|
this.form.customerJson = JSON.stringify(this.customerRows);
|
||||||
this.syncSelectedCustomerOptions();
|
this.syncSelectedCustomerOptions();
|
||||||
this.$refs.projectForm?.validateField('customerNames');
|
this.$refs.projectForm?.validateField('customerNames');
|
||||||
@@ -1654,6 +1769,14 @@ export default {
|
|||||||
this.form[prop] =
|
this.form[prop] =
|
||||||
parts.length > 1 ? `${parts[0]}.${parts.slice(1).join('').slice(0, 2)}` : parts[0];
|
parts.length > 1 ? `${parts[0]}.${parts.slice(1).join('').slice(0, 2)}` : parts[0];
|
||||||
},
|
},
|
||||||
|
formatAmount(value) {
|
||||||
|
if (value === null || value === undefined || value === '' || Number(value) === -1) return '';
|
||||||
|
const amount = Number(value);
|
||||||
|
return Number.isFinite(amount) ? amount.toFixed(2) : value;
|
||||||
|
},
|
||||||
|
formatAmountField(prop) {
|
||||||
|
this.form[prop] = this.formatAmount(this.form[prop]);
|
||||||
|
},
|
||||||
handleIntegerInput(prop, value) {
|
handleIntegerInput(prop, value) {
|
||||||
this.form[prop] = String(value || '').replace(/[^\d]/g, '');
|
this.form[prop] = String(value || '').replace(/[^\d]/g, '');
|
||||||
},
|
},
|
||||||
@@ -1734,7 +1857,7 @@ export default {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.project-apply-form {
|
.project-apply-form {
|
||||||
padding: 0 8px;
|
padding: 0;
|
||||||
|
|
||||||
:deep(.el-input),
|
:deep(.el-input),
|
||||||
:deep(.el-select),
|
:deep(.el-select),
|
||||||
@@ -1752,12 +1875,30 @@ export default {
|
|||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分区标题融入白色卡片顶部(与下方内容块拼成一张完整卡片)
|
||||||
|
:deep(.dialog-section-title:not(.project-apply-form__material-title)) {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 6px 6px 0 0;
|
||||||
|
padding: 14px 16px 4px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
&__grid {
|
&__grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||||
column-gap: 72px;
|
column-gap: 72px;
|
||||||
row-gap: 0;
|
row-gap: 0;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 16px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0 0 6px 6px;
|
||||||
|
padding: 14px 16px 4px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
&__picker-icon {
|
&__picker-icon {
|
||||||
@@ -1779,7 +1920,11 @@ export default {
|
|||||||
|
|
||||||
&__table {
|
&__table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 16px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0 0 6px 6px;
|
||||||
|
padding: 12px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
:deep(.el-table__header th) {
|
:deep(.el-table__header th) {
|
||||||
background: #f5f7fa;
|
background: #f5f7fa;
|
||||||
@@ -1793,6 +1938,12 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__textarea-list {
|
&__textarea-list {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0 0 6px 6px;
|
||||||
|
padding: 14px 16px 4px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
:deep(.el-form-item) {
|
:deep(.el-form-item) {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
@@ -1806,12 +1957,38 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-top: 8px;
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__material-card {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__material-table {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
:deep(.el-table__header th) {
|
||||||
|
background: #f5f7fa;
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__cell) {
|
||||||
|
border-color: #eff1f7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__material-warning {
|
||||||
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__material-title {
|
&__material-title {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-bottom: 14px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__material-warn {
|
&__material-warn {
|
||||||
@@ -1822,11 +1999,19 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__upload {
|
&__upload {
|
||||||
margin: -12px 0 24px;
|
margin: 0 0 16px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 12px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
&__change-textarea {
|
&__change-textarea {
|
||||||
margin-bottom: 24px;
|
margin-bottom: 16px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0 0 6px 6px;
|
||||||
|
padding: 14px 16px 4px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
:deep(.el-form-item__content) {
|
:deep(.el-form-item__content) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -1838,7 +2023,9 @@ export default {
|
|||||||
:global(.project-apply-dialog .el-dialog__body) {
|
:global(.project-apply-dialog .el-dialog__body) {
|
||||||
max-height: 76vh;
|
max-height: 76vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 16px 24px 8px;
|
overflow-x: hidden;
|
||||||
|
padding: 16px;
|
||||||
|
background: #f5f6fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-apply-dialog__footer {
|
.project-apply-dialog__footer {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<business-crud-page :api="api" :config="config" :crud-option="option" />
|
<business-crud-page :api="api" :config="config" :crud-option="option" :menu-width="270" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<business-crud-page :api="api" :config="config" :crud-option="option" />
|
<business-crud-page :api="api" :config="config" :crud-option="option" :menu-width="270" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<business-crud-page :api="api" :config="config" :crud-option="option" />
|
<business-crud-page :api="api" :config="config" :crud-option="option" :menu-width="220" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<business-crud-page :api="api" :config="config" :crud-option="option" />
|
<business-crud-page :api="api" :config="config" :crud-option="option" :menu-width="250" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
dialogType: 'drawer',
|
dialogType: 'drawer',
|
||||||
column: [
|
column: [
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export default {
|
|||||||
height: 'auto',
|
height: 'auto',
|
||||||
calcHeight: 32,
|
calcHeight: 32,
|
||||||
dialogWidth: 950,
|
dialogWidth: 950,
|
||||||
|
menuWidth: 180,
|
||||||
tip: false,
|
tip: false,
|
||||||
searchShow: true,
|
searchShow: true,
|
||||||
searchMenuSpan: 24,
|
searchMenuSpan: 24,
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export default {
|
|||||||
addBtn: false,
|
addBtn: false,
|
||||||
viewBtn: false,
|
viewBtn: false,
|
||||||
dialogWidth: 900,
|
dialogWidth: 900,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ export default {
|
|||||||
viewBtn: false,
|
viewBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
dialogWidth: 900,
|
dialogWidth: 900,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ export default {
|
|||||||
viewBtn: false,
|
viewBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
dialogWidth: 900,
|
dialogWidth: 900,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
size: 'default',
|
size: 'default',
|
||||||
searchSize: 'default',
|
searchSize: 'default',
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogType: 'drawer',
|
dialogType: 'drawer',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogType: 'drawer',
|
dialogType: 'drawer',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogType: 'drawer',
|
dialogType: 'drawer',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export default {
|
|||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
grid: true,
|
grid: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
dialogWidth: 880,
|
dialogWidth: 880,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export default {
|
|||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
grid: true,
|
grid: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
labelWidth: 'auto',
|
labelWidth: 'auto',
|
||||||
dialogWidth: 880,
|
dialogWidth: 880,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
|
|||||||
@@ -40,23 +40,121 @@
|
|||||||
</el-link>
|
</el-link>
|
||||||
</template>
|
</template>
|
||||||
<template #deptCategory="{ row }">
|
<template #deptCategory="{ row }">
|
||||||
<el-tag>{{ row.deptCategoryName }}</el-tag>
|
<el-tag>{{ getDeptCategoryLabel(row.deptCategory) }}</el-tag>
|
||||||
|
</template>
|
||||||
|
<template #leaderId="{ row }">
|
||||||
|
{{ getLeaderValue(row.leaderId, 'realName') }}
|
||||||
|
</template>
|
||||||
|
<template #leaderPhone="{ row }">
|
||||||
|
{{ getLeaderValue(row.leaderId, 'phone') }}
|
||||||
|
</template>
|
||||||
|
<template #status="{ row }">
|
||||||
|
<el-tag :type="Number(row.status) === 1 ? 'success' : 'info'">
|
||||||
|
{{ Number(row.status) === 1 ? '启用' : '停用' }}
|
||||||
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</avue-crud>
|
</avue-crud>
|
||||||
|
<el-dialog v-model="carrierDialogVisible" title="选择承运商" width="1100px" append-to-body>
|
||||||
|
<el-form :inline="true" :model="carrierQuery" class="carrier-search-form">
|
||||||
|
<el-form-item label="名称">
|
||||||
|
<el-input v-model="carrierQuery.fullName" placeholder="请输入承运商名称" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="准入标准">
|
||||||
|
<el-select v-model="carrierQuery.accessType" placeholder="全部" clearable>
|
||||||
|
<el-option label="临时" value="temporary" />
|
||||||
|
<el-option label="正式" value="formal" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="审批状态">
|
||||||
|
<el-select v-model="carrierQuery.approvalStatus" placeholder="全部" clearable>
|
||||||
|
<el-option label="草稿" value="draft" />
|
||||||
|
<el-option label="审核中" value="reviewing" />
|
||||||
|
<el-option label="审核通过" value="approved" />
|
||||||
|
<el-option label="审核不通过" value="rejected" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-select v-model="carrierQuery.status" placeholder="全部" clearable>
|
||||||
|
<el-option label="启用" :value="1" />
|
||||||
|
<el-option label="停用" :value="2" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="searchCarrier">搜索</el-button>
|
||||||
|
<el-button @click="resetCarrierQuery">清空</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-table :data="carrierData" border stripe height="420" @row-dblclick="selectCarrier">
|
||||||
|
<el-table-column prop="customerCode" label="客商编号" min-width="130" />
|
||||||
|
<el-table-column prop="shortName" label="客商简称" min-width="140" />
|
||||||
|
<el-table-column prop="fullName" label="客商名称" min-width="200" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="customerType" label="客户类型" min-width="120" />
|
||||||
|
<el-table-column prop="customerNature" label="客户性质" min-width="120" />
|
||||||
|
<el-table-column prop="unifiedCreditCode" label="统一信用代码" min-width="180" />
|
||||||
|
<el-table-column prop="deptName" label="所属组织" min-width="150" />
|
||||||
|
<el-table-column prop="accessType" label="准入标准" min-width="110">
|
||||||
|
<template #default="{ row }">{{ formatAccessType(row.accessType) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="approvalStatus" label="审批状态" min-width="120">
|
||||||
|
<template #default="{ row }">{{ formatApprovalStatus(row.approvalStatus) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="currentNode" label="当前节点" min-width="130" />
|
||||||
|
<el-table-column prop="currentProcessor" label="当前处理人" min-width="130" />
|
||||||
|
<el-table-column prop="approvedTime" label="审核通过时间" min-width="170" />
|
||||||
|
<el-table-column prop="status" label="状态" width="90">
|
||||||
|
<template #default="{ row }">{{ Number(row.status) === 1 ? '启用' : '停用' }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="90" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-link type="primary" @click="selectCarrier(row)">选择</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="carrier-pagination">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="carrierPage.current"
|
||||||
|
v-model:page-size="carrierPage.size"
|
||||||
|
:total="carrierPage.total"
|
||||||
|
:page-sizes="[10, 20, 50]"
|
||||||
|
layout="total, sizes, prev, pager, next"
|
||||||
|
@current-change="loadCarrierList"
|
||||||
|
@size-change="handleCarrierSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</basic-container>
|
</basic-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getLazyList, remove, update, add, getDept, getDeptTree } from '@/api/system/dept';
|
import { getLazyList, remove, update, add, getDept, getDeptTree } from '@/api/system/dept';
|
||||||
import { getLeaderList } from '@/api/system/user';
|
import { getLeaderList } from '@/api/system/user';
|
||||||
|
import { getList as getCustomerArchiveList } from '@/api/vehicle/customer-archive';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import website from '@/config/website';
|
import website from '@/config/website';
|
||||||
import func from '@/utils/func';
|
import func from '@/utils/func';
|
||||||
|
|
||||||
|
const escapeRegExp = value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {},
|
form: {},
|
||||||
|
leaderOptions: [],
|
||||||
|
parentDeptCode: '',
|
||||||
|
parentDept: null,
|
||||||
|
carrierDialogVisible: false,
|
||||||
|
carrierData: [],
|
||||||
|
carrierQuery: {
|
||||||
|
fullName: '',
|
||||||
|
accessType: '',
|
||||||
|
approvalStatus: '',
|
||||||
|
status: undefined,
|
||||||
|
},
|
||||||
|
carrierPage: {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
selectionList: [],
|
selectionList: [],
|
||||||
query: {},
|
query: {},
|
||||||
loading: true,
|
loading: true,
|
||||||
@@ -73,29 +171,170 @@ export default {
|
|||||||
searchShow: true,
|
searchShow: true,
|
||||||
searchMenuSpan: 24,
|
searchMenuSpan: 24,
|
||||||
searchIcon: true,
|
searchIcon: true,
|
||||||
searchIndex: 8,
|
searchIndex: 4,
|
||||||
searchMenuPosition: 'right',
|
searchMenuPosition: 'right',
|
||||||
tree: true,
|
tree: true,
|
||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
menuWidth: 160,
|
menuWidth: 320,
|
||||||
dialogWidth: 800,
|
dialogWidth: 800,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
|
labelPosition: 'right',
|
||||||
|
labelWidth: 'auto',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '机构名称',
|
label: '组织名称',
|
||||||
prop: 'deptName',
|
prop: 'deptName',
|
||||||
|
minWidth: 160,
|
||||||
|
order: 80,
|
||||||
search: true,
|
search: true,
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入机构名称',
|
message: '请输入组织名称',
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '组织编码',
|
||||||
|
prop: 'deptCode',
|
||||||
|
minWidth: 140,
|
||||||
|
order: 70,
|
||||||
|
maxlength: 30,
|
||||||
|
showWordLimit: true,
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入组织编码',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
const deptCode = String(value || '').trim();
|
||||||
|
if (deptCode.length > 30) {
|
||||||
|
callback(new Error('组织编码不能超过30个字符'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.parentDeptCode) {
|
||||||
|
callback(new Error('请先选择上级组织'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const pattern = new RegExp(`^${escapeRegExp(this.parentDeptCode)}-\\d+$`);
|
||||||
|
if (!pattern.test(deptCode)) {
|
||||||
|
callback(new Error(`组织编码格式应为:${this.parentDeptCode}-分段数字`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '组织简称',
|
||||||
|
prop: 'shortName',
|
||||||
|
minWidth: 140,
|
||||||
|
order: 60,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '组织类型',
|
||||||
|
type: 'select',
|
||||||
|
dicData: [
|
||||||
|
{ label: '一级集团', value: 1 },
|
||||||
|
{ label: '二级事业部', value: 2 },
|
||||||
|
{ label: '部门', value: 3 },
|
||||||
|
{ label: '三级分公司', value: 4 },
|
||||||
|
{ label: '物流园区', value: 5 },
|
||||||
|
{ label: '承运商', value: 6 },
|
||||||
|
],
|
||||||
|
dataType: 'number',
|
||||||
|
minWidth: 120,
|
||||||
|
order: 90,
|
||||||
|
prop: 'deptCategory',
|
||||||
|
slot: true,
|
||||||
|
change: ({ value }) => this.handleDeptCategoryChange(value),
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择组织类型',
|
||||||
|
trigger: 'change',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '负责人',
|
||||||
|
prop: 'leaderId',
|
||||||
|
minWidth: 120,
|
||||||
|
slot: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '联系电话',
|
||||||
|
prop: 'leaderPhone',
|
||||||
|
minWidth: 140,
|
||||||
|
slot: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '助记码',
|
||||||
|
prop: 'mnemonicCode',
|
||||||
|
minWidth: 120,
|
||||||
|
order: 40,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '拼音助记码',
|
||||||
|
prop: 'pinyinMnemonic',
|
||||||
|
minWidth: 140,
|
||||||
|
order: 50,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '排序',
|
||||||
|
prop: 'sort',
|
||||||
|
type: 'number',
|
||||||
|
align: 'right',
|
||||||
|
width: 80,
|
||||||
|
order: 30,
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入排序',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '状态',
|
||||||
|
prop: 'status',
|
||||||
|
width: 100,
|
||||||
|
slot: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '上级组织',
|
||||||
|
prop: 'parentId',
|
||||||
|
dicData: [],
|
||||||
|
type: 'tree',
|
||||||
|
hide: true,
|
||||||
|
addDisabled: false,
|
||||||
|
order: 100,
|
||||||
|
change: ({ value }) => this.handleParentChange(value),
|
||||||
|
props: {
|
||||||
|
label: 'title',
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择上级组织',
|
||||||
|
trigger: 'click',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '所属租户',
|
label: '所属租户',
|
||||||
prop: 'tenantId',
|
prop: 'tenantId',
|
||||||
@@ -104,112 +343,37 @@ export default {
|
|||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
viewDisplay: website.tenantMode,
|
viewDisplay: website.tenantMode,
|
||||||
span: 24,
|
|
||||||
props: {
|
props: {
|
||||||
label: 'tenantName',
|
label: 'tenantName',
|
||||||
value: 'tenantId',
|
value: 'tenantId',
|
||||||
},
|
},
|
||||||
hide: !website.tenantMode,
|
hide: true,
|
||||||
search: website.tenantMode,
|
search: website.tenantMode,
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入所属租户',
|
|
||||||
trigger: 'click',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '机构全称',
|
label: '机构全称',
|
||||||
prop: 'fullName',
|
prop: 'fullName',
|
||||||
search: true,
|
search: true,
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入机构全称',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '上级机构',
|
|
||||||
prop: 'parentId',
|
|
||||||
dicData: [],
|
|
||||||
type: 'tree',
|
|
||||||
hide: true,
|
hide: true,
|
||||||
addDisabled: false,
|
addDisplay: false,
|
||||||
props: {
|
editDisplay: false,
|
||||||
label: 'title',
|
|
||||||
},
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: false,
|
|
||||||
message: '请选择上级机构',
|
|
||||||
trigger: 'click',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '直属主管',
|
|
||||||
prop: 'leaderId',
|
|
||||||
type: 'tree',
|
|
||||||
multiple: true,
|
|
||||||
filterable: true,
|
|
||||||
dicData: [],
|
|
||||||
props: {
|
|
||||||
label: 'realName',
|
|
||||||
value: 'id',
|
|
||||||
},
|
|
||||||
clearable: true,
|
|
||||||
hide: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '机构类型',
|
|
||||||
type: 'select',
|
|
||||||
dicUrl: '/blade-system/dict/dictionary?code=org_category',
|
|
||||||
props: {
|
|
||||||
label: 'dictValue',
|
|
||||||
value: 'dictKey',
|
|
||||||
},
|
|
||||||
dataType: 'number',
|
|
||||||
width: 120,
|
|
||||||
prop: 'deptCategory',
|
|
||||||
slot: true,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入机构类型',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '排序',
|
|
||||||
prop: 'sort',
|
|
||||||
type: 'number',
|
|
||||||
align: 'right',
|
|
||||||
width: 80,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入排序',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '备注',
|
label: '备注',
|
||||||
prop: 'remark',
|
prop: 'remark',
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
span: 24,
|
|
||||||
minRows: 2,
|
|
||||||
hide: true,
|
hide: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
data: [],
|
data: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
this.loadLeaderOptions();
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['userInfo', 'permission']),
|
...mapGetters(['userInfo', 'permission']),
|
||||||
permissionList() {
|
permissionList() {
|
||||||
@@ -234,13 +398,130 @@ export default {
|
|||||||
const column = this.findColumn(this.option.column, 'parentId');
|
const column = this.findColumn(this.option.column, 'parentId');
|
||||||
column.dicData = res.data.data;
|
column.dicData = res.data.data;
|
||||||
});
|
});
|
||||||
getLeaderList(tenantId).then(res => {
|
},
|
||||||
const column = this.findColumn(this.option.column, 'leaderId');
|
handleParentChange(parentId) {
|
||||||
column.dicData = res.data.data;
|
this.loadParentDeptCode(parentId);
|
||||||
|
},
|
||||||
|
loadParentDeptCode(parentId) {
|
||||||
|
this.parentDeptCode = '';
|
||||||
|
this.parentDept = null;
|
||||||
|
if (!parentId || String(parentId) === '0') return;
|
||||||
|
getDept(parentId).then(res => {
|
||||||
|
this.parentDept = res.data.data || null;
|
||||||
|
this.parentDeptCode = this.parentDept?.deptCode || '';
|
||||||
|
this.updateDeptCategoryOptions();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
updateDeptCategoryOptions() {
|
||||||
|
const categoryColumn = this.findColumn(this.option.column, 'deptCategory');
|
||||||
|
const parent = this.parentDept;
|
||||||
|
if (!parent) return;
|
||||||
|
let dicData = [];
|
||||||
|
if (this.isRootDept(parent)) {
|
||||||
|
dicData =
|
||||||
|
parent.deptName === '外部组织'
|
||||||
|
? [{ label: '承运商', value: 6 }]
|
||||||
|
: [{ label: '集团', value: 1 }];
|
||||||
|
} else if (Number(parent.deptCategory) === 1) {
|
||||||
|
dicData = [
|
||||||
|
{ label: '事业部', value: 2 },
|
||||||
|
{ label: '部门', value: 3 },
|
||||||
|
];
|
||||||
|
} else if ([2, 3].includes(Number(parent.deptCategory))) {
|
||||||
|
dicData = [
|
||||||
|
{ label: '分公司', value: 4 },
|
||||||
|
{ label: '物流园区', value: 5 },
|
||||||
|
{ label: '承运商', value: 6 },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
categoryColumn.dicData = dicData;
|
||||||
|
if (!dicData.some(item => item.value === Number(this.form.deptCategory))) {
|
||||||
|
this.form.deptCategory = dicData[0]?.value;
|
||||||
|
}
|
||||||
|
if (Number(this.form.deptCategory) === 6) {
|
||||||
|
this.openCarrierDialog();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleDeptCategoryChange(value) {
|
||||||
|
if (Number(value) === 6) {
|
||||||
|
this.openCarrierDialog();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openCarrierDialog() {
|
||||||
|
this.carrierDialogVisible = true;
|
||||||
|
this.loadCarrierList();
|
||||||
|
},
|
||||||
|
loadCarrierList() {
|
||||||
|
getCustomerArchiveList(this.carrierPage.current, this.carrierPage.size, {
|
||||||
|
...this.carrierQuery,
|
||||||
|
customerType: '承运商',
|
||||||
|
}).then(res => {
|
||||||
|
const page = res.data.data || {};
|
||||||
|
this.carrierData = page.records || [];
|
||||||
|
this.carrierPage.total = page.total || 0;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
searchCarrier() {
|
||||||
|
this.carrierPage.current = 1;
|
||||||
|
this.loadCarrierList();
|
||||||
|
},
|
||||||
|
resetCarrierQuery() {
|
||||||
|
this.carrierQuery = { fullName: '', accessType: '', approvalStatus: '', status: undefined };
|
||||||
|
this.searchCarrier();
|
||||||
|
},
|
||||||
|
handleCarrierSizeChange(size) {
|
||||||
|
this.carrierPage.size = size;
|
||||||
|
this.carrierPage.current = 1;
|
||||||
|
this.loadCarrierList();
|
||||||
|
},
|
||||||
|
selectCarrier(row) {
|
||||||
|
this.form.carrierCustomerId = row.id;
|
||||||
|
this.form.deptName = row.fullName;
|
||||||
|
this.form.shortName = row.shortName;
|
||||||
|
this.form.mnemonicCode = row.mnemonicCode;
|
||||||
|
this.carrierDialogVisible = false;
|
||||||
|
},
|
||||||
|
formatAccessType(value) {
|
||||||
|
return value === 'formal' ? '正式' : value === 'temporary' ? '临时' : '-';
|
||||||
|
},
|
||||||
|
formatApprovalStatus(value) {
|
||||||
|
const statusMap = {
|
||||||
|
draft: '草稿',
|
||||||
|
reviewing: '审核中',
|
||||||
|
approved: '审核通过',
|
||||||
|
rejected: '审核不通过',
|
||||||
|
};
|
||||||
|
return statusMap[value] || '-';
|
||||||
|
},
|
||||||
|
loadLeaderOptions(tenantId) {
|
||||||
|
getLeaderList(tenantId).then(res => {
|
||||||
|
this.leaderOptions = res.data.data || [];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getDeptCategoryLabel(deptCategory) {
|
||||||
|
const categoryMap = {
|
||||||
|
1: '集团',
|
||||||
|
2: '事业部',
|
||||||
|
3: '部门',
|
||||||
|
4: '分公司',
|
||||||
|
5: '物流园区',
|
||||||
|
6: '承运商',
|
||||||
|
};
|
||||||
|
return categoryMap[Number(deptCategory)] || '-';
|
||||||
|
},
|
||||||
|
getLeaderValue(leaderId, field) {
|
||||||
|
const values = func.split(leaderId);
|
||||||
|
const result = values
|
||||||
|
.map(id => this.leaderOptions.find(item => String(item.id) === String(id))?.[field])
|
||||||
|
.filter(Boolean);
|
||||||
|
return result.length ? result.join('、') : '-';
|
||||||
|
},
|
||||||
|
isRootDept(row) {
|
||||||
|
return row && (row.parentId === 0 || String(row.parentId) === '0');
|
||||||
|
},
|
||||||
handleAdd(row) {
|
handleAdd(row) {
|
||||||
this.parentId = row.id;
|
this.parentId = row.id;
|
||||||
|
this.loadParentDeptCode(row.id);
|
||||||
const column = this.findColumn(this.option.column, 'parentId');
|
const column = this.findColumn(this.option.column, 'parentId');
|
||||||
column.value = row.id;
|
column.value = row.id;
|
||||||
column.addDisabled = true;
|
column.addDisabled = true;
|
||||||
@@ -248,7 +529,13 @@ export default {
|
|||||||
},
|
},
|
||||||
rowSave(row, done, loading) {
|
rowSave(row, done, loading) {
|
||||||
row.tenantId = row.tenantId || this.userInfo.tenantId || website.tenantId;
|
row.tenantId = row.tenantId || this.userInfo.tenantId || website.tenantId;
|
||||||
|
row.deptCode = String(row.deptCode || '').trim();
|
||||||
row.leaderId = func.join(row.leaderId);
|
row.leaderId = func.join(row.leaderId);
|
||||||
|
if (Number(row.deptCategory) === 6 && !row.carrierCustomerId) {
|
||||||
|
this.$message.warning('请选择承运商');
|
||||||
|
loading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
add(row).then(
|
add(row).then(
|
||||||
res => {
|
res => {
|
||||||
// 获取新增数据的相关字段
|
// 获取新增数据的相关字段
|
||||||
@@ -271,7 +558,13 @@ export default {
|
|||||||
},
|
},
|
||||||
rowUpdate(row, index, done, loading) {
|
rowUpdate(row, index, done, loading) {
|
||||||
row.tenantId = row.tenantId || this.userInfo.tenantId || website.tenantId;
|
row.tenantId = row.tenantId || this.userInfo.tenantId || website.tenantId;
|
||||||
|
row.deptCode = String(row.deptCode || '').trim();
|
||||||
row.leaderId = func.join(row.leaderId);
|
row.leaderId = func.join(row.leaderId);
|
||||||
|
if (Number(row.deptCategory) === 6 && !row.carrierCustomerId) {
|
||||||
|
this.$message.warning('请选择承运商');
|
||||||
|
loading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
update(row).then(
|
update(row).then(
|
||||||
() => {
|
() => {
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -288,6 +581,10 @@ export default {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
rowDel(row, index, done) {
|
rowDel(row, index, done) {
|
||||||
|
if (this.isRootDept(row)) {
|
||||||
|
this.$message.warning('根节点不能删除');
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.$confirm('确定将选择数据删除?', {
|
this.$confirm('确定将选择数据删除?', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
@@ -310,13 +607,22 @@ export default {
|
|||||||
this.$message.warning('请选择至少一条数据');
|
this.$message.warning('请选择至少一条数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const deletableRows = this.selectionList.filter(row => !this.isRootDept(row));
|
||||||
|
if (deletableRows.length === 0) {
|
||||||
|
this.$message.warning('根节点不能删除');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (deletableRows.length !== this.selectionList.length) {
|
||||||
|
this.$message.warning('根节点不能删除,已忽略根节点');
|
||||||
|
}
|
||||||
|
const deletableIds = deletableRows.map(row => row.id).join(',');
|
||||||
this.$confirm('确定将选择数据删除?', {
|
this.$confirm('确定将选择数据删除?', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return remove(this.ids);
|
return remove(deletableIds);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// 刷新表格数据并重载
|
// 刷新表格数据并重载
|
||||||
@@ -355,6 +661,7 @@ export default {
|
|||||||
if (type === 'add') {
|
if (type === 'add') {
|
||||||
this.form.tenantId = this.form.tenantId || this.userInfo.tenantId || website.tenantId;
|
this.form.tenantId = this.form.tenantId || this.userInfo.tenantId || website.tenantId;
|
||||||
this.initData(this.form.tenantId);
|
this.initData(this.form.tenantId);
|
||||||
|
this.loadParentDeptCode(this.form.parentId);
|
||||||
}
|
}
|
||||||
if (type === 'edit') {
|
if (type === 'edit') {
|
||||||
this.initData(this.form.tenantId || this.userInfo.tenantId || website.tenantId);
|
this.initData(this.form.tenantId || this.userInfo.tenantId || website.tenantId);
|
||||||
@@ -367,6 +674,7 @@ export default {
|
|||||||
if (this.form.parentId === '0') {
|
if (this.form.parentId === '0') {
|
||||||
this.form.parentId = '';
|
this.form.parentId = '';
|
||||||
}
|
}
|
||||||
|
this.loadParentDeptCode(this.form.parentId);
|
||||||
if (this.form.hasOwnProperty('leaderId')) {
|
if (this.form.hasOwnProperty('leaderId')) {
|
||||||
this.form.leaderId = func.split(this.form.leaderId);
|
this.form.leaderId = func.split(this.form.leaderId);
|
||||||
}
|
}
|
||||||
@@ -376,6 +684,8 @@ export default {
|
|||||||
},
|
},
|
||||||
beforeClose(done) {
|
beforeClose(done) {
|
||||||
this.parentId = '';
|
this.parentId = '';
|
||||||
|
this.parentDeptCode = '';
|
||||||
|
this.parentDept = null;
|
||||||
const column = this.findColumn(this.option.column, 'parentId');
|
const column = this.findColumn(this.option.column, 'parentId');
|
||||||
column.value = '';
|
column.value = '';
|
||||||
column.addDisabled = false;
|
column.addDisabled = false;
|
||||||
@@ -408,4 +718,34 @@ export default {
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style>
|
<style scoped>
|
||||||
|
.carrier-search-form {
|
||||||
|
padding: 12px 12px 4px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.carrier-pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 操作列兜底:确保「查看 / 编辑 / 删除 / 新增子项」横向排列并保留 8px 间距,
|
||||||
|
避免退化成 block 导致操作项竖排错位。全局样式已统一处理,此处为双保险。 */
|
||||||
|
:deep(.avue-crud__menu) {
|
||||||
|
display: inline-flex !important;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
> .el-button,
|
||||||
|
> .el-link,
|
||||||
|
> .el-dropdown {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export default {
|
|||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
menuWidth: 320,
|
menuWidth: 220,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</template>
|
</template>
|
||||||
<!-- 操作栏模块 -->
|
<!-- 操作栏模块 -->
|
||||||
<el-table-column prop="menu" label="操作" :width="220" align="center">
|
<el-table-column prop="menu" label="操作" :width="180" align="center">
|
||||||
<template #="{ row }">
|
<template #="{ row }">
|
||||||
<el-link
|
<el-link
|
||||||
v-if="this.permissionList.viewBtn"
|
v-if="this.permissionList.viewBtn"
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ export default {
|
|||||||
selection: true,
|
selection: true,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
menuWidth: 160,
|
menuWidth: 240,
|
||||||
dialogWidth: 900,
|
dialogWidth: 900,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ export default {
|
|||||||
index: true,
|
index: true,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 900,
|
dialogWidth: 900,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
column: [
|
column: [
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
v-if="permission.user_add && !auditMode"
|
v-if="permission.user_add && !auditMode"
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
@click="$refs.crud.rowAdd()"
|
@click="openUserDialog('add')"
|
||||||
>新 增
|
>新 增
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
@@ -134,7 +134,7 @@
|
|||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="this.permission.user_edit"
|
v-if="this.permission.user_edit"
|
||||||
@click.stop="$refs.crud.rowEdit(row, index)"
|
@click.stop="openUserDialog('edit', row)"
|
||||||
>编辑
|
>编辑
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-dropdown @command="command => handleDropdownCommand(command, row, index)">
|
<el-dropdown @command="command => handleDropdownCommand(command, row, index)">
|
||||||
@@ -147,12 +147,6 @@
|
|||||||
<el-dropdown-item command="grantRole" v-if="permission.user_role">
|
<el-dropdown-item command="grantRole" v-if="permission.user_role">
|
||||||
角色配置
|
角色配置
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item
|
|
||||||
command="platformConfig"
|
|
||||||
v-if="userInfo.authority.includes('admin')"
|
|
||||||
>
|
|
||||||
平台配置
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="authLog" v-if="userInfo.authority.includes('admin')">
|
<el-dropdown-item command="authLog" v-if="userInfo.authority.includes('admin')">
|
||||||
认证日志
|
认证日志
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
@@ -172,20 +166,62 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</template>
|
</template>
|
||||||
<template #tenantName="{ row }">
|
|
||||||
<el-tag>{{ row.tenantName }}</el-tag>
|
|
||||||
</template>
|
|
||||||
<template #roleName="{ row }">
|
<template #roleName="{ row }">
|
||||||
<el-tag>{{ row.roleName }}</el-tag>
|
<el-tag>{{ row.roleName }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #deptName="{ row }">
|
<template #deptName="{ row }">
|
||||||
<el-tag>{{ row.deptName }}</el-tag>
|
<el-tag>{{ row.deptName }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #userTypeName="{ row }">
|
|
||||||
<el-tag>{{ row.userTypeName }}</el-tag>
|
|
||||||
</template>
|
|
||||||
</avue-crud>
|
</avue-crud>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
v-model="userDialog"
|
||||||
|
:title="userDialogMode === 'add' ? '新增用户' : '编辑用户'"
|
||||||
|
width="90%"
|
||||||
|
top="5vh"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
class="user-edit-dialog"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<span class="dialog-title">{{ userDialogMode === 'add' ? '新增用户' : '编辑用户' }}</span>
|
||||||
|
</template>
|
||||||
|
<el-form ref="userFormRef" :model="form" :rules="userRules" label-position="right" label-width="120px">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="6"><el-form-item label="账号名" prop="account"><el-input v-model="form.account" /></el-form-item></el-col>
|
||||||
|
<el-col :span="6"><el-form-item label="姓名" prop="realName"><el-input v-model="form.realName" /></el-form-item></el-col>
|
||||||
|
<el-col :span="6"><el-form-item label="手机号" prop="phone"><el-input v-model="form.phone" /></el-form-item></el-col>
|
||||||
|
<el-col :span="6"><el-form-item label="邮箱"><el-input v-model="form.email" /></el-form-item></el-col>
|
||||||
|
<el-col :span="6"><el-form-item label="性别"><el-select v-model="form.sex" class="full-width"><el-option label="男" :value="1" /><el-option label="女" :value="2" /><el-option label="未知" :value="3" /></el-select></el-form-item></el-col>
|
||||||
|
<el-col :span="6"><el-form-item label="岗位" prop="postId"><el-tree-select v-model="form.postId" :data="postList" :props="{ label: 'postName', value: 'id' }" check-strictly class="full-width" /></el-form-item></el-col>
|
||||||
|
<el-col :span="6"><el-form-item label="所属组织" prop="deptId"><el-tree-select v-model="form.deptId" :data="permissionDeptTree" :props="{ label: 'title', value: 'id' }" multiple check-strictly show-checkbox class="full-width" /></el-form-item></el-col>
|
||||||
|
<el-col :span="6"><el-form-item label="工号"><el-input v-model="form.code" /></el-form-item></el-col>
|
||||||
|
<el-col :span="6"><el-form-item label="人员类别"><el-select v-model="form.personCategory" class="full-width"><el-option label="内部员工" :value="1" /><el-option label="承运商" :value="2" /></el-select></el-form-item></el-col>
|
||||||
|
<el-col :span="18"><el-form-item label="数据权限范围"><el-radio-group v-model="form.dataScopeRange"><el-radio :value="1">仅所属组织</el-radio><el-radio :value="2">全部组织</el-radio><el-radio :value="3">自定义</el-radio></el-radio-group></el-form-item></el-col>
|
||||||
|
<el-col :span="18" :offset="6"><el-form-item label="数据层级范围"><el-radio-group v-model="form.dataLevelRange"><el-radio :value="1">包含下级</el-radio><el-radio :value="2">仅本级</el-radio></el-radio-group></el-form-item></el-col>
|
||||||
|
<el-col :span="24"><el-form-item label="备注"><el-input v-model="form.remark" type="textarea" :rows="3" maxlength="200" show-word-limit /></el-form-item></el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<el-tabs class="user-permission-tabs">
|
||||||
|
<el-tab-pane label="已拥有角色">
|
||||||
|
<el-table :data="formRoleList" border>
|
||||||
|
<el-table-column type="index" label="序号" width="70" />
|
||||||
|
<el-table-column prop="id" label="角色编号" />
|
||||||
|
<el-table-column prop="title" label="角色名称" />
|
||||||
|
<el-table-column label="操作" width="90"><template #default="{ row }"><el-link type="danger" @click="removeFormRole(row.id)">删除</el-link></template></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane v-if="form.dataScopeRange === 3" label="数据权限">
|
||||||
|
<el-tree :data="permissionDeptTree" show-checkbox node-key="id" :default-checked-keys="form.dataScopeDeptIds || []" :props="{ label: 'title', children: 'children' }" @check="handleDataScopeCheck" />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="客商权限">
|
||||||
|
<div class="permission-toolbar customer-toolbar"><el-checkbox v-model="form.includeNewCustomer" :true-value="1" :false-value="0">包含新增的客商</el-checkbox></div>
|
||||||
|
<el-table ref="customerTable" :data="customerList" border @selection-change="handleCustomerSelection"><el-table-column type="selection" width="55" /><el-table-column prop="customerCode" label="客商编码" /><el-table-column prop="fullName" label="客商名称" /></el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<template #footer><span class="dialog-footer"><el-button type="primary" @click="submitUserForm">保存</el-button><el-button @click="userDialog = false">返回</el-button><el-button v-if="userDialogMode === 'edit'" @click="resetDialogPassword">重置密码</el-button><el-button @click="handleAddRole">添加角色</el-button></span></template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 用户角色配置 -->
|
<!-- 用户角色配置 -->
|
||||||
<el-dialog title="用户角色配置" append-to-body v-model="roleBox" width="345px">
|
<el-dialog title="用户角色配置" append-to-body v-model="roleBox" width="345px">
|
||||||
<el-row
|
<el-row
|
||||||
@@ -200,8 +236,13 @@
|
|||||||
size="small"
|
size="small"
|
||||||
@change="handleLinkedChange('treeRole')"
|
@change="handleLinkedChange('treeRole')"
|
||||||
/>
|
/>
|
||||||
<el-tooltip content="开启后勾选父节点会自动勾选所有子节点,关闭则可独立勾选任意节点" placement="top">
|
<el-tooltip
|
||||||
<el-icon style="margin-left: 4px; color: #909399; cursor: pointer"><el-icon-question-filled /></el-icon>
|
content="开启后勾选父节点会自动勾选所有子节点,关闭则可独立勾选任意节点"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-icon style="margin-left: 4px; color: #909399; cursor: pointer"
|
||||||
|
><el-icon-question-filled
|
||||||
|
/></el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<el-button-group>
|
<el-button-group>
|
||||||
@@ -246,17 +287,6 @@
|
|||||||
</avue-form>
|
</avue-form>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 用户平台配置(行级别) -->
|
|
||||||
<el-dialog title="用户平台配置" append-to-body v-model="platformBox" width="600px">
|
|
||||||
<avue-form ref="platformFormRef" :option="platformFormOption" v-model="platformForm" />
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="platformBox = false">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="submitPlatformConfig">确 定</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<!-- 管理员修改密码 -->
|
<!-- 管理员修改密码 -->
|
||||||
<el-dialog title="修改密码" append-to-body v-model="passwordBox" width="460px">
|
<el-dialog title="修改密码" append-to-body v-model="passwordBox" width="460px">
|
||||||
<el-form
|
<el-form
|
||||||
@@ -265,7 +295,7 @@
|
|||||||
:rules="passwordRules"
|
:rules="passwordRules"
|
||||||
label-width="auto"
|
label-width="auto"
|
||||||
>
|
>
|
||||||
<el-form-item label="登录账号">
|
<el-form-item label="账号名">
|
||||||
<el-input v-model="passwordForm.account" disabled />
|
<el-input v-model="passwordForm.account" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="新密码" prop="password">
|
<el-form-item label="新密码" prop="password">
|
||||||
@@ -296,10 +326,8 @@
|
|||||||
import {
|
import {
|
||||||
getList,
|
getList,
|
||||||
getUser,
|
getUser,
|
||||||
getUserPlatform,
|
|
||||||
remove,
|
remove,
|
||||||
update,
|
update,
|
||||||
updatePlatform,
|
|
||||||
add,
|
add,
|
||||||
grant,
|
grant,
|
||||||
resetPassword,
|
resetPassword,
|
||||||
@@ -308,6 +336,7 @@ import {
|
|||||||
auditRefuse,
|
auditRefuse,
|
||||||
setLeader,
|
setLeader,
|
||||||
getLeaderList,
|
getLeaderList,
|
||||||
|
getCustomerOptions,
|
||||||
} from '@/api/system/user';
|
} from '@/api/system/user';
|
||||||
import { exportBlob } from '@/api/common';
|
import { exportBlob } from '@/api/common';
|
||||||
import { getDeptTree } from '@/api/system/dept';
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
@@ -315,14 +344,13 @@ import { getRoleTree } from '@/api/system/role';
|
|||||||
import { getPostList } from '@/api/system/post';
|
import { getPostList } from '@/api/system/post';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { h } from 'vue';
|
import { h } from 'vue';
|
||||||
import website from '@/config/website';
|
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
import { downloadXls } from '@/utils/util';
|
import { downloadXls } from '@/utils/util';
|
||||||
import NProgress from 'nprogress';
|
import NProgress from 'nprogress';
|
||||||
import 'nprogress/nprogress.css';
|
import 'nprogress/nprogress.css';
|
||||||
import func from '@/utils/func';
|
import func from '@/utils/func';
|
||||||
import { sensitive } from '@/utils/sensitive';
|
import { sensitive } from '@/utils/sensitive';
|
||||||
import { excelOption, platformFormOption, treeOption, userOption } from '@/option/system/user';
|
import { excelOption, treeOption, userOption } from '@/option/system/user';
|
||||||
import AuthLog from './authlog.vue';
|
import AuthLog from './authlog.vue';
|
||||||
import AuthLock from './authlock.vue';
|
import AuthLock from './authlock.vue';
|
||||||
|
|
||||||
@@ -331,13 +359,15 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {},
|
form: {},
|
||||||
|
userDialog: false,
|
||||||
|
userDialogMode: 'add',
|
||||||
search: {},
|
search: {},
|
||||||
sensitiveManager: null,
|
sensitiveManager: null,
|
||||||
roleBox: false,
|
roleBox: false,
|
||||||
roleLinked: false,
|
roleLinked: false,
|
||||||
|
roleFormMode: false,
|
||||||
grantUserId: '',
|
grantUserId: '',
|
||||||
excelBox: false,
|
excelBox: false,
|
||||||
platformBox: false,
|
|
||||||
passwordBox: false,
|
passwordBox: false,
|
||||||
initFlag: true,
|
initFlag: true,
|
||||||
auditMode: false,
|
auditMode: false,
|
||||||
@@ -357,11 +387,12 @@ export default {
|
|||||||
roleTreeObj: [],
|
roleTreeObj: [],
|
||||||
treeDeptId: '',
|
treeDeptId: '',
|
||||||
treeData: [],
|
treeData: [],
|
||||||
|
permissionDeptTree: [],
|
||||||
|
postList: [],
|
||||||
|
customerList: [],
|
||||||
treeOption: treeOption,
|
treeOption: treeOption,
|
||||||
userOption: userOption(this),
|
userOption: userOption(this),
|
||||||
platformFormOption: platformFormOption,
|
|
||||||
data: [],
|
data: [],
|
||||||
platformForm: {},
|
|
||||||
passwordForm: {},
|
passwordForm: {},
|
||||||
passwordRules: {
|
passwordRules: {
|
||||||
password: [
|
password: [
|
||||||
@@ -373,16 +404,17 @@ export default {
|
|||||||
{ validator: this.validatePassword2, trigger: 'blur' },
|
{ validator: this.validatePassword2, trigger: 'blur' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
userRules: {
|
||||||
|
account: [{ required: true, message: '请输入账号名', trigger: 'blur' }],
|
||||||
|
realName: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
||||||
|
phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
|
||||||
|
deptId: [{ required: true, message: '请选择所属组织', trigger: 'change' }],
|
||||||
|
},
|
||||||
excelForm: {},
|
excelForm: {},
|
||||||
excelOption: excelOption,
|
excelOption: excelOption,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'form.tenantId'() {
|
|
||||||
if (this.form.tenantId !== '' && this.initFlag) {
|
|
||||||
this.initData(this.form.tenantId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'excelForm.isCovered'() {
|
'excelForm.isCovered'() {
|
||||||
if (this.excelForm.isCovered !== '') {
|
if (this.excelForm.isCovered !== '') {
|
||||||
const column = this.findColumn(this.excelOption.column, 'excelFile');
|
const column = this.findColumn(this.excelOption.column, 'excelFile');
|
||||||
@@ -407,14 +439,20 @@ export default {
|
|||||||
});
|
});
|
||||||
return ids.join(',');
|
return ids.join(',');
|
||||||
},
|
},
|
||||||
|
formRoleList() {
|
||||||
|
const selected = new Set(func.split(this.form.roleId || '').map(String));
|
||||||
|
const roles = [];
|
||||||
|
const walk = nodes =>
|
||||||
|
(nodes || []).forEach(node => {
|
||||||
|
if (selected.has(String(node.id))) roles.push(node);
|
||||||
|
walk(node.children);
|
||||||
|
});
|
||||||
|
walk(this.roleGrantList);
|
||||||
|
return roles;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
// 非租户模式默认加载管理组数据
|
this.initData(this.userInfo.tenantId || this.website.tenantId);
|
||||||
if (!website.tenantMode) {
|
|
||||||
this.initData(website.tenantId);
|
|
||||||
} else {
|
|
||||||
this.initData();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
// 创建脱敏工具实例
|
// 创建脱敏工具实例
|
||||||
@@ -437,8 +475,6 @@ export default {
|
|||||||
this.$refs.authLog.openUserAuthLog(row.id, row.name);
|
this.$refs.authLog.openUserAuthLog(row.id, row.name);
|
||||||
} else if (command === 'lockUser') {
|
} else if (command === 'lockUser') {
|
||||||
this.$refs.authLock.openLockUser(row.id, row.account);
|
this.$refs.authLock.openLockUser(row.id, row.account);
|
||||||
} else if (command === 'platformConfig') {
|
|
||||||
this.handlePlatformForRow(row);
|
|
||||||
} else if (command === 'resetPassword') {
|
} else if (command === 'resetPassword') {
|
||||||
this.handleResetForRow(row);
|
this.handleResetForRow(row);
|
||||||
} else if (command === 'setPassword') {
|
} else if (command === 'setPassword') {
|
||||||
@@ -488,14 +524,17 @@ export default {
|
|||||||
},
|
},
|
||||||
initData(tenantId) {
|
initData(tenantId) {
|
||||||
getRoleTree(tenantId).then(res => {
|
getRoleTree(tenantId).then(res => {
|
||||||
|
this.roleGrantList = res.data.data;
|
||||||
const column = this.findColumn(this.userOption.group, 'roleId');
|
const column = this.findColumn(this.userOption.group, 'roleId');
|
||||||
column.dicData = res.data.data;
|
column.dicData = res.data.data;
|
||||||
});
|
});
|
||||||
getDeptTree(tenantId).then(res => {
|
getDeptTree(tenantId).then(res => {
|
||||||
|
this.permissionDeptTree = res.data.data;
|
||||||
const column = this.findColumn(this.userOption.group, 'deptId');
|
const column = this.findColumn(this.userOption.group, 'deptId');
|
||||||
column.dicData = res.data.data;
|
column.dicData = res.data.data;
|
||||||
});
|
});
|
||||||
getPostList(tenantId).then(res => {
|
getPostList(tenantId).then(res => {
|
||||||
|
this.postList = res.data.data;
|
||||||
const column = this.findColumn(this.userOption.group, 'postId');
|
const column = this.findColumn(this.userOption.group, 'postId');
|
||||||
column.dicData = res.data.data;
|
column.dicData = res.data.data;
|
||||||
});
|
});
|
||||||
@@ -503,9 +542,18 @@ export default {
|
|||||||
const column = this.findColumn(this.userOption.group, 'leaderId');
|
const column = this.findColumn(this.userOption.group, 'leaderId');
|
||||||
column.dicData = res.data.data;
|
column.dicData = res.data.data;
|
||||||
});
|
});
|
||||||
|
getCustomerOptions().then(res => {
|
||||||
|
this.customerList = res.data.data || [];
|
||||||
|
});
|
||||||
},
|
},
|
||||||
submitRole() {
|
submitRole() {
|
||||||
const roleList = this.$refs.treeRole.getCheckedKeys().join(',');
|
const roleList = this.$refs.treeRole.getCheckedKeys().join(',');
|
||||||
|
if (this.roleFormMode) {
|
||||||
|
this.form.roleId = roleList;
|
||||||
|
this.roleBox = false;
|
||||||
|
this.roleFormMode = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
grant(this.grantUserId, roleList).then(() => {
|
grant(this.grantUserId, roleList).then(() => {
|
||||||
this.roleBox = false;
|
this.roleBox = false;
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -515,6 +563,98 @@ export default {
|
|||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleAddRole() {
|
||||||
|
this.roleFormMode = true;
|
||||||
|
this.roleTreeObj = func.split(this.form.roleId || '');
|
||||||
|
this.roleLinked = false;
|
||||||
|
getRoleTree(this.userInfo.tenantId).then(res => {
|
||||||
|
this.roleGrantList = res.data.data;
|
||||||
|
this.roleBox = true;
|
||||||
|
this.$nextTick(() => this.applyCheckedKeys('treeRole', this.roleTreeObj));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeFormRole(roleId) {
|
||||||
|
this.form.roleId = func
|
||||||
|
.split(this.form.roleId || '')
|
||||||
|
.filter(id => String(id) !== String(roleId));
|
||||||
|
},
|
||||||
|
handleDataScopeCheck(_, checked) {
|
||||||
|
this.form.dataScopeDeptIds = checked.checkedKeys;
|
||||||
|
},
|
||||||
|
handleCustomerSelection(rows) {
|
||||||
|
this.form.customerIds = rows.map(row => row.id);
|
||||||
|
},
|
||||||
|
openUserDialog(mode, row = {}) {
|
||||||
|
this.userDialogMode = mode;
|
||||||
|
if (mode === 'add') {
|
||||||
|
this.form = {
|
||||||
|
account: '',
|
||||||
|
realName: '',
|
||||||
|
phone: '',
|
||||||
|
email: '',
|
||||||
|
sex: 3,
|
||||||
|
postId: '',
|
||||||
|
deptId: [],
|
||||||
|
code: '',
|
||||||
|
personCategory: 1,
|
||||||
|
dataScopeRange: 1,
|
||||||
|
dataLevelRange: 1,
|
||||||
|
remark: '',
|
||||||
|
roleId: '',
|
||||||
|
dataScopeDeptIds: [],
|
||||||
|
customerIds: [],
|
||||||
|
includeNewCustomer: 0,
|
||||||
|
};
|
||||||
|
this.userDialog = true;
|
||||||
|
this.$nextTick(() => this.$refs.userFormRef && this.$refs.userFormRef.clearValidate());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getUser(row.id).then(res => {
|
||||||
|
const user = res.data.data;
|
||||||
|
this.form = {
|
||||||
|
...user,
|
||||||
|
deptId: func.split(user.deptId || ''),
|
||||||
|
postId: func.split(user.postId || '')[0] || '',
|
||||||
|
roleId: func.join(user.roleId || ''),
|
||||||
|
dataScopeDeptIds: user.dataScopeDeptIds || [],
|
||||||
|
customerIds: user.customerIds || [],
|
||||||
|
includeNewCustomer: user.includeNewCustomer || 0,
|
||||||
|
personCategory: user.personCategory || 1,
|
||||||
|
dataScopeRange: user.dataScopeRange || 1,
|
||||||
|
dataLevelRange: user.dataLevelRange || 1,
|
||||||
|
};
|
||||||
|
this.sensitiveManager.saveInitialData(this.form);
|
||||||
|
this.userDialog = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.userFormRef && this.$refs.userFormRef.clearValidate();
|
||||||
|
(this.form.customerIds || []).forEach(id => {
|
||||||
|
const customer = this.customerList.find(item => String(item.id) === String(id));
|
||||||
|
if (customer) this.$refs.customerTable && this.$refs.customerTable.toggleRowSelection(customer, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
submitUserForm() {
|
||||||
|
this.$refs.userFormRef.validate(valid => {
|
||||||
|
if (!valid) return;
|
||||||
|
const row = {
|
||||||
|
...this.form,
|
||||||
|
deptId: func.join(this.form.deptId),
|
||||||
|
postId: func.join(this.form.postId),
|
||||||
|
roleId: func.join(this.form.roleId),
|
||||||
|
leaderId: func.join(this.form.leaderId),
|
||||||
|
};
|
||||||
|
const request = this.userDialogMode === 'add' ? add(row) : update(this.sensitiveManager.getSubmitData(row));
|
||||||
|
request.then(() => {
|
||||||
|
this.userDialog = false;
|
||||||
|
this.onLoad(this.page);
|
||||||
|
this.$message.success('操作成功!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resetDialogPassword() {
|
||||||
|
this.handleResetForRow(this.form);
|
||||||
|
},
|
||||||
rowSave(row, done, loading) {
|
rowSave(row, done, loading) {
|
||||||
row.deptId = func.join(row.deptId);
|
row.deptId = func.join(row.deptId);
|
||||||
row.roleId = func.join(row.roleId);
|
row.roleId = func.join(row.roleId);
|
||||||
@@ -779,23 +919,6 @@ export default {
|
|||||||
if (!tree) return;
|
if (!tree) return;
|
||||||
tree.setCheckedKeys(keys);
|
tree.setCheckedKeys(keys);
|
||||||
},
|
},
|
||||||
// ========== 平台配置(行级别) ==========
|
|
||||||
handlePlatformForRow(row) {
|
|
||||||
getUserPlatform(row.id).then(res => {
|
|
||||||
this.platformForm = { ...res.data.data, account: row.account };
|
|
||||||
this.platformBox = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
submitPlatformConfig() {
|
|
||||||
updatePlatform(
|
|
||||||
this.platformForm.id,
|
|
||||||
this.platformForm.userType,
|
|
||||||
this.platformForm.userExt
|
|
||||||
).then(() => {
|
|
||||||
this.platformBox = false;
|
|
||||||
this.$message({ type: 'success', message: '操作成功!' });
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handlePasswordForRow(row) {
|
handlePasswordForRow(row) {
|
||||||
this.passwordForm = {
|
this.passwordForm = {
|
||||||
userId: row.id,
|
userId: row.id,
|
||||||
@@ -902,12 +1025,11 @@ export default {
|
|||||||
},
|
},
|
||||||
onLoad(page, params = {}) {
|
onLoad(page, params = {}) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
getList(
|
const queryParams = { ...this.query, ...params };
|
||||||
page.currentPage,
|
if (this.auditMode) {
|
||||||
page.pageSize,
|
queryParams.status = 0;
|
||||||
Object.assign(params, this.query, { status: this.auditMode ? 0 : 1 }),
|
}
|
||||||
this.treeDeptId
|
getList(page.currentPage, page.pageSize, queryParams, this.treeDeptId).then(res => {
|
||||||
).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;
|
||||||
@@ -931,4 +1053,62 @@ export default {
|
|||||||
.box .el-scrollbar__wrap {
|
.box .el-scrollbar__wrap {
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-permission-tabs {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-edit-dialog .dialog-title {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-edit-dialog .dialog-title::before {
|
||||||
|
width: 4px;
|
||||||
|
height: 18px;
|
||||||
|
margin-right: 8px;
|
||||||
|
background: #409eff;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-edit-dialog .el-form-item {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-edit-dialog .el-form-item__label {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-edit-dialog .el-radio-group {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-permission-tabs .el-tabs__header {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.permission-toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-toolbar {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avue-dialog .el-form-item__label {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avue-dialog .el-radio-group {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
90
src/views/transportCapacity/components/ship-ledger.vue
Normal file
90
src/views/transportCapacity/components/ship-ledger.vue
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :model-value="modelValue" title="船舶综合台账" width="96%" top="3vh" append-to-body destroy-on-close @update:model-value="$emit('update:modelValue', $event)">
|
||||||
|
<div v-loading="detailLoading" class="ship-ledger">
|
||||||
|
<section v-for="section in sections" :key="section.title" class="ship-ledger__section">
|
||||||
|
<div class="dialog-section-title">{{ section.title }}</div>
|
||||||
|
<el-descriptions :column="3" border>
|
||||||
|
<el-descriptions-item v-for="item in section.items" :key="item.label" :label="item.label">
|
||||||
|
{{ display(item) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</section>
|
||||||
|
<section class="ship-ledger__section">
|
||||||
|
<div class="dialog-section-title">证书附件</div>
|
||||||
|
<div class="ship-ledger__images">
|
||||||
|
<div v-for="item in imageFields" :key="item.prop" class="ship-ledger__image-item">
|
||||||
|
<span>{{ item.label }}</span>
|
||||||
|
<el-image v-if="shipDetail[item.prop]" :src="shipDetail[item.prop]" :preview-src-list="imageUrls" preview-teleported fit="cover" />
|
||||||
|
<el-empty v-else :image-size="36" description="暂无附件" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<el-tabs v-model="activeTab" @tab-change="loadRecords">
|
||||||
|
<el-tab-pane v-for="tab in tabs" :key="tab.name" :label="tab.label" :name="tab.name" />
|
||||||
|
</el-tabs>
|
||||||
|
<el-table v-loading="tableLoading" :data="records" border stripe>
|
||||||
|
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||||
|
<el-table-column v-for="column in activeColumns" :key="column.prop" :prop="column.prop" :label="column.label" :min-width="column.width || 140" show-overflow-tooltip />
|
||||||
|
</el-table>
|
||||||
|
<div class="ship-ledger__pagination"><el-pagination v-model:current-page="page.current" v-model:page-size="page.size" :page-sizes="[10, 20, 50]" :total="page.total" layout="total, sizes, prev, pager, next" @size-change="handlePageChange" @current-change="loadRecords" /></div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getDetail } from '@/api/transportCapacity/transport-ship';
|
||||||
|
import { getList as insurance } from '@/api/vehicle/insurance-record';
|
||||||
|
import { getList as violation } from '@/api/vehicle/violation-record';
|
||||||
|
import { getList as maintenance } from '@/api/vehicle/maintenance-record';
|
||||||
|
import { getList as maintenancePlan } from '@/api/vehicle/maintenance-plan';
|
||||||
|
import { getList as accident } from '@/api/vehicle/accident-record';
|
||||||
|
import { getList as annualInspection } from '@/api/vehicle/annual-inspection-record';
|
||||||
|
import { getList as change } from '@/api/vehicle/transport-change-record';
|
||||||
|
import { getList as oilElectric } from '@/api/vehicle/oil-electric-record';
|
||||||
|
import { getList as otherExpense } from '@/api/vehicle/other-expense-record';
|
||||||
|
|
||||||
|
const columns = (...items) => items.map(([label, prop]) => ({ label, prop }));
|
||||||
|
const tabConfigs = [
|
||||||
|
['insurance', '保险记录', insurance, columns(['船号', 'vehicleNo'], ['保险类型', 'insuranceType'], ['开始日期', 'startDate'], ['结束日期', 'endDate'], ['保费', 'premium'], ['保单号', 'policyNo'])],
|
||||||
|
['violation', '违章记录', violation, columns(['船号', 'vehicleNo'], ['驾驶人/船长', 'driverName'], ['类型', 'violationType'], ['事项', 'violationItem'], ['违章时间', 'violationTime'], ['罚款金额', 'fineAmount'])],
|
||||||
|
['maintenance', '维修记录', maintenance, columns(['船号', 'vehicleNo'], ['维修人', 'maintainer'], ['维修时间', 'maintenanceTime'], ['维修位置', 'location'], ['费用', 'cost'])],
|
||||||
|
['maintenancePlan', '保养记录', maintenancePlan, columns(['船号', 'vehicleNo'], ['保养人', 'maintainer'], ['保养时间', 'maintenanceTime'], ['保养项目', 'maintenanceItem'], ['费用', 'cost'])],
|
||||||
|
['accident', '事故记录', accident, columns(['船号', 'vehicleNo'], ['事故时间', 'accidentTime'], ['事故地点', 'accidentLocation'], ['事故类型', 'accidentType'], ['损失金额', 'lossAmount'])],
|
||||||
|
['annualInspection', '年检记录', annualInspection, columns(['船号', 'vehicleNo'], ['年检日期', 'inspectionDate'], ['年检有效期至', 'inspectionEndDate'], ['年检机构', 'inspectionOrganization'], ['费用', 'cost'])],
|
||||||
|
['change', '变更记录', change, columns(['船号', 'vehicleNo'], ['变更类型', 'changeType'], ['变更时间', 'changeTime'], ['变更前内容', 'beforeChange'], ['变更后内容', 'afterChange'])],
|
||||||
|
['equipment', '设备台账', null, columns(['设备编码', 'equipmentCode'], ['设备名称', 'equipmentName'], ['设备类型', 'equipmentType'], ['安装日期', 'installDate'], ['状态', 'status'])],
|
||||||
|
['oilElectric', '油电台账', oilElectric, columns(['船号', 'vehicleNo'], ['加油/充电日期', 'recordDate'], ['类型', 'energyType'], ['数量', 'quantity'], ['金额', 'amount'])],
|
||||||
|
['otherExpense', '其他费用记录', otherExpense, columns(['船号', 'vehicleNo'], ['费用日期', 'expenseDate'], ['费用类型', 'expenseType'], ['金额', 'amount'], ['备注', 'remark'])],
|
||||||
|
].map(([name, label, request, cols]) => ({ name, label, request, columns: cols }));
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: { modelValue: Boolean, ship: { type: Object, default: () => ({}) } }, emits: ['update:modelValue'],
|
||||||
|
data() { return { detailLoading: false, tableLoading: false, shipDetail: {}, activeTab: 'insurance', records: [], page: { current: 1, size: 10, total: 0 } }; },
|
||||||
|
computed: {
|
||||||
|
tabs() { return tabConfigs; }, activeConfig() { return tabConfigs.find(item => item.name === this.activeTab) || tabConfigs[0]; }, activeColumns() { return this.activeConfig.columns; },
|
||||||
|
imageFields() { return [['船舶所有权证书', 'ownershipCertImage'], ['内河船舶安全与环保证书', 'safetyCertImage'], ['船舶国籍证书', 'nationalityCertImage'], ['最低安全配员证书', 'safeManningCertImage'], ['船舶营业运输证', 'businessTransportCertImage'], ['光船租赁登记证书', 'leaseContractImage']].map(([label, prop]) => ({ label, prop })); },
|
||||||
|
imageUrls() { return this.imageFields.map(item => this.shipDetail[item.prop]).filter(Boolean); },
|
||||||
|
sections() { const s = this.shipDetail; return [
|
||||||
|
{ title: '船舶基本信息', items: [['船舶所属组织', 'organizationName'], ['船名', 'shipName'], ['安放龙骨日期/建造完工日期', 'constructionDate'], ['总长(m)', 'totalLength'], ['船宽(m)', 'shipWidth'], ['型深(m)', 'moldedDepth'], ['最大船高(m)', 'maxShipHeight'], ['空载吃水(t)', 'lightDraft'], ['满载吃水(t)', 'fullLoadDraft'], ['航区', 'navigationArea']] },
|
||||||
|
{ title: '船舶证书信息', items: [['登记号码', 'ownershipRegistrationNo'], ['初次登记号码', 'initialRegistrationNo'], ['船舶所有人', 'shipOwner'], ['取得所有权日期', 'ownershipAcquisitionDate'], ['船舶识别号', 'shipIdentifierNo'], ['总吨', 'grossTonnage'], ['净吨', 'netTonnage'], ['船检登记号', 'shipInspectionNo'], ['船舶类型', 'shipType'], ['国籍证书有效期', 'nationalityCertDate'], ['最低安全配员证书有效期', 'safeManningCertDate'], ['起租日期', 'leaseStartDate'], ['终止日期', 'leaseEndDate'], ['船舶承租人', 'shipLessee'], ['营业运输证证书编号', 'businessTransportCertNo'], ['营业运输证发证日期', 'businessTransportCertIssueDate'], ['营业运输证有效期至', 'businessTransportCertEndDate'], ['船舶经营人', 'shipOperator']] },
|
||||||
|
].map(section => ({ ...section, items: section.items.map(([label, prop]) => ({ label, prop, value: prop === 'constructionDate' ? `${s.keelLayingDate || '-'} / ${s.buildCompletionDate || '-'}` : prop === 'nationalityCertDate' ? `${s.nationalityCertStartDate || '-'} 至 ${s.nationalityCertEndDate || '-'}` : prop === 'safeManningCertDate' ? `${s.safeManningCertStartDate || '-'} 至 ${s.safeManningCertEndDate || '-'}` : s[prop] })) })); },
|
||||||
|
},
|
||||||
|
watch: { modelValue(value) { if (value) this.initialize(); } },
|
||||||
|
methods: {
|
||||||
|
display(item) { return item.value === null || item.value === undefined || item.value === '' ? '-' : item.value; },
|
||||||
|
async initialize() { this.activeTab = 'insurance'; this.page.current = 1; this.shipDetail = { ...this.ship }; if (this.ship.id) { this.detailLoading = true; try { const res = await getDetail(this.ship.id); this.shipDetail = { ...this.ship, ...(res.data.data || {}) }; } finally { this.detailLoading = false; } } this.loadRecords(); },
|
||||||
|
async loadRecords() { const { request } = this.activeConfig; if (!request) { this.records = []; this.page.total = 0; return; } this.tableLoading = true; try { const res = await request(this.page.current, this.page.size, { vehicleNo: this.shipDetail.shipName || this.ship.shipName, vehicleType: '船舶' }); const data = res.data.data || {}; this.records = data.records || []; this.page.total = data.total || 0; } finally { this.tableLoading = false; } },
|
||||||
|
handlePageChange() { this.page.current = 1; this.loadRecords(); },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.ship-ledger__section { margin-bottom: 16px; }
|
||||||
|
.ship-ledger__images { display: flex; gap: 16px; overflow-x: auto; padding: 12px 0; }
|
||||||
|
.ship-ledger__image-item { width: 150px; flex: 0 0 150px; text-align: center; color: #606266; }
|
||||||
|
.ship-ledger__image-item > span { display: block; margin-bottom: 8px; }
|
||||||
|
.ship-ledger__image-item :deep(.el-image) { width: 150px; height: 110px; border: 1px solid #eff1f7; }
|
||||||
|
.ship-ledger__image-item :deep(.el-empty) { height: 110px; border: 1px solid #eff1f7; }
|
||||||
|
.ship-ledger__pagination { display: flex; justify-content: flex-end; margin-top: 16px; }
|
||||||
|
</style>
|
||||||
141
src/views/transportCapacity/components/vehicle-ledger.vue
Normal file
141
src/views/transportCapacity/components/vehicle-ledger.vue
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
:model-value="modelValue"
|
||||||
|
title="车辆综合台账"
|
||||||
|
width="96%"
|
||||||
|
top="3vh"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
@update:model-value="$emit('update:modelValue', $event)"
|
||||||
|
>
|
||||||
|
<div v-loading="detailLoading" class="vehicle-ledger">
|
||||||
|
<section class="vehicle-ledger__overview">
|
||||||
|
<div class="vehicle-ledger__title">
|
||||||
|
<span>{{ vehicleDetail.plateNo || vehicle.plateNo }}</span>
|
||||||
|
<el-tag :type="plateColorType">{{ vehicleDetail.plateColor || '-' }}</el-tag>
|
||||||
|
<el-tag type="primary">{{ vehicleDetail.businessRelation || '-' }}</el-tag>
|
||||||
|
</div>
|
||||||
|
<el-descriptions :column="4" border>
|
||||||
|
<el-descriptions-item label="所属组织">{{ vehicleDetail.organizationName || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="车辆类型">{{ vehicleDetail.vehicleType || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="能源类型">{{ vehicleDetail.energyType || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="外廓尺寸(mm)">{{ dimensions }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="核定载质量(KG)">{{ vehicleDetail.approvedLoadKg ?? '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="准牵引总质量(KG)">{{ vehicleDetail.tractionMassKg ?? '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="行驶证档案编号">{{ vehicleDetail.drivingLicenseNo || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="道路运输证号">{{ vehicleDetail.roadTransportCertNo || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="行驶证有效期">{{ vehicleDetail.drivingLicenseEndDate || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="道路运输证有效期">{{ vehicleDetail.roadTransportCertEndDate || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="道路运输证年审有效期">{{ vehicleDetail.annualReviewEndDate || '-' }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<div class="vehicle-ledger__images">
|
||||||
|
<div v-for="item in imageFields" :key="item.prop" class="vehicle-ledger__image-item">
|
||||||
|
<span>{{ item.label }}</span>
|
||||||
|
<el-image
|
||||||
|
v-if="vehicleDetail[item.prop]"
|
||||||
|
:src="vehicleDetail[item.prop]"
|
||||||
|
:preview-src-list="imageUrls"
|
||||||
|
preview-teleported
|
||||||
|
fit="cover"
|
||||||
|
/>
|
||||||
|
<el-empty v-else :image-size="36" description="暂无图片" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<el-tabs v-model="activeTab" class="vehicle-ledger__tabs" @tab-change="loadRecords">
|
||||||
|
<el-tab-pane v-for="tab in tabs" :key="tab.name" :label="tab.label" :name="tab.name" />
|
||||||
|
</el-tabs>
|
||||||
|
<el-table v-loading="tableLoading" :data="records" border stripe>
|
||||||
|
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||||
|
<el-table-column
|
||||||
|
v-for="column in activeColumns"
|
||||||
|
:key="column.prop"
|
||||||
|
:prop="column.prop"
|
||||||
|
:label="column.label"
|
||||||
|
:min-width="column.width || 140"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
<div class="vehicle-ledger__pagination">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="page.current"
|
||||||
|
v-model:page-size="page.size"
|
||||||
|
:page-sizes="[10, 20, 50]"
|
||||||
|
:total="page.total"
|
||||||
|
layout="total, sizes, prev, pager, next"
|
||||||
|
@size-change="handlePageChange"
|
||||||
|
@current-change="loadRecords"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getDetail } from '@/api/transportCapacity/transport-vehicle';
|
||||||
|
import { getList as getInsuranceList } from '@/api/vehicle/insurance-record';
|
||||||
|
import { getList as getViolationList } from '@/api/vehicle/violation-record';
|
||||||
|
import { getList as getMaintenanceList } from '@/api/vehicle/maintenance-record';
|
||||||
|
import { getList as getMaintenancePlanList } from '@/api/vehicle/maintenance-plan';
|
||||||
|
import { getList as getTireList } from '@/api/vehicle/tire-replacement-record';
|
||||||
|
import { getList as getAccidentList } from '@/api/vehicle/accident-record';
|
||||||
|
import { getList as getAnnualInspectionList } from '@/api/vehicle/annual-inspection-record';
|
||||||
|
import { getList as getMileageList } from '@/api/vehicle/mileage-record';
|
||||||
|
import { getList as getChangeList } from '@/api/vehicle/transport-change-record';
|
||||||
|
import { getList as getOilElectricList } from '@/api/vehicle/oil-electric-record';
|
||||||
|
import { getList as getEtcList } from '@/api/vehicle/etc-record';
|
||||||
|
import { getList as getOtherExpenseList } from '@/api/vehicle/other-expense-record';
|
||||||
|
|
||||||
|
const cols = (...items) => items.map(([label, prop, width]) => ({ label, prop, width }));
|
||||||
|
const tabConfigs = [
|
||||||
|
['insurance', '保险记录', getInsuranceList, cols(['车牌号', 'vehicleNo'], ['保险类型', 'insuranceType'], ['开始日期', 'startDate'], ['结束日期', 'endDate'], ['保费', 'premium'], ['保单号', 'policyNo'])],
|
||||||
|
['violation', '违章记录', getViolationList, cols(['车牌号', 'vehicleNo'], ['驾驶人', 'driverName'], ['类型', 'violationType'], ['事项', 'violationItem'], ['违章时间', 'violationTime'], ['罚款金额', 'fineAmount'])],
|
||||||
|
['maintenance', '维修记录', getMaintenanceList, cols(['车牌号', 'vehicleNo'], ['维修人', 'maintainer'], ['维修时间', 'maintenanceTime'], ['维修位置', 'location'], ['费用', 'cost'], ['维修单位', 'company'])],
|
||||||
|
['maintenancePlan', '保养记录', getMaintenancePlanList, cols(['车牌号', 'vehicleNo'], ['保养人', 'maintainer'], ['保养时间', 'maintenanceTime'], ['保养项目', 'maintenanceItem'], ['费用', 'cost'], ['下次保养时间', 'nextMaintenanceTime'])],
|
||||||
|
['tire', '换胎记录', getTireList, cols(['车牌号', 'vehicleNo'], ['更换时间', 'replacementTime'], ['轮胎品牌', 'tireBrand'], ['轮胎规格', 'tireSpec'], ['费用', 'cost'])],
|
||||||
|
['accident', '事故记录', getAccidentList, cols(['车牌号', 'vehicleNo'], ['事故时间', 'accidentTime'], ['事故地点', 'accidentLocation'], ['事故类型', 'accidentType'], ['损失金额', 'lossAmount'])],
|
||||||
|
['annualInspection', '年检记录', getAnnualInspectionList, cols(['车牌号', 'vehicleNo'], ['年检日期', 'inspectionDate'], ['年检有效期至', 'inspectionEndDate'], ['年检机构', 'inspectionOrganization'], ['费用', 'cost'])],
|
||||||
|
['mileage', '里程记录', getMileageList, cols(['车牌号', 'vehicleNo'], ['记录时间', 'recordTime'], ['里程数', 'mileage'], ['里程单位', 'mileageUnit'], ['备注', 'remark'])],
|
||||||
|
['change', '变更记录', getChangeList, cols(['车牌号', 'vehicleNo'], ['变更类型', 'changeType'], ['变更时间', 'changeTime'], ['变更前内容', 'beforeChange'], ['变更后内容', 'afterChange'])],
|
||||||
|
['equipment', '设备台账', null, cols(['设备编码', 'equipmentCode'], ['设备名称', 'equipmentName'], ['设备类型', 'equipmentType'], ['安装日期', 'installDate'], ['状态', 'status'])],
|
||||||
|
['oilElectric', '油电台账', getOilElectricList, cols(['车牌号', 'vehicleNo'], ['加油/充电日期', 'recordDate'], ['类型', 'energyType'], ['数量', 'quantity'], ['金额', 'amount'])],
|
||||||
|
['etc', 'ETC记录', getEtcList, cols(['车牌号', 'vehicleNo'], ['交易日期', 'transactionDate'], ['交易金额', 'amount'], ['交易地点', 'location'], ['ETC卡号', 'etcCardNo'])],
|
||||||
|
['otherExpense', '其他费用记录', getOtherExpenseList, cols(['车牌号', 'vehicleNo'], ['费用日期', 'expenseDate'], ['费用类型', 'expenseType'], ['金额', 'amount'], ['备注', 'remark'])],
|
||||||
|
].map(([name, label, request, columns]) => ({ name, label, request, columns }));
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: { modelValue: Boolean, vehicle: { type: Object, default: () => ({}) } },
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
data() {
|
||||||
|
return { detailLoading: false, tableLoading: false, vehicleDetail: {}, activeTab: 'insurance', records: [], page: { current: 1, size: 10, total: 0 } };
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tabs() { return tabConfigs; },
|
||||||
|
activeConfig() { return tabConfigs.find(item => item.name === this.activeTab) || tabConfigs[0]; },
|
||||||
|
activeColumns() { return this.activeConfig.columns; },
|
||||||
|
dimensions() { const v = this.vehicleDetail; return [v.outerLength, v.outerWidth, v.outerHeight].filter(item => item !== null && item !== undefined && item !== '').join('×') || '-'; },
|
||||||
|
plateColorType() { return { 黄牌: 'warning', 蓝牌: 'primary', 绿牌: 'success' }[this.vehicleDetail.plateColor] || 'info'; },
|
||||||
|
imageFields() { return [['行驶证主页面', 'drivingLicenseImage'], ['行驶证主页反页', 'drivingLicenseMainBack'], ['行驶证副页正页', 'drivingLicenseViceFront'], ['行驶证副页反页', 'drivingLicenseViceBack'], ['道路运输证', 'roadTransportCertImage']].map(([label, prop]) => ({ label, prop })); },
|
||||||
|
imageUrls() { return this.imageFields.map(item => this.vehicleDetail[item.prop]).filter(Boolean); },
|
||||||
|
},
|
||||||
|
watch: { modelValue(value) { if (value) this.initialize(); } },
|
||||||
|
methods: {
|
||||||
|
async initialize() { this.activeTab = 'insurance'; this.page.current = 1; this.vehicleDetail = { ...this.vehicle }; if (this.vehicle.id) { this.detailLoading = true; try { const res = await getDetail(this.vehicle.id); this.vehicleDetail = { ...this.vehicle, ...(res.data.data || {}) }; } finally { this.detailLoading = false; } } this.loadRecords(); },
|
||||||
|
async loadRecords() { const { request } = this.activeConfig; if (!request) { this.records = []; this.page.total = 0; return; } this.tableLoading = true; try { const res = await request(this.page.current, this.page.size, { vehicleNo: this.vehicleDetail.plateNo || this.vehicle.plateNo, vehicleType: '车辆' }); const data = res.data.data || {}; this.records = data.records || []; this.page.total = data.total || 0; } finally { this.tableLoading = false; } },
|
||||||
|
handlePageChange() { this.page.current = 1; this.loadRecords(); },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.vehicle-ledger__overview { padding: 16px; border: 1px solid #eff1f7; }
|
||||||
|
.vehicle-ledger__title { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; font-size: 26px; font-weight: 600; }
|
||||||
|
.vehicle-ledger__images { display: flex; gap: 16px; margin-top: 16px; overflow-x: auto; }
|
||||||
|
.vehicle-ledger__image-item { width: 150px; flex: 0 0 150px; color: #606266; text-align: center; }
|
||||||
|
.vehicle-ledger__image-item > span { display: block; margin-bottom: 8px; }
|
||||||
|
.vehicle-ledger__image-item :deep(.el-image) { width: 150px; height: 110px; border: 1px solid #eff1f7; }
|
||||||
|
.vehicle-ledger__image-item :deep(.el-empty) { height: 110px; border: 1px solid #eff1f7; }
|
||||||
|
.vehicle-ledger__tabs { margin-top: 16px; }
|
||||||
|
.vehicle-ledger__pagination { display: flex; justify-content: flex-end; margin-top: 16px; }
|
||||||
|
</style>
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
plain
|
|
||||||
v-if="hasPermission('driver_add')"
|
v-if="hasPermission('driver_add')"
|
||||||
@click="openDriver()"
|
@click="openDriver()"
|
||||||
>新增
|
>新增
|
||||||
@@ -42,23 +41,23 @@
|
|||||||
>批量删除
|
>批量删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template #menu-right>
|
<template #expireStatus-search>
|
||||||
<el-radio-group
|
<div class="driver-page__expiry-tags">
|
||||||
v-model="query.expireStatus"
|
<el-check-tag
|
||||||
class="driver-stat"
|
v-for="item in expiryTagOptions"
|
||||||
@change="handleExpireChange"
|
:key="item.value"
|
||||||
|
:checked="query.expireStatus === item.value"
|
||||||
|
@change="handleExpireChange(item.value)"
|
||||||
>
|
>
|
||||||
<el-radio-button label="">全部({{ expiryStat.total }})</el-radio-button>
|
{{ item.label }}({{ expiryStat[item.statKey] || 0 }})
|
||||||
<el-radio-button label="within30"
|
</el-check-tag>
|
||||||
>30天内到期({{ expiryStat.within30 }})</el-radio-button
|
</div>
|
||||||
>
|
|
||||||
<el-radio-button label="expired">已到期({{ expiryStat.expired }})</el-radio-button>
|
|
||||||
</el-radio-group>
|
|
||||||
</template>
|
</template>
|
||||||
<template #driverName="{ row }">
|
<template #driverName="{ row }">
|
||||||
<el-button type="primary" link @click="openDriver(row, true)">
|
<div class="driver-page__identity">
|
||||||
{{ row.driverName }}
|
<el-link type="primary" @click="openDriver(row, true)">{{ row.driverName }}</el-link>
|
||||||
</el-button>
|
<span>{{ row.idCardNo || '-' }}</span>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #status="{ row }">
|
<template #status="{ row }">
|
||||||
<el-tag :type="row.status === 1 ? 'primary' : 'info'">
|
<el-tag :type="row.status === 1 ? 'primary' : 'info'">
|
||||||
@@ -92,21 +91,13 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row }">
|
<template #menu="{ row }">
|
||||||
<el-link
|
<el-link type="primary" v-if="hasPermission('driver_view')" @click="openDriver(row, true)">
|
||||||
type="primary"
|
|
||||||
v-if="hasPermission('driver_view')"
|
|
||||||
@click="openDriver(row, true)"
|
|
||||||
>
|
|
||||||
查看
|
查看
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-link type="primary" v-if="hasPermission('driver_edit')" @click="openDriver(row)">
|
<el-link type="primary" v-if="hasPermission('driver_edit')" @click="openDriver(row)">
|
||||||
修改
|
修改
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-link
|
<el-link type="primary" v-if="hasPermission('driver_status')" @click="handleStatus(row)">
|
||||||
type="primary"
|
|
||||||
v-if="hasPermission('driver_status')"
|
|
||||||
@click="handleStatus(row)"
|
|
||||||
>
|
|
||||||
{{ row.status === 1 ? '停用' : '启用' }}
|
{{ row.status === 1 ? '停用' : '启用' }}
|
||||||
</el-link>
|
</el-link>
|
||||||
</template>
|
</template>
|
||||||
@@ -116,7 +107,7 @@
|
|||||||
:title="dialogTitle"
|
:title="dialogTitle"
|
||||||
append-to-body
|
append-to-body
|
||||||
v-model="driverBox"
|
v-model="driverBox"
|
||||||
width="92%"
|
width="90%"
|
||||||
top="4vh"
|
top="4vh"
|
||||||
class="driver-dialog"
|
class="driver-dialog"
|
||||||
@closed="resetDriver"
|
@closed="resetDriver"
|
||||||
@@ -129,11 +120,11 @@
|
|||||||
:disabled="readonly"
|
:disabled="readonly"
|
||||||
class="driver-form"
|
class="driver-form"
|
||||||
>
|
>
|
||||||
<div class="section-title">基础身份信息</div>
|
<section-card title="基础身份信息">
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="司机姓名" prop="driverName">
|
<el-form-item label="司机姓名" prop="driverName">
|
||||||
<el-input v-model="driverForm.driverName" maxlength="20" show-word-limit />
|
<el-input v-model="driverForm.driverName" maxlength="10" show-word-limit />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
@@ -148,7 +139,11 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="出生年月" prop="birthday">
|
<el-form-item label="出生年月" prop="birthday">
|
||||||
<el-date-picker v-model="driverForm.birthday" type="date" value-format="YYYY-MM-DD" />
|
<el-date-picker
|
||||||
|
v-model="driverForm.birthday"
|
||||||
|
type="date"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -164,7 +159,12 @@
|
|||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="民族" prop="nation">
|
<el-form-item label="民族" prop="nation">
|
||||||
<el-select v-model="driverForm.nation" clearable filterable>
|
<el-select v-model="driverForm.nation" clearable filterable>
|
||||||
<el-option v-for="item in nationOptions" :key="item" :label="item" :value="item" />
|
<el-option
|
||||||
|
v-for="item in nationOptions"
|
||||||
|
:key="item"
|
||||||
|
:label="item"
|
||||||
|
:value="item"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -246,8 +246,9 @@
|
|||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<div class="section-title">驾驶证信息</div>
|
<section-card title="驾驶证信息">
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="准驾车型" prop="drivingType">
|
<el-form-item label="准驾车型" prop="drivingType">
|
||||||
@@ -316,8 +317,7 @@
|
|||||||
:headers="uploadHeaders"
|
:headers="uploadHeaders"
|
||||||
large
|
large
|
||||||
@success="
|
@success="
|
||||||
(url, file) =>
|
(url, file) => handleDrivingLicenseUploadSuccess('drivingLicenseFront', url, file)
|
||||||
handleDrivingLicenseUploadSuccess('drivingLicenseFront', url, file)
|
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -335,8 +335,9 @@
|
|||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<div class="section-title">从业资格证信息</div>
|
<section-card title="从业资格证信息">
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="从业资格认证类型" prop="qualificationType">
|
<el-form-item label="从业资格认证类型" prop="qualificationType">
|
||||||
@@ -344,8 +345,6 @@
|
|||||||
v-model="driverForm.qualificationType"
|
v-model="driverForm.qualificationType"
|
||||||
clearable
|
clearable
|
||||||
filterable
|
filterable
|
||||||
allow-create
|
|
||||||
default-first-option
|
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in qualificationTypeOptions"
|
v-for="item in qualificationTypeOptions"
|
||||||
@@ -413,35 +412,39 @@
|
|||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<div class="section-title">司机联系信息</div>
|
<section-card title="司机联系信息">
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="8">
|
<el-col :span="6">
|
||||||
<el-form-item label="司机类型" prop="driverType">
|
<el-form-item label="司机类型" prop="driverType">
|
||||||
<el-select v-model="driverForm.driverType" filterable>
|
<el-select v-model="driverForm.driverType" filterable>
|
||||||
<el-option label="自有" value="自有" />
|
<el-option label="自有" value="自有" />
|
||||||
<el-option label="外协" value="外协" />
|
<el-option label="外协" value="外协" />
|
||||||
|
<el-option label="承运管理员" value="承运管理员" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="6">
|
||||||
<el-form-item label="手机号" prop="mobile">
|
<el-form-item label="手机号" prop="mobile">
|
||||||
<el-input v-model="driverForm.mobile" maxlength="20" />
|
<el-input v-model="driverForm.mobile" maxlength="20" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="6">
|
||||||
<el-form-item label="紧急联系人姓名" prop="emergencyContactName">
|
<el-form-item label="紧急联系人姓名" prop="emergencyContactName">
|
||||||
<el-input v-model="driverForm.emergencyContactName" maxlength="20" />
|
<el-input
|
||||||
|
v-model="driverForm.emergencyContactName"
|
||||||
|
maxlength="20"
|
||||||
|
@input="driverForm.emergencyContactName = removeDigits($event)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
<el-col :span="6">
|
||||||
<el-row :gutter="18">
|
|
||||||
<el-col :span="8">
|
|
||||||
<el-form-item label="紧急联系人手机号" prop="emergencyContactMobile">
|
<el-form-item label="紧急联系人手机号" prop="emergencyContactMobile">
|
||||||
<el-input v-model="driverForm.emergencyContactMobile" maxlength="20" />
|
<el-input v-model="driverForm.emergencyContactMobile" maxlength="20" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="6">
|
||||||
<el-form-item label="与联系人关系" prop="contactRelation">
|
<el-form-item label="与联系人关系" prop="contactRelation">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="driverForm.contactRelation"
|
v-model="driverForm.contactRelation"
|
||||||
@@ -459,7 +462,7 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="6">
|
||||||
<el-form-item label="所属组织" prop="organizationName">
|
<el-form-item label="所属组织" prop="organizationName">
|
||||||
<el-select v-model="driverForm.organizationName" clearable filterable>
|
<el-select v-model="driverForm.organizationName" clearable filterable>
|
||||||
<el-option
|
<el-option
|
||||||
@@ -472,6 +475,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</section-card>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="driverBox = false">取消</el-button>
|
<el-button @click="driverBox = false">取消</el-button>
|
||||||
@@ -499,6 +503,7 @@ import {
|
|||||||
recognitionTransportCertificates,
|
recognitionTransportCertificates,
|
||||||
} from '@/api/transportCapacity/driver';
|
} from '@/api/transportCapacity/driver';
|
||||||
import { getDeptTree } from '@/api/system/dept';
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
|
import { getDictionary } from '@/api/system/dictbiz';
|
||||||
import { getLazyTree } from '@/api/base/region';
|
import { getLazyTree } from '@/api/base/region';
|
||||||
import { exportBlob } from '@/api/common';
|
import { exportBlob } from '@/api/common';
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
@@ -636,18 +641,8 @@ export default {
|
|||||||
],
|
],
|
||||||
educationOptions: ['初中', '高中', '中专', '大专', '本科', '硕士及以上'],
|
educationOptions: ['初中', '高中', '中专', '大专', '本科', '硕士及以上'],
|
||||||
drivingTypeOptions: ['A1', 'A2', 'A3', 'B1', 'B2', 'C1', 'C2'],
|
drivingTypeOptions: ['A1', 'A2', 'A3', 'B1', 'B2', 'C1', 'C2'],
|
||||||
qualificationTypeOptions: [
|
qualificationTypeOptions: [],
|
||||||
'放射品押运员',
|
relationOptions: ['父母', '配偶', '子女', '兄弟姐妹', '朋友', '同事', '其他'],
|
||||||
'道路运输从业资格证',
|
|
||||||
'危险货物运输从业资格证',
|
|
||||||
'A1',
|
|
||||||
'A2',
|
|
||||||
'B1',
|
|
||||||
'B2',
|
|
||||||
'C1',
|
|
||||||
'C2',
|
|
||||||
],
|
|
||||||
relationOptions: ['父母', '配偶', '子女', '兄弟姐妹', '朋友', '同事'],
|
|
||||||
organizationOptions: [],
|
organizationOptions: [],
|
||||||
regionOptions: [],
|
regionOptions: [],
|
||||||
formRules: {
|
formRules: {
|
||||||
@@ -683,6 +678,7 @@ export default {
|
|||||||
mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
|
mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
|
||||||
emergencyContactName: [
|
emergencyContactName: [
|
||||||
{ required: true, message: '请输入紧急联系人姓名', trigger: 'blur' },
|
{ required: true, message: '请输入紧急联系人姓名', trigger: 'blur' },
|
||||||
|
{ validator: this.validateEmergencyContactName, trigger: 'blur' },
|
||||||
],
|
],
|
||||||
emergencyContactMobile: [
|
emergencyContactMobile: [
|
||||||
{ required: true, message: '请输入紧急联系人手机号', trigger: 'blur' },
|
{ required: true, message: '请输入紧急联系人手机号', trigger: 'blur' },
|
||||||
@@ -723,10 +719,18 @@ export default {
|
|||||||
emitPath: true,
|
emitPath: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
expiryTagOptions() {
|
||||||
|
return [
|
||||||
|
{ label: '全部', value: '', statKey: 'total' },
|
||||||
|
{ label: '30天内到期', value: 'within30', statKey: 'within30' },
|
||||||
|
{ label: '已到期', value: 'expired', statKey: 'expired' },
|
||||||
|
];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.initDeptTree();
|
this.initDeptTree();
|
||||||
this.initRegionOptions();
|
this.initRegionOptions();
|
||||||
|
this.initQualificationTypeOptions();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
hasPermission(code) {
|
hasPermission(code) {
|
||||||
@@ -737,6 +741,16 @@ export default {
|
|||||||
this.organizationOptions = this.formatDeptOptions(res.data.data || []);
|
this.organizationOptions = this.formatDeptOptions(res.data.data || []);
|
||||||
const column = this.findColumn(this.option.column, 'organizationName');
|
const column = this.findColumn(this.option.column, 'organizationName');
|
||||||
column.dicData = this.organizationOptions;
|
column.dicData = this.organizationOptions;
|
||||||
|
if (this.driverBox && !this.driverForm.id && !this.driverForm.organizationName) {
|
||||||
|
this.driverForm.organizationName = this.getCurrentOrganizationName();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initQualificationTypeOptions() {
|
||||||
|
getDictionary({ code: 'type_of_cert' }).then(res => {
|
||||||
|
this.qualificationTypeOptions = (res.data.data || [])
|
||||||
|
.map(item => item.dictValue)
|
||||||
|
.filter(Boolean);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
formatDeptOptions(tree = [], level = 0) {
|
formatDeptOptions(tree = [], level = 0) {
|
||||||
@@ -746,6 +760,8 @@ export default {
|
|||||||
result.push({
|
result.push({
|
||||||
label: `${' '.repeat(level)}${label}`,
|
label: `${' '.repeat(level)}${label}`,
|
||||||
value: label,
|
value: label,
|
||||||
|
rawLabel: label,
|
||||||
|
id: item.id || item.value,
|
||||||
});
|
});
|
||||||
if (item.children && item.children.length) {
|
if (item.children && item.children.length) {
|
||||||
result.push(...this.formatDeptOptions(item.children, level + 1));
|
result.push(...this.formatDeptOptions(item.children, level + 1));
|
||||||
@@ -753,6 +769,13 @@ export default {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
getCurrentOrganizationName() {
|
||||||
|
const currentDeptId = this.userInfo.deptId || this.userInfo.dept_id;
|
||||||
|
const currentDept = this.organizationOptions.find(
|
||||||
|
item => String(item.id) === String(currentDeptId)
|
||||||
|
);
|
||||||
|
return currentDept?.rawLabel || this.userInfo.deptName || this.userInfo.dept_name || '';
|
||||||
|
},
|
||||||
initRegionOptions() {
|
initRegionOptions() {
|
||||||
getLazyTree().then(res => {
|
getLazyTree().then(res => {
|
||||||
const regions = this.buildRegionTree(res.data.data || []);
|
const regions = this.buildRegionTree(res.data.data || []);
|
||||||
@@ -882,10 +905,21 @@ export default {
|
|||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
|
validateEmergencyContactName(rule, value, callback) {
|
||||||
|
if (/\d/.test(value || '')) {
|
||||||
|
callback(new Error('紧急联系人姓名不能包含数字'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
removeDigits(value = '') {
|
||||||
|
return String(value).replace(/\d/g, '');
|
||||||
|
},
|
||||||
openDriver(row, readonly = false) {
|
openDriver(row, readonly = false) {
|
||||||
this.readonly = readonly;
|
this.readonly = readonly;
|
||||||
if (!row?.id) {
|
if (!row?.id) {
|
||||||
this.driverForm = emptyForm();
|
this.driverForm = emptyForm();
|
||||||
|
this.driverForm.organizationName = this.getCurrentOrganizationName();
|
||||||
this.driverBox = true;
|
this.driverBox = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -918,9 +952,9 @@ export default {
|
|||||||
this.setImage(prop, url);
|
this.setImage(prop, url);
|
||||||
this.recognizeIdCard(url);
|
this.recognizeIdCard(url);
|
||||||
},
|
},
|
||||||
handleDrivingLicenseUploadSuccess(prop, url, file = {}) {
|
handleDrivingLicenseUploadSuccess(prop, url) {
|
||||||
this.setImage(prop, url);
|
this.setImage(prop, url);
|
||||||
this.drivingLicenseUploads[prop] = this.getUploadRecognitionKey(file, url);
|
this.drivingLicenseUploads[prop] = url;
|
||||||
this.recognizeDrivingLicense();
|
this.recognizeDrivingLicense();
|
||||||
},
|
},
|
||||||
recognizeIdCard(url = '') {
|
recognizeIdCard(url = '') {
|
||||||
@@ -973,10 +1007,10 @@ export default {
|
|||||||
buildDrivingLicenseRecognitionCertificates() {
|
buildDrivingLicenseRecognitionCertificates() {
|
||||||
return ['drivingLicenseFront', 'drivingLicenseBack']
|
return ['drivingLicenseFront', 'drivingLicenseBack']
|
||||||
.map(prop => {
|
.map(prop => {
|
||||||
const objectKey = this.drivingLicenseUploads[prop] || this.driverForm[prop];
|
const url = this.drivingLicenseUploads[prop] || this.driverForm[prop];
|
||||||
if (!objectKey) return null;
|
if (!url) return null;
|
||||||
return {
|
return {
|
||||||
driverLicenseUrl: objectKey,
|
driverLicenseUrl: url,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
@@ -1043,19 +1077,6 @@ export default {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getUploadRecognitionKey(file = {}, url = '') {
|
|
||||||
return (
|
|
||||||
file.objectKey ||
|
|
||||||
file.key ||
|
|
||||||
file.fileName ||
|
|
||||||
file.name ||
|
|
||||||
file.link ||
|
|
||||||
file.url ||
|
|
||||||
file.domain ||
|
|
||||||
url ||
|
|
||||||
''
|
|
||||||
);
|
|
||||||
},
|
|
||||||
applyIdCardRecognition(data = {}) {
|
applyIdCardRecognition(data = {}) {
|
||||||
const driverName = data.name || data.driverName || this.getOcrValue(data, ['name', '姓名']);
|
const driverName = data.name || data.driverName || this.getOcrValue(data, ['name', '姓名']);
|
||||||
const idCardNo = String(
|
const idCardNo = String(
|
||||||
@@ -1203,7 +1224,8 @@ export default {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleExpireChange() {
|
handleExpireChange(expireStatus) {
|
||||||
|
this.query.expireStatus = expireStatus;
|
||||||
this.page.currentPage = 1;
|
this.page.currentPage = 1;
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
},
|
},
|
||||||
@@ -1319,8 +1341,23 @@ export default {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.driver-page {
|
.driver-page {
|
||||||
.driver-stat {
|
&__identity {
|
||||||
flex-shrink: 0;
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__expiry-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
:deep(.el-check-tag) {
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-table th .cell),
|
:deep(.el-table th .cell),
|
||||||
@@ -1330,19 +1367,6 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.driver-form {
|
.driver-form {
|
||||||
.section-title {
|
|
||||||
margin: 18px 0 14px;
|
|
||||||
padding-left: 10px;
|
|
||||||
border-left: 3px solid #e74b5f;
|
|
||||||
color: #303133;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-date-editor.el-input),
|
:deep(.el-date-editor.el-input),
|
||||||
:deep(.el-date-editor.el-input__wrapper),
|
:deep(.el-date-editor.el-input__wrapper),
|
||||||
:deep(.el-cascader),
|
:deep(.el-cascader),
|
||||||
@@ -1358,9 +1382,9 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 大尺寸证件照:按身份证 1.586:1 比例缩放(约真实尺寸 75%,240×151),左对齐显示
|
||||||
:deep(.driver-uploader) {
|
:deep(.driver-uploader) {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.driver-uploader .el-upload),
|
:deep(.driver-uploader .el-upload),
|
||||||
@@ -1375,9 +1399,17 @@ export default {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 大尺寸模式:缩成 1.586:1 比例,左对齐(不再 100% 占栏)
|
||||||
|
:deep(.driver-uploader--large) {
|
||||||
|
display: block;
|
||||||
|
width: 240px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.driver-uploader--large .el-upload),
|
:deep(.driver-uploader--large .el-upload),
|
||||||
:deep(.driver-uploader--large.el-upload) {
|
:deep(.driver-uploader--large.el-upload) {
|
||||||
height: 260px;
|
width: 100%;
|
||||||
|
height: 151px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.driver-uploader__image) {
|
:deep(.driver-uploader__image) {
|
||||||
@@ -1396,6 +1428,7 @@ export default {
|
|||||||
color: #606266;
|
color: #606266;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 弹窗内可滚动(弹窗 body 灰底已由全局 .el-dialog__body 规则生效)
|
||||||
.driver-dialog {
|
.driver-dialog {
|
||||||
:deep(.el-dialog__body) {
|
:deep(.el-dialog__body) {
|
||||||
max-height: 72vh;
|
max-height: 72vh;
|
||||||
@@ -1410,9 +1443,8 @@ export default {
|
|||||||
|
|
||||||
@media (max-width: 1200px) {
|
@media (max-width: 1200px) {
|
||||||
.driver-page {
|
.driver-page {
|
||||||
.driver-stat {
|
&__expiry-tags {
|
||||||
display: flex;
|
flex: 1;
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
plain
|
|
||||||
v-if="hasPermission('transport_ship_add')"
|
v-if="hasPermission('transport_ship_add')"
|
||||||
@click="openShip()"
|
@click="openShip()"
|
||||||
>
|
>
|
||||||
@@ -45,12 +44,17 @@
|
|||||||
批量删除
|
批量删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template #menu-right>
|
<template #expireStatus-search>
|
||||||
<el-radio-group v-model="query.expireStatus" class="ship-stat" @change="handleExpireChange">
|
<div class="transport-ship-page__expiry-tags">
|
||||||
<el-radio-button label="">全部({{ expiryStat.total }})</el-radio-button>
|
<el-check-tag
|
||||||
<el-radio-button label="within30">30天内到期({{ expiryStat.within30 }})</el-radio-button>
|
v-for="item in expiryTagOptions"
|
||||||
<el-radio-button label="expired">已到期({{ expiryStat.expired }})</el-radio-button>
|
:key="item.value"
|
||||||
</el-radio-group>
|
:checked="query.expireStatus === item.value"
|
||||||
|
@change="handleExpireChange(item.value)"
|
||||||
|
>
|
||||||
|
{{ item.label }}({{ expiryStat[item.statKey] || 0 }})
|
||||||
|
</el-check-tag>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #shipName="{ row }">
|
<template #shipName="{ row }">
|
||||||
<el-button type="primary" link @click="openShip(row, true)">
|
<el-button type="primary" link @click="openShip(row, true)">
|
||||||
@@ -68,14 +72,22 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #safeManningCertEndDate="{ row }">
|
<template #safeManningCertEndDate="{ row }">
|
||||||
<span :class="getDateClass(row, 'safeManningCertEndDate', 'safeManningCertLongTerm')">
|
<span
|
||||||
|
:class="
|
||||||
|
getCertificateExpiryClass(row, 'safeManningCertEndDate', 'safeManningCertLongTerm')
|
||||||
|
"
|
||||||
|
>
|
||||||
{{ formatEndDate(row.safeManningCertEndDate, row.safeManningCertLongTerm) }}
|
{{ formatEndDate(row.safeManningCertEndDate, row.safeManningCertLongTerm) }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #businessTransportCertEndDate="{ row }">
|
<template #businessTransportCertEndDate="{ row }">
|
||||||
<span
|
<span
|
||||||
:class="
|
:class="
|
||||||
getDateClass(row, 'businessTransportCertEndDate', 'businessTransportCertLongTerm')
|
getCertificateExpiryClass(
|
||||||
|
row,
|
||||||
|
'businessTransportCertEndDate',
|
||||||
|
'businessTransportCertLongTerm'
|
||||||
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ formatEndDate(row.businessTransportCertEndDate, row.businessTransportCertLongTerm) }}
|
{{ formatEndDate(row.businessTransportCertEndDate, row.businessTransportCertLongTerm) }}
|
||||||
@@ -87,17 +99,13 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row }">
|
<template #menu="{ row }">
|
||||||
<el-link
|
<el-link type="primary" v-if="hasPermission('transport_ship_edit')" @click="openShip(row)">
|
||||||
type="primary"
|
|
||||||
v-if="hasPermission('transport_ship_edit')"
|
|
||||||
@click="openShip(row)"
|
|
||||||
>
|
|
||||||
修改
|
修改
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="hasPermission('transport_ship_view')"
|
v-if="hasPermission('transport_ship_view')"
|
||||||
@click="openShip(row, true)"
|
@click="openShipLedger(row)"
|
||||||
>
|
>
|
||||||
综合台账
|
综合台账
|
||||||
</el-link>
|
</el-link>
|
||||||
@@ -111,6 +119,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</avue-crud>
|
</avue-crud>
|
||||||
|
|
||||||
|
<ship-ledger v-model="shipLedgerBox" :ship="ledgerShip" />
|
||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:title="dialogTitle"
|
:title="dialogTitle"
|
||||||
append-to-body
|
append-to-body
|
||||||
@@ -128,11 +138,16 @@
|
|||||||
:disabled="readonly"
|
:disabled="readonly"
|
||||||
class="ship-form"
|
class="ship-form"
|
||||||
>
|
>
|
||||||
<div class="section-title">基础船舶信息</div>
|
<section-card title="基础船舶信息">
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="船舶所属组织" prop="organizationName">
|
<el-form-item label="船舶所属组织" prop="organizationName">
|
||||||
<el-select v-model="shipForm.organizationName" filterable clearable placeholder="请选择">
|
<el-select
|
||||||
|
v-model="shipForm.organizationName"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
placeholder="请选择"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in organizationOptions"
|
v-for="item in organizationOptions"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
@@ -144,7 +159,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="船名" prop="shipName">
|
<el-form-item label="船名" prop="shipName">
|
||||||
<el-input v-model="shipForm.shipName" maxlength="50" show-word-limit />
|
<el-input v-model="shipForm.shipName" maxlength="20" show-word-limit />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
@@ -170,64 +185,64 @@
|
|||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="总长" prop="totalLength">
|
<el-form-item label="总长" prop="totalLength">
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="shipForm.totalLength"
|
v-model="shipForm.totalLength"
|
||||||
:min="0"
|
@input="normalizeNonNegativeDecimal('totalLength')"
|
||||||
:precision="2"
|
>
|
||||||
:controls="false"
|
<template #suffix>m</template>
|
||||||
/>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="船宽" prop="shipWidth">
|
<el-form-item label="船宽" prop="shipWidth">
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="shipForm.shipWidth"
|
v-model="shipForm.shipWidth"
|
||||||
:min="0"
|
@input="normalizeNonNegativeDecimal('shipWidth')"
|
||||||
:precision="2"
|
>
|
||||||
:controls="false"
|
<template #suffix>m</template>
|
||||||
/>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="型深" prop="moldedDepth">
|
<el-form-item label="型深" prop="moldedDepth">
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="shipForm.moldedDepth"
|
v-model="shipForm.moldedDepth"
|
||||||
:min="0"
|
@input="normalizeNonNegativeDecimal('moldedDepth')"
|
||||||
:precision="2"
|
>
|
||||||
:controls="false"
|
<template #suffix>m</template>
|
||||||
/>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="最大船高" prop="maxShipHeight">
|
<el-form-item label="最大船高" prop="maxShipHeight">
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="shipForm.maxShipHeight"
|
v-model="shipForm.maxShipHeight"
|
||||||
:min="0"
|
@input="normalizeNonNegativeDecimal('maxShipHeight')"
|
||||||
:precision="2"
|
>
|
||||||
:controls="false"
|
<template #suffix>m</template>
|
||||||
/>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="空载吃水" prop="lightDraft">
|
<el-form-item label="空载吃水" prop="lightDraft">
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="shipForm.lightDraft"
|
v-model="shipForm.lightDraft"
|
||||||
:min="0"
|
@input="normalizeNonNegativeDecimal('lightDraft')"
|
||||||
:precision="2"
|
>
|
||||||
:controls="false"
|
<template #suffix>t</template>
|
||||||
/>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="满载吃水" prop="fullLoadDraft">
|
<el-form-item label="满载吃水" prop="fullLoadDraft">
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="shipForm.fullLoadDraft"
|
v-model="shipForm.fullLoadDraft"
|
||||||
:min="0"
|
@input="normalizeNonNegativeDecimal('fullLoadDraft')"
|
||||||
:precision="2"
|
>
|
||||||
:controls="false"
|
<template #suffix>t</template>
|
||||||
/>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -267,8 +282,9 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<div class="section-title section-title--wide">船舶证书信息</div>
|
<section-card title="船舶证书信息">
|
||||||
<div class="cert-block">
|
<div class="cert-block">
|
||||||
<div class="cert-block__title">船舶所有权证书</div>
|
<div class="cert-block__title">船舶所有权证书</div>
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
@@ -304,7 +320,9 @@
|
|||||||
v-model="shipForm.shipIdentifierNo"
|
v-model="shipForm.shipIdentifierNo"
|
||||||
maxlength="50"
|
maxlength="50"
|
||||||
@input="
|
@input="
|
||||||
shipForm.shipIdentifierNo = String(shipForm.shipIdentifierNo || '').toUpperCase()
|
shipForm.shipIdentifierNo = String(
|
||||||
|
shipForm.shipIdentifierNo || ''
|
||||||
|
).toUpperCase()
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -344,7 +362,12 @@
|
|||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="船舶类型" prop="shipType">
|
<el-form-item label="船舶类型" prop="shipType">
|
||||||
<el-input v-model="shipForm.shipType" maxlength="50" />
|
<el-select v-model="shipForm.shipType" placeholder="请选择船舶类型" clearable>
|
||||||
|
<el-option label="散货船" value="散货船" />
|
||||||
|
<el-option label="集装箱船" value="集装箱船" />
|
||||||
|
<el-option label="杂货船" value="杂货船" />
|
||||||
|
<el-option label="油船" value="油船" />
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -541,6 +564,7 @@
|
|||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</section-card>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="shipBox = false">取消</el-button>
|
<el-button @click="shipBox = false">取消</el-button>
|
||||||
@@ -571,6 +595,7 @@ import { getToken } from '@/utils/auth';
|
|||||||
import { getUploadHeaders } from '@/utils/upload';
|
import { getUploadHeaders } from '@/utils/upload';
|
||||||
import { downloadXls } from '@/utils/util';
|
import { downloadXls } from '@/utils/util';
|
||||||
import ImageUploadField from '@/components/image-upload-field/main.vue';
|
import ImageUploadField from '@/components/image-upload-field/main.vue';
|
||||||
|
import ShipLedger from './components/ship-ledger.vue';
|
||||||
|
|
||||||
const emptyForm = () => ({
|
const emptyForm = () => ({
|
||||||
id: '',
|
id: '',
|
||||||
@@ -620,7 +645,7 @@ const emptyForm = () => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { ImageUploadField, InfoFilled },
|
components: { ImageUploadField, InfoFilled, ShipLedger },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
option,
|
option,
|
||||||
@@ -635,13 +660,18 @@ export default {
|
|||||||
page: { pageSize: 10, currentPage: 1, total: 0 },
|
page: { pageSize: 10, currentPage: 1, total: 0 },
|
||||||
expiryStat: { total: 0, within30: 0, expired: 0 },
|
expiryStat: { total: 0, within30: 0, expired: 0 },
|
||||||
shipBox: false,
|
shipBox: false,
|
||||||
|
shipLedgerBox: false,
|
||||||
|
ledgerShip: {},
|
||||||
readonly: false,
|
readonly: false,
|
||||||
shipForm: emptyForm(),
|
shipForm: emptyForm(),
|
||||||
uploadHeaders: getUploadHeaders(),
|
uploadHeaders: getUploadHeaders(),
|
||||||
organizationOptions: [],
|
organizationOptions: [],
|
||||||
formRules: {
|
formRules: {
|
||||||
organizationName: [{ required: true, message: '请选择船舶所属组织', trigger: 'change' }],
|
organizationName: [{ required: true, message: '请选择船舶所属组织', trigger: 'change' }],
|
||||||
shipName: [{ required: true, message: '请输入船名', trigger: 'blur' }],
|
shipName: [
|
||||||
|
{ required: true, message: '请输入船名', trigger: 'blur' },
|
||||||
|
{ max: 20, message: '船名不能超过20个字符', trigger: 'blur' },
|
||||||
|
],
|
||||||
keelLayingDate: [{ validator: this.validateKeelCompletionDate, trigger: 'change' }],
|
keelLayingDate: [{ validator: this.validateKeelCompletionDate, trigger: 'change' }],
|
||||||
shipIdentifierNo: [{ required: true, message: '请输入船舶识别号', trigger: 'blur' }],
|
shipIdentifierNo: [{ required: true, message: '请输入船舶识别号', trigger: 'blur' }],
|
||||||
totalLength: [{ validator: this.validateNonNegativeField, trigger: 'change' }],
|
totalLength: [{ validator: this.validateNonNegativeField, trigger: 'change' }],
|
||||||
@@ -657,9 +687,13 @@ export default {
|
|||||||
grossTonnage: [{ required: true, message: '请输入总吨', trigger: 'change' }],
|
grossTonnage: [{ required: true, message: '请输入总吨', trigger: 'change' }],
|
||||||
netTonnage: [{ required: true, message: '请输入净吨', trigger: 'change' }],
|
netTonnage: [{ required: true, message: '请输入净吨', trigger: 'change' }],
|
||||||
shipInspectionNo: [{ required: true, message: '请输入船检登记号', trigger: 'blur' }],
|
shipInspectionNo: [{ required: true, message: '请输入船检登记号', trigger: 'blur' }],
|
||||||
shipType: [{ required: true, message: '请输入船舶类型', trigger: 'blur' }],
|
shipType: [{ required: true, message: '请选择船舶类型', trigger: 'change' }],
|
||||||
nationalityCertStartDate: [{ validator: this.validateNationalityCertDate, trigger: 'change' }],
|
nationalityCertStartDate: [
|
||||||
safeManningCertStartDate: [{ validator: this.validateSafeManningCertDate, trigger: 'change' }],
|
{ validator: this.validateNationalityCertDate, trigger: 'change' },
|
||||||
|
],
|
||||||
|
safeManningCertStartDate: [
|
||||||
|
{ validator: this.validateSafeManningCertDate, trigger: 'change' },
|
||||||
|
],
|
||||||
leaseStartDate: [{ validator: this.validateLeaseDate, trigger: 'change' }],
|
leaseStartDate: [{ validator: this.validateLeaseDate, trigger: 'change' }],
|
||||||
businessTransportCertNo: [{ required: true, message: '请输入证书编号', trigger: 'blur' }],
|
businessTransportCertNo: [{ required: true, message: '请输入证书编号', trigger: 'blur' }],
|
||||||
businessTransportCertIssueDate: [
|
businessTransportCertIssueDate: [
|
||||||
@@ -694,6 +728,13 @@ export default {
|
|||||||
if (this.readonly) return '船舶综合台账';
|
if (this.readonly) return '船舶综合台账';
|
||||||
return this.shipForm.id ? '修改船舶' : '新增船舶';
|
return this.shipForm.id ? '修改船舶' : '新增船舶';
|
||||||
},
|
},
|
||||||
|
expiryTagOptions() {
|
||||||
|
return [
|
||||||
|
{ label: '全部', value: '', statKey: 'total' },
|
||||||
|
{ label: '30天内到期', value: 'within30', statKey: 'within30' },
|
||||||
|
{ label: '已到期', value: 'expired', statKey: 'expired' },
|
||||||
|
];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.initDeptTree();
|
this.initDeptTree();
|
||||||
@@ -707,6 +748,9 @@ export default {
|
|||||||
this.organizationOptions = this.flattenDeptOptions(res.data.data || []);
|
this.organizationOptions = this.flattenDeptOptions(res.data.data || []);
|
||||||
const column = this.findColumn(this.option.column, 'organizationName');
|
const column = this.findColumn(this.option.column, 'organizationName');
|
||||||
column.dicData = this.organizationOptions;
|
column.dicData = this.organizationOptions;
|
||||||
|
if (this.shipBox && !this.shipForm.id && !this.shipForm.organizationName) {
|
||||||
|
this.shipForm.organizationName = this.getCurrentOrganizationName();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
flattenDeptOptions(tree = [], level = 0) {
|
flattenDeptOptions(tree = [], level = 0) {
|
||||||
@@ -716,6 +760,8 @@ export default {
|
|||||||
result.push({
|
result.push({
|
||||||
label: `${' '.repeat(level)}${label}`,
|
label: `${' '.repeat(level)}${label}`,
|
||||||
value: label,
|
value: label,
|
||||||
|
rawLabel: label,
|
||||||
|
id: item.id || item.value,
|
||||||
});
|
});
|
||||||
if (item.children && item.children.length) {
|
if (item.children && item.children.length) {
|
||||||
result.push(...this.flattenDeptOptions(item.children, level + 1));
|
result.push(...this.flattenDeptOptions(item.children, level + 1));
|
||||||
@@ -723,9 +769,22 @@ export default {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
getCurrentOrganizationName() {
|
||||||
|
const currentDeptId = this.userInfo.deptId || this.userInfo.dept_id;
|
||||||
|
const currentDept = this.organizationOptions.find(
|
||||||
|
item => String(item.id) === String(currentDeptId)
|
||||||
|
);
|
||||||
|
return currentDept?.rawLabel || this.userInfo.deptName || this.userInfo.dept_name || '';
|
||||||
|
},
|
||||||
validateField(prop) {
|
validateField(prop) {
|
||||||
this.$refs.shipForm?.validateField(prop);
|
this.$refs.shipForm?.validateField(prop);
|
||||||
},
|
},
|
||||||
|
normalizeNonNegativeDecimal(prop) {
|
||||||
|
const value = String(this.shipForm[prop] ?? '').replace(/[^\d.]/g, '');
|
||||||
|
const [integerPart = '', ...decimalParts] = value.split('.');
|
||||||
|
const decimalPart = decimalParts.join('').slice(0, 2);
|
||||||
|
this.shipForm[prop] = decimalParts.length ? `${integerPart}.${decimalPart}` : integerPart;
|
||||||
|
},
|
||||||
validateNonNegativeField(rule, value, callback) {
|
validateNonNegativeField(rule, value, callback) {
|
||||||
if (value !== undefined && value !== null && value < 0) {
|
if (value !== undefined && value !== null && value < 0) {
|
||||||
callback(new Error('数值不能小于0'));
|
callback(new Error('数值不能小于0'));
|
||||||
@@ -779,7 +838,11 @@ export default {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
validateDateRangeByProp(startProp, endProp, longTermProp, emptyMessage, callback) {
|
validateDateRangeByProp(startProp, endProp, longTermProp, emptyMessage, callback) {
|
||||||
if (this.shipForm[longTermProp] === 1 && !this.shipForm[startProp] && !this.shipForm[endProp]) {
|
if (
|
||||||
|
this.shipForm[longTermProp] === 1 &&
|
||||||
|
!this.shipForm[startProp] &&
|
||||||
|
!this.shipForm[endProp]
|
||||||
|
) {
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -804,6 +867,7 @@ export default {
|
|||||||
this.readonly = readonly;
|
this.readonly = readonly;
|
||||||
if (!row?.id) {
|
if (!row?.id) {
|
||||||
this.shipForm = emptyForm();
|
this.shipForm = emptyForm();
|
||||||
|
this.shipForm.organizationName = this.getCurrentOrganizationName();
|
||||||
this.shipBox = true;
|
this.shipBox = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -812,6 +876,10 @@ export default {
|
|||||||
this.shipBox = true;
|
this.shipBox = true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
openShipLedger(row) {
|
||||||
|
this.ledgerShip = { ...row };
|
||||||
|
this.shipLedgerBox = true;
|
||||||
|
},
|
||||||
resetShip() {
|
resetShip() {
|
||||||
this.shipForm = emptyForm();
|
this.shipForm = emptyForm();
|
||||||
this.readonly = false;
|
this.readonly = false;
|
||||||
@@ -867,7 +935,8 @@ export default {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleExpireChange() {
|
handleExpireChange(expireStatus) {
|
||||||
|
this.query.expireStatus = expireStatus;
|
||||||
this.page.currentPage = 1;
|
this.page.currentPage = 1;
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
},
|
},
|
||||||
@@ -963,40 +1032,37 @@ export default {
|
|||||||
if (endDate.diff(today, 'day') <= 30) return 'date-warning';
|
if (endDate.diff(today, 'day') <= 30) return 'date-warning';
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
|
getCertificateExpiryClass(row, dateProp, longTermProp) {
|
||||||
|
if (row[longTermProp] === 1 || !row[dateProp]) return '';
|
||||||
|
const endDate = this.$dayjs(row[dateProp]);
|
||||||
|
return endDate.isValid() && endDate.diff(this.$dayjs(), 'day') <= 30 ? 'date-danger' : '';
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.transport-ship-page {
|
.transport-ship-page {
|
||||||
.ship-stat {
|
&__expiry-tags {
|
||||||
flex-shrink: 0;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
:deep(.el-check-tag) {
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-table th .cell),
|
:deep(.el-table th .cell),
|
||||||
:deep(.el-table td .cell) {
|
:deep(.el-table td .cell) {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ship-form {
|
|
||||||
.section-title {
|
|
||||||
margin: 18px 0 14px;
|
|
||||||
padding-left: 10px;
|
|
||||||
border-left: 3px solid #e74b5f;
|
|
||||||
color: #303133;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title--wide {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
.ship-form {
|
||||||
:deep(.el-date-editor.el-input),
|
:deep(.el-date-editor.el-input),
|
||||||
:deep(.el-date-editor.el-input__wrapper),
|
:deep(.el-date-editor.el-input__wrapper),
|
||||||
:deep(.el-select),
|
:deep(.el-select),
|
||||||
@@ -1004,64 +1070,64 @@ export default {
|
|||||||
:deep(.el-input-number) {
|
:deep(.el-input-number) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-range-inline {
|
.date-range-inline {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-range-inline :deep(.el-date-editor) {
|
.date-range-inline :deep(.el-date-editor) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-area-field {
|
.navigation-area-field {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-area-field :deep(.el-select) {
|
.navigation-area-field :deep(.el-select) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-info-icon {
|
.navigation-info-icon {
|
||||||
color: #909399;
|
color: #909399;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
cursor: help;
|
cursor: help;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cert-block {
|
.cert-block {
|
||||||
padding: 16px 0 8px;
|
padding: 16px 0 8px;
|
||||||
border-top: 1px solid #e5e6eb;
|
border-top: 1px solid #e5e6eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cert-block__title {
|
.cert-block__title {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cert-upload-grid {
|
.cert-upload-grid {
|
||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cert-upload-spacer {
|
.cert-upload-spacer {
|
||||||
height: 1px;
|
height: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ship-upload-item {
|
.ship-upload-item {
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ocr-tip {
|
.ocr-tip {
|
||||||
min-height: 114px;
|
min-height: 114px;
|
||||||
padding: 18px 20px;
|
padding: 18px 20px;
|
||||||
background: #ffd84d;
|
background: #ffd84d;
|
||||||
@@ -1069,11 +1135,11 @@ export default {
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 大尺寸证件照:按身份证 1.586:1 比例缩放(约真实尺寸 75%,240×151),左对齐显示
|
||||||
:deep(.ship-uploader) {
|
:deep(.ship-uploader) {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ship-uploader .el-upload),
|
:deep(.ship-uploader .el-upload),
|
||||||
@@ -1090,7 +1156,14 @@ export default {
|
|||||||
|
|
||||||
:deep(.ship-uploader--large .el-upload),
|
:deep(.ship-uploader--large .el-upload),
|
||||||
:deep(.ship-uploader--large.el-upload) {
|
:deep(.ship-uploader--large.el-upload) {
|
||||||
height: 260px;
|
width: 100%;
|
||||||
|
height: 151px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ship-uploader--large) {
|
||||||
|
display: block;
|
||||||
|
width: 240px;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ship-uploader__image) {
|
:deep(.ship-uploader__image) {
|
||||||
@@ -1109,34 +1182,34 @@ export default {
|
|||||||
color: #606266;
|
color: #606266;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ship-navigation-tooltip) {
|
:deep(.ship-navigation-tooltip) {
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-cargo-table {
|
.navigation-cargo-table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-cargo-table th,
|
.navigation-cargo-table th,
|
||||||
.navigation-cargo-table td {
|
.navigation-cargo-table td {
|
||||||
border: 1px solid #909399;
|
border: 1px solid #909399;
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-cargo-table th {
|
.navigation-cargo-table th {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-warning {
|
.date-warning {
|
||||||
color: #f56c6c;
|
color: #f56c6c;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-danger {
|
.date-danger {
|
||||||
color: #d40000;
|
color: #d40000;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
plain
|
|
||||||
v-if="hasPermission('transport_vehicle_add')"
|
v-if="hasPermission('transport_vehicle_add')"
|
||||||
@click="openVehicle()"
|
@click="openVehicle()"
|
||||||
>新增
|
>新增
|
||||||
@@ -42,16 +41,17 @@
|
|||||||
>批量删除
|
>批量删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template #menu-right>
|
<template #expireStatus-search>
|
||||||
<el-radio-group
|
<div class="transport-vehicle-page__expiry-tags">
|
||||||
v-model="query.expireStatus"
|
<el-check-tag
|
||||||
class="vehicle-stat"
|
v-for="item in expiryTagOptions"
|
||||||
@change="handleExpireChange"
|
:key="item.value"
|
||||||
|
:checked="query.expireStatus === item.value"
|
||||||
|
@change="handleExpireChange(item.value)"
|
||||||
>
|
>
|
||||||
<el-radio-button label="">全部({{ expiryStat.total }})</el-radio-button>
|
{{ item.label }}({{ expiryStat[item.statKey] || 0 }})
|
||||||
<el-radio-button label="within30">30天内到期({{ expiryStat.within30 }})</el-radio-button>
|
</el-check-tag>
|
||||||
<el-radio-button label="expired">已到期({{ expiryStat.expired }})</el-radio-button>
|
</div>
|
||||||
</el-radio-group>
|
|
||||||
</template>
|
</template>
|
||||||
<template #plateNo="{ row }">
|
<template #plateNo="{ row }">
|
||||||
<el-button type="primary" link @click="openVehicle(row, true)">
|
<el-button type="primary" link @click="openVehicle(row, true)">
|
||||||
@@ -63,6 +63,14 @@
|
|||||||
{{ row.status === 1 ? '启用' : '停用' }}
|
{{ row.status === 1 ? '启用' : '停用' }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
|
<template #boundDriver>
|
||||||
|
<span>-</span>
|
||||||
|
</template>
|
||||||
|
<template #certificationStatus="{ row }">
|
||||||
|
<el-tag :type="getCertificationStatus(row).type">
|
||||||
|
{{ getCertificationStatus(row).label }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
<template #drivingLicenseEndDate="{ row }">
|
<template #drivingLicenseEndDate="{ row }">
|
||||||
<span :class="getDateClass(row, 'drivingLicenseEndDate', 'drivingLicenseLongTerm')">
|
<span :class="getDateClass(row, 'drivingLicenseEndDate', 'drivingLicenseLongTerm')">
|
||||||
{{ formatEndDate(row.drivingLicenseEndDate, row.drivingLicenseLongTerm) }}
|
{{ formatEndDate(row.drivingLicenseEndDate, row.drivingLicenseLongTerm) }}
|
||||||
@@ -93,6 +101,10 @@
|
|||||||
>
|
>
|
||||||
修改
|
修改
|
||||||
</el-link>
|
</el-link>
|
||||||
|
<el-link type="primary" @click="openVehicleLedger(row)">综合台账</el-link>
|
||||||
|
<el-link type="primary" v-if="row.certificationStatus === 0" @click="openCertificationAudit(row)">
|
||||||
|
审核
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="hasPermission('transport_vehicle_status')"
|
v-if="hasPermission('transport_vehicle_status')"
|
||||||
@@ -103,6 +115,26 @@
|
|||||||
</template>
|
</template>
|
||||||
</avue-crud>
|
</avue-crud>
|
||||||
|
|
||||||
|
<vehicle-ledger v-model="vehicleLedgerBox" :vehicle="ledgerVehicle" />
|
||||||
|
|
||||||
|
<el-dialog v-model="certificationAuditBox" title="车辆认证审核" width="92%" top="4vh">
|
||||||
|
<el-descriptions :column="3" border>
|
||||||
|
<el-descriptions-item v-for="item in auditDetailItems" :key="item.label" :label="item.label">
|
||||||
|
{{ formatAuditValue(item) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-form v-if="showRejectReason" class="certification-audit__reason" label-position="right" label-width="auto">
|
||||||
|
<el-form-item label="驳回原因" required>
|
||||||
|
<el-input v-model="certificationRejectReason" type="textarea" maxlength="200" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="certificationAuditBox = false">取消</el-button>
|
||||||
|
<el-button type="danger" @click="handleCertificationReject">认证驳回</el-button>
|
||||||
|
<el-button type="primary" @click="handleCertificationApprove">认证通过</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:title="dialogTitle"
|
:title="dialogTitle"
|
||||||
append-to-body
|
append-to-body
|
||||||
@@ -120,7 +152,7 @@
|
|||||||
:disabled="readonly"
|
:disabled="readonly"
|
||||||
class="vehicle-form"
|
class="vehicle-form"
|
||||||
>
|
>
|
||||||
<div class="section-title">基础车辆信息</div>
|
<section-card title="基础车辆信息">
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="所有组织" prop="organizationName">
|
<el-form-item label="所有组织" prop="organizationName">
|
||||||
@@ -200,29 +232,26 @@
|
|||||||
<div class="dimension-group">
|
<div class="dimension-group">
|
||||||
<div class="dimension-group__item">
|
<div class="dimension-group__item">
|
||||||
<span class="dimension-group__label">长</span>
|
<span class="dimension-group__label">长</span>
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="vehicleForm.outerLength"
|
v-model="vehicleForm.outerLength"
|
||||||
:min="0"
|
inputmode="numeric"
|
||||||
:precision="0"
|
@input="vehicleForm.outerLength = digitsOnly($event)"
|
||||||
controls-position="right"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="dimension-group__item">
|
<div class="dimension-group__item">
|
||||||
<span class="dimension-group__label">宽</span>
|
<span class="dimension-group__label">宽</span>
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="vehicleForm.outerWidth"
|
v-model="vehicleForm.outerWidth"
|
||||||
:min="0"
|
inputmode="numeric"
|
||||||
:precision="0"
|
@input="vehicleForm.outerWidth = digitsOnly($event)"
|
||||||
controls-position="right"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="dimension-group__item">
|
<div class="dimension-group__item">
|
||||||
<span class="dimension-group__label">高</span>
|
<span class="dimension-group__label">高</span>
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="vehicleForm.outerHeight"
|
v-model="vehicleForm.outerHeight"
|
||||||
:min="0"
|
inputmode="numeric"
|
||||||
:precision="0"
|
@input="vehicleForm.outerHeight = digitsOnly($event)"
|
||||||
controls-position="right"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -232,21 +261,19 @@
|
|||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="核定载质量(KG)" prop="approvedLoadKg">
|
<el-form-item label="核定载质量(KG)" prop="approvedLoadKg">
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="vehicleForm.approvedLoadKg"
|
v-model="vehicleForm.approvedLoadKg"
|
||||||
:min="0"
|
inputmode="numeric"
|
||||||
:precision="0"
|
@input="vehicleForm.approvedLoadKg = digitsOnly($event)"
|
||||||
controls-position="right"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="准牵引总质量(KG)" prop="tractionMassKg">
|
<el-form-item label="准牵引总质量(KG)" prop="tractionMassKg">
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="vehicleForm.tractionMassKg"
|
v-model="vehicleForm.tractionMassKg"
|
||||||
:min="0"
|
inputmode="numeric"
|
||||||
:precision="0"
|
@input="vehicleForm.tractionMassKg = digitsOnly($event)"
|
||||||
controls-position="right"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -306,8 +333,9 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</section-card>
|
||||||
|
|
||||||
<div class="section-title">车辆资质图片</div>
|
<section-card title="车辆资质图片">
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="行驶证档案编号" prop="drivingLicenseNo">
|
<el-form-item label="行驶证档案编号" prop="drivingLicenseNo">
|
||||||
@@ -484,6 +512,7 @@
|
|||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</section-card>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="vehicleBox = false">取消</el-button>
|
<el-button @click="vehicleBox = false">取消</el-button>
|
||||||
@@ -506,6 +535,7 @@ import {
|
|||||||
submit,
|
submit,
|
||||||
remove,
|
remove,
|
||||||
changeStatus,
|
changeStatus,
|
||||||
|
auditCertification,
|
||||||
getExpiryStat,
|
getExpiryStat,
|
||||||
recognitionTransportCertificates,
|
recognitionTransportCertificates,
|
||||||
} from '@/api/transportCapacity/transport-vehicle';
|
} from '@/api/transportCapacity/transport-vehicle';
|
||||||
@@ -515,6 +545,7 @@ import { getToken } from '@/utils/auth';
|
|||||||
import { getUploadHeaders } from '@/utils/upload';
|
import { getUploadHeaders } from '@/utils/upload';
|
||||||
import { downloadXls } from '@/utils/util';
|
import { downloadXls } from '@/utils/util';
|
||||||
import ImageUploadField from '@/components/image-upload-field/main.vue';
|
import ImageUploadField from '@/components/image-upload-field/main.vue';
|
||||||
|
import VehicleLedger from './components/vehicle-ledger.vue';
|
||||||
|
|
||||||
const emptyForm = () => ({
|
const emptyForm = () => ({
|
||||||
id: '',
|
id: '',
|
||||||
@@ -596,6 +627,7 @@ const plateColorOptions = ['黄牌', '蓝牌', '绿牌'].map(item => ({ label: i
|
|||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ImageUploadField,
|
ImageUploadField,
|
||||||
|
VehicleLedger,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -604,7 +636,9 @@ export default {
|
|||||||
query: {
|
query: {
|
||||||
expireStatus: '',
|
expireStatus: '',
|
||||||
},
|
},
|
||||||
searchForm: {},
|
searchForm: {
|
||||||
|
businessRelation: '',
|
||||||
|
},
|
||||||
loading: true,
|
loading: true,
|
||||||
submitLoading: false,
|
submitLoading: false,
|
||||||
data: [],
|
data: [],
|
||||||
@@ -621,6 +655,12 @@ export default {
|
|||||||
expired: 0,
|
expired: 0,
|
||||||
},
|
},
|
||||||
vehicleBox: false,
|
vehicleBox: false,
|
||||||
|
vehicleLedgerBox: false,
|
||||||
|
ledgerVehicle: {},
|
||||||
|
certificationAuditBox: false,
|
||||||
|
certificationAuditForm: {},
|
||||||
|
certificationRejectReason: '',
|
||||||
|
showRejectReason: false,
|
||||||
readonly: false,
|
readonly: false,
|
||||||
vehicleForm: emptyForm(),
|
vehicleForm: emptyForm(),
|
||||||
vehicleCertificateUploads: {},
|
vehicleCertificateUploads: {},
|
||||||
@@ -640,13 +680,18 @@ export default {
|
|||||||
energyTypeOptions: ['柴油', '汽油', '新能源', '天然气'],
|
energyTypeOptions: ['柴油', '汽油', '新能源', '天然气'],
|
||||||
formRules: {
|
formRules: {
|
||||||
organizationName: [{ required: true, message: '请选择所属组织', trigger: 'change' }],
|
organizationName: [{ required: true, message: '请选择所属组织', trigger: 'change' }],
|
||||||
plateNo: [{ validator: this.validatePlateNo, trigger: 'change' }],
|
plateNo: [
|
||||||
|
{ required: true, message: '请输入车牌号', trigger: 'change' },
|
||||||
|
{ validator: this.validatePlateNo, trigger: 'change' },
|
||||||
|
],
|
||||||
vehicleType: [{ required: true, message: '请选择车辆类型', trigger: 'change' }],
|
vehicleType: [{ required: true, message: '请选择车辆类型', trigger: 'change' }],
|
||||||
approvedLoadKg: [{ required: true, message: '请输入核定载质量', trigger: 'blur' }],
|
approvedLoadKg: [{ required: true, message: '请输入核定载质量', trigger: 'blur' }],
|
||||||
businessRelation: [{ required: true, message: '请选择业务关系', trigger: 'change' }],
|
businessRelation: [{ required: true, message: '请选择业务关系', trigger: 'change' }],
|
||||||
energyType: [{ required: true, message: '请选择能源类型', trigger: 'change' }],
|
energyType: [{ required: true, message: '请选择能源类型', trigger: 'change' }],
|
||||||
drivingLicenseNo: [{ required: true, message: '请输入行驶证档案编号', trigger: 'blur' }],
|
drivingLicenseNo: [{ required: true, message: '请输入行驶证档案编号', trigger: 'blur' }],
|
||||||
drivingLicenseEndDate: [{ required: true, message: '请选择行驶证有效期', trigger: 'change' }],
|
drivingLicenseEndDate: [
|
||||||
|
{ required: true, message: '请选择行驶证有效期', trigger: 'change' },
|
||||||
|
],
|
||||||
roadTransportCertNo: [{ required: true, message: '请输入道路运输证号', trigger: 'blur' }],
|
roadTransportCertNo: [{ required: true, message: '请输入道路运输证号', trigger: 'blur' }],
|
||||||
roadTransportCertEndDate: [
|
roadTransportCertEndDate: [
|
||||||
{ required: true, message: '请选择道路运输证有效期', trigger: 'change' },
|
{ required: true, message: '请选择道路运输证有效期', trigger: 'change' },
|
||||||
@@ -676,6 +721,25 @@ export default {
|
|||||||
}
|
}
|
||||||
return this.vehicleForm.id ? '修改车辆' : '新增车辆';
|
return this.vehicleForm.id ? '修改车辆' : '新增车辆';
|
||||||
},
|
},
|
||||||
|
auditDetailItems() {
|
||||||
|
return [
|
||||||
|
['所属组织', 'organizationName'], ['车牌号', 'plateNo'], ['车牌颜色', 'plateColor'],
|
||||||
|
['车辆类型', 'vehicleType'], ['外廓长度(mm)', 'outerLength'], ['外廓宽度(mm)', 'outerWidth'],
|
||||||
|
['外廓高度(mm)', 'outerHeight'], ['核定载质量(KG)', 'approvedLoadKg'], ['准牵引总质量(KG)', 'tractionMassKg'],
|
||||||
|
['业务关系', 'businessRelation'], ['能源类型', 'energyType'], ['强制报废日期', 'compulsoryScrapDate'],
|
||||||
|
['海关备案号', 'customsRecordNo'], ['行驶证档案编号', 'drivingLicenseNo'], ['行驶证有效期起', 'drivingLicenseStartDate'],
|
||||||
|
['行驶证有效期止', 'drivingLicenseEndDate'], ['道路运输证号', 'roadTransportCertNo'], ['道路运输证有效期起', 'roadTransportCertStartDate'],
|
||||||
|
['道路运输证有效期止', 'roadTransportCertEndDate'], ['道路运输年审有效期', 'annualReviewEndDate'],
|
||||||
|
['机动车登记编号', 'registrationNo'], ['机动车登记日期', 'registrationDate'], ['备注', 'remark'],
|
||||||
|
].map(([label, prop]) => ({ label, prop }));
|
||||||
|
},
|
||||||
|
expiryTagOptions() {
|
||||||
|
return [
|
||||||
|
{ label: '全部', value: '', statKey: 'total' },
|
||||||
|
{ label: '30天内到期', value: 'within30', statKey: 'within30' },
|
||||||
|
{ label: '已到期', value: 'expired', statKey: 'expired' },
|
||||||
|
];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.initDeptTree();
|
this.initDeptTree();
|
||||||
@@ -689,6 +753,9 @@ export default {
|
|||||||
this.organizationOptions = this.flattenDeptOptions(res.data.data || []);
|
this.organizationOptions = this.flattenDeptOptions(res.data.data || []);
|
||||||
const column = this.findColumn(this.option.column, 'organizationName');
|
const column = this.findColumn(this.option.column, 'organizationName');
|
||||||
column.dicData = this.organizationOptions;
|
column.dicData = this.organizationOptions;
|
||||||
|
if (this.vehicleBox && !this.vehicleForm.id && !this.vehicleForm.organizationName) {
|
||||||
|
this.vehicleForm.organizationName = this.getCurrentOrganizationName();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
flattenDeptOptions(tree = [], level = 0) {
|
flattenDeptOptions(tree = [], level = 0) {
|
||||||
@@ -698,6 +765,8 @@ export default {
|
|||||||
result.push({
|
result.push({
|
||||||
label: `${' '.repeat(level)}${label}`,
|
label: `${' '.repeat(level)}${label}`,
|
||||||
value: label,
|
value: label,
|
||||||
|
rawLabel: label,
|
||||||
|
id: item.id || item.value,
|
||||||
});
|
});
|
||||||
if (item.children && item.children.length) {
|
if (item.children && item.children.length) {
|
||||||
result.push(...this.flattenDeptOptions(item.children, level + 1));
|
result.push(...this.flattenDeptOptions(item.children, level + 1));
|
||||||
@@ -705,9 +774,21 @@ export default {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
getCurrentOrganizationName() {
|
||||||
|
const currentDeptId = this.userInfo.deptId || this.userInfo.dept_id;
|
||||||
|
const currentDept = this.organizationOptions.find(
|
||||||
|
item => String(item.id) === String(currentDeptId)
|
||||||
|
);
|
||||||
|
return currentDept?.rawLabel || this.userInfo.deptName || this.userInfo.dept_name || '';
|
||||||
|
},
|
||||||
|
digitsOnly(value = '') {
|
||||||
|
return String(value).replace(/\D/g, '');
|
||||||
|
},
|
||||||
validatePlateNo(rule, value, callback) {
|
validatePlateNo(rule, value, callback) {
|
||||||
const plateProvince = String(this.vehicleForm.plateProvince || '').trim();
|
const plateProvince = String(this.vehicleForm.plateProvince || '').trim();
|
||||||
const plateNoBody = String(this.vehicleForm.plateNoBody || '').trim().toUpperCase();
|
const plateNoBody = String(this.vehicleForm.plateNoBody || '')
|
||||||
|
.trim()
|
||||||
|
.toUpperCase();
|
||||||
const plateColor = String(this.vehicleForm.plateColor || '').trim();
|
const plateColor = String(this.vehicleForm.plateColor || '').trim();
|
||||||
if (!plateProvince || !plateNoBody || !plateColor) {
|
if (!plateProvince || !plateNoBody || !plateColor) {
|
||||||
callback(new Error('请完整填写车牌号'));
|
callback(new Error('请完整填写车牌号'));
|
||||||
@@ -730,6 +811,7 @@ export default {
|
|||||||
this.readonly = readonly;
|
this.readonly = readonly;
|
||||||
if (!row?.id) {
|
if (!row?.id) {
|
||||||
this.vehicleForm = emptyForm();
|
this.vehicleForm = emptyForm();
|
||||||
|
this.vehicleForm.organizationName = this.getCurrentOrganizationName();
|
||||||
this.syncPlateNo(false);
|
this.syncPlateNo(false);
|
||||||
this.vehicleBox = true;
|
this.vehicleBox = true;
|
||||||
return;
|
return;
|
||||||
@@ -744,6 +826,38 @@ export default {
|
|||||||
this.vehicleBox = true;
|
this.vehicleBox = true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
openVehicleLedger(row) {
|
||||||
|
this.ledgerVehicle = { ...row };
|
||||||
|
this.vehicleLedgerBox = true;
|
||||||
|
},
|
||||||
|
openCertificationAudit(row) {
|
||||||
|
getDetail(row.id).then(res => {
|
||||||
|
this.certificationAuditForm = { ...(res.data.data || {}) };
|
||||||
|
this.certificationRejectReason = '';
|
||||||
|
this.showRejectReason = false;
|
||||||
|
this.certificationAuditBox = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
formatAuditValue(item) {
|
||||||
|
const value = this.certificationAuditForm[item.prop];
|
||||||
|
return value === undefined || value === null || value === '' ? '-' : value;
|
||||||
|
},
|
||||||
|
handleCertificationApprove() {
|
||||||
|
auditCertification(this.certificationAuditForm.id, 1).then(() => {
|
||||||
|
this.$message.success('认证已通过');
|
||||||
|
this.certificationAuditBox = false;
|
||||||
|
this.onLoad(this.page);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleCertificationReject() {
|
||||||
|
if (!this.showRejectReason) { this.showRejectReason = true; return; }
|
||||||
|
if (!this.certificationRejectReason.trim()) { this.$message.warning('请输入认证驳回原因'); return; }
|
||||||
|
auditCertification(this.certificationAuditForm.id, 2, this.certificationRejectReason).then(() => {
|
||||||
|
this.$message.success('认证已驳回');
|
||||||
|
this.certificationAuditBox = false;
|
||||||
|
this.onLoad(this.page);
|
||||||
|
});
|
||||||
|
},
|
||||||
resetVehicle() {
|
resetVehicle() {
|
||||||
this.vehicleForm = emptyForm();
|
this.vehicleForm = emptyForm();
|
||||||
this.vehicleCertificateUploads = {};
|
this.vehicleCertificateUploads = {};
|
||||||
@@ -755,9 +869,9 @@ export default {
|
|||||||
this.vehicleForm[prop] = url;
|
this.vehicleForm[prop] = url;
|
||||||
this.$refs.vehicleForm?.validateField(prop);
|
this.$refs.vehicleForm?.validateField(prop);
|
||||||
},
|
},
|
||||||
handleVehicleCertificateUploadSuccess(prop, url, file = {}) {
|
handleVehicleCertificateUploadSuccess(prop, url) {
|
||||||
this.setImage(prop, url);
|
this.setImage(prop, url);
|
||||||
this.vehicleCertificateUploads[prop] = this.getUploadRecognitionKey(file, url);
|
this.vehicleCertificateUploads[prop] = url;
|
||||||
this.recognizeVehicleCertificates();
|
this.recognizeVehicleCertificates();
|
||||||
},
|
},
|
||||||
recognizeVehicleCertificates() {
|
recognizeVehicleCertificates() {
|
||||||
@@ -838,19 +952,6 @@ export default {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getUploadRecognitionKey(file = {}, url = '') {
|
|
||||||
return (
|
|
||||||
file.objectKey ||
|
|
||||||
file.key ||
|
|
||||||
file.fileName ||
|
|
||||||
file.name ||
|
|
||||||
file.link ||
|
|
||||||
file.url ||
|
|
||||||
file.domain ||
|
|
||||||
url ||
|
|
||||||
''
|
|
||||||
);
|
|
||||||
},
|
|
||||||
normalizeDate(value = '') {
|
normalizeDate(value = '') {
|
||||||
const dateValue = String(value || '').trim();
|
const dateValue = String(value || '').trim();
|
||||||
const match = dateValue.match(/^(\d{4})[-/.年](\d{1,2})[-/.月](\d{1,2})日?$/);
|
const match = dateValue.match(/^(\d{4})[-/.年](\d{1,2})[-/.月](\d{1,2})日?$/);
|
||||||
@@ -871,10 +972,13 @@ export default {
|
|||||||
},
|
},
|
||||||
syncPlateNo(validate = true) {
|
syncPlateNo(validate = true) {
|
||||||
const plateProvince = String(this.vehicleForm.plateProvince || '').trim();
|
const plateProvince = String(this.vehicleForm.plateProvince || '').trim();
|
||||||
const plateNoBody = String(this.vehicleForm.plateNoBody || '').trim().toUpperCase();
|
const plateNoBody = String(this.vehicleForm.plateNoBody || '')
|
||||||
|
.trim()
|
||||||
|
.toUpperCase();
|
||||||
const plateColor = String(this.vehicleForm.plateColor || '').trim();
|
const plateColor = String(this.vehicleForm.plateColor || '').trim();
|
||||||
this.vehicleForm.plateNoBody = plateNoBody;
|
this.vehicleForm.plateNoBody = plateNoBody;
|
||||||
this.vehicleForm.plateNo = plateProvince && plateNoBody ? `${plateProvince}${plateNoBody}` : '';
|
this.vehicleForm.plateNo =
|
||||||
|
plateProvince && plateNoBody ? `${plateProvince}${plateNoBody}` : '';
|
||||||
this.vehicleForm.plateColor = plateColor;
|
this.vehicleForm.plateColor = plateColor;
|
||||||
if (validate) {
|
if (validate) {
|
||||||
this.$refs.vehicleForm?.validateField('plateNo');
|
this.$refs.vehicleForm?.validateField('plateNo');
|
||||||
@@ -938,7 +1042,8 @@ export default {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleExpireChange() {
|
handleExpireChange(expireStatus) {
|
||||||
|
this.query.expireStatus = expireStatus;
|
||||||
this.page.currentPage = 1;
|
this.page.currentPage = 1;
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
},
|
},
|
||||||
@@ -952,7 +1057,9 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
searchReset() {
|
searchReset() {
|
||||||
this.searchForm = {};
|
this.searchForm = {
|
||||||
|
businessRelation: '',
|
||||||
|
};
|
||||||
this.query = {
|
this.query = {
|
||||||
expireStatus: this.query.expireStatus,
|
expireStatus: this.query.expireStatus,
|
||||||
};
|
};
|
||||||
@@ -1053,14 +1160,44 @@ export default {
|
|||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
|
getCertificationStatus(row) {
|
||||||
|
if (row.certificationStatus === 0) return { label: '认证中', type: 'warning' };
|
||||||
|
if (row.certificationStatus === 1) return { label: '已认证', type: 'success' };
|
||||||
|
if (row.certificationStatus === 2) return { label: '已驳回', type: 'danger' };
|
||||||
|
const today = this.$dayjs().startOf('day');
|
||||||
|
const certificateDates = [
|
||||||
|
[row.drivingLicenseEndDate, row.drivingLicenseLongTerm],
|
||||||
|
[row.roadTransportCertEndDate, row.roadTransportCertLongTerm],
|
||||||
|
];
|
||||||
|
if (certificateDates.some(([date, longTerm]) => longTerm !== 1 && !date)) {
|
||||||
|
return { label: '未认证', type: 'info' };
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
certificateDates.some(
|
||||||
|
([date, longTerm]) => longTerm !== 1 && this.$dayjs(date).isBefore(today, 'day')
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return { label: '已过期', type: 'danger' };
|
||||||
|
}
|
||||||
|
return { label: '已认证', type: 'success' };
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.transport-vehicle-page {
|
.transport-vehicle-page {
|
||||||
.vehicle-stat {
|
&__expiry-tags {
|
||||||
flex-shrink: 0;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
:deep(.el-check-tag) {
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-table th .cell),
|
:deep(.el-table th .cell),
|
||||||
@@ -1070,19 +1207,6 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.vehicle-form {
|
.vehicle-form {
|
||||||
.section-title {
|
|
||||||
margin: 18px 0 14px;
|
|
||||||
padding-left: 10px;
|
|
||||||
border-left: 3px solid #e74b5f;
|
|
||||||
color: #303133;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-date-editor.el-input),
|
:deep(.el-date-editor.el-input),
|
||||||
:deep(.el-date-editor.el-input__wrapper),
|
:deep(.el-date-editor.el-input__wrapper),
|
||||||
:deep(.el-select),
|
:deep(.el-select),
|
||||||
@@ -1149,9 +1273,9 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 大尺寸证件照:按身份证 1.586:1 比例缩放(约真实尺寸 75%,240×151),左对齐显示
|
||||||
:deep(.vehicle-uploader) {
|
:deep(.vehicle-uploader) {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.vehicle-uploader .el-upload),
|
:deep(.vehicle-uploader .el-upload),
|
||||||
@@ -1166,9 +1290,17 @@ export default {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 大尺寸模式:缩成 1.586:1 比例,左对齐(不再 100% 占栏)
|
||||||
|
:deep(.vehicle-uploader--large) {
|
||||||
|
display: block;
|
||||||
|
width: 240px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.vehicle-uploader--large .el-upload),
|
:deep(.vehicle-uploader--large .el-upload),
|
||||||
:deep(.vehicle-uploader--large.el-upload) {
|
:deep(.vehicle-uploader--large.el-upload) {
|
||||||
height: 260px;
|
width: 100%;
|
||||||
|
height: 151px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.vehicle-uploader__image) {
|
:deep(.vehicle-uploader__image) {
|
||||||
@@ -1188,7 +1320,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.date-warning {
|
.date-warning {
|
||||||
color: #f56c6c;
|
color: #d40000;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export default {
|
|||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
viewBtn: true,
|
viewBtn: true,
|
||||||
menuWidth: 160,
|
menuWidth: 180,
|
||||||
dialogWidth: 880,
|
dialogWidth: 880,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user