diff --git a/docs/backend-stubs/transit/risk-disposal/RiskDisposalBackend.md b/docs/backend-stubs/transit/risk-disposal/RiskDisposalBackend.md new file mode 100644 index 0000000..ca8f261 --- /dev/null +++ b/docs/backend-stubs/transit/risk-disposal/RiskDisposalBackend.md @@ -0,0 +1,76 @@ +# 风险处置后端接口契约 + +> 当前仓库为前端工程,无 Java 后端源码。本文件提供 BladeX 后端落库与接口实现契约,路径需放入 `blade-transport` 服务。 + +## Controller + +```java +@RestController +@AllArgsConstructor +@RequestMapping("/risk-disposal") +@Api(value = "风险处置", tags = "风险处置") +public class RiskDisposalController { + + private final IRiskDisposalService riskDisposalService; + + @GetMapping("/list") + public R> list(RiskDisposalQuery query, Query page) { + IPage pages = riskDisposalService.selectRiskDisposalPage(Condition.getPage(page), query); + return R.data(pages); + } + + @GetMapping("/detail") + public R detail(Long id) { + return R.data(riskDisposalService.detail(id)); + } + + @PostMapping("/dispose") + public R dispose(@Valid @RequestBody RiskDisposalDTO dto) { + return R.status(riskDisposalService.dispose(dto)); + } + + @PostMapping("/batch-dispose") + public R batchDispose(@Valid @RequestBody RiskDisposalBatchDTO dto) { + return R.status(riskDisposalService.batchDispose(dto)); + } +} +``` + +## 字段约定 + +- `riskLevel`: `low` 低,`medium` 中,`high` 高 +- `disposalStatus`: `pending` 待处理,`processed` 已处理,`ignored` 已忽略 +- `disposalMethod`: `process` 处理,`ignore` 忽略 +- 列表默认按 `create_time DESC` 返回 +- `riskNo` 由后端生成:`RK + yyyyMMdd + 3位流水号` + +## 接口 + +- `GET /blade-transport/risk-disposal/list` +- `GET /blade-transport/risk-disposal/detail?id=` +- `POST /blade-transport/risk-disposal/dispose` +- `POST /blade-transport/risk-disposal/batch-dispose` + +## DTO + +```java +@Data +public class RiskDisposalDTO { + @NotNull(message = "风险ID不能为空") + private Long id; + @NotBlank(message = "请选择处理方式") + private String disposalMethod; + @Length(max = 500, message = "处置说明不能超过500个字符") + private String disposalRemark; +} + +@Data +public class RiskDisposalBatchDTO { + @NotEmpty(message = "风险ID不能为空") + private List ids; + @NotBlank(message = "请选择处理方式") + private String disposalMethod; + @Length(max = 500, message = "处置说明不能超过500个字符") + private String disposalRemark; +} +``` diff --git a/docs/backend-stubs/transit/track-tracking/TrackTrackingBackend.md b/docs/backend-stubs/transit/track-tracking/TrackTrackingBackend.md new file mode 100644 index 0000000..a03827f --- /dev/null +++ b/docs/backend-stubs/transit/track-tracking/TrackTrackingBackend.md @@ -0,0 +1,27 @@ +# 在途追踪后端接口契约 + +## 接口 + +- `GET /blade-transport/track-tracking/map` +- `GET /blade-transport/track-tracking/ship` + +## 建议返回 + +```json +{ + "code": 200, + "success": true, + "data": { + "siteName": "XX园区A门", + "address": "南宁市邕宁区龙岗大道21号", + "coordinates": "108.348610;22.721864", + "records": [] + } +} +``` + +## 说明 + +- `map` 用于轨迹查询 +- `ship` 用于船舶查询 +- 当前前端先做高德地图占位,后端可先只返回基础信息和轨迹点数组 diff --git a/docs/sql/transit/risk-disposal.sql b/docs/sql/transit/risk-disposal.sql new file mode 100644 index 0000000..f35e515 --- /dev/null +++ b/docs/sql/transit/risk-disposal.sql @@ -0,0 +1,66 @@ +-- 风险处置模块初始化脚本 +-- 父菜单:在途管理 + +INSERT INTO `blade_menu` ( + `id`, `parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, + `remark`, `tenant_id`, `create_user`, `create_dept`, `create_time`, `update_user`, `update_time`, `status`, + `is_deleted` +) VALUES ( + '1710000000000000001', 0, 'transit_manage', '在途管理', 'transit_manage', '/transit', 'el-icon-truck', + 20, 1, 1, 1, '在途管理父菜单', '000000', 1, 1, NOW(), 1, NOW(), 1, 0 +); + +INSERT INTO `blade_menu` ( + `id`, `parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, + `remark`, `tenant_id`, `create_user`, `create_dept`, `create_time`, `update_user`, `update_time`, `status`, + `is_deleted` +) VALUES ( + '1710000000000000002', '1710000000000000001', 'risk_disposal', '风险处置', 'risk_disposal', + '/transit/risk-disposal', 'el-icon-warning-outline', 20, 1, 1, 1, '风险处置页面', + '000000', 1, 1, NOW(), 1, NOW(), 1, 0 +); + +INSERT INTO `blade_menu` ( + `id`, `parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, + `remark`, `tenant_id`, `create_user`, `create_dept`, `create_time`, `update_user`, `update_time`, `status`, + `is_deleted` +) VALUES +('1710000000000000003', '1710000000000000002', 'risk_disposal_query', '查询', 'risk_disposal_query', '', '', 10, 2, 1, 1, '风险处置查询权限', '000000', 1, 1, NOW(), 1, NOW(), 1, 0), +('1710000000000000004', '1710000000000000002', 'risk_disposal_process', '处理', 'risk_disposal_process', '', '', 20, 2, 1, 1, '风险处置处理权限', '000000', 1, 1, NOW(), 1, NOW(), 1, 0), +('1710000000000000005', '1710000000000000002', 'risk_disposal_ignore', '忽略', 'risk_disposal_ignore', '', '', 30, 2, 1, 1, '风险处置忽略权限', '000000', 1, 1, NOW(), 1, NOW(), 1, 0), +('1710000000000000006', '1710000000000000002', 'risk_disposal_batch_process', '批量处理', 'risk_disposal_batch_process', '', '', 40, 2, 1, 1, '风险处置批量处理权限', '000000', 1, 1, NOW(), 1, NOW(), 1, 0), +('1710000000000000007', '1710000000000000002', 'risk_disposal_batch_ignore', '批量忽略', 'risk_disposal_batch_ignore', '', '', 50, 2, 1, 1, '风险处置批量忽略权限', '000000', 1, 1, NOW(), 1, NOW(), 1, 0), +('1710000000000000008', '1710000000000000002', 'risk_disposal_view', '查看', 'risk_disposal_view', '', '', 60, 2, 1, 1, '风险处置查看权限', '000000', 1, 1, NOW(), 1, NOW(), 1, 0); + +CREATE TABLE IF NOT EXISTS `tms_risk_disposal` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` varchar(12) DEFAULT '000000' COMMENT '租户ID', + `risk_no` varchar(30) NOT NULL COMMENT '风险编号', + `rule_name` varchar(50) NOT NULL COMMENT '规则名称', + `waybill_id` bigint DEFAULT NULL COMMENT '运单ID', + `waybill_no` varchar(30) DEFAULT NULL COMMENT '运单号', + `project_id` bigint DEFAULT NULL COMMENT '项目ID', + `project_name` varchar(50) DEFAULT NULL COMMENT '项目名称', + `risk_level` varchar(20) NOT NULL COMMENT '风险等级:low/medium/high', + `transport_type` varchar(20) DEFAULT NULL COMMENT '运输类型', + `risk_description` varchar(500) DEFAULT NULL COMMENT '风险描述', + `trigger_time` datetime DEFAULT NULL COMMENT '触发时间', + `disposal_status` varchar(20) NOT NULL DEFAULT 'pending' COMMENT '处理状态:pending/processed/ignored', + `disposal_method` varchar(20) DEFAULT NULL COMMENT '处理方式:process/ignore', + `disposal_remark` varchar(500) DEFAULT NULL COMMENT '处置说明', + `dispose_user` bigint DEFAULT NULL COMMENT '处置人', + `dispose_user_name` varchar(50) DEFAULT NULL COMMENT '处置人名称', + `dispose_time` datetime DEFAULT NULL COMMENT '处置时间', + `create_user` bigint DEFAULT NULL COMMENT '创建人', + `create_dept` bigint DEFAULT NULL COMMENT '创建部门', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_user` bigint DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `status` int DEFAULT 1 COMMENT '状态', + `is_deleted` int DEFAULT 0 COMMENT '是否已删除', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_tms_risk_disposal_no` (`risk_no`), + KEY `idx_tms_risk_disposal_status` (`disposal_status`), + KEY `idx_tms_risk_disposal_level` (`risk_level`), + KEY `idx_tms_risk_disposal_waybill` (`waybill_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='风险处置'; diff --git a/docs/sql/transit/track-tracking.sql b/docs/sql/transit/track-tracking.sql new file mode 100644 index 0000000..8decdfa --- /dev/null +++ b/docs/sql/transit/track-tracking.sql @@ -0,0 +1,29 @@ +-- 在途追踪模块初始化脚本 + +INSERT INTO `blade_menu` ( + `id`, `parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, + `remark`, `tenant_id`, `create_user`, `create_dept`, `create_time`, `update_user`, `update_time`, `status`, + `is_deleted` +) VALUES ( + '1720000000000000001', 0, 'transit_manage', '在途管理', 'transit_manage', '/transit', 'el-icon-truck', + 20, 1, 1, 1, '在途管理父菜单', '000000', 1, 1, NOW(), 1, NOW(), 1, 0 +); + +INSERT INTO `blade_menu` ( + `id`, `parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, + `remark`, `tenant_id`, `create_user`, `create_dept`, `create_time`, `update_user`, `update_time`, `status`, + `is_deleted` +) VALUES ( + '1720000000000000002', '1720000000000000001', 'track_tracking', '在途追踪', 'track_tracking', + '/transit/track-tracking', 'el-icon-position', 10, 1, 1, 1, '在途追踪页面', + '000000', 1, 1, NOW(), 1, NOW(), 1, 0 +); + +INSERT INTO `blade_menu` ( + `id`, `parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, + `remark`, `tenant_id`, `create_user`, `create_dept`, `create_time`, `update_user`, `update_time`, `status`, + `is_deleted` +) VALUES +('1720000000000000003', '1720000000000000002', 'track_tracking_query', '查询', 'track_tracking_query', '', '', 10, 2, 1, 1, '在途追踪查询权限', '000000', 1, 1, NOW(), 1, NOW(), 1, 0), +('1720000000000000004', '1720000000000000002', 'track_tracking_ship_query', '船舶查询', 'track_tracking_ship_query', '', '', 20, 2, 1, 1, '在途追踪船舶查询权限', '000000', 1, 1, NOW(), 1, NOW(), 1, 0), +('1720000000000000005', '1720000000000000002', 'track_tracking_refresh', '刷新', 'track_tracking_refresh', '', '', 30, 2, 1, 1, '在途追踪刷新权限', '000000', 1, 1, NOW(), 1, NOW(), 1, 0); diff --git a/src/api/business/process-config.js b/src/api/business/process-config.js index 21a3bc4..a43262c 100644 --- a/src/api/business/process-config.js +++ b/src/api/business/process-config.js @@ -1,9 +1,24 @@ +import request from '@/axios'; import { createCrudApi } from './common'; const api = createCrudApi('/blade-transport/process-config'); export const getList = api.getList; -export const getDetail = api.getDetail; +export const getDetail = (id, waybillId) => + request({ + url: '/blade-transport/process-config/detail', + method: 'get', + params: { + id, + ...(waybillId === undefined ? {} : { waybillId }), + }, + }); +export const getVoucherImages = waybillId => + request({ + url: '/blade-transport/process-config/voucher-images', + method: 'get', + params: { waybillId }, + }); export const submit = api.submit; export const remove = api.remove; export const copy = api.copy; diff --git a/src/api/business/voucher-manage.js b/src/api/business/voucher-manage.js new file mode 100644 index 0000000..3f3ccd5 --- /dev/null +++ b/src/api/business/voucher-manage.js @@ -0,0 +1,39 @@ +import request from '@/axios'; + +const baseUrl = '/blade-transport/voucher-manage'; + +export const getList = (current, size, params) => + request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } }); +export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get', params: { id } }); +export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data }); +export const createUploadDraft = data => + request({ url: `${baseUrl}/upload-draft`, method: 'post', data }); +export const completeUploadFile = data => + request({ url: `${baseUrl}/complete-upload-file`, method: 'post', data }); +export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } }); +export const getWaybillBatches = (current, size, params) => + request({ + url: `${baseUrl}/waybill-batches`, + method: 'get', + params: { current, size, ...params }, + }); + +const fileTaskBaseUrl = '/blade-file/fileTask'; +export const queryFileTask = md5 => + request({ url: `${fileTaskBaseUrl}/queryFileTask`, method: 'get', params: { md5 } }); +export const getFileTask = id => + request({ url: `${fileTaskBaseUrl}/queryFileTask`, method: 'get', params: { id } }); +export const createFileTask = data => + request({ url: `${fileTaskBaseUrl}/createFileTask`, method: 'post', data }); +export const getPartUploadUrl = (id, partNumber) => + request({ url: `${fileTaskBaseUrl}/getUploadUrl`, method: 'get', params: { id, partNumber } }); +export const updateFileTask = data => + request({ url: `${fileTaskBaseUrl}/updateFileTask`, method: 'post', data }); +export const pauseFileTask = ids => + request({ url: `${fileTaskBaseUrl}/updatePaused`, method: 'post', data: { ids } }); +export const resumeFileTask = id => + request({ url: `${fileTaskBaseUrl}/resume`, method: 'post', params: { id } }); +export const getFileTaskList = (current, size, params) => + request({ url: `${fileTaskBaseUrl}/list`, method: 'get', params: { current, size, ...params } }); +export const getFileTaskUrl = id => + request({ url: `${fileTaskBaseUrl}/file-url`, method: 'get', params: { id } }); diff --git a/src/api/business/waybill-manage.js b/src/api/business/waybill-manage.js index 07f3d35..220dd24 100644 --- a/src/api/business/waybill-manage.js +++ b/src/api/business/waybill-manage.js @@ -13,6 +13,12 @@ export const cancel = api.cancel; export const reassign = api.reassign; export const complete = api.complete; export const batchComplete = api.batchComplete; +export const changeRoute = data => + request({ + url: `${baseUrl}/change-route`, + method: 'post', + data, + }); export const roadLoading = ids => request({ url: `${baseUrl}/road-loading`, @@ -26,7 +32,6 @@ export const getImportBatches = params => request({ url: `${baseUrl}/import-batc export const getImportDetails = params => request({ url: `${baseUrl}/import-batch/details`, method: 'get', params }); export const removeImportBatches = ids => request({ url: `${baseUrl}/import-batch/remove`, method: 'post', params: { ids } }); export const getImportOptions = () => request({ url: `${baseUrl}/import-batch/options`, method: 'get' }); -export const getImportContracts = projectId => request({ url: `${baseUrl}/import-batch/contracts`, method: 'get', params: { projectId } }); export const exportImportTemplate = () => request({ url: `${baseUrl}/import-batch/export-template`, method: 'get', responseType: 'blob' }); export const saveImportDraft = data => request({ url: `${baseUrl}/import-batch/draft`, method: 'post', data }); export const confirmImport = data => request({ url: `${baseUrl}/import-batch/confirm`, method: 'post', data }); diff --git a/src/api/settlement/receivable-payable-detail.js b/src/api/settlement/receivable-payable-detail.js new file mode 100644 index 0000000..b9c9e80 --- /dev/null +++ b/src/api/settlement/receivable-payable-detail.js @@ -0,0 +1,54 @@ +import request from '@/axios'; + +const baseUrl = '/blade-transport/receivable-payable-detail'; + +export const getList = (current, size, params) => + request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } }); + +export const getFeeDetail = id => + request({ url: `${baseUrl}/fee-detail`, method: 'get', params: { id } }); + +export const getChangeRecords = (current, size, params) => + request({ + url: `${baseUrl}/change-records`, + method: 'get', + params: { current, size, ...params }, + }); + +export const updateFee = data => + request({ url: `${baseUrl}/update-fee`, method: 'post', data }); + +export const transferSettlement = data => + request({ url: `${baseUrl}/transfer-settlement`, method: 'post', data }); + +export const getTransferCandidates = (current, size, params) => + request({ + url: `${baseUrl}/transfer-candidates`, + method: 'get', + params: { current, size, ...params }, + }); + +export const getGenerateWaybills = (current, size, params) => + request({ + url: `${baseUrl}/generate-waybills`, + method: 'get', + params: { current, size, ...params }, + }); + +export const getGeneratePreview = (current, size, params) => + request({ + url: `${baseUrl}/generate-preview`, + method: 'get', + params: { current, size, ...params }, + }); + +export const generateFee = data => + request({ url: `${baseUrl}/generate-fee`, method: 'post', data }); + +export const exportDetail = params => + request({ + url: `${baseUrl}/export-receivable-payable-detail`, + method: 'get', + params, + responseType: 'blob', + }); diff --git a/src/api/transit/exception-disposal.js b/src/api/transit/exception-disposal.js new file mode 100644 index 0000000..4929b8b --- /dev/null +++ b/src/api/transit/exception-disposal.js @@ -0,0 +1,15 @@ +import request from '@/axios'; + +const baseUrl = '/blade-transport/exception-disposal'; + +export const getList = (current, size, params) => + request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } }); + +export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get', params: { id } }); + +export const follow = data => request({ url: `${baseUrl}/follow`, method: 'post', data }); + +export const complete = data => request({ url: `${baseUrl}/complete`, method: 'post', data }); + +export const batchComplete = ids => + request({ url: `${baseUrl}/batch-complete`, method: 'post', params: { ids } }); diff --git a/src/api/transit/risk-disposal.js b/src/api/transit/risk-disposal.js new file mode 100644 index 0000000..c761e38 --- /dev/null +++ b/src/api/transit/risk-disposal.js @@ -0,0 +1,13 @@ +import request from '@/axios'; + +const baseUrl = '/blade-transport/risk-disposal'; + +export const getList = (current, size, params) => + request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } }); + +export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get', params: { id } }); + +export const dispose = data => request({ url: `${baseUrl}/dispose`, method: 'post', data }); + +export const batchDispose = data => + request({ url: `${baseUrl}/batch-dispose`, method: 'post', data }); diff --git a/src/api/transit/track-tracking.js b/src/api/transit/track-tracking.js new file mode 100644 index 0000000..0a53a5f --- /dev/null +++ b/src/api/transit/track-tracking.js @@ -0,0 +1,9 @@ +import request from '@/axios'; + +const baseUrl = '/blade-transport/track-tracking'; + +export const getTrackingMap = params => + request({ url: `${baseUrl}/map`, method: 'get', params }); + +export const getShipTracking = params => + request({ url: `${baseUrl}/ship`, method: 'get', params }); diff --git a/src/option/base/common-address.js b/src/option/base/common-address.js index 4271ee1..2316d19 100644 --- a/src/option/base/common-address.js +++ b/src/option/base/common-address.js @@ -122,8 +122,7 @@ export const createOption = () => ({ maxlength: 20, formslot: true, rules: [ - { max: 20, message: '联系方式不能超过20个字', trigger: 'blur' }, - { pattern: /^\d*$/, message: '联系方式只能输入数字', trigger: 'blur' }, + { pattern: /^1[3-9]\d{9}$/, message: '联系方式格式不正确', trigger: 'blur' }, ], }, { diff --git a/src/option/business/common.js b/src/option/business/common.js index 9c2e976..7ac8431 100644 --- a/src/option/business/common.js +++ b/src/option/business/common.js @@ -36,7 +36,6 @@ export const planStatusOptions = [ { label: '待调度', value: 'waiting_dispatch' }, { label: '调度中', value: 'dispatching' }, { label: '已完成', value: 'completed' }, - { label: '已取消', value: 'cancelled' }, ]; export const waybillStatusOptions = [ @@ -172,7 +171,7 @@ export const nonNegativeRule = label => ({ }); export const phoneRule = label => ({ - pattern: /^(1\d{10}|0\d{2,3}-?\d{7,8})$/, + pattern: /^1[3-9]\d{9}$/, message: `${label}格式不正确`, trigger: 'blur', }); @@ -209,6 +208,21 @@ export const createCrudOption = columns => ({ column: columns, }); +export const withSearchPlaceholders = columns => + columns.map(column => { + if (!column.search || column.searchPlaceholder) return column; + if (column.type === 'date' || column.type === 'datetime' || column.searchRange) return column; + const isSelectSearch = + column.type === 'select' || + column.searchType === 'select' || + Boolean(column.dicData) || + Boolean(column.dicUrl); + return { + ...column, + searchPlaceholder: isSelectSearch ? '请选择' : '请输入', + }; + }); + export const auditColumns = [ { label: '创建人', diff --git a/src/option/business/loading-manage.js b/src/option/business/loading-manage.js index 007bd23..6f3e74e 100644 --- a/src/option/business/loading-manage.js +++ b/src/option/business/loading-manage.js @@ -8,7 +8,7 @@ export const transportTypeDict = { }, }; -export const carrierTypeOptions = ['承运商', '自运', '网签平台']; +export const carrierTypeOptions = ['承运商', '自运', '网货平台']; export const loadingStatusOptions = [ { label: '草稿', value: 'draft' }, @@ -28,6 +28,24 @@ export const loadingManageConfig = { permission: 'loading_manage', exportUrl: '/blade-transport/loading-manage/export-loading-manage', exportName: '配载管理', + exportColumns: [ + { prop: 'loadingNo', label: '配载单号' }, + { prop: 'loadingSubNos', label: '配载子单号' }, + { prop: 'vehicleNo', label: '车牌号/航班号/船号/班列号' }, + { prop: 'driverName', label: '司机' }, + { prop: 'driverPhone', label: '联系电话' }, + { prop: 'carrierType', label: '承运类型' }, + { prop: 'departureAddress', label: '发货地' }, + { prop: 'transitAddress', label: '途经地' }, + { prop: 'arrivalAddress', label: '到货地' }, + { prop: 'carrierName', label: '承运商' }, + { prop: 'transportType', label: '运输方式' }, + { prop: 'dataSource', label: '数据来源' }, + { prop: 'createTime', label: '创建时间' }, + { prop: 'updateTime', label: '更新时间' }, + { prop: 'currentProcessNode', label: '过程节点' }, + { prop: 'businessStatus', label: '状态' }, + ], createText: '新建配载', batchCompleteText: '批量完成', statusProp: 'businessStatus', diff --git a/src/option/business/shipping-template.js b/src/option/business/shipping-template.js index ab2cc73..fd40586 100644 --- a/src/option/business/shipping-template.js +++ b/src/option/business/shipping-template.js @@ -1,4 +1,11 @@ -import { auditColumns, createCrudOption, selectRule, textRule, transportTypeOptions } from './common'; +import { + auditColumns, + createCrudOption, + selectRule, + textRule, + transportTypeOptions, + withSearchPlaceholders, +} from './common'; const templateTypeOptions = [ { label: '运输计划', value: '运输计划' }, @@ -8,10 +15,31 @@ const templateTypeOptions = [ export const config = { title: '发货模板', permission: 'shipping_template', - exportUrl: '/blade-transport/shipping-template/export-shipping-template', - exportName: '发货模板', + tableColumnOrder: [ + 'templateCode', + 'templateName', + 'templateType', + 'transportType', + 'createUserName', + 'remark', + 'updateTime', + 'createTime', + ], + exportColumns: [ + { prop: 'templateCode', label: '模板编号' }, + { prop: 'templateName', label: '模板名称' }, + { prop: 'templateType', label: '模板类型' }, + { prop: 'transportType', label: '运输方式' }, + { prop: 'createUserName', label: '创建人' }, + { prop: 'remark', label: '备注' }, + { prop: 'updateTime', label: '更新时间' }, + { prop: 'createTime', label: '创建时间' }, + ], enableAllDept: false, enableProjectSelect: true, + projectQueryParams: { + approvalStatuses: 'approved,change_approved', + }, excludeVoidedProjects: true, enableAttachmentTable: true, enableTransportPlanForm: true, @@ -41,178 +69,206 @@ export const config = { }; export const option = { - ...createCrudOption([ - { - label: '', - prop: 'templateInfoTitle', - formslot: true, - span: 24, - order: 400, - hide: true, - labelWidth: 0, - }, - { - label: '模板编号', - prop: 'templateCode', - search: true, - searchOrder: 4, - span: 6, - order: 390, - minWidth: 170, - disabled: true, - placeholder: '系统自动生成', - }, - { - label: '模板名称', - prop: 'templateName', - search: true, - searchOrder: 3, - span: 6, - order: 380, - minWidth: 150, - rules: textRule('模板名称', 50, true), - }, - { - label: '模板类型', - prop: 'templateType', - type: 'select', - search: true, - searchOrder: 2, - span: 6, - order: 370, - dicData: templateTypeOptions, - minWidth: 120, - rules: selectRule('模板类型'), - }, - { - label: '备注', - prop: 'remark', - type: 'textarea', - minRows: 2, - span: 18, - order: 360, - minWidth: 180, - maxlength: 200, - showWordLimit: true, - rules: textRule('备注', 200), - }, - { - label: '', - prop: 'basicInfoTitle', - formslot: true, - span: 24, - order: 350, - hide: true, - labelWidth: 0, - }, - { - label: '项目', - prop: 'projectName', - formslot: true, - search: true, - searchOrder: 1, - span: 6, - order: 340, - minWidth: 150, - rules: textRule('项目', 100, true), - }, - { - label: '客户合同', - prop: 'contractName', - formslot: true, - span: 6, - order: 330, - minWidth: 160, - rules: textRule('客户合同', 100, true), - }, - { - label: '运输方式', - prop: 'transportType', - type: 'select', - span: 6, - order: 320, - dicData: transportTypeOptions, - minWidth: 130, - rules: selectRule('运输方式'), - }, - { - label: '', - prop: 'shippingInfoTitle', - formslot: true, - span: 24, - order: 310, - hide: true, - labelWidth: 0, - }, - { - label: '发货地址', - prop: 'departureAddress', - formslot: true, - span: 24, - order: 300, - minWidth: 220, - rules: textRule('发货地址', 255, true), - }, - { - label: '收货地址', - prop: 'arrivalAddress', - formslot: true, - span: 24, - order: 290, - minWidth: 220, - rules: textRule('收货地址', 255, true), - }, - { - label: '', - prop: 'goodsInfoTitle', - formslot: true, - span: 24, - order: 280, - hide: true, - labelWidth: 0, - }, - { - label: '', - prop: 'goodsJson', - type: 'textarea', - formslot: true, - span: 24, - order: 270, - hide: true, - labelWidth: '0px', - className: 'business-crud-page__full-form-item', - }, - { label: '运费信息', prop: 'freightJson', hide: true, display: false }, - { - label: '', - prop: 'attachmentTitle', - formslot: true, - span: 24, - order: 260, - hide: true, - labelWidth: 0, - }, - { - label: '', - prop: 'attachmentsJson', - type: 'textarea', - formslot: true, - span: 24, - order: 250, - hide: true, - labelWidth: '0px', - className: 'business-crud-page__full-form-item', - }, - { label: '项目ID', prop: 'projectId', hide: true, display: false }, - { label: '客户合同ID', prop: 'contractId', hide: true, display: false }, - { label: '发货地', prop: 'departureName', hide: true, display: false }, - { label: '发货联系人', prop: 'departureContact', hide: true, display: false }, - { label: '发货联系方式', prop: 'departurePhone', hide: true, display: false }, - { label: '收货地', prop: 'arrivalName', hide: true, display: false }, - { label: '收货联系人', prop: 'arrivalContact', hide: true, display: false }, - { label: '收货联系方式', prop: 'arrivalPhone', hide: true, display: false }, - { label: '所属组织', prop: 'deptName', minWidth: 150, addDisplay: false, editDisplay: false }, - ...auditColumns, - ]), + ...createCrudOption( + withSearchPlaceholders([ + { + label: '', + prop: 'templateInfoTitle', + formslot: true, + span: 24, + order: 400, + hide: true, + labelWidth: 0, + }, + { + label: '模板编号', + prop: 'templateCode', + search: true, + searchOrder: 4, + span: 8, + order: 390, + minWidth: 170, + disabled: true, + placeholder: '系统自动生成', + display: true, + }, + { + label: '模板名称', + prop: 'templateName', + search: true, + searchOrder: 3, + span: 8, + order: 380, + minWidth: 150, + rules: textRule('模板名称', 50, true), + display: true, + }, + { + label: '模板类型', + prop: 'templateType', + type: 'select', + search: true, + searchOrder: 2, + span: 8, + order: 370, + dicData: templateTypeOptions, + minWidth: 120, + rules: selectRule('模板类型'), + display: true, + }, + { + label: '备注', + prop: 'remark', + type: 'textarea', + minRows: 3, + span: 24, + order: 360, + minWidth: 180, + maxlength: 200, + showWordLimit: true, + rules: textRule('备注', 200), + display: true, + }, + { + label: '', + prop: 'basicInfoTitle', + formslot: true, + span: 24, + order: 350, + hide: true, + labelWidth: 0, + }, + { + label: '项目', + prop: 'projectName', + formslot: true, + search: true, + searchOrder: 1, + span: 8, + order: 340, + minWidth: 150, + rules: textRule('项目', 100, true), + display: true, + }, + { + label: '客户合同', + prop: 'contractName', + formslot: true, + span: 8, + order: 330, + minWidth: 160, + rules: textRule('客户合同', 100, true), + display: true, + }, + { + label: '运输方式', + prop: 'transportType', + type: 'select', + span: 8, + order: 320, + dicData: transportTypeOptions, + minWidth: 130, + rules: selectRule('运输方式'), + display: true, + }, + { + label: '备注', + prop: 'basicRemark', + type: 'textarea', + minRows: 3, + span: 24, + order: 315, + minWidth: 180, + maxlength: 200, + showWordLimit: true, + rules: textRule('备注', 200), + display: true, + }, + { + label: '', + prop: 'shippingInfoTitle', + formslot: true, + span: 24, + order: 310, + hide: true, + labelWidth: 0, + }, + { + label: '发货地址', + prop: 'departureAddress', + formslot: true, + span: 24, + order: 300, + minWidth: 220, + rules: textRule('发货地址', 255, true), + display: true, + }, + { + label: '收货地址', + prop: 'arrivalAddress', + formslot: true, + span: 24, + order: 290, + minWidth: 220, + rules: textRule('收货地址', 255, true), + display: true, + }, + { + label: '', + prop: 'goodsInfoTitle', + formslot: true, + span: 24, + order: 280, + hide: true, + labelWidth: 0, + }, + { + label: '', + prop: 'goodsJson', + type: 'textarea', + formslot: true, + span: 24, + order: 270, + hide: true, + labelWidth: '0px', + className: 'business-crud-page__full-form-item', + }, + { label: '运费信息', prop: 'freightJson', hide: true, display: false }, + { + label: '', + prop: 'attachmentTitle', + formslot: true, + span: 24, + order: 260, + hide: true, + labelWidth: 0, + }, + { + label: '', + prop: 'attachmentsJson', + type: 'textarea', + formslot: true, + span: 24, + order: 250, + hide: true, + labelWidth: '0px', + className: 'business-crud-page__full-form-item', + }, + { label: '项目ID', prop: 'projectId', hide: true, display: false }, + { label: '客户合同ID', prop: 'contractId', hide: true, display: false }, + { label: '发货地', prop: 'departureName', hide: true, display: false }, + { label: '发货联系人', prop: 'departureContact', hide: true, display: false }, + { label: '发货联系方式', prop: 'departurePhone', hide: true, display: false }, + { label: '收货地', prop: 'arrivalName', hide: true, display: false }, + { label: '收货联系人', prop: 'arrivalContact', hide: true, display: false }, + { label: '收货联系方式', prop: 'arrivalPhone', hide: true, display: false }, + { label: '所属组织', prop: 'deptName', minWidth: 150, addDisplay: false, editDisplay: false, display: false }, + ...auditColumns.map(column => ({ + ...column, + display: false, + })), + ]) + ), dialogWidth: '96%', + dialogTop: '10px', }; diff --git a/src/option/business/transport-plan.js b/src/option/business/transport-plan.js index 2a80001..b4a537c 100644 --- a/src/option/business/transport-plan.js +++ b/src/option/business/transport-plan.js @@ -6,6 +6,7 @@ import { planStatusOptions, selectRule, textRule, + withSearchPlaceholders, } from './common'; const listDicFormatter = res => { @@ -104,8 +105,55 @@ const formatGoodsInfo = row => { return text || row.goodsInfo || ''; }; -const formatDispatchProgress = row => - row.dispatchProgressName || row.dispatchProgress || row.progress || ''; +const parseDispatchRows = row => { + const sources = [ + row.dispatchRows, + row.dispatchList, + row.dispatchRecords, + row.waybillList, + row.waybillRows, + ]; + for (const source of sources) { + const rows = parseGoodsRows(source); + if (rows.length) return rows; + } + return []; +}; + +const formatDispatchQuantity = value => { + const number = Number(value || 0); + if (!Number.isFinite(number)) return '0'; + const fixed = Math.round((number + Number.EPSILON) * 1000) / 1000; + return Number.isInteger(fixed) ? String(fixed) : String(fixed).replace(/\.?0+$/, ''); +}; + +const formatDispatchProgress = row => { + const goodsRows = parseGoodsRows(row.goodsJson); + const totalRows = goodsRows.length ? goodsRows : [row]; + const dispatchRows = parseDispatchRows(row); + const summary = new Map(); + const add = (item, field) => { + const unit = item.quantityUnit || item.goodsQuantityUnit || item.unit || '吨'; + const quantity = Number(item.quantity || item.cargoQuantity || item.goodsQuantity || 0); + if (!summary.has(unit)) summary.set(unit, { total: 0, assigned: 0 }); + if (Number.isFinite(quantity)) summary.get(unit)[field] += quantity; + }; + totalRows.forEach(item => add(item, 'total')); + dispatchRows.forEach(item => add(item, 'assigned')); + + if (!dispatchRows.length) { + const assigned = Number(row.dispatchedQuantity || row.dispatchQuantity || 0); + if (Number.isFinite(assigned)) { + const unit = row.quantityUnit || row.goodsQuantityUnit || row.unit || '吨'; + if (!summary.has(unit)) summary.set(unit, { total: 0, assigned: 0 }); + summary.get(unit).assigned = assigned; + } + } + const lines = Array.from(summary.entries()).map( + ([unit, item]) => `${formatDispatchQuantity(item.assigned)}/${formatDispatchQuantity(item.total)}${unit}` + ); + return lines.length ? lines.join('\n') : row.dispatchProgressName || row.dispatchProgress || row.progress || ''; +}; const auditColumn = prop => ({ ...auditColumns.find(item => item.prop === prop) }); @@ -116,11 +164,15 @@ export const config = { exportName: '运输计划', enableAllDept: false, enableProjectSelect: true, + projectQueryParams: { + approvalStatuses: 'approved,change_approved', + }, templateCreateTarget: 'transport-plan', enableAttachmentTable: true, enableTransportPlanForm: true, enableTransportPlanCreateActions: true, enableTransportPlanImport: true, + fixedTransportAddressType: true, transportPlanImportTitle: '导入发货计划', transportPlanTemplateUrl: '/blade-transport/transport-plan/export-template', attachmentTitle: '附件', @@ -128,10 +180,10 @@ export const config = { planStartDateRange: ['planStartDateStart', 'planStartDateEnd'], planEndDateRange: ['planEndDateStart', 'planEndDateEnd'], }, - actions: ['copy', 'cancel', 'complete'], + actions: ['copy', 'complete'], statusProp: 'businessStatus', statusTextProp: 'businessStatusName', - deleteStatus: ['draft'], + deleteStatus: ['draft', 'waiting_dispatch'], editStatus: ['draft', 'waiting_dispatch'], detailButton: true, detailSections: [ @@ -177,7 +229,7 @@ export const config = { action: 'dispatch', label: '调度', statusProp: 'businessStatus', - status: ['waiting_dispatch'], + status: ['waiting_dispatch', 'dispatching'], permission: 'transport_plan_edit', confirm: '确定调度该运输计划?', }, @@ -185,367 +237,370 @@ export const config = { }; export const option = { - ...createCrudOption([ - { - label: '', - prop: 'basicInfoTitle', - formslot: true, - span: 24, - order: 400, - hide: true, - labelWidth: 0, - }, - { - label: '计划单号', - prop: 'planNo', - search: true, - searchOrder: 13, - span: 6, - order: 370, - minWidth: 150, - disabled: true, - placeholder: '系统自动生成', - }, - { - label: '计划名称', - prop: 'planName', - search: true, - searchOrder: 12, - span: 6, - order: 380, - minWidth: 150, - rules: textRule('计划名称', 50, true), - }, - { - label: '运输方式', - prop: 'transportType', - type: 'select', - search: true, - searchOrder: 10, - span: 6, - order: 360, - dicUrl: '/blade-system/dict-biz/dictionary?code=transport_type', - props: { - label: 'dictValue', - value: 'dictKey', + ...createCrudOption( + withSearchPlaceholders([ + { + label: '', + prop: 'basicInfoTitle', + formslot: true, + span: 24, + order: 400, + hide: true, + labelWidth: 0, }, - minWidth: 130, - rules: selectRule('运输类型'), - }, - { - label: '货物信息', - prop: 'goodsInfo', - formatter: row => formatGoodsInfo(row), - minWidth: 320, - className: 'business-crud-page__goods-info-cell', - overHidden: false, - showOverflowTooltip: false, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '调度进度', - prop: 'dispatchProgress', - formatter: row => formatDispatchProgress(row), - minWidth: 120, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '发货地址', - prop: 'departureAddress', - formslot: true, - search: true, - searchOrder: 7, - span: 24, - order: 310, - minWidth: 220, - rules: textRule('发货地址', 255, true), - }, - { - label: '到货地址', - prop: 'arrivalAddress', - formslot: true, - search: true, - searchOrder: 6, - span: 24, - order: 300, - minWidth: 220, - rules: textRule('收货地址', 255, true), - }, - { - label: '项目名称', - prop: 'projectName', - formslot: true, - search: true, - searchOrder: 11, - searchType: 'select', - span: 6, - order: 400, - dicUrl: '/blade-transport/project-apply/list?current=1&size=9999', - dicFormatter: listDicFormatter, - props: { - label: 'projectName', - value: 'projectName', + { + label: '计划单号', + prop: 'planNo', + search: true, + searchOrder: 13, + span: 6, + order: 370, + minWidth: 150, + disabled: true, + placeholder: '系统自动生成', }, - filterable: true, - minWidth: 150, - rules: textRule('项目', 100, true), - }, - { - label: '客户名称', - prop: 'customerName', - search: true, - searchOrder: 5, - minWidth: 150, - addDisplay: false, - editDisplay: false, - }, - { - label: '计划开始日期', - prop: 'planStartDate', - sortable: true, - type: 'date', - format: 'YYYY-MM-DD', - valueFormat: 'YYYY-MM-DD', - span: 6, - order: 350, - minWidth: 130, - }, - { - label: '计划结束日期', - prop: 'planEndDate', - sortable: true, - type: 'date', - format: 'YYYY-MM-DD', - valueFormat: 'YYYY-MM-DD', - span: 6, - order: 340, - minWidth: 130, - }, - { - label: '数据来源', - prop: 'dataSource', - type: 'select', - search: true, - searchOrder: 1, - dicData: dataSourceOptions, - minWidth: 120, - addDisplay: false, - editDisplay: false, - }, - { - label: '货物类型', - prop: 'cargoType', - search: true, - searchOrder: 8, - formatter: row => formatGoodsField(row, ['cargoType', 'goodsType']), - minWidth: 130, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '货物名称', - prop: 'cargoName', - search: true, - searchOrder: 9, - formatter: row => formatGoodsField(row, ['cargoName', 'goodsName']), - minWidth: 150, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '备注', - prop: 'remark', - type: 'textarea', - minRows: 2, - span: 24, - order: 330, - minWidth: 180, - maxlength: 200, - showWordLimit: true, - rules: textRule('备注', 200), - }, - { - ...auditColumn('updateUserName'), - }, - { - ...auditColumn('createTime'), - }, - { - ...auditColumn('updateTime'), - }, - { - label: '调度状态', - prop: 'businessStatus', - type: 'select', - slot: true, - search: true, - searchLabel: '状态', - searchOrder: 2, - dicData: planStatusOptions, - minWidth: 120, - fixed: 'right', - addDisplay: false, - editDisplay: false, - }, - { - label: '', - prop: 'shippingInfoTitle', - formslot: true, - span: 24, - order: 320, - hide: true, - labelWidth: 0, - }, - { - label: '项目ID', - prop: 'projectId', - hide: true, - display: false, - }, - { - label: '客户合同', - prop: 'contractName', - formslot: true, - hide: true, - span: 6, - order: 390, - minWidth: 160, - rules: textRule('客户合同', 100, true), - }, - { - label: '客户合同ID', - prop: 'contractId', - hide: true, - display: false, - }, - { - label: '发货地', - prop: 'departureName', - hide: true, - display: false, - minWidth: 140, - rules: textRule('发货地', 100, true), - }, - { - label: '收货地', - prop: 'arrivalName', - hide: true, - display: false, - minWidth: 140, - rules: textRule('收货地', 100, true), - }, - { - label: '发货联系人', - prop: 'departureContact', - hide: true, - display: false, - rules: textRule('发货联系人', 50), - }, - { - label: '发货联系方式', - prop: 'departurePhone', - hide: true, - display: false, - rules: [phoneRule('发货联系方式'), ...textRule('发货联系方式', 50)], - }, - { - label: '收货联系人', - prop: 'arrivalContact', - hide: true, - display: false, - rules: textRule('收货联系人', 50), - }, - { - label: '收货联系方式', - prop: 'arrivalPhone', - hide: true, - display: false, - rules: [phoneRule('收货联系方式'), ...textRule('收货联系方式', 50)], - }, - { - label: '', - prop: 'goodsInfoTitle', - formslot: true, - span: 24, - order: 280, - hide: true, - labelWidth: 0, - }, - { - label: '计划开始日期', - prop: 'planStartDateRange', - type: 'date', - format: 'YYYY-MM-DD', - valueFormat: 'YYYY-MM-DD', - search: true, - searchRange: true, - searchOrder: 4, - hide: true, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '计划结束日期', - prop: 'planEndDateRange', - type: 'date', - format: 'YYYY-MM-DD', - valueFormat: 'YYYY-MM-DD', - search: true, - searchRange: true, - searchOrder: 3, - hide: true, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '所属组织', - prop: 'deptName', - hide: true, - minWidth: 150, - addDisplay: false, - editDisplay: false, - }, - { - label: '', - prop: 'goodsJson', - type: 'textarea', - formslot: true, - minRows: 5, - span: 24, - order: 270, - hide: true, - labelWidth: '0px', - className: 'business-crud-page__full-form-item', - }, - { - label: '', - prop: 'attachmentTitle', - formslot: true, - span: 24, - order: 265, - hide: true, - labelWidth: 0, - }, - { - label: '', - prop: 'attachmentsJson', - type: 'textarea', - formslot: true, - minRows: 2, - span: 24, - order: 260, - hide: true, - labelWidth: '0px', - className: 'business-crud-page__full-form-item', - }, - ]), + { + label: '计划名称', + prop: 'planName', + search: true, + searchOrder: 12, + span: 6, + order: 380, + minWidth: 150, + rules: textRule('计划名称', 50, true), + }, + { + label: '运输方式', + prop: 'transportType', + type: 'select', + search: true, + searchOrder: 10, + span: 6, + order: 360, + dicUrl: '/blade-system/dict-biz/dictionary?code=transport_type', + props: { + label: 'dictValue', + value: 'dictKey', + }, + minWidth: 130, + rules: selectRule('运输类型'), + }, + { + label: '货物信息', + prop: 'goodsInfo', + formatter: row => formatGoodsInfo(row), + minWidth: 320, + className: 'business-crud-page__goods-info-cell', + overHidden: false, + showOverflowTooltip: false, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '调度进度', + prop: 'dispatchProgress', + formatter: row => formatDispatchProgress(row), + minWidth: 120, + className: 'business-crud-page__dispatch-progress-cell', + overHidden: false, + showOverflowTooltip: false, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '发货地址', + prop: 'departureAddress', + formslot: true, + search: true, + searchOrder: 7, + span: 24, + order: 310, + minWidth: 220, + rules: textRule('发货地址', 255, true), + }, + { + label: '到货地址', + prop: 'arrivalAddress', + formslot: true, + search: true, + searchOrder: 6, + span: 24, + order: 300, + minWidth: 220, + rules: textRule('收货地址', 255, true), + }, + { + label: '项目名称', + prop: 'projectName', + formslot: true, + search: true, + searchOrder: 11, + searchType: 'select', + span: 6, + order: 400, + dicUrl: '/blade-transport/project-apply/list?current=1&size=9999', + dicFormatter: listDicFormatter, + props: { + label: 'projectName', + value: 'projectName', + }, + filterable: true, + minWidth: 150, + rules: textRule('项目', 100, true), + }, + { + label: '客户名称', + prop: 'customerName', + search: true, + searchOrder: 5, + minWidth: 150, + addDisplay: false, + editDisplay: false, + }, + { + label: '计划开始日期', + prop: 'planStartDate', + type: 'date', + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + span: 6, + order: 350, + minWidth: 150, + }, + { + label: '计划结束日期', + prop: 'planEndDate', + type: 'date', + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + span: 6, + order: 340, + minWidth: 150, + }, + { + label: '数据来源', + prop: 'dataSource', + type: 'select', + search: true, + searchOrder: 1, + dicData: dataSourceOptions, + minWidth: 120, + addDisplay: false, + editDisplay: false, + }, + { + label: '货物类型', + prop: 'cargoType', + search: true, + searchOrder: 8, + formatter: row => formatGoodsField(row, ['cargoType', 'goodsType']), + minWidth: 130, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '货物名称', + prop: 'cargoName', + search: true, + searchOrder: 9, + formatter: row => formatGoodsField(row, ['cargoName', 'goodsName']), + minWidth: 150, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '备注', + prop: 'remark', + type: 'textarea', + minRows: 4, + span: 24, + order: 330, + minWidth: 180, + maxlength: 200, + showWordLimit: true, + rules: textRule('备注', 200), + }, + { + ...auditColumn('updateUserName'), + }, + { + ...auditColumn('createTime'), + }, + { + ...auditColumn('updateTime'), + }, + { + label: '调度状态', + prop: 'businessStatus', + type: 'select', + slot: true, + search: true, + searchLabel: '状态', + searchOrder: 2, + dicData: planStatusOptions, + minWidth: 120, + fixed: 'right', + addDisplay: false, + editDisplay: false, + }, + { + label: '', + prop: 'shippingInfoTitle', + formslot: true, + span: 24, + order: 320, + hide: true, + labelWidth: 0, + }, + { + label: '项目ID', + prop: 'projectId', + hide: true, + display: false, + }, + { + label: '客户合同', + prop: 'contractName', + formslot: true, + hide: true, + span: 6, + order: 390, + minWidth: 160, + rules: textRule('客户合同', 100, true), + }, + { + label: '客户合同ID', + prop: 'contractId', + hide: true, + display: false, + }, + { + label: '发货地', + prop: 'departureName', + hide: true, + display: false, + minWidth: 140, + rules: textRule('发货地', 100, true), + }, + { + label: '收货地', + prop: 'arrivalName', + hide: true, + display: false, + minWidth: 140, + rules: textRule('收货地', 100, true), + }, + { + label: '发货联系人', + prop: 'departureContact', + hide: true, + display: false, + rules: textRule('发货联系人', 50), + }, + { + label: '发货联系方式', + prop: 'departurePhone', + hide: true, + display: false, + rules: [phoneRule('发货联系方式'), ...textRule('发货联系方式', 50)], + }, + { + label: '收货联系人', + prop: 'arrivalContact', + hide: true, + display: false, + rules: textRule('收货联系人', 50), + }, + { + label: '收货联系方式', + prop: 'arrivalPhone', + hide: true, + display: false, + rules: [phoneRule('收货联系方式'), ...textRule('收货联系方式', 50)], + }, + { + label: '', + prop: 'goodsInfoTitle', + formslot: true, + span: 24, + order: 280, + hide: true, + labelWidth: 0, + }, + { + label: '计划开始日期', + prop: 'planStartDateRange', + type: 'date', + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + search: true, + searchRange: true, + searchOrder: 4, + hide: true, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '计划结束日期', + prop: 'planEndDateRange', + type: 'date', + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + search: true, + searchRange: true, + searchOrder: 3, + hide: true, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '所属组织', + prop: 'deptName', + hide: true, + minWidth: 150, + addDisplay: false, + editDisplay: false, + }, + { + label: '', + prop: 'goodsJson', + type: 'textarea', + formslot: true, + minRows: 5, + span: 24, + order: 270, + hide: true, + labelWidth: '0px', + className: 'business-crud-page__full-form-item', + }, + { + label: '', + prop: 'attachmentTitle', + formslot: true, + span: 24, + order: 265, + hide: true, + labelWidth: 0, + }, + { + label: '', + prop: 'attachmentsJson', + type: 'textarea', + formslot: true, + minRows: 3, + span: 24, + order: 260, + hide: true, + labelWidth: '0px', + className: 'business-crud-page__full-form-item', + }, + ]) + ), dialogWidth: '96%', }; diff --git a/src/option/business/waybill-manage.js b/src/option/business/waybill-manage.js index b286cc5..dc1d2b4 100644 --- a/src/option/business/waybill-manage.js +++ b/src/option/business/waybill-manage.js @@ -6,6 +6,7 @@ import { selectRule, textRule, waybillStatusOptions, + withSearchPlaceholders, } from './common'; const transportTypeDict = { @@ -17,6 +18,7 @@ const transportTypeDict = { }; const isEmpty = value => value === undefined || value === null || value === ''; +const normalizeNumericDisplayValue = value => (Number(value) === -1 ? '' : value); const parseJsonArray = value => { if (Array.isArray(value)) return value; @@ -32,23 +34,34 @@ const parseJsonArray = value => { } }; -const hasProcessConfig = value => { - if (isEmpty(value)) return false; - if (typeof value !== 'string') { - return Array.isArray(value) ? value.length > 0 : typeof value === 'object'; - } - const text = value.trim(); - if (!text) return false; +const parseJsonObject = value => { + if (!value) return {}; + if (typeof value === 'object' && !Array.isArray(value)) return value; + if (typeof value !== 'string' || !value.trim()) return {}; try { - const result = JSON.parse(text); - return Array.isArray(result) - ? result.length > 0 - : Boolean(result && Object.keys(result).length); + const result = JSON.parse(value); + return result && typeof result === 'object' && !Array.isArray(result) ? result : {}; } catch (error) { - return true; + return {}; } }; +const parseProcessNodes = value => { + const result = parseJsonArray(value); + if (result.length) return result; + if (!value || typeof value !== 'object' || Array.isArray(value)) return []; + return Array.isArray(value.nodes) ? value.nodes : []; +}; + +const requiresDriverAcceptConfirmation = processJson => + parseProcessNodes(processJson).some( + node => + (node.key === 'accept' || node.name === '接单') && + node.enabled !== false && + node.confirmMode === 'yes' && + node.confirmDriver === true + ); + const getFirstValue = (row, props) => { const prop = props.find(item => !isEmpty(row[item])); return prop ? row[prop] : ''; @@ -74,7 +87,9 @@ const formatGoodsInfo = row => { const name = getFirstValue(item, ['cargoName', 'goodsName', 'name']); const type = getFirstValue(item, ['cargoType', 'goodsType', 'typeName']); const quantity = joinText([ - getFirstValue(item, ['quantity', 'cargoQuantity', 'goodsQuantity']), + normalizeNumericDisplayValue( + getFirstValue(item, ['quantity', 'cargoQuantity', 'goodsQuantity']) + ), getFirstValue(item, ['quantityUnit', 'cargoUnit', 'unit']), ]); return joinText([name, type, quantity]); @@ -90,28 +105,80 @@ const formatGoodsField = (row, props) => { return goods ? getFirstValue(goods, props) : ''; }; -const formatTransportMode = row => - getFirstValue(row, ['transportModeName', 'transportMode', 'transportWayName', 'transportWay']); - const formatUnitPrice = row => { - const value = getFirstValue(row, ['unitPrice', 'price']); + const value = normalizeNumericDisplayValue(getFirstValue(row, ['unitPrice', 'price'])); const unit = getFirstValue(row, ['priceUnit', 'billingUnit', 'unit']); if (!isEmpty(value)) return unit ? `${value}(${unit})` : value; - const billing = getBillingRows(row).find(item => !isEmpty(item.unitPrice)); + const billing = getBillingRows(row).find( + item => !isEmpty(normalizeNumericDisplayValue(item.unitPrice)) + ); if (!billing) return ''; const billingUnit = getFirstValue(billing, ['priceUnit', 'billingUnit', 'unit']); - return billingUnit ? `${billing.unitPrice}(${billingUnit})` : billing.unitPrice; + const billingPrice = normalizeNumericDisplayValue(billing.unitPrice); + return billingUnit ? `${billingPrice}(${billingUnit})` : billingPrice; }; const formatAmount = (row, props) => getFirstValue(row, props); +const sumAmount = list => + list.reduce((sum, item) => { + const value = getFirstValue(item, ['freightAmount', 'amount', 'totalAmount']); + return isEmpty(value) ? sum : sum + Number(value || 0); + }, 0); + +const calculateFreightTotal = rows => { + if (!rows.length) return ''; + let hasAmountField = false; + const total = rows.reduce((sum, item) => { + const amount = getFirstValue(item, ['freightAmount', 'amount']); + if (!isEmpty(amount)) { + hasAmountField = true; + return sum + Number(amount || 0); + } + if (isEmpty(item?.unitPrice) || isEmpty(item?.quantity)) return sum; + hasAmountField = true; + return sum + Number(item.unitPrice || 0) * Number(item.quantity || 0); + }, 0); + if (!hasAmountField) return ''; + return Number.isFinite(total) ? Number(total.toFixed(2)).toString() : ''; +}; + +const formatFreight = row => { + const value = formatAmount(row, ['freight', 'freightAmount', 'transportFee']); + if (!isEmpty(value)) return value; + const freight = parseJsonObject(row.freightJson); + const freightValue = getFirstValue(freight, ['freightAmount', 'transportFee']); + if (!isEmpty(freightValue)) return freightValue; + const total = sumAmount(Array.isArray(freight.freightItems) ? freight.freightItems : []); + return total ? total : ''; +}; + +const formatOtherFeeTotal = row => { + const value = formatAmount(row, ['otherFeeTotal', 'otherAmount', 'otherFeeAmount']); + return Number(value) === -1 ? '' : value; +}; + +const formatFreightTotal = row => { + const freight = parseJsonObject(row.freightJson); + const freightItems = Array.isArray(freight.freightItems) ? freight.freightItems : []; + const goodsRows = getGoodsRows(row); + const calculated = calculateFreightTotal(freightItems.length ? freightItems : goodsRows); + const otherFee = getFirstValue(freight, ['otherFreightAmount', 'otherFeeTotal']); + const otherFeeTotal = !isEmpty(otherFee) ? otherFee : formatOtherFeeTotal(row); + if (!isEmpty(calculated)) { + const total = Number(calculated || 0) + Number(otherFeeTotal || 0); + return Number.isFinite(total) ? Number(total.toFixed(2)).toString() : calculated; + } + const value = getFirstValue(freight, ['totalFreightAmount', 'totalFreight', 'totalAmount']); + if (!isEmpty(value)) return value; + return formatAmount(row, ['freightTotal', 'totalFreight', 'totalAmount']); +}; + const auditColumn = prop => ({ ...auditColumns.find(item => item.prop === prop) }); export const config = { title: '运单管理', permission: 'waybill_manage', - exportUrl: '/blade-transport/waybill-manage/export-waybill-manage', - exportName: '运单管理', importUrl: '/blade-transport/waybill-manage/import-waybill-manage', defaultForm: { carrierType: '承运商', @@ -120,10 +187,15 @@ export const config = { }, enableAllDept: false, enableProjectSelect: true, + projectQueryParams: { + approvalStatuses: 'approved,change_approved', + }, templateCreateTarget: 'waybill-manage', enableContractSelect: true, enableShippingPlanSelect: true, enableShippingInfoForm: true, + enableAttachmentTable: true, + attachmentTitle: '附件', fixedTransportAddressType: true, enableTaskInfoForm: true, enableWaybillFooterFreightSummary: true, @@ -146,13 +218,14 @@ export const config = { createTimeRange: ['createTimeStart', 'createTimeEnd'], }, actions: ['copy', 'cancel', 'reassign', 'complete', 'batchComplete'], + detailButton: true, statusProp: 'businessStatus', statusTextProp: 'businessStatusName', formatStatus(row, prop, defaultText) { if ( prop === 'businessStatus' && row.businessStatus === 'pending' && - !hasProcessConfig(row.processJson) + !requiresDriverAcceptConfirmation(row.processJson) ) { return '进行中'; } @@ -163,603 +236,609 @@ export const config = { }; export const option = { - ...createCrudOption([ - { - label: '', - prop: 'basicInfoTitle', - formslot: true, - span: 24, - order: 900, - hide: true, - labelWidth: 0, - }, - { - label: '运单号', - prop: 'waybillNo', - search: true, - searchOrder: 23, - minWidth: 150, - addDisplay: false, - editDisabled: true, - }, - { - label: '配载单号', - prop: 'loadingNo', - search: true, - searchOrder: 5, - span: 6, - order: 840, - minWidth: 140, - }, - { - label: '总单号', - prop: 'masterNo', - search: true, - searchLabel: '多联总单', - searchOrder: 6, - span: 6, - order: 830, - minWidth: 140, - }, - { - label: '项目', - prop: 'projectName', - formslot: true, - search: true, - searchOrder: 22, - span: 6, - order: 890, - minWidth: 150, - rules: textRule('项目', 100, true), - }, - { - label: '客户', - prop: 'customerName', - search: true, - searchLabel: '客户名称', - searchOrder: 21, - minWidth: 150, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - display: false, - }, - { - label: '车牌号/航班号/船号/班列号', - prop: 'vehicleNo', - search: true, - searchLabel: '车/船/航班/班列', - searchOrder: 13, - minWidth: 210, - display: false, - }, - { - label: '司机', - prop: 'driverName', - search: true, - searchLabel: '司机名称', - searchOrder: 14, - minWidth: 120, - display: false, - }, - { - label: '联系方式', - prop: 'driverPhone', - formatter: row => getFirstValue(row, ['driverPhone', 'driverMobile', 'driverTel']), - minWidth: 140, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - display: false, - }, - { - label: '运输方式', - prop: 'transportMode', - type: 'select', - search: true, - searchOrder: 1, - formatter: row => formatTransportMode(row), - ...transportTypeDict, - minWidth: 130, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '运输类型', - prop: 'transportType', - type: 'select', - search: true, - searchOrder: 20, - span: 6, - order: 850, - ...transportTypeDict, - minWidth: 130, - rules: selectRule('运输类型'), - }, - { - label: '过程节点', - prop: 'currentProcessNode', - minWidth: 140, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - display: false, - }, - { - label: '承运类型', - prop: 'carrierType', - formatter: row => getFirstValue(row, ['carrierTypeName', 'carrierType']), - minWidth: 120, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - display: false, - }, - { - label: '承运商', - prop: 'carrierName', - search: true, - searchLabel: '承运商名称', - searchOrder: 15, - minWidth: 150, - display: false, - }, - { - label: '货物信息', - prop: 'goodsInfo', - formatter: row => formatGoodsInfo(row), - minWidth: 260, - overHidden: true, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '发货地址', - prop: 'departureAddress', - formslot: true, - search: true, - searchOrder: 17, - span: 24, - order: 790, - minWidth: 220, - rules: textRule('发货地址', 255, true), - }, - { - label: '到货地址', - prop: 'arrivalAddress', - formslot: true, - search: true, - searchLabel: '收货地址', - searchOrder: 16, - span: 24, - order: 780, - minWidth: 220, - rules: textRule('收货地址', 255, true), - }, - { - label: '发货联系人', - prop: 'departureContact', - minWidth: 120, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '收货联系人', - prop: 'arrivalContact', - minWidth: 120, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '单价(计价单位)', - prop: 'unitPrice', - formatter: row => formatUnitPrice(row), - minWidth: 140, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '运费', - prop: 'freight', - formatter: row => formatAmount(row, ['freight', 'freightAmount', 'transportFee']), - minWidth: 120, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '其他费用合计', - prop: 'otherFeeTotal', - formatter: row => formatAmount(row, ['otherFeeTotal', 'otherAmount', 'otherFeeAmount']), - minWidth: 140, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '运费合计', - prop: 'freightTotal', - formatter: row => formatAmount(row, ['freightTotal', 'totalFreight', 'totalAmount']), - minWidth: 120, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '客户合同', - prop: 'contractName', - formslot: true, - span: 6, - order: 880, - minWidth: 160, - rules: textRule('客户合同', 100, true), - }, - { - label: '发货计划', - prop: 'planName', - formslot: true, - search: true, - searchOrder: 7, - span: 6, - order: 870, - minWidth: 150, - }, - { - label: '货物类型', - prop: 'cargoType', - search: true, - searchOrder: 18, - formatter: row => formatGoodsField(row, ['cargoType', 'goodsType', 'typeName']), - minWidth: 130, - display: false, - rules: textRule('货物类型', 100, true), - }, - { - label: '货物名称', - prop: 'cargoName', - search: true, - searchOrder: 19, - formatter: row => formatGoodsField(row, ['cargoName', 'goodsName', 'name']), - minWidth: 150, - display: false, - rules: textRule('货物名称', 100, true), - }, - { - label: '实际发货时间', - prop: 'startDate', - sortable: true, - type: 'datetime', - format: 'YYYY-MM-DD HH:mm:ss', - valueFormat: 'YYYY-MM-DD HH:mm:ss', - minWidth: 170, - }, - { - label: '实际完成时间', - prop: 'endDate', - sortable: true, - type: 'datetime', - format: 'YYYY-MM-DD HH:mm:ss', - valueFormat: 'YYYY-MM-DD HH:mm:ss', - minWidth: 170, - }, - { - label: '原始单号', - prop: 'originalNo', - search: true, - searchOrder: 12, - span: 6, - order: 860, - minWidth: 140, - }, - { - label: '运单批次号', - prop: 'batchNo', - search: true, - searchLabel: '运输批次', - searchOrder: 3, - minWidth: 140, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - display: false, - }, - { - label: '预计发货日期', - prop: 'estimatedStartTime', - sortable: true, - type: 'date', - format: 'YYYY-MM-DD', - valueFormat: 'YYYY-MM-DD', - formatter: row => getFirstValue(row, ['estimatedStartTime', 'planStartDate']), - minWidth: 170, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - display: false, - }, - { - label: '预计完成日期', - prop: 'estimatedEndTime', - sortable: true, - type: 'date', - format: 'YYYY-MM-DD', - valueFormat: 'YYYY-MM-DD', - formatter: row => getFirstValue(row, ['estimatedEndTime', 'planEndDate']), - minWidth: 170, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - display: false, - }, - { - label: '备注', - prop: 'remark', - type: 'textarea', - minRows: 2, - span: 24, - order: 810, - minWidth: 180, - overHidden: true, - maxlength: 200, - showWordLimit: true, - rules: textRule('备注', 200), - }, - { - label: '数据来源', - prop: 'dataSource', - type: 'select', - search: true, - searchOrder: 10, - dicData: dataSourceOptions, - minWidth: 120, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - display: false, - }, - { - ...auditColumn('createTime'), - }, - { - ...auditColumn('updateTime'), - }, - { - label: '状态', - prop: 'businessStatus', - type: 'select', - slot: true, - search: true, - searchLabel: '状态', - searchOrder: 11, - dicData: waybillStatusOptions, - minWidth: 120, - fixed: 'right', - addDisplay: false, - editDisplay: false, - }, - { - label: '', - prop: 'shippingInfoTitle', - formslot: true, - span: 24, - order: 800, - hide: true, - labelWidth: 0, - }, - { - label: '', - prop: 'taskInfoTitle', - formslot: true, - span: 24, - order: 770, - hide: true, - labelWidth: 0, - }, - { - label: '', - prop: 'taskInfoForm', - formslot: true, - span: 24, - order: 760, - hide: true, - labelWidth: '0px', - className: 'business-crud-page__full-form-item', - }, - { - label: '实际发货时间', - prop: 'startDateRange', - type: 'datetime', - format: 'YYYY-MM-DD HH:mm:ss', - valueFormat: 'YYYY-MM-DD HH:mm:ss', - search: true, - searchRange: true, - searchOrder: 9, - hide: true, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - display: false, - }, - { - label: '实际完成时间', - prop: 'endDateRange', - type: 'datetime', - format: 'YYYY-MM-DD HH:mm:ss', - valueFormat: 'YYYY-MM-DD HH:mm:ss', - search: true, - searchRange: true, - searchOrder: 8, - hide: true, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - display: false, - }, - { - label: '创建时间', - prop: 'createTimeRange', - type: 'datetime', - format: 'YYYY-MM-DD HH:mm:ss', - valueFormat: 'YYYY-MM-DD HH:mm:ss', - search: true, - searchRange: true, - searchOrder: 4, - hide: true, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '关联单号', - prop: 'relationNo', - search: true, - searchOrder: 2, - span: 6, - order: 820, - minWidth: 140, - hide: true, - }, - { - label: '货物信息', - prop: 'goodsJson', - type: 'textarea', - minRows: 5, - span: 24, - hide: true, - display: false, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '承运信息', - prop: 'carrierJson', - type: 'textarea', - minRows: 2, - span: 24, - hide: true, - display: false, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '过程配置', - prop: 'processJson', - type: 'textarea', - minRows: 2, - span: 24, - hide: true, - display: false, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '运费信息', - prop: 'freightJson', - type: 'textarea', - minRows: 2, - span: 24, - hide: true, - display: false, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '附件', - prop: 'attachmentsJson', - type: 'textarea', - minRows: 2, - span: 24, - hide: true, - display: false, - addDisplay: false, - editDisplay: false, - viewDisplay: false, - }, - { - label: '所属组织', - prop: 'deptName', - hide: true, - minWidth: 150, - addDisplay: false, - editDisplay: false, - }, - { - label: '发货地', - prop: 'departureName', - hide: true, - display: false, - minWidth: 140, - rules: textRule('发货地', 100, true), - }, - { - label: '收货地', - prop: 'arrivalName', - hide: true, - display: false, - minWidth: 140, - rules: textRule('收货地', 100, true), - }, - { - label: '发货联系方式', - prop: 'departurePhone', - hide: true, - display: false, - rules: [phoneRule('发货联系方式'), ...textRule('发货联系方式', 50)], - }, - { - label: '收货联系方式', - prop: 'arrivalPhone', - hide: true, - display: false, - rules: [phoneRule('收货联系方式'), ...textRule('收货联系方式', 50)], - }, - { - label: '项目ID', - prop: 'projectId', - hide: true, - display: false, - }, - { - label: '客户合同ID', - prop: 'contractId', - hide: true, - display: false, - }, - { - label: '发货计划ID', - prop: 'planId', - hide: true, - display: false, - }, - { - label: '任务录入模式', - prop: 'taskEntryMode', - hide: true, - display: false, - value: 'simple', - }, - { - label: '任务备注', - prop: 'taskRemark', - hide: true, - display: false, - }, - { - label: '任务信息', - prop: 'taskInfoJson', - hide: true, - display: false, - }, - ]), + ...createCrudOption( + withSearchPlaceholders([ + { + label: '', + prop: 'basicInfoTitle', + formslot: true, + span: 24, + order: 900, + hide: true, + labelWidth: 0, + }, + { + label: '运单号', + prop: 'waybillNo', + search: true, + searchOrder: 23, + minWidth: 150, + addDisplay: false, + editDisabled: true, + }, + { + label: '配载单号', + prop: 'loadingNo', + search: true, + searchOrder: 5, + span: 6, + order: 840, + minWidth: 140, + addDisplay: false, + editDisplay: false, + }, + { + label: '总单号', + prop: 'masterNo', + search: true, + searchLabel: '多联总单', + searchOrder: 6, + span: 6, + order: 830, + minWidth: 140, + addDisplay: false, + editDisplay: false, + }, + { + label: '项目名称', + prop: 'projectName', + formslot: true, + search: true, + searchLabel: '项目', + searchOrder: 22, + span: 6, + order: 890, + minWidth: 150, + rules: textRule('项目', 100, true), + }, + { + label: '客户', + prop: 'customerName', + search: true, + searchLabel: '客户名称', + searchOrder: 21, + minWidth: 150, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + display: false, + }, + { + label: '车牌号/航班号/船号/班列号', + prop: 'vehicleNo', + search: true, + searchLabel: '车/船/航班/班列', + searchOrder: 13, + minWidth: 210, + display: false, + }, + { + label: '司机', + prop: 'driverName', + search: true, + searchLabel: '司机名称', + searchOrder: 14, + minWidth: 120, + display: false, + }, + { + label: '联系方式', + prop: 'driverPhone', + formatter: row => getFirstValue(row, ['driverPhone', 'driverMobile', 'driverTel']), + minWidth: 140, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + display: false, + }, + { + label: '运输方式', + prop: 'transportType', + type: 'select', + search: true, + searchOrder: 20, + span: 6, + order: 850, + ...transportTypeDict, + minWidth: 130, + rules: selectRule('运输方式'), + }, + { + label: '过程节点', + prop: 'currentProcessNode', + minWidth: 140, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + display: false, + }, + { + label: '承运类型', + prop: 'carrierType', + formatter: row => getFirstValue(row, ['carrierTypeName', 'carrierType']), + minWidth: 120, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + display: false, + }, + { + label: '承运商', + prop: 'carrierName', + search: true, + searchLabel: '承运商名称', + searchOrder: 15, + minWidth: 150, + display: false, + }, + { + label: '货物信息', + prop: 'goodsInfo', + formatter: row => formatGoodsInfo(row), + minWidth: 260, + overHidden: true, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '发货地址', + prop: 'departureAddress', + formslot: true, + search: true, + searchOrder: 17, + span: 24, + order: 790, + minWidth: 220, + rules: textRule('发货地址', 255, true), + }, + { + label: '到货地址', + prop: 'arrivalAddress', + formslot: true, + search: true, + searchLabel: '收货地址', + searchOrder: 16, + span: 24, + order: 780, + minWidth: 220, + rules: textRule('收货地址', 255, true), + }, + { + label: '发货联系人', + prop: 'departureContact', + minWidth: 120, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '收货联系人', + prop: 'arrivalContact', + minWidth: 120, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '单价(计价单位)', + prop: 'unitPrice', + formatter: row => formatUnitPrice(row), + minWidth: 140, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '运费', + prop: 'freight', + formatter: row => formatFreightTotal(row), + minWidth: 120, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '其他费用合计', + prop: 'otherFeeTotal', + formatter: row => formatOtherFeeTotal(row), + minWidth: 140, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '运费合计', + prop: 'freightTotal', + formatter: row => formatFreightTotal(row), + minWidth: 120, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '客户合同', + prop: 'contractName', + formslot: true, + span: 6, + order: 880, + minWidth: 160, + rules: textRule('客户合同', 100, true), + }, + { + label: '计划名称', + prop: 'planName', + formslot: true, + search: true, + searchOrder: 7, + span: 6, + order: 870, + minWidth: 150, + }, + { + label: '货物类型', + prop: 'cargoType', + search: true, + searchOrder: 18, + formatter: row => formatGoodsField(row, ['cargoType', 'goodsType', 'typeName']), + minWidth: 130, + display: false, + rules: textRule('货物类型', 100, true), + }, + { + label: '货物名称', + prop: 'cargoName', + search: true, + searchOrder: 19, + formatter: row => formatGoodsField(row, ['cargoName', 'goodsName', 'name']), + minWidth: 150, + display: false, + rules: textRule('货物名称', 100, true), + }, + { + label: '实际发货时间', + prop: 'startDate', + sortable: true, + type: 'datetime', + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + minWidth: 170, + addDisplay: false, + editDisplay: false, + }, + { + label: '实际完成时间', + prop: 'endDate', + sortable: true, + type: 'datetime', + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + minWidth: 170, + addDisplay: false, + editDisplay: false, + }, + { + label: '原始单号', + prop: 'originalNo', + search: true, + searchOrder: 12, + span: 6, + order: 860, + minWidth: 140, + }, + { + label: '运单批次号', + prop: 'batchNo', + search: true, + searchLabel: '运输批次', + searchOrder: 3, + minWidth: 140, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + display: false, + }, + { + label: '预计发货日期', + prop: 'estimatedStartTime', + sortable: true, + type: 'date', + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + formatter: row => getFirstValue(row, ['estimatedStartTime', 'planStartDate']), + minWidth: 170, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + display: false, + }, + { + label: '预计完成日期', + prop: 'estimatedEndTime', + sortable: true, + type: 'date', + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + formatter: row => getFirstValue(row, ['estimatedEndTime', 'planEndDate']), + minWidth: 170, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + display: false, + }, + { + label: '备注', + prop: 'remark', + type: 'textarea', + minRows: 4, + span: 24, + order: 810, + minWidth: 180, + overHidden: true, + maxlength: 200, + showWordLimit: true, + rules: textRule('备注', 200), + }, + { + label: '数据来源', + prop: 'dataSource', + type: 'select', + search: true, + searchOrder: 10, + dicData: dataSourceOptions, + minWidth: 120, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + display: false, + }, + { + ...auditColumn('createTime'), + }, + { + ...auditColumn('updateTime'), + }, + { + label: '状态', + prop: 'businessStatus', + type: 'select', + slot: true, + search: true, + searchLabel: '状态', + searchOrder: 11, + dicData: waybillStatusOptions, + minWidth: 120, + fixed: 'right', + addDisplay: false, + editDisplay: false, + }, + { + label: '', + prop: 'shippingInfoTitle', + formslot: true, + span: 24, + order: 800, + hide: true, + labelWidth: 0, + }, + { + label: '', + prop: 'taskInfoTitle', + formslot: true, + span: 24, + order: 770, + hide: true, + labelWidth: 0, + }, + { + label: '', + prop: 'taskInfoForm', + formslot: true, + span: 24, + order: 760, + hide: true, + labelWidth: '0px', + className: 'business-crud-page__full-form-item', + }, + { + label: '实际发货时间', + prop: 'startDateRange', + type: 'datetime', + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + search: true, + searchRange: true, + searchOrder: 9, + hide: true, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + display: false, + }, + { + label: '实际完成时间', + prop: 'endDateRange', + type: 'datetime', + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + search: true, + searchRange: true, + searchOrder: 8, + hide: true, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + display: false, + }, + { + label: '创建时间', + prop: 'createTimeRange', + type: 'datetime', + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + search: true, + searchRange: true, + searchOrder: 4, + hide: true, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '关联单号', + prop: 'relationNo', + search: true, + searchOrder: 2, + span: 6, + order: 820, + minWidth: 140, + hide: true, + }, + { + label: '货物信息', + prop: 'goodsJson', + type: 'textarea', + minRows: 5, + span: 24, + hide: true, + display: false, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '承运信息', + prop: 'carrierJson', + type: 'textarea', + minRows: 4, + span: 24, + hide: true, + display: false, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '过程配置', + prop: 'processJson', + type: 'textarea', + minRows: 4, + span: 24, + hide: true, + display: false, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '运费信息', + prop: 'freightJson', + type: 'textarea', + minRows: 4, + span: 24, + hide: true, + display: false, + addDisplay: false, + editDisplay: false, + viewDisplay: false, + }, + { + label: '', + prop: 'attachmentTitle', + formslot: true, + span: 24, + order: 750, + hide: true, + labelWidth: 0, + }, + { + label: '', + prop: 'attachmentsJson', + type: 'textarea', + formslot: true, + span: 24, + order: 740, + hide: true, + labelWidth: '0px', + className: 'business-crud-page__full-form-item', + }, + { + label: '所属组织', + prop: 'deptName', + hide: true, + minWidth: 150, + addDisplay: false, + editDisplay: false, + }, + { + label: '发货地', + prop: 'departureName', + hide: true, + display: false, + minWidth: 140, + rules: textRule('发货地', 100, true), + }, + { + label: '收货地', + prop: 'arrivalName', + hide: true, + display: false, + minWidth: 140, + rules: textRule('收货地', 100, true), + }, + { + label: '发货联系方式', + prop: 'departurePhone', + hide: true, + display: false, + rules: [phoneRule('发货联系方式'), ...textRule('发货联系方式', 50)], + }, + { + label: '收货联系方式', + prop: 'arrivalPhone', + hide: true, + display: false, + rules: [phoneRule('收货联系方式'), ...textRule('收货联系方式', 50)], + }, + { + label: '项目ID', + prop: 'projectId', + hide: true, + display: false, + }, + { + label: '客户合同ID', + prop: 'contractId', + hide: true, + display: false, + }, + { + label: '计划名称ID', + prop: 'planId', + hide: true, + display: false, + }, + { + label: '任务录入模式', + prop: 'taskEntryMode', + hide: true, + display: false, + value: 'simple', + }, + { + label: '任务备注', + prop: 'taskRemark', + hide: true, + display: false, + }, + { + label: '任务信息', + prop: 'taskInfoJson', + hide: true, + display: false, + }, + ]) + ), dialogWidth: '96%', dialogTop: '10px', menuWidth: 280, diff --git a/src/option/settlement/receivable-payable-detail.js b/src/option/settlement/receivable-payable-detail.js new file mode 100644 index 0000000..952ac91 --- /dev/null +++ b/src/option/settlement/receivable-payable-detail.js @@ -0,0 +1,126 @@ +export const settlementTypeOptions = [ + { label: '应收', value: 'receivable' }, + { label: '应付', value: 'payable' }, +]; + +export const settlementStatusOptions = [ + { label: '待结算', value: 'pending' }, + { label: '已转预结算', value: 'pre_settled' }, + { label: '已转正式结算', value: 'formal_settled' }, + { label: '已关闭', value: 'closed' }, +]; + +export const searchFields = [ + { label: '单据号', prop: 'documentNo', type: 'input' }, + { label: '生成日期', prop: 'generateDateRange', type: 'daterange' }, + { label: '客户名称', prop: 'customerName', type: 'input' }, + { label: '所属组织', prop: 'deptName', type: 'input' }, + { label: '项目名称', prop: 'projectName', type: 'input' }, + { label: '货物类型', prop: 'cargoType', type: 'input' }, + { label: '货物名称', prop: 'cargoName', type: 'input' }, + { label: '合同编号', prop: 'contractNo', type: 'input' }, + { label: '合同名称', prop: 'contractName', type: 'input' }, + { label: '预结算单号', prop: 'preSettlementNo', type: 'input' }, + { label: '正式结算单号', prop: 'formalSettlementNo', type: 'input' }, + { label: '批次号', prop: 'batchNo', type: 'input' }, + { label: '车号', prop: 'vehicleNo', type: 'input' }, +]; + +export const tableColumns = [ + { label: '单据号', prop: 'documentNo', minWidth: 180, link: true }, + { label: '项目名称', prop: 'projectName', minWidth: 120 }, + { label: '所属组织', prop: 'deptName', minWidth: 120 }, + { label: '费用日期', prop: 'feeDate', minWidth: 120 }, + { label: '客商名称', prop: 'customerName', minWidth: 130 }, + { label: '合同编号', prop: 'contractNo', minWidth: 140 }, + { label: '合同名称', prop: 'contractName', minWidth: 140 }, + { label: '来源', prop: 'sourceType', minWidth: 110 }, + { label: '预结算单号', prop: 'preSettlementNo', minWidth: 140, link: true }, + { label: '正式结算单号', prop: 'formalSettlementNo', minWidth: 140, link: true }, + { label: '运单号', prop: 'waybillNo', minWidth: 140 }, + { label: '车号', prop: 'vehicleNo', minWidth: 120 }, + { label: '运输类型', prop: 'transportType', minWidth: 120 }, + { label: '货物名称', prop: 'cargoName', minWidth: 130 }, + { label: '货物类型', prop: 'cargoType', minWidth: 120 }, + { label: '运输总量', prop: 'transportQuantity', minWidth: 120, align: 'right' }, + { label: '里程(KM)', prop: 'mileage', minWidth: 120, align: 'right' }, + { label: '批次号', prop: 'batchNo', minWidth: 120 }, + { label: '运输单价', prop: 'unitPriceText', minWidth: 120, align: 'right' }, + { label: '运输费', prop: 'freightAmountText', minWidth: 120, align: 'right' }, + { label: '其它费用', prop: 'otherFeeAmountText', minWidth: 120, align: 'right' }, + { label: '费用合计', prop: 'totalAmountText', minWidth: 130, align: 'right' }, + { label: '状态', prop: 'settlementStatusName', minWidth: 120 }, + { label: '创建人', prop: 'createUserName', minWidth: 120 }, + { label: '创建时间', prop: 'createTime', minWidth: 170 }, +]; + +export const feeDetailBaseColumns = [ + { label: '货物名称', prop: 'cargoName', minWidth: 140 }, + { label: '货物类型', prop: 'cargoType', minWidth: 130 }, + { label: '规格', prop: 'specification', minWidth: 120 }, + { label: '型号', prop: 'model', minWidth: 120 }, + { label: '运费计费要素', prop: 'billingFactor', minWidth: 130 }, + { label: '运费计费类型', prop: 'billingType', minWidth: 130 }, + { label: '运输量', prop: 'transportQuantityText', minWidth: 120 }, + { label: '运费计算单位', prop: 'priceUnit', minWidth: 130 }, + { label: '运输单价', prop: 'unitPrice', minWidth: 120, align: 'right' }, + { label: '里程(KM)', prop: 'mileage', minWidth: 120, align: 'right' }, + { label: '运输费', prop: 'freightAmount', minWidth: 120, align: 'right' }, +]; + +export const feeDetailTailColumns = [ + { label: '原总金额', prop: 'originalAmountText', minWidth: 120, align: 'right' }, + { label: '调整金额', prop: 'adjustAmountText', minWidth: 120, align: 'right' }, + { label: '调整后总金额', prop: 'afterAmountText', minWidth: 140, align: 'right' }, + { label: '备注', prop: 'remark', minWidth: 160 }, + { label: '最后录入人', prop: 'updateUserName', minWidth: 120 }, + { label: '最后录入时间', prop: 'updateTime', minWidth: 170 }, +]; + +export const changeRecordColumns = [ + { label: '行号', prop: 'lineNo', minWidth: 120 }, + { label: '货物名称', prop: 'cargoName', minWidth: 140 }, + { label: '变更内容', prop: 'changeContent', minWidth: 260 }, + { label: '调整人', prop: 'adjustUserName', minWidth: 140 }, + { label: '调整原因', prop: 'adjustReason', minWidth: 180 }, + { label: '调整时间', prop: 'adjustTime', minWidth: 170 }, +]; + +export const updateFeeFormFields = [ + { label: '更新范围', prop: 'contractId', required: true }, + { label: '合同计费方案', prop: 'billingPlanId' }, +]; + +export const transferSearchFields = [ + { label: '合同名称', prop: 'contractName', type: 'input' }, + { label: '批次号', prop: 'batchNo', type: 'input' }, + { label: '生成日期', prop: 'generateDateRange', type: 'daterange' }, +]; + +export const generateSearchFields = [ + { label: '运单合同', prop: 'contractId', required: true }, + { label: '计费方案', prop: 'billingPlanId', required: true }, + { label: '批次号', prop: 'batchNo' }, + { label: '运单完成日期', prop: 'finishDateRange', type: 'daterange' }, +]; + +export const generateWaybillColumns = [ + { label: '运单号', prop: 'waybillNo', minWidth: 160, link: true }, + { label: '项目名称', prop: 'projectName', minWidth: 160 }, + { label: '客户/委托方', prop: 'customerName', minWidth: 160 }, + { label: '车牌号/航班号/船号/班列号', prop: 'vehicleNo', minWidth: 190 }, + { label: '司机', prop: 'driverName', minWidth: 120 }, + { label: '承运商', prop: 'carrierName', minWidth: 160 }, + { label: '运输类型', prop: 'transportType', minWidth: 130 }, + { label: '承运类型', prop: 'carrierType', minWidth: 130 }, + { label: '货物信息', prop: 'cargoInfo', minWidth: 160 }, +]; + +export const generatePreviewColumns = [ + { label: '客商名称', prop: 'customerName', minWidth: 160 }, + { label: '运单号', prop: 'waybillNo', minWidth: 160 }, + { label: '车号', prop: 'vehicleNo', minWidth: 140 }, + { label: '货物名称', prop: 'cargoName', minWidth: 140 }, + { label: '货物类型', prop: 'cargoType', minWidth: 140 }, + { label: '规格', prop: 'specification', minWidth: 140 }, +]; diff --git a/src/option/transit/exception-disposal.js b/src/option/transit/exception-disposal.js new file mode 100644 index 0000000..6f0ba58 --- /dev/null +++ b/src/option/transit/exception-disposal.js @@ -0,0 +1,91 @@ +export const exceptionCategoryOptions = [ + { + label: '交通异常', + value: 'traffic', + children: [ + { label: '道路拥堵', value: '道路拥堵' }, + { label: '交通事故', value: '交通事故' }, + { label: '道路封闭', value: '道路封闭' }, + { label: '天气影响', value: '天气影响' }, + { label: '其他', value: '交通异常-其他' }, + ], + }, + { + label: '车辆异常', + value: 'vehicle', + children: [ + { label: '车辆故障维修', value: '车辆故障维修' }, + { label: '车辆事故', value: '车辆事故' }, + { label: '爆胎', value: '爆胎' }, + { label: '设备异常', value: '设备异常' }, + { label: '缺油缺电', value: '缺油缺电' }, + { label: '其他', value: '车辆异常-其他' }, + ], + }, + { + label: '货物异常', + value: 'cargo', + children: [ + { label: '货损', value: '货损' }, + { label: '货差', value: '货差' }, + { label: '货物丢失', value: '货物丢失' }, + { label: '包装异常', value: '包装异常' }, + { label: '其他', value: '货物异常-其他' }, + ], + }, + { + label: '其他异常', + value: 'other', + children: [ + { label: '变更路线地址', value: '变更路线地址' }, + { label: '其他', value: '其他异常-其他' }, + ], + }, +]; + +export const disposalStatusOptions = [ + { label: '待处理', value: 'pending' }, + { label: '处理中', value: 'processing' }, + { label: '已完成', value: 'completed' }, +]; + +export const searchFields = [ + { label: '运单号', prop: 'waybillNo', type: 'input' }, + { label: '车辆', prop: 'vehicleNo', type: 'input' }, + { label: '上报人', prop: 'reporterName', type: 'input' }, + { label: '上报时间', prop: 'reportTimeRange', type: 'daterange' }, + { label: '项目', prop: 'projectName', type: 'input' }, + { label: '承运商', prop: 'carrierName', type: 'input' }, + { label: '异常类型', prop: 'exceptionType', type: 'select', options: exceptionCategoryOptions }, + { label: '状态', prop: 'disposalStatus', type: 'select', options: disposalStatusOptions }, +]; + +export const tableColumns = [ + { label: '运单号', prop: 'waybillNo', minWidth: 160, link: true }, + { label: '项目', prop: 'projectName', minWidth: 160 }, + { label: '车辆', prop: 'vehicleNo', minWidth: 150, link: true }, + { label: '上报人', prop: 'reporterName', minWidth: 120 }, + { label: '异常类型', prop: 'exceptionTypeName', minWidth: 160 }, + { label: '上报说明', prop: 'reportDescription', minWidth: 180 }, + { label: '承运商', prop: 'carrierName', minWidth: 160 }, + { label: '最新跟进说明', prop: 'latestFollowContent', minWidth: 200 }, + { label: '状态', prop: 'disposalStatusName', minWidth: 120 }, +]; + +export const detailFields = [ + { label: '配载单号/总单号', prop: 'loadingOrMasterNo', link: true }, + { label: '运单号', prop: 'waybillNo', link: true }, + { label: '项目', prop: 'projectName', link: true }, + { label: '车牌号', prop: 'vehicleNo', link: true }, + { label: '上报人', prop: 'reporterName' }, + { label: '承运商', prop: 'carrierName' }, + { label: '异常类型', prop: 'exceptionTypeName' }, + { label: '异常原因', prop: 'exceptionReason' }, + { label: '上报说明', prop: 'reportDescription', span: 2 }, +]; + +export const followColumns = [ + { label: '跟进说明', prop: 'followContent', minWidth: 260 }, + { label: '跟进人', prop: 'followUserName', minWidth: 130 }, + { label: '跟进时间', prop: 'followTime', minWidth: 170 }, +]; diff --git a/src/option/transit/risk-disposal.js b/src/option/transit/risk-disposal.js new file mode 100644 index 0000000..22d52dd --- /dev/null +++ b/src/option/transit/risk-disposal.js @@ -0,0 +1,50 @@ +export const riskLevelOptions = [ + { label: '低', value: 'low', tagType: 'success' }, + { label: '中', value: 'medium', tagType: 'warning' }, + { label: '高', value: 'high', tagType: 'danger' }, +]; + +export const disposalStatusOptions = [ + { label: '待处理', value: 'pending', tagType: 'warning' }, + { label: '已处理', value: 'processed', tagType: 'success' }, + { label: '已忽略', value: 'ignored', tagType: 'info' }, +]; + +export const disposalMethodOptions = [ + { label: '处理', value: 'process' }, + { label: '忽略', value: 'ignore' }, +]; + +export const searchFields = [ + { label: '规则名称', prop: 'ruleName', type: 'input', placeholder: '请输入' }, + { label: '风险等级', prop: 'riskLevel', type: 'select', placeholder: '全部', options: riskLevelOptions }, + { + label: '处理状态', + prop: 'disposalStatus', + type: 'select', + placeholder: '全部', + options: disposalStatusOptions, + }, + { label: '组织', prop: 'deptName', type: 'input', placeholder: '默认展示当前组织,可搜索' }, +]; + +export const tableColumns = [ + { label: '风险编号', prop: 'riskNo', minWidth: 210 }, + { label: '规则名称', prop: 'ruleName', minWidth: 210 }, + { label: '运单号', prop: 'waybillNo', minWidth: 220, link: true }, + { label: '项目名称', prop: 'projectName', minWidth: 160 }, + { label: '风险等级', prop: 'riskLevelName', minWidth: 130, tag: true }, + { label: '运输类型', prop: 'transportType', minWidth: 130 }, + { label: '风险描述', prop: 'riskDescription', minWidth: 310 }, + { label: '处理状态', prop: 'disposalStatusName', minWidth: 130, tag: true }, +]; + +export const detailFields = [ + { label: '风险编号', prop: 'riskNo' }, + { label: '规则名称', prop: 'ruleName' }, + { label: '风险等级', prop: 'riskLevelName', tag: true }, + { label: '运单号', prop: 'waybillNo', link: true }, + { label: '项目名称', prop: 'projectName' }, + { label: '触发时间', prop: 'triggerTime' }, + { label: '风险描述', prop: 'riskDescription', span: 3 }, +]; diff --git a/src/option/transit/track-tracking.js b/src/option/transit/track-tracking.js new file mode 100644 index 0000000..1706e54 --- /dev/null +++ b/src/option/transit/track-tracking.js @@ -0,0 +1,10 @@ +export const queryTypeOptions = [ + { label: '轨迹查询', value: 'track' }, + { label: '船舶查询', value: 'ship' }, +]; + +export const mapInfoFields = [ + { label: '站点名称', prop: 'siteName' }, + { label: '地址', prop: 'address' }, + { label: '经纬度', prop: 'coordinates' }, +]; diff --git a/src/utils/validate.js b/src/utils/validate.js index cc55c08..ccba6e7 100644 --- a/src/utils/validate.js +++ b/src/utils/validate.js @@ -27,7 +27,7 @@ export function isEmail(s) { * @param {*} s */ export function isMobile(s) { - return /^1[0-9]{10}$/.test(s); + return /^1[3-9]\d{9}$/.test(String(s || '').trim()); } /** diff --git a/src/views/base/common-address.vue b/src/views/base/common-address.vue index 2331bb6..d913257 100644 --- a/src/views/base/common-address.vue +++ b/src/views/base/common-address.vue @@ -267,6 +267,7 @@ import { createOption } from '@/option/base/common-address'; import { mapGetters } from 'vuex'; import { downloadXls } from '@/utils/util'; import { getToken } from '@/utils/auth'; +import { isMobile } from '@/utils/validate'; import NProgress from 'nprogress'; import 'nprogress/nprogress.css'; @@ -830,12 +831,8 @@ export default { this.$message.warning('联系人不能超过50个字'); return false; } - if (row.contactPhone && row.contactPhone.length > 20) { - this.$message.warning('联系方式不能超过20个字'); - return false; - } - if (row.contactPhone && !/^\d+$/.test(row.contactPhone)) { - this.$message.warning('联系方式只能输入数字'); + if (row.contactPhone && !isMobile(row.contactPhone)) { + this.$message.warning('联系方式格式不正确'); return false; } if (row.remark && row.remark.length > 200) { diff --git a/src/views/business/common-route.vue b/src/views/business/common-route.vue index f178f76..28680a8 100644 --- a/src/views/business/common-route.vue +++ b/src/views/business/common-route.vue @@ -322,6 +322,7 @@ import { config, excelOption, option } from '@/option/business/common-route'; import { getToken } from '@/utils/auth'; import { openImportDialog } from '@/utils/import-excel'; import { downloadXls } from '@/utils/util'; +import { isMobile } from '@/utils/validate'; import { List, Search } from '@element-plus/icons-vue'; import { mapGetters } from 'vuex'; import NProgress from 'nprogress'; @@ -789,6 +790,14 @@ export default { this.$message.warning('收货地址不能超过255个字符'); return false; } + const invalidPhone = [ + [row.departurePhone, '发货联系方式'], + [row.arrivalPhone, '收货联系方式'], + ].find(([value]) => value && !isMobile(value)); + if (invalidPhone) { + this.$message.warning(`${invalidPhone[1]}格式不正确`); + return false; + } if (row.remark && row.remark.length > 500) { this.$message.warning('备注不能超过500个字符'); return false; diff --git a/src/views/business/components/business-crud-page.vue b/src/views/business/components/business-crud-page.vue index 1ddff69..96d5c09 100644 --- a/src/views/business/components/business-crud-page.vue +++ b/src/views/business/components/business-crud-page.vue @@ -105,20 +105,12 @@