🎨 异常跟进修排版并支持上传附件
跟进弹窗按编辑弹窗的排法改造:section-card 分组 + el-row/el-col 栅格, 依次为异常信息、现场照片、跟进、历史跟进。 新增跟进附件上传(v-model 走 vehicle-attachment-upload), 历史跟进表补附件列。跟进说明与附件至少填其一,二者都为空时前端拦下, 与后端校验一致。
This commit is contained in:
@@ -283,68 +283,103 @@
|
||||
</el-form>
|
||||
|
||||
<template v-else>
|
||||
<div class="dialog-section-title">异常信息</div>
|
||||
<dl class="exception-disposal-page__detail-grid">
|
||||
<template v-for="field in detailFields" :key="field.prop">
|
||||
<div :class="{ 'is-wide': field.span === 2 }">
|
||||
<dt>{{ field.label }}</dt>
|
||||
<dd>
|
||||
<el-link v-if="field.link && detail[field.prop]" type="primary">
|
||||
{{ detail[field.prop] }}
|
||||
</el-link>
|
||||
<span v-else>{{ detail[field.prop] || '-' }}</span>
|
||||
</dd>
|
||||
</div>
|
||||
</template>
|
||||
</dl>
|
||||
<section-card title="异常信息">
|
||||
<dl class="exception-disposal-page__detail-grid">
|
||||
<template v-for="field in detailFields" :key="field.prop">
|
||||
<div :class="{ 'is-wide': field.span === 2 }">
|
||||
<dt>{{ field.label }}</dt>
|
||||
<dd>
|
||||
<el-link v-if="field.link && detail[field.prop]" type="primary">
|
||||
{{ detail[field.prop] }}
|
||||
</el-link>
|
||||
<span v-else>{{ detail[field.prop] || '-' }}</span>
|
||||
</dd>
|
||||
</div>
|
||||
</template>
|
||||
</dl>
|
||||
</section-card>
|
||||
|
||||
<div class="dialog-section-title">现场照片</div>
|
||||
<div class="exception-disposal-page__photos">
|
||||
<el-image
|
||||
v-for="(url, index) in photoUrls"
|
||||
:key="url"
|
||||
:src="url"
|
||||
:preview-src-list="photoUrls"
|
||||
:initial-index="index"
|
||||
fit="cover"
|
||||
/>
|
||||
<el-empty v-if="!photoUrls.length" description="暂无现场照片" :image-size="56" />
|
||||
</div>
|
||||
|
||||
<el-form
|
||||
v-if="dialog.mode === 'follow'"
|
||||
ref="followFormRef"
|
||||
:model="followForm"
|
||||
:rules="followRules"
|
||||
label-position="right"
|
||||
label-width="auto"
|
||||
class="exception-disposal-page__follow-form"
|
||||
>
|
||||
<el-form-item label="跟进说明" prop="followContent">
|
||||
<el-input
|
||||
v-model="followForm.followContent"
|
||||
type="textarea"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
:rows="2"
|
||||
placeholder="请输入"
|
||||
<section-card title="现场照片">
|
||||
<div class="exception-disposal-page__photos">
|
||||
<el-image
|
||||
v-for="(url, index) in photoUrls"
|
||||
:key="url"
|
||||
:src="url"
|
||||
:preview-src-list="photoUrls"
|
||||
:initial-index="index"
|
||||
fit="cover"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-empty v-if="!photoUrls.length" description="暂无现场照片" :image-size="56" />
|
||||
</div>
|
||||
</section-card>
|
||||
|
||||
<div class="dialog-section-title">历史跟进</div>
|
||||
<el-table :data="detail.followRecords || []" border>
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column
|
||||
v-for="column in followColumns"
|
||||
:key="column.prop"
|
||||
:prop="column.prop"
|
||||
:label="column.label"
|
||||
:min-width="column.minWidth"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
</el-table>
|
||||
<section-card v-if="dialog.mode === 'follow'" title="跟进">
|
||||
<el-form
|
||||
ref="followFormRef"
|
||||
:model="followForm"
|
||||
:rules="followRules"
|
||||
label-position="right"
|
||||
label-width="96px"
|
||||
>
|
||||
<el-row :gutter="18">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="跟进说明" prop="followContent">
|
||||
<el-input
|
||||
v-model="followForm.followContent"
|
||||
type="textarea"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
:rows="3"
|
||||
placeholder="请输入"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="跟进附件">
|
||||
<vehicle-attachment-upload
|
||||
v-model="followForm.attachments"
|
||||
:limit="20"
|
||||
:max-size="500"
|
||||
button-text="上传附件"
|
||||
:show-tip="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</section-card>
|
||||
|
||||
<section-card title="历史跟进">
|
||||
<el-table :data="detail.followRecords || []" border>
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column
|
||||
v-for="column in followColumns"
|
||||
:key="column.prop"
|
||||
:prop="column.prop"
|
||||
:label="column.label"
|
||||
:min-width="column.minWidth"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="附件" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<template v-if="parseAttachments(row.attachmentsJson).length">
|
||||
<el-link
|
||||
v-for="(file, index) in parseAttachments(row.attachmentsJson)"
|
||||
:key="index"
|
||||
type="primary"
|
||||
class="exception-disposal-page__attachment-link"
|
||||
:href="file.url"
|
||||
target="_blank"
|
||||
>
|
||||
{{ file.name || '附件' + (index + 1) }}
|
||||
</el-link>
|
||||
</template>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section-card>
|
||||
</template>
|
||||
</div>
|
||||
<template #footer>
|
||||
@@ -417,12 +452,9 @@ export default {
|
||||
page: { current: 1, size: 10, total: 0 },
|
||||
dialog: { visible: false, mode: 'follow', loading: false, submitting: false },
|
||||
detail: {},
|
||||
followForm: { followContent: '' },
|
||||
followForm: { followContent: '', attachments: [] },
|
||||
followRules: {
|
||||
followContent: [
|
||||
{ required: true, message: '请输入跟进说明', trigger: 'blur' },
|
||||
{ max: 500, message: '跟进说明不能超过500个字符', trigger: 'blur' },
|
||||
],
|
||||
followContent: [{ max: 500, message: '跟进说明不能超过500个字符', trigger: 'blur' }],
|
||||
},
|
||||
editForm: {
|
||||
exceptionType: '',
|
||||
@@ -503,7 +535,7 @@ export default {
|
||||
},
|
||||
async openDisposal(row, mode) {
|
||||
this.dialog = { visible: true, mode, loading: true, submitting: false };
|
||||
this.followForm = { followContent: '' };
|
||||
this.followForm = { followContent: '', attachments: [] };
|
||||
try {
|
||||
const res = await api.getDetail(row.id);
|
||||
this.detail = this.decorateRow(res.data?.data || res.data || res || {});
|
||||
@@ -582,9 +614,18 @@ export default {
|
||||
},
|
||||
async submitFollow() {
|
||||
await this.$refs.followFormRef.validate();
|
||||
const followContent = (this.followForm.followContent || '').trim();
|
||||
const attachmentsJson = this.followForm.attachments.length
|
||||
? JSON.stringify(this.followForm.attachments)
|
||||
: '';
|
||||
// 后端要求二者至少有其一
|
||||
if (!followContent && !attachmentsJson) {
|
||||
this.$message.warning('请填写跟进说明或上传附件');
|
||||
return;
|
||||
}
|
||||
this.dialog.submitting = true;
|
||||
try {
|
||||
await api.follow({ id: this.detail.id, followContent: this.followForm.followContent });
|
||||
await api.follow({ id: this.detail.id, followContent, attachmentsJson });
|
||||
this.$message.success('跟进成功');
|
||||
this.dialog.visible = false;
|
||||
this.loadTable();
|
||||
@@ -592,6 +633,16 @@ export default {
|
||||
this.dialog.submitting = false;
|
||||
}
|
||||
},
|
||||
parseAttachments(value) {
|
||||
if (!value) return [];
|
||||
if (Array.isArray(value)) return value;
|
||||
try {
|
||||
const parsed = JSON.parse(value);
|
||||
return Array.isArray(parsed) ? parsed.filter(item => item && item.url) : [];
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
async completeRow(row) {
|
||||
await this.$confirm('确认完成该异常处置?', '提示', { type: 'warning' });
|
||||
await api.complete({ id: row.id });
|
||||
@@ -751,12 +802,9 @@ export default {
|
||||
padding: 4px 0 0;
|
||||
}
|
||||
|
||||
.dialog-section-title {
|
||||
margin: 12px 0;
|
||||
padding-left: 12px;
|
||||
border-left: 4px solid #409eff;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
.exception-disposal-page__attachment-link {
|
||||
display: block;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.exception-disposal-page__detail-grid {
|
||||
@@ -799,10 +847,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.exception-disposal-page__follow-form {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.exception-disposal-page__dialog :deep(.section-card + .section-card) {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user