撤回
@@ -495,7 +480,7 @@ import { getDicts } from '/@/api/admin/dict';
import { useMessage } from '/@/hooks/message';
import UploadFile from '/@/components/Upload/index.vue';
import other from '/@/utils/other';
-import { Document, Download } from '@element-plus/icons-vue';
+import { Document, Download, QuestionFilled } from '@element-plus/icons-vue';
import { fetchList as getBusinessDeptList } from '/@/api/purchase/purchasingBusinessDept';
import { getPage as getSchoolLeaderPage } from '/@/api/finance/purchasingschoolleader';
import { Session } from '/@/utils/storage';
@@ -555,9 +540,10 @@ const flowSubmitDisabled = ref(false);
/** 流程嵌入时当前节点是否为采购中心(仅采购中心可编辑采购方式/采购形式) */
const isPurchaseCenter = ref(false);
-/** 流程嵌入且为采购中心时,除采购方式/采购形式外其余字段均只读 */
-function flowFieldDisabled(key: string) {
- return isFlowEmbed.value && isPurchaseCenter.value && !['purchaseType', 'purchaseMode'].includes(key);
+/** 流程嵌入时:采购中心审核节点放开所有字段编辑;非采购中心节点只读 */
+function flowFieldDisabled(_key: string) {
+ if (isFlowEmbed.value && isPurchaseCenter.value) return false;
+ return !!isFlowEmbed.value;
}
// 定义变量内容
@@ -575,6 +561,7 @@ const dataForm = reactive({
purchaseMode: '',
purchaseType: '',
purchaseTypeUnion: '',
+ purchaseChannel: '',
categoryCode: '',
remark: '',
status: '',
@@ -634,6 +621,7 @@ const purchaseTypeUnionList = ref
([]);
const businessDeptList = ref([]);
const schoolLeaderList = ref([]);
const loading = ref(false);
+const helpDialogVisible = ref(false);
// 文件类型映射(对应数据库 file_type 字段)
// 10:商务洽谈纪要 20:市场采购纪要 30:网上商城采购相关材料 40:可行性论证报告 50:会议记录 60:其他材料 70:单一来源专家论证表 90:进口产品专家论证表 100:政府采购意向表 110:履约验收单 120:采购需求表 130:采购文件
@@ -670,13 +658,19 @@ Object.entries(FILE_TYPE_MAP).forEach(([field, type]) => {
FILE_TYPE_TO_FIELDS[type].push(field);
});
+// 金额阈值常量(与后端 PurchaseConstants 保持一致)
+const BUDGET_DEPT_PURCHASE_THRESHOLD = 50000; // 部门自行采购上限(< 5 万)
+const BUDGET_FEASIBILITY_THRESHOLD = 300000; // 可行性论证/会议纪要起点(≥ 30 万)
+const BUDGET_PUBLIC_SELECT_THRESHOLD = 400000; // 公开比选起点(≥ 40 万)
+const BUDGET_GOV_PURCHASE_THRESHOLD = 1000000; // 政府采购起点(≥ 100 万)
+
// 部门采购方式字典 value(与 DeptPurchaseTypeEnum 一致)
const DEPT_PURCHASE_TYPE = {
ONLINE_MALL: '1',
MARKET_PURCHASE: '2',
BUSINESS_NEGOTIATION: '3',
ENTRUST_CENTER: '4',
- INQUIRY: '6',
+ INQUIRY: '5',
} as const;
// 学校统一采购方式字典 value(与 PurchaseTypeEnum 一致)
@@ -700,6 +694,12 @@ const isSpecialType = (dictValue: string) => {
return item ? dataForm.isSpecial === item.value : dataForm.isSpecial === dictValue;
};
+// 采购途径(与后端 purchasing_apply.purchase_channel 一致:1 自行采购 2 委托采购中心采购)
+const PURCHASE_CHANNEL = {
+ SELF: '1',
+ ENTRUST_CENTER: '2',
+} as const;
+
// 判断是否为部门自行采购
// 条件:特殊情况=否 且 集采=否 且 预算金额<5万 → 部门自行采购
// 其他情况 → 学校统一采购
@@ -714,6 +714,9 @@ const isDeptPurchase = computed(() => {
dataForm.budget && dataForm.budget < 50000);
});
+// 是否为“委托采购中心采购”途径
+const isEntrustCenterChannel = computed(() => dataForm.purchaseChannel === PURCHASE_CHANNEL.ENTRUST_CENTER);
+
// 是否已填入“是否特殊情况”“是否集采”“预算金额”,从而能明确是部门自行采购还是学校统一采购(新增时先隐藏采购详情,填完后再显示)
const isPurchaseTypeDetermined = computed(() => {
return dataForm.isSpecial !== '' && dataForm.isCentralized !== '' &&
@@ -728,8 +731,8 @@ const showPurchaseDetailBlocks = computed(() => {
const schoolUnifiedPurchaseFormDefault = computed(() => {
if (isDeptPurchase.value || dataForm.budget == null) return null;
const budget = Number(dataForm.budget);
- if (budget >= 1000000) return '1'; // 政府采购
- if (budget >= 50000 && budget < 1000000) {
+ if (budget >= BUDGET_GOV_PURCHASE_THRESHOLD) return '1'; // 政府采购
+ if (budget >= BUDGET_DEPT_PURCHASE_THRESHOLD && budget < BUDGET_GOV_PURCHASE_THRESHOLD) {
if (dataForm.isCentralized === '0') return '2'; // 集采=否 → 学校自主采购
if (dataForm.isCentralized === '1') return '1'; // 政府集中采购 → 政府采购
if (dataForm.isCentralized === '2') return '2'; // 学校集中采购 → 学校自主采购
@@ -737,8 +740,20 @@ const schoolUnifiedPurchaseFormDefault = computed(() => {
return null;
});
-// 学校统一采购时采购形式是否禁用(由规则自动选择,不由用户选择)
-const schoolUnifiedPurchaseFormDisabled = computed(() => flowFieldDisabled('purchaseMode') || (schoolUnifiedPurchaseFormDefault.value != null));
+// 学校统一采购时采购形式是否禁用
+// 申请阶段:始终可选(根据默认值自动选中后,允许用户自行修改)
+// 流程嵌入:采购中心节点可编辑,其他节点只读
+const schoolUnifiedPurchaseFormDisabled = computed(() => {
+ if (!isFlowEmbed.value) {
+ return false;
+ }
+ // 流程嵌入且为采购中心:放开编辑
+ if (isPurchaseCenter.value) {
+ return false;
+ }
+ // 其他流程节点只读
+ return true;
+});
// 特殊情况字典 value:0否 1紧急 2单一 3进口
const isUrgentSpecial = computed(() => dataForm.isSpecial === '1');
@@ -823,7 +838,7 @@ const isSpecialServiceCategory = computed(() => {
// - 服务类:若末级节点 isMallService=0 且 isMallProject=0,则选“其他方式”,否则选“服务类网上商城”
// - 非服务类:默认选“其他方式”
const calcEntrustCenterType = (): 'service_online' | 'other' | '' => {
- if (!isPurchaseType(DEPT_PURCHASE_TYPE.ENTRUST_CENTER)) return '';
+ if (!isEntrustCenterChannel.value) return '';
if (!dataForm.categoryCode) return '';
const category = getCategoryInfo();
@@ -839,9 +854,9 @@ const calcEntrustCenterType = (): 'service_online' | 'other' | '' => {
return 'other';
};
-// 监听品目/采购方式变化,自动设置委托采购中心方式,并清理无关字段
+// 监听品目/采购途径变化,自动设置委托采购中心方式,并清理无关字段
watch(
- [() => dataForm.purchaseType, () => dataForm.categoryCode, () => categoryTreeData.value],
+ [() => dataForm.purchaseChannel, () => dataForm.categoryCode, () => categoryTreeData.value],
() => {
const nextType = calcEntrustCenterType();
if (!nextType) return;
@@ -870,7 +885,7 @@ watch(
const isAutoSelectPurchaseType = computed(() => {
if (!dataForm.budget) return false;
const budget = dataForm.budget;
- return budget >= 50000 && budget < 400000 && isServiceCategory.value && isSpecialServiceCategory.value;
+ return budget >= BUDGET_DEPT_PURCHASE_THRESHOLD && budget < BUDGET_PUBLIC_SELECT_THRESHOLD && isServiceCategory.value && isSpecialServiceCategory.value;
});
// 判断是否显示自动邀请比选模版(5万<=金额<40万,服务类目,特殊服务类目)
@@ -878,7 +893,7 @@ const showAutoInviteSelect = computed(() => {
if (!isDeptPurchase.value) return false;
if (!dataForm.budget) return false;
const budget = dataForm.budget;
- return budget >= 50000 && budget < 400000 && isServiceCategory.value && isSpecialServiceCategory.value;
+ return budget >= BUDGET_DEPT_PURCHASE_THRESHOLD && budget < BUDGET_PUBLIC_SELECT_THRESHOLD && isServiceCategory.value && isSpecialServiceCategory.value;
});
// 判断是否显示学校统一采购的自动邀请比选模版(5万<=金额<40万,服务类目,特殊服务类目)
@@ -886,7 +901,7 @@ const showAutoInviteSelectSchool = computed(() => {
if (isDeptPurchase.value) return false;
if (!dataForm.budget) return false;
const budget = dataForm.budget;
- return budget >= 50000 && budget < 400000 && isSpecialServiceCategory.value;
+ return budget >= BUDGET_DEPT_PURCHASE_THRESHOLD && budget < BUDGET_PUBLIC_SELECT_THRESHOLD && isSpecialServiceCategory.value;
});
// 判断是否显示自动公开比选模版(40万<=金额<100万,特殊服务类目:isMallService=1、isProjectService=1)
@@ -894,7 +909,7 @@ const showAutoPublicSelect = computed(() => {
if (isDeptPurchase.value) return false;
if (!dataForm.budget) return false;
const budget = dataForm.budget;
- return budget >= 400000 && budget < 1000000 && isSpecialServiceCategory.value;
+ return budget >= BUDGET_PUBLIC_SELECT_THRESHOLD && budget < BUDGET_GOV_PURCHASE_THRESHOLD && isSpecialServiceCategory.value;
});
// 获取需求文件的 prop 名称(用于表单验证)
@@ -916,25 +931,41 @@ const isAutoSelectPurchaseTypeUnion = computed(() => {
if (isDeptPurchase.value) return false;
if (!dataForm.budget) return false;
const budget = dataForm.budget;
- return budget >= 50000 && budget < 400000 && isSpecialServiceCategory.value;
+ return budget >= BUDGET_DEPT_PURCHASE_THRESHOLD && budget < BUDGET_PUBLIC_SELECT_THRESHOLD && isSpecialServiceCategory.value;
});
-// 监听品目编码、预算金额及采购类型变化,自动设置/清空采购方式
-watch([() => dataForm.categoryCode, () => dataForm.budget, () => isDeptPurchase.value, () => isFlowEmbed.value], () => {
+// 监听品目编码、预算金额、采购类型及采购途径变化,自动设置/清空采购方式
+watch(
+ [() => dataForm.categoryCode, () => dataForm.budget, () => isDeptPurchase.value, () => isFlowEmbed.value, () => dataForm.purchaseChannel, () => isPurchaseCenter.value],
+ () => {
// 学校统一采购申请阶段:采购方式隐藏,由审批环节采购中心补充,此处不自动写入且清空已有值
if (!isDeptPurchase.value && !isFlowEmbed.value) {
dataForm.purchaseType = '';
return;
}
-
- // 部门自行采购:自动设置网上商城
- if (isAutoSelectPurchaseType.value && isDeptPurchase.value) {
+
+ // 部门自行采购 & 采购途径为“委托采购中心采购”且为申请阶段:采购方式隐藏且不设置
+ if (isDeptPurchase.value && isEntrustCenterChannel.value && !isFlowEmbed.value) {
+ dataForm.purchaseType = '';
+ return;
+ }
+
+ // 部门自行采购 & 采购途径为“自行采购”:自动设置网上商城
+ if (isAutoSelectPurchaseType.value && isDeptPurchase.value && !isEntrustCenterChannel.value) {
const onlineMallOption = purchaseTypeDeptList.value.find(item => item.value === DEPT_PURCHASE_TYPE.ONLINE_MALL);
if (onlineMallOption && dataForm.purchaseType !== onlineMallOption.value) {
dataForm.purchaseType = onlineMallOption.value;
}
}
-
+
+ // 部门自行采购 & 采购途径为“委托采购中心采购” & 采购中心审批节点:根据特殊服务类目自动设置网上商城
+ if (isAutoSelectPurchaseType.value && isDeptPurchase.value && isEntrustCenterChannel.value && isFlowEmbed.value && isPurchaseCenter.value) {
+ const onlineMallOption = purchaseTypeDeptList.value.find(item => item.value === DEPT_PURCHASE_TYPE.ONLINE_MALL);
+ if (onlineMallOption && dataForm.purchaseType !== onlineMallOption.value) {
+ dataForm.purchaseType = onlineMallOption.value;
+ }
+ }
+
// 学校统一采购审批阶段:自动设置网上商城采购方式
if (isAutoSelectPurchaseTypeUnion.value && !isDeptPurchase.value && isFlowEmbed.value) {
const onlineMallOption = purchaseTypeUnionList.value.find(item => item.value === UNION_PURCHASE_TYPE.ONLINE_MALL);
@@ -942,7 +973,8 @@ watch([() => dataForm.categoryCode, () => dataForm.budget, () => isDeptPurchase.
dataForm.purchaseType = onlineMallOption.value;
}
}
-}, { immediate: true });
+},
+{ immediate: true });
// 学校统一采购:采购形式由规则默认选择,随预算与集采变化自动更新
watch([() => schoolUnifiedPurchaseFormDefault.value, () => isDeptPurchase.value], () => {
@@ -953,21 +985,21 @@ watch([() => schoolUnifiedPurchaseFormDefault.value, () => isDeptPurchase.value]
}
}, { immediate: true });
-// 下载模版
+// 下载模版:统一走后端接口,按原始文件下载(避免前端静态资源被当成 HTML 返回)
const downloadTemplate = async (type: string) => {
- const templateMap: Record = {
- 'business_negotiation': { fileName: '商务洽谈表.xlsx', displayName: '商务洽谈表.xlsx' },
- 'market_purchase_minutes': { fileName: '市场采购纪要.xlsx', displayName: '市场采购纪要.xlsx' },
- 'inquiry': { fileName: '部门采购询价模版.docx', displayName: '部门采购询价模版.docx' },
- 'direct_select': { fileName: '服务商城项目需求模板(直选).doc', displayName: '服务商城项目需求模板(直选).doc' },
- 'public_select': { fileName: '服务商城项目需求模板(公开比选).doc', displayName: '服务商城项目需求模板(公开比选).doc' },
- 'invite_select': { fileName: '服务商城项目需求模板(邀请比选).doc', displayName: '服务商城项目需求模板(邀请比选).doc' },
- 'purchase_requirement': { fileName: '默认需求模板.doc', displayName: '默认需求模板.doc' },
- 'import_application': { fileName: '附件1:进口产品申请及专家论证意见表.doc', displayName: '进口产品申请及专家论证意见表.doc' },
- 'single_source': { fileName: '表7:单一来源论专家证附件.docx', displayName: '单一来源论专家证附件.docx' },
- 'feasibility_report': { fileName: '表6:项目可行性论证报告模板.doc', displayName: '项目可行性论证报告模板.doc' },
+ const templateMap: Record = {
+ business_negotiation: { displayName: '商务洽谈表.doc' },
+ market_purchase_minutes: { displayName: '部门自行采购市场采购纪要.doc' },
+ inquiry: { displayName: '部门采购询价模版.doc' },
+ direct_select: { displayName: '服务商城项目需求模板(直选).doc' },
+ public_select: { displayName: '服务商城项目需求模板(公开比选).doc' },
+ invite_select: { displayName: '服务商城项目需求模板(邀请比选).doc' },
+ purchase_requirement: { displayName: '采购需求填报模板.doc' },
+ import_application: { displayName: '进口产品申请及专家论证意见表.doc' },
+ single_source: { displayName: '单一来源论专家证附件.docx' },
+ feasibility_report: { displayName: '项目可行性论证报告模板.doc' },
};
-
+
const template = templateMap[type];
if (!template) {
useMessage().error('模版不存在');
@@ -975,32 +1007,14 @@ const downloadTemplate = async (type: string) => {
}
try {
- const fileUrl = new URL(`../../assets/file/${template.fileName}`, import.meta.url).href;
- const response = await fetch(fileUrl);
- if (!response.ok) {
- throw new Error('文件下载失败');
- }
- const blob = await response.blob();
- const url = window.URL.createObjectURL(blob);
- const link = document.createElement('a');
- link.href = url;
- link.download = template.displayName;
- document.body.appendChild(link);
- link.click();
- window.URL.revokeObjectURL(url);
- document.body.removeChild(link);
+ await other.downBlobFile(
+ `/purchase/purchasingtemplate/download?type=${encodeURIComponent(type)}`,
+ {},
+ template.displayName,
+ );
useMessage().success('模版下载成功');
- } catch (error) {
- try {
- await other.downBlobFile(
- `/purchase/purchasingfiles/downloadTemplate?type=${type}`,
- {},
- template.displayName
- );
- useMessage().success('模版下载成功');
- } catch (err) {
- useMessage().error('模版下载失败,请先维护模版文件');
- }
+ } catch (err) {
+ useMessage().error('模版下载失败,请联系管理员维护模版文件');
}
};
@@ -1031,8 +1045,38 @@ const dataRules = reactive({
{ required: true, message: '采购内容不能为空', trigger: 'blur' },
{ max: 1000, message: '采购内容不能超过1000字', trigger: 'blur' }
],
+ purchaseChannel: [
+ {
+ validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
+ if (!isDeptPurchase.value) {
+ callback();
+ return;
+ }
+ if (!value || String(value).trim() === '') {
+ callback(new Error('请选择采购途径'));
+ return;
+ }
+ callback();
+ },
+ trigger: 'change',
+ },
+ ],
purchaseType: [
- { required: true, message: '请选择采购方式', trigger: 'change' }
+ {
+ validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
+ // 部门自行采购且采购途径为“委托采购中心采购”并且为申请阶段:此处不校验采购方式
+ if (isDeptPurchase.value && isEntrustCenterChannel.value && !isFlowEmbed.value) {
+ callback();
+ return;
+ }
+ if (!value || String(value).trim() === '') {
+ callback(new Error('请选择采购方式'));
+ return;
+ }
+ callback();
+ },
+ trigger: 'change',
+ },
],
// 学校统一采购时必填
deptClassifyUserId: [
@@ -1098,7 +1142,8 @@ async function loadDetail(applyId: string | number) {
isCentralized: detail.isCentralized != null ? String(detail.isCentralized) : '',
isSpecial: detail.isSpecial != null ? String(detail.isSpecial) : '',
purchaseMode: detail.purchaseMode ?? '',
- purchaseType: detail.purchaseType ?? '',
+ purchaseType: detail.purchaseType === DEPT_PURCHASE_TYPE.ENTRUST_CENTER ? '' : (detail.purchaseType ?? ''),
+ purchaseChannel: (detail as any).purchaseChannel ?? (detail.purchaseType === DEPT_PURCHASE_TYPE.ENTRUST_CENTER ? PURCHASE_CHANNEL.ENTRUST_CENTER : ''),
purchaseTypeUnion: detail.purchaseTypeUnion ?? '',
categoryCode: detail.categoryCode ?? '',
remark: detail.remark ?? '',
@@ -1346,16 +1391,18 @@ const getIsSpecialDict = async () => {
}
};
-// 获取部门采购方式字典
+// 获取部门采购方式字典(过滤掉“委托采购中心采购”,由采购途径字段控制)
const getPurchaseTypeDeptDict = async () => {
try {
const res = await getDicts('PURCHASE_TYPE_DEPT');
purchaseTypeDeptList.value = res.data && Array.isArray(res.data)
- ? res.data.map((item: any) => ({
- id: item.id,
- label: item.label || item.dictLabel || item.name,
- value: item.value || item.dictValue || item.code
- }))
+ ? res.data
+ .map((item: any) => ({
+ id: item.id,
+ label: item.label || item.dictLabel || item.name,
+ value: item.value || item.dictValue || item.code,
+ }))
+ .filter((item: any) => item.value !== DEPT_PURCHASE_TYPE.ENTRUST_CENTER)
: [];
} catch (err) {
purchaseTypeDeptList.value = [];
diff --git a/src/views/finance/purchasingtemplate/index.vue b/src/views/finance/purchasingtemplate/index.vue
new file mode 100644
index 0000000..fa99065
--- /dev/null
+++ b/src/views/finance/purchasingtemplate/index.vue
@@ -0,0 +1,250 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 下载
+
+
+ 重新上传
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 选择文件
+
+ 支持 doc、docx 等 Word 模板文件,上传后前端下载将使用该文件。
+
+
+
+
+
+ 取 消
+ 上 传
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取 消
+ 保 存
+
+
+
+
+
+
+
+
+
+