1、完善项目
2、完善合同 3、完善费用项 4、司机管理对接OCR 5、完善运输计划 6、完善临时额度
This commit is contained in:
@@ -167,7 +167,7 @@ Avue 表格/表单配置独立存放于 `src/option/` 目录,与 `views` 和 `
|
||||
- 搜索组件需展示轻量阴影,统一使用 `0 2px 8px rgba(0, 0, 0, 0.06)`,不得被局部卡片去样式规则覆盖。
|
||||
- 表格线条颜色需统一使用 `#EFF1F7`,包括表格外边框、单元格分割线和固定列边线。
|
||||
- 表格偶数行需统一使用 `#FAFAFA` 背景色,固定列单元格必须与对应行背景保持一致。
|
||||
- 表格操作列同时展示“查看、编辑、删除”等三个按钮时,操作列宽度统一不小于 `220px`,禁止出现按钮裁切或显示不全。
|
||||
- 表格操作列同时展示“查看、编辑、删除”等三个按钮时,操作列宽度统一不小于 `220px`;操作列最大按钮数量超过 3 个时,操作列宽度统一加宽到不小于 `320px`;最大按钮数量超过 4 个时,仍按 `320px` 保持列宽,并从第 5 个按钮开始换行展示,禁止出现按钮裁切或显示不全。
|
||||
- 表格操作列按钮统一仅展示文字,禁止配置 `icon` / `:icon` 或在操作按钮、操作下拉项中嵌入图标;顶部工具栏按钮不受此条限制。
|
||||
- `.avue-crud__header` 顶部间距统一为 `12px`。
|
||||
- 分页组件整体靠右展示,必须展示接口返回的数据总条数,`X条/页` 的页容量选择器必须放在总条数右侧。
|
||||
|
||||
@@ -51,6 +51,20 @@ export const voidProject = (id, reason) =>
|
||||
params: { id, reason },
|
||||
});
|
||||
|
||||
export const saveChange = row =>
|
||||
request({
|
||||
url: `${baseUrl}/save-change`,
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
|
||||
export const submitChange = row =>
|
||||
request({
|
||||
url: `${baseUrl}/submit-change`,
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
|
||||
export const startChange = (id, reason) =>
|
||||
request({
|
||||
url: `${baseUrl}/start-change`,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import request from '@/axios';
|
||||
import { createCrudApi } from './common';
|
||||
|
||||
const api = createCrudApi('/blade-transport/waybill-manage');
|
||||
const baseUrl = '/blade-transport/waybill-manage';
|
||||
const api = createCrudApi(baseUrl);
|
||||
|
||||
export const getList = api.getList;
|
||||
export const getDetail = api.getDetail;
|
||||
@@ -11,3 +13,11 @@ export const cancel = api.cancel;
|
||||
export const reassign = api.reassign;
|
||||
export const complete = api.complete;
|
||||
export const batchComplete = api.batchComplete;
|
||||
export const roadLoading = ids =>
|
||||
request({
|
||||
url: `${baseUrl}/road-loading`,
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -58,3 +58,23 @@ export const getExpiryStat = params => {
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
export const recognitionIDCard = url => {
|
||||
return request({
|
||||
url: '/blade-file/file/recognitionIDCard',
|
||||
method: 'get',
|
||||
timeout: 60000,
|
||||
params: {
|
||||
url,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const recognitionTransportCertificates = objectKeys => {
|
||||
return request({
|
||||
url: '/blade-file/file/recognitionTransportCertificates',
|
||||
method: 'post',
|
||||
timeout: 60000,
|
||||
data: objectKeys,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -58,3 +58,12 @@ export const getExpiryStat = params => {
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
export const recognitionTransportCertificates = objectKeys => {
|
||||
return request({
|
||||
url: '/blade-file/file/recognitionTransportCertificates',
|
||||
method: 'post',
|
||||
timeout: 60000,
|
||||
data: objectKeys,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
:class="[`${classPrefix}-uploader`, { [`${classPrefix}-uploader--large`]: large }]"
|
||||
action="/api/blade-resource/oss/endpoint/put-file"
|
||||
name="file"
|
||||
:headers="headers"
|
||||
:headers="uploadHeaders"
|
||||
:show-file-list="false"
|
||||
:disabled="readonly"
|
||||
:before-upload="beforeUpload"
|
||||
:on-progress="handleProgress"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
>
|
||||
<img v-if="value" :src="value" :class="`${classPrefix}-uploader__image`" />
|
||||
<div v-else :class="`${classPrefix}-uploader__empty`">{{ emptyText }}</div>
|
||||
@@ -24,11 +26,13 @@
|
||||
:class="`${classPrefix}-upload-card__uploader`"
|
||||
action="/api/blade-resource/oss/endpoint/put-file"
|
||||
name="file"
|
||||
:headers="headers"
|
||||
:headers="uploadHeaders"
|
||||
:show-file-list="false"
|
||||
:disabled="readonly"
|
||||
:before-upload="beforeUpload"
|
||||
:on-progress="handleProgress"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
>
|
||||
<img v-if="value" :src="value" :class="`${classPrefix}-upload-card__image`" />
|
||||
<div v-else :class="`${classPrefix}-upload-card__empty`">{{ emptyText }}</div>
|
||||
@@ -38,6 +42,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ElLoading } from 'element-plus';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
|
||||
export default {
|
||||
name: 'ImageUploadField',
|
||||
props: {
|
||||
@@ -64,15 +71,54 @@ export default {
|
||||
default: '点击上传',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
uploadHeaders() {
|
||||
return getUploadHeaders(this.headers || {});
|
||||
},
|
||||
},
|
||||
emits: ['success'],
|
||||
data() {
|
||||
return {
|
||||
uploadLoading: null,
|
||||
};
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.closeUploadLoading();
|
||||
},
|
||||
methods: {
|
||||
showUploadLoading() {
|
||||
if (this.uploadLoading) {
|
||||
return;
|
||||
}
|
||||
this.uploadLoading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '上传中',
|
||||
background: 'rgba(255, 255, 255, 0.7)',
|
||||
});
|
||||
},
|
||||
closeUploadLoading() {
|
||||
if (!this.uploadLoading) {
|
||||
return;
|
||||
}
|
||||
this.uploadLoading.close();
|
||||
this.uploadLoading = null;
|
||||
},
|
||||
handleProgress() {
|
||||
this.showUploadLoading();
|
||||
},
|
||||
handleSuccess(res) {
|
||||
this.closeUploadLoading();
|
||||
if (res.code === 200 && res.data) {
|
||||
this.$emit('success', res.data.link || res.data.url || res.data.domain || '');
|
||||
this.$message.success('上传完成');
|
||||
this.$emit('success', res.data.link || res.data.url || res.data.domain || '', res.data);
|
||||
} else {
|
||||
this.$message.error(res.msg || '上传失败');
|
||||
}
|
||||
},
|
||||
handleError() {
|
||||
this.closeUploadLoading();
|
||||
this.$message.error('上传失败');
|
||||
},
|
||||
beforeUpload(file) {
|
||||
const validType = ['image/jpeg', 'image/png', 'image/jpg', 'image/bmp'].includes(file.type);
|
||||
const validSize = file.size / 1024 / 1024 < 5;
|
||||
@@ -82,7 +128,11 @@ export default {
|
||||
if (!validSize) {
|
||||
this.$message.error('图片大小不能超过 5MB');
|
||||
}
|
||||
return validType && validSize;
|
||||
const valid = validType && validSize;
|
||||
if (valid) {
|
||||
this.showUploadLoading();
|
||||
}
|
||||
return valid;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
:multiple="multiple"
|
||||
:limit="limit"
|
||||
:disabled="readonly"
|
||||
:show-file-list="true"
|
||||
:show-file-list="showFileList"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:on-remove="handleRemove"
|
||||
@@ -69,8 +69,7 @@ import {
|
||||
import '@open-file-viewer/core/style.css';
|
||||
import pdfWorkerSrc from 'pdfjs-dist/build/pdf.worker.mjs?url';
|
||||
import { baseUrl } from '@/config/env';
|
||||
import website from '@/config/website';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
|
||||
const MIME_MAP = {
|
||||
jpg: 'image/jpeg',
|
||||
@@ -159,6 +158,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showFileList: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'change', 'success'],
|
||||
data() {
|
||||
@@ -182,9 +185,7 @@ export default {
|
||||
return this.action || `${baseUrl}/blade-resource/oss/endpoint/put-file`;
|
||||
},
|
||||
uploadHeaders() {
|
||||
return {
|
||||
[website.tokenHeader]: getToken(),
|
||||
};
|
||||
return getUploadHeaders();
|
||||
},
|
||||
acceptedList() {
|
||||
const types = this.fileTypes.length ? this.fileTypes : this.accept;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
export const transportTypeOptions = [
|
||||
{ label: '公路整车', value: '公路整车' },
|
||||
{ label: '公路零担', value: '公路零担' },
|
||||
{ label: '公路运输', value: '公路运输' },
|
||||
{ label: '铁路运输', value: '铁路运输' },
|
||||
{ label: '水路运输', value: '水路运输' },
|
||||
{ label: '跨境海运', value: '跨境海运' },
|
||||
{ label: '航空运输', value: '航空运输' },
|
||||
];
|
||||
|
||||
|
||||
@@ -4,98 +4,156 @@ import {
|
||||
contractCategoryOptions,
|
||||
contractStageOptions,
|
||||
createCrudOption,
|
||||
effectiveTypeOptions,
|
||||
selectRule,
|
||||
settlementModeOptions,
|
||||
signTypeOptions,
|
||||
textRule,
|
||||
} 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 = {
|
||||
title: '合同管理',
|
||||
permission: 'contract_manage',
|
||||
exportUrl: '/blade-transport/contract-manage/export-contract-manage',
|
||||
exportName: '合同管理',
|
||||
enableAllDept: true,
|
||||
enableAllDept: false,
|
||||
batchDelete: false,
|
||||
enableContractForm: true,
|
||||
enableProjectSelect: true,
|
||||
enableContractPeriod: true,
|
||||
enableContractFileUpload: true,
|
||||
enableCurrentUserHandler: true,
|
||||
enableBillingPlan: true,
|
||||
enableSettlementRule: true,
|
||||
enableReconciliation: true,
|
||||
enableAttachmentTable: true,
|
||||
enableChangeRecord: true,
|
||||
enableOrganizationSelect: true,
|
||||
enableContractCreateActions: true,
|
||||
actions: ['copy'],
|
||||
statusProp: 'approvalStatus',
|
||||
statusTextProp: 'approvalStatusName',
|
||||
customMenuActions: true,
|
||||
editLabelStatusMap: {
|
||||
change_rejected: '编辑变更内容',
|
||||
},
|
||||
deleteStatus: ['draft'],
|
||||
deleteStage: ['draft'],
|
||||
editStatus: ['draft', 'rejected', 'change_rejected'],
|
||||
operations: [
|
||||
{
|
||||
action: 'toTemporary',
|
||||
label: '转临时',
|
||||
action: 'flow',
|
||||
label: '查看流程',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['draft'],
|
||||
stage: ['draft'],
|
||||
permission: 'contract_manage_temp',
|
||||
},
|
||||
{
|
||||
action: 'submitFormal',
|
||||
label: '转正式',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['draft', 'rejected', 'approved'],
|
||||
stage: ['temporary'],
|
||||
permission: 'contract_manage_formal',
|
||||
status: ['reviewing', 'change_reviewing'],
|
||||
stage: ['temporary', 'formal'],
|
||||
permission: 'contract_manage_view',
|
||||
},
|
||||
{
|
||||
action: 'withdraw',
|
||||
label: '撤回',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['reviewing', 'change_reviewing'],
|
||||
status: ['reviewing'],
|
||||
stage: ['temporary'],
|
||||
permission: 'contract_manage_withdraw',
|
||||
},
|
||||
{
|
||||
action: 'approve',
|
||||
label: '审批通过',
|
||||
type: 'success',
|
||||
action: 'submitFormal',
|
||||
label: '重新提交转正',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['reviewing', 'change_reviewing'],
|
||||
permission: 'contract_manage_approve',
|
||||
},
|
||||
{
|
||||
action: 'reject',
|
||||
label: '审批驳回',
|
||||
type: 'warning',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['reviewing', 'change_reviewing'],
|
||||
permission: 'contract_manage_reject',
|
||||
status: ['rejected'],
|
||||
stage: ['temporary'],
|
||||
permission: 'contract_manage_formal',
|
||||
},
|
||||
{
|
||||
action: 'startChange',
|
||||
label: '发起变更',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['approved', 'change_approved'],
|
||||
status: ['approved'],
|
||||
stage: ['formal'],
|
||||
permission: 'contract_manage_change',
|
||||
prompt: '请输入变更内容与原因',
|
||||
},
|
||||
{
|
||||
action: 'terminate',
|
||||
label: '终止',
|
||||
type: 'danger',
|
||||
action: 'startChange',
|
||||
label: '再次发起变更',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['change_approved'],
|
||||
stage: ['formal'],
|
||||
permission: 'contract_manage_change',
|
||||
prompt: '请输入变更内容与原因',
|
||||
},
|
||||
{
|
||||
action: 'attachmentUpload',
|
||||
label: '附件上传',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['approved', 'change_approved'],
|
||||
stage: ['formal'],
|
||||
permission: 'contract_manage_terminate',
|
||||
prompt: '请输入终止原因',
|
||||
permission: 'contract_manage_edit',
|
||||
},
|
||||
{
|
||||
action: 'flow',
|
||||
label: '查看流程',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['approved', 'change_approved'],
|
||||
stage: ['formal', 'terminated'],
|
||||
permission: 'contract_manage_view',
|
||||
},
|
||||
{
|
||||
action: 'withdraw',
|
||||
label: '撤回变更',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['change_reviewing'],
|
||||
stage: ['formal'],
|
||||
permission: 'contract_manage_withdraw',
|
||||
},
|
||||
{
|
||||
action: 'startChange',
|
||||
label: '重新提交变更',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['change_rejected'],
|
||||
stage: ['formal'],
|
||||
permission: 'contract_manage_change',
|
||||
prompt: '请输入变更内容与原因',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const option = createCrudOption([
|
||||
{
|
||||
label: '',
|
||||
prop: 'basicInfoTitle',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: 200,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '合同编号',
|
||||
prop: 'contractNo',
|
||||
search: true,
|
||||
searchOrder: 6,
|
||||
order: 185,
|
||||
disabled: true,
|
||||
placeholder: '不填写,则系统自动生成',
|
||||
minWidth: 160,
|
||||
addDisplay: false,
|
||||
editDisabled: true,
|
||||
},
|
||||
{
|
||||
label: '合同名称',
|
||||
prop: 'contractName',
|
||||
search: true,
|
||||
searchOrder: 7,
|
||||
order: 180,
|
||||
minWidth: 180,
|
||||
rules: textRule('合同名称', 100, true),
|
||||
},
|
||||
@@ -103,26 +161,54 @@ export const option = createCrudOption([
|
||||
label: '所属项目',
|
||||
prop: 'projectName',
|
||||
search: true,
|
||||
searchOrder: 8,
|
||||
searchType: 'select',
|
||||
formslot: true,
|
||||
order: 140,
|
||||
dicUrl: '/blade-transport/project-apply/list?current=1&size=9999',
|
||||
dicFormatter: listDicFormatter,
|
||||
props: {
|
||||
label: 'projectName',
|
||||
value: 'projectName',
|
||||
},
|
||||
filterable: true,
|
||||
minWidth: 160,
|
||||
rules: selectRule('所属项目'),
|
||||
},
|
||||
{
|
||||
label: '所属项目ID',
|
||||
prop: 'projectId',
|
||||
hide: true,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '所属组织',
|
||||
prop: 'organizationName',
|
||||
search: true,
|
||||
searchOrder: 3,
|
||||
searchType: 'cascader',
|
||||
formslot: true,
|
||||
order: 120,
|
||||
dicData: [],
|
||||
props: {
|
||||
label: 'label',
|
||||
value: 'id',
|
||||
children: 'children',
|
||||
},
|
||||
checkStrictly: true,
|
||||
emitPath: false,
|
||||
showAllLevels: false,
|
||||
filterable: true,
|
||||
minWidth: 150,
|
||||
addDisplay: false,
|
||||
editDisabled: true,
|
||||
rules: selectRule('所属组织'),
|
||||
},
|
||||
{
|
||||
label: '合同类别',
|
||||
prop: 'contractCategory',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 9,
|
||||
order: 170,
|
||||
dicData: contractCategoryOptions,
|
||||
minWidth: 130,
|
||||
rules: selectRule('合同类别'),
|
||||
@@ -132,18 +218,60 @@ export const option = createCrudOption([
|
||||
prop: 'signType',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 1,
|
||||
span: 24,
|
||||
order: 190,
|
||||
dicData: signTypeOptions,
|
||||
minWidth: 120,
|
||||
rules: selectRule('签约类型'),
|
||||
},
|
||||
{
|
||||
label: '生效类型',
|
||||
prop: 'effectiveType',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 5,
|
||||
dicData: effectiveTypeOptions,
|
||||
hide: true,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '甲方',
|
||||
prop: 'partyA',
|
||||
type: 'select',
|
||||
order: 160,
|
||||
dicUrl: '/blade-transport/customer-archive/list?current=1&size=9999&approvalStatus=approved',
|
||||
dicFormatter: listDicFormatter,
|
||||
props: {
|
||||
label: 'fullName',
|
||||
value: 'fullName',
|
||||
},
|
||||
filterable: true,
|
||||
minWidth: 160,
|
||||
rules: selectRule('甲方'),
|
||||
},
|
||||
{
|
||||
label: '乙方',
|
||||
prop: 'partyB',
|
||||
type: 'select',
|
||||
order: 150,
|
||||
dicUrl: '/blade-transport/customer-archive/list?current=1&size=9999&approvalStatus=approved',
|
||||
dicFormatter: listDicFormatter,
|
||||
props: {
|
||||
label: 'fullName',
|
||||
value: 'fullName',
|
||||
},
|
||||
filterable: true,
|
||||
minWidth: 160,
|
||||
rules: selectRule('乙方'),
|
||||
},
|
||||
{
|
||||
label: '合同期限',
|
||||
prop: 'contractPeriod',
|
||||
formslot: true,
|
||||
order: 130,
|
||||
hide: true,
|
||||
rules: [{ required: true, message: '请选择合同期限', trigger: 'change' }],
|
||||
},
|
||||
{
|
||||
label: '开始日期',
|
||||
@@ -152,6 +280,8 @@ export const option = createCrudOption([
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
minWidth: 130,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '结束日期',
|
||||
@@ -160,6 +290,8 @@ export const option = createCrudOption([
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
minWidth: 130,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '临时效力起',
|
||||
@@ -168,6 +300,8 @@ export const option = createCrudOption([
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
minWidth: 130,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '临时效力止',
|
||||
@@ -176,11 +310,16 @@ export const option = createCrudOption([
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
minWidth: 130,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '经办人',
|
||||
prop: 'handlerUserName',
|
||||
order: 110,
|
||||
disabled: true,
|
||||
minWidth: 120,
|
||||
rules: textRule('经办人', 50, true),
|
||||
},
|
||||
{
|
||||
label: '签订日期',
|
||||
@@ -188,14 +327,20 @@ export const option = createCrudOption([
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
hide: true,
|
||||
order: 100,
|
||||
minWidth: 130,
|
||||
rules: [{ required: true, message: '请选择签订日期', trigger: 'change' }],
|
||||
},
|
||||
{
|
||||
label: '结算方式',
|
||||
prop: 'settlementMode',
|
||||
type: 'select',
|
||||
dicData: settlementModeOptions,
|
||||
hide: true,
|
||||
order: 90,
|
||||
minWidth: 120,
|
||||
rules: selectRule('结算方式'),
|
||||
},
|
||||
{
|
||||
label: '合同格式',
|
||||
@@ -205,54 +350,74 @@ export const option = createCrudOption([
|
||||
{ label: '电子合同', value: '电子合同' },
|
||||
{ label: '纸质合同', value: '纸质合同' },
|
||||
],
|
||||
hide: true,
|
||||
order: 80,
|
||||
minWidth: 120,
|
||||
rules: selectRule('合同格式'),
|
||||
},
|
||||
{
|
||||
label: '法人章',
|
||||
label: '是否需要加盖法人章',
|
||||
prop: 'legalSealFlag',
|
||||
type: 'switch',
|
||||
type: 'select',
|
||||
dicData: [
|
||||
{ label: '否', value: 0 },
|
||||
{ label: '是', value: 1 },
|
||||
],
|
||||
value: 0,
|
||||
hide: true,
|
||||
order: 70,
|
||||
minWidth: 100,
|
||||
rules: selectRule('是否需要加盖法人章'),
|
||||
},
|
||||
{
|
||||
label: '一式份数',
|
||||
label: '一式',
|
||||
prop: 'copyCount',
|
||||
type: 'number',
|
||||
formslot: true,
|
||||
hide: true,
|
||||
order: 60,
|
||||
minWidth: 110,
|
||||
},
|
||||
{
|
||||
label: '回款账期(天)',
|
||||
label: '回款账期',
|
||||
prop: 'paymentDays',
|
||||
type: 'number',
|
||||
formslot: true,
|
||||
hide: true,
|
||||
order: 50,
|
||||
minWidth: 130,
|
||||
},
|
||||
{
|
||||
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,
|
||||
},
|
||||
{
|
||||
label: '合同阶段',
|
||||
prop: 'contractStage',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 2,
|
||||
slot: true,
|
||||
dicData: contractStageOptions,
|
||||
minWidth: 120,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
fixed: 'right',
|
||||
},
|
||||
{
|
||||
label: '审核状态',
|
||||
prop: 'approvalStatus',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 4,
|
||||
slot: true,
|
||||
dicData: contractApprovalStatusOptions,
|
||||
minWidth: 130,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
fixed: 'right',
|
||||
},
|
||||
{
|
||||
label: '当前节点',
|
||||
@@ -276,53 +441,133 @@ export const option = createCrudOption([
|
||||
{ label: '关闭', value: 0 },
|
||||
{ label: '开启', value: 1 },
|
||||
],
|
||||
value: 0,
|
||||
value: 1,
|
||||
hide: true,
|
||||
display: false,
|
||||
minWidth: 110,
|
||||
},
|
||||
{
|
||||
label: '合同主文件JSON',
|
||||
prop: 'contractFileJson',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '其它附件JSON',
|
||||
prop: 'attachmentsJson',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '计费方案JSON',
|
||||
prop: 'billingPlanJson',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '结算生成规则JSON',
|
||||
prop: 'settlementRuleJson',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '对账配置JSON',
|
||||
prop: 'reconciliationJson',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
hide: true,
|
||||
order: 40,
|
||||
maxlength: 2000,
|
||||
showWordLimit: true,
|
||||
rules: textRule('备注', 2000),
|
||||
},
|
||||
...auditColumns,
|
||||
{
|
||||
label: '',
|
||||
prop: 'contractFileTitle',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: 30,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '附件',
|
||||
prop: 'contractFileJson',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: 20,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
prop: 'billingInfoTitle',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: 10,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
prop: 'billingPlanJson',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: 0,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
prop: 'settlementRuleTitle',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: -10,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
prop: 'settlementRuleJson',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: -20,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
prop: 'reconciliationTitle',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: -30,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
prop: 'reconciliationJson',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: -40,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
prop: 'attachmentTitle',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: -50,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
prop: 'attachmentsJson',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: -60,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
prop: 'changeRecordTitle',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: -70,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
prop: 'changeRecordJson',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
order: -80,
|
||||
hide: true,
|
||||
labelWidth: 0,
|
||||
},
|
||||
...auditColumns
|
||||
.filter(column => column.prop !== 'createTime')
|
||||
.map(column => ({ ...column, hide: true })),
|
||||
]);
|
||||
|
||||
option.span = 8;
|
||||
option.dialogWidth = 1480;
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
selectRule,
|
||||
textRule,
|
||||
} from './common';
|
||||
import { applyTableMenuWidth } from '@/utils/table-menu';
|
||||
|
||||
export const config = {
|
||||
title: '过程配置',
|
||||
@@ -19,7 +20,7 @@ export const config = {
|
||||
deleteStatus: [0, 2],
|
||||
};
|
||||
|
||||
export const option = {
|
||||
export const option = applyTableMenuWidth({
|
||||
...createCrudOption([
|
||||
{
|
||||
label: '',
|
||||
@@ -144,4 +145,4 @@ export const option = {
|
||||
dialogTop: '10px',
|
||||
dialogWidth: '96%',
|
||||
searchSpan: 8,
|
||||
};
|
||||
}, 5);
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
selectRule,
|
||||
settlementModeOptions,
|
||||
textRule,
|
||||
transportTypeOptions,
|
||||
} from './common';
|
||||
|
||||
const amountRules = label => [
|
||||
@@ -18,12 +17,24 @@ const amountRules = label => [
|
||||
nonNegativeRule(label),
|
||||
];
|
||||
|
||||
const userDicFormatter = res => {
|
||||
const list = Array.isArray(res)
|
||||
? res
|
||||
: Array.isArray(res.data)
|
||||
? res.data
|
||||
: res.data?.records || [];
|
||||
return list.map(user => ({
|
||||
...user,
|
||||
realName: user.realName || user.name || user.account,
|
||||
}));
|
||||
};
|
||||
|
||||
export const config = {
|
||||
title: '项目管理',
|
||||
permission: 'project_apply',
|
||||
exportUrl: '/blade-transport/project-apply/export-project-apply',
|
||||
exportName: '项目立项',
|
||||
enableAllDept: true,
|
||||
enableAllDept: false,
|
||||
statusProp: 'approvalStatus',
|
||||
statusTextProp: 'approvalStatusName',
|
||||
deleteStatus: ['draft', 'withdrawn', 'rejected'],
|
||||
@@ -31,9 +42,9 @@ export const config = {
|
||||
operations: [
|
||||
{
|
||||
action: 'submitApproval',
|
||||
label: '提交审批',
|
||||
label: '提交',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['draft', 'withdrawn', 'rejected'],
|
||||
status: ['draft'],
|
||||
permission: 'project_apply_submit',
|
||||
},
|
||||
{
|
||||
@@ -45,7 +56,7 @@ export const config = {
|
||||
},
|
||||
{
|
||||
action: 'approve',
|
||||
label: '审批通过',
|
||||
label: '通过',
|
||||
type: 'success',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['reviewing', 'change_reviewing'],
|
||||
@@ -61,11 +72,10 @@ export const config = {
|
||||
},
|
||||
{
|
||||
action: 'startChange',
|
||||
label: '发起变更',
|
||||
label: '变更',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['approved', 'change_approved'],
|
||||
status: ['approved'],
|
||||
permission: 'project_apply_change',
|
||||
prompt: '请输入变更内容与原因',
|
||||
},
|
||||
{
|
||||
action: 'voidProject',
|
||||
@@ -84,6 +94,7 @@ export const option = createCrudOption([
|
||||
label: '立项申请单号',
|
||||
prop: 'applyNo',
|
||||
search: true,
|
||||
searchOrder: 7,
|
||||
minWidth: 160,
|
||||
addDisplay: false,
|
||||
editDisabled: true,
|
||||
@@ -99,6 +110,7 @@ export const option = createCrudOption([
|
||||
label: '项目名称',
|
||||
prop: 'projectName',
|
||||
search: true,
|
||||
searchOrder: 6,
|
||||
minWidth: 180,
|
||||
maxlength: 50,
|
||||
rules: textRule('项目名称', 50, true),
|
||||
@@ -106,6 +118,7 @@ export const option = createCrudOption([
|
||||
{
|
||||
label: '项目简称',
|
||||
prop: 'projectShortName',
|
||||
hide: true,
|
||||
minWidth: 140,
|
||||
maxlength: 20,
|
||||
rules: textRule('项目简称', 20, true),
|
||||
@@ -115,13 +128,27 @@ export const option = createCrudOption([
|
||||
prop: 'projectType',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 3,
|
||||
dicData: projectTypeOptions,
|
||||
minWidth: 120,
|
||||
rules: selectRule('项目类型'),
|
||||
},
|
||||
{
|
||||
label: '客户名称',
|
||||
prop: 'customerNames',
|
||||
minWidth: 180,
|
||||
rules: textRule('客户名称', 255, true),
|
||||
},
|
||||
{
|
||||
label: '下游承运商',
|
||||
prop: 'carrierNames',
|
||||
minWidth: 180,
|
||||
rules: textRule('下游承运商', 255, true),
|
||||
},
|
||||
{
|
||||
label: '业务部门',
|
||||
prop: 'businessDeptName',
|
||||
hide: true,
|
||||
minWidth: 150,
|
||||
rules: textRule('业务部门', 50, true),
|
||||
},
|
||||
@@ -129,6 +156,8 @@ export const option = createCrudOption([
|
||||
label: '承办部门',
|
||||
prop: 'undertakeDeptName',
|
||||
search: true,
|
||||
searchLabel: '承办单位',
|
||||
searchOrder: 5,
|
||||
minWidth: 150,
|
||||
rules: textRule('承办部门', 50, true),
|
||||
},
|
||||
@@ -140,13 +169,29 @@ export const option = createCrudOption([
|
||||
{
|
||||
label: '项目负责人',
|
||||
prop: 'principalUserName',
|
||||
search: true,
|
||||
minWidth: 130,
|
||||
rules: textRule('项目负责人', 50, true),
|
||||
},
|
||||
{
|
||||
label: '项目负责人',
|
||||
prop: 'principalUserId',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 4,
|
||||
filterable: true,
|
||||
dicUrl: '/blade-system/user/user-list',
|
||||
dicFormatter: userDicFormatter,
|
||||
props: {
|
||||
label: 'realName',
|
||||
value: 'id',
|
||||
},
|
||||
hide: true,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '项目经办人',
|
||||
prop: 'handlerUserName',
|
||||
hide: true,
|
||||
minWidth: 130,
|
||||
rules: textRule('项目经办人', 50, true),
|
||||
},
|
||||
@@ -156,6 +201,7 @@ export const option = createCrudOption([
|
||||
type: 'select',
|
||||
dicData: projectSourceOptions,
|
||||
value: '商务洽谈',
|
||||
hide: true,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
@@ -163,6 +209,7 @@ export const option = createCrudOption([
|
||||
prop: 'fundLimit',
|
||||
type: 'number',
|
||||
precision: 2,
|
||||
hide: true,
|
||||
minWidth: 190,
|
||||
rules: amountRules('项目资金使用额度'),
|
||||
},
|
||||
@@ -171,6 +218,7 @@ export const option = createCrudOption([
|
||||
prop: 'receivableLimit',
|
||||
type: 'number',
|
||||
precision: 2,
|
||||
hide: true,
|
||||
minWidth: 200,
|
||||
rules: amountRules('项目应收账款额度'),
|
||||
},
|
||||
@@ -178,6 +226,7 @@ export const option = createCrudOption([
|
||||
label: '应收账款回款期限(天)',
|
||||
prop: 'receivableDays',
|
||||
type: 'number',
|
||||
hide: true,
|
||||
minWidth: 190,
|
||||
rules: [{ required: true, message: '请输入应收账款回款期限', trigger: 'blur' }],
|
||||
},
|
||||
@@ -185,30 +234,20 @@ export const option = createCrudOption([
|
||||
label: '回款账期(天)',
|
||||
prop: 'paymentDays',
|
||||
type: 'number',
|
||||
hide: true,
|
||||
minWidth: 140,
|
||||
rules: [{ required: true, message: '请输入回款账期', trigger: 'blur' }],
|
||||
},
|
||||
{
|
||||
label: '客户名称',
|
||||
prop: 'customerNames',
|
||||
search: true,
|
||||
minWidth: 180,
|
||||
rules: textRule('客户名称', 255, true),
|
||||
},
|
||||
{
|
||||
label: '下游承运商',
|
||||
prop: 'carrierNames',
|
||||
minWidth: 180,
|
||||
rules: textRule('下游承运商', 255, true),
|
||||
},
|
||||
{
|
||||
label: '货物类型',
|
||||
prop: 'cargoType',
|
||||
hide: true,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
label: '预估货物数量',
|
||||
prop: 'cargoQuantity',
|
||||
hide: true,
|
||||
minWidth: 150,
|
||||
maxlength: 100,
|
||||
},
|
||||
@@ -218,6 +257,7 @@ export const option = createCrudOption([
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
hide: true,
|
||||
minWidth: 130,
|
||||
},
|
||||
{
|
||||
@@ -226,11 +266,13 @@ export const option = createCrudOption([
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
hide: true,
|
||||
minWidth: 130,
|
||||
},
|
||||
{
|
||||
label: '运输线路',
|
||||
prop: 'transportRoute',
|
||||
hide: true,
|
||||
minWidth: 180,
|
||||
maxlength: 100,
|
||||
},
|
||||
@@ -238,7 +280,12 @@ export const option = createCrudOption([
|
||||
label: '运输类型',
|
||||
prop: 'transportType',
|
||||
type: 'select',
|
||||
dicData: transportTypeOptions,
|
||||
dicUrl: '/blade-system/dict-biz/dictionary?code=transport_type',
|
||||
props: {
|
||||
label: 'dictValue',
|
||||
value: 'dictKey',
|
||||
},
|
||||
hide: true,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
@@ -246,6 +293,7 @@ export const option = createCrudOption([
|
||||
prop: 'businessType',
|
||||
type: 'select',
|
||||
dicData: businessTypeOptions,
|
||||
hide: true,
|
||||
minWidth: 130,
|
||||
},
|
||||
{
|
||||
@@ -253,6 +301,7 @@ export const option = createCrudOption([
|
||||
prop: 'projectScale',
|
||||
type: 'number',
|
||||
precision: 2,
|
||||
hide: true,
|
||||
minWidth: 150,
|
||||
rules: [nonNegativeRule('项目规模')],
|
||||
},
|
||||
@@ -261,6 +310,7 @@ export const option = createCrudOption([
|
||||
prop: 'estimatedProfit',
|
||||
type: 'number',
|
||||
precision: 2,
|
||||
hide: true,
|
||||
minWidth: 150,
|
||||
rules: [nonNegativeRule('预计利润')],
|
||||
},
|
||||
@@ -269,6 +319,7 @@ export const option = createCrudOption([
|
||||
prop: 'fundDemand',
|
||||
type: 'number',
|
||||
precision: 2,
|
||||
hide: true,
|
||||
minWidth: 150,
|
||||
rules: [nonNegativeRule('资金需求')],
|
||||
},
|
||||
@@ -277,6 +328,7 @@ export const option = createCrudOption([
|
||||
prop: 'settlementMode',
|
||||
type: 'select',
|
||||
dicData: settlementModeOptions,
|
||||
hide: true,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
@@ -284,12 +336,12 @@ export const option = createCrudOption([
|
||||
prop: 'approvalStatus',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 2,
|
||||
slot: true,
|
||||
dicData: projectApprovalStatusOptions,
|
||||
minWidth: 130,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
fixed: 'right',
|
||||
},
|
||||
{
|
||||
label: '当前节点',
|
||||
@@ -310,6 +362,7 @@ export const option = createCrudOption([
|
||||
prop: 'effectiveType',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 1,
|
||||
dicData: effectiveTypeOptions,
|
||||
value: 'temporary',
|
||||
minWidth: 110,
|
||||
@@ -349,5 +402,5 @@ export const option = createCrudOption([
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
...auditColumns,
|
||||
...auditColumns.map(column => ({ ...column, hide: true })),
|
||||
]);
|
||||
|
||||
@@ -12,7 +12,7 @@ export const config = {
|
||||
permission: 'shipping_template',
|
||||
exportUrl: '/blade-transport/shipping-template/export-shipping-template',
|
||||
exportName: '发货模板',
|
||||
enableAllDept: true,
|
||||
enableAllDept: false,
|
||||
actions: ['copy'],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,23 +1,61 @@
|
||||
import { approvalStatusOptions, auditColumns, createCrudOption, nonNegativeRule, textRule } from './common';
|
||||
import {
|
||||
approvalStatusOptions,
|
||||
auditColumns,
|
||||
createCrudOption,
|
||||
nonNegativeRule,
|
||||
textRule,
|
||||
} from './common';
|
||||
|
||||
const listDicFormatter = res => {
|
||||
const data = res?.data || res;
|
||||
if (Array.isArray(data)) return data;
|
||||
if (Array.isArray(data?.records)) return data.records;
|
||||
if (Array.isArray(data?.data)) return data.data;
|
||||
if (Array.isArray(data?.data?.records)) return data.data.records;
|
||||
return [];
|
||||
};
|
||||
|
||||
const userDicFormatter = res =>
|
||||
listDicFormatter(res).map(user => ({
|
||||
...user,
|
||||
realName: user.realName || user.name || user.account,
|
||||
}));
|
||||
|
||||
export const config = {
|
||||
title: '临时额度管理',
|
||||
permission: 'temporary_credit_limit',
|
||||
exportUrl: '/blade-transport/temporary-credit-limit/export-temporary-credit-limit',
|
||||
exportName: '临时额度申请',
|
||||
enableAllDept: true,
|
||||
enableAllDept: false,
|
||||
enableProjectSelect: true,
|
||||
enableAttachmentTable: true,
|
||||
enableDraftSave: true,
|
||||
saveAsDraft: true,
|
||||
defaultForm: {
|
||||
usedFundLimit: 0,
|
||||
remainingFundLimit: 0,
|
||||
},
|
||||
statusProp: 'approvalStatus',
|
||||
statusTextProp: 'approvalStatusName',
|
||||
deleteStatus: ['draft', 'withdrawn', 'rejected'],
|
||||
editStatus: ['draft', 'withdrawn', 'rejected'],
|
||||
deleteStatus: ['draft', 'withdrawn', 'rejected', '草稿'],
|
||||
editStatus: ['draft', 'withdrawn', 'rejected', '草稿', '已撤回'],
|
||||
ignoreReadonlyEditStatus: ['draft', 'withdrawn', '草稿', '已撤回'],
|
||||
ignoreReadonlyDeleteStatus: ['draft', '草稿'],
|
||||
operations: [
|
||||
{
|
||||
action: 'submitApproval',
|
||||
label: '提交审批',
|
||||
label: '提交',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['draft', 'withdrawn', 'rejected'],
|
||||
permission: 'temporary_credit_limit_submit',
|
||||
},
|
||||
{
|
||||
action: 'flow',
|
||||
label: '流程',
|
||||
statusProp: 'approvalStatus',
|
||||
status: ['reviewing'],
|
||||
permission: 'temporary_credit_limit_view',
|
||||
},
|
||||
{
|
||||
action: 'withdraw',
|
||||
label: '撤回',
|
||||
@@ -44,145 +82,184 @@ export const config = {
|
||||
],
|
||||
};
|
||||
|
||||
export const option = createCrudOption([
|
||||
{
|
||||
label: '申请单号',
|
||||
prop: 'applicationNo',
|
||||
search: true,
|
||||
minWidth: 160,
|
||||
addDisplay: false,
|
||||
editDisabled: true,
|
||||
},
|
||||
{
|
||||
label: '项目名称',
|
||||
prop: 'projectName',
|
||||
search: true,
|
||||
minWidth: 180,
|
||||
rules: textRule('项目名称', 100, true),
|
||||
},
|
||||
{
|
||||
label: '项目ID',
|
||||
prop: 'projectId',
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '项目编号',
|
||||
prop: 'projectCode',
|
||||
minWidth: 150,
|
||||
rules: textRule('项目编号', 50, true),
|
||||
},
|
||||
{
|
||||
label: '承办部门',
|
||||
prop: 'undertakeDeptName',
|
||||
minWidth: 150,
|
||||
rules: textRule('承办部门', 50, true),
|
||||
},
|
||||
{
|
||||
label: '项目资金使用额度(万元)',
|
||||
prop: 'projectFundLimit',
|
||||
type: 'number',
|
||||
precision: 2,
|
||||
minWidth: 200,
|
||||
editDisabled: true,
|
||||
rules: [nonNegativeRule('项目资金使用额度')],
|
||||
},
|
||||
{
|
||||
label: '已使用项目资金额度(万元)',
|
||||
prop: 'usedFundLimit',
|
||||
type: 'number',
|
||||
precision: 2,
|
||||
minWidth: 220,
|
||||
value: 0,
|
||||
editDisabled: true,
|
||||
rules: [nonNegativeRule('已使用项目资金额度')],
|
||||
},
|
||||
{
|
||||
label: '剩余项目资金使用额度(万元)',
|
||||
prop: 'remainingFundLimit',
|
||||
type: 'number',
|
||||
precision: 2,
|
||||
minWidth: 230,
|
||||
editDisabled: true,
|
||||
rules: [nonNegativeRule('剩余项目资金使用额度')],
|
||||
},
|
||||
{
|
||||
label: '申请临时额度(万元)',
|
||||
prop: 'applyLimit',
|
||||
type: 'number',
|
||||
precision: 2,
|
||||
minWidth: 180,
|
||||
rules: [
|
||||
{ required: true, message: '请输入申请临时额度', trigger: 'blur' },
|
||||
nonNegativeRule('申请临时额度'),
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '申请有效期至',
|
||||
prop: 'validUntil',
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
minWidth: 140,
|
||||
rules: [{ required: true, message: '请选择申请有效期至', trigger: 'change' }],
|
||||
},
|
||||
{
|
||||
label: '申请部门',
|
||||
prop: 'applyDeptName',
|
||||
search: true,
|
||||
minWidth: 150,
|
||||
addDisplay: false,
|
||||
editDisabled: true,
|
||||
},
|
||||
{
|
||||
label: '申请人',
|
||||
prop: 'applicantName',
|
||||
search: true,
|
||||
minWidth: 120,
|
||||
addDisplay: false,
|
||||
editDisabled: true,
|
||||
},
|
||||
{
|
||||
label: '审批状态',
|
||||
prop: 'approvalStatus',
|
||||
type: 'select',
|
||||
search: true,
|
||||
slot: true,
|
||||
dicData: approvalStatusOptions,
|
||||
minWidth: 130,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
fixed: 'right',
|
||||
},
|
||||
{
|
||||
label: '当前节点',
|
||||
prop: 'currentNode',
|
||||
minWidth: 140,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '当前处理人',
|
||||
prop: 'currentProcessor',
|
||||
minWidth: 130,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '附件JSON',
|
||||
prop: 'attachmentsJson',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
hide: true,
|
||||
maxlength: 500,
|
||||
showWordLimit: true,
|
||||
rules: textRule('备注', 500),
|
||||
},
|
||||
...auditColumns,
|
||||
]);
|
||||
export const option = {
|
||||
...createCrudOption([
|
||||
{
|
||||
label: '申请单号',
|
||||
prop: 'applicationNo',
|
||||
search: true,
|
||||
searchOrder: 5,
|
||||
minWidth: 160,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
editDisabled: true,
|
||||
},
|
||||
{
|
||||
label: '项目名称',
|
||||
prop: 'projectName',
|
||||
search: true,
|
||||
searchOrder: 4,
|
||||
searchType: 'select',
|
||||
formslot: true,
|
||||
dicUrl: '/blade-transport/project-apply/list?current=1&size=9999',
|
||||
dicFormatter: listDicFormatter,
|
||||
props: {
|
||||
label: 'projectName',
|
||||
value: 'projectName',
|
||||
},
|
||||
filterable: true,
|
||||
minWidth: 180,
|
||||
rules: textRule('项目名称', 100, true),
|
||||
},
|
||||
{
|
||||
label: '项目ID',
|
||||
prop: 'projectId',
|
||||
hide: true,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '项目编号',
|
||||
prop: 'projectCode',
|
||||
hide: true,
|
||||
disabled: true,
|
||||
minWidth: 150,
|
||||
rules: textRule('项目编号', 50, true),
|
||||
},
|
||||
{
|
||||
label: '承办部门',
|
||||
prop: 'undertakeDeptName',
|
||||
hide: true,
|
||||
disabled: true,
|
||||
minWidth: 150,
|
||||
rules: textRule('承办部门', 50, true),
|
||||
},
|
||||
{
|
||||
label: '项目资金使用额度(万元)',
|
||||
prop: 'projectFundLimit',
|
||||
hide: true,
|
||||
disabled: true,
|
||||
minWidth: 200,
|
||||
rules: [nonNegativeRule('项目资金使用额度')],
|
||||
},
|
||||
{
|
||||
label: '已使用项目资金使用额度(万元)',
|
||||
prop: 'usedFundLimit',
|
||||
hide: true,
|
||||
disabled: true,
|
||||
minWidth: 220,
|
||||
value: 0,
|
||||
rules: [nonNegativeRule('已使用项目资金额度')],
|
||||
},
|
||||
{
|
||||
label: '剩余项目资金使用额度(万元)',
|
||||
prop: 'remainingFundLimit',
|
||||
hide: true,
|
||||
disabled: true,
|
||||
minWidth: 230,
|
||||
value: 0,
|
||||
rules: [nonNegativeRule('剩余项目资金使用额度')],
|
||||
},
|
||||
{
|
||||
label: '申请临时额度(万元)',
|
||||
prop: 'applyLimit',
|
||||
formslot: true,
|
||||
minWidth: 180,
|
||||
rules: [
|
||||
{ required: true, message: '请输入申请临时额度', trigger: 'blur' },
|
||||
nonNegativeRule('申请临时额度'),
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '申请有效期至',
|
||||
prop: 'validUntil',
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
minWidth: 140,
|
||||
rules: [{ required: true, message: '请选择申请有效期至', trigger: 'change' }],
|
||||
},
|
||||
{
|
||||
label: '申请部门',
|
||||
prop: 'applyDeptName',
|
||||
search: true,
|
||||
searchOrder: 2,
|
||||
searchType: 'select',
|
||||
dicUrl: '/blade-system/dept/select',
|
||||
props: {
|
||||
label: 'deptName',
|
||||
value: 'deptName',
|
||||
},
|
||||
filterable: true,
|
||||
minWidth: 150,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
editDisabled: true,
|
||||
},
|
||||
{
|
||||
label: '申请人',
|
||||
prop: 'applicantName',
|
||||
search: true,
|
||||
searchOrder: 3,
|
||||
searchType: 'select',
|
||||
dicUrl: '/blade-system/user/user-list',
|
||||
dicFormatter: userDicFormatter,
|
||||
props: {
|
||||
label: 'realName',
|
||||
value: 'realName',
|
||||
},
|
||||
filterable: true,
|
||||
minWidth: 120,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
editDisabled: true,
|
||||
},
|
||||
{
|
||||
label: '审批状态',
|
||||
searchLabel: '状态',
|
||||
prop: 'approvalStatus',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 1,
|
||||
slot: true,
|
||||
dicData: approvalStatusOptions,
|
||||
minWidth: 130,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
fixed: 'right',
|
||||
},
|
||||
{
|
||||
label: '当前节点',
|
||||
prop: 'currentNode',
|
||||
minWidth: 140,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '当前处理人',
|
||||
prop: 'currentProcessor',
|
||||
minWidth: 130,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
hide: true,
|
||||
maxlength: 200,
|
||||
showWordLimit: true,
|
||||
rules: textRule('备注', 200),
|
||||
},
|
||||
{
|
||||
label: '附件',
|
||||
prop: 'attachmentsJson',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
...auditColumns.map(column => ({ ...column, hide: true })),
|
||||
]),
|
||||
dialogWidth: 1480,
|
||||
index: false,
|
||||
};
|
||||
|
||||
@@ -2,18 +2,128 @@ import {
|
||||
auditColumns,
|
||||
createCrudOption,
|
||||
dataSourceOptions,
|
||||
phoneRule,
|
||||
planStatusOptions,
|
||||
selectRule,
|
||||
textRule,
|
||||
transportTypeOptions,
|
||||
} from './common';
|
||||
|
||||
const listDicFormatter = res => {
|
||||
const data = res?.data || res;
|
||||
if (Array.isArray(data)) return data;
|
||||
if (Array.isArray(data?.records)) return data.records;
|
||||
if (Array.isArray(data?.data)) return data.data;
|
||||
if (Array.isArray(data?.data?.records)) return data.data.records;
|
||||
return [];
|
||||
};
|
||||
|
||||
const parseGoodsRows = value => {
|
||||
if (!value) return [];
|
||||
if (Array.isArray(value)) return value;
|
||||
if (typeof value === 'object') return [value];
|
||||
try {
|
||||
const data = JSON.parse(value);
|
||||
return Array.isArray(data) ? data : [data];
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const formatGoodsField = (row, propList) => {
|
||||
const values = propList.map(prop => row[prop]).filter(Boolean);
|
||||
if (values.length) return values.join('、');
|
||||
return parseGoodsRows(row.goodsJson)
|
||||
.map(item => propList.map(prop => item?.[prop]).find(Boolean))
|
||||
.filter(Boolean)
|
||||
.join('、');
|
||||
};
|
||||
|
||||
const getGoodsQuantity = item => {
|
||||
const value = item?.quantity ?? item?.cargoQuantity ?? item?.goodsQuantity ?? 0;
|
||||
const number = Number(String(value).replace(/,/g, ''));
|
||||
return Number.isFinite(number) ? number : 0;
|
||||
};
|
||||
|
||||
const formatGoodsQuantity = value => {
|
||||
const number = Math.round((value + Number.EPSILON) * 1000) / 1000;
|
||||
return Number.isInteger(number) ? String(number) : String(number).replace(/\.?0+$/, '');
|
||||
};
|
||||
|
||||
const getSecondCargoTypeName = item =>
|
||||
item?.cargoType ||
|
||||
item?.secondCargoTypeName ||
|
||||
item?.secondCargoType ||
|
||||
item?.goodsType ||
|
||||
item?.type ||
|
||||
item?.cargoTypeName ||
|
||||
item?.firstCargoTypeName ||
|
||||
'货物';
|
||||
|
||||
const formatGoodsInfo = row => {
|
||||
const rows = parseGoodsRows(row.goodsJson);
|
||||
if (!rows.length) return row.goodsInfo || '';
|
||||
|
||||
const groups = rows.reduce((result, item = {}) => {
|
||||
const hasGoodsInfo = [
|
||||
item.cargoName,
|
||||
item.goodsName,
|
||||
item.name,
|
||||
item.cargoType,
|
||||
item.secondCargoTypeName,
|
||||
item.goodsType,
|
||||
item.type,
|
||||
item.quantity,
|
||||
item.cargoQuantity,
|
||||
item.goodsQuantity,
|
||||
item.quantityUnit,
|
||||
item.goodsQuantityUnit,
|
||||
item.unit,
|
||||
].some(Boolean);
|
||||
if (!hasGoodsInfo) return result;
|
||||
|
||||
const unit = item.quantityUnit || item.goodsQuantityUnit || item.unit || '';
|
||||
if (!result[unit]) {
|
||||
result[unit] = {
|
||||
typeName: getSecondCargoTypeName(item),
|
||||
count: 0,
|
||||
quantity: 0,
|
||||
};
|
||||
}
|
||||
result[unit].count += 1;
|
||||
result[unit].quantity += getGoodsQuantity(item);
|
||||
return result;
|
||||
}, {});
|
||||
|
||||
const text = Object.entries(groups)
|
||||
.map(([unit, group]) => {
|
||||
const quantity = `${formatGoodsQuantity(group.quantity)}${unit}`;
|
||||
return `${group.typeName}等${group.count}中货物 | ${quantity}`;
|
||||
})
|
||||
.join('; ');
|
||||
|
||||
return text || row.goodsInfo || '';
|
||||
};
|
||||
|
||||
const formatDispatchProgress = row =>
|
||||
row.dispatchProgressName || row.dispatchProgress || row.progress || '';
|
||||
|
||||
const auditColumn = prop => ({ ...auditColumns.find(item => item.prop === prop) });
|
||||
|
||||
export const config = {
|
||||
title: '运输计划',
|
||||
permission: 'transport_plan',
|
||||
exportUrl: '/blade-transport/transport-plan/export-transport-plan',
|
||||
exportName: '运输计划',
|
||||
enableAllDept: true,
|
||||
enableAllDept: false,
|
||||
enableProjectSelect: true,
|
||||
enableAttachmentTable: true,
|
||||
enableTransportPlanForm: true,
|
||||
enableTransportPlanCreateActions: true,
|
||||
attachmentTitle: '附件',
|
||||
searchRangeMap: {
|
||||
planStartDateRange: ['planStartDateStart', 'planStartDateEnd'],
|
||||
planEndDateRange: ['planEndDateStart', 'planEndDateEnd'],
|
||||
},
|
||||
actions: ['copy', 'cancel', 'complete'],
|
||||
statusProp: 'businessStatus',
|
||||
statusTextProp: 'businessStatusName',
|
||||
@@ -21,155 +131,366 @@ export const config = {
|
||||
editStatus: ['draft', 'waiting_dispatch'],
|
||||
};
|
||||
|
||||
export const option = createCrudOption([
|
||||
{
|
||||
label: '计划单号',
|
||||
prop: 'planNo',
|
||||
search: true,
|
||||
minWidth: 150,
|
||||
addDisplay: false,
|
||||
editDisabled: true,
|
||||
},
|
||||
{
|
||||
label: '计划名称',
|
||||
prop: 'planName',
|
||||
search: true,
|
||||
minWidth: 150,
|
||||
rules: textRule('计划名称', 50, true),
|
||||
},
|
||||
{
|
||||
label: '项目',
|
||||
prop: 'projectName',
|
||||
minWidth: 150,
|
||||
rules: textRule('项目', 100, true),
|
||||
},
|
||||
{
|
||||
label: '项目ID',
|
||||
prop: 'projectId',
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '客户合同',
|
||||
prop: 'contractName',
|
||||
minWidth: 160,
|
||||
rules: textRule('客户合同', 100, true),
|
||||
},
|
||||
{
|
||||
label: '客户合同ID',
|
||||
prop: 'contractId',
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '客户名称',
|
||||
prop: 'customerName',
|
||||
search: true,
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
label: '运输类型',
|
||||
prop: 'transportType',
|
||||
type: 'select',
|
||||
search: true,
|
||||
dicData: transportTypeOptions,
|
||||
minWidth: 130,
|
||||
rules: selectRule('运输类型'),
|
||||
},
|
||||
{
|
||||
label: '计划开始日期',
|
||||
prop: 'planStartDate',
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
search: true,
|
||||
minWidth: 130,
|
||||
},
|
||||
{
|
||||
label: '计划结束日期',
|
||||
prop: 'planEndDate',
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
search: true,
|
||||
minWidth: 130,
|
||||
},
|
||||
{
|
||||
label: '发货地',
|
||||
prop: 'departureName',
|
||||
minWidth: 140,
|
||||
rules: textRule('发货地', 100, true),
|
||||
},
|
||||
{
|
||||
label: '发货地址',
|
||||
prop: 'departureAddress',
|
||||
search: true,
|
||||
minWidth: 220,
|
||||
rules: textRule('发货地址', 255, true),
|
||||
},
|
||||
{
|
||||
label: '收货地',
|
||||
prop: 'arrivalName',
|
||||
minWidth: 140,
|
||||
rules: textRule('收货地', 100, true),
|
||||
},
|
||||
{
|
||||
label: '收货地址',
|
||||
prop: 'arrivalAddress',
|
||||
search: true,
|
||||
minWidth: 220,
|
||||
rules: textRule('收货地址', 255, true),
|
||||
},
|
||||
{
|
||||
label: '货物信息JSON',
|
||||
prop: 'goodsJson',
|
||||
type: 'textarea',
|
||||
minRows: 5,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '附件JSON',
|
||||
prop: 'attachmentsJson',
|
||||
type: 'textarea',
|
||||
minRows: 3,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '数据来源',
|
||||
prop: 'dataSource',
|
||||
type: 'select',
|
||||
search: true,
|
||||
dicData: dataSourceOptions,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
label: '业务状态',
|
||||
prop: 'businessStatus',
|
||||
type: 'select',
|
||||
slot: true,
|
||||
search: true,
|
||||
dicData: planStatusOptions,
|
||||
minWidth: 120,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '所属组织',
|
||||
prop: 'deptName',
|
||||
minWidth: 150,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
type: 'textarea',
|
||||
minRows: 4,
|
||||
span: 24,
|
||||
hide: true,
|
||||
maxlength: 200,
|
||||
showWordLimit: true,
|
||||
rules: textRule('备注', 200),
|
||||
},
|
||||
...auditColumns,
|
||||
]);
|
||||
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',
|
||||
},
|
||||
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',
|
||||
},
|
||||
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: 130,
|
||||
},
|
||||
{
|
||||
label: '计划结束日期',
|
||||
prop: 'planEndDate',
|
||||
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: 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%',
|
||||
};
|
||||
|
||||
@@ -4,16 +4,108 @@ import {
|
||||
dataSourceOptions,
|
||||
selectRule,
|
||||
textRule,
|
||||
transportTypeOptions,
|
||||
waybillStatusOptions,
|
||||
} from './common';
|
||||
|
||||
const transportTypeDict = {
|
||||
dicUrl: '/blade-system/dict-biz/dictionary?code=transport_type',
|
||||
props: {
|
||||
label: 'dictValue',
|
||||
value: 'dictKey',
|
||||
},
|
||||
};
|
||||
|
||||
const isEmpty = value => value === undefined || value === null || value === '';
|
||||
|
||||
const parseJsonArray = value => {
|
||||
if (Array.isArray(value)) return value;
|
||||
if (typeof value !== 'string' || !value.trim()) return [];
|
||||
try {
|
||||
const result = JSON.parse(value);
|
||||
if (Array.isArray(result)) return result;
|
||||
if (Array.isArray(result.records)) return result.records;
|
||||
if (Array.isArray(result.rows)) return result.rows;
|
||||
return [];
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const getFirstValue = (row, props) => {
|
||||
const prop = props.find(item => !isEmpty(row[item]));
|
||||
return prop ? row[prop] : '';
|
||||
};
|
||||
|
||||
const getGoodsRows = row => parseJsonArray(row.goodsList || row.goodsRows || row.goodsJson);
|
||||
|
||||
const getBillingRows = row => {
|
||||
const freightRows = parseJsonArray(row.freightList || row.freightRows || row.freightJson);
|
||||
if (freightRows.length) return freightRows;
|
||||
return parseJsonArray(row.billingPlanJson).flatMap(item =>
|
||||
Array.isArray(item.rules) ? item.rules : []
|
||||
);
|
||||
};
|
||||
|
||||
const joinText = list => list.filter(item => !isEmpty(item)).join('/');
|
||||
|
||||
const formatGoodsInfo = row => {
|
||||
const text = getFirstValue(row, ['goodsInfo', 'cargoInfo']);
|
||||
if (text) return text;
|
||||
return getGoodsRows(row)
|
||||
.map(item => {
|
||||
const name = getFirstValue(item, ['cargoName', 'goodsName', 'name']);
|
||||
const type = getFirstValue(item, ['cargoType', 'goodsType', 'typeName']);
|
||||
const quantity = joinText([
|
||||
getFirstValue(item, ['quantity', 'cargoQuantity', 'goodsQuantity']),
|
||||
getFirstValue(item, ['quantityUnit', 'cargoUnit', 'unit']),
|
||||
]);
|
||||
return joinText([name, type, quantity]);
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('; ');
|
||||
};
|
||||
|
||||
const formatGoodsField = (row, props) => {
|
||||
const value = getFirstValue(row, props);
|
||||
if (value) return value;
|
||||
const goods = getGoodsRows(row).find(item => getFirstValue(item, 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 unit = getFirstValue(row, ['priceUnit', 'billingUnit', 'unit']);
|
||||
if (!isEmpty(value)) return unit ? `${value}(${unit})` : value;
|
||||
const billing = getBillingRows(row).find(item => !isEmpty(item.unitPrice));
|
||||
if (!billing) return '';
|
||||
const billingUnit = getFirstValue(billing, ['priceUnit', 'billingUnit', 'unit']);
|
||||
return billingUnit ? `${billing.unitPrice}(${billingUnit})` : billing.unitPrice;
|
||||
};
|
||||
|
||||
const formatAmount = (row, props) => getFirstValue(row, props);
|
||||
|
||||
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: '运单管理',
|
||||
enableAllDept: true,
|
||||
importUrl: '/blade-transport/waybill-manage/import-waybill-manage',
|
||||
enableAllDept: false,
|
||||
batchDelete: false,
|
||||
createText: '新建运单',
|
||||
importText: '导入运单',
|
||||
roadLoading: true,
|
||||
roadLoadingText: '公路配载',
|
||||
searchRangeMap: {
|
||||
startDateRange: ['startDateStart', 'startDateEnd'],
|
||||
endDateRange: ['endDateStart', 'endDateEnd'],
|
||||
createTimeRange: ['createTimeStart', 'createTimeEnd'],
|
||||
},
|
||||
actions: ['copy', 'cancel', 'reassign', 'complete', 'batchComplete'],
|
||||
statusProp: 'businessStatus',
|
||||
statusTextProp: 'businessStatusName',
|
||||
@@ -21,234 +113,437 @@ export const config = {
|
||||
editStatus: ['draft', 'pending'],
|
||||
};
|
||||
|
||||
export const option = createCrudOption([
|
||||
{
|
||||
label: '运单号',
|
||||
prop: 'waybillNo',
|
||||
search: true,
|
||||
minWidth: 150,
|
||||
addDisplay: false,
|
||||
editDisabled: true,
|
||||
},
|
||||
{
|
||||
label: '项目',
|
||||
prop: 'projectName',
|
||||
search: true,
|
||||
minWidth: 150,
|
||||
rules: textRule('项目', 100, true),
|
||||
},
|
||||
{
|
||||
label: '项目ID',
|
||||
prop: 'projectId',
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '客户合同',
|
||||
prop: 'contractName',
|
||||
minWidth: 160,
|
||||
rules: textRule('客户合同', 100, true),
|
||||
},
|
||||
{
|
||||
label: '客户合同ID',
|
||||
prop: 'contractId',
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '客户名称',
|
||||
prop: 'customerName',
|
||||
search: true,
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
label: '运输类型',
|
||||
prop: 'transportType',
|
||||
type: 'select',
|
||||
search: true,
|
||||
dicData: transportTypeOptions,
|
||||
minWidth: 130,
|
||||
rules: selectRule('运输类型'),
|
||||
},
|
||||
{
|
||||
label: '货物名称',
|
||||
prop: 'cargoName',
|
||||
search: true,
|
||||
minWidth: 150,
|
||||
rules: textRule('货物名称', 100, true),
|
||||
},
|
||||
{
|
||||
label: '货物类型',
|
||||
prop: 'cargoType',
|
||||
search: true,
|
||||
minWidth: 130,
|
||||
rules: textRule('货物类型', 100, true),
|
||||
},
|
||||
{
|
||||
label: '发货地址',
|
||||
prop: 'departureAddress',
|
||||
search: true,
|
||||
minWidth: 220,
|
||||
rules: textRule('发货地址', 255, true),
|
||||
},
|
||||
{
|
||||
label: '收货地址',
|
||||
prop: 'arrivalAddress',
|
||||
search: true,
|
||||
minWidth: 220,
|
||||
rules: textRule('收货地址', 255, true),
|
||||
},
|
||||
{
|
||||
label: '承运商名称',
|
||||
prop: 'carrierName',
|
||||
search: true,
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
label: '司机姓名',
|
||||
prop: 'driverName',
|
||||
search: true,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
label: '车/船/航班/班列号',
|
||||
prop: 'vehicleNo',
|
||||
search: true,
|
||||
minWidth: 170,
|
||||
},
|
||||
{
|
||||
label: '原始单号',
|
||||
prop: 'originalNo',
|
||||
search: true,
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '业务状态',
|
||||
prop: 'businessStatus',
|
||||
type: 'select',
|
||||
slot: true,
|
||||
search: true,
|
||||
dicData: waybillStatusOptions,
|
||||
minWidth: 120,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '数据来源',
|
||||
prop: 'dataSource',
|
||||
type: 'select',
|
||||
search: true,
|
||||
dicData: dataSourceOptions,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
label: '开始日期',
|
||||
prop: 'startDate',
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
search: true,
|
||||
minWidth: 130,
|
||||
},
|
||||
{
|
||||
label: '结束日期',
|
||||
prop: 'endDate',
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
search: true,
|
||||
minWidth: 130,
|
||||
},
|
||||
{
|
||||
label: '计划名称',
|
||||
prop: 'planName',
|
||||
search: true,
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
label: '多联总单',
|
||||
prop: 'masterNo',
|
||||
search: true,
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '配载单号',
|
||||
prop: 'loadingNo',
|
||||
search: true,
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '运单批次号',
|
||||
prop: 'batchNo',
|
||||
search: true,
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '关联单号',
|
||||
prop: 'relationNo',
|
||||
search: true,
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '当前过程节点',
|
||||
prop: 'currentProcessNode',
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '货物信息JSON',
|
||||
prop: 'goodsJson',
|
||||
type: 'textarea',
|
||||
minRows: 5,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '承运信息JSON',
|
||||
prop: 'carrierJson',
|
||||
type: 'textarea',
|
||||
minRows: 4,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '过程配置JSON',
|
||||
prop: 'processJson',
|
||||
type: 'textarea',
|
||||
minRows: 4,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '运费信息JSON',
|
||||
prop: 'freightJson',
|
||||
type: 'textarea',
|
||||
minRows: 4,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '附件JSON',
|
||||
prop: 'attachmentsJson',
|
||||
type: 'textarea',
|
||||
minRows: 3,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '所属组织',
|
||||
prop: 'deptName',
|
||||
minWidth: 150,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
type: 'textarea',
|
||||
minRows: 4,
|
||||
span: 24,
|
||||
hide: true,
|
||||
maxlength: 500,
|
||||
showWordLimit: true,
|
||||
rules: textRule('备注', 500),
|
||||
},
|
||||
...auditColumns,
|
||||
]);
|
||||
export const option = {
|
||||
...createCrudOption([
|
||||
{
|
||||
label: '运单号',
|
||||
prop: 'waybillNo',
|
||||
search: true,
|
||||
searchOrder: 23,
|
||||
minWidth: 150,
|
||||
addDisplay: false,
|
||||
editDisabled: true,
|
||||
},
|
||||
{
|
||||
label: '配载单号',
|
||||
prop: 'loadingNo',
|
||||
search: true,
|
||||
searchOrder: 5,
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '总单号',
|
||||
prop: 'masterNo',
|
||||
search: true,
|
||||
searchLabel: '多联总单',
|
||||
searchOrder: 6,
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '项目名称',
|
||||
prop: 'projectName',
|
||||
search: true,
|
||||
searchOrder: 22,
|
||||
minWidth: 150,
|
||||
rules: textRule('项目', 100, true),
|
||||
},
|
||||
{
|
||||
label: '客户',
|
||||
prop: 'customerName',
|
||||
search: true,
|
||||
searchLabel: '客户名称',
|
||||
searchOrder: 21,
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
label: '车牌号/航班号/船号/班列号',
|
||||
prop: 'vehicleNo',
|
||||
search: true,
|
||||
searchLabel: '车/船/航班/班列',
|
||||
searchOrder: 13,
|
||||
minWidth: 210,
|
||||
},
|
||||
{
|
||||
label: '司机',
|
||||
prop: 'driverName',
|
||||
search: true,
|
||||
searchLabel: '司机名称',
|
||||
searchOrder: 14,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
label: '联系方式',
|
||||
prop: 'driverPhone',
|
||||
formatter: row => getFirstValue(row, ['driverPhone', 'driverMobile', 'driverTel']),
|
||||
minWidth: 140,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: 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,
|
||||
...transportTypeDict,
|
||||
minWidth: 130,
|
||||
rules: selectRule('运输类型'),
|
||||
},
|
||||
{
|
||||
label: '过程节点',
|
||||
prop: 'currentProcessNode',
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '承运类型',
|
||||
prop: 'carrierType',
|
||||
formatter: row => getFirstValue(row, ['carrierTypeName', 'carrierType']),
|
||||
minWidth: 120,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '承运商',
|
||||
prop: 'carrierName',
|
||||
search: true,
|
||||
searchLabel: '承运商名称',
|
||||
searchOrder: 15,
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
label: '货物信息',
|
||||
prop: 'goodsInfo',
|
||||
formatter: row => formatGoodsInfo(row),
|
||||
minWidth: 260,
|
||||
overHidden: true,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '发货地址',
|
||||
prop: 'departureAddress',
|
||||
search: true,
|
||||
searchOrder: 17,
|
||||
minWidth: 220,
|
||||
rules: textRule('发货地址', 255, true),
|
||||
},
|
||||
{
|
||||
label: '到货地址',
|
||||
prop: 'arrivalAddress',
|
||||
search: true,
|
||||
searchLabel: '收货地址',
|
||||
searchOrder: 16,
|
||||
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',
|
||||
minWidth: 160,
|
||||
rules: textRule('客户合同', 100, true),
|
||||
},
|
||||
{
|
||||
label: '计划名称',
|
||||
prop: 'planName',
|
||||
search: true,
|
||||
searchOrder: 7,
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
label: '货物类型',
|
||||
prop: 'cargoType',
|
||||
search: true,
|
||||
searchOrder: 18,
|
||||
formatter: row => formatGoodsField(row, ['cargoType', 'goodsType', 'typeName']),
|
||||
minWidth: 130,
|
||||
rules: textRule('货物类型', 100, true),
|
||||
},
|
||||
{
|
||||
label: '货物名称',
|
||||
prop: 'cargoName',
|
||||
search: true,
|
||||
searchOrder: 19,
|
||||
formatter: row => formatGoodsField(row, ['cargoName', 'goodsName', 'name']),
|
||||
minWidth: 150,
|
||||
rules: textRule('货物名称', 100, true),
|
||||
},
|
||||
{
|
||||
label: '实际发货时间',
|
||||
prop: 'startDate',
|
||||
type: 'datetime',
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
minWidth: 170,
|
||||
},
|
||||
{
|
||||
label: '实际完成时间',
|
||||
prop: 'endDate',
|
||||
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,
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '运单批次号',
|
||||
prop: 'batchNo',
|
||||
search: true,
|
||||
searchLabel: '运输批次',
|
||||
searchOrder: 3,
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '预计发货时间',
|
||||
prop: 'estimatedStartTime',
|
||||
type: 'datetime',
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
formatter: row => getFirstValue(row, ['estimatedStartTime', 'planStartDate']),
|
||||
minWidth: 170,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '预计完成时间',
|
||||
prop: 'estimatedEndTime',
|
||||
type: 'datetime',
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
formatter: row => getFirstValue(row, ['estimatedEndTime', 'planEndDate']),
|
||||
minWidth: 170,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
type: 'textarea',
|
||||
minRows: 4,
|
||||
span: 24,
|
||||
minWidth: 180,
|
||||
overHidden: true,
|
||||
maxlength: 500,
|
||||
showWordLimit: true,
|
||||
rules: textRule('备注', 500),
|
||||
},
|
||||
{
|
||||
label: '数据来源',
|
||||
prop: 'dataSource',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 10,
|
||||
dicData: dataSourceOptions,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
...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: '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,
|
||||
},
|
||||
{
|
||||
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,
|
||||
},
|
||||
{
|
||||
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,
|
||||
minWidth: 140,
|
||||
hide: true,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '货物信息JSON',
|
||||
prop: 'goodsJson',
|
||||
type: 'textarea',
|
||||
minRows: 5,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '承运信息JSON',
|
||||
prop: 'carrierJson',
|
||||
type: 'textarea',
|
||||
minRows: 4,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '过程配置JSON',
|
||||
prop: 'processJson',
|
||||
type: 'textarea',
|
||||
minRows: 4,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '运费信息JSON',
|
||||
prop: 'freightJson',
|
||||
type: 'textarea',
|
||||
minRows: 4,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '附件JSON',
|
||||
prop: 'attachmentsJson',
|
||||
type: 'textarea',
|
||||
minRows: 3,
|
||||
span: 24,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '所属组织',
|
||||
prop: 'deptName',
|
||||
hide: true,
|
||||
minWidth: 150,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '项目ID',
|
||||
prop: 'projectId',
|
||||
hide: true,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '客户合同ID',
|
||||
prop: 'contractId',
|
||||
hide: true,
|
||||
display: false,
|
||||
},
|
||||
]),
|
||||
menuWidth: 320,
|
||||
};
|
||||
|
||||
@@ -462,20 +462,27 @@
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// 全站统一:操作栏按钮紧凑间距
|
||||
// 全站统一:操作列最多一行展示 4 个按钮,第 5 个开始自动换行
|
||||
.avue-crud .el-table td .cell.avue-crud__menu {
|
||||
display: inline-grid;
|
||||
grid-template-columns: repeat(4, max-content);
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.avue-crud__menu > .el-button,
|
||||
.avue-crud__menu > .el-dropdown {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.avue-crud__menu .el-button {
|
||||
margin-left: 4px;
|
||||
margin-right: 0;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
// 全站统一:操作列内容左对齐(Avue 内置菜单默认右对齐)
|
||||
.avue-crud .el-table td .cell.avue-crud__menu {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.avue-crud__pagination .el-pagination,
|
||||
.empty-pagination .el-pagination,
|
||||
|
||||
16
src/utils/table-menu.js
Normal file
16
src/utils/table-menu.js
Normal file
@@ -0,0 +1,16 @@
|
||||
export const TABLE_MENU_WIDTH = {
|
||||
default: 160,
|
||||
three: 220,
|
||||
four: 320,
|
||||
};
|
||||
|
||||
export const resolveTableMenuWidth = buttonCount => {
|
||||
if (buttonCount >= 4) return TABLE_MENU_WIDTH.four;
|
||||
if (buttonCount === 3) return TABLE_MENU_WIDTH.three;
|
||||
return TABLE_MENU_WIDTH.default;
|
||||
};
|
||||
|
||||
export const applyTableMenuWidth = (option, buttonCount) => ({
|
||||
...option,
|
||||
menuWidth: Math.max(Number(option.menuWidth) || 0, resolveTableMenuWidth(buttonCount)),
|
||||
});
|
||||
12
src/utils/upload.js
Normal file
12
src/utils/upload.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Base64 } from 'js-base64';
|
||||
import website from '@/config/website';
|
||||
import { getToken } from '@/utils/auth';
|
||||
|
||||
export function getUploadHeaders(extraHeaders = {}) {
|
||||
return {
|
||||
...extraHeaders,
|
||||
[website.tokenHeader]: `bearer ${getToken() || ''}`,
|
||||
Authorization: `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`,
|
||||
'Blade-Requested-With': 'BladeHttpRequest',
|
||||
};
|
||||
}
|
||||
@@ -129,7 +129,7 @@ import { exportBlob } from '@/api/common';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import { openImportDialog } from '@/utils/import-excel';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
import { Plus, Upload, Download, Delete } from '@element-plus/icons-vue';
|
||||
@@ -265,9 +265,7 @@ export default {
|
||||
propsHttp: {
|
||||
res: 'data',
|
||||
},
|
||||
headers: {
|
||||
'Blade-Auth': `bearer ${getToken()}`,
|
||||
},
|
||||
headers: getUploadHeaders(),
|
||||
tip: '请上传 .xls,.xlsx 标准格式文件',
|
||||
action: '/blade-system/cargo-type/import-cargo-type',
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<basic-container class="fee-item-page">
|
||||
<avue-crud
|
||||
:option="option"
|
||||
:table-loading="loading"
|
||||
@@ -14,20 +14,20 @@
|
||||
@row-del="rowDel"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
plain
|
||||
v-if="permission.fee_item_delete"
|
||||
@click="handleDelete"
|
||||
>批量删除
|
||||
<el-button type="primary" plain v-if="permission.fee_item_import" @click="handleImport">
|
||||
<el-icon class="el-icon--left"><Upload /></el-icon>批量导入
|
||||
</el-button>
|
||||
<el-button type="primary" plain v-if="permission.fee_item_template" @click="handleTemplate">
|
||||
<el-icon class="el-icon--left"><Download /></el-icon>下载模板
|
||||
</el-button>
|
||||
<el-button type="primary" plain v-if="permission.fee_item_export" @click="handleExport">
|
||||
<el-icon class="el-icon--left"><Download /></el-icon>批量导出
|
||||
</el-button>
|
||||
</template>
|
||||
<template #status="{ row }">
|
||||
@@ -35,6 +35,35 @@
|
||||
{{ row.status === 1 ? '启用' : '停用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template #feeCategory-form>
|
||||
<el-select
|
||||
v-model="form.feeCategory"
|
||||
class="fee-item-form-control"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择费用类型"
|
||||
@change="handleFeeCategoryChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in feeCategoryOptions"
|
||||
:key="item.id || item.dictKey"
|
||||
:label="item.dictValue"
|
||||
:value="item.dictKey"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
<template #englishName-form>
|
||||
<el-input
|
||||
v-model="form.englishName"
|
||||
:maxlength="feeItemCodeMaxlength"
|
||||
class="fee-item-form-control"
|
||||
clearable
|
||||
placeholder="请输入费用项代码"
|
||||
@change="handleFeeItemCodeChange"
|
||||
>
|
||||
<template #prepend>{{ feeCategoryPrefix || '费用类型' }}</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<template #menu="{ row, index }">
|
||||
<el-button
|
||||
type="primary"
|
||||
@@ -44,41 +73,60 @@
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
v-if="permission.fee_item_status"
|
||||
@click="handleStatus(row)"
|
||||
>
|
||||
<el-button type="primary" text v-if="permission.fee_item_status" @click="handleStatus(row)">
|
||||
{{ row.status === 1 ? '停用' : '启用' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</avue-crud>
|
||||
|
||||
<el-dialog title="费用项导入" append-to-body v-model="excelBox" width="555px">
|
||||
<avue-form :option="excelOption" 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>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getList, getDetail, submit, remove, changeStatus } from '@/api/base/fee-item';
|
||||
import { exportBlob } from '@/api/common';
|
||||
import { getDictionary } from '@/api/system/dictbiz';
|
||||
import { getDeptTree } from '@/api/system/dept';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import { openImportDialog } from '@/utils/import-excel';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import { Upload, Download } from '@element-plus/icons-vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
|
||||
export default {
|
||||
components: { Upload, Download },
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
query: {},
|
||||
loading: true,
|
||||
data: [],
|
||||
excelBox: false,
|
||||
excelForm: {},
|
||||
feeCategoryOptions: [],
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
selectionList: [],
|
||||
option: {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
dialogWidth: 680,
|
||||
dialogWidth: 980,
|
||||
labelPosition: 'right',
|
||||
labelWidth: 'auto',
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 24,
|
||||
@@ -88,10 +136,11 @@ export default {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 70,
|
||||
viewBtn: false,
|
||||
delBtn: false,
|
||||
editBtn: false,
|
||||
selection: true,
|
||||
selection: false,
|
||||
dialogClickModal: false,
|
||||
menuWidth: 160,
|
||||
column: [
|
||||
@@ -100,8 +149,11 @@ export default {
|
||||
prop: 'feeCategory',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 3,
|
||||
filterable: true,
|
||||
dicUrl: '/blade-system/dict/dictionary?code=fee_category',
|
||||
formslot: true,
|
||||
span: 12,
|
||||
dicData: [],
|
||||
props: {
|
||||
label: 'dictValue',
|
||||
value: 'dictKey',
|
||||
@@ -109,35 +161,56 @@ export default {
|
||||
minWidth: 120,
|
||||
rules: [{ required: true, message: '请选择费用类型', trigger: 'change' }],
|
||||
},
|
||||
{
|
||||
label: '费用项代码',
|
||||
prop: 'englishName',
|
||||
formslot: true,
|
||||
span: 12,
|
||||
minWidth: 160,
|
||||
maxlength: 100,
|
||||
rules: [{ required: true, message: '请输入费用项代码', trigger: 'blur' }],
|
||||
},
|
||||
{
|
||||
label: '费用项',
|
||||
prop: 'name',
|
||||
minWidth: 140,
|
||||
search: true,
|
||||
searchOrder: 4,
|
||||
span: 12,
|
||||
maxlength: 50,
|
||||
rules: [{ required: true, message: '请输入费用项', trigger: 'blur' }],
|
||||
},
|
||||
{
|
||||
label: '费用项代码',
|
||||
prop: 'englishName',
|
||||
label: '组织',
|
||||
prop: 'createDeptName',
|
||||
minWidth: 160,
|
||||
search: true,
|
||||
maxlength: 100,
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
search: true,
|
||||
slot: true,
|
||||
dataType: 'number',
|
||||
dicData: [
|
||||
{ label: '启用', value: 1 },
|
||||
{ label: '停用', value: 2 },
|
||||
],
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
value: 1,
|
||||
viewDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '组织',
|
||||
prop: 'createDept',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 1,
|
||||
hide: true,
|
||||
display: false,
|
||||
filterable: true,
|
||||
dicData: [],
|
||||
props: {
|
||||
label: 'label',
|
||||
value: 'value',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '更新人',
|
||||
prop: 'updateUserName',
|
||||
minWidth: 120,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '更新时间',
|
||||
@@ -161,32 +234,135 @@ export default {
|
||||
display: false,
|
||||
minWidth: 160,
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
search: true,
|
||||
searchOrder: 2,
|
||||
slot: true,
|
||||
dataType: 'number',
|
||||
dicData: [
|
||||
{ label: '启用', value: 1 },
|
||||
{ label: '停用', value: 2 },
|
||||
],
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
value: 1,
|
||||
minWidth: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
excelOption: {
|
||||
submitBtn: false,
|
||||
emptyBtn: false,
|
||||
column: [
|
||||
{
|
||||
label: '模板上传',
|
||||
prop: 'excelFile',
|
||||
type: 'upload',
|
||||
drag: true,
|
||||
loadText: '模板上传中,请稍等',
|
||||
span: 24,
|
||||
propsHttp: {
|
||||
res: 'data',
|
||||
},
|
||||
headers: getUploadHeaders(),
|
||||
tip: '请上传 .xls,.xlsx 标准格式文件',
|
||||
action: '/blade-system/fee-item/import-fee-item',
|
||||
},
|
||||
{
|
||||
label: '模板下载',
|
||||
prop: 'excelTemplate',
|
||||
formslot: true,
|
||||
span: 24,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.initFeeCategoryOptions();
|
||||
this.initDeptTree();
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permission']),
|
||||
...mapGetters(['permission', 'userInfo']),
|
||||
feeCategoryPrefix() {
|
||||
return this.getFeeCategoryPrefix(this.form.feeCategory);
|
||||
},
|
||||
feeItemCodeMaxlength() {
|
||||
return Math.max(1, 100 - this.feeCategoryPrefix.length);
|
||||
},
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.fee_item_add, false),
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
initFeeCategoryOptions() {
|
||||
getDictionary({ code: 'fee_category' }).then(res => {
|
||||
this.feeCategoryOptions = res.data.data || [];
|
||||
const column = this.findColumn(this.option.column, 'feeCategory');
|
||||
column.dicData = this.feeCategoryOptions;
|
||||
});
|
||||
},
|
||||
initDeptTree() {
|
||||
getDeptTree(this.userInfo.tenantId).then(res => {
|
||||
const column = this.findColumn(this.option.column, 'createDept');
|
||||
column.dicData = this.flattenDept(res.data.data || []);
|
||||
});
|
||||
},
|
||||
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;
|
||||
},
|
||||
getFeeCategoryPrefix(value) {
|
||||
const feeCategory = String(value || '').trim();
|
||||
const option = this.feeCategoryOptions.find(
|
||||
item => String(item.dictKey || '') === feeCategory
|
||||
);
|
||||
return String((option && option.dictKey) || feeCategory);
|
||||
},
|
||||
getFeeItemCodeSuffix(code, feeCategory) {
|
||||
const value = String(code || '').trim();
|
||||
const prefix = this.getFeeCategoryPrefix(feeCategory);
|
||||
if (prefix && value.startsWith(prefix)) {
|
||||
return value.slice(prefix.length);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
handleFeeCategoryChange(value) {
|
||||
this.form.feeCategory = value;
|
||||
this.form.englishName = this.getFeeItemCodeSuffix(this.form.englishName, value);
|
||||
},
|
||||
handleFeeItemCodeChange(value) {
|
||||
this.form.englishName = this.getFeeItemCodeSuffix(value, this.form.feeCategory);
|
||||
},
|
||||
normalizeRow(row) {
|
||||
row.feeCategory = String(row.feeCategory || '').trim();
|
||||
row.name = String(row.name || '').trim();
|
||||
row.englishName = String(row.englishName || '').trim();
|
||||
if (!row.status) row.status = 1;
|
||||
return row;
|
||||
const values = { ...row };
|
||||
const prefix = this.getFeeCategoryPrefix(values.feeCategory);
|
||||
const code = this.getFeeItemCodeSuffix(values.englishName, values.feeCategory);
|
||||
values.feeCategory = String(values.feeCategory || '').trim();
|
||||
values.name = String(values.name || '').trim();
|
||||
values.englishName = prefix ? `${prefix}${code}` : code;
|
||||
if (!values.status) values.status = 1;
|
||||
return values;
|
||||
},
|
||||
normalizeFormForEdit(row) {
|
||||
const values = { ...row };
|
||||
values.feeCategory = String(values.feeCategory || '').trim();
|
||||
values.englishName = this.getFeeItemCodeSuffix(values.englishName, values.feeCategory);
|
||||
return values;
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
submit(this.normalizeRow(row)).then(
|
||||
@@ -226,23 +402,6 @@ export default {
|
||||
this.$message({ type: 'success', message: '操作成功!' });
|
||||
});
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => remove(this.ids))
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({ type: 'success', message: '操作成功!' });
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
handleStatus(row) {
|
||||
const nextStatus = row.status === 1 ? 2 : 1;
|
||||
const actionName = nextStatus === 1 ? '启用' : '停用';
|
||||
@@ -260,12 +419,13 @@ export default {
|
||||
beforeOpen(done, type) {
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDetail(this.form.id).then(res => {
|
||||
this.form = res.data.data;
|
||||
this.form = this.normalizeFormForEdit(res.data.data || {});
|
||||
done();
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.form.status = 1;
|
||||
this.form.englishName = '';
|
||||
done();
|
||||
},
|
||||
searchReset() {
|
||||
@@ -278,13 +438,6 @@ export default {
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
@@ -294,6 +447,42 @@ export default {
|
||||
refreshChange() {
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
handleImport() {
|
||||
openImportDialog(this, '费用项');
|
||||
},
|
||||
buildExportParams() {
|
||||
return {
|
||||
...this.query,
|
||||
[this.website.tokenHeader]: getToken(),
|
||||
};
|
||||
},
|
||||
handleExport() {
|
||||
this.$confirm('是否导出费用项数据?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
NProgress.start();
|
||||
exportBlob('/blade-system/fee-item/export-fee-item', this.buildExportParams(), {
|
||||
feedback: true,
|
||||
})
|
||||
.then(res => {
|
||||
downloadXls(res.data, `费用项${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
|
||||
})
|
||||
.finally(() => {
|
||||
NProgress.done();
|
||||
});
|
||||
});
|
||||
},
|
||||
handleTemplate() {
|
||||
exportBlob(
|
||||
`/blade-system/fee-item/export-template?${this.website.tokenHeader}=${getToken()}`,
|
||||
undefined,
|
||||
{ feedback: true }
|
||||
).then(res => {
|
||||
downloadXls(res.data, '费用项模板.xlsx');
|
||||
});
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
||||
@@ -301,9 +490,25 @@ export default {
|
||||
this.page.total = data.total;
|
||||
this.data = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fee-item-page :deep(.avue-crud__dialog .avue-form__row),
|
||||
.fee-item-page :deep(.avue-crud__dialog .el-row) {
|
||||
margin-left: -36px;
|
||||
margin-right: -36px;
|
||||
}
|
||||
|
||||
.fee-item-page :deep(.avue-crud__dialog .el-col) {
|
||||
padding-left: 36px;
|
||||
padding-right: 36px;
|
||||
}
|
||||
|
||||
.fee-item-form-control {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,15 @@
|
||||
@on-load="onLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-plus"
|
||||
plain
|
||||
v-if="canMajorProjectSupplement"
|
||||
@click="openProjectDialog('majorSupplement')"
|
||||
>
|
||||
重大项目补录
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-plus"
|
||||
@@ -44,16 +53,6 @@
|
||||
>
|
||||
批量删除
|
||||
</el-button>
|
||||
<el-switch
|
||||
v-if="config.enableAllDept && canViewAllDept"
|
||||
v-model="allDept"
|
||||
class="project-apply-page__scope"
|
||||
active-text="全部组织"
|
||||
inactive-text="当前组织"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="handleScopeChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #approvalStatus="{ row }">
|
||||
@@ -71,12 +70,7 @@
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
v-if="canEdit(row)"
|
||||
@click="openProjectDialog('edit', row)"
|
||||
>
|
||||
<el-button type="primary" text v-if="canEdit(row)" @click="openProjectDialog('edit', row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
@@ -88,14 +82,7 @@
|
||||
>
|
||||
{{ operation.label }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
v-if="canDelete(row)"
|
||||
@click="rowDel(row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<el-button type="primary" text v-if="canDelete(row)" @click="rowDel(row)"> 删除 </el-button>
|
||||
</template>
|
||||
</avue-crud>
|
||||
|
||||
@@ -127,8 +114,25 @@
|
||||
>
|
||||
<div class="dialog-section-title">项目基本信息</div>
|
||||
<div class="project-apply-form__grid">
|
||||
<el-form-item v-if="isChangeDialog" label="变更类型" prop="changeType">
|
||||
<el-select v-model="form.changeType" placeholder="请选择变更类型">
|
||||
<el-option
|
||||
v-for="item in changeTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div v-if="isChangeDialog"></div>
|
||||
<el-form-item label="项目类型" prop="projectType">
|
||||
<el-select v-model="form.projectType" placeholder="请选择项目类型" clearable>
|
||||
<el-select
|
||||
v-model="form.projectType"
|
||||
placeholder="请选择项目类型"
|
||||
clearable
|
||||
:disabled="isBasicInfoReadonly || isMajorProjectSupplementDialog"
|
||||
@change="handleProjectTypeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in projectTypeOptions"
|
||||
:key="item.value"
|
||||
@@ -141,10 +145,20 @@
|
||||
<el-input v-model="form.projectCode" disabled placeholder="系统自动生成" />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input v-model="form.projectName" placeholder="请填写项目名称" maxlength="50" />
|
||||
<el-input
|
||||
v-model="form.projectName"
|
||||
placeholder="请填写项目名称"
|
||||
maxlength="50"
|
||||
:disabled="isBasicInfoReadonly"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目简称" prop="projectShortName">
|
||||
<el-input v-model="form.projectShortName" placeholder="请填写项目简称" maxlength="20" />
|
||||
<el-input
|
||||
v-model="form.projectShortName"
|
||||
placeholder="请填写项目简称"
|
||||
maxlength="20"
|
||||
:disabled="isBasicInfoReadonly"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="业务部门" prop="businessDeptId">
|
||||
<el-select
|
||||
@@ -152,6 +166,7 @@
|
||||
placeholder="请选择业务部门"
|
||||
filterable
|
||||
clearable
|
||||
:disabled="isBasicInfoReadonly"
|
||||
@change="handleBusinessDeptChange"
|
||||
>
|
||||
<el-option
|
||||
@@ -168,6 +183,7 @@
|
||||
placeholder="请选择承办部门"
|
||||
filterable
|
||||
clearable
|
||||
:disabled="isBasicInfoReadonly"
|
||||
@change="handleUndertakeDeptChange"
|
||||
>
|
||||
<el-option
|
||||
@@ -179,7 +195,12 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目由来" prop="projectSource">
|
||||
<el-select v-model="form.projectSource" placeholder="请选择项目由来" clearable>
|
||||
<el-select
|
||||
v-model="form.projectSource"
|
||||
placeholder="请选择项目由来"
|
||||
clearable
|
||||
:disabled="isBasicInfoReadonly"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in projectSourceOptions"
|
||||
:key="item.value"
|
||||
@@ -189,7 +210,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目由来说明" prop="sourceRemark">
|
||||
<el-input v-model="form.sourceRemark" maxlength="300" />
|
||||
<el-input v-model="form.sourceRemark" maxlength="300" :disabled="isBasicInfoReadonly" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
@@ -368,10 +389,7 @@
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="dialog-section-title project-apply-form__table-title">
|
||||
客户信息
|
||||
<span class="project-apply-form__tip">选择客户/承运商信息后,自动关联出客商信息</span>
|
||||
</div>
|
||||
<div class="dialog-section-title project-apply-form__table-title">客户信息</div>
|
||||
<el-table :data="customerRows" border class="project-apply-form__table">
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column prop="customer" label="客户" min-width="160" align="center" />
|
||||
@@ -451,12 +469,7 @@
|
||||
</div>
|
||||
|
||||
<div class="project-apply-form__material-head">
|
||||
<div class="dialog-section-title project-apply-form__material-title">
|
||||
项目材料
|
||||
<span class="project-apply-form__material-warn">
|
||||
项目立项报告、考察报告、立项成本测算表、企业资质板附件未上传
|
||||
</span>
|
||||
</div>
|
||||
<div class="dialog-section-title project-apply-form__material-title">项目材料</div>
|
||||
<el-button type="primary" :disabled="!attachmentRows.length" @click="handleBatchDownload"
|
||||
>批量下载</el-button
|
||||
>
|
||||
@@ -466,21 +479,18 @@
|
||||
<el-table-column label="附件类型" min-width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.fileType" placeholder="请选择" :disabled="dialogReadonly">
|
||||
<el-option label="项目立项报告" value="项目立项报告" />
|
||||
<el-option label="考察报告" value="考察报告" />
|
||||
<el-option label="立项成本测算表" value="立项成本测算表" />
|
||||
<el-option label="企业资质板附件" value="企业资质板附件" />
|
||||
<el-option label="其他" value="其他" />
|
||||
<el-option
|
||||
v-for="item in projectAttachmentTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="文件名"
|
||||
min-width="220"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="文件名" min-width="220" align="center" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.originalName || row.name }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="附件描述" min-width="240" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input
|
||||
@@ -519,13 +529,15 @@
|
||||
@change="handleAttachmentChange"
|
||||
/>
|
||||
|
||||
<div class="dialog-section-title project-apply-form__table-title">
|
||||
<div v-if="!isChangeDialog" class="dialog-section-title project-apply-form__table-title">
|
||||
变更记录
|
||||
<span class="project-apply-form__tip"
|
||||
>查看页面显示变更记录,变更提交后生成,可查看详情页面</span
|
||||
>
|
||||
</div>
|
||||
<el-table :data="changeRows" border class="project-apply-form__table">
|
||||
<el-table
|
||||
v-if="!isChangeDialog"
|
||||
:data="changeRows"
|
||||
border
|
||||
class="project-apply-form__table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column prop="changeDate" label="变更日期" min-width="140" align="center" />
|
||||
<el-table-column prop="changeType" label="变更类型" min-width="160" align="center" />
|
||||
@@ -553,19 +565,58 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<template v-if="isChangeDialog">
|
||||
<div class="dialog-section-title">变更内容</div>
|
||||
<el-form-item prop="changeContent" class="project-apply-form__change-textarea">
|
||||
<el-input
|
||||
v-model="form.changeContent"
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
placeholder="2000字以内"
|
||||
maxlength="2000"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
<div class="dialog-section-title">变更原因</div>
|
||||
<el-form-item prop="changeReason" class="project-apply-form__change-textarea">
|
||||
<el-input
|
||||
v-model="form.changeReason"
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
placeholder="2000字以内"
|
||||
maxlength="2000"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="project-apply-dialog__footer">
|
||||
<el-button @click="projectBox = false">取消</el-button>
|
||||
<el-button
|
||||
v-if="!dialogReadonly"
|
||||
type="primary"
|
||||
:loading="submitLoading"
|
||||
@click="submitProject"
|
||||
>
|
||||
提交
|
||||
</el-button>
|
||||
<div
|
||||
class="project-apply-dialog__footer"
|
||||
:class="{ 'project-apply-dialog__footer--change': 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>
|
||||
<el-button @click="projectBox = false">关闭</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button @click="projectBox = false">取消</el-button>
|
||||
<el-button
|
||||
v-if="!dialogReadonly"
|
||||
type="primary"
|
||||
:loading="submitLoading"
|
||||
@click="submitProject"
|
||||
>
|
||||
提交
|
||||
</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -628,9 +679,11 @@ import {
|
||||
getDetail as getCustomerArchiveDetail,
|
||||
} from '@/api/vehicle/customer-archive';
|
||||
import { getDeptTree } from '@/api/system/dept';
|
||||
import { getDictionary } from '@/api/system/dict';
|
||||
import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
||||
import { getDictionary as getBizDictionary } from '@/api/system/dictbiz';
|
||||
import { getList as getUserList } from '@/api/system/user';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { applyTableMenuWidth } from '@/utils/table-menu';
|
||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||
import { mapGetters } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
@@ -640,7 +693,6 @@ import {
|
||||
projectSourceOptions,
|
||||
projectTypeOptions,
|
||||
settlementModeOptions,
|
||||
transportTypeOptions,
|
||||
} from '@/option/business/common';
|
||||
import { config, option } from '@/option/business/project-apply';
|
||||
|
||||
@@ -655,6 +707,7 @@ const emptyForm = () => ({
|
||||
undertakeDeptName: '',
|
||||
projectSource: '商务洽谈',
|
||||
sourceRemark: '',
|
||||
changeType: '',
|
||||
customerNames: '',
|
||||
carrierNames: '',
|
||||
fundLimit: '',
|
||||
@@ -685,8 +738,38 @@ const emptyForm = () => ({
|
||||
profitRemark: '',
|
||||
riskPoint: '',
|
||||
emergencyPlan: '',
|
||||
changeContent: '',
|
||||
changeReason: '',
|
||||
});
|
||||
|
||||
const changeTypeOptions = [
|
||||
{ label: '项目变更', value: '项目变更' },
|
||||
{ label: '项目备案调整', value: '项目备案调整' },
|
||||
];
|
||||
|
||||
const normalProjectAttachmentTypeOptions = [
|
||||
'利润测算表',
|
||||
'单一来源供应商申请表/三方比价表',
|
||||
'合同模板',
|
||||
'项目操作说明',
|
||||
'项目分析报告',
|
||||
'项目考察报告',
|
||||
].map(item => ({ label: item, value: item }));
|
||||
|
||||
const majorProjectAttachmentTypeOptions = [
|
||||
'会议纪要',
|
||||
'评审表决票',
|
||||
'利润测算表',
|
||||
'单一来源供应商申请表/三方比价表',
|
||||
'项目操作说明',
|
||||
'项目分析报告',
|
||||
'项目考察报告',
|
||||
'合同模板',
|
||||
'上游尽职调查报告',
|
||||
'下游尽职调查报告',
|
||||
'业务承诺函',
|
||||
].map(item => ({ label: item, value: item }));
|
||||
|
||||
export default {
|
||||
data() {
|
||||
const validateAmount = (rule, value, callback) => {
|
||||
@@ -719,14 +802,22 @@ export default {
|
||||
}
|
||||
callback();
|
||||
};
|
||||
const validateUser = (rule, value, callback) => {
|
||||
if (value || this.form[rule.nameProp]) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
callback(new Error(`请选择${rule.label}`));
|
||||
};
|
||||
return {
|
||||
api,
|
||||
config,
|
||||
projectTypeOptions,
|
||||
projectSourceOptions,
|
||||
transportTypeOptions,
|
||||
transportTypeOptions: [],
|
||||
businessTypeOptions,
|
||||
settlementModeOptions,
|
||||
changeTypeOptions,
|
||||
tableForm: {},
|
||||
tableOption: this.buildTableOption(),
|
||||
loading: true,
|
||||
@@ -746,6 +837,7 @@ export default {
|
||||
submitLoading: false,
|
||||
form: emptyForm(),
|
||||
formRules: {
|
||||
changeType: [{ required: true, message: '请选择变更类型', trigger: 'change' }],
|
||||
projectType: [{ required: true, message: '请选择项目类型', trigger: 'change' }],
|
||||
projectName: [
|
||||
{ required: true, message: '请输入项目名称', trigger: 'blur' },
|
||||
@@ -784,8 +876,30 @@ export default {
|
||||
projectScale: [{ label: '项目规模', validator: validateAmount, trigger: 'blur' }],
|
||||
estimatedProfit: [{ label: '预估利润', validator: validateAmount, trigger: 'blur' }],
|
||||
fundDemand: [{ label: '资金需求', validator: validateAmount, trigger: 'blur' }],
|
||||
handlerUserId: [{ required: true, message: '请选择项目经办人', trigger: 'change' }],
|
||||
principalUserId: [{ required: true, message: '请选择项目负责人', trigger: 'change' }],
|
||||
handlerUserId: [
|
||||
{
|
||||
label: '项目经办人',
|
||||
nameProp: 'handlerUserName',
|
||||
validator: validateUser,
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
principalUserId: [
|
||||
{
|
||||
label: '项目负责人',
|
||||
nameProp: 'principalUserName',
|
||||
validator: validateUser,
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
changeContent: [
|
||||
{ required: true, message: '请输入变更内容', trigger: 'blur' },
|
||||
{ max: 2000, message: '变更内容不能超过2000个字符', trigger: 'blur' },
|
||||
],
|
||||
changeReason: [
|
||||
{ required: true, message: '请输入变更原因', trigger: 'blur' },
|
||||
{ max: 2000, message: '变更原因不能超过2000个字符', trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
deptOptions: [],
|
||||
cargoTypeOptions: [],
|
||||
@@ -852,29 +966,56 @@ export default {
|
||||
canCreate() {
|
||||
return this.hasPermission(`${this.config.permission}_add`) && !this.readonlyScope;
|
||||
},
|
||||
canMajorProjectSupplement() {
|
||||
return this.hasPermission(`${this.config.permission}_supplement`) && !this.readonlyScope;
|
||||
},
|
||||
isMajorProjectSupplementDialog() {
|
||||
return this.dialogType === 'majorSupplement';
|
||||
},
|
||||
isChangeDialog() {
|
||||
return this.dialogType === 'change';
|
||||
},
|
||||
isBasicInfoReadonly() {
|
||||
return this.dialogReadonly || this.isChangeDialog;
|
||||
},
|
||||
ids() {
|
||||
return this.selectionList.map(item => item.id).join(',');
|
||||
},
|
||||
projectDialogTitle() {
|
||||
if (this.isChangeDialog) {
|
||||
return '项目变更';
|
||||
}
|
||||
if (this.isMajorProjectSupplementDialog) {
|
||||
return '重大项目补录';
|
||||
}
|
||||
const text = { add: '新增', edit: '编辑', view: '查看' }[this.dialogType] || '新增';
|
||||
return `${text}${this.config.title}`;
|
||||
},
|
||||
projectAttachmentTypeOptions() {
|
||||
return this.form.projectType === '重大项目'
|
||||
? majorProjectAttachmentTypeOptions
|
||||
: normalProjectAttachmentTypeOptions;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.loadDeptOptions();
|
||||
this.loadCargoTypeOptions();
|
||||
this.loadTransportTypeOptions();
|
||||
},
|
||||
methods: {
|
||||
buildTableOption() {
|
||||
return {
|
||||
...option,
|
||||
dialogType: 'dialog',
|
||||
addBtn: false,
|
||||
viewBtn: false,
|
||||
editBtn: false,
|
||||
delBtn: false,
|
||||
column: (option.column || []).map(column => ({ ...column, display: false })),
|
||||
};
|
||||
return applyTableMenuWidth(
|
||||
{
|
||||
...option,
|
||||
dialogType: 'dialog',
|
||||
addBtn: false,
|
||||
viewBtn: false,
|
||||
editBtn: false,
|
||||
delBtn: false,
|
||||
column: (option.column || []).map(column => ({ ...column, display: false })),
|
||||
},
|
||||
4
|
||||
);
|
||||
},
|
||||
hasPermission(code) {
|
||||
return this.isAdmin || this.validData(this.permission && this.permission[code], false);
|
||||
@@ -1029,9 +1170,17 @@ export default {
|
||||
this.selectionClear();
|
||||
},
|
||||
handleCustomOperation(operation, row) {
|
||||
if (operation.action === 'startChange') {
|
||||
this.openProjectDialog('change', row);
|
||||
return;
|
||||
}
|
||||
const run = value => {
|
||||
const args = operation.prompt ? [row.id, value] : [row.id];
|
||||
this.api[operation.action](...args).then(() => {
|
||||
this.api[operation.action](...args).then(res => {
|
||||
if (res.data?.success === false || res.data?.data === false) {
|
||||
this.$message.error(res.data?.msg || `${operation.label}失败,请联系管理员`);
|
||||
return;
|
||||
}
|
||||
this.$message.success(`${operation.label}成功`);
|
||||
this.onLoad(this.page, this.query);
|
||||
});
|
||||
@@ -1084,13 +1233,20 @@ export default {
|
||||
this.dialogType = type;
|
||||
this.dialogReadonly = type === 'view';
|
||||
this.projectBox = true;
|
||||
if (type === 'add') {
|
||||
this.applyProjectDetail(emptyForm());
|
||||
if (type === 'add' || type === 'majorSupplement') {
|
||||
this.applyProjectDetail({
|
||||
...emptyForm(),
|
||||
projectType: type === 'majorSupplement' ? '重大项目' : '',
|
||||
});
|
||||
this.fillDefaultUsers();
|
||||
return;
|
||||
}
|
||||
this.api.getDetail(row.id).then(res => {
|
||||
this.applyProjectDetail(res.data.data || {});
|
||||
const detail = res.data.data || {};
|
||||
this.applyProjectDetail({
|
||||
...detail,
|
||||
changeType: type === 'change' ? this.resolveChangeType(detail) : detail.changeType,
|
||||
});
|
||||
});
|
||||
},
|
||||
resetProjectDialog() {
|
||||
@@ -1113,16 +1269,23 @@ export default {
|
||||
: [],
|
||||
};
|
||||
const situation = this.parseSituation(row.situationRemark);
|
||||
const customerRows = this.parseJsonArray(row.customerJson);
|
||||
const carrierRows = this.parseJsonArray(row.carrierJson);
|
||||
this.form = {
|
||||
...form,
|
||||
...situation,
|
||||
customerNames: this.getCustomerRowNames(customerRows, 'customer') || form.customerNames,
|
||||
carrierNames: this.getCustomerRowNames(carrierRows, 'carrier') || form.carrierNames,
|
||||
};
|
||||
this.customerRows = this.parseJsonArray(row.customerJson);
|
||||
this.carrierRows = this.parseJsonArray(row.carrierJson);
|
||||
this.customerRows = customerRows;
|
||||
this.carrierRows = carrierRows;
|
||||
this.attachmentRows = this.parseJsonArray(row.attachmentsJson);
|
||||
this.changeRows = this.buildChangeRows(row);
|
||||
this.selectedCustomerId = this.customerRows[0]?.id || '';
|
||||
this.selectedCarrierIds = this.carrierRows.map(item => item.id).filter(Boolean);
|
||||
this.selectedCustomerId = this.getCustomerRowId(this.customerRows[0]);
|
||||
this.selectedCarrierIds = this.carrierRows
|
||||
.map(item => this.getCustomerRowId(item))
|
||||
.filter(Boolean);
|
||||
this.syncSelectedCustomerOptions();
|
||||
},
|
||||
fillDefaultUsers() {
|
||||
const userId = this.userInfo?.userId || this.userInfo?.id || '';
|
||||
@@ -1135,14 +1298,28 @@ export default {
|
||||
this.form.principalUserName = userName;
|
||||
}
|
||||
},
|
||||
resolveChangeType(row = {}) {
|
||||
if (row.changeType) return row.changeType;
|
||||
const node = row.currentNode || '';
|
||||
if (String(node).includes('备案')) return '项目备案调整';
|
||||
return '项目变更';
|
||||
},
|
||||
submitProject() {
|
||||
this.$refs.projectForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
if (!valid) {
|
||||
this.handleValidateFail();
|
||||
return;
|
||||
}
|
||||
if (!this.validateAttachmentFileTypes()) return;
|
||||
this.submitLoading = true;
|
||||
this.api
|
||||
.submit(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);
|
||||
@@ -1156,7 +1333,39 @@ export default {
|
||||
});
|
||||
});
|
||||
},
|
||||
normalizeSubmitForm() {
|
||||
saveChangeProject() {
|
||||
this.submitChangeForm(false);
|
||||
},
|
||||
submitChangeProject() {
|
||||
this.submitChangeForm(true);
|
||||
},
|
||||
submitChangeForm(needSubmit) {
|
||||
this.$refs.projectForm.validate(valid => {
|
||||
if (!valid) {
|
||||
this.handleValidateFail();
|
||||
return;
|
||||
}
|
||||
if (!this.validateAttachmentFileTypes()) return;
|
||||
this.submitLoading = true;
|
||||
const request = needSubmit ? this.api.submitChange : this.api.saveChange;
|
||||
request(this.normalizeSubmitForm({ includeChangeType: true }))
|
||||
.then(res => {
|
||||
if (res.data?.success === false || res.data?.data === false) {
|
||||
this.$message.error(
|
||||
res.data?.msg || `${needSubmit ? '提交' : '保存'}失败,请联系管理员`
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.$message.success(`${needSubmit ? '提交' : '保存'}成功!`);
|
||||
this.projectBox = false;
|
||||
this.onLoad(this.page, this.query);
|
||||
})
|
||||
.finally(() => {
|
||||
this.submitLoading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
normalizeSubmitForm(options = {}) {
|
||||
const [businessStartDate, businessEndDate] = this.form.businessDateRange || [];
|
||||
const submitRow = {
|
||||
...this.form,
|
||||
@@ -1173,6 +1382,9 @@ export default {
|
||||
}),
|
||||
};
|
||||
delete submitRow.businessDateRange;
|
||||
if (!options.includeChangeType) {
|
||||
delete submitRow.changeType;
|
||||
}
|
||||
['projectIntro', 'profitRemark', 'riskPoint', 'emergencyPlan'].forEach(
|
||||
key => delete submitRow[key]
|
||||
);
|
||||
@@ -1183,6 +1395,35 @@ export default {
|
||||
});
|
||||
return submitRow;
|
||||
},
|
||||
normalizeAttachmentFileTypes() {
|
||||
const values = this.projectAttachmentTypeOptions.map(item => item.value);
|
||||
this.attachmentRows = this.attachmentRows.map(row => ({
|
||||
...row,
|
||||
fileType: values.includes(row.fileType) ? row.fileType : '',
|
||||
}));
|
||||
},
|
||||
validateAttachmentFileTypes() {
|
||||
const values = this.projectAttachmentTypeOptions.map(item => item.value);
|
||||
const invalidIndex = this.attachmentRows.findIndex(row => !values.includes(row.fileType));
|
||||
if (invalidIndex === -1) return true;
|
||||
this.$message.warning(`请选择第${invalidIndex + 1}行项目材料的附件类型`);
|
||||
this.$nextTick(() => {
|
||||
const field = this.$el.querySelector('.project-apply-form__material-head');
|
||||
if (field && typeof field.scrollIntoView === 'function') {
|
||||
field.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
});
|
||||
return false;
|
||||
},
|
||||
handleValidateFail() {
|
||||
this.$message.warning('请完善表单必填项后再提交');
|
||||
this.$nextTick(() => {
|
||||
const field = this.$el.querySelector('.is-error');
|
||||
if (field && typeof field.scrollIntoView === 'function') {
|
||||
field.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
});
|
||||
},
|
||||
parseSituation(value) {
|
||||
if (!value) {
|
||||
return { projectIntro: '', profitRemark: '', riskPoint: '', emergencyPlan: '' };
|
||||
@@ -1212,15 +1453,63 @@ export default {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
getCustomerRowId(row = {}) {
|
||||
return row.id || row.customerId || row.carrierId || '';
|
||||
},
|
||||
getCustomerRowLabel(row = {}, type) {
|
||||
return (
|
||||
row[type === 'carrier' ? 'carrier' : 'customer'] ||
|
||||
row.fullName ||
|
||||
row.shortName ||
|
||||
row.customerName ||
|
||||
row.carrierName ||
|
||||
row.customerCode ||
|
||||
''
|
||||
);
|
||||
},
|
||||
getCustomerRowNames(rows = [], type) {
|
||||
return rows
|
||||
.map(row => this.getCustomerRowLabel(row, type))
|
||||
.filter(Boolean)
|
||||
.join('、');
|
||||
},
|
||||
buildCustomerOptionsFromRows(rows = [], type) {
|
||||
return rows
|
||||
.map(row => {
|
||||
const value = this.getCustomerRowId(row);
|
||||
const label = this.getCustomerRowLabel(row, type);
|
||||
return value && label ? { label, value, raw: row } : null;
|
||||
})
|
||||
.filter(Boolean);
|
||||
},
|
||||
mergeCustomerOptions(options = [], selectedOptions = []) {
|
||||
const result = [...selectedOptions];
|
||||
options.forEach(option => {
|
||||
const exists = result.some(item => String(item.value) === String(option.value));
|
||||
if (!exists) {
|
||||
result.push(option);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
syncSelectedCustomerOptions() {
|
||||
this.customerOptions = this.mergeCustomerOptions(
|
||||
this.customerOptions,
|
||||
this.buildCustomerOptionsFromRows(this.customerRows, 'customer')
|
||||
);
|
||||
this.carrierOptions = this.mergeCustomerOptions(
|
||||
this.carrierOptions,
|
||||
this.buildCustomerOptionsFromRows(this.carrierRows, 'carrier')
|
||||
);
|
||||
},
|
||||
buildChangeRows(row) {
|
||||
if (!row || (!row.changeContent && !row.changeReason)) return [];
|
||||
return [
|
||||
{
|
||||
changeDate: row.updateTime || row.createTime || '',
|
||||
changeType:
|
||||
row.approvalStatus && String(row.approvalStatus).includes('change')
|
||||
? '项目变更'
|
||||
: '项目调整备案',
|
||||
row.changeType ||
|
||||
(String(row.currentNode || '').includes('备案') ? '项目备案调整' : '项目变更'),
|
||||
handler: row.handlerUserName || '',
|
||||
content: row.changeContent || '',
|
||||
reason: row.changeReason || '',
|
||||
@@ -1239,6 +1528,10 @@ export default {
|
||||
this.form.undertakeDeptName = dept ? dept.rawLabel : '';
|
||||
this.$refs.projectForm?.validateField('undertakeDeptId');
|
||||
},
|
||||
handleProjectTypeChange() {
|
||||
this.normalizeAttachmentFileTypes();
|
||||
this.$refs.projectForm?.validateField('projectType');
|
||||
},
|
||||
loadDeptOptions() {
|
||||
getDeptTree().then(res => {
|
||||
this.deptOptions = this.flattenDept(res.data.data || []);
|
||||
@@ -1259,13 +1552,21 @@ export default {
|
||||
}, []);
|
||||
},
|
||||
loadCargoTypeOptions() {
|
||||
getDictionary({ code: 'type_of_goods' }).then(res => {
|
||||
getSystemDictionary({ code: 'type_of_goods' }).then(res => {
|
||||
this.cargoTypeOptions = (res.data.data || []).map(item => ({
|
||||
label: item.dictValue,
|
||||
value: item.dictKey,
|
||||
}));
|
||||
});
|
||||
},
|
||||
loadTransportTypeOptions() {
|
||||
getBizDictionary({ code: 'transport_type' }).then(res => {
|
||||
this.transportTypeOptions = (res.data.data || []).map(item => ({
|
||||
label: item.dictValue,
|
||||
value: item.dictKey,
|
||||
}));
|
||||
});
|
||||
},
|
||||
loadCustomerOptions(type) {
|
||||
const loadingKey = type === '客户' ? 'customerLoading' : 'carrierLoading';
|
||||
const optionsKey = type === '客户' ? 'customerOptions' : 'carrierOptions';
|
||||
@@ -1273,7 +1574,14 @@ export default {
|
||||
getCustomerArchiveList(1, 100, { customerType: type, status: 1 })
|
||||
.then(res => {
|
||||
const records = (res.data.data && res.data.data.records) || [];
|
||||
this[optionsKey] = records.map(item => this.mapCustomerOption(item));
|
||||
const selectedOptions = this.buildCustomerOptionsFromRows(
|
||||
type === '客户' ? this.customerRows : this.carrierRows,
|
||||
type === '客户' ? 'customer' : 'carrier'
|
||||
);
|
||||
this[optionsKey] = this.mergeCustomerOptions(
|
||||
records.map(item => this.mapCustomerOption(item)),
|
||||
selectedOptions
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
this[loadingKey] = false;
|
||||
@@ -1298,6 +1606,7 @@ export default {
|
||||
this.customerRows = [row];
|
||||
this.form.customerNames = row.customer;
|
||||
this.form.customerJson = JSON.stringify(this.customerRows);
|
||||
this.syncSelectedCustomerOptions();
|
||||
this.$refs.projectForm?.validateField('customerNames');
|
||||
});
|
||||
},
|
||||
@@ -1312,6 +1621,7 @@ export default {
|
||||
this.carrierRows = rows;
|
||||
this.form.carrierNames = rows.map(item => item.carrier).join('、');
|
||||
this.form.carrierJson = JSON.stringify(this.carrierRows);
|
||||
this.syncSelectedCustomerOptions();
|
||||
this.$refs.projectForm?.validateField('carrierNames');
|
||||
});
|
||||
},
|
||||
@@ -1353,9 +1663,10 @@ export default {
|
||||
handleAttachmentChange(list) {
|
||||
const userName = this.userInfo?.realName || this.userInfo?.userName || '';
|
||||
const uploadTime = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
const values = this.projectAttachmentTypeOptions.map(item => item.value);
|
||||
this.attachmentRows = (list || []).map(item => ({
|
||||
...item,
|
||||
fileType: item.fileType || '其他',
|
||||
fileType: values.includes(item.fileType) ? item.fileType : '',
|
||||
description: item.description || '',
|
||||
uploadUserName: item.uploadUserName || userName,
|
||||
uploadTime: item.uploadTime || uploadTime,
|
||||
@@ -1377,7 +1688,7 @@ export default {
|
||||
this.$message.warning('附件地址为空');
|
||||
return;
|
||||
}
|
||||
downloadFileByUrl(url, row.name || '附件');
|
||||
downloadFileByUrl(url, row.originalName || row.name || '附件');
|
||||
},
|
||||
handleBatchDownload() {
|
||||
this.attachmentRows.forEach(row => this.downloadAttachment(row));
|
||||
@@ -1425,13 +1736,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.project-apply-page {
|
||||
&__scope {
|
||||
margin-left: 12px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.project-apply-form {
|
||||
padding: 0 8px;
|
||||
|
||||
@@ -1523,6 +1827,15 @@ export default {
|
||||
&__upload {
|
||||
margin: -12px 0 24px;
|
||||
}
|
||||
|
||||
&__change-textarea {
|
||||
margin-bottom: 24px;
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
width: 100%;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(.project-apply-dialog .el-dialog__body) {
|
||||
@@ -1535,6 +1848,11 @@ export default {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
|
||||
&--change {
|
||||
justify-content: flex-start;
|
||||
padding-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.project-apply-user-dialog {
|
||||
|
||||
@@ -41,6 +41,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import { getList, remove, update, add, getNotice } from '@/api/desk/notice';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
|
||||
// 定义响应式数据
|
||||
const form = ref({});
|
||||
@@ -145,6 +146,7 @@ const option = reactive({
|
||||
prop: 'content',
|
||||
component: 'avue-ueditor',
|
||||
action: '/blade-resource/oss/endpoint/put-file',
|
||||
headers: getUploadHeaders(),
|
||||
propsHttp: {
|
||||
res: 'data',
|
||||
url: 'link',
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
import { getList, remove, update, add, getNotice } from '@/api/desk/notice';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { validatenull } from '@/utils/validate';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -146,6 +147,7 @@ export default {
|
||||
prop: 'content',
|
||||
component: 'avue-ueditor',
|
||||
action: '/blade-resource/oss/endpoint/put-file',
|
||||
headers: getUploadHeaders(),
|
||||
propsHttp: {
|
||||
res: 'data',
|
||||
url: 'link',
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<script>
|
||||
import { getList, getDetail, remove } from '@/api/resource/attach';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import { UploadFilled } from '@element-plus/icons-vue';
|
||||
import func from '@/utils/func';
|
||||
|
||||
@@ -98,10 +98,6 @@ export default {
|
||||
uploading: false,
|
||||
uploadPercent: 0,
|
||||
selectionList: [],
|
||||
uploadHeaders: {
|
||||
'Blade-Auth': `bearer ${getToken()}`,
|
||||
'Blade-Requested-With': 'BladeHttpRequest',
|
||||
},
|
||||
option: {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
@@ -194,6 +190,9 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
uploadHeaders() {
|
||||
return getUploadHeaders();
|
||||
},
|
||||
func() {
|
||||
return func;
|
||||
},
|
||||
|
||||
@@ -64,6 +64,7 @@ import { getList, getDetail, add, update, remove, enable } from '@/api/resource/
|
||||
import { mapGetters } from 'vuex';
|
||||
import func from '@/utils/func';
|
||||
import { sensitive } from '@/utils/sensitive';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -252,6 +253,7 @@ export default {
|
||||
listType: 'picture-img',
|
||||
dataType: 'string',
|
||||
action: '/blade-resource/oss/endpoint/put-file',
|
||||
headers: getUploadHeaders(),
|
||||
propsHttp: {
|
||||
res: 'data',
|
||||
url: 'link',
|
||||
|
||||
@@ -68,6 +68,7 @@ export default {
|
||||
loading: true,
|
||||
selectionList: [],
|
||||
parentId: 0,
|
||||
currentEditMenuId: '',
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
@@ -331,6 +332,7 @@ export default {
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
row.id = row.id || this.currentEditMenuId;
|
||||
update(row).then(
|
||||
() => {
|
||||
this.$message({
|
||||
@@ -419,8 +421,11 @@ export default {
|
||||
this.form.isDisplay = 1;
|
||||
}
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getMenu(this.form.id).then(res => {
|
||||
const menuId = this.form.id;
|
||||
this.currentEditMenuId = menuId;
|
||||
getMenu(menuId).then(res => {
|
||||
this.form = Object.assign(res.data.data, {
|
||||
id: res.data.data.id || menuId,
|
||||
hasChildren: this.form.hasChildren,
|
||||
});
|
||||
if (this.form.parentId === '0') {
|
||||
@@ -432,6 +437,7 @@ export default {
|
||||
},
|
||||
beforeClose(done) {
|
||||
this.parentId = '';
|
||||
this.currentEditMenuId = '';
|
||||
const column = this.findColumn(this.option.column, 'parentId');
|
||||
column.value = '';
|
||||
column.addDisabled = false;
|
||||
|
||||
@@ -205,6 +205,7 @@ import { getDetail as packageDetail } from '@/api/system/tenantpackage';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { getMenuTree } from '@/api/system/menu';
|
||||
import { validatenull } from '@/utils/validate';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -326,6 +327,7 @@ export default {
|
||||
listType: 'picture-img',
|
||||
dataType: 'string',
|
||||
action: '/blade-resource/oss/endpoint/put-file',
|
||||
headers: getUploadHeaders(),
|
||||
propsHttp: {
|
||||
res: 'data',
|
||||
url: 'link',
|
||||
|
||||
@@ -156,7 +156,7 @@ import {
|
||||
Delete,
|
||||
} from '@element-plus/icons-vue';
|
||||
import { ElImageViewer } from 'element-plus';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -192,10 +192,6 @@ export default {
|
||||
sensitiveManager: null,
|
||||
showAvatarPreview: false,
|
||||
avatarPreviewList: [],
|
||||
uploadHeaders: {
|
||||
'Blade-Auth': `bearer ${getToken()}`,
|
||||
'Blade-Requested-With': 'BladeHttpRequest',
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
@@ -208,6 +204,11 @@ export default {
|
||||
this.loadUserInfo();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
uploadHeaders() {
|
||||
return getUploadHeaders();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// Tab切换处理
|
||||
handleTabChange(name) {
|
||||
|
||||
@@ -100,12 +100,7 @@
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
v-if="hasPermission('driver_edit')"
|
||||
@click="openDriver(row)"
|
||||
>
|
||||
<el-button type="primary" text v-if="hasPermission('driver_edit')" @click="openDriver(row)">
|
||||
修改
|
||||
</el-button>
|
||||
<el-button
|
||||
@@ -222,7 +217,7 @@
|
||||
:readonly="readonly"
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
@success="url => setImage('idCardFront', url)"
|
||||
@success="url => handleIdCardUploadSuccess('idCardFront', url)"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
@@ -233,7 +228,7 @@
|
||||
:readonly="readonly"
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
@success="url => setImage('idCardBack', url)"
|
||||
@success="url => handleIdCardUploadSuccess('idCardBack', url)"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
@@ -317,7 +312,10 @@
|
||||
:readonly="readonly"
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
@success="url => setImage('drivingLicenseFront', url)"
|
||||
@success="
|
||||
(url, file) =>
|
||||
handleDrivingLicenseUploadSuccess('drivingLicenseFront', url, file)
|
||||
"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -328,7 +326,9 @@
|
||||
:readonly="readonly"
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
@success="url => setImage('drivingLicenseBack', url)"
|
||||
@success="
|
||||
(url, file) => handleDrivingLicenseUploadSuccess('drivingLicenseBack', url, file)
|
||||
"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -483,6 +483,7 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import { ElLoading } from 'element-plus';
|
||||
import { option } from '@/option/transportCapacity/driver';
|
||||
import {
|
||||
getList,
|
||||
@@ -491,10 +492,13 @@ import {
|
||||
remove,
|
||||
changeStatus,
|
||||
getExpiryStat,
|
||||
recognitionIDCard,
|
||||
recognitionTransportCertificates,
|
||||
} from '@/api/transportCapacity/driver';
|
||||
import { getDeptTree } from '@/api/system/dept';
|
||||
import { exportBlob } from '@/api/common';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import ImageUploadField from '@/components/image-upload-field/main.vue';
|
||||
|
||||
@@ -565,10 +569,8 @@ export default {
|
||||
driverBox: false,
|
||||
readonly: false,
|
||||
driverForm: emptyForm(),
|
||||
uploadHeaders: {
|
||||
'Blade-Auth': `bearer ${getToken()}`,
|
||||
'Blade-Requested-With': 'BladeHttpRequest',
|
||||
},
|
||||
drivingLicenseUploads: {},
|
||||
uploadHeaders: getUploadHeaders(),
|
||||
nationOptions: [
|
||||
'汉族',
|
||||
'蒙古族',
|
||||
@@ -773,6 +775,7 @@ export default {
|
||||
},
|
||||
resetDriver() {
|
||||
this.driverForm = emptyForm();
|
||||
this.drivingLicenseUploads = {};
|
||||
this.readonly = false;
|
||||
this.submitLoading = false;
|
||||
this.$refs.driverForm?.clearValidate();
|
||||
@@ -781,6 +784,230 @@ export default {
|
||||
this.driverForm[prop] = url;
|
||||
this.$refs.driverForm?.validateField(prop);
|
||||
},
|
||||
handleIdCardUploadSuccess(prop, url) {
|
||||
this.setImage(prop, url);
|
||||
this.recognizeIdCard(url);
|
||||
},
|
||||
handleDrivingLicenseUploadSuccess(prop, url, file = {}) {
|
||||
this.setImage(prop, url);
|
||||
this.drivingLicenseUploads[prop] = this.getUploadRecognitionKey(file, url);
|
||||
this.recognizeDrivingLicense();
|
||||
},
|
||||
recognizeIdCard(url = '') {
|
||||
if (!url) {
|
||||
this.$message.warning('身份证图片上传成功,未获取到图片地址,无法自动识别');
|
||||
return;
|
||||
}
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '身份证识别中',
|
||||
background: 'rgba(255, 255, 255, 0.7)',
|
||||
});
|
||||
recognitionIDCard(url)
|
||||
.then(res => {
|
||||
const data = res.data.data || {};
|
||||
this.applyIdCardRecognition(data);
|
||||
this.$message.success('身份证识别完成');
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.warning('身份证图片上传成功,自动识别失败,请手动填写身份信息');
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close();
|
||||
});
|
||||
},
|
||||
recognizeDrivingLicense() {
|
||||
const objectKeys = [
|
||||
this.drivingLicenseUploads.drivingLicenseFront || this.driverForm.drivingLicenseFront,
|
||||
this.drivingLicenseUploads.drivingLicenseBack || this.driverForm.drivingLicenseBack,
|
||||
].filter(Boolean);
|
||||
if (!objectKeys.length) {
|
||||
this.$message.warning('驾驶证图片上传成功,未获取到图片地址,无法自动识别');
|
||||
return;
|
||||
}
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '驾驶证识别中',
|
||||
background: 'rgba(255, 255, 255, 0.7)',
|
||||
});
|
||||
recognitionTransportCertificates(objectKeys)
|
||||
.then(res => {
|
||||
const data = res.data.data || {};
|
||||
this.applyDrivingLicenseRecognition(data);
|
||||
this.$message.success('驾驶证识别完成');
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.warning('驾驶证图片上传成功,自动识别失败,请手动填写驾驶证信息');
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close();
|
||||
});
|
||||
},
|
||||
applyDrivingLicenseRecognition(data = {}) {
|
||||
const driverName = data.driverLicenseName || data.name || this.getOcrValue(data, ['name', '姓名']);
|
||||
const idCardNo = String(
|
||||
data.driverLicenseIdNo ||
|
||||
data.idNo ||
|
||||
data.idCardNo ||
|
||||
this.getOcrValue(data, ['ID_no', 'idNo', 'idCardNo', '证号'])
|
||||
).toUpperCase();
|
||||
const drivingType =
|
||||
data.driverLicenseType ||
|
||||
data.drivingType ||
|
||||
data.driverClass ||
|
||||
this.getOcrValue(data, ['class', '准驾车型']);
|
||||
const drivingLicenseNo =
|
||||
data.driverLicenseFileNo ||
|
||||
data.drivingLicenseNo ||
|
||||
data.fileNo ||
|
||||
this.getOcrValue(data, ['file_no', '档案编号']);
|
||||
const validDateStart =
|
||||
data.driverLicenseValidDateStart ||
|
||||
data.drivingLicenseStartDate ||
|
||||
this.getOcrValue(data, ['date_vaild_start', '有效期限(起始时间)']);
|
||||
const validDateEnd =
|
||||
data.driverLicenseValidDateEnd ||
|
||||
data.drivingLicenseEndDate ||
|
||||
this.getOcrValue(data, ['date_vaild_end', '有效期限(终止时间)', '有效期限(终⽌时间)']);
|
||||
if (driverName && !this.driverForm.driverName) {
|
||||
this.driverForm.driverName = driverName;
|
||||
}
|
||||
if (idCardNo && !this.driverForm.idCardNo) {
|
||||
this.driverForm.idCardNo = idCardNo;
|
||||
}
|
||||
if (idCardNo && !this.driverForm.qualificationNo) {
|
||||
this.driverForm.qualificationNo = idCardNo;
|
||||
}
|
||||
if (drivingType) {
|
||||
this.driverForm.drivingType = drivingType;
|
||||
}
|
||||
if (drivingLicenseNo) {
|
||||
this.driverForm.drivingLicenseNo = drivingLicenseNo;
|
||||
}
|
||||
if (validDateStart) {
|
||||
this.driverForm.drivingLicenseStartDate = this.normalizeBirthday(validDateStart);
|
||||
}
|
||||
if (validDateEnd) {
|
||||
this.driverForm.drivingLicenseEndDate = this.normalizeBirthday(validDateEnd);
|
||||
this.driverForm.drivingLicenseLongTerm = 0;
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
[
|
||||
'driverName',
|
||||
'idCardNo',
|
||||
'drivingType',
|
||||
'drivingLicenseNo',
|
||||
'drivingLicenseEndDate',
|
||||
'qualificationNo',
|
||||
].forEach(prop => {
|
||||
this.$refs.driverForm?.validateField(prop);
|
||||
});
|
||||
});
|
||||
},
|
||||
getUploadRecognitionKey(file = {}, url = '') {
|
||||
return (
|
||||
file.objectKey ||
|
||||
file.key ||
|
||||
file.fileName ||
|
||||
file.name ||
|
||||
file.link ||
|
||||
file.url ||
|
||||
file.domain ||
|
||||
url ||
|
||||
''
|
||||
);
|
||||
},
|
||||
applyIdCardRecognition(data = {}) {
|
||||
const driverName = data.name || data.driverName || this.getOcrValue(data, ['name', '姓名']);
|
||||
const idCardNo = String(
|
||||
data.idNo ||
|
||||
data.idCardNo ||
|
||||
data.idCard ||
|
||||
this.getOcrValue(data, ['idNo', 'idCardNo', 'number', '公民身份号码', '身份证号'])
|
||||
).toUpperCase();
|
||||
const ocrGender = data.gender || this.getOcrValue(data, ['gender', '性别']);
|
||||
const ocrNation =
|
||||
data.nation ||
|
||||
data.ethnicGroup ||
|
||||
this.getOcrValue(data, ['ethnic_group', 'nation', '民族']);
|
||||
const ocrBirthday =
|
||||
data.birthday || data.birthDate || this.getOcrValue(data, ['date', '出生']);
|
||||
if (driverName) {
|
||||
this.driverForm.driverName = driverName;
|
||||
}
|
||||
if (ocrGender) {
|
||||
this.driverForm.gender = ocrGender;
|
||||
}
|
||||
if (ocrNation) {
|
||||
this.driverForm.nation = this.normalizeNation(ocrNation);
|
||||
}
|
||||
if (ocrBirthday) {
|
||||
this.driverForm.birthday = this.normalizeBirthday(ocrBirthday);
|
||||
}
|
||||
if (idCardNo) {
|
||||
this.driverForm.idCardNo = idCardNo;
|
||||
if (!this.driverForm.qualificationNo) {
|
||||
this.driverForm.qualificationNo = idCardNo;
|
||||
}
|
||||
const idCardInfo = this.parseIdCardInfo(idCardNo);
|
||||
if (!this.driverForm.birthday && idCardInfo.birthday) {
|
||||
this.driverForm.birthday = idCardInfo.birthday;
|
||||
}
|
||||
if (!this.driverForm.gender && idCardInfo.gender) {
|
||||
this.driverForm.gender = idCardInfo.gender;
|
||||
}
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
['driverName', 'idCardNo', 'birthday', 'gender', 'nation', 'qualificationNo'].forEach(
|
||||
prop => {
|
||||
this.$refs.driverForm?.validateField(prop);
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
getOcrValue(data = {}, keys = []) {
|
||||
const keyInfos = data.keyInfos || data.keyInfo || data.ocrKeyInfos || [];
|
||||
const list = Array.isArray(keyInfos) ? keyInfos : [];
|
||||
const item = list.find(info => {
|
||||
const key = String(info.key || '').toLowerCase();
|
||||
const description = String(info.description || '');
|
||||
return keys.some(value => key === String(value).toLowerCase() || description === value);
|
||||
});
|
||||
return item ? item.value || '' : '';
|
||||
},
|
||||
normalizeNation(value = '') {
|
||||
const nation = String(value || '').trim();
|
||||
if (!nation) return '';
|
||||
if (this.nationOptions.includes(nation)) return nation;
|
||||
const fullNation = `${nation}族`;
|
||||
return this.nationOptions.includes(fullNation) ? fullNation : nation;
|
||||
},
|
||||
normalizeBirthday(value = '') {
|
||||
const birthday = String(value || '').trim();
|
||||
const match = birthday.match(/^(\d{4})[-/.年](\d{1,2})[-/.月](\d{1,2})日?$/);
|
||||
if (!match) return birthday;
|
||||
const [, year, month, day] = match;
|
||||
return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
|
||||
},
|
||||
parseIdCardInfo(idCardNo = '') {
|
||||
if (!/^\d{17}[\dX]$/.test(idCardNo)) {
|
||||
return {};
|
||||
}
|
||||
const birthday = `${idCardNo.slice(6, 10)}-${idCardNo.slice(10, 12)}-${idCardNo.slice(
|
||||
12,
|
||||
14
|
||||
)}`;
|
||||
const date = new Date(`${birthday}T00:00:00`);
|
||||
const validDate =
|
||||
!Number.isNaN(date.getTime()) &&
|
||||
date.getFullYear() === Number(idCardNo.slice(6, 10)) &&
|
||||
date.getMonth() + 1 === Number(idCardNo.slice(10, 12)) &&
|
||||
date.getDate() === Number(idCardNo.slice(12, 14));
|
||||
return {
|
||||
birthday: validDate ? birthday : '',
|
||||
gender: Number(idCardNo.slice(16, 17)) % 2 === 1 ? '男' : '女',
|
||||
};
|
||||
},
|
||||
validateFormField(prop) {
|
||||
this.$refs.driverForm?.validateField(prop);
|
||||
},
|
||||
@@ -914,7 +1141,9 @@ export default {
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
NProgress.start();
|
||||
exportBlob('/blade-transport/driver/export-driver', this.buildExportParams(), { feedback: true })
|
||||
exportBlob('/blade-transport/driver/export-driver', this.buildExportParams(), {
|
||||
feedback: true,
|
||||
})
|
||||
.then(res => {
|
||||
downloadXls(res.data, `司机管理${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
|
||||
})
|
||||
|
||||
@@ -571,6 +571,7 @@ import {
|
||||
} from '@/api/transportCapacity/transport-ship';
|
||||
import { exportBlob } from '@/api/common';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import ImageUploadField from '@/components/image-upload-field/main.vue';
|
||||
|
||||
@@ -639,10 +640,7 @@ export default {
|
||||
shipBox: false,
|
||||
readonly: false,
|
||||
shipForm: emptyForm(),
|
||||
uploadHeaders: {
|
||||
'Blade-Auth': `bearer ${getToken()}`,
|
||||
'Blade-Requested-With': 'BladeHttpRequest',
|
||||
},
|
||||
uploadHeaders: getUploadHeaders(),
|
||||
organizationOptions: [],
|
||||
formRules: {
|
||||
organizationName: [{ required: true, message: '请选择船舶所属组织', trigger: 'change' }],
|
||||
|
||||
@@ -406,7 +406,10 @@
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
class-prefix="vehicle"
|
||||
@success="url => setImage('drivingLicenseImage', url)"
|
||||
@success="
|
||||
(url, file) =>
|
||||
handleVehicleCertificateUploadSuccess('drivingLicenseImage', url, file)
|
||||
"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
@@ -418,7 +421,10 @@
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
class-prefix="vehicle"
|
||||
@success="url => setImage('drivingLicenseMainBack', url)"
|
||||
@success="
|
||||
(url, file) =>
|
||||
handleVehicleCertificateUploadSuccess('drivingLicenseMainBack', url, file)
|
||||
"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
@@ -430,7 +436,10 @@
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
class-prefix="vehicle"
|
||||
@success="url => setImage('drivingLicenseViceFront', url)"
|
||||
@success="
|
||||
(url, file) =>
|
||||
handleVehicleCertificateUploadSuccess('drivingLicenseViceFront', url, file)
|
||||
"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -444,7 +453,10 @@
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
class-prefix="vehicle"
|
||||
@success="url => setImage('drivingLicenseViceBack', url)"
|
||||
@success="
|
||||
(url, file) =>
|
||||
handleVehicleCertificateUploadSuccess('drivingLicenseViceBack', url, file)
|
||||
"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
@@ -468,7 +480,10 @@
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
class-prefix="vehicle"
|
||||
@success="url => setImage('registrationImage', url)"
|
||||
@success="
|
||||
(url, file) =>
|
||||
handleVehicleCertificateUploadSuccess('registrationImage', url, file)
|
||||
"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -486,6 +501,7 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import { ElLoading } from 'element-plus';
|
||||
import { option } from '@/option/transportCapacity/transport-vehicle';
|
||||
import {
|
||||
getList,
|
||||
@@ -494,10 +510,12 @@ import {
|
||||
remove,
|
||||
changeStatus,
|
||||
getExpiryStat,
|
||||
recognitionTransportCertificates,
|
||||
} from '@/api/transportCapacity/transport-vehicle';
|
||||
import { getDeptTree } from '@/api/system/dept';
|
||||
import { exportBlob } from '@/api/common';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import ImageUploadField from '@/components/image-upload-field/main.vue';
|
||||
|
||||
@@ -608,10 +626,8 @@ export default {
|
||||
vehicleBox: false,
|
||||
readonly: false,
|
||||
vehicleForm: emptyForm(),
|
||||
uploadHeaders: {
|
||||
'Blade-Auth': `bearer ${getToken()}`,
|
||||
'Blade-Requested-With': 'BladeHttpRequest',
|
||||
},
|
||||
vehicleCertificateUploads: {},
|
||||
uploadHeaders: getUploadHeaders(),
|
||||
organizationOptions: [],
|
||||
plateProvinceOptions,
|
||||
plateColorOptions,
|
||||
@@ -733,6 +749,7 @@ export default {
|
||||
},
|
||||
resetVehicle() {
|
||||
this.vehicleForm = emptyForm();
|
||||
this.vehicleCertificateUploads = {};
|
||||
this.readonly = false;
|
||||
this.submitLoading = false;
|
||||
this.$refs.vehicleForm?.clearValidate();
|
||||
@@ -741,6 +758,116 @@ export default {
|
||||
this.vehicleForm[prop] = url;
|
||||
this.$refs.vehicleForm?.validateField(prop);
|
||||
},
|
||||
handleVehicleCertificateUploadSuccess(prop, url, file = {}) {
|
||||
this.setImage(prop, url);
|
||||
this.vehicleCertificateUploads[prop] = this.getUploadRecognitionKey(file, url);
|
||||
this.recognizeVehicleCertificates();
|
||||
},
|
||||
recognizeVehicleCertificates() {
|
||||
const objectKeys = [
|
||||
this.vehicleCertificateUploads.drivingLicenseImage || this.vehicleForm.drivingLicenseImage,
|
||||
this.vehicleCertificateUploads.drivingLicenseMainBack ||
|
||||
this.vehicleForm.drivingLicenseMainBack,
|
||||
this.vehicleCertificateUploads.drivingLicenseViceFront ||
|
||||
this.vehicleForm.drivingLicenseViceFront,
|
||||
this.vehicleCertificateUploads.drivingLicenseViceBack ||
|
||||
this.vehicleForm.drivingLicenseViceBack,
|
||||
this.vehicleCertificateUploads.registrationImage || this.vehicleForm.registrationImage,
|
||||
].filter(Boolean);
|
||||
if (!objectKeys.length) {
|
||||
this.$message.warning('车辆资质图片上传成功,未获取到图片地址,无法自动识别');
|
||||
return;
|
||||
}
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '车辆资质识别中',
|
||||
background: 'rgba(255, 255, 255, 0.7)',
|
||||
});
|
||||
recognitionTransportCertificates(objectKeys)
|
||||
.then(res => {
|
||||
this.applyVehicleCertificateRecognition(res.data.data || {});
|
||||
this.$message.success('车辆资质识别完成');
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.warning('车辆资质图片上传成功,自动识别失败,请手动填写车辆资质信息');
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close();
|
||||
});
|
||||
},
|
||||
applyVehicleCertificateRecognition(data = {}) {
|
||||
const plateNo = data.drivingPlateNo || data.vehicleLicensePlateNo || '';
|
||||
const vehicleType = data.vehicleLicenseVehicleType || data.vehicleType || '';
|
||||
const drivingLicenseNo =
|
||||
data.vehicleLicenseFileNo || data.drivingLicenseNo || data.fileNo || '';
|
||||
const drivingLicenseEndDate =
|
||||
data.vehicleLicenseInspectionValidDate ||
|
||||
data.drivingLicenseEndDate ||
|
||||
data.vehicleLicenseValidDateEnd ||
|
||||
'';
|
||||
const registrationDate =
|
||||
data.vehicleLicenseRegisterDate || data.registrationDate || data.dateRegister || '';
|
||||
const registrationNo = data.registrationNo || data.vehicleLicenseNo || '';
|
||||
if (plateNo) {
|
||||
this.vehicleForm.plateNo = plateNo;
|
||||
this.splitPlateNo();
|
||||
this.syncPlateNo(false);
|
||||
}
|
||||
if (vehicleType) {
|
||||
this.vehicleForm.vehicleType = this.normalizeVehicleType(vehicleType);
|
||||
}
|
||||
if (drivingLicenseNo) {
|
||||
this.vehicleForm.drivingLicenseNo = drivingLicenseNo;
|
||||
}
|
||||
if (drivingLicenseEndDate) {
|
||||
this.vehicleForm.drivingLicenseEndDate = this.normalizeDate(drivingLicenseEndDate);
|
||||
this.vehicleForm.drivingLicenseLongTerm = 0;
|
||||
}
|
||||
if (registrationDate) {
|
||||
this.vehicleForm.registrationDate = this.normalizeDate(registrationDate);
|
||||
}
|
||||
if (registrationNo) {
|
||||
this.vehicleForm.registrationNo = registrationNo;
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
[
|
||||
'plateNo',
|
||||
'vehicleType',
|
||||
'drivingLicenseNo',
|
||||
'drivingLicenseEndDate',
|
||||
'registrationNo',
|
||||
].forEach(prop => {
|
||||
this.$refs.vehicleForm?.validateField(prop);
|
||||
});
|
||||
});
|
||||
},
|
||||
getUploadRecognitionKey(file = {}, url = '') {
|
||||
return (
|
||||
file.objectKey ||
|
||||
file.key ||
|
||||
file.fileName ||
|
||||
file.name ||
|
||||
file.link ||
|
||||
file.url ||
|
||||
file.domain ||
|
||||
url ||
|
||||
''
|
||||
);
|
||||
},
|
||||
normalizeDate(value = '') {
|
||||
const dateValue = String(value || '').trim();
|
||||
const match = dateValue.match(/^(\d{4})[-/.年](\d{1,2})[-/.月](\d{1,2})日?$/);
|
||||
if (!match) return dateValue;
|
||||
const [, year, month, day] = match;
|
||||
return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
|
||||
},
|
||||
normalizeVehicleType(value = '') {
|
||||
const vehicleType = String(value || '').trim();
|
||||
const option = this.vehicleTypeOptions.find(
|
||||
item => item.value === vehicleType || item.label === vehicleType
|
||||
);
|
||||
return option ? option.value : vehicleType;
|
||||
},
|
||||
handlePlateBodyInput(value) {
|
||||
this.vehicleForm.plateNoBody = String(value || '').toUpperCase();
|
||||
this.syncPlateNo();
|
||||
|
||||
@@ -252,7 +252,7 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="营业期限" prop="businessEndDate">
|
||||
<el-form-item label="营业期限" prop="businessEndDate" required>
|
||||
<div class="business-term-field">
|
||||
<el-date-picker
|
||||
v-model="archiveForm.businessEndDate"
|
||||
@@ -1122,6 +1122,7 @@ import { getLazyTree } from '@/api/base/region';
|
||||
import { exportBlob } from '@/api/common';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import { normalizeSearchRangeParams } from '@/utils/search-range';
|
||||
import { ArrowRight } from '@element-plus/icons-vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
@@ -1353,7 +1354,7 @@ export default {
|
||||
editBtn: false,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
menuWidth: 160,
|
||||
menuWidth: 320,
|
||||
column: [
|
||||
{
|
||||
label: '客商编号',
|
||||
@@ -1535,9 +1536,7 @@ export default {
|
||||
return missing.length ? `缺失核心客商材料:${missing.join('、')}` : '';
|
||||
},
|
||||
uploadHeaders() {
|
||||
return {
|
||||
[this.website.tokenHeader]: getToken(),
|
||||
};
|
||||
return getUploadHeaders();
|
||||
},
|
||||
scoreList() {
|
||||
return this.archiveForm.scores || [];
|
||||
|
||||
@@ -157,6 +157,7 @@ import { exportBlob } from '@/api/common';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import { openImportDialog } from '@/utils/import-excel';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import { normalizeSearchRangeParams } from '@/utils/search-range';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { excelOption, option } from '@/option/vehicle/insurance-record';
|
||||
@@ -225,9 +226,7 @@ export default {
|
||||
};
|
||||
},
|
||||
uploadHeaders() {
|
||||
return {
|
||||
[this.website.tokenHeader]: getToken(),
|
||||
};
|
||||
return getUploadHeaders();
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
||||
Reference in New Issue
Block a user