✨ 结算单用印类型、合同甲乙丙列表与项目调整材料
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -676,7 +676,7 @@
|
||||
<div class="project-apply-form__material-head">
|
||||
<div class="dialog-section-title project-apply-form__material-title">项目材料</div>
|
||||
<span
|
||||
v-if="missingRequiredAttachmentTypes.length"
|
||||
v-if="!isChangeDialog && missingRequiredAttachmentTypes.length"
|
||||
class="project-apply-form__material-warn"
|
||||
>
|
||||
未上传:{{ missingRequiredAttachmentTypes.join('、') }}
|
||||
@@ -698,7 +698,11 @@
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column label="附件类型" min-width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.fileType" placeholder="请选择" :disabled="dialogReadonly">
|
||||
<el-select
|
||||
v-model="row.fileType"
|
||||
placeholder="请选择"
|
||||
:disabled="dialogReadonly || isChangeDialog"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in projectAttachmentTypeOptions"
|
||||
:key="item.value"
|
||||
@@ -731,7 +735,7 @@
|
||||
<el-input
|
||||
v-model="row.description"
|
||||
placeholder="请输入"
|
||||
:disabled="dialogReadonly"
|
||||
:disabled="dialogReadonly || isChangeDialog"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -741,14 +745,26 @@
|
||||
<el-table-column prop="uploadUserName" label="上传人" min-width="140" align="center" />
|
||||
<el-table-column prop="uploadTime" label="上传时间" min-width="170" align="center" sortable/>
|
||||
<el-table-column label="操作" width="110" align="center">
|
||||
<template #default="{ $index }">
|
||||
<el-link v-if="!dialogReadonly" type="danger" @click="removeAttachment($index)"
|
||||
>删除</el-link
|
||||
<template #default="{ row, $index }">
|
||||
<el-link
|
||||
v-if="isChangeDialog && !dialogReadonly"
|
||||
type="primary"
|
||||
@click="openAdjustAttachmentDialog(row, $index)"
|
||||
>
|
||||
调整
|
||||
</el-link>
|
||||
<el-link
|
||||
v-else-if="!dialogReadonly && !isChangeDialog"
|
||||
type="danger"
|
||||
@click="removeAttachment($index)"
|
||||
>
|
||||
删除
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<vehicle-attachment-upload
|
||||
v-if="!isChangeDialog"
|
||||
v-model="attachmentRows"
|
||||
class="project-apply-form__upload"
|
||||
:readonly="dialogReadonly"
|
||||
@@ -761,6 +777,57 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="isChangeDialog" class="project-apply-form__material-card">
|
||||
<div class="project-apply-form__material-head">
|
||||
<div class="dialog-section-title project-apply-form__material-title">调整材料</div>
|
||||
</div>
|
||||
<el-table :data="adjustAttachmentRows" border class="project-apply-form__material-table">
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column label="原附件" min-width="180" align="center" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ attachmentName(row.originAttachment) || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="附件类型" min-width="160" align="center">
|
||||
<template #default="{ row }">{{ row.fileType || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="文件名"
|
||||
min-width="220"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
class-name="is-ellipsis-link"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span
|
||||
class="attachment-file-name"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click="previewAttachment(row)"
|
||||
@keydown.enter="previewAttachment(row)"
|
||||
@keydown.space.prevent="previewAttachment(row)"
|
||||
>{{ attachmentName(row) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="附件描述" min-width="200" align="center" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.description || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="调整原因" min-width="180" align="center" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.adjustReason || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文件大小" min-width="120" align="center">
|
||||
<template #default="{ row }">{{ formatFileSize(row.size) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="uploadUserName" label="上传人" min-width="140" align="center" />
|
||||
<el-table-column prop="uploadTime" label="上传时间" min-width="170" align="center" />
|
||||
<el-table-column v-if="!dialogReadonly" label="操作" width="110" align="center">
|
||||
<template #default="{ $index }">
|
||||
<el-link type="danger" @click="removeAdjustAttachment($index)">删除</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<template v-if="showProjectContractSection">
|
||||
<div class="dialog-section-title project-apply-form__table-title">项目合同</div>
|
||||
<el-table
|
||||
@@ -1011,6 +1078,86 @@
|
||||
@close="attachmentImagePreviewVisible = false"
|
||||
/>
|
||||
|
||||
<el-dialog
|
||||
v-model="adjustAttachmentBox"
|
||||
title="调整材料"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
width="720px"
|
||||
class="project-apply-adjust-dialog"
|
||||
@closed="resetAdjustAttachmentForm"
|
||||
>
|
||||
<el-form
|
||||
ref="adjustAttachmentFormRef"
|
||||
:model="adjustAttachmentForm"
|
||||
:rules="adjustAttachmentRules"
|
||||
label-position="right"
|
||||
label-width="auto"
|
||||
>
|
||||
<el-form-item label="原附件">
|
||||
<span>{{ attachmentName(adjustAttachmentForm.originAttachment) || '-' }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="附件类型" prop="fileType">
|
||||
<el-select v-model="adjustAttachmentForm.fileType" placeholder="请选择" clearable>
|
||||
<el-option
|
||||
v-for="item in projectAttachmentTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="附件文件" prop="url">
|
||||
<div class="project-apply-adjust-dialog__upload">
|
||||
<span
|
||||
v-if="attachmentName(adjustAttachmentForm)"
|
||||
class="attachment-file-name"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click="previewAttachment(adjustAttachmentForm)"
|
||||
@keydown.enter="previewAttachment(adjustAttachmentForm)"
|
||||
@keydown.space.prevent="previewAttachment(adjustAttachmentForm)"
|
||||
>
|
||||
{{ attachmentName(adjustAttachmentForm) }}
|
||||
</span>
|
||||
<span v-else class="project-apply-adjust-dialog__upload-empty">请上传新材料</span>
|
||||
<vehicle-attachment-upload
|
||||
v-model="adjustAttachmentUploadRows"
|
||||
:readonly="false"
|
||||
:multiple="false"
|
||||
:limit="1"
|
||||
:file-types="attachmentFileTypes"
|
||||
:max-size="50"
|
||||
:show-file-list="false"
|
||||
button-text="上传附件"
|
||||
tip="支持pdf、bmp、jpeg、png、jpg、doc、docx、ppt、pptx、xlsx、xls、eml、msg、zip,单个文件不超过50M"
|
||||
@change="handleAdjustAttachmentUploadChange"
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="附件描述" prop="description">
|
||||
<el-input v-model="adjustAttachmentForm.description" placeholder="请输入" maxlength="200" />
|
||||
</el-form-item>
|
||||
<el-form-item label="文件大小">
|
||||
<span>{{ formatFileSize(adjustAttachmentForm.size) || '-' }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="调整原因" prop="adjustReason" class="project-apply-form__change-textarea">
|
||||
<el-input
|
||||
v-model="adjustAttachmentForm.adjustReason"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="2000"
|
||||
show-word-limit
|
||||
placeholder="请输入调整原因"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="adjustAttachmentBox = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmAdjustAttachment">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="userBox"
|
||||
title="选择用户"
|
||||
@@ -1166,6 +1313,7 @@ const emptyForm = () => ({
|
||||
customerJson: '',
|
||||
carrierJson: '',
|
||||
attachmentsJson: '',
|
||||
adjustAttachmentsJson: '',
|
||||
situationRemark: '',
|
||||
projectIntro: '',
|
||||
profitRemark: '',
|
||||
@@ -1175,6 +1323,24 @@ const emptyForm = () => ({
|
||||
changeReason: '',
|
||||
});
|
||||
|
||||
const emptyAdjustAttachmentForm = () => ({
|
||||
uid: '',
|
||||
fileType: '',
|
||||
originalName: '',
|
||||
name: '',
|
||||
fileName: '',
|
||||
url: '',
|
||||
link: '',
|
||||
fileUrl: '',
|
||||
description: '',
|
||||
size: '',
|
||||
uploadUserName: '',
|
||||
uploadTime: '',
|
||||
adjustReason: '',
|
||||
originAttachment: null,
|
||||
originKey: '',
|
||||
});
|
||||
|
||||
const optionalSentinelFields = [
|
||||
'projectScale',
|
||||
'estimatedProfit',
|
||||
@@ -1449,6 +1615,29 @@ export default {
|
||||
customerRows: [],
|
||||
carrierRows: [],
|
||||
attachmentRows: [],
|
||||
adjustAttachmentRows: [],
|
||||
adjustAttachmentBox: false,
|
||||
adjustAttachmentForm: emptyAdjustAttachmentForm(),
|
||||
adjustAttachmentUploadRows: [],
|
||||
adjustAttachmentRules: {
|
||||
fileType: [{ required: true, message: '请选择附件类型', trigger: 'change' }],
|
||||
url: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (!this.attachmentUrl(this.adjustAttachmentForm)) {
|
||||
callback(new Error('请上传新材料'));
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
adjustReason: [
|
||||
{ required: true, message: '请输入调整原因', trigger: 'blur' },
|
||||
{ max: 2000, message: '调整原因不能超过2000个字符', trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
selectedAttachmentRows: [],
|
||||
attachmentImagePreviewVisible: false,
|
||||
attachmentImagePreviewUrls: [],
|
||||
@@ -2207,6 +2396,9 @@ export default {
|
||||
this.customerRows = [];
|
||||
this.carrierRows = [];
|
||||
this.attachmentRows = [];
|
||||
this.adjustAttachmentRows = [];
|
||||
this.adjustAttachmentBox = false;
|
||||
this.resetAdjustAttachmentForm();
|
||||
this.selectedAttachmentRows = [];
|
||||
this.changeRows = [];
|
||||
this.projectContractRows = [];
|
||||
@@ -2248,6 +2440,7 @@ export default {
|
||||
this.carrierRows = carrierRows;
|
||||
this.attachmentRows = this.parseJsonArray(displayRow.attachmentsJson);
|
||||
this.normalizeAttachmentFileTypes();
|
||||
this.adjustAttachmentRows = this.parseJsonArray(displayRow.adjustAttachmentsJson);
|
||||
this.selectedAttachmentRows = [];
|
||||
this.changeRows = this.buildChangeRows(displayRow);
|
||||
this.selectedCustomerId = this.customerRows
|
||||
@@ -2556,6 +2749,9 @@ export default {
|
||||
customerJson: JSON.stringify(this.customerRows),
|
||||
carrierJson: JSON.stringify(this.carrierRows),
|
||||
attachmentsJson: JSON.stringify(this.attachmentRows),
|
||||
adjustAttachmentsJson: this.isChangeDialog
|
||||
? JSON.stringify(this.adjustAttachmentRows || [])
|
||||
: undefined,
|
||||
situationRemark: JSON.stringify({
|
||||
projectIntro: this.form.projectIntro || '',
|
||||
profitRemark: this.form.profitRemark || '',
|
||||
@@ -2571,6 +2767,9 @@ export default {
|
||||
if (this.isNewProjectDialog && !options.includeChangeType) {
|
||||
delete submitRow.changeReason;
|
||||
}
|
||||
if (!this.isChangeDialog) {
|
||||
delete submitRow.adjustAttachmentsJson;
|
||||
}
|
||||
['projectIntro', 'profitRemark', 'riskPoint', 'emergencyPlan'].forEach(
|
||||
key => delete submitRow[key]
|
||||
);
|
||||
@@ -3191,6 +3390,112 @@ export default {
|
||||
removeAttachment(index) {
|
||||
this.attachmentRows.splice(index, 1);
|
||||
},
|
||||
attachmentIdentity(row = {}) {
|
||||
const uid = String(row.uid || '').trim();
|
||||
if (uid) return `uid:${uid}`;
|
||||
const url = String(this.attachmentUrl(row) || '').trim();
|
||||
if (url) return `url:${url}`;
|
||||
const name = String(this.attachmentName(row) || '').trim();
|
||||
const fileType = String(row.fileType || '').trim();
|
||||
if (name || fileType) return `name:${fileType}|${name}`;
|
||||
return '';
|
||||
},
|
||||
openAdjustAttachmentDialog(row) {
|
||||
const originKey = this.attachmentIdentity(row);
|
||||
const existing = this.adjustAttachmentRows.find(item => item.originKey === originKey);
|
||||
if (existing) {
|
||||
this.adjustAttachmentForm = {
|
||||
...emptyAdjustAttachmentForm(),
|
||||
...existing,
|
||||
originAttachment: existing.originAttachment || { ...row },
|
||||
originKey,
|
||||
};
|
||||
this.adjustAttachmentUploadRows = this.attachmentUrl(existing)
|
||||
? [{ ...existing }]
|
||||
: [];
|
||||
} else {
|
||||
this.adjustAttachmentForm = {
|
||||
...emptyAdjustAttachmentForm(),
|
||||
fileType: row.fileType || '',
|
||||
description: row.description || '',
|
||||
originAttachment: { ...row },
|
||||
originKey,
|
||||
};
|
||||
this.adjustAttachmentUploadRows = [];
|
||||
}
|
||||
this.adjustAttachmentBox = true;
|
||||
this.$nextTick(() => this.$refs.adjustAttachmentFormRef?.clearValidate?.());
|
||||
},
|
||||
resetAdjustAttachmentForm() {
|
||||
this.adjustAttachmentForm = emptyAdjustAttachmentForm();
|
||||
this.adjustAttachmentUploadRows = [];
|
||||
this.$refs.adjustAttachmentFormRef?.clearValidate?.();
|
||||
},
|
||||
handleAdjustAttachmentUploadChange(list) {
|
||||
const latest = Array.isArray(list) && list.length ? list[list.length - 1] : null;
|
||||
if (!latest) {
|
||||
this.adjustAttachmentForm = {
|
||||
...this.adjustAttachmentForm,
|
||||
uid: '',
|
||||
originalName: '',
|
||||
name: '',
|
||||
fileName: '',
|
||||
url: '',
|
||||
link: '',
|
||||
fileUrl: '',
|
||||
size: '',
|
||||
uploadUserName: '',
|
||||
uploadTime: '',
|
||||
};
|
||||
this.adjustAttachmentUploadRows = [];
|
||||
return;
|
||||
}
|
||||
const userName = this.userInfo?.realName || this.userInfo?.userName || '';
|
||||
const uploadTime = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
this.adjustAttachmentForm = {
|
||||
...this.adjustAttachmentForm,
|
||||
...latest,
|
||||
fileType:
|
||||
this.adjustAttachmentForm.fileType || this.resolveAttachmentFileType(latest),
|
||||
description: this.adjustAttachmentForm.description || latest.description || '',
|
||||
uploadUserName: latest.uploadUserName || userName,
|
||||
uploadTime: latest.uploadTime || uploadTime,
|
||||
};
|
||||
this.adjustAttachmentUploadRows = [{ ...latest }];
|
||||
this.$refs.adjustAttachmentFormRef?.validateField?.('url');
|
||||
},
|
||||
confirmAdjustAttachment() {
|
||||
this.$refs.adjustAttachmentFormRef?.validate(valid => {
|
||||
if (!valid) return;
|
||||
if (!this.attachmentUrl(this.adjustAttachmentForm)) {
|
||||
this.$message.warning('请上传新材料');
|
||||
return;
|
||||
}
|
||||
const nextRow = {
|
||||
...this.adjustAttachmentForm,
|
||||
fileType: this.adjustAttachmentForm.fileType,
|
||||
description: this.adjustAttachmentForm.description || '',
|
||||
adjustReason: String(this.adjustAttachmentForm.adjustReason || '').trim(),
|
||||
originAttachment: this.adjustAttachmentForm.originAttachment
|
||||
? { ...this.adjustAttachmentForm.originAttachment }
|
||||
: null,
|
||||
originKey: this.adjustAttachmentForm.originKey,
|
||||
};
|
||||
const index = this.adjustAttachmentRows.findIndex(
|
||||
item => item.originKey === nextRow.originKey
|
||||
);
|
||||
if (index >= 0) {
|
||||
this.adjustAttachmentRows.splice(index, 1, nextRow);
|
||||
} else {
|
||||
this.adjustAttachmentRows.push(nextRow);
|
||||
}
|
||||
this.adjustAttachmentBox = false;
|
||||
this.$message.success('已加入调整材料');
|
||||
});
|
||||
},
|
||||
removeAdjustAttachment(index) {
|
||||
this.adjustAttachmentRows.splice(index, 1);
|
||||
},
|
||||
formatFileSize(size) {
|
||||
const number = Number(size);
|
||||
if (!number) return '';
|
||||
@@ -3708,6 +4013,24 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.project-apply-adjust-dialog {
|
||||
&__upload {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__upload-empty {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
:deep(.el-select),
|
||||
:deep(.el-input) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.project-apply-form {
|
||||
&__grid {
|
||||
|
||||
Reference in New Issue
Block a user