|
|
|
|
@ -353,6 +353,7 @@ export default {
|
|
|
|
|
purchaseCategoryOptions: [],
|
|
|
|
|
contractTypeOptions: [],
|
|
|
|
|
purchaseMethodOptions: [],
|
|
|
|
|
suppressFundSourceYearWatcher: false,
|
|
|
|
|
form: {
|
|
|
|
|
contract_no: "",
|
|
|
|
|
contract_no_without_prefix: "",
|
|
|
|
|
@ -425,13 +426,17 @@ export default {
|
|
|
|
|
'form.fund_source_year_id'(newVal, oldVal) {
|
|
|
|
|
// 当预算年度变化时,自动加载项目经费来源选项
|
|
|
|
|
if (newVal) {
|
|
|
|
|
this.fetchFundSourceOptions(newVal);
|
|
|
|
|
if (!this.suppressFundSourceYearWatcher) {
|
|
|
|
|
this.fetchFundSourceOptions(newVal);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this.fundSourceOptions = [];
|
|
|
|
|
this.form.fund_source_budget_data_id = null;
|
|
|
|
|
if (!this.suppressFundSourceYearWatcher) {
|
|
|
|
|
this.form.fund_source_budget_data_id = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 如果年度变化了,清空之前选择的经费来源
|
|
|
|
|
if (newVal !== oldVal) {
|
|
|
|
|
if (newVal !== oldVal && !this.suppressFundSourceYearWatcher) {
|
|
|
|
|
this.form.fund_source_budget_data_id = null;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
@ -757,6 +762,34 @@ export default {
|
|
|
|
|
this.fundSourceOptions = [];
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async fetchBudgetDataDetail(budgetDataId) {
|
|
|
|
|
if (!budgetDataId) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
const response = await request.get(`/api/budget/budget-data/${budgetDataId}`);
|
|
|
|
|
return response?.data || response || null;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('获取项目经费来源详情失败', e);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async restoreFundSourceByBudgetDataId(budgetDataId) {
|
|
|
|
|
if (!budgetDataId) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const budgetData = await this.fetchBudgetDataDetail(budgetDataId);
|
|
|
|
|
const yearId = budgetData?.year_id || budgetData?.budget_year?.id || budgetData?.budgetYear?.id;
|
|
|
|
|
if (yearId) {
|
|
|
|
|
this.suppressFundSourceYearWatcher = true;
|
|
|
|
|
this.form.fund_source_year_id = yearId;
|
|
|
|
|
await this.fetchFundSourceOptions(yearId);
|
|
|
|
|
this.form.fund_source_budget_data_id = budgetDataId;
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
this.suppressFundSourceYearWatcher = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async fetchPurchaseCategoryOptions() {
|
|
|
|
|
try {
|
|
|
|
|
// 注意:响应拦截器已经返回了 res.data,所以 response 直接就是数据
|
|
|
|
|
@ -909,7 +942,12 @@ export default {
|
|
|
|
|
const contractExists = await this.loadExistingContract();
|
|
|
|
|
// 如果找不到已有合同,且提供了flowId,则从流程数据预填
|
|
|
|
|
if (!contractExists && this.flowId) {
|
|
|
|
|
this.loadFlowDataAndPrefill();
|
|
|
|
|
await this.loadFlowDataAndPrefill();
|
|
|
|
|
} else if (contractExists && this.flowId && this.isEditMode()) {
|
|
|
|
|
await this.loadFlowDataAndPrefill({
|
|
|
|
|
onlyEmpty: true,
|
|
|
|
|
fields: this.getResignSupplementFields(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
// 重新初始化校验规则(因为可能已经加载了合同数据,需要区分新建/编辑)
|
|
|
|
|
this.initRules();
|
|
|
|
|
@ -1060,13 +1098,13 @@ export default {
|
|
|
|
|
this.form.fund_source = contractData.fund_source || "";
|
|
|
|
|
this.form.fund_source_year_id = contractData.fund_source_year_id || null;
|
|
|
|
|
this.form.fund_source_budget_data_id = contractData.fund_source_budget_data_id || null;
|
|
|
|
|
this.form.is_government_purchase = contractData.is_government_purchase || false;
|
|
|
|
|
this.form.is_government_purchase = contractData.is_government_purchase ?? null;
|
|
|
|
|
this.form.tender_agent = contractData.tender_agent || "";
|
|
|
|
|
// 优先使用ID字段,如果不存在则使用旧字段(兼容历史数据)
|
|
|
|
|
this.form.purchase_method_id = contractData.purchase_method_id || null;
|
|
|
|
|
this.form.purchase_method = contractData.purchase_method || ""; // 保留旧字段,用于兼容
|
|
|
|
|
this.form.perform_status = contractData.perform_status || "";
|
|
|
|
|
this.form.is_accepted = contractData.is_accepted || false;
|
|
|
|
|
this.form.is_accepted = contractData.is_accepted ?? null;
|
|
|
|
|
this.form.purchase_category = contractData.purchase_category || "";
|
|
|
|
|
this.form.purchase_category_id = contractData.purchase_category_id || null;
|
|
|
|
|
this.form.apply_handler_id = contractData.apply_handler_id || "";
|
|
|
|
|
@ -1075,8 +1113,10 @@ export default {
|
|
|
|
|
this.form.remark = contractData.remark || "";
|
|
|
|
|
this.form.attachment_id = contractData.attachment_id || null;
|
|
|
|
|
|
|
|
|
|
// 如果设置了预算年度和经费来源,需要加载经费来源选项
|
|
|
|
|
if (this.form.fund_source_year_id) {
|
|
|
|
|
// 项目经费来源优先:可从 budget_data_id 反推预算年度,预算年度只用于加载下拉选项。
|
|
|
|
|
if (this.form.fund_source_budget_data_id) {
|
|
|
|
|
await this.restoreFundSourceByBudgetDataId(this.form.fund_source_budget_data_id);
|
|
|
|
|
} else if (this.form.fund_source_year_id) {
|
|
|
|
|
await this.fetchFundSourceOptions(this.form.fund_source_year_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1145,7 +1185,134 @@ export default {
|
|
|
|
|
this.loading = false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async loadFlowDataAndPrefill() {
|
|
|
|
|
getResignSupplementFields() {
|
|
|
|
|
return [
|
|
|
|
|
'fund_source',
|
|
|
|
|
'fund_source_year_id',
|
|
|
|
|
'fund_source_budget_data_id',
|
|
|
|
|
'is_government_purchase',
|
|
|
|
|
'tender_agent',
|
|
|
|
|
'purchase_method_id',
|
|
|
|
|
'purchase_method',
|
|
|
|
|
'perform_status',
|
|
|
|
|
'is_accepted',
|
|
|
|
|
'purchase_category',
|
|
|
|
|
'purchase_category_id',
|
|
|
|
|
'handler_admin_ids',
|
|
|
|
|
'apply_handler_id',
|
|
|
|
|
'purchase_handler_id',
|
|
|
|
|
'owner_department_id',
|
|
|
|
|
'owner_department_ids',
|
|
|
|
|
'remark',
|
|
|
|
|
'attachment_id',
|
|
|
|
|
'pay_plans',
|
|
|
|
|
];
|
|
|
|
|
},
|
|
|
|
|
isEmptyPrefillValue(value) {
|
|
|
|
|
if (value === null || value === undefined || value === '') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (Array.isArray(value)) {
|
|
|
|
|
return value.length === 0;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
},
|
|
|
|
|
applyMappingTransform(value, map) {
|
|
|
|
|
if (!map || map.value_transform !== 'json_field') {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const jsonField = map.json_field || 'id';
|
|
|
|
|
let parsed = value;
|
|
|
|
|
if (typeof parsed === 'string') {
|
|
|
|
|
try {
|
|
|
|
|
parsed = JSON.parse(parsed);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(parsed)) {
|
|
|
|
|
parsed = parsed[0] || null;
|
|
|
|
|
}
|
|
|
|
|
if (!parsed || typeof parsed !== 'object') {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return parsed[jsonField] ?? null;
|
|
|
|
|
},
|
|
|
|
|
getFirstJsonObject(value) {
|
|
|
|
|
let parsed = value;
|
|
|
|
|
if (typeof parsed === 'string') {
|
|
|
|
|
try {
|
|
|
|
|
parsed = JSON.parse(parsed);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (Array.isArray(parsed)) {
|
|
|
|
|
parsed = parsed[0] || null;
|
|
|
|
|
}
|
|
|
|
|
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
|
|
|
},
|
|
|
|
|
resolveMappedValue(rawValue, map, budgetField) {
|
|
|
|
|
const transformed = this.applyMappingTransform(rawValue, map);
|
|
|
|
|
if (budgetField === 'attachment_id' && (transformed === rawValue || transformed === null || transformed === undefined)) {
|
|
|
|
|
const fileInfo = this.getFirstJsonObject(rawValue);
|
|
|
|
|
return fileInfo?.id ?? transformed;
|
|
|
|
|
}
|
|
|
|
|
return transformed;
|
|
|
|
|
},
|
|
|
|
|
async setPrefillValue(field, value, onlyEmpty = false, rawValue = null) {
|
|
|
|
|
if (!Object.prototype.hasOwnProperty.call(this.form, field) || value === undefined || value === null || value === '') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (onlyEmpty && !this.isEmptyPrefillValue(this.form[field])) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (field === 'fund_source_budget_data_id') {
|
|
|
|
|
await this.restoreFundSourceByBudgetDataId(value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.form[field] = value;
|
|
|
|
|
|
|
|
|
|
if (field === 'owner_department_ids') {
|
|
|
|
|
const ids = typeof value === 'string'
|
|
|
|
|
? value.split(',').filter(id => id)
|
|
|
|
|
: (Array.isArray(value) ? value : []);
|
|
|
|
|
this.form.owner_department_ids_array = ids.map(id => String(id));
|
|
|
|
|
if (!this.form.owner_department_id && ids.length > 0) {
|
|
|
|
|
this.form.owner_department_id = parseInt(ids[0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (field === 'handler_admin_ids') {
|
|
|
|
|
const ids = typeof value === 'string'
|
|
|
|
|
? value.split(',').filter(id => id)
|
|
|
|
|
: (Array.isArray(value) ? value : []);
|
|
|
|
|
this.form.handler_admin_ids_array = ids.map(id => String(id));
|
|
|
|
|
}
|
|
|
|
|
if (field === 'apply_handler_id') {
|
|
|
|
|
const ids = typeof value === 'string'
|
|
|
|
|
? value.split(',').filter(id => id)
|
|
|
|
|
: (Array.isArray(value) ? value : []);
|
|
|
|
|
this.form.apply_handler_id_array = ids.map(id => String(id));
|
|
|
|
|
}
|
|
|
|
|
if (field === 'attachment_id') {
|
|
|
|
|
const fileInfo = this.getFirstJsonObject(rawValue);
|
|
|
|
|
this.attachmentFileList = fileInfo ? [{
|
|
|
|
|
name: fileInfo.original_name || fileInfo.name || '文件',
|
|
|
|
|
url: fileInfo.url || (fileInfo.folder && fileInfo.name ? `${fileInfo.folder}/${fileInfo.name}` : ''),
|
|
|
|
|
uid: fileInfo.id || value,
|
|
|
|
|
id: fileInfo.id || value
|
|
|
|
|
}] : [];
|
|
|
|
|
}
|
|
|
|
|
if (field === 'fund_source_year_id' && value) {
|
|
|
|
|
await this.fetchFundSourceOptions(value);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async loadFlowDataAndPrefill(options = {}) {
|
|
|
|
|
if (!this.flowId) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@ -1167,20 +1334,24 @@ export default {
|
|
|
|
|
const flowData = flowDetail.flow.data;
|
|
|
|
|
const contractMapping = (settings?.contract_field_mapping || []);
|
|
|
|
|
const payplanMapping = (settings?.payplan_field_mapping || []);
|
|
|
|
|
const onlyEmpty = !!options.onlyEmpty;
|
|
|
|
|
const allowedFields = Array.isArray(options.fields) ? options.fields : null;
|
|
|
|
|
|
|
|
|
|
if (contractMapping && contractMapping.length > 0) {
|
|
|
|
|
contractMapping.forEach((map) => {
|
|
|
|
|
for (const map of contractMapping) {
|
|
|
|
|
const budgetField = map.budget_field;
|
|
|
|
|
const oaField = map.oa_field;
|
|
|
|
|
if (allowedFields && !allowedFields.includes(budgetField)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (budgetField && oaField && flowData[oaField] !== undefined) {
|
|
|
|
|
if (this.form.hasOwnProperty(budgetField)) {
|
|
|
|
|
this.form[budgetField] = flowData[oaField];
|
|
|
|
|
}
|
|
|
|
|
await this.setPrefillValue(budgetField, this.resolveMappedValue(flowData[oaField], map, budgetField), onlyEmpty, flowData[oaField]);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (settings.oa_custom_model_id_for_payplan && flowDetail.customModel) {
|
|
|
|
|
const shouldFillPayPlans = !allowedFields || allowedFields.includes('pay_plans');
|
|
|
|
|
if (shouldFillPayPlans && (!onlyEmpty || this.isEmptyPrefillValue(this.form.pay_plans)) && settings.oa_custom_model_id_for_payplan && flowDetail.customModel) {
|
|
|
|
|
const payplanField = flowDetail.customModel.fields.find(
|
|
|
|
|
(f) => f.type === "relation" && f.sub_custom_model_id === settings.oa_custom_model_id_for_payplan
|
|
|
|
|
);
|
|
|
|
|
@ -1197,7 +1368,7 @@ export default {
|
|
|
|
|
this.form.pay_plans = this.mapPayPlans(payplanRows, payplanMapping);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (flowData.pay_plans && Array.isArray(flowData.pay_plans)) {
|
|
|
|
|
} else if (shouldFillPayPlans && (!onlyEmpty || this.isEmptyPrefillValue(this.form.pay_plans)) && flowData.pay_plans && Array.isArray(flowData.pay_plans)) {
|
|
|
|
|
this.form.pay_plans = this.mapPayPlans(flowData.pay_plans, payplanMapping);
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
@ -1218,7 +1389,7 @@ export default {
|
|
|
|
|
const budgetField = map.budget_field;
|
|
|
|
|
const oaField = map.oa_field;
|
|
|
|
|
if (budgetField && oaField && row[oaField] !== undefined) {
|
|
|
|
|
item[budgetField] = row[oaField];
|
|
|
|
|
item[budgetField] = this.applyMappingTransform(row[oaField], map);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (!item.phase_no) {
|
|
|
|
|
|