合并代码

This commit is contained in:
2026-01-29 11:47:29 +08:00
parent e35d3c2d16
commit c7a686dcaa
12 changed files with 6674 additions and 4237 deletions

View File

@@ -0,0 +1,434 @@
<template>
<el-dialog
:title="dialogTitle"
v-model="visible"
width="900px"
:close-on-click-modal="false"
draggable>
<el-form
ref="formRef"
:model="dataForm"
:rules="dataRules"
label-width="140px"
v-loading="loading">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="采购项目名称" prop="projectName">
<el-input
v-model="dataForm.projectName"
placeholder="请输入采购项目名称"
clearable
:disabled="isView" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="项目类别" prop="projectType">
<el-select
v-model="dataForm.projectType"
placeholder="请选择项目类别"
clearable
:disabled="isView"
style="width: 100%">
<el-option label="货物" value="A" />
<el-option label="工程" value="B" />
<el-option label="服务" value="C" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="品目编码" prop="categoryCode">
<el-tree-select
v-model="dataForm.categoryCode"
:data="categoryTreeData"
:props="{ value: 'code', label: 'name', children: 'children' }"
placeholder="请选择品目编码"
clearable
check-strictly
:render-after-expand="false"
:disabled="isView"
style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="填报日期" prop="applyDate">
<el-date-picker
v-model="dataForm.applyDate"
type="date"
placeholder="请选择填报日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
:disabled="isView"
style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="采购内容" prop="projectContent" class="mb20">
<el-input
v-model="dataForm.projectContent"
type="textarea"
:rows="3"
placeholder="请输入采购内容"
clearable
:disabled="isView" />
</el-form-item>
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="资金来源" prop="fundSource">
<el-input
v-model="dataForm.fundSource"
placeholder="请输入资金来源"
clearable
:disabled="isView" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="预算金额(元)" prop="budget">
<el-input-number
v-model="dataForm.budget"
:min="0.01"
:precision="2"
placeholder="请输入预算金额"
:disabled="isView"
style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="是否集采" prop="isCentralized">
<el-select
v-model="dataForm.isCentralized"
placeholder="请选择是否集采"
clearable
:disabled="isView"
style="width: 100%">
<el-option label="否" value="0" />
<el-option label="是" value="1" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="是否特殊情况" prop="isSpecial">
<el-select
v-model="dataForm.isSpecial"
placeholder="请选择是否特殊情况"
clearable
:disabled="isView"
style="width: 100%">
<el-option label="否" value="0" />
<el-option label="紧急" value="1" />
<el-option label="单一" value="2" />
<el-option label="进口" value="3" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="采购形式" prop="purchaseMode">
<el-select
v-model="dataForm.purchaseMode"
placeholder="请选择采购形式"
clearable
:disabled="isView"
style="width: 100%">
<el-option label="部门自行采购" value="0" />
<el-option label="学校统一采购" value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="学校统一采购方式" prop="purchaseSchool">
<el-select
v-model="dataForm.purchaseSchool"
placeholder="请选择学校统一采购方式"
clearable
:disabled="isView || dataForm.purchaseMode !== '2'"
style="width: 100%">
<el-option label="无" value="0" />
<el-option label="政府采购" value="1" />
<el-option label="学校自主采购" value="2" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="采购方式" prop="purchaseType" class="mb20">
<el-input
v-model="dataForm.purchaseType"
placeholder="请输入采购方式"
clearable
:disabled="isView" />
</el-form-item>
<el-form-item label="附件" prop="fileIds" class="mb20">
<upload-file
v-model="dataForm.fileIds"
:limit="10"
:disabled="isView"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="dataForm.remark"
type="textarea"
:rows="3"
placeholder="请输入备注"
clearable
:disabled="isView" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">{{ isView ? '关闭' : '取消' }}</el-button>
<template v-if="!isView">
<el-button v-if="dataForm.id && dataForm.status === '-1'" type="warning" @click="handleTempStore" :disabled="loading">暂存</el-button>
<el-button type="primary" @click="handleSubmit" :disabled="loading">{{ dataForm.id ? '保存' : '提交' }}</el-button>
</template>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="PurchasingRequisitionForm">
import { reactive, ref, nextTick, computed } from 'vue'
import { getObj, addObj, editObj, tempStore, submitObj } from '/@/api/finance/purchasingrequisition';
import { getTree } from '/@/api/finance/purchasingcategory';
import { useMessage } from '/@/hooks/message';
import UploadFile from '/@/components/Upload/index.vue';
// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh']);
// 定义变量内容
const formRef = ref();
const dataForm = reactive({
id: '',
projectName: '',
projectType: '',
projectContent: '',
applyDate: '',
fundSource: '',
budget: null as number | null,
isCentralized: '',
isSpecial: '',
purchaseMode: '',
purchaseSchool: '',
purchaseType: '',
categoryCode: '',
fileIds: '',
remark: '',
status: '',
});
const categoryTreeData = ref<any[]>([]);
const visible = ref(false);
const loading = ref(false);
const dialogType = ref<'add' | 'edit' | 'view'>('add');
const isView = computed(() => dialogType.value === 'view');
const dialogTitle = computed(() => {
if (dialogType.value === 'view') return '查看采购申请';
if (dialogType.value === 'edit') return '编辑采购申请';
return '新增采购申请';
});
const dataRules = reactive({
projectContent: [
{ required: true, message: '采购内容不能为空', trigger: 'blur' }
],
budget: [
{ required: true, message: '预算金额不能为空', trigger: 'blur' },
{ type: 'number', min: 0.01, message: '预算金额必须大于0.01', trigger: 'blur' }
],
isCentralized: [
{ required: true, message: '请选择是否集采', trigger: 'change' }
],
isSpecial: [
{ required: true, message: '请选择是否特殊情况', trigger: 'change' }
],
});
// 打开弹窗
const openDialog = async (type: 'add' | 'edit' | 'view', rowData?: any) => {
dialogType.value = type;
visible.value = true;
// 重置表单
dataForm.id = '';
dataForm.projectName = '';
dataForm.projectType = '';
dataForm.projectContent = '';
dataForm.applyDate = '';
dataForm.fundSource = '';
dataForm.budget = null;
dataForm.isCentralized = '';
dataForm.isSpecial = '';
dataForm.purchaseMode = '';
dataForm.purchaseSchool = '';
dataForm.purchaseType = '';
dataForm.categoryCode = '';
dataForm.fileIds = '';
dataForm.remark = '';
dataForm.status = '';
await getCategoryTreeData();
nextTick(() => {
formRef.value?.resetFields();
if (type === 'edit' || type === 'view') {
loading.value = true;
getObj(rowData.id)
.then((res) => {
Object.assign(dataForm, {
id: res.data.id || '',
projectName: res.data.projectName || '',
projectType: res.data.projectType || '',
projectContent: res.data.projectContent || '',
applyDate: res.data.applyDate || '',
fundSource: res.data.fundSource || '',
budget: res.data.budget || null,
isCentralized: res.data.isCentralized || '',
isSpecial: res.data.isSpecial || '',
purchaseMode: res.data.purchaseMode || '',
purchaseSchool: res.data.purchaseSchool || '',
purchaseType: res.data.purchaseType || '',
categoryCode: res.data.categoryCode || '',
fileIds: res.data.fileIds ? (Array.isArray(res.data.fileIds) ? res.data.fileIds.join(',') : res.data.fileIds) : '',
remark: res.data.remark || '',
status: res.data.status || '',
});
})
.catch((err: any) => {
useMessage().error(err.msg || '获取详情失败');
})
.finally(() => {
loading.value = false;
});
}
});
};
// 获取品目树形数据
const getCategoryTreeData = async () => {
try {
const res = await getTree();
categoryTreeData.value = [];
if (res.data && Array.isArray(res.data)) {
categoryTreeData.value = res.data;
}
} catch (err: any) {
console.error('获取品目树形数据失败', err);
categoryTreeData.value = [];
}
};
// 处理文件ID字符串转数组
// 从URL中提取文件IDURL格式通常为: /admin/sys-file/show?fileName=xxx&id=xxx
const getFileIdsArray = (): string[] => {
if (!dataForm.fileIds) return [];
if (Array.isArray(dataForm.fileIds)) return dataForm.fileIds;
// 如果是逗号分隔的URL字符串需要从URL中提取文件ID
const urls = dataForm.fileIds.split(',').filter(url => url.trim());
const fileIds: string[] = [];
urls.forEach(url => {
try {
// 尝试从URL参数中提取id
const urlObj = new URL(url, window.location.origin);
const id = urlObj.searchParams.get('id') || urlObj.searchParams.get('fileName');
if (id) {
fileIds.push(id);
} else {
// 如果没有id参数尝试从路径中提取
const pathParts = urlObj.pathname.split('/');
const lastPart = pathParts[pathParts.length - 1];
if (lastPart) {
fileIds.push(lastPart);
}
}
} catch {
// 如果URL解析失败直接使用原始值
fileIds.push(url);
}
});
return fileIds;
};
// 提交(新增或编辑)
const handleSubmit = async () => {
if (loading.value) return;
loading.value = true;
try {
const valid = await formRef.value?.validate().catch(() => {});
if (!valid) {
loading.value = false;
return false;
}
const submitData = {
...dataForm,
fileIds: getFileIdsArray(),
};
if (dataForm.id) {
// 编辑
await editObj(submitData);
useMessage().success('保存成功');
} else {
// 新增(暂存,不启动流程)
await addObj(submitData);
useMessage().success('提交成功');
}
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg || (dataForm.id ? '保存失败' : '提交失败'));
} finally {
loading.value = false;
}
};
// 暂存
const handleTempStore = async () => {
if (loading.value) return;
loading.value = true;
try {
const valid = await formRef.value?.validate().catch(() => {});
if (!valid) {
loading.value = false;
return false;
}
const submitData = {
...dataForm,
fileIds: getFileIdsArray(),
};
await tempStore(submitData);
useMessage().success('暂存成功');
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg || '暂存失败');
} finally {
loading.value = false;
}
};
// 暴露变量
defineExpose({
openDialog,
});
</script>
<style scoped>
.mb20 {
margin-bottom: 20px;
}
</style>