1、调整合同
2、调整项目 3、调整客商
This commit is contained in:
@@ -424,7 +424,7 @@
|
||||
<el-table :data="paymentRatioRows" border>
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column prop="paymentTerm" label="付款笔数" min-width="180" align="center" />
|
||||
<el-table-column label="付款比例上限" min-width="220" align="center">
|
||||
<el-table-column label="付款比例上限(%)" min-width="220" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input
|
||||
v-model="row.ratioLimit"
|
||||
@@ -541,8 +541,17 @@
|
||||
width="90%"
|
||||
top="4vh"
|
||||
>
|
||||
<pdf-preview
|
||||
v-if="
|
||||
attachmentDocumentPreviewVisible &&
|
||||
attachmentPreviewFile.url &&
|
||||
attachmentPreviewFile.isPdf
|
||||
"
|
||||
:source="attachmentPreviewFile.url"
|
||||
@error="handleAttachmentPreviewError"
|
||||
/>
|
||||
<open-file-viewer
|
||||
v-if="attachmentDocumentPreviewVisible && attachmentPreviewFile.url"
|
||||
v-else-if="attachmentDocumentPreviewVisible && attachmentPreviewFile.url"
|
||||
:file="attachmentPreviewFile.url"
|
||||
:file-name="attachmentPreviewFile.name"
|
||||
:mime-type="attachmentPreviewFile.mimeType"
|
||||
@@ -706,7 +715,7 @@
|
||||
<el-table :data="detailPaymentRatioRows" border>
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column prop="paymentTerm" label="付款笔数" min-width="180" align="center" />
|
||||
<el-table-column label="付款比例上限" min-width="220" align="center">
|
||||
<el-table-column label="付款比例上限(%)" min-width="220" align="center">
|
||||
<template #default="{ row }">{{
|
||||
detailObjectUnitValue(row, 'ratioLimit', '%')
|
||||
}}</template>
|
||||
@@ -791,15 +800,10 @@ import { config, option } from '@/option/business/contract-manage';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
||||
import PdfPreview from '@/components/pdf-preview/main.vue';
|
||||
import { ElImageViewer } from 'element-plus';
|
||||
import { OpenFileViewer } from '@open-file-viewer/vue';
|
||||
import {
|
||||
fallbackPlugin,
|
||||
imagePlugin,
|
||||
officePlugin,
|
||||
pdfPlugin,
|
||||
textPlugin,
|
||||
} from '@open-file-viewer/core';
|
||||
import { fallbackPlugin, imagePlugin, officePlugin, textPlugin } from '@open-file-viewer/core';
|
||||
import '@open-file-viewer/core/style.css';
|
||||
import pdfWorkerSrc from 'pdfjs-dist/build/pdf.worker.mjs?url';
|
||||
|
||||
@@ -879,6 +883,10 @@ const attachmentExtension = row => {
|
||||
};
|
||||
const isAttachmentImage = row =>
|
||||
['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(attachmentExtension(row));
|
||||
const isAttachmentPdf = row => {
|
||||
const mimeType = String(row.mimeType || row.contentType || '').toLowerCase();
|
||||
return mimeType.includes('application/pdf') || attachmentExtension(row) === 'pdf';
|
||||
};
|
||||
const attachmentFileTypes = [
|
||||
'pdf',
|
||||
'bmp',
|
||||
@@ -897,7 +905,6 @@ const attachmentFileTypes = [
|
||||
];
|
||||
const attachmentViewerPlugins = [
|
||||
imagePlugin(),
|
||||
pdfPlugin({ workerSrc: pdfWorkerSrc, useFetchData: true }),
|
||||
officePlugin({ pdf: { workerSrc: pdfWorkerSrc, useFetchData: true } }),
|
||||
textPlugin(),
|
||||
fallbackPlugin(),
|
||||
@@ -1090,7 +1097,7 @@ const AttachmentSection = defineComponent({
|
||||
|
||||
export default {
|
||||
name: 'ContractManage',
|
||||
components: { AttachmentSection, BillingPlanEditor, ElImageViewer, OpenFileViewer },
|
||||
components: { AttachmentSection, BillingPlanEditor, ElImageViewer, OpenFileViewer, PdfPreview },
|
||||
data() {
|
||||
return {
|
||||
api,
|
||||
@@ -1757,10 +1764,12 @@ export default {
|
||||
this.attachmentImagePreviewVisible = true;
|
||||
return;
|
||||
}
|
||||
const isPdf = isAttachmentPdf(row);
|
||||
this.attachmentPreviewFile = {
|
||||
name: attachmentName(row),
|
||||
url,
|
||||
mimeType: row.mimeType || row.contentType || '',
|
||||
mimeType: isPdf ? 'application/pdf' : row.mimeType || row.contentType || '',
|
||||
isPdf,
|
||||
};
|
||||
this.attachmentDocumentPreviewVisible = true;
|
||||
},
|
||||
|
||||
@@ -660,8 +660,17 @@
|
||||
top="4vh"
|
||||
class="project-apply-form__attachment-viewer-dialog"
|
||||
>
|
||||
<pdf-preview
|
||||
v-if="
|
||||
attachmentDocumentPreviewVisible &&
|
||||
attachmentPreviewFile.url &&
|
||||
attachmentPreviewFile.isPdf
|
||||
"
|
||||
:source="attachmentPreviewFile.url"
|
||||
@error="handleAttachmentPreviewError"
|
||||
/>
|
||||
<open-file-viewer
|
||||
v-if="attachmentDocumentPreviewVisible && attachmentPreviewFile.url"
|
||||
v-else-if="attachmentDocumentPreviewVisible && attachmentPreviewFile.url"
|
||||
:file="attachmentPreviewFile.url"
|
||||
:file-name="attachmentPreviewFile.name"
|
||||
:mime-type="attachmentPreviewFile.mimeType"
|
||||
@@ -748,11 +757,11 @@ import { getToken } from '@/utils/auth';
|
||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||
import { ElImageViewer } from 'element-plus';
|
||||
import { OpenFileViewer } from '@open-file-viewer/vue';
|
||||
import PdfPreview from '@/components/pdf-preview/main.vue';
|
||||
import {
|
||||
fallbackPlugin,
|
||||
imagePlugin,
|
||||
officePlugin,
|
||||
pdfPlugin,
|
||||
textPlugin,
|
||||
} from '@open-file-viewer/core';
|
||||
import '@open-file-viewer/core/style.css';
|
||||
@@ -821,7 +830,6 @@ const changeTypeOptions = [
|
||||
|
||||
const attachmentViewerPlugins = [
|
||||
imagePlugin(),
|
||||
pdfPlugin({ workerSrc: pdfWorkerSrc, useFetchData: true }),
|
||||
officePlugin({ pdf: { workerSrc: pdfWorkerSrc, useFetchData: true } }),
|
||||
textPlugin(),
|
||||
fallbackPlugin(),
|
||||
@@ -854,6 +862,7 @@ export default {
|
||||
components: {
|
||||
ElImageViewer,
|
||||
OpenFileViewer,
|
||||
PdfPreview,
|
||||
},
|
||||
data() {
|
||||
const validateAmount = (rule, value, callback) => {
|
||||
@@ -1982,6 +1991,10 @@ export default {
|
||||
this.attachmentExtension(row)
|
||||
);
|
||||
},
|
||||
isAttachmentPdf(row) {
|
||||
const mimeType = String(row.mimeType || row.contentType || '').toLowerCase();
|
||||
return mimeType.includes('application/pdf') || this.attachmentExtension(row) === 'pdf';
|
||||
},
|
||||
previewAttachment(row) {
|
||||
const url = this.attachmentUrl(row);
|
||||
if (!url) {
|
||||
@@ -1999,10 +2012,12 @@ export default {
|
||||
this.attachmentImagePreviewVisible = true;
|
||||
return;
|
||||
}
|
||||
const isPdf = this.isAttachmentPdf(row);
|
||||
this.attachmentPreviewFile = {
|
||||
name: this.attachmentName(row),
|
||||
url,
|
||||
mimeType: row.mimeType || row.contentType || '',
|
||||
mimeType: isPdf ? 'application/pdf' : row.mimeType || row.contentType || '',
|
||||
isPdf,
|
||||
};
|
||||
this.attachmentDocumentPreviewVisible = true;
|
||||
},
|
||||
|
||||
@@ -703,8 +703,17 @@
|
||||
width="90%"
|
||||
top="4vh"
|
||||
>
|
||||
<pdf-preview
|
||||
v-if="
|
||||
qualificationDocumentPreviewVisible &&
|
||||
qualificationPreviewFile.url &&
|
||||
qualificationPreviewFile.isPdf
|
||||
"
|
||||
:source="qualificationPreviewFile.url"
|
||||
@error="handleQualificationPreviewError"
|
||||
/>
|
||||
<open-file-viewer
|
||||
v-if="qualificationDocumentPreviewVisible && qualificationPreviewFile.url"
|
||||
v-else-if="qualificationDocumentPreviewVisible && qualificationPreviewFile.url"
|
||||
:file="qualificationPreviewFile.url"
|
||||
:file-name="qualificationPreviewFile.name"
|
||||
:mime-type="qualificationPreviewFile.mimeType"
|
||||
@@ -1385,7 +1394,7 @@ import { getDictionary } from '@/api/system/dictbiz';
|
||||
import { getDeptTree } from '@/api/system/dept';
|
||||
import { getLazyTree } from '@/api/base/region';
|
||||
import { exportBlob } from '@/api/common';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import { normalizeSearchRangeParams } from '@/utils/search-range';
|
||||
@@ -1396,7 +1405,6 @@ import {
|
||||
fallbackPlugin,
|
||||
imagePlugin,
|
||||
officePlugin,
|
||||
pdfPlugin,
|
||||
textPlugin,
|
||||
} from '@open-file-viewer/core';
|
||||
import '@open-file-viewer/core/style.css';
|
||||
@@ -1405,6 +1413,7 @@ import { mapGetters } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
import SectionCard from '@/components/section-card/main.vue';
|
||||
import PdfPreview from '@/components/pdf-preview/main.vue';
|
||||
|
||||
const createTimeRangeMap = {
|
||||
createTimeRange: ['createTimeStart', 'createTimeEnd'],
|
||||
@@ -1415,7 +1424,6 @@ const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a';
|
||||
let amapLoader;
|
||||
const qualificationViewerPlugins = [
|
||||
imagePlugin(),
|
||||
pdfPlugin({ workerSrc: pdfWorkerSrc, useFetchData: true }),
|
||||
officePlugin({ pdf: { workerSrc: pdfWorkerSrc, useFetchData: true } }),
|
||||
textPlugin(),
|
||||
fallbackPlugin(),
|
||||
@@ -1428,6 +1436,7 @@ export default {
|
||||
Location,
|
||||
ElImageViewer,
|
||||
OpenFileViewer,
|
||||
PdfPreview,
|
||||
},
|
||||
data() {
|
||||
const nonNegativeLabelMap = {
|
||||
@@ -2427,8 +2436,10 @@ export default {
|
||||
initDeptTree() {
|
||||
getDeptTree(this.userInfo.tenantId)
|
||||
.then(res => {
|
||||
this.deptTree = this.normalizeDeptTree(res.data.data || []);
|
||||
const deptTree = this.excludeExternalOrganization(res.data.data || []);
|
||||
this.deptTree = this.normalizeDeptTree(deptTree);
|
||||
this.deptOptions = this.flattenDept(this.deptTree);
|
||||
this.setDefaultTopLevelDept();
|
||||
const deptColumn = this.findColumn(this.option.column, 'deptName');
|
||||
deptColumn.dicData = [
|
||||
{ label: '全部', value: '' },
|
||||
@@ -2611,6 +2622,17 @@ export default {
|
||||
};
|
||||
});
|
||||
},
|
||||
excludeExternalOrganization(tree = []) {
|
||||
return tree.reduce((result, item) => {
|
||||
const deptName = item.label || item.title || item.deptName || item.name || '';
|
||||
if (String(deptName).trim() === '外部组织') return result;
|
||||
result.push({
|
||||
...item,
|
||||
children: this.excludeExternalOrganization(item.children || []),
|
||||
});
|
||||
return result;
|
||||
}, []);
|
||||
},
|
||||
flattenDept(tree, level = 0) {
|
||||
const result = [];
|
||||
tree.forEach(item => {
|
||||
@@ -2625,6 +2647,18 @@ export default {
|
||||
});
|
||||
return result;
|
||||
},
|
||||
setDefaultTopLevelDept() {
|
||||
const deptIds = Array.isArray(this.archiveForm.deptId)
|
||||
? this.archiveForm.deptId
|
||||
: this.archiveForm.deptId
|
||||
? [this.archiveForm.deptId]
|
||||
: [];
|
||||
const firstTopLevelDept = this.deptTree[0];
|
||||
if (!this.isArchivePage || this.$route.query.id || deptIds.length || !firstTopLevelDept) {
|
||||
return;
|
||||
}
|
||||
this.onDeptChange([firstTopLevelDept.value]);
|
||||
},
|
||||
onDeptChange(value) {
|
||||
const deptIds = Array.isArray(value) ? value : value ? [value] : [];
|
||||
const deptNames = deptIds
|
||||
@@ -3387,6 +3421,12 @@ export default {
|
||||
this.getQualificationFileExtension(file)
|
||||
);
|
||||
},
|
||||
isQualificationPdf(file) {
|
||||
const mimeType = String(file.mimeType || file.contentType || '').toLowerCase();
|
||||
return (
|
||||
mimeType.includes('application/pdf') || this.getQualificationFileExtension(file) === 'pdf'
|
||||
);
|
||||
},
|
||||
previewQualificationFile(file) {
|
||||
const url = this.getQualificationFileUrl(file);
|
||||
if (!url) {
|
||||
@@ -3404,10 +3444,12 @@ export default {
|
||||
this.qualificationImagePreviewVisible = true;
|
||||
return;
|
||||
}
|
||||
const isPdf = this.isQualificationPdf(file);
|
||||
this.qualificationPreviewFile = {
|
||||
name: file.originalName || file.name || '附件',
|
||||
url,
|
||||
mimeType: file.mimeType || file.contentType || '',
|
||||
mimeType: isPdf ? 'application/pdf' : file.mimeType || file.contentType || '',
|
||||
isPdf,
|
||||
};
|
||||
this.qualificationDocumentPreviewVisible = true;
|
||||
},
|
||||
@@ -3457,20 +3499,46 @@ export default {
|
||||
})
|
||||
.map(item => item.file);
|
||||
},
|
||||
getMissingQualificationTypes(files = this.qualificationFiles) {
|
||||
getRequiredQualificationTypes(customerType = this.archiveForm.customerType) {
|
||||
const customerTypes = Array.isArray(customerType)
|
||||
? customerType
|
||||
: this.splitValue(customerType);
|
||||
const requiredTypes = ['营业执照', '法人身份证'];
|
||||
const includesCarrier = customerTypes.some(item =>
|
||||
['承运商', 'carrier'].includes(String(item || '').trim().toLowerCase())
|
||||
);
|
||||
if (includesCarrier) requiredTypes.push('运输许可证');
|
||||
return requiredTypes;
|
||||
},
|
||||
isUploadedQualificationType(uploadedType, requiredType) {
|
||||
const uploaded = String(uploadedType || '')
|
||||
.replace(/\s/g, '')
|
||||
.trim();
|
||||
if (uploaded === requiredType || uploaded.includes(requiredType)) return true;
|
||||
return requiredType === '运输许可证' && /运输.*许可证/.test(uploaded);
|
||||
},
|
||||
getMissingQualificationTypes(
|
||||
files = this.qualificationFiles,
|
||||
customerType = this.archiveForm.customerType
|
||||
) {
|
||||
const uploadedTypes = new Set(
|
||||
(files || [])
|
||||
.filter(item => item.url)
|
||||
.map(item => String(item.type || '').trim())
|
||||
.filter(Boolean)
|
||||
);
|
||||
return this.qualificationTypeOptions
|
||||
.filter(item => String(item.label || item.value || '').trim() !== '其他附件')
|
||||
.filter(item => !uploadedTypes.has(String(item.value || item.label || '').trim()))
|
||||
.map(item => item.label || item.value);
|
||||
return this.getRequiredQualificationTypes(customerType).filter(
|
||||
requiredType =>
|
||||
![...uploadedTypes].some(uploadedType =>
|
||||
this.isUploadedQualificationType(uploadedType, requiredType)
|
||||
)
|
||||
);
|
||||
},
|
||||
validateQualificationMaterials(files = this.qualificationFiles) {
|
||||
const missing = this.getMissingQualificationTypes(files);
|
||||
validateQualificationMaterials(
|
||||
files = this.qualificationFiles,
|
||||
customerType = this.archiveForm.customerType
|
||||
) {
|
||||
const missing = this.getMissingQualificationTypes(files, customerType);
|
||||
if (!missing.length) return true;
|
||||
this.$message.warning(`请先上传客商材料:${missing.join('、')}`);
|
||||
return false;
|
||||
@@ -3486,7 +3554,14 @@ export default {
|
||||
);
|
||||
return;
|
||||
}
|
||||
files.forEach(item => window.open(item.url, '_blank'));
|
||||
files.forEach((item, index) => {
|
||||
window.setTimeout(() => {
|
||||
downloadFileByUrl(
|
||||
item.url,
|
||||
item.originalName || item.name || `客商材料${index + 1}`
|
||||
);
|
||||
}, index * 300);
|
||||
});
|
||||
},
|
||||
handleQualificationSelectionChange(rows) {
|
||||
this.selectedQualificationFiles = rows || [];
|
||||
@@ -3690,7 +3765,8 @@ export default {
|
||||
validateFormalForApproval(archive) {
|
||||
if (
|
||||
!this.validateQualificationMaterials(
|
||||
this.parseAttachments(archive.qualificationAttachments)
|
||||
this.parseAttachments(archive.qualificationAttachments),
|
||||
archive.customerType
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user