完成基础信息页面开发
This commit is contained in:
@@ -1,453 +1,481 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="履约验收"
|
||||
width="75%"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
class="purchasing-accept-modal"
|
||||
@close="handleClose"
|
||||
>
|
||||
<div v-loading="loading" class="modal-body" :key="String(purchaseId)">
|
||||
<div class="main-tabs">
|
||||
<div class="main-tab-nav">
|
||||
<div class="main-tab-item" :class="{ active: mainTab === 'common' }" @click="mainTab = 'common'">公共信息</div>
|
||||
<div class="main-tab-item" :class="{ active: mainTab === 'batch' }" @click="mainTab = 'batch'">
|
||||
{{ commonForm?.isInstallment === '0' ? '验收' : '分期验收'
|
||||
}}{{ commonForm?.isInstallment !== '0' && batches.length > 0 ? ` (${batches.length})` : '' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-tab-content">
|
||||
<div v-show="mainTab === 'common'" class="tab-content">
|
||||
<AcceptCommonForm
|
||||
:key="`${purchaseId}-${openToken}`"
|
||||
:reset-key="openToken"
|
||||
ref="commonFormRef"
|
||||
v-model="commonForm"
|
||||
:purchase-id="purchaseId"
|
||||
:project-name="applyInfo?.projectName"
|
||||
:dept-name="applyInfo?.deptName"
|
||||
/>
|
||||
</div>
|
||||
<div v-show="mainTab === 'batch'" class="tab-content">
|
||||
<div v-if="batches.length > 0">
|
||||
<div v-show="commonForm?.isInstallment !== '0'" class="batch-tabs">
|
||||
<div
|
||||
v-for="b in batches"
|
||||
:key="b.id"
|
||||
class="batch-tab-item"
|
||||
:class="{ active: String(b.batch) === activeTab, disabled: !canEditBatch(b.batch) }"
|
||||
@click="canEditBatch(b.batch) && (activeTab = String(b.batch))"
|
||||
>
|
||||
<span>第{{ b.batch }}期</span>
|
||||
<el-tag v-if="isBatchCompleted(b)" type="success" size="small">已填</el-tag>
|
||||
<el-tag v-else-if="!canEditBatch(b.batch)" type="info" size="small">需先完成上一期</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="batch-panel">
|
||||
<AcceptBatchForm
|
||||
v-for="b in batches"
|
||||
v-show="String(b.batch) === activeTab"
|
||||
:key="b.id"
|
||||
:ref="(el) => setBatchFormRef(b.batch, el)"
|
||||
:model-value="batchForms[b.batch]"
|
||||
:readonly="false"
|
||||
:purchase-id="String(purchaseId)"
|
||||
:project-type="acceptProjectType"
|
||||
:budget="applyInfo?.budget"
|
||||
:batch-num="b.batch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="tip-box">
|
||||
<el-alert type="info" :closable="false" show-icon>
|
||||
请先在「公共信息」中填写并点击「保存公共配置」,系统将按分期次数自动生成验收批次
|
||||
</el-alert>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="履约验收"
|
||||
width="75%"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
class="purchasing-accept-modal"
|
||||
@close="handleClose"
|
||||
>
|
||||
<div v-loading="loading" class="modal-body" :key="String(purchaseId)">
|
||||
<div class="main-tabs">
|
||||
<div class="main-tab-nav">
|
||||
<div
|
||||
class="main-tab-item"
|
||||
:class="{ active: mainTab === 'common' }"
|
||||
@click="mainTab = 'common'"
|
||||
>
|
||||
公共信息
|
||||
</div>
|
||||
<div
|
||||
class="main-tab-item"
|
||||
:class="{ active: mainTab === 'batch' }"
|
||||
@click="mainTab = 'batch'"
|
||||
>
|
||||
{{ commonForm?.isInstallment === '0' ? '验收' : '分期验收' }}{{ commonForm?.isInstallment !== '0' && batches.length > 0 ? ` (${batches.length})` : '' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-tab-content">
|
||||
<div v-show="mainTab === 'common'" class="tab-content">
|
||||
<AcceptCommonForm
|
||||
:key="`${purchaseId}-${openToken}`"
|
||||
:reset-key="openToken"
|
||||
ref="commonFormRef"
|
||||
v-model="commonForm"
|
||||
:purchase-id="purchaseId"
|
||||
:project-name="applyInfo?.projectName"
|
||||
:dept-name="applyInfo?.deptName"
|
||||
/>
|
||||
</div>
|
||||
<div v-show="mainTab === 'batch'" class="tab-content">
|
||||
<div v-if="batches.length > 0">
|
||||
<div v-show="commonForm?.isInstallment !== '0'" class="batch-tabs">
|
||||
<div
|
||||
v-for="b in batches"
|
||||
:key="b.id"
|
||||
class="batch-tab-item"
|
||||
:class="{ active: String(b.batch) === activeTab, disabled: !canEditBatch(b.batch) }"
|
||||
@click="canEditBatch(b.batch) && (activeTab = String(b.batch))"
|
||||
>
|
||||
<span>第{{ b.batch }}期</span>
|
||||
<el-tag v-if="isBatchCompleted(b)" type="success" size="small">已填</el-tag>
|
||||
<el-tag v-else-if="!canEditBatch(b.batch)" type="info" size="small">需先完成上一期</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="batch-panel">
|
||||
<AcceptBatchForm
|
||||
v-for="b in batches"
|
||||
v-show="String(b.batch) === activeTab"
|
||||
:key="b.id"
|
||||
:ref="(el) => setBatchFormRef(b.batch, el)"
|
||||
:model-value="batchForms[b.batch]"
|
||||
:readonly="false"
|
||||
:purchase-id="String(purchaseId)"
|
||||
:project-type="acceptProjectType"
|
||||
:budget="applyInfo?.budget"
|
||||
:batch-num="b.batch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="tip-box">
|
||||
<el-alert type="info" :closable="false" show-icon>
|
||||
请先在「公共信息」中填写并点击「保存公共配置」,系统将按分期次数自动生成验收批次
|
||||
</el-alert>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button @click="handleClose">关 闭</el-button>
|
||||
<el-button v-if="mainTab === 'common' || batches.length === 0" type="primary" @click="saveCommonConfig" :loading="saving">
|
||||
保存公共配置
|
||||
</el-button>
|
||||
<el-button v-else-if="mainTab === 'batch' && activeBatchId" type="primary" @click="saveCurrentBatch" :loading="saving">
|
||||
保存第{{ activeTab }}期
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button @click="handleClose">关 闭</el-button>
|
||||
<el-button
|
||||
v-if="mainTab === 'common' || batches.length === 0"
|
||||
type="primary"
|
||||
@click="saveCommonConfig"
|
||||
:loading="saving"
|
||||
>
|
||||
保存公共配置
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else-if="mainTab === 'batch' && activeBatchId"
|
||||
type="primary"
|
||||
@click="saveCurrentBatch"
|
||||
:loading="saving"
|
||||
>
|
||||
保存第{{ activeTab }}期
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, nextTick } from 'vue';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { saveCommonConfig as apiSaveCommonConfig, getCommonConfigWithBatches, updateBatch, getDetail } from '/@/api/purchase/purchasingAccept';
|
||||
import AcceptCommonForm from './AcceptCommonForm.vue';
|
||||
import AcceptBatchForm from './AcceptBatchForm.vue';
|
||||
import { ref, reactive, computed, nextTick } from 'vue'
|
||||
import { useMessage } from '/@/hooks/message'
|
||||
import {
|
||||
saveCommonConfig as apiSaveCommonConfig,
|
||||
getCommonConfigWithBatches,
|
||||
updateBatch,
|
||||
getDetail,
|
||||
} from '/@/api/purchase/purchasingAccept'
|
||||
import AcceptCommonForm from './AcceptCommonForm.vue'
|
||||
import AcceptBatchForm from './AcceptBatchForm.vue'
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
const purchaseId = ref<string | number>('');
|
||||
const applyInfo = ref<any>(null);
|
||||
const rowProjectType = ref<string>('A');
|
||||
const batches = ref<any[]>([]);
|
||||
const mainTab = ref('common');
|
||||
const activeTab = ref('1');
|
||||
const commonFormRef = ref();
|
||||
const batchFormRefMap = ref<Record<number, any>>({});
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const purchaseId = ref<string | number>('')
|
||||
const applyInfo = ref<any>(null)
|
||||
const rowProjectType = ref<string>('A')
|
||||
const batches = ref<any[]>([])
|
||||
const mainTab = ref('common')
|
||||
const activeTab = ref('1')
|
||||
const commonFormRef = ref()
|
||||
const batchFormRefMap = ref<Record<number, any>>({})
|
||||
/** 使用 ref 并在每次打开时替换整个对象,确保子组件能感知引用变化并清空 */
|
||||
const commonForm = ref<Record<string, any>>({});
|
||||
const commonForm = ref<Record<string, any>>({})
|
||||
/** 每次打开自增,用于强制 AcceptCommonForm 重新挂载,确保公共信息彻底清空 */
|
||||
const openToken = ref(0);
|
||||
const batchForms = reactive<Record<number, any>>({});
|
||||
const openToken = ref(0)
|
||||
const batchForms = reactive<Record<number, any>>({})
|
||||
/** 记录哪些期已保存到服务器,用于控制”下一期可填”:只有上一期已保存才允许填下一期 */
|
||||
const batchSavedFlags = ref<Record<number, boolean>>({});
|
||||
const batchSavedFlags = ref<Record<number, boolean>>({})
|
||||
|
||||
const setBatchFormRef = (batch: number, el: any) => {
|
||||
if (el) batchFormRefMap.value[batch] = el;
|
||||
};
|
||||
if (el) batchFormRefMap.value[batch] = el
|
||||
}
|
||||
|
||||
const activeBatchId = computed(() => {
|
||||
const b = batches.value.find((x: any) => String(x.batch) === activeTab.value);
|
||||
return b?.id || '';
|
||||
});
|
||||
const b = batches.value.find((x: any) => String(x.batch) === activeTab.value)
|
||||
return b?.id || ''
|
||||
})
|
||||
|
||||
/** 项目类型 A:货物 B:工程 C:服务,用于批次表单模版下载 */
|
||||
const acceptProjectType = computed(() => applyInfo.value?.projectType || rowProjectType.value || 'A');
|
||||
const acceptProjectType = computed(() => applyInfo.value?.projectType || rowProjectType.value || 'A')
|
||||
|
||||
/** 是否允许编辑该期:第 1 期始终可编辑;第 N 期仅当第 1~N-1 期均已保存后才可编辑 */
|
||||
const canEditBatch = (batch: number) => {
|
||||
if (batch === 1) return true;
|
||||
for (let i = 1; i < batch; i++) {
|
||||
if (!batchSavedFlags.value[i]) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if (batch === 1) return true
|
||||
for (let i = 1; i < batch; i++) {
|
||||
if (!batchSavedFlags.value[i]) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/** 该期是否已保存(用于 tab 上显示“已填”标签) */
|
||||
const isBatchCompleted = (b: any) => {
|
||||
return !!batchSavedFlags.value[b.batch];
|
||||
};
|
||||
return !!batchSavedFlags.value[b.batch]
|
||||
}
|
||||
|
||||
const isBatchCompletedByIdx = (batch: number) => {
|
||||
return !!batchSavedFlags.value[batch];
|
||||
};
|
||||
return !!batchSavedFlags.value[batch]
|
||||
}
|
||||
|
||||
const loadData = async () => {
|
||||
if (!purchaseId.value) return;
|
||||
const currentId = String(purchaseId.value);
|
||||
loading.value = true;
|
||||
try {
|
||||
const configRes = await getCommonConfigWithBatches(currentId);
|
||||
if (String(purchaseId.value) !== currentId) return;
|
||||
if (!purchaseId.value) return
|
||||
const currentId = String(purchaseId.value)
|
||||
loading.value = true
|
||||
try {
|
||||
const configRes = await getCommonConfigWithBatches(currentId)
|
||||
// 防止快速切换:若已打开其他申请单,忽略本次结果
|
||||
if (String(purchaseId.value) !== currentId) return
|
||||
|
||||
const config = configRes?.data;
|
||||
const config = configRes?.data
|
||||
|
||||
if (config?.common) {
|
||||
applyInfo.value = config.common;
|
||||
commonForm.value.purchaserId = config.common.purchaserId || '';
|
||||
commonForm.value.purchaserName = config.common.purchaserName || '';
|
||||
commonForm.value.assetAdminId = config.common.assetAdminId || '';
|
||||
commonForm.value.assetAdminName = config.common.assetAdminName || '';
|
||||
commonForm.value.hasContract = config.common.hasContract || '0';
|
||||
commonForm.value.contractId = config.common.contractId || '';
|
||||
commonForm.value.contractName = config.common.contractName || '';
|
||||
commonForm.value.contractNo = config.common.contractNo || '';
|
||||
commonForm.value.contractMoney = config.common.contractMoney || null;
|
||||
commonForm.value.contractFlowStatus = config.common.contractFlowStatus || '';
|
||||
commonForm.value.supplierName = config.common.supplierName || '';
|
||||
commonForm.value.isInstallment = config.common.isInstallment || '0';
|
||||
commonForm.value.totalPhases = config.common.totalPhases || 1;
|
||||
commonForm.value.transactionAmount = config.common.transactionAmount || null;
|
||||
}
|
||||
if (config?.common) {
|
||||
applyInfo.value = config.common
|
||||
// 采购人员和资产管理员始终回填
|
||||
commonForm.value.purchaserId = config.common.purchaserId || ''
|
||||
commonForm.value.purchaserName = config.common.purchaserName || ''
|
||||
commonForm.value.assetAdminId = config.common.assetAdminId || ''
|
||||
commonForm.value.assetAdminName = config.common.assetAdminName || ''
|
||||
|
||||
// 其他字段仅当存在已保存批次时回填
|
||||
if (config?.batches?.length) {
|
||||
Object.assign(commonForm.value, {
|
||||
hasContract: config.common.hasContract || '0',
|
||||
contractId: config.common.contractId || '',
|
||||
isInstallment: config.common.isInstallment || '0',
|
||||
totalPhases: config.common.totalPhases || 1,
|
||||
supplierName: config.common.supplierName || '',
|
||||
supplierContact: config.common.supplierContact || '',
|
||||
transactionAmount: config.common.transactionAmount || null,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (config?.batches?.length) {
|
||||
batches.value = config.batches.sort((a: any, b: any) => (a.batch || 0) - (b.batch || 0));
|
||||
activeTab.value = String(batches.value[0]?.batch || '1');
|
||||
mainTab.value = 'batch';
|
||||
for (const b of batches.value) {
|
||||
if (!batchForms[b.batch]) batchForms[b.batch] = {};
|
||||
}
|
||||
await loadBatchDetails();
|
||||
if (String(purchaseId.value) !== currentId) return;
|
||||
} else {
|
||||
batches.value = [];
|
||||
}
|
||||
} catch (e: any) {
|
||||
useMessage().error(e?.msg || '加载失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
if (config?.batches?.length) {
|
||||
batches.value = config.batches.sort((a: any, b: any) => (a.batch || 0) - (b.batch || 0))
|
||||
activeTab.value = String(batches.value[0]?.batch || '1')
|
||||
mainTab.value = 'batch'
|
||||
for (const b of batches.value) {
|
||||
if (!batchForms[b.batch]) batchForms[b.batch] = {}
|
||||
}
|
||||
await loadBatchDetails()
|
||||
if (String(purchaseId.value) !== currentId) return
|
||||
} else {
|
||||
batches.value = []
|
||||
}
|
||||
} catch (e: any) {
|
||||
useMessage().error(e?.msg || '加载失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const loadBatchDetails = async () => {
|
||||
for (const b of batches.value) {
|
||||
batchSavedFlags.value[b.batch] = false;
|
||||
}
|
||||
for (const b of batches.value) {
|
||||
try {
|
||||
const res = await getDetail(String(purchaseId.value), b.batch);
|
||||
const d = res?.data;
|
||||
if (d?.accept) {
|
||||
// 仅当该期在服务端有验收日期时才视为已保存
|
||||
const hasSaved = !!d.accept.acceptDate;
|
||||
batchSavedFlags.value[b.batch] = hasSaved;
|
||||
// 优先使用 templateFiles(包含id和fileTitle),否则降级使用 templateFileIds
|
||||
let fileIdsStr = '';
|
||||
if (d.accept.templateFiles && d.accept.templateFiles.length > 0) {
|
||||
// 使用 templateFiles,格式为 {id: string, fileTitle: string}[]
|
||||
fileIdsStr = d.accept.templateFiles.map((f: any) => f.id).join(',');
|
||||
} else if (d.accept.templateFileIds) {
|
||||
// 降级使用 templateFileIds
|
||||
const fileIds = d.accept.templateFileIds;
|
||||
fileIdsStr = Array.isArray(fileIds) ? fileIds.join(',') : fileIds || '';
|
||||
}
|
||||
batchForms[b.batch] = {
|
||||
acceptType: '2', // 固定为上传模式
|
||||
acceptDate: d.accept.acceptDate || '',
|
||||
remark: d.accept.remark || '',
|
||||
templateFileIds: fileIdsStr,
|
||||
// 保存文件信息用于显示
|
||||
_templateFiles: d.accept.templateFiles || [],
|
||||
};
|
||||
// 通知子组件初始化数据
|
||||
await nextTick();
|
||||
const batchFormRef = batchFormRefMap.value[b.batch];
|
||||
if (batchFormRef?.initData) {
|
||||
batchFormRef.initData();
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
};
|
||||
for (const b of batches.value) {
|
||||
batchSavedFlags.value[b.batch] = false
|
||||
}
|
||||
for (const b of batches.value) {
|
||||
try {
|
||||
const res = await getDetail(String(purchaseId.value), b.batch)
|
||||
const d = res?.data
|
||||
if (d?.accept) {
|
||||
// 仅当该期在服务端有验收日期时才视为已保存
|
||||
const hasSaved = !!d.accept.acceptDate
|
||||
batchSavedFlags.value[b.batch] = hasSaved
|
||||
// 优先使用 templateFiles(包含id和fileTitle),否则降级使用 templateFileIds
|
||||
let fileIdsStr = ''
|
||||
if (d.accept.templateFiles && d.accept.templateFiles.length > 0) {
|
||||
// 使用 templateFiles,格式为 {id: string, fileTitle: string}[]
|
||||
fileIdsStr = d.accept.templateFiles.map((f: any) => f.id).join(',')
|
||||
} else if (d.accept.templateFileIds) {
|
||||
// 降级使用 templateFileIds
|
||||
const fileIds = d.accept.templateFileIds
|
||||
fileIdsStr = Array.isArray(fileIds) ? fileIds.join(',') : (fileIds || '')
|
||||
}
|
||||
batchForms[b.batch] = {
|
||||
acceptType: '2', // 固定为上传模式
|
||||
acceptDate: d.accept.acceptDate || '',
|
||||
remark: d.accept.remark || '',
|
||||
templateFileIds: fileIdsStr,
|
||||
// 保存文件信息用于显示
|
||||
_templateFiles: d.accept.templateFiles || [],
|
||||
}
|
||||
// 通知子组件初始化数据
|
||||
await nextTick()
|
||||
const batchFormRef = batchFormRefMap.value[b.batch]
|
||||
if (batchFormRef?.initData) {
|
||||
batchFormRef.initData()
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
const saveCommonConfig = async () => {
|
||||
const formRef = commonFormRef.value;
|
||||
const valid = await formRef?.validate?.().catch(() => false);
|
||||
if (!valid) return;
|
||||
const form = formRef?.form || commonForm.value;
|
||||
const isInstallment = form.isInstallment === '1' || form.isInstallment === 1;
|
||||
if (isInstallment && (!form.totalPhases || form.totalPhases < 1)) {
|
||||
useMessage().error('请填写分期次数');
|
||||
return;
|
||||
}
|
||||
saving.value = true;
|
||||
try {
|
||||
await apiSaveCommonConfig({
|
||||
purchaseId: String(purchaseId.value),
|
||||
isInstallment: form.isInstallment ?? '0',
|
||||
totalPhases: isInstallment ? Number(form.totalPhases) || 1 : 1,
|
||||
purchaserId: String(form.purchaserId ?? ''),
|
||||
purchaserName: String(form.purchaserName ?? ''),
|
||||
assetAdminId: String(form.assetAdminId ?? ''),
|
||||
assetAdminName: String(form.assetAdminName ?? ''),
|
||||
transactionAmount: form.transactionAmount ?? null,
|
||||
supplierName: String(form.supplierName ?? ''),
|
||||
});
|
||||
useMessage().success('保存成功');
|
||||
await loadData();
|
||||
} catch (e: any) {
|
||||
useMessage().error(e?.msg || '保存失败');
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
const formRef = commonFormRef.value
|
||||
const valid = await formRef?.validate?.().catch(() => false)
|
||||
if (!valid) return
|
||||
// 直接从子组件 form 读取,确保拿到用户填写的最新值(避免 v-model 同步延迟)
|
||||
const form = formRef?.form || commonForm.value
|
||||
const isInstallment = form.isInstallment === '1' || form.isInstallment === 1
|
||||
if (isInstallment && (!form.totalPhases || form.totalPhases < 1)) {
|
||||
useMessage().error('请填写分期次数')
|
||||
return
|
||||
}
|
||||
saving.value = true
|
||||
try {
|
||||
await apiSaveCommonConfig({
|
||||
purchaseId: String(purchaseId.value),
|
||||
hasContract: form.hasContract ?? '0',
|
||||
contractId: form.contractId ?? '',
|
||||
isInstallment: form.isInstallment ?? '0',
|
||||
totalPhases: isInstallment ? (Number(form.totalPhases) || 1) : 1,
|
||||
supplierName: String(form.supplierName ?? ''),
|
||||
supplierContact: String(form.supplierContact ?? ''),
|
||||
purchaserId: String(form.purchaserId ?? ''),
|
||||
purchaserName: String(form.purchaserName ?? ''),
|
||||
assetAdminId: String(form.assetAdminId ?? ''),
|
||||
assetAdminName: String(form.assetAdminName ?? ''),
|
||||
transactionAmount: form.transactionAmount ?? null,
|
||||
})
|
||||
useMessage().success('保存成功')
|
||||
await loadData()
|
||||
} catch (e: any) {
|
||||
useMessage().error(e?.msg || '保存失败')
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const saveCurrentBatch = async () => {
|
||||
const curBatch = Number(activeTab.value);
|
||||
const batchFormRef = batchFormRefMap.value[curBatch];
|
||||
const valid = await batchFormRef?.validate?.().catch(() => false);
|
||||
if (!valid) return;
|
||||
const curBatch = Number(activeTab.value)
|
||||
const batchFormRef = batchFormRefMap.value[curBatch]
|
||||
const valid = await batchFormRef?.validate?.().catch(() => false)
|
||||
if (!valid) return
|
||||
|
||||
const b = batches.value.find((x: any) => String(x.batch) === activeTab.value);
|
||||
if (!b?.id) return;
|
||||
const b = batches.value.find((x: any) => String(x.batch) === activeTab.value)
|
||||
if (!b?.id) return
|
||||
|
||||
// 从子组件获取表单数据
|
||||
const formData = batchFormRef?.getFormData?.() || batchFormRef?.form;
|
||||
if (!formData) return;
|
||||
// 从子组件获取表单数据
|
||||
const formData = batchFormRef?.getFormData?.() || batchFormRef?.form
|
||||
if (!formData) return
|
||||
|
||||
// acceptDate is now optional - removed the validation check
|
||||
if (!formData.acceptDate) {
|
||||
useMessage().error('请选择验收日期')
|
||||
return
|
||||
}
|
||||
|
||||
// templateFileIds: 提取ID数组
|
||||
let fileIds: string[] = [];
|
||||
if (formData.templateFileIds) {
|
||||
if (Array.isArray(formData.templateFileIds)) {
|
||||
fileIds = formData.templateFileIds
|
||||
.map((item: any) => {
|
||||
if (typeof item === 'string') return item;
|
||||
if (item && item.id) return item.id;
|
||||
return null;
|
||||
})
|
||||
.filter(Boolean);
|
||||
} else if (typeof formData.templateFileIds === 'string') {
|
||||
fileIds = formData.templateFileIds
|
||||
.split(',')
|
||||
.map((s: string) => s.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
}
|
||||
// templateFileIds: 提取ID数组
|
||||
let fileIds: string[] = []
|
||||
if (formData.templateFileIds) {
|
||||
if (Array.isArray(formData.templateFileIds)) {
|
||||
fileIds = formData.templateFileIds.map((item: any) => {
|
||||
if (typeof item === 'string') return item
|
||||
if (item && item.id) return item.id
|
||||
return null
|
||||
}).filter(Boolean)
|
||||
} else if (typeof formData.templateFileIds === 'string') {
|
||||
fileIds = formData.templateFileIds.split(',').map((s: string) => s.trim()).filter(Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
saving.value = true;
|
||||
try {
|
||||
await updateBatch({
|
||||
id: b.id,
|
||||
purchaseId: String(purchaseId.value),
|
||||
acceptType: '2', // 固定为上传模式
|
||||
acceptDate: formData.acceptDate,
|
||||
remark: formData.remark,
|
||||
templateFileIds: fileIds,
|
||||
});
|
||||
useMessage().success('保存成功');
|
||||
batchSavedFlags.value[curBatch] = true;
|
||||
await loadData();
|
||||
} catch (e: any) {
|
||||
useMessage().error(e?.msg || '保存失败');
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
saving.value = true
|
||||
try {
|
||||
await updateBatch({
|
||||
id: b.id,
|
||||
purchaseId: String(purchaseId.value),
|
||||
acceptType: '2', // 固定为上传模式
|
||||
acceptDate: formData.acceptDate,
|
||||
remark: formData.remark,
|
||||
templateFileIds: fileIds,
|
||||
})
|
||||
useMessage().success('保存成功')
|
||||
batchSavedFlags.value[curBatch] = true
|
||||
await loadData()
|
||||
} catch (e: any) {
|
||||
useMessage().error(e?.msg || '保存失败')
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
};
|
||||
visible.value = false
|
||||
emit('refresh')
|
||||
}
|
||||
|
||||
const DEFAULT_COMMON_FORM = {
|
||||
hasContract: '0',
|
||||
contractId: '',
|
||||
contractName: '',
|
||||
contractNo: '',
|
||||
contractMoney: null,
|
||||
contractFlowStatus: '',
|
||||
isInstallment: '0',
|
||||
totalPhases: 1,
|
||||
supplierName: '',
|
||||
purchaserId: '',
|
||||
purchaserName: '',
|
||||
assetAdminId: '',
|
||||
assetAdminName: '',
|
||||
transactionAmount: null,
|
||||
};
|
||||
hasContract: '0',
|
||||
contractId: '',
|
||||
isInstallment: '0',
|
||||
totalPhases: 1,
|
||||
supplierName: '',
|
||||
supplierContact: '',
|
||||
purchaserId: '',
|
||||
purchaserName: '',
|
||||
assetAdminId: '',
|
||||
assetAdminName: '',
|
||||
transactionAmount: null,
|
||||
}
|
||||
|
||||
/** 将弹窗内所有内容恢复为初始空值(替换整个对象以确保引用变化) */
|
||||
const resetAllToDefault = () => {
|
||||
openToken.value++;
|
||||
commonForm.value = { ...DEFAULT_COMMON_FORM };
|
||||
applyInfo.value = null;
|
||||
mainTab.value = 'common';
|
||||
activeTab.value = '1';
|
||||
batchFormRefMap.value = {};
|
||||
batches.value = [];
|
||||
Object.keys(batchForms).forEach((k) => delete batchForms[Number(k)]);
|
||||
batchSavedFlags.value = {};
|
||||
};
|
||||
openToken.value++
|
||||
commonForm.value = { ...DEFAULT_COMMON_FORM }
|
||||
applyInfo.value = null
|
||||
mainTab.value = 'common'
|
||||
activeTab.value = '1'
|
||||
batchFormRefMap.value = {}
|
||||
batches.value = []
|
||||
Object.keys(batchForms).forEach((k) => delete batchForms[Number(k)])
|
||||
batchSavedFlags.value = {}
|
||||
}
|
||||
|
||||
const open = async (row: any) => {
|
||||
purchaseId.value = row?.id ?? '';
|
||||
rowProjectType.value = row?.projectType || 'A';
|
||||
purchaseId.value = row?.id ?? ''
|
||||
rowProjectType.value = row?.projectType || 'A'
|
||||
|
||||
// 1. 先将弹窗内所有内容恢复为初始空值
|
||||
resetAllToDefault();
|
||||
// 1. 先将弹窗内所有内容恢复为初始空值
|
||||
resetAllToDefault()
|
||||
|
||||
// 2. 显示弹窗并开启 loading,避免接口返回前展示旧数据
|
||||
visible.value = true;
|
||||
loading.value = true;
|
||||
// 2. 显示弹窗并开启 loading,避免接口返回前展示旧数据
|
||||
visible.value = true
|
||||
loading.value = true
|
||||
|
||||
// 3. 等待 Vue 完成渲染,确保子组件已接收并展示空值
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
// 3. 等待 Vue 完成渲染,确保子组件已接收并展示空值
|
||||
await nextTick()
|
||||
await nextTick()
|
||||
|
||||
// 4. 再进行接口查询并覆盖
|
||||
await loadData();
|
||||
};
|
||||
// 4. 再进行接口查询并覆盖
|
||||
await loadData()
|
||||
}
|
||||
|
||||
defineExpose({ open });
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-body {
|
||||
padding: 0;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 0;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.main-tab-nav {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin-bottom: 16px;
|
||||
border-bottom: 1px solid var(--el-border-color);
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin-bottom: 16px;
|
||||
border-bottom: 1px solid var(--el-border-color);
|
||||
}
|
||||
.main-tab-item {
|
||||
padding: 12px 20px;
|
||||
cursor: pointer;
|
||||
color: var(--el-text-color-regular);
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
transition: all 0.2s;
|
||||
padding: 12px 20px;
|
||||
cursor: pointer;
|
||||
color: var(--el-text-color-regular);
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.main-tab-item:hover {
|
||||
color: var(--el-color-primary);
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
.main-tab-item.active {
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 600;
|
||||
border-bottom-color: var(--el-color-primary);
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 600;
|
||||
border-bottom-color: var(--el-color-primary);
|
||||
}
|
||||
.main-tab-content {
|
||||
padding-top: 4px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
.tab-content {
|
||||
min-height: 200px;
|
||||
display: block;
|
||||
min-height: 200px;
|
||||
display: block;
|
||||
}
|
||||
.tip-box {
|
||||
padding: 20px 0;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.batch-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.batch-tab-item {
|
||||
padding: 8px 16px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transition: all 0.2s;
|
||||
padding: 8px 16px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.batch-tab-item:hover:not(.disabled) {
|
||||
border-color: var(--el-color-primary);
|
||||
color: var(--el-color-primary);
|
||||
border-color: var(--el-color-primary);
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
.batch-tab-item.active {
|
||||
background: var(--el-color-primary);
|
||||
border-color: var(--el-color-primary);
|
||||
color: #fff;
|
||||
background: var(--el-color-primary);
|
||||
border-color: var(--el-color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
.batch-tab-item.disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.batch-panel {
|
||||
min-height: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/* 弹窗横向滚动修复,需非 scoped 以影响 el-dialog */
|
||||
.purchasing-accept-modal .el-dialog__body {
|
||||
overflow-x: hidden;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user