fix
This commit is contained in:
@@ -1,49 +1,48 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="remark" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入remark"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="关联验收类型:A:货物 B:工程 C:服务" prop="acceptanceType">
|
||||
<el-input v-model="form.acceptanceType" placeholder="请输入关联验收类型:A:货物 B:工程 C:服务"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收项名称" prop="itemName">
|
||||
<el-input v-model="form.itemName" placeholder="请输入验收项名称"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="是否启用 0:不启用 1:启用" prop="isEnabled">
|
||||
<el-input v-model="form.isEnabled" placeholder="请输入是否启用 0:不启用 1:启用"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="排序" prop="sortOrder">
|
||||
<el-input v-model="form.sortOrder" placeholder="请输入排序"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="remark" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入remark" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="关联验收类型:A:货物 B:工程 C:服务" prop="acceptanceType">
|
||||
<el-input v-model="form.acceptanceType" placeholder="请输入关联验收类型:A:货物 B:工程 C:服务" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收项名称" prop="itemName">
|
||||
<el-input v-model="form.itemName" placeholder="请输入验收项名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="是否启用 0:不启用 1:启用" prop="isEnabled">
|
||||
<el-input v-model="form.isEnabled" placeholder="请输入是否启用 0:不启用 1:启用" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="排序" prop="sortOrder">
|
||||
<el-input v-model="form.sortOrder" placeholder="请输入排序" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="AcceptanceItemConfigDialog">
|
||||
// ========== 1. 导入语句 ==========
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { rule } from '/@/utils/validate';
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj, validateExist } from '/@/api/purchase/acceptanceItemConfig';
|
||||
|
||||
// ========== 2. 组件定义 ==========
|
||||
@@ -58,79 +57,78 @@ const loading = ref(false); // 加载状态
|
||||
|
||||
// 表单数据对象
|
||||
const form = reactive({
|
||||
id: '', // 主键
|
||||
remark: '', // ${field.fieldComment}
|
||||
acceptanceType: '', // 关联验收类型:A:货物 B:工程 C:服务
|
||||
itemName: '', // 验收项名称
|
||||
isEnabled: '', // 是否启用 0:不启用 1:启用
|
||||
sortOrder: '', // 排序
|
||||
id: '', // 主键
|
||||
remark: '', // ${field.fieldComment}
|
||||
acceptanceType: '', // 关联验收类型:A:货物 B:工程 C:服务
|
||||
itemName: '', // 验收项名称
|
||||
isEnabled: '', // 是否启用 0:不启用 1:启用
|
||||
sortOrder: '', // 排序
|
||||
});
|
||||
|
||||
// ========== 4. 字典数据处理 ==========
|
||||
|
||||
// ========== 5. 表单校验规则 ==========
|
||||
const dataRules = ref({
|
||||
});
|
||||
const dataRules = ref({});
|
||||
|
||||
// ========== 6. 方法定义 ==========
|
||||
// 获取详情数据
|
||||
const getAcceptanceItemConfigData = async (id: string) => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } = await getObj({ id: id });
|
||||
// 直接将第一条数据赋值给表单
|
||||
Object.assign(form, data[0]);
|
||||
} catch (error) {
|
||||
useMessage().error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } = await getObj({ id: id });
|
||||
// 直接将第一条数据赋值给表单
|
||||
Object.assign(form, data[0]);
|
||||
} catch (error) {
|
||||
useMessage().error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 打开弹窗方法
|
||||
const openDialog = (id: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取AcceptanceItemConfig信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getAcceptanceItemConfigData(id);
|
||||
}
|
||||
// 获取AcceptanceItemConfig信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getAcceptanceItemConfigData(id);
|
||||
}
|
||||
};
|
||||
|
||||
// 提交表单方法
|
||||
const onSubmit = async () => {
|
||||
loading.value = true; // 防止重复提交
|
||||
|
||||
// 表单校验
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
loading.value = true; // 防止重复提交
|
||||
|
||||
try {
|
||||
// 根据是否有ID判断是新增还是修改
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh'); // 通知父组件刷新列表
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
// 表单校验
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 根据是否有ID判断是新增还是修改
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh'); // 通知父组件刷新列表
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ========== 7. 对外暴露 ==========
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,138 +1,101 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'purchase_acceptanceItemConfig_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
icon="upload-filled"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="excelUploadRef.show()"
|
||||
v-auth="'purchase_acceptanceItemConfig_add'"
|
||||
>
|
||||
导入
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'purchase_acceptanceItemConfig_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_acceptanceItemConfig_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button
|
||||
icon="folder-add"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="formDialogRef.openDialog()"
|
||||
v-auth="'purchase_acceptanceItemConfig_add'"
|
||||
>
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
icon="upload-filled"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="excelUploadRef.show()"
|
||||
v-auth="'purchase_acceptanceItemConfig_add'"
|
||||
>
|
||||
导入
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'purchase_acceptanceItemConfig_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_acceptanceItemConfig_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right;"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
<!-- 数据表格区域 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column prop="remark" label="remark" show-overflow-tooltip />
|
||||
<el-table-column prop="acceptanceType" label="关联验收类型:A:货物 B:工程 C:服务" show-overflow-tooltip />
|
||||
<el-table-column prop="itemName" label="验收项名称" show-overflow-tooltip />
|
||||
<el-table-column prop="isEnabled" label="是否启用 0:不启用 1:启用" show-overflow-tooltip />
|
||||
<el-table-column prop="sortOrder" label="排序" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_acceptanceItemConfig_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" v-auth="'purchase_acceptanceItemConfig_del'" @click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 数据表格区域 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column
|
||||
prop="remark"
|
||||
label="remark"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="acceptanceType"
|
||||
label="关联验收类型:A:货物 B:工程 C:服务"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="itemName"
|
||||
label="验收项名称"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="isEnabled"
|
||||
label="是否启用 0:不启用 1:启用"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="sortOrder"
|
||||
label="排序"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_acceptanceItemConfig_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="delete"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_acceptanceItemConfig_del'"
|
||||
@click="handleDelete([scope.row.id])"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
v-bind="state.pagination"
|
||||
/>
|
||||
</div>
|
||||
<!-- 编辑、新增弹窗 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 编辑、新增弹窗 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||
<upload-excel
|
||||
ref="excelUploadRef"
|
||||
title="导入"
|
||||
url="/purchase/acceptanceItemConfig/import"
|
||||
temp-url="/admin/sys-file/local/file/acceptanceItemConfig.xlsx"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
</div>
|
||||
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||
<upload-excel
|
||||
ref="excelUploadRef"
|
||||
title="导入"
|
||||
url="/purchase/acceptanceItemConfig/import"
|
||||
temp-url="/admin/sys-file/local/file/acceptanceItemConfig.xlsx"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemAcceptanceItemConfig">
|
||||
// ========== 导入声明 ==========
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObjs } from "/@/api/purchase/acceptanceItemConfig";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs } from '/@/api/purchase/acceptanceItemConfig';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
|
||||
// ========== 组件声明 ==========
|
||||
@@ -142,54 +105,43 @@ const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
// ========== 字典数据 ==========
|
||||
|
||||
// ========== 组件引用 ==========
|
||||
const formDialogRef = ref(); // 表单弹窗引用
|
||||
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||
const queryRef = ref(); // 查询表单引用
|
||||
const formDialogRef = ref(); // 表单弹窗引用
|
||||
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||
const queryRef = ref(); // 查询表单引用
|
||||
|
||||
// ========== 响应式数据 ==========
|
||||
const showSearch = ref(true); // 是否显示搜索区域
|
||||
const selectObjs = ref([]) as any; // 表格多选数据
|
||||
const multiple = ref(true); // 是否多选
|
||||
const showSearch = ref(true); // 是否显示搜索区域
|
||||
const selectObjs = ref([]) as any; // 表格多选数据
|
||||
const multiple = ref(true); // 是否多选
|
||||
|
||||
// ========== 表格状态 ==========
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {}, // 查询参数
|
||||
pageList: fetchList // 分页查询方法
|
||||
queryForm: {}, // 查询参数
|
||||
pageList: fetchList, // 分页查询方法
|
||||
});
|
||||
|
||||
// ========== Hook引用 ==========
|
||||
// 表格相关Hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state);
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// ========== 方法定义 ==========
|
||||
/**
|
||||
* 重置查询条件
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
// 重新查询
|
||||
getDataList();
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
// 重新查询
|
||||
getDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出Excel文件
|
||||
*/
|
||||
const exportExcel = () => {
|
||||
downBlobFile(
|
||||
'/purchase/acceptanceItemConfig/export',
|
||||
Object.assign(state.queryForm, { ids: selectObjs }),
|
||||
'acceptanceItemConfig.xlsx'
|
||||
);
|
||||
downBlobFile('/purchase/acceptanceItemConfig/export', Object.assign(state.queryForm, { ids: selectObjs }), 'acceptanceItemConfig.xlsx');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -197,8 +149,8 @@ const exportExcel = () => {
|
||||
* @param objs 选中的数据行
|
||||
*/
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -206,18 +158,18 @@ const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
* @param ids 要删除的数据ID数组
|
||||
*/
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,44 +1,43 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="remark" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入remark"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="配置项ID" prop="configId">
|
||||
<el-input v-model="form.configId" placeholder="请输入配置项ID"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="是否合格 0:不合格 1:合格" prop="isQualified">
|
||||
<el-input v-model="form.isQualified" placeholder="请输入是否合格 0:不合格 1:合格"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收批次ID" prop="acceptBatchId">
|
||||
<el-input v-model="form.acceptBatchId" placeholder="请输入验收批次ID"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="remark" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入remark" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="配置项ID" prop="configId">
|
||||
<el-input v-model="form.configId" placeholder="请输入配置项ID" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="是否合格 0:不合格 1:合格" prop="isQualified">
|
||||
<el-input v-model="form.isQualified" placeholder="请输入是否合格 0:不合格 1:合格" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收批次ID" prop="acceptBatchId">
|
||||
<el-input v-model="form.acceptBatchId" placeholder="请输入验收批次ID" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PuchasingAcceptContentDialog">
|
||||
// ========== 1. 导入语句 ==========
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { rule } from '/@/utils/validate';
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj, validateExist } from '/@/api/purchase/puchasingAcceptContent';
|
||||
|
||||
// ========== 2. 组件定义 ==========
|
||||
@@ -53,78 +52,77 @@ const loading = ref(false); // 加载状态
|
||||
|
||||
// 表单数据对象
|
||||
const form = reactive({
|
||||
id: '', // 主键
|
||||
remark: '', // ${field.fieldComment}
|
||||
configId: '', // 配置项ID
|
||||
isQualified: '', // 是否合格 0:不合格 1:合格
|
||||
acceptBatchId: '', // 验收批次ID
|
||||
id: '', // 主键
|
||||
remark: '', // ${field.fieldComment}
|
||||
configId: '', // 配置项ID
|
||||
isQualified: '', // 是否合格 0:不合格 1:合格
|
||||
acceptBatchId: '', // 验收批次ID
|
||||
});
|
||||
|
||||
// ========== 4. 字典数据处理 ==========
|
||||
|
||||
// ========== 5. 表单校验规则 ==========
|
||||
const dataRules = ref({
|
||||
});
|
||||
const dataRules = ref({});
|
||||
|
||||
// ========== 6. 方法定义 ==========
|
||||
// 获取详情数据
|
||||
const getPuchasingAcceptContentData = async (id: string) => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } = await getObj({ id: id });
|
||||
// 直接将第一条数据赋值给表单
|
||||
Object.assign(form, data[0]);
|
||||
} catch (error) {
|
||||
useMessage().error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } = await getObj({ id: id });
|
||||
// 直接将第一条数据赋值给表单
|
||||
Object.assign(form, data[0]);
|
||||
} catch (error) {
|
||||
useMessage().error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 打开弹窗方法
|
||||
const openDialog = (id: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取PuchasingAcceptContent信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getPuchasingAcceptContentData(id);
|
||||
}
|
||||
// 获取PuchasingAcceptContent信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getPuchasingAcceptContentData(id);
|
||||
}
|
||||
};
|
||||
|
||||
// 提交表单方法
|
||||
const onSubmit = async () => {
|
||||
loading.value = true; // 防止重复提交
|
||||
|
||||
// 表单校验
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
loading.value = true; // 防止重复提交
|
||||
|
||||
try {
|
||||
// 根据是否有ID判断是新增还是修改
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh'); // 通知父组件刷新列表
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
// 表单校验
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 根据是否有ID判断是新增还是修改
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh'); // 通知父组件刷新列表
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ========== 7. 对外暴露 ==========
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,133 +1,100 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'purchase_puchasingAcceptContent_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
icon="upload-filled"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="excelUploadRef.show()"
|
||||
v-auth="'purchase_puchasingAcceptContent_add'"
|
||||
>
|
||||
导入
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'purchase_puchasingAcceptContent_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_puchasingAcceptContent_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button
|
||||
icon="folder-add"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="formDialogRef.openDialog()"
|
||||
v-auth="'purchase_puchasingAcceptContent_add'"
|
||||
>
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
icon="upload-filled"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="excelUploadRef.show()"
|
||||
v-auth="'purchase_puchasingAcceptContent_add'"
|
||||
>
|
||||
导入
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'purchase_puchasingAcceptContent_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_puchasingAcceptContent_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right;"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
<!-- 数据表格区域 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column prop="remark" label="remark" show-overflow-tooltip />
|
||||
<el-table-column prop="configId" label="配置项ID" show-overflow-tooltip />
|
||||
<el-table-column prop="isQualified" label="是否合格 0:不合格 1:合格" show-overflow-tooltip />
|
||||
<el-table-column prop="acceptBatchId" label="验收批次ID" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_puchasingAcceptContent_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" v-auth="'purchase_puchasingAcceptContent_del'" @click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 数据表格区域 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column
|
||||
prop="remark"
|
||||
label="remark"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="configId"
|
||||
label="配置项ID"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="isQualified"
|
||||
label="是否合格 0:不合格 1:合格"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="acceptBatchId"
|
||||
label="验收批次ID"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_puchasingAcceptContent_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="delete"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_puchasingAcceptContent_del'"
|
||||
@click="handleDelete([scope.row.id])"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
v-bind="state.pagination"
|
||||
/>
|
||||
</div>
|
||||
<!-- 编辑、新增弹窗 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 编辑、新增弹窗 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||
<upload-excel
|
||||
ref="excelUploadRef"
|
||||
title="导入"
|
||||
url="/purchase/puchasingAcceptContent/import"
|
||||
temp-url="/admin/sys-file/local/file/puchasingAcceptContent.xlsx"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
</div>
|
||||
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||
<upload-excel
|
||||
ref="excelUploadRef"
|
||||
title="导入"
|
||||
url="/purchase/puchasingAcceptContent/import"
|
||||
temp-url="/admin/sys-file/local/file/puchasingAcceptContent.xlsx"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemPuchasingAcceptContent">
|
||||
// ========== 导入声明 ==========
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObjs } from "/@/api/purchase/puchasingAcceptContent";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs } from '/@/api/purchase/puchasingAcceptContent';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
|
||||
// ========== 组件声明 ==========
|
||||
@@ -137,54 +104,43 @@ const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
// ========== 字典数据 ==========
|
||||
|
||||
// ========== 组件引用 ==========
|
||||
const formDialogRef = ref(); // 表单弹窗引用
|
||||
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||
const queryRef = ref(); // 查询表单引用
|
||||
const formDialogRef = ref(); // 表单弹窗引用
|
||||
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||
const queryRef = ref(); // 查询表单引用
|
||||
|
||||
// ========== 响应式数据 ==========
|
||||
const showSearch = ref(true); // 是否显示搜索区域
|
||||
const selectObjs = ref([]) as any; // 表格多选数据
|
||||
const multiple = ref(true); // 是否多选
|
||||
const showSearch = ref(true); // 是否显示搜索区域
|
||||
const selectObjs = ref([]) as any; // 表格多选数据
|
||||
const multiple = ref(true); // 是否多选
|
||||
|
||||
// ========== 表格状态 ==========
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {}, // 查询参数
|
||||
pageList: fetchList // 分页查询方法
|
||||
queryForm: {}, // 查询参数
|
||||
pageList: fetchList, // 分页查询方法
|
||||
});
|
||||
|
||||
// ========== Hook引用 ==========
|
||||
// 表格相关Hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state);
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// ========== 方法定义 ==========
|
||||
/**
|
||||
* 重置查询条件
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
// 重新查询
|
||||
getDataList();
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
// 重新查询
|
||||
getDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出Excel文件
|
||||
*/
|
||||
const exportExcel = () => {
|
||||
downBlobFile(
|
||||
'/purchase/puchasingAcceptContent/export',
|
||||
Object.assign(state.queryForm, { ids: selectObjs }),
|
||||
'puchasingAcceptContent.xlsx'
|
||||
);
|
||||
downBlobFile('/purchase/puchasingAcceptContent/export', Object.assign(state.queryForm, { ids: selectObjs }), 'puchasingAcceptContent.xlsx');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -192,8 +148,8 @@ const exportExcel = () => {
|
||||
* @param objs 选中的数据行
|
||||
*/
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -201,18 +157,18 @@ const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
* @param ids 要删除的数据ID数组
|
||||
*/
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,49 +1,48 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="remark" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入remark"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="所在部门编码" prop="deptCode">
|
||||
<el-input v-model="form.deptCode" placeholder="请输入所在部门编码"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="所在部门" prop="deptName">
|
||||
<el-input v-model="form.deptName" placeholder="请输入所在部门"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入姓名"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收批次ID" prop="acceptBatchId">
|
||||
<el-input v-model="form.acceptBatchId" placeholder="请输入验收批次ID"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="remark" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入remark" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="所在部门编码" prop="deptCode">
|
||||
<el-input v-model="form.deptCode" placeholder="请输入所在部门编码" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="所在部门" prop="deptName">
|
||||
<el-input v-model="form.deptName" placeholder="请输入所在部门" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入姓名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收批次ID" prop="acceptBatchId">
|
||||
<el-input v-model="form.acceptBatchId" placeholder="请输入验收批次ID" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PuchasingAcceptTeamDialog">
|
||||
// ========== 1. 导入语句 ==========
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { rule } from '/@/utils/validate';
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj, validateExist } from '/@/api/purchase/puchasingAcceptTeam';
|
||||
|
||||
// ========== 2. 组件定义 ==========
|
||||
@@ -58,79 +57,78 @@ const loading = ref(false); // 加载状态
|
||||
|
||||
// 表单数据对象
|
||||
const form = reactive({
|
||||
id: '', // 主键
|
||||
remark: '', // ${field.fieldComment}
|
||||
deptCode: '', // 所在部门编码
|
||||
deptName: '', // 所在部门
|
||||
name: '', // 姓名
|
||||
acceptBatchId: '', // 验收批次ID
|
||||
id: '', // 主键
|
||||
remark: '', // ${field.fieldComment}
|
||||
deptCode: '', // 所在部门编码
|
||||
deptName: '', // 所在部门
|
||||
name: '', // 姓名
|
||||
acceptBatchId: '', // 验收批次ID
|
||||
});
|
||||
|
||||
// ========== 4. 字典数据处理 ==========
|
||||
|
||||
// ========== 5. 表单校验规则 ==========
|
||||
const dataRules = ref({
|
||||
});
|
||||
const dataRules = ref({});
|
||||
|
||||
// ========== 6. 方法定义 ==========
|
||||
// 获取详情数据
|
||||
const getPuchasingAcceptTeamData = async (id: string) => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } = await getObj({ id: id });
|
||||
// 直接将第一条数据赋值给表单
|
||||
Object.assign(form, data[0]);
|
||||
} catch (error) {
|
||||
useMessage().error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } = await getObj({ id: id });
|
||||
// 直接将第一条数据赋值给表单
|
||||
Object.assign(form, data[0]);
|
||||
} catch (error) {
|
||||
useMessage().error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 打开弹窗方法
|
||||
const openDialog = (id: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取PuchasingAcceptTeam信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getPuchasingAcceptTeamData(id);
|
||||
}
|
||||
// 获取PuchasingAcceptTeam信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getPuchasingAcceptTeamData(id);
|
||||
}
|
||||
};
|
||||
|
||||
// 提交表单方法
|
||||
const onSubmit = async () => {
|
||||
loading.value = true; // 防止重复提交
|
||||
|
||||
// 表单校验
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
loading.value = true; // 防止重复提交
|
||||
|
||||
try {
|
||||
// 根据是否有ID判断是新增还是修改
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh'); // 通知父组件刷新列表
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
// 表单校验
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 根据是否有ID判断是新增还是修改
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh'); // 通知父组件刷新列表
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ========== 7. 对外暴露 ==========
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,138 +1,101 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'purchase_puchasingAcceptTeam_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
icon="upload-filled"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="excelUploadRef.show()"
|
||||
v-auth="'purchase_puchasingAcceptTeam_add'"
|
||||
>
|
||||
导入
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'purchase_puchasingAcceptTeam_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_puchasingAcceptTeam_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button
|
||||
icon="folder-add"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="formDialogRef.openDialog()"
|
||||
v-auth="'purchase_puchasingAcceptTeam_add'"
|
||||
>
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
icon="upload-filled"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="excelUploadRef.show()"
|
||||
v-auth="'purchase_puchasingAcceptTeam_add'"
|
||||
>
|
||||
导入
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'purchase_puchasingAcceptTeam_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_puchasingAcceptTeam_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right;"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
<!-- 数据表格区域 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column prop="remark" label="remark" show-overflow-tooltip />
|
||||
<el-table-column prop="deptCode" label="所在部门编码" show-overflow-tooltip />
|
||||
<el-table-column prop="deptName" label="所在部门" show-overflow-tooltip />
|
||||
<el-table-column prop="name" label="姓名" show-overflow-tooltip />
|
||||
<el-table-column prop="acceptBatchId" label="验收批次ID" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_puchasingAcceptTeam_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" v-auth="'purchase_puchasingAcceptTeam_del'" @click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 数据表格区域 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column
|
||||
prop="remark"
|
||||
label="remark"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="deptCode"
|
||||
label="所在部门编码"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="deptName"
|
||||
label="所在部门"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="姓名"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="acceptBatchId"
|
||||
label="验收批次ID"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_puchasingAcceptTeam_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="delete"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_puchasingAcceptTeam_del'"
|
||||
@click="handleDelete([scope.row.id])"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
v-bind="state.pagination"
|
||||
/>
|
||||
</div>
|
||||
<!-- 编辑、新增弹窗 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 编辑、新增弹窗 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||
<upload-excel
|
||||
ref="excelUploadRef"
|
||||
title="导入"
|
||||
url="/purchase/puchasingAcceptTeam/import"
|
||||
temp-url="/admin/sys-file/local/file/puchasingAcceptTeam.xlsx"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
</div>
|
||||
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||
<upload-excel
|
||||
ref="excelUploadRef"
|
||||
title="导入"
|
||||
url="/purchase/puchasingAcceptTeam/import"
|
||||
temp-url="/admin/sys-file/local/file/puchasingAcceptTeam.xlsx"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemPuchasingAcceptTeam">
|
||||
// ========== 导入声明 ==========
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObjs } from "/@/api/purchase/puchasingAcceptTeam";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs } from '/@/api/purchase/puchasingAcceptTeam';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
|
||||
// ========== 组件声明 ==========
|
||||
@@ -142,54 +105,43 @@ const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
// ========== 字典数据 ==========
|
||||
|
||||
// ========== 组件引用 ==========
|
||||
const formDialogRef = ref(); // 表单弹窗引用
|
||||
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||
const queryRef = ref(); // 查询表单引用
|
||||
const formDialogRef = ref(); // 表单弹窗引用
|
||||
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||
const queryRef = ref(); // 查询表单引用
|
||||
|
||||
// ========== 响应式数据 ==========
|
||||
const showSearch = ref(true); // 是否显示搜索区域
|
||||
const selectObjs = ref([]) as any; // 表格多选数据
|
||||
const multiple = ref(true); // 是否多选
|
||||
const showSearch = ref(true); // 是否显示搜索区域
|
||||
const selectObjs = ref([]) as any; // 表格多选数据
|
||||
const multiple = ref(true); // 是否多选
|
||||
|
||||
// ========== 表格状态 ==========
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {}, // 查询参数
|
||||
pageList: fetchList // 分页查询方法
|
||||
queryForm: {}, // 查询参数
|
||||
pageList: fetchList, // 分页查询方法
|
||||
});
|
||||
|
||||
// ========== Hook引用 ==========
|
||||
// 表格相关Hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state);
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// ========== 方法定义 ==========
|
||||
/**
|
||||
* 重置查询条件
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
// 重新查询
|
||||
getDataList();
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
// 重新查询
|
||||
getDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出Excel文件
|
||||
*/
|
||||
const exportExcel = () => {
|
||||
downBlobFile(
|
||||
'/purchase/puchasingAcceptTeam/export',
|
||||
Object.assign(state.queryForm, { ids: selectObjs }),
|
||||
'puchasingAcceptTeam.xlsx'
|
||||
);
|
||||
downBlobFile('/purchase/puchasingAcceptTeam/export', Object.assign(state.queryForm, { ids: selectObjs }), 'puchasingAcceptTeam.xlsx');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -197,8 +149,8 @@ const exportExcel = () => {
|
||||
* @param objs 选中的数据行
|
||||
*/
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -206,18 +158,18 @@ const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
* @param ids 要删除的数据ID数组
|
||||
*/
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,62 +1,34 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="dataForm.id ? '编辑' : '新增'"
|
||||
v-model="visible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="dataForm"
|
||||
:rules="dataRules"
|
||||
label-width="100px"
|
||||
v-loading="loading">
|
||||
<el-form-item label="代理名称" prop="agentName">
|
||||
<el-input
|
||||
v-model="dataForm.agentName"
|
||||
placeholder="请输入代理名称"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人" prop="contactPerson">
|
||||
<el-input
|
||||
v-model="dataForm.contactPerson"
|
||||
placeholder="请输入联系人"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话" prop="contactPhone">
|
||||
<el-input
|
||||
v-model="dataForm.contactPhone"
|
||||
placeholder="请输入联系电话"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="登录用户名" prop="username">
|
||||
<el-input
|
||||
v-model="dataForm.username"
|
||||
placeholder="请输入登录用户名(不填则自动生成)"
|
||||
clearable
|
||||
:disabled="!!dataForm.id" />
|
||||
<div class="form-tip" v-if="!dataForm.id">新增时自动创建系统用户,默认密码:Aa123456,角色:招标代理</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="dataForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="dataForm.id ? '编辑' : '新增'" v-model="visible" width="600px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="formRef" :model="dataForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item label="代理名称" prop="agentName">
|
||||
<el-input v-model="dataForm.agentName" placeholder="请输入代理名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人" prop="contactPerson">
|
||||
<el-input v-model="dataForm.contactPerson" placeholder="请输入联系人" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话" prop="contactPhone">
|
||||
<el-input v-model="dataForm.contactPhone" placeholder="请输入联系电话" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="登录用户名" prop="username">
|
||||
<el-input v-model="dataForm.username" placeholder="请输入登录用户名(不填则自动生成)" clearable :disabled="!!dataForm.id" />
|
||||
<div class="form-tip" v-if="!dataForm.id">新增时自动创建系统用户,默认密码:Aa123456,角色:招标代理</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="dataForm.remark" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchaseAgentForm">
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { getObj, addObj, editObj } from '/@/api/purchase/purchaseagent';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
|
||||
@@ -66,97 +38,96 @@ const emit = defineEmits(['refresh']);
|
||||
// 定义变量内容
|
||||
const formRef = ref();
|
||||
const dataForm = reactive({
|
||||
id: '',
|
||||
agentName: '',
|
||||
contactPerson: '',
|
||||
contactPhone: '',
|
||||
username: '',
|
||||
remark: '',
|
||||
id: '',
|
||||
agentName: '',
|
||||
contactPerson: '',
|
||||
contactPhone: '',
|
||||
username: '',
|
||||
remark: '',
|
||||
});
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const dataRules = ref({
|
||||
agentName: [
|
||||
{ required: true, message: '请输入代理名称', trigger: 'blur' }
|
||||
],
|
||||
agentName: [{ required: true, message: '请输入代理名称', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = async (type: string, rowData?: any) => {
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.agentName = '';
|
||||
dataForm.contactPerson = '';
|
||||
dataForm.contactPhone = '';
|
||||
dataForm.username = '';
|
||||
dataForm.remark = '';
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.agentName = '';
|
||||
dataForm.contactPerson = '';
|
||||
dataForm.contactPhone = '';
|
||||
dataForm.username = '';
|
||||
dataForm.remark = '';
|
||||
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'edit' && rowData?.id) {
|
||||
// 编辑时,先获取详情数据
|
||||
loading.value = true;
|
||||
getObj(rowData.id).then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(dataForm, {
|
||||
id: res.data.id || '',
|
||||
agentName: res.data.agentName || '',
|
||||
contactPerson: res.data.contactPerson || '',
|
||||
contactPhone: res.data.contactPhone || '',
|
||||
username: res.data.username || '',
|
||||
remark: res.data.remark || '',
|
||||
});
|
||||
}
|
||||
loading.value = false;
|
||||
}).catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'edit' && rowData?.id) {
|
||||
// 编辑时,先获取详情数据
|
||||
loading.value = true;
|
||||
getObj(rowData.id)
|
||||
.then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(dataForm, {
|
||||
id: res.data.id || '',
|
||||
agentName: res.data.agentName || '',
|
||||
contactPerson: res.data.contactPerson || '',
|
||||
contactPhone: res.data.contactPhone || '',
|
||||
username: res.data.username || '',
|
||||
remark: res.data.remark || '',
|
||||
});
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dataForm.id) {
|
||||
await editObj(dataForm);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(dataForm);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
if (dataForm.id) {
|
||||
await editObj(dataForm);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(dataForm);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-tip {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,230 +1,185 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="代理名称" prop="agentName">
|
||||
<el-input
|
||||
v-model="state.queryForm.agentName"
|
||||
placeholder="请输入代理名称"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="代理名称" prop="agentName">
|
||||
<el-input v-model="state.queryForm.agentName" placeholder="请输入代理名称" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
招标代理管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="Files"
|
||||
link
|
||||
type="primary"
|
||||
@click="openSummaryDialog"
|
||||
>
|
||||
代理汇总
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="FolderAdd"
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog('add')"
|
||||
v-auth="'purchase_purchasingagent_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
招标代理管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="Files" link type="primary" @click="openSummaryDialog"> 代理汇总 </el-button>
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog('add')" v-auth="'purchase_purchasingagent_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="agentName" label="代理名称" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Document /></el-icon>
|
||||
<span style="margin-left: 4px">代理名称</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contactPerson" label="联系人" width="120" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">联系人</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contactPhone" label="联系电话" width="140" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Phone /></el-icon>
|
||||
<span style="margin-left: 4px">联系电话</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="登录用户名" width="140" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">登录用户名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="Edit"
|
||||
link
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingagent_edit'"
|
||||
@click="formDialogRef.openDialog('edit', scope.row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Delete"
|
||||
link
|
||||
type="danger"
|
||||
v-auth="'purchase_purchasingagent_del'"
|
||||
@click="handleDelete(scope.row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="agentName" label="代理名称" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Document /></el-icon>
|
||||
<span style="margin-left: 4px">代理名称</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contactPerson" label="联系人" width="120" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">联系人</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contactPhone" label="联系电话" width="140" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Phone /></el-icon>
|
||||
<span style="margin-left: 4px">联系电话</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="登录用户名" width="140" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">登录用户名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="Edit"
|
||||
link
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingagent_edit'"
|
||||
@click="formDialogRef.openDialog('edit', scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button icon="Delete" link type="danger" v-auth="'purchase_purchasingagent_del'" @click="handleDelete(scope.row)"> 删除 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-show="state.total > 0"
|
||||
:total="state.total"
|
||||
v-model:page="state.page"
|
||||
v-model:limit="state.limit"
|
||||
@pagination="getDataList"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<pagination v-show="state.total > 0" :total="state.total" v-model:page="state.page" v-model:limit="state.limit" @pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
|
||||
<!-- 代理汇总弹窗 -->
|
||||
<el-dialog
|
||||
v-model="summaryDialogVisible"
|
||||
title="代理数据汇总"
|
||||
width="85%"
|
||||
destroy-on-close
|
||||
class="agent-summary-dialog"
|
||||
>
|
||||
<el-form :model="summaryQuery" inline class="summary-query-form">
|
||||
<el-form-item label="需求部门">
|
||||
<el-select
|
||||
v-model="summaryQuery.deptCode"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 200px"
|
||||
>
|
||||
<el-option v-for="d in deptOptions" :key="d.value" :label="d.label" :value="d.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="计划采购开始时间">
|
||||
<el-date-picker
|
||||
v-model="summaryQuery.planStartDate"
|
||||
type="date"
|
||||
placeholder="请选择"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 180px"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="计划采购结束时间">
|
||||
<el-date-picker
|
||||
v-model="summaryQuery.planEndDate"
|
||||
type="date"
|
||||
placeholder="请选择"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 180px"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否履约评价">
|
||||
<el-select v-model="summaryQuery.hasAcceptEvaluation" placeholder="请选择" clearable style="width: 140px">
|
||||
<el-option label="已履约评价" value="1" />
|
||||
<el-option label="未履约评价" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="querySummary">查询</el-button>
|
||||
<el-button @click="clearSummaryQuery">清空</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table
|
||||
:data="summaryList"
|
||||
v-loading="summaryLoading"
|
||||
border
|
||||
stripe
|
||||
max-height="400"
|
||||
class="summary-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="agentName" label="代理机构" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="projectCount" label="代理项目" width="100" align="center" />
|
||||
<el-table-column prop="budgetAmount" label="预算金额" width="140" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ formatMoney(row.budgetAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contractAmount" label="合同(成交)金额" width="140" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ formatMoney(row.contractAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<!-- 代理汇总弹窗 -->
|
||||
<el-dialog v-model="summaryDialogVisible" title="代理数据汇总" width="85%" destroy-on-close class="agent-summary-dialog">
|
||||
<el-form :model="summaryQuery" inline class="summary-query-form">
|
||||
<el-form-item label="需求部门">
|
||||
<el-select v-model="summaryQuery.deptCode" placeholder="请选择" clearable filterable style="width: 200px">
|
||||
<el-option v-for="d in deptOptions" :key="d.value" :label="d.label" :value="d.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="计划采购开始时间">
|
||||
<el-date-picker
|
||||
v-model="summaryQuery.planStartDate"
|
||||
type="date"
|
||||
placeholder="请选择"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 180px"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="计划采购结束时间">
|
||||
<el-date-picker
|
||||
v-model="summaryQuery.planEndDate"
|
||||
type="date"
|
||||
placeholder="请选择"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 180px"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否履约评价">
|
||||
<el-select v-model="summaryQuery.hasAcceptEvaluation" placeholder="请选择" clearable style="width: 140px">
|
||||
<el-option label="已履约评价" value="1" />
|
||||
<el-option label="未履约评价" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="querySummary">查询</el-button>
|
||||
<el-button @click="clearSummaryQuery">清空</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="summaryList" v-loading="summaryLoading" border stripe max-height="400" class="summary-table">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="agentName" label="代理机构" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="projectCount" label="代理项目" width="100" align="center" />
|
||||
<el-table-column prop="budgetAmount" label="预算金额" width="140" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ formatMoney(row.budgetAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contractAmount" label="合同(成交)金额" width="140" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ formatMoney(row.contractAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchaseAgent">
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { getPage, delObj, getAgentSummary } from "/@/api/purchase/purchaseagent";
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { getPage, delObj, getAgentSummary } from '/@/api/purchase/purchaseagent';
|
||||
import { deptTree } from '/@/api/admin/dept';
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { List, Document, EditPen, Clock, Search, User, Phone, UserFilled } from '@element-plus/icons-vue'
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { List, Document, EditPen, Clock, Search, User, Phone, UserFilled } from '@element-plus/icons-vue';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
@@ -234,86 +189,86 @@ const summaryDialogVisible = ref(false);
|
||||
const summaryLoading = ref(false);
|
||||
const summaryList = ref<any[]>([]);
|
||||
const summaryQuery = reactive({
|
||||
deptCode: '',
|
||||
planStartDate: '',
|
||||
planEndDate: '',
|
||||
hasAcceptEvaluation: '',
|
||||
deptCode: '',
|
||||
planStartDate: '',
|
||||
planEndDate: '',
|
||||
hasAcceptEvaluation: '',
|
||||
});
|
||||
const deptOptions = ref<{ label: string; value: string }[]>([]);
|
||||
|
||||
const flattenDept = (nodes: any[], list: { label: string; value: string }[]) => {
|
||||
if (!nodes || !Array.isArray(nodes)) return;
|
||||
nodes.forEach((n: any) => {
|
||||
const code = n.deptId ?? n.id ?? n.deptCode;
|
||||
const name = n.name ?? n.deptName ?? '';
|
||||
if (code != null && String(code)) list.push({ label: name || String(code), value: String(code) });
|
||||
if (n.children?.length) flattenDept(n.children, list);
|
||||
});
|
||||
if (!nodes || !Array.isArray(nodes)) return;
|
||||
nodes.forEach((n: any) => {
|
||||
const code = n.deptId ?? n.id ?? n.deptCode;
|
||||
const name = n.name ?? n.deptName ?? '';
|
||||
if (code != null && String(code)) list.push({ label: name || String(code), value: String(code) });
|
||||
if (n.children?.length) flattenDept(n.children, list);
|
||||
});
|
||||
};
|
||||
|
||||
const openSummaryDialog = async () => {
|
||||
summaryDialogVisible.value = true;
|
||||
if (deptOptions.value.length === 0) {
|
||||
try {
|
||||
const res = await deptTree();
|
||||
const tree = res?.data ?? res ?? [];
|
||||
const list: { label: string; value: string }[] = [];
|
||||
flattenDept(Array.isArray(tree) ? tree : [], list);
|
||||
deptOptions.value = list;
|
||||
} catch (_) {
|
||||
deptOptions.value = [];
|
||||
}
|
||||
}
|
||||
querySummary();
|
||||
summaryDialogVisible.value = true;
|
||||
if (deptOptions.value.length === 0) {
|
||||
try {
|
||||
const res = await deptTree();
|
||||
const tree = res?.data ?? res ?? [];
|
||||
const list: { label: string; value: string }[] = [];
|
||||
flattenDept(Array.isArray(tree) ? tree : [], list);
|
||||
deptOptions.value = list;
|
||||
} catch (_) {
|
||||
deptOptions.value = [];
|
||||
}
|
||||
}
|
||||
querySummary();
|
||||
};
|
||||
|
||||
const querySummary = async () => {
|
||||
summaryLoading.value = true;
|
||||
try {
|
||||
const res = await getAgentSummary({
|
||||
deptCode: summaryQuery.deptCode || undefined,
|
||||
planStartDate: summaryQuery.planStartDate || undefined,
|
||||
planEndDate: summaryQuery.planEndDate || undefined,
|
||||
hasAcceptEvaluation: summaryQuery.hasAcceptEvaluation || undefined,
|
||||
});
|
||||
summaryList.value = res?.data && Array.isArray(res.data) ? res.data : [];
|
||||
} catch (_) {
|
||||
summaryList.value = [];
|
||||
} finally {
|
||||
summaryLoading.value = false;
|
||||
}
|
||||
summaryLoading.value = true;
|
||||
try {
|
||||
const res = await getAgentSummary({
|
||||
deptCode: summaryQuery.deptCode || undefined,
|
||||
planStartDate: summaryQuery.planStartDate || undefined,
|
||||
planEndDate: summaryQuery.planEndDate || undefined,
|
||||
hasAcceptEvaluation: summaryQuery.hasAcceptEvaluation || undefined,
|
||||
});
|
||||
summaryList.value = res?.data && Array.isArray(res.data) ? res.data : [];
|
||||
} catch (_) {
|
||||
summaryList.value = [];
|
||||
} finally {
|
||||
summaryLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const clearSummaryQuery = () => {
|
||||
summaryQuery.deptCode = '';
|
||||
summaryQuery.planStartDate = '';
|
||||
summaryQuery.planEndDate = '';
|
||||
summaryQuery.hasAcceptEvaluation = '';
|
||||
querySummary();
|
||||
summaryQuery.deptCode = '';
|
||||
summaryQuery.planStartDate = '';
|
||||
summaryQuery.planEndDate = '';
|
||||
summaryQuery.hasAcceptEvaluation = '';
|
||||
querySummary();
|
||||
};
|
||||
|
||||
const formatMoney = (v: any) => {
|
||||
if (v == null || v === '') return '—';
|
||||
const n = Number(v);
|
||||
if (Number.isNaN(n)) return String(v);
|
||||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 0, maximumFractionDigits: 2 });
|
||||
if (v == null || v === '') return '—';
|
||||
const n = Number(v);
|
||||
if (Number.isNaN(n)) return String(v);
|
||||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 0, maximumFractionDigits: 2 });
|
||||
};
|
||||
|
||||
// 定义变量内容
|
||||
const tableRef = ref()
|
||||
const formDialogRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const tableRef = ref();
|
||||
const formDialogRef = ref();
|
||||
const searchFormRef = ref();
|
||||
const showSearch = ref(true);
|
||||
|
||||
/**
|
||||
* 定义响应式表格数据
|
||||
*/
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
agentName: '',
|
||||
},
|
||||
createdIsNeed: true
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
agentName: '',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -325,8 +280,8 @@ const { getDataList, tableStyle } = useTable(state);
|
||||
* 重置搜索表单
|
||||
*/
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -334,27 +289,26 @@ const handleReset = () => {
|
||||
* @param row - 当前行数据
|
||||
*/
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj({"id":row.id});
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObj({ id: row.id });
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,64 +1,63 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="采购人员" prop="purchaserName">
|
||||
<el-input v-model="form.purchaserName" placeholder="请输入采购人员" disabled/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="资产管理员" prop="assetAdminName">
|
||||
<el-input v-model="form.assetAdminName" placeholder="请输入资产管理员" disabled/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="remark" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入remark"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="采购申请ID" prop="purchaseId">
|
||||
<el-input v-model="form.purchaseId" placeholder="请输入采购申请ID"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收日期" prop="acceptDate">
|
||||
<el-input v-model="form.acceptDate" placeholder="请输入验收日期"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收地点" prop="acceptAddress">
|
||||
<el-input v-model="form.acceptAddress" placeholder="请输入验收地点"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收批次" prop="batch">
|
||||
<el-input v-model="form.batch" placeholder="请输入验收批次"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="问题意见" prop="question">
|
||||
<el-input v-model="form.question" placeholder="请输入问题意见"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="采购人员" prop="purchaserName">
|
||||
<el-input v-model="form.purchaserName" placeholder="请输入采购人员" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="资产管理员" prop="assetAdminName">
|
||||
<el-input v-model="form.assetAdminName" placeholder="请输入资产管理员" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="remark" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入remark" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="采购申请ID" prop="purchaseId">
|
||||
<el-input v-model="form.purchaseId" placeholder="请输入采购申请ID" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收日期" prop="acceptDate">
|
||||
<el-input v-model="form.acceptDate" placeholder="请输入验收日期" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收地点" prop="acceptAddress">
|
||||
<el-input v-model="form.acceptAddress" placeholder="请输入验收地点" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="验收批次" prop="batch">
|
||||
<el-input v-model="form.batch" placeholder="请输入验收批次" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="问题意见" prop="question">
|
||||
<el-input v-model="form.question" placeholder="请输入问题意见" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingAcceptDialog">
|
||||
// ========== 1. 导入语句 ==========
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { rule } from '/@/utils/validate';
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj, validateExist, getCommonConfigWithBatches } from '/@/api/purchase/purchasingAccept';
|
||||
|
||||
// ========== 2. 组件定义 ==========
|
||||
@@ -73,95 +72,94 @@ const loading = ref(false); // 加载状态
|
||||
|
||||
// 表单数据对象
|
||||
const form = reactive({
|
||||
id: '', // 主键
|
||||
remark: '', // ${field.fieldComment}
|
||||
purchaseId: '', // 采购申请ID
|
||||
acceptDate: '', // 验收日期
|
||||
acceptAddress: '', // 验收地点
|
||||
batch: '', // 验收批次
|
||||
question: '', // 问题意见
|
||||
purchaserId: '', // 采购人员ID
|
||||
purchaserName: '', // 采购人员姓名
|
||||
assetAdminId: '', // 资产管理员ID
|
||||
assetAdminName: '', // 资产管理员姓名
|
||||
id: '', // 主键
|
||||
remark: '', // ${field.fieldComment}
|
||||
purchaseId: '', // 采购申请ID
|
||||
acceptDate: '', // 验收日期
|
||||
acceptAddress: '', // 验收地点
|
||||
batch: '', // 验收批次
|
||||
question: '', // 问题意见
|
||||
purchaserId: '', // 采购人员ID
|
||||
purchaserName: '', // 采购人员姓名
|
||||
assetAdminId: '', // 资产管理员ID
|
||||
assetAdminName: '', // 资产管理员姓名
|
||||
});
|
||||
|
||||
// ========== 4. 字典数据处理 ==========
|
||||
|
||||
// ========== 5. 表单校验规则 ==========
|
||||
const dataRules = ref({
|
||||
});
|
||||
const dataRules = ref({});
|
||||
|
||||
// ========== 6. 方法定义 ==========
|
||||
// 获取详情数据
|
||||
const getPurchasingAcceptData = async (id: string) => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } = await getObj({ id: id });
|
||||
// 直接将第一条数据赋值给表单
|
||||
Object.assign(form, data[0]);
|
||||
|
||||
// 获取采购人员和资产管理员信息
|
||||
if (form.purchaseId) {
|
||||
const { data: commonData } = await getCommonConfigWithBatches(form.purchaseId);
|
||||
if (commonData && commonData.common) {
|
||||
form.purchaserId = commonData.common.purchaserId || '';
|
||||
form.purchaserName = commonData.common.purchaserName || '';
|
||||
form.assetAdminId = commonData.common.assetAdminId || '';
|
||||
form.assetAdminName = commonData.common.assetAdminName || '';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
useMessage().error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } = await getObj({ id: id });
|
||||
// 直接将第一条数据赋值给表单
|
||||
Object.assign(form, data[0]);
|
||||
|
||||
// 获取采购人员和资产管理员信息
|
||||
if (form.purchaseId) {
|
||||
const { data: commonData } = await getCommonConfigWithBatches(form.purchaseId);
|
||||
if (commonData && commonData.common) {
|
||||
form.purchaserId = commonData.common.purchaserId || '';
|
||||
form.purchaserName = commonData.common.purchaserName || '';
|
||||
form.assetAdminId = commonData.common.assetAdminId || '';
|
||||
form.assetAdminName = commonData.common.assetAdminName || '';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
useMessage().error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 打开弹窗方法
|
||||
const openDialog = (id: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取PurchasingAccept信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getPurchasingAcceptData(id);
|
||||
}
|
||||
// 获取PurchasingAccept信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getPurchasingAcceptData(id);
|
||||
}
|
||||
};
|
||||
|
||||
// 提交表单方法
|
||||
const onSubmit = async () => {
|
||||
loading.value = true; // 防止重复提交
|
||||
|
||||
// 表单校验
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
loading.value = true; // 防止重复提交
|
||||
|
||||
try {
|
||||
// 根据是否有ID判断是新增还是修改
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh'); // 通知父组件刷新列表
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
// 表单校验
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 根据是否有ID判断是新增还是修改
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh'); // 通知父组件刷新列表
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ========== 7. 对外暴露 ==========
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,143 +1,89 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'purchase_purchasingAccept_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button plain icon="upload-filled" type="primary" class="ml10" @click="excelUploadRef.show()" v-auth="'purchase_purchasingAccept_add'">
|
||||
导入
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingAccept_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_purchasingAccept_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button
|
||||
icon="folder-add"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="formDialogRef.openDialog()"
|
||||
v-auth="'purchase_purchasingAccept_add'"
|
||||
>
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
icon="upload-filled"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="excelUploadRef.show()"
|
||||
v-auth="'purchase_purchasingAccept_add'"
|
||||
>
|
||||
导入
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingAccept_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_purchasingAccept_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right;"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
<!-- 数据表格区域 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column prop="remark" label="remark" show-overflow-tooltip />
|
||||
<el-table-column prop="purchaseId" label="采购申请ID" show-overflow-tooltip />
|
||||
<el-table-column prop="acceptDate" label="验收日期" show-overflow-tooltip />
|
||||
<el-table-column prop="acceptAddress" label="验收地点" show-overflow-tooltip />
|
||||
<el-table-column prop="batch" label="验收批次" show-overflow-tooltip />
|
||||
<el-table-column prop="question" label="问题意见" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="edit-pen" text type="primary" v-auth="'purchase_purchasingAccept_edit'" @click="formDialogRef.openDialog(scope.row.id)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" v-auth="'purchase_purchasingAccept_del'" @click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 数据表格区域 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column
|
||||
prop="remark"
|
||||
label="remark"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="purchaseId"
|
||||
label="采购申请ID"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="acceptDate"
|
||||
label="验收日期"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="acceptAddress"
|
||||
label="验收地点"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="batch"
|
||||
label="验收批次"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="question"
|
||||
label="问题意见"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingAccept_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="delete"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingAccept_del'"
|
||||
@click="handleDelete([scope.row.id])"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
v-bind="state.pagination"
|
||||
/>
|
||||
</div>
|
||||
<!-- 编辑、新增弹窗 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 编辑、新增弹窗 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||
<upload-excel
|
||||
ref="excelUploadRef"
|
||||
title="导入"
|
||||
url="/purchase/purchasingAccept/import"
|
||||
temp-url="/admin/sys-file/local/file/purchasingAccept.xlsx"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
</div>
|
||||
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||
<upload-excel
|
||||
ref="excelUploadRef"
|
||||
title="导入"
|
||||
url="/purchase/purchasingAccept/import"
|
||||
temp-url="/admin/sys-file/local/file/purchasingAccept.xlsx"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemPurchasingAccept">
|
||||
// ========== 导入声明 ==========
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObjs } from "/@/api/purchase/purchasingAccept";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs } from '/@/api/purchase/purchasingAccept';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
|
||||
// ========== 组件声明 ==========
|
||||
@@ -147,54 +93,43 @@ const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
// ========== 字典数据 ==========
|
||||
|
||||
// ========== 组件引用 ==========
|
||||
const formDialogRef = ref(); // 表单弹窗引用
|
||||
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||
const queryRef = ref(); // 查询表单引用
|
||||
const formDialogRef = ref(); // 表单弹窗引用
|
||||
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||
const queryRef = ref(); // 查询表单引用
|
||||
|
||||
// ========== 响应式数据 ==========
|
||||
const showSearch = ref(true); // 是否显示搜索区域
|
||||
const selectObjs = ref([]) as any; // 表格多选数据
|
||||
const multiple = ref(true); // 是否多选
|
||||
const showSearch = ref(true); // 是否显示搜索区域
|
||||
const selectObjs = ref([]) as any; // 表格多选数据
|
||||
const multiple = ref(true); // 是否多选
|
||||
|
||||
// ========== 表格状态 ==========
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {}, // 查询参数
|
||||
pageList: fetchList // 分页查询方法
|
||||
queryForm: {}, // 查询参数
|
||||
pageList: fetchList, // 分页查询方法
|
||||
});
|
||||
|
||||
// ========== Hook引用 ==========
|
||||
// 表格相关Hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state);
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// ========== 方法定义 ==========
|
||||
/**
|
||||
* 重置查询条件
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
// 重新查询
|
||||
getDataList();
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
// 重新查询
|
||||
getDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出Excel文件
|
||||
*/
|
||||
const exportExcel = () => {
|
||||
downBlobFile(
|
||||
'/purchase/purchasingAccept/export',
|
||||
Object.assign(state.queryForm, { ids: selectObjs }),
|
||||
'purchasingAccept.xlsx'
|
||||
);
|
||||
downBlobFile('/purchase/purchasingAccept/export', Object.assign(state.queryForm, { ids: selectObjs }), 'purchasingAccept.xlsx');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -202,8 +137,8 @@ const exportExcel = () => {
|
||||
* @param objs 选中的数据行
|
||||
*/
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -211,18 +146,18 @@ const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
* @param ids 要删除的数据ID数组
|
||||
*/
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,95 +1,59 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="form.id ? '编辑' : '新增'"
|
||||
v-model="visible"
|
||||
width="700px"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="form"
|
||||
:rules="dataRules"
|
||||
label-width="120px"
|
||||
v-loading="loading">
|
||||
<el-form-item label="选择人员" prop="userId">
|
||||
<el-select
|
||||
v-model="form.userId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchUser"
|
||||
:loading="userLoading"
|
||||
style="width: 100%"
|
||||
@change="handleUserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px;">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input
|
||||
v-model="form.name"
|
||||
placeholder="选择人员后自动填充"
|
||||
readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input
|
||||
v-model="form.username"
|
||||
placeholder="选择人员后自动填充"
|
||||
readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门" prop="deptId">
|
||||
<el-select
|
||||
v-model="form.deptId"
|
||||
placeholder="请选择部门"
|
||||
filterable
|
||||
clearable
|
||||
style="width: 100%"
|
||||
@change="handleDeptChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptOptions"
|
||||
:key="item.deptId"
|
||||
:label="item.deptName"
|
||||
:value="item.deptId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input
|
||||
v-model="form.deptName"
|
||||
placeholder="选择部门后自动填充"
|
||||
readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" width="700px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="120px" v-loading="loading">
|
||||
<el-form-item label="选择人员" prop="userId">
|
||||
<el-select
|
||||
v-model="form.userId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchUser"
|
||||
:loading="userLoading"
|
||||
style="width: 100%"
|
||||
@change="handleUserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="form.name" placeholder="选择人员后自动填充" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input v-model="form.username" placeholder="选择人员后自动填充" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门" prop="deptId">
|
||||
<el-select v-model="form.deptId" placeholder="请选择部门" filterable clearable style="width: 100%" @change="handleDeptChange">
|
||||
<el-option v-for="item in deptOptions" :key="item.deptId" :label="item.deptName" :value="item.deptId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input v-model="form.deptName" placeholder="选择部门后自动填充" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingBusinessDeptForm">
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { getObj, addObj, putObj } from '/@/api/purchase/purchasingBusinessDept';
|
||||
import { searchTeachers, getSecondDeptList } from '/@/api/purchase/purchasingrequisition';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
@@ -101,158 +65,151 @@ const deptOptions = ref<any[]>([]);
|
||||
const userOptions = ref<any[]>([]);
|
||||
const userLoading = ref(false);
|
||||
const form = reactive({
|
||||
id: '',
|
||||
deptId: '',
|
||||
deptName: '',
|
||||
userId: '',
|
||||
username: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
id: '',
|
||||
deptId: '',
|
||||
deptName: '',
|
||||
userId: '',
|
||||
username: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
});
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const dataRules = ref({
|
||||
userId: [
|
||||
{ required: true, message: '请选择人员', trigger: 'change' }
|
||||
],
|
||||
deptId: [
|
||||
{ required: true, message: '请选择部门', trigger: 'change' }
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '请先选择人员', trigger: 'blur' }
|
||||
],
|
||||
username: [
|
||||
{ required: true, message: '请先选择人员', trigger: 'blur' }
|
||||
],
|
||||
userId: [{ required: true, message: '请选择人员', trigger: 'change' }],
|
||||
deptId: [{ required: true, message: '请选择部门', trigger: 'change' }],
|
||||
name: [{ required: true, message: '请先选择人员', trigger: 'blur' }],
|
||||
username: [{ required: true, message: '请先选择人员', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
const loadDeptOptions = async () => {
|
||||
try {
|
||||
const res = await getSecondDeptList();
|
||||
deptOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
deptOptions.value = [];
|
||||
}
|
||||
try {
|
||||
const res = await getSecondDeptList();
|
||||
deptOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
deptOptions.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
const searchUser = async (query: string) => {
|
||||
if (!query) {
|
||||
userOptions.value = [];
|
||||
return;
|
||||
}
|
||||
userLoading.value = true;
|
||||
try {
|
||||
const res = await searchTeachers(query);
|
||||
userOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
userOptions.value = [];
|
||||
} finally {
|
||||
userLoading.value = false;
|
||||
}
|
||||
if (!query) {
|
||||
userOptions.value = [];
|
||||
return;
|
||||
}
|
||||
userLoading.value = true;
|
||||
try {
|
||||
const res = await searchTeachers(query);
|
||||
userOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
userOptions.value = [];
|
||||
} finally {
|
||||
userLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeptChange = (deptId: string) => {
|
||||
if (!deptId) {
|
||||
form.deptId = '';
|
||||
form.deptName = '';
|
||||
return;
|
||||
}
|
||||
const selected = deptOptions.value.find((item: any) => item.deptId === deptId);
|
||||
if (selected) {
|
||||
form.deptId = selected.deptId;
|
||||
form.deptName = selected.deptName;
|
||||
}
|
||||
if (!deptId) {
|
||||
form.deptId = '';
|
||||
form.deptName = '';
|
||||
return;
|
||||
}
|
||||
const selected = deptOptions.value.find((item: any) => item.deptId === deptId);
|
||||
if (selected) {
|
||||
form.deptId = selected.deptId;
|
||||
form.deptName = selected.deptName;
|
||||
}
|
||||
};
|
||||
|
||||
const handleUserChange = (teacherNo: string) => {
|
||||
if (!teacherNo) {
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
return;
|
||||
}
|
||||
const selected = userOptions.value.find((item: any) => item.teacherNo === teacherNo);
|
||||
if (selected) {
|
||||
form.userId = selected.teacherNo;
|
||||
form.username = selected.teacherNo;
|
||||
form.name = selected.realName || selected.name;
|
||||
}
|
||||
if (!teacherNo) {
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
return;
|
||||
}
|
||||
const selected = userOptions.value.find((item: any) => item.teacherNo === teacherNo);
|
||||
if (selected) {
|
||||
form.userId = selected.teacherNo;
|
||||
form.username = selected.teacherNo;
|
||||
form.name = selected.realName || selected.name;
|
||||
}
|
||||
};
|
||||
|
||||
const openDialog = async (id?: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
form.deptId = '';
|
||||
form.deptName = '';
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
form.remark = '';
|
||||
userOptions.value = [];
|
||||
|
||||
await loadDeptOptions();
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
form.deptId = '';
|
||||
form.deptName = '';
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
form.remark = '';
|
||||
userOptions.value = [];
|
||||
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
if (id) {
|
||||
loading.value = true;
|
||||
getObj({ id }).then((res: any) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
const data = res.data[0];
|
||||
Object.assign(form, {
|
||||
id: data.id || '',
|
||||
deptId: data.deptId || '',
|
||||
deptName: data.deptName || '',
|
||||
userId: data.userId || '',
|
||||
username: data.username || '',
|
||||
name: data.name || '',
|
||||
remark: data.remark || '',
|
||||
});
|
||||
if (form.userId) {
|
||||
userOptions.value = [{ teacherNo: form.userId, realName: form.name, name: form.name }];
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
}).catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
await loadDeptOptions();
|
||||
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
if (id) {
|
||||
loading.value = true;
|
||||
getObj({ id })
|
||||
.then((res: any) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
const data = res.data[0];
|
||||
Object.assign(form, {
|
||||
id: data.id || '',
|
||||
deptId: data.deptId || '',
|
||||
deptName: data.deptName || '',
|
||||
userId: data.userId || '',
|
||||
username: data.username || '',
|
||||
name: data.name || '',
|
||||
remark: data.remark || '',
|
||||
});
|
||||
if (form.userId) {
|
||||
userOptions.value = [{ teacherNo: form.userId, realName: form.name, name: form.name }];
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (form.id) {
|
||||
await putObj(form);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(form);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (form.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
if (form.id) {
|
||||
await putObj(form);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(form);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (form.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,249 +1,220 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input
|
||||
v-model="state.queryForm.deptName"
|
||||
placeholder="请输入部门名称"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input
|
||||
v-model="state.queryForm.username"
|
||||
placeholder="请输入用户工号"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input
|
||||
v-model="state.queryForm.name"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input v-model="state.queryForm.deptName" placeholder="请输入部门名称" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input v-model="state.queryForm.username" placeholder="请输入用户工号" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="state.queryForm.name" placeholder="请输入姓名" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
业务分管处室及人员
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="FolderAdd"
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog()"
|
||||
v-auth="'purchase_purchasingBusinessDept_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<!-- <el-button -->
|
||||
<!-- plain -->
|
||||
<!-- icon="UploadFilled" -->
|
||||
<!-- type="primary" -->
|
||||
<!-- class="ml10" -->
|
||||
<!-- @click="excelUploadRef.show()" -->
|
||||
<!-- v-auth="'purchase_purchasingBusinessDept_add'">-->
|
||||
<!-- 导入-->
|
||||
<!-- </el-button>-->
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
v-auth="'purchase_purchasingBusinessDept_del'"
|
||||
@click="handleDelete(selectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_purchasingBusinessDept_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10"
|
||||
@queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
业务分管处室及人员
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog()" v-auth="'purchase_purchasingBusinessDept_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<!-- <el-button -->
|
||||
<!-- plain -->
|
||||
<!-- icon="UploadFilled" -->
|
||||
<!-- type="primary" -->
|
||||
<!-- class="ml10" -->
|
||||
<!-- @click="excelUploadRef.show()" -->
|
||||
<!-- v-auth="'purchase_purchasingBusinessDept_add'">-->
|
||||
<!-- 导入-->
|
||||
<!-- </el-button>-->
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
v-auth="'purchase_purchasingBusinessDept_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_purchasingBusinessDept_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
class="modern-table">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deptName" label="部门名称" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><OfficeBuilding /></el-icon>
|
||||
<span style="margin-left: 4px">部门名称</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="姓名" min-width="120" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">姓名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="用户工号" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">用户工号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="300" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<!-- <el-button -->
|
||||
<!-- icon="Edit" -->
|
||||
<!-- link -->
|
||||
<!-- type="primary" -->
|
||||
<!-- v-auth="'purchase_purchasingBusinessDept_edit'"-->
|
||||
<!-- @click="formDialogRef.openDialog(scope.row.id)">-->
|
||||
<!-- 编辑-->
|
||||
<!-- </el-button>-->
|
||||
<el-button
|
||||
icon="Delete"
|
||||
link
|
||||
type="danger"
|
||||
v-auth="'purchase_purchasingBusinessDept_del'"
|
||||
@click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deptName" label="部门名称" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><OfficeBuilding /></el-icon>
|
||||
<span style="margin-left: 4px">部门名称</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="姓名" min-width="120" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">姓名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="用户工号" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">用户工号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="300" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<!-- <el-button -->
|
||||
<!-- icon="Edit" -->
|
||||
<!-- link -->
|
||||
<!-- type="primary" -->
|
||||
<!-- v-auth="'purchase_purchasingBusinessDept_edit'"-->
|
||||
<!-- @click="formDialogRef.openDialog(scope.row.id)">-->
|
||||
<!-- 编辑-->
|
||||
<!-- </el-button>-->
|
||||
<el-button icon="Delete" link type="danger" v-auth="'purchase_purchasingBusinessDept_del'" @click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="state.pagination"
|
||||
v-show="state.pagination.total && state.pagination.total > 0"
|
||||
:total="state.pagination.total"
|
||||
:current="state.pagination.current"
|
||||
:size="state.pagination.size"
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="state.pagination"
|
||||
v-show="state.pagination.total && state.pagination.total > 0"
|
||||
:total="state.pagination.total"
|
||||
:current="state.pagination.current"
|
||||
:size="state.pagination.size"
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList" />
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList" />
|
||||
|
||||
<!-- 导入excel弹窗 -->
|
||||
<uploadExcel
|
||||
ref="excelUploadRef"
|
||||
title="导入"
|
||||
url="/purchase/purchasingBusinessDept/import"
|
||||
temp-url="/admin/sys-file/local/file/purchasingBusinessDept.xlsx"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
</div>
|
||||
<!-- 导入excel弹窗 -->
|
||||
<uploadExcel
|
||||
ref="excelUploadRef"
|
||||
title="导入"
|
||||
url="/purchase/purchasingBusinessDept/import"
|
||||
temp-url="/admin/sys-file/local/file/purchasingBusinessDept.xlsx"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingBusinessDept">
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObjs } from "/@/api/purchase/purchasingBusinessDept";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { List, Document, User, UserFilled, EditPen, Clock, Search, OfficeBuilding } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs } from '/@/api/purchase/purchasingBusinessDept';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { List, Document, User, UserFilled, EditPen, Clock, Search, OfficeBuilding } from '@element-plus/icons-vue';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
|
||||
// 定义变量内容
|
||||
const tableRef = ref()
|
||||
const formDialogRef = ref()
|
||||
const excelUploadRef = ref()
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
const tableRef = ref();
|
||||
const formDialogRef = ref();
|
||||
const excelUploadRef = ref();
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
/**
|
||||
* 定义响应式表格数据
|
||||
*/
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: fetchList,
|
||||
queryForm: {
|
||||
deptName: '',
|
||||
username: '',
|
||||
name: '',
|
||||
},
|
||||
createdIsNeed: true
|
||||
pageList: fetchList,
|
||||
queryForm: {
|
||||
deptName: '',
|
||||
username: '',
|
||||
name: '',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* 使用 useTable 定义表格相关操作
|
||||
*/
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state);
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
/**
|
||||
* 重置搜索表单
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
queryRef.value?.resetFields();
|
||||
selectObjs.value = [];
|
||||
multiple.value = true;
|
||||
getDataList();
|
||||
queryRef.value?.resetFields();
|
||||
selectObjs.value = [];
|
||||
multiple.value = true;
|
||||
getDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出Excel文件
|
||||
*/
|
||||
const exportExcel = () => {
|
||||
downBlobFile(
|
||||
'/purchase/purchasingBusinessDept/export',
|
||||
Object.assign(state.queryForm, { ids: selectObjs.value }),
|
||||
'purchasingBusinessDept.xlsx'
|
||||
);
|
||||
downBlobFile('/purchase/purchasingBusinessDept/export', Object.assign(state.queryForm, { ids: selectObjs.value }), 'purchasingBusinessDept.xlsx');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -251,8 +222,8 @@ const exportExcel = () => {
|
||||
* @param objs 选中的数据行
|
||||
*/
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -260,19 +231,19 @@ const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
* @param ids - 要删除的ID数组
|
||||
*/
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,72 +1,51 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="form.id ? '编辑' : '新增'"
|
||||
v-model="visible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="form"
|
||||
:rules="dataRules"
|
||||
label-width="120px"
|
||||
v-loading="loading">
|
||||
<el-form-item label="选择人员" prop="userId">
|
||||
<el-select
|
||||
v-model="form.userId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchUser"
|
||||
:loading="userLoading"
|
||||
style="width: 100%"
|
||||
@change="handleUserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px;">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input
|
||||
v-model="form.name"
|
||||
placeholder="选择人员后自动填充"
|
||||
readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input
|
||||
v-model="form.username"
|
||||
placeholder="选择人员后自动填充"
|
||||
readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" width="600px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="120px" v-loading="loading">
|
||||
<el-form-item label="选择人员" prop="userId">
|
||||
<el-select
|
||||
v-model="form.userId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchUser"
|
||||
:loading="userLoading"
|
||||
style="width: 100%"
|
||||
@change="handleUserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="form.name" placeholder="选择人员后自动填充" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input v-model="form.username" placeholder="选择人员后自动填充" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingBusinessLeaderForm">
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { getObj, addObj, putObj } from '/@/api/purchase/purchasingBusinessLeader';
|
||||
import { searchTeachers } from '/@/api/purchase/purchasingrequisition';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
@@ -77,125 +56,120 @@ const dataFormRef = ref();
|
||||
const userOptions = ref<any[]>([]);
|
||||
const userLoading = ref(false);
|
||||
const form = reactive({
|
||||
id: '',
|
||||
userId: '',
|
||||
username: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
id: '',
|
||||
userId: '',
|
||||
username: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
});
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const dataRules = ref({
|
||||
userId: [
|
||||
{ required: true, message: '请选择人员', trigger: 'change' }
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '请先选择人员', trigger: 'blur' }
|
||||
],
|
||||
username: [
|
||||
{ required: true, message: '请先选择人员', trigger: 'blur' }
|
||||
],
|
||||
userId: [{ required: true, message: '请选择人员', trigger: 'change' }],
|
||||
name: [{ required: true, message: '请先选择人员', trigger: 'blur' }],
|
||||
username: [{ required: true, message: '请先选择人员', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
const searchUser = async (query: string) => {
|
||||
if (!query) {
|
||||
userOptions.value = [];
|
||||
return;
|
||||
}
|
||||
userLoading.value = true;
|
||||
try {
|
||||
const res = await searchTeachers(query);
|
||||
userOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
userOptions.value = [];
|
||||
} finally {
|
||||
userLoading.value = false;
|
||||
}
|
||||
if (!query) {
|
||||
userOptions.value = [];
|
||||
return;
|
||||
}
|
||||
userLoading.value = true;
|
||||
try {
|
||||
const res = await searchTeachers(query);
|
||||
userOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
userOptions.value = [];
|
||||
} finally {
|
||||
userLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleUserChange = (teacherNo: string) => {
|
||||
if (!teacherNo) {
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
return;
|
||||
}
|
||||
const selected = userOptions.value.find((item: any) => item.teacherNo === teacherNo);
|
||||
if (selected) {
|
||||
form.userId = selected.teacherNo;
|
||||
form.username = selected.teacherNo;
|
||||
form.name = selected.realName || selected.name;
|
||||
}
|
||||
if (!teacherNo) {
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
return;
|
||||
}
|
||||
const selected = userOptions.value.find((item: any) => item.teacherNo === teacherNo);
|
||||
if (selected) {
|
||||
form.userId = selected.teacherNo;
|
||||
form.username = selected.teacherNo;
|
||||
form.name = selected.realName || selected.name;
|
||||
}
|
||||
};
|
||||
|
||||
const openDialog = async (id?: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
form.remark = '';
|
||||
userOptions.value = [];
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
form.remark = '';
|
||||
userOptions.value = [];
|
||||
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
if (id) {
|
||||
loading.value = true;
|
||||
getObj(id).then((res: any) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
const data = res.data[0];
|
||||
Object.assign(form, {
|
||||
id: data.id || '',
|
||||
userId: data.userId || '',
|
||||
username: data.username || '',
|
||||
name: data.name || '',
|
||||
remark: data.remark || '',
|
||||
});
|
||||
if (form.userId) {
|
||||
userOptions.value = [{ teacherNo: form.userId, realName: form.name, name: form.name }];
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
}).catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
if (id) {
|
||||
loading.value = true;
|
||||
getObj(id)
|
||||
.then((res: any) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
const data = res.data[0];
|
||||
Object.assign(form, {
|
||||
id: data.id || '',
|
||||
userId: data.userId || '',
|
||||
username: data.username || '',
|
||||
name: data.name || '',
|
||||
remark: data.remark || '',
|
||||
});
|
||||
if (form.userId) {
|
||||
userOptions.value = [{ teacherNo: form.userId, realName: form.name, name: form.name }];
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (form.id) {
|
||||
await putObj(form);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(form);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (form.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
if (form.id) {
|
||||
await putObj(form);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(form);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (form.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,208 +1,185 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input
|
||||
v-model="state.queryForm.name"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input
|
||||
v-model="state.queryForm.username"
|
||||
placeholder="请输入用户工号"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="state.queryForm.name" placeholder="请输入姓名" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input v-model="state.queryForm.username" placeholder="请输入用户工号" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><User /></el-icon>
|
||||
业务分管校领导
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="FolderAdd"
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog()"
|
||||
v-auth="'purchasing_bus_leader_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
v-auth="'purchasing_bus_leader_del'"
|
||||
@click="handleDelete(selectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchasing_bus_leader_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10"
|
||||
@queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><User /></el-icon>
|
||||
业务分管校领导
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog()" v-auth="'purchasing_bus_leader_add'"> 新增 </el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
v-auth="'purchasing_bus_leader_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchasing_bus_leader_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
class="modern-table">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="姓名" min-width="120" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">姓名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="用户工号" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">用户工号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="300" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="Delete"
|
||||
link
|
||||
type="danger"
|
||||
v-auth="'purchasing_bus_leader_del'"
|
||||
@click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="姓名" min-width="120" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">姓名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="用户工号" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">用户工号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="300" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="Delete" link type="danger" v-auth="'purchasing_bus_leader_del'" @click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="state.pagination"
|
||||
v-show="state.pagination.total && state.pagination.total > 0"
|
||||
:total="state.pagination.total"
|
||||
:current="state.pagination.current"
|
||||
:size="state.pagination.size"
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="state.pagination"
|
||||
v-show="state.pagination.total && state.pagination.total > 0"
|
||||
:total="state.pagination.total"
|
||||
:current="state.pagination.current"
|
||||
:size="state.pagination.size"
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingBusinessLeader">
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObjs } from "/@/api/purchase/purchasingBusinessLeader";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { List, User, UserFilled, EditPen, Clock, Search } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs } from '/@/api/purchase/purchasingBusinessLeader';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { List, User, UserFilled, EditPen, Clock, Search } from '@element-plus/icons-vue';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
|
||||
// 定义变量内容
|
||||
const tableRef = ref()
|
||||
const formDialogRef = ref()
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
const tableRef = ref();
|
||||
const formDialogRef = ref();
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
/**
|
||||
* 定义响应式表格数据
|
||||
*/
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: fetchList,
|
||||
queryForm: {
|
||||
name: '',
|
||||
username: '',
|
||||
},
|
||||
createdIsNeed: true
|
||||
pageList: fetchList,
|
||||
queryForm: {
|
||||
name: '',
|
||||
username: '',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* 使用 useTable 定义表格相关操作
|
||||
*/
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state);
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
/**
|
||||
* 重置搜索表单
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
queryRef.value?.resetFields();
|
||||
selectObjs.value = [];
|
||||
multiple.value = true;
|
||||
getDataList();
|
||||
queryRef.value?.resetFields();
|
||||
selectObjs.value = [];
|
||||
multiple.value = true;
|
||||
getDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出Excel文件
|
||||
*/
|
||||
const exportExcel = () => {
|
||||
downBlobFile(
|
||||
'/purchase/purchasingBusinessLeader/export',
|
||||
Object.assign(state.queryForm, { ids: selectObjs.value }),
|
||||
'purchasingBusinessLeader.xlsx'
|
||||
);
|
||||
downBlobFile(
|
||||
'/purchase/purchasingBusinessLeader/export',
|
||||
Object.assign(state.queryForm, { ids: selectObjs.value }),
|
||||
'purchasingBusinessLeader.xlsx'
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -210,8 +187,8 @@ const exportExcel = () => {
|
||||
* @param objs 选中的数据行
|
||||
*/
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -219,22 +196,22 @@ const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
* @param ids - 要删除的ID数组
|
||||
*/
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,95 +1,59 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="form.id ? '编辑' : '新增'"
|
||||
v-model="visible"
|
||||
width="700px"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="form"
|
||||
:rules="dataRules"
|
||||
label-width="120px"
|
||||
v-loading="loading">
|
||||
<el-form-item label="选择人员" prop="userId">
|
||||
<el-select
|
||||
v-model="form.userId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchUser"
|
||||
:loading="userLoading"
|
||||
style="width: 100%"
|
||||
@change="handleUserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px;">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input
|
||||
v-model="form.name"
|
||||
placeholder="选择人员后自动填充"
|
||||
readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input
|
||||
v-model="form.username"
|
||||
placeholder="选择人员后自动填充"
|
||||
readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门" prop="deptId">
|
||||
<el-select
|
||||
v-model="form.deptId"
|
||||
placeholder="请选择部门"
|
||||
filterable
|
||||
clearable
|
||||
style="width: 100%"
|
||||
@change="handleDeptChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptOptions"
|
||||
:key="item.deptId"
|
||||
:label="item.deptName"
|
||||
:value="item.deptId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input
|
||||
v-model="form.deptName"
|
||||
placeholder="选择部门后自动填充"
|
||||
readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" width="700px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="120px" v-loading="loading">
|
||||
<el-form-item label="选择人员" prop="userId">
|
||||
<el-select
|
||||
v-model="form.userId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchUser"
|
||||
:loading="userLoading"
|
||||
style="width: 100%"
|
||||
@change="handleUserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="form.name" placeholder="选择人员后自动填充" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input v-model="form.username" placeholder="选择人员后自动填充" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门" prop="deptId">
|
||||
<el-select v-model="form.deptId" placeholder="请选择部门" filterable clearable style="width: 100%" @change="handleDeptChange">
|
||||
<el-option v-for="item in deptOptions" :key="item.deptId" :label="item.deptName" :value="item.deptId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input v-model="form.deptName" placeholder="选择部门后自动填充" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingPurchaseManagerForm">
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { getObj, addObj, putObj } from '/@/api/purchase/purchasingPurchaseManager';
|
||||
import { searchTeachers, getSecondDeptList } from '/@/api/purchase/purchasingrequisition';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
@@ -101,158 +65,151 @@ const deptOptions = ref<any[]>([]);
|
||||
const userOptions = ref<any[]>([]);
|
||||
const userLoading = ref(false);
|
||||
const form = reactive({
|
||||
id: '',
|
||||
deptId: '',
|
||||
deptName: '',
|
||||
userId: '',
|
||||
username: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
id: '',
|
||||
deptId: '',
|
||||
deptName: '',
|
||||
userId: '',
|
||||
username: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
});
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const dataRules = ref({
|
||||
userId: [
|
||||
{ required: true, message: '请选择人员', trigger: 'change' }
|
||||
],
|
||||
deptId: [
|
||||
{ required: true, message: '请选择部门', trigger: 'change' }
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '请先选择人员', trigger: 'blur' }
|
||||
],
|
||||
username: [
|
||||
{ required: true, message: '请先选择人员', trigger: 'blur' }
|
||||
],
|
||||
userId: [{ required: true, message: '请选择人员', trigger: 'change' }],
|
||||
deptId: [{ required: true, message: '请选择部门', trigger: 'change' }],
|
||||
name: [{ required: true, message: '请先选择人员', trigger: 'blur' }],
|
||||
username: [{ required: true, message: '请先选择人员', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
const loadDeptOptions = async () => {
|
||||
try {
|
||||
const res = await getSecondDeptList();
|
||||
deptOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
deptOptions.value = [];
|
||||
}
|
||||
try {
|
||||
const res = await getSecondDeptList();
|
||||
deptOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
deptOptions.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
const searchUser = async (query: string) => {
|
||||
if (!query) {
|
||||
userOptions.value = [];
|
||||
return;
|
||||
}
|
||||
userLoading.value = true;
|
||||
try {
|
||||
const res = await searchTeachers(query);
|
||||
userOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
userOptions.value = [];
|
||||
} finally {
|
||||
userLoading.value = false;
|
||||
}
|
||||
if (!query) {
|
||||
userOptions.value = [];
|
||||
return;
|
||||
}
|
||||
userLoading.value = true;
|
||||
try {
|
||||
const res = await searchTeachers(query);
|
||||
userOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
userOptions.value = [];
|
||||
} finally {
|
||||
userLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeptChange = (deptId: string) => {
|
||||
if (!deptId) {
|
||||
form.deptId = '';
|
||||
form.deptName = '';
|
||||
return;
|
||||
}
|
||||
const selected = deptOptions.value.find((item: any) => item.deptId === deptId);
|
||||
if (selected) {
|
||||
form.deptId = selected.deptId;
|
||||
form.deptName = selected.deptName;
|
||||
}
|
||||
if (!deptId) {
|
||||
form.deptId = '';
|
||||
form.deptName = '';
|
||||
return;
|
||||
}
|
||||
const selected = deptOptions.value.find((item: any) => item.deptId === deptId);
|
||||
if (selected) {
|
||||
form.deptId = selected.deptId;
|
||||
form.deptName = selected.deptName;
|
||||
}
|
||||
};
|
||||
|
||||
const handleUserChange = (teacherNo: string) => {
|
||||
if (!teacherNo) {
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
return;
|
||||
}
|
||||
const selected = userOptions.value.find((item: any) => item.teacherNo === teacherNo);
|
||||
if (selected) {
|
||||
form.userId = selected.teacherNo;
|
||||
form.username = selected.teacherNo;
|
||||
form.name = selected.realName || selected.name;
|
||||
}
|
||||
if (!teacherNo) {
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
return;
|
||||
}
|
||||
const selected = userOptions.value.find((item: any) => item.teacherNo === teacherNo);
|
||||
if (selected) {
|
||||
form.userId = selected.teacherNo;
|
||||
form.username = selected.teacherNo;
|
||||
form.name = selected.realName || selected.name;
|
||||
}
|
||||
};
|
||||
|
||||
const openDialog = async (id?: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
form.deptId = '';
|
||||
form.deptName = '';
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
form.remark = '';
|
||||
userOptions.value = [];
|
||||
|
||||
await loadDeptOptions();
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
form.deptId = '';
|
||||
form.deptName = '';
|
||||
form.userId = '';
|
||||
form.username = '';
|
||||
form.name = '';
|
||||
form.remark = '';
|
||||
userOptions.value = [];
|
||||
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
if (id) {
|
||||
loading.value = true;
|
||||
getObj(id).then((res: any) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
const data = res.data[0];
|
||||
Object.assign(form, {
|
||||
id: data.id || '',
|
||||
deptId: data.deptId || '',
|
||||
deptName: data.deptName || '',
|
||||
userId: data.userId || '',
|
||||
username: data.username || '',
|
||||
name: data.name || '',
|
||||
remark: data.remark || '',
|
||||
});
|
||||
if (form.userId) {
|
||||
userOptions.value = [{ teacherNo: form.userId, realName: form.name, name: form.name }];
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
}).catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
await loadDeptOptions();
|
||||
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
if (id) {
|
||||
loading.value = true;
|
||||
getObj(id)
|
||||
.then((res: any) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
const data = res.data[0];
|
||||
Object.assign(form, {
|
||||
id: data.id || '',
|
||||
deptId: data.deptId || '',
|
||||
deptName: data.deptName || '',
|
||||
userId: data.userId || '',
|
||||
username: data.username || '',
|
||||
name: data.name || '',
|
||||
remark: data.remark || '',
|
||||
});
|
||||
if (form.userId) {
|
||||
userOptions.value = [{ teacherNo: form.userId, realName: form.name, name: form.name }];
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (form.id) {
|
||||
await putObj(form);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(form);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (form.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
if (form.id) {
|
||||
await putObj(form);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(form);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (form.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,222 +1,189 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input
|
||||
v-model="state.queryForm.deptName"
|
||||
placeholder="请输入部门名称"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input
|
||||
v-model="state.queryForm.username"
|
||||
placeholder="请输入用户工号"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input
|
||||
v-model="state.queryForm.name"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input v-model="state.queryForm.deptName" placeholder="请输入部门名称" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input v-model="state.queryForm.username" placeholder="请输入用户工号" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="state.queryForm.name" placeholder="请输入姓名" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
采购分管领导
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="FolderAdd"
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog()"
|
||||
v-auth="'purchase_manager_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
v-auth="'purchase_manager_del'"
|
||||
@click="handleDelete(selectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_manager_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10"
|
||||
@queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
采购分管领导
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog()" v-auth="'purchase_manager_add'"> 新增 </el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
v-auth="'purchase_manager_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'purchase_manager_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
class="modern-table">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deptName" label="部门名称" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><OfficeBuilding /></el-icon>
|
||||
<span style="margin-left: 4px">部门名称</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="姓名" min-width="120" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">姓名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="用户工号" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">用户工号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="300" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="Delete"
|
||||
link
|
||||
type="danger"
|
||||
v-auth="'purchase_manager_del'"
|
||||
@click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deptName" label="部门名称" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><OfficeBuilding /></el-icon>
|
||||
<span style="margin-left: 4px">部门名称</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="姓名" min-width="120" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">姓名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="用户工号" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">用户工号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="300" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="Delete" link type="danger" v-auth="'purchase_manager_del'" @click="handleDelete([scope.row.id])"> 删除 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="state.pagination"
|
||||
v-show="state.pagination.total && state.pagination.total > 0"
|
||||
:total="state.pagination.total"
|
||||
:current="state.pagination.current"
|
||||
:size="state.pagination.size"
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="state.pagination"
|
||||
v-show="state.pagination.total && state.pagination.total > 0"
|
||||
:total="state.pagination.total"
|
||||
:current="state.pagination.current"
|
||||
:size="state.pagination.size"
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingPurchaseManager">
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObjs } from "/@/api/purchase/purchasingPurchaseManager";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { List, Document, User, UserFilled, EditPen, Clock, Search, OfficeBuilding } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs } from '/@/api/purchase/purchasingPurchaseManager';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { List, Document, User, UserFilled, EditPen, Clock, Search, OfficeBuilding } from '@element-plus/icons-vue';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
|
||||
// 定义变量内容
|
||||
const tableRef = ref()
|
||||
const formDialogRef = ref()
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
const tableRef = ref();
|
||||
const formDialogRef = ref();
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
/**
|
||||
* 定义响应式表格数据
|
||||
*/
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: fetchList,
|
||||
queryForm: {
|
||||
deptName: '',
|
||||
username: '',
|
||||
name: '',
|
||||
},
|
||||
createdIsNeed: true
|
||||
pageList: fetchList,
|
||||
queryForm: {
|
||||
deptName: '',
|
||||
username: '',
|
||||
name: '',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* 使用 useTable 定义表格相关操作
|
||||
*/
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state);
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
/**
|
||||
* 重置搜索表单
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
queryRef.value?.resetFields();
|
||||
selectObjs.value = [];
|
||||
multiple.value = true;
|
||||
getDataList();
|
||||
queryRef.value?.resetFields();
|
||||
selectObjs.value = [];
|
||||
multiple.value = true;
|
||||
getDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出Excel文件
|
||||
*/
|
||||
const exportExcel = () => {
|
||||
downBlobFile(
|
||||
'/purchasingPurchaseManager/export',
|
||||
Object.assign(state.queryForm, { ids: selectObjs.value }),
|
||||
'purchasingPurchaseManager.xlsx'
|
||||
);
|
||||
downBlobFile('/purchasingPurchaseManager/export', Object.assign(state.queryForm, { ids: selectObjs.value }), 'purchasingPurchaseManager.xlsx');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -224,8 +191,8 @@ const exportExcel = () => {
|
||||
* @param objs 选中的数据行
|
||||
*/
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -233,22 +200,22 @@ const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
* @param ids - 要删除的ID数组
|
||||
*/
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,151 +1,129 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:title="dialogTitle"
|
||||
width="700px"
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="规则编码" prop="ruleCode">
|
||||
<el-input v-model="form.ruleCode" placeholder="请输入规则编码" :disabled="isEdit" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="规则名称" prop="ruleName">
|
||||
<el-input v-model="form.ruleName" placeholder="请输入规则名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="规则类型" prop="ruleType">
|
||||
<el-select v-model="form.ruleType" placeholder="请选择规则类型" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in ruleTypes"
|
||||
:key="item.code"
|
||||
:label="item.name"
|
||||
:value="item.code"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="优先级" prop="sortOrder">
|
||||
<el-input-number v-model="form.sortOrder" :min="1" :max="999" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="金额区间">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<el-input-number
|
||||
v-model="form.amountMin"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
placeholder="金额下限"
|
||||
style="width: 200px;"
|
||||
@change="handleAmountMinChange"
|
||||
/>
|
||||
<span>元</span>
|
||||
<span style="margin: 0 8px;">至</span>
|
||||
<el-input-number
|
||||
v-model="form.amountMax"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
placeholder="金额上限"
|
||||
style="width: 200px;"
|
||||
@change="handleAmountMaxChange"
|
||||
/>
|
||||
<span>元</span>
|
||||
<span style="color: #909399; font-size: 12px;">(不填表示不限)</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="附加条件字段">
|
||||
<el-select v-model="form.conditionField" placeholder="请选择" clearable style="width: 100%">
|
||||
<el-option label="是否集采" value="isCentralized" />
|
||||
<el-option label="是否特殊情况" value="isSpecial" />
|
||||
<el-option label="是否有推荐供应商" value="hasSupplier" />
|
||||
<el-option label="项目类别" value="projectType" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="附加条件值">
|
||||
<el-input v-model="form.conditionValue" placeholder="如:0、1、A等" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="动作类型" prop="actionType">
|
||||
<el-select v-model="form.actionType" placeholder="请选择动作类型" style="width: 100%">
|
||||
<el-option label="设置字段值" value="SET_FIELD" />
|
||||
<el-option label="切换模板" value="SWITCH_TEMPLATE" />
|
||||
<el-option label="要求文件" value="REQUIRE_FILE" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="动作目标" prop="actionTarget">
|
||||
<el-select v-model="form.actionTarget" placeholder="请选择" allow-create filterable style="width: 100%">
|
||||
<el-option v-if="form.actionType === 'SET_FIELD'" label="采购形式" value="purchaseMode" />
|
||||
<el-option v-if="form.actionType === 'SET_FIELD'" label="学校采购方式" value="purchaseSchool" />
|
||||
<el-option v-if="form.actionType === 'SWITCH_TEMPLATE'" label="比选模板" value="bidTemplate" />
|
||||
<el-option v-if="form.actionType === 'REQUIRE_FILE'" label="可行性论证报告" value="feasibilityReport" />
|
||||
<el-option v-if="form.actionType === 'REQUIRE_FILE'" label="会议纪要" value="meetingMinutes" />
|
||||
<el-option v-if="form.actionType === 'REQUIRE_FILE'" label="政府采购意向表" value="governmentIntention" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="动作值">
|
||||
<el-input v-model="form.actionValue" placeholder="设置的值" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否启用">
|
||||
<el-radio-group v-model="form.isEnabled">
|
||||
<el-radio label="1">启用</el-radio>
|
||||
<el-radio label="0">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="规则描述">
|
||||
<el-input
|
||||
v-model="form.description"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入规则描述"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-dialog v-model="visible" :title="dialogTitle" width="700px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px" v-loading="loading">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="规则编码" prop="ruleCode">
|
||||
<el-input v-model="form.ruleCode" placeholder="请输入规则编码" :disabled="isEdit" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="规则名称" prop="ruleName">
|
||||
<el-input v-model="form.ruleName" placeholder="请输入规则名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="规则类型" prop="ruleType">
|
||||
<el-select v-model="form.ruleType" placeholder="请选择规则类型" style="width: 100%">
|
||||
<el-option v-for="item in ruleTypes" :key="item.code" :label="item.name" :value="item.code" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="优先级" prop="sortOrder">
|
||||
<el-input-number v-model="form.sortOrder" :min="1" :max="999" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="金额区间">
|
||||
<div style="display: flex; align-items: center; gap: 8px">
|
||||
<el-input-number
|
||||
v-model="form.amountMin"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
placeholder="金额下限"
|
||||
style="width: 200px"
|
||||
@change="handleAmountMinChange"
|
||||
/>
|
||||
<span>元</span>
|
||||
<span style="margin: 0 8px">至</span>
|
||||
<el-input-number
|
||||
v-model="form.amountMax"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
placeholder="金额上限"
|
||||
style="width: 200px"
|
||||
@change="handleAmountMaxChange"
|
||||
/>
|
||||
<span>元</span>
|
||||
<span style="color: #909399; font-size: 12px">(不填表示不限)</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="附加条件字段">
|
||||
<el-select v-model="form.conditionField" placeholder="请选择" clearable style="width: 100%">
|
||||
<el-option label="是否集采" value="isCentralized" />
|
||||
<el-option label="是否特殊情况" value="isSpecial" />
|
||||
<el-option label="是否有推荐供应商" value="hasSupplier" />
|
||||
<el-option label="项目类别" value="projectType" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="附加条件值">
|
||||
<el-input v-model="form.conditionValue" placeholder="如:0、1、A等" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="动作类型" prop="actionType">
|
||||
<el-select v-model="form.actionType" placeholder="请选择动作类型" style="width: 100%">
|
||||
<el-option label="设置字段值" value="SET_FIELD" />
|
||||
<el-option label="切换模板" value="SWITCH_TEMPLATE" />
|
||||
<el-option label="要求文件" value="REQUIRE_FILE" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="动作目标" prop="actionTarget">
|
||||
<el-select v-model="form.actionTarget" placeholder="请选择" allow-create filterable style="width: 100%">
|
||||
<el-option v-if="form.actionType === 'SET_FIELD'" label="采购形式" value="purchaseMode" />
|
||||
<el-option v-if="form.actionType === 'SET_FIELD'" label="学校采购方式" value="purchaseSchool" />
|
||||
<el-option v-if="form.actionType === 'SWITCH_TEMPLATE'" label="比选模板" value="bidTemplate" />
|
||||
<el-option v-if="form.actionType === 'REQUIRE_FILE'" label="可行性论证报告" value="feasibilityReport" />
|
||||
<el-option v-if="form.actionType === 'REQUIRE_FILE'" label="会议纪要" value="meetingMinutes" />
|
||||
<el-option v-if="form.actionType === 'REQUIRE_FILE'" label="政府采购意向表" value="governmentIntention" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="动作值">
|
||||
<el-input v-model="form.actionValue" placeholder="设置的值" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否启用">
|
||||
<el-radio-group v-model="form.isEnabled">
|
||||
<el-radio label="1">启用</el-radio>
|
||||
<el-radio label="0">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="规则描述">
|
||||
<el-input v-model="form.description" type="textarea" :rows="2" placeholder="请输入规则描述" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { getObj, addObj, putObj, getRuleTypes } from "/@/api/purchase/purchasingRuleConfig";
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj, getRuleTypes } from '/@/api/purchase/purchasingRuleConfig';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
@@ -156,106 +134,106 @@ const formRef = ref();
|
||||
const ruleTypes = ref<{ code: string; name: string }[]>([]);
|
||||
|
||||
const isEdit = ref(false);
|
||||
const dialogTitle = computed(() => isEdit.value ? '编辑规则' : '新增规则');
|
||||
const dialogTitle = computed(() => (isEdit.value ? '编辑规则' : '新增规则'));
|
||||
|
||||
const form = reactive({
|
||||
id: '',
|
||||
ruleCode: '',
|
||||
ruleName: '',
|
||||
ruleType: '',
|
||||
amountMin: null as number | null,
|
||||
amountMax: null as number | null,
|
||||
conditionField: '',
|
||||
conditionValue: '',
|
||||
actionType: '',
|
||||
actionTarget: '',
|
||||
actionValue: '',
|
||||
description: '',
|
||||
sortOrder: 1,
|
||||
isEnabled: '1',
|
||||
remark: ''
|
||||
id: '',
|
||||
ruleCode: '',
|
||||
ruleName: '',
|
||||
ruleType: '',
|
||||
amountMin: null as number | null,
|
||||
amountMax: null as number | null,
|
||||
conditionField: '',
|
||||
conditionValue: '',
|
||||
actionType: '',
|
||||
actionTarget: '',
|
||||
actionValue: '',
|
||||
description: '',
|
||||
sortOrder: 1,
|
||||
isEnabled: '1',
|
||||
remark: '',
|
||||
});
|
||||
|
||||
const rules = {
|
||||
ruleCode: [{ required: true, message: '请输入规则编码', trigger: 'blur' }],
|
||||
ruleName: [{ required: true, message: '请输入规则名称', trigger: 'blur' }],
|
||||
ruleType: [{ required: true, message: '请选择规则类型', trigger: 'change' }],
|
||||
actionType: [{ required: true, message: '请选择动作类型', trigger: 'change' }],
|
||||
actionTarget: [{ required: true, message: '请输入动作目标', trigger: 'blur' }]
|
||||
ruleCode: [{ required: true, message: '请输入规则编码', trigger: 'blur' }],
|
||||
ruleName: [{ required: true, message: '请输入规则名称', trigger: 'blur' }],
|
||||
ruleType: [{ required: true, message: '请选择规则类型', trigger: 'change' }],
|
||||
actionType: [{ required: true, message: '请选择动作类型', trigger: 'change' }],
|
||||
actionTarget: [{ required: true, message: '请输入动作目标', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
const openDialog = async (id?: string) => {
|
||||
visible.value = true;
|
||||
isEdit.value = !!id;
|
||||
resetForm();
|
||||
visible.value = true;
|
||||
isEdit.value = !!id;
|
||||
resetForm();
|
||||
|
||||
const res = await getRuleTypes();
|
||||
ruleTypes.value = res.data || [];
|
||||
const res = await getRuleTypes();
|
||||
ruleTypes.value = res.data || [];
|
||||
|
||||
if (id) {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await getObj(id);
|
||||
if (response.data) {
|
||||
Object.assign(form, response.data);
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
if (id) {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await getObj(id);
|
||||
if (response.data) {
|
||||
Object.assign(form, response.data);
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
form.id = '';
|
||||
form.ruleCode = '';
|
||||
form.ruleName = '';
|
||||
form.ruleType = '';
|
||||
form.amountMin = null;
|
||||
form.amountMax = null;
|
||||
form.conditionField = '';
|
||||
form.conditionValue = '';
|
||||
form.actionType = '';
|
||||
form.actionTarget = '';
|
||||
form.actionValue = '';
|
||||
form.description = '';
|
||||
form.sortOrder = 1;
|
||||
form.isEnabled = '1';
|
||||
form.remark = '';
|
||||
formRef.value?.resetFields();
|
||||
form.id = '';
|
||||
form.ruleCode = '';
|
||||
form.ruleName = '';
|
||||
form.ruleType = '';
|
||||
form.amountMin = null;
|
||||
form.amountMax = null;
|
||||
form.conditionField = '';
|
||||
form.conditionValue = '';
|
||||
form.actionType = '';
|
||||
form.actionTarget = '';
|
||||
form.actionValue = '';
|
||||
form.description = '';
|
||||
form.sortOrder = 1;
|
||||
form.isEnabled = '1';
|
||||
form.remark = '';
|
||||
formRef.value?.resetFields();
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
await formRef.value?.validate();
|
||||
const submitData = {
|
||||
...form,
|
||||
amountMin: form.amountMin ?? null,
|
||||
amountMax: form.amountMax ?? null
|
||||
};
|
||||
submitLoading.value = true;
|
||||
try {
|
||||
if (isEdit.value) {
|
||||
await putObj(submitData);
|
||||
useMessage().success('修改成功');
|
||||
} else {
|
||||
await addObj(submitData);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '操作失败');
|
||||
} finally {
|
||||
submitLoading.value = false;
|
||||
}
|
||||
await formRef.value?.validate();
|
||||
const submitData = {
|
||||
...form,
|
||||
amountMin: form.amountMin ?? null,
|
||||
amountMax: form.amountMax ?? null,
|
||||
};
|
||||
submitLoading.value = true;
|
||||
try {
|
||||
if (isEdit.value) {
|
||||
await putObj(submitData);
|
||||
useMessage().success('修改成功');
|
||||
} else {
|
||||
await addObj(submitData);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '操作失败');
|
||||
} finally {
|
||||
submitLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleAmountMinChange = (val: number | undefined) => {
|
||||
form.amountMin = val ?? null;
|
||||
form.amountMin = val ?? null;
|
||||
};
|
||||
|
||||
const handleAmountMaxChange = (val: number | undefined) => {
|
||||
form.amountMax = val ?? null;
|
||||
form.amountMax = val ?? null;
|
||||
};
|
||||
|
||||
defineExpose({ openDialog });
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,116 +1,92 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'purchase_purchasingruleconfig_add'">
|
||||
新增规则
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingruleconfig_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10 mr20" style="float: right" @queryTable="getDataList" />
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button
|
||||
icon="folder-add"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="formDialogRef.openDialog()"
|
||||
v-auth="'purchase_purchasingruleconfig_add'"
|
||||
>
|
||||
新增规则
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingruleconfig_del'"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
class="ml10 mr20"
|
||||
style="float: right;"
|
||||
@queryTable="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-alert type="warning" :closable="false">既定规则请不要随意修改,否则会出错</el-alert>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="50" />
|
||||
<el-table-column prop="ruleCode" label="规则编码" width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="ruleName" label="规则名称" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="ruleTypeName" label="规则类型" width="120" />
|
||||
<el-table-column label="金额区间" width="180">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.amountMin || scope.row.amountMax">
|
||||
{{ formatAmount(scope.row.amountMin) }} ~ {{ formatAmount(scope.row.amountMax) }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="附加条件" width="150">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.conditionField"> {{ getConditionLabel(scope.row.conditionField) }} = {{ scope.row.conditionValue }} </span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="actionTypeName" label="动作类型" width="100" />
|
||||
<el-table-column prop="description" label="规则描述" min-width="250" show-overflow-tooltip />
|
||||
<el-table-column prop="sortOrder" label="优先级" width="80" align="center" />
|
||||
<el-table-column label="状态" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isEnabled === '1' ? 'success' : 'danger'" size="small">
|
||||
{{ scope.row.isEnabled === '1' ? '启用' : '禁用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingruleconfig_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" v-auth="'purchase_purchasingruleconfig_del'" @click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-alert type="warning" :closable="false">既定规则请不要随意修改,否则会出错</el-alert>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="50" />
|
||||
<el-table-column prop="ruleCode" label="规则编码" width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="ruleName" label="规则名称" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="ruleTypeName" label="规则类型" width="120" />
|
||||
<el-table-column label="金额区间" width="180">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.amountMin || scope.row.amountMax">
|
||||
{{ formatAmount(scope.row.amountMin) }} ~ {{ formatAmount(scope.row.amountMax) }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="附加条件" width="150">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.conditionField">
|
||||
{{ getConditionLabel(scope.row.conditionField) }} = {{ scope.row.conditionValue }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="actionTypeName" label="动作类型" width="100" />
|
||||
<el-table-column prop="description" label="规则描述" min-width="250" show-overflow-tooltip />
|
||||
<el-table-column prop="sortOrder" label="优先级" width="80" align="center" />
|
||||
<el-table-column label="状态" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isEnabled === '1' ? 'success' : 'danger'" size="small">
|
||||
{{ scope.row.isEnabled === '1' ? '启用' : '禁用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingruleconfig_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="delete"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingruleconfig_del'"
|
||||
@click="handleDelete([scope.row.id])"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<pagination
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
v-bind="state.pagination"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
</div>
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="purchasingRuleConfig">
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObjs } from "/@/api/purchase/purchasingRuleConfig";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs } from '/@/api/purchase/purchasingRuleConfig';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
|
||||
@@ -121,50 +97,45 @@ const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {},
|
||||
pageList: fetchList
|
||||
queryForm: {},
|
||||
pageList: fetchList,
|
||||
});
|
||||
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
tableStyle
|
||||
} = useTable(state);
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state);
|
||||
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除该规则,是否继续?');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除该规则,是否继续?');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
const formatAmount = (amount: number | null) => {
|
||||
if (amount === null || amount === undefined) return '不限';
|
||||
return (amount / 10000).toFixed(0) + '万';
|
||||
if (amount === null || amount === undefined) return '不限';
|
||||
return (amount / 10000).toFixed(0) + '万';
|
||||
};
|
||||
|
||||
const getConditionLabel = (field: string) => {
|
||||
const map: Record<string, string> = {
|
||||
isCentralized: '是否集采',
|
||||
isSpecial: '是否特殊',
|
||||
hasSupplier: '是否有推荐供应商',
|
||||
projectType: '项目类别'
|
||||
};
|
||||
return map[field] || field;
|
||||
const map: Record<string, string> = {
|
||||
isCentralized: '是否集采',
|
||||
isSpecial: '是否特殊',
|
||||
hasSupplier: '是否有推荐供应商',
|
||||
projectType: '项目类别',
|
||||
};
|
||||
return map[field] || field;
|
||||
};
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,72 +1,51 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="dataForm.id ? '编辑' : '新增'"
|
||||
v-model="visible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="dataForm"
|
||||
:rules="dataRules"
|
||||
label-width="100px"
|
||||
v-loading="loading">
|
||||
<el-form-item label="选择人员" prop="userId">
|
||||
<el-select
|
||||
v-model="dataForm.userId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchUser"
|
||||
:loading="userLoading"
|
||||
style="width: 100%"
|
||||
@change="handleUserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px;">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input
|
||||
v-model="dataForm.name"
|
||||
placeholder="选择人员后自动填充"
|
||||
readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input
|
||||
v-model="dataForm.username"
|
||||
placeholder="选择人员后自动填充"
|
||||
readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="dataForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="dataForm.id ? '编辑' : '新增'" v-model="visible" width="600px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="formRef" :model="dataForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item label="选择人员" prop="userId">
|
||||
<el-select
|
||||
v-model="dataForm.userId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchUser"
|
||||
:loading="userLoading"
|
||||
style="width: 100%"
|
||||
@change="handleUserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="dataForm.name" placeholder="选择人员后自动填充" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input v-model="dataForm.username" placeholder="选择人员后自动填充" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="dataForm.remark" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingSchoolLeaderForm">
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { getObj, addObj, editObj } from '/@/api/purchase/purchasingschoolleader';
|
||||
import { searchTeachers } from '/@/api/purchase/purchasingrequisition';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
@@ -77,124 +56,119 @@ const formRef = ref();
|
||||
const userOptions = ref<any[]>([]);
|
||||
const userLoading = ref(false);
|
||||
const dataForm = reactive({
|
||||
id: '',
|
||||
userId: '',
|
||||
username: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
id: '',
|
||||
userId: '',
|
||||
username: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
});
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const dataRules = ref({
|
||||
userId: [
|
||||
{ required: true, message: '请选择人员', trigger: 'change' }
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '姓名不能为空', trigger: 'blur' }
|
||||
],
|
||||
username: [
|
||||
{ required: true, message: '用户工号不能为空', trigger: 'blur' }
|
||||
],
|
||||
userId: [{ required: true, message: '请选择人员', trigger: 'change' }],
|
||||
name: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
|
||||
username: [{ required: true, message: '用户工号不能为空', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
const searchUser = async (query: string) => {
|
||||
if (!query) {
|
||||
userOptions.value = [];
|
||||
return;
|
||||
}
|
||||
userLoading.value = true;
|
||||
try {
|
||||
const res = await searchTeachers(query);
|
||||
userOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
userOptions.value = [];
|
||||
} finally {
|
||||
userLoading.value = false;
|
||||
}
|
||||
if (!query) {
|
||||
userOptions.value = [];
|
||||
return;
|
||||
}
|
||||
userLoading.value = true;
|
||||
try {
|
||||
const res = await searchTeachers(query);
|
||||
userOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
userOptions.value = [];
|
||||
} finally {
|
||||
userLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleUserChange = (teacherNo: string) => {
|
||||
if (!teacherNo) {
|
||||
dataForm.userId = '';
|
||||
dataForm.username = '';
|
||||
dataForm.name = '';
|
||||
return;
|
||||
}
|
||||
const selected = userOptions.value.find((item: any) => item.teacherNo === teacherNo);
|
||||
if (selected) {
|
||||
dataForm.userId = selected.teacherNo;
|
||||
dataForm.username = selected.teacherNo;
|
||||
dataForm.name = selected.realName || selected.name;
|
||||
}
|
||||
if (!teacherNo) {
|
||||
dataForm.userId = '';
|
||||
dataForm.username = '';
|
||||
dataForm.name = '';
|
||||
return;
|
||||
}
|
||||
const selected = userOptions.value.find((item: any) => item.teacherNo === teacherNo);
|
||||
if (selected) {
|
||||
dataForm.userId = selected.teacherNo;
|
||||
dataForm.username = selected.teacherNo;
|
||||
dataForm.name = selected.realName || selected.name;
|
||||
}
|
||||
};
|
||||
|
||||
const openDialog = async (type: string, rowData?: any) => {
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.userId = '';
|
||||
dataForm.username = '';
|
||||
dataForm.name = '';
|
||||
dataForm.remark = '';
|
||||
userOptions.value = [];
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.userId = '';
|
||||
dataForm.username = '';
|
||||
dataForm.name = '';
|
||||
dataForm.remark = '';
|
||||
userOptions.value = [];
|
||||
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'edit' && rowData?.id) {
|
||||
loading.value = true;
|
||||
getObj(rowData.id).then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(dataForm, {
|
||||
id: res.data.id || '',
|
||||
userId: res.data.userId || '',
|
||||
username: res.data.username || '',
|
||||
name: res.data.name || '',
|
||||
remark: res.data.remark || '',
|
||||
});
|
||||
if (dataForm.userId) {
|
||||
userOptions.value = [{ teacherNo: dataForm.userId, realName: dataForm.name, name: dataForm.name }];
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
}).catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'edit' && rowData?.id) {
|
||||
loading.value = true;
|
||||
getObj(rowData.id)
|
||||
.then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(dataForm, {
|
||||
id: res.data.id || '',
|
||||
userId: res.data.userId || '',
|
||||
username: res.data.username || '',
|
||||
name: res.data.name || '',
|
||||
remark: res.data.remark || '',
|
||||
});
|
||||
if (dataForm.userId) {
|
||||
userOptions.value = [{ teacherNo: dataForm.userId, realName: dataForm.name, name: dataForm.name }];
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dataForm.id) {
|
||||
await editObj(dataForm);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(dataForm);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
if (dataForm.id) {
|
||||
await editObj(dataForm);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(dataForm);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,163 +1,146 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input
|
||||
v-model="state.queryForm.name"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input
|
||||
v-model="state.queryForm.username"
|
||||
placeholder="请输入用户工号"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="state.queryForm.name" placeholder="请输入姓名" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户工号" prop="username">
|
||||
<el-input v-model="state.queryForm.username" placeholder="请输入用户工号" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><User /></el-icon>
|
||||
校党委人员
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="FolderAdd"
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog('add')"
|
||||
v-auth="'purchase_purchasingSchoolLeader_add'"
|
||||
>
|
||||
新增
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><User /></el-icon>
|
||||
校党委人员
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog('add')" v-auth="'purchase_purchasingSchoolLeader_add'">
|
||||
新增
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="姓名" min-width="120" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">姓名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="用户工号" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">用户工号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="300" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<!-- <el-button -->
|
||||
<!-- icon="Edit" -->
|
||||
<!-- link -->
|
||||
<!-- type="primary" -->
|
||||
<!-- @click="formDialogRef.openDialog('edit', scope.row)">-->
|
||||
<!-- 编辑-->
|
||||
<!-- </el-button>-->
|
||||
<el-button
|
||||
icon="Delete"
|
||||
link
|
||||
type="danger"
|
||||
v-auth="'purchase_purchasingSchoolLeader_del'"
|
||||
@click="handleDelete(scope.row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="姓名" min-width="120" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">姓名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="用户工号" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">用户工号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="300" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<!-- <el-button -->
|
||||
<!-- icon="Edit" -->
|
||||
<!-- link -->
|
||||
<!-- type="primary" -->
|
||||
<!-- @click="formDialogRef.openDialog('edit', scope.row)">-->
|
||||
<!-- 编辑-->
|
||||
<!-- </el-button>-->
|
||||
<el-button icon="Delete" link type="danger" v-auth="'purchase_purchasingSchoolLeader_del'" @click="handleDelete(scope.row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="state.pagination"
|
||||
v-show="state.pagination.total && state.pagination.total > 0"
|
||||
:total="state.pagination.total"
|
||||
:current="state.pagination.current"
|
||||
:size="state.pagination.size"
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="state.pagination"
|
||||
v-show="state.pagination.total && state.pagination.total > 0"
|
||||
:total="state.pagination.total"
|
||||
:current="state.pagination.current"
|
||||
:size="state.pagination.size"
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingSchoolLeader">
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { getPage, delObj } from "/@/api/purchase/purchasingschoolleader";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { List, User, UserFilled, EditPen, Clock, Search } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { getPage, delObj } from '/@/api/purchase/purchasingschoolleader';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { List, User, UserFilled, EditPen, Clock, Search } from '@element-plus/icons-vue';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
|
||||
// 定义变量内容
|
||||
const tableRef = ref()
|
||||
const formDialogRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const tableRef = ref();
|
||||
const formDialogRef = ref();
|
||||
const searchFormRef = ref();
|
||||
const showSearch = ref(true);
|
||||
|
||||
/**
|
||||
* 定义响应式表格数据
|
||||
*/
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
name: '',
|
||||
username: '',
|
||||
},
|
||||
createdIsNeed: true
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
name: '',
|
||||
username: '',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -169,8 +152,8 @@ const { getDataList, tableStyle, sizeChangeHandle, currentChangeHandle } = useTa
|
||||
* 重置搜索表单
|
||||
*/
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -178,23 +161,22 @@ const handleReset = () => {
|
||||
* @param row - 当前行数据
|
||||
*/
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj([row.id]);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObj([row.id]);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,61 +1,39 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="dataForm.id ? '编辑' : '新增'"
|
||||
v-model="visible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="dataForm"
|
||||
:rules="dataRules"
|
||||
label-width="100px"
|
||||
v-loading="loading">
|
||||
<el-form-item label="父级节点" prop="parentCode">
|
||||
<el-tree-select
|
||||
v-model="dataForm.parentCode"
|
||||
:data="parentData"
|
||||
:props="{ value: 'code', label: 'name', children: 'children' }"
|
||||
class="w100"
|
||||
clearable
|
||||
check-strictly
|
||||
:render-after-expand="false"
|
||||
placeholder="请选择父级节点(不选则为根节点)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="品目编码" prop="code">
|
||||
<el-input
|
||||
v-model="dataForm.code"
|
||||
placeholder="请输入品目编码"
|
||||
clearable
|
||||
:disabled="!!dataForm.id" />
|
||||
</el-form-item>
|
||||
<el-form-item label="品目名称" prop="name">
|
||||
<el-input
|
||||
v-model="dataForm.name"
|
||||
placeholder="请输入品目名称"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="dataForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="dataForm.id ? '编辑' : '新增'" v-model="visible" width="600px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="formRef" :model="dataForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item label="父级节点" prop="parentCode">
|
||||
<el-tree-select
|
||||
v-model="dataForm.parentCode"
|
||||
:data="parentData"
|
||||
:props="{ value: 'code', label: 'name', children: 'children' }"
|
||||
class="w100"
|
||||
clearable
|
||||
check-strictly
|
||||
:render-after-expand="false"
|
||||
placeholder="请选择父级节点(不选则为根节点)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="品目编码" prop="code">
|
||||
<el-input v-model="dataForm.code" placeholder="请输入品目编码" clearable :disabled="!!dataForm.id" />
|
||||
</el-form-item>
|
||||
<el-form-item label="品目名称" prop="name">
|
||||
<el-input v-model="dataForm.name" placeholder="请输入品目名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="dataForm.remark" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingCategoryForm">
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { getTree, addObj, editObj } from '/@/api/purchase/purchasingcategory';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
|
||||
@@ -65,118 +43,113 @@ const emit = defineEmits(['refresh']);
|
||||
// 定义变量内容
|
||||
const formRef = ref();
|
||||
const dataForm = reactive({
|
||||
id: '',
|
||||
parentCode: '',
|
||||
code: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
isMallService: '',
|
||||
isMallProject: '',
|
||||
id: '',
|
||||
parentCode: '',
|
||||
code: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
isMallService: '',
|
||||
isMallProject: '',
|
||||
});
|
||||
const parentData = ref<any[]>([]);
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const dataRules = ref({
|
||||
code: [
|
||||
{ required: true, message: '请输入品目编码', trigger: 'blur' }
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '请输入品目名称', trigger: 'blur' }
|
||||
],
|
||||
code: [{ required: true, message: '请输入品目编码', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '请输入品目名称', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (type: string, rowData?: any) => {
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.parentCode = '';
|
||||
dataForm.code = '';
|
||||
dataForm.name = '';
|
||||
dataForm.remark = '';
|
||||
dataForm.isMallService = '';
|
||||
dataForm.isMallProject = '';
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.parentCode = '';
|
||||
dataForm.code = '';
|
||||
dataForm.name = '';
|
||||
dataForm.remark = '';
|
||||
dataForm.isMallService = '';
|
||||
dataForm.isMallProject = '';
|
||||
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'add' && rowData?.code) {
|
||||
// 新增时,rowData 是父节点数据,设置父级编码
|
||||
dataForm.parentCode = rowData.code;
|
||||
} else if (type === 'edit' && rowData) {
|
||||
// 编辑时,rowData 是当前行数据
|
||||
Object.assign(dataForm, {
|
||||
id: rowData.id || '',
|
||||
parentCode: rowData.parentCode || '',
|
||||
code: rowData.code || '',
|
||||
name: rowData.name || '',
|
||||
remark: rowData.remark || '',
|
||||
isMallService: rowData.isMallService || '',
|
||||
isMallProject: rowData.isMallProject || '',
|
||||
});
|
||||
}
|
||||
});
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'add' && rowData?.code) {
|
||||
// 新增时,rowData 是父节点数据,设置父级编码
|
||||
dataForm.parentCode = rowData.code;
|
||||
} else if (type === 'edit' && rowData) {
|
||||
// 编辑时,rowData 是当前行数据
|
||||
Object.assign(dataForm, {
|
||||
id: rowData.id || '',
|
||||
parentCode: rowData.parentCode || '',
|
||||
code: rowData.code || '',
|
||||
name: rowData.name || '',
|
||||
remark: rowData.remark || '',
|
||||
isMallService: rowData.isMallService || '',
|
||||
isMallProject: rowData.isMallProject || '',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
getTreeData();
|
||||
getTreeData();
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dataForm.id) {
|
||||
await editObj(dataForm);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(dataForm);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
if (dataForm.id) {
|
||||
await editObj(dataForm);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(dataForm);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 从后端获取树形数据
|
||||
const getTreeData = async () => {
|
||||
try {
|
||||
const res = await getTree();
|
||||
parentData.value = [];
|
||||
const root = {
|
||||
code: '',
|
||||
name: '根节点',
|
||||
children: [] as any[],
|
||||
};
|
||||
if (res.data && Array.isArray(res.data)) {
|
||||
root.children = res.data;
|
||||
}
|
||||
parentData.value.push(root);
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取树形数据失败');
|
||||
parentData.value = [];
|
||||
}
|
||||
try {
|
||||
const res = await getTree();
|
||||
parentData.value = [];
|
||||
const root = {
|
||||
code: '',
|
||||
name: '根节点',
|
||||
children: [] as any[],
|
||||
};
|
||||
if (res.data && Array.isArray(res.data)) {
|
||||
root.children = res.data;
|
||||
}
|
||||
parentData.value.push(root);
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取树形数据失败');
|
||||
parentData.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.w100 {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,241 +1,222 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
采购品目管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="FolderAdd"
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingcategory_add'"
|
||||
@click="formDialogRef.openDialog('add')">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Download"
|
||||
type="success"
|
||||
v-auth="'purchase_purchasingcategory_import'"
|
||||
@click="handleDownloadTemplate">
|
||||
下载模板
|
||||
</el-button>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:show-file-list="false"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:http-request="handleImport"
|
||||
accept=".xlsx,.xls"
|
||||
v-auth="'purchase_purchasingcategory_import'">
|
||||
<el-button icon="Upload" type="warning" :loading="importLoading">
|
||||
导入
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<el-button
|
||||
icon="Download"
|
||||
type="info"
|
||||
v-auth="'purchase_purchasingcategory_export'"
|
||||
@click="handleExport">
|
||||
导出
|
||||
</el-button>
|
||||
<right-toolbar class="ml10" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
采购品目管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" v-auth="'purchase_purchasingcategory_add'" @click="formDialogRef.openDialog('add')">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button icon="Download" type="success" v-auth="'purchase_purchasingcategory_import'" @click="handleDownloadTemplate">
|
||||
下载模板
|
||||
</el-button>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:show-file-list="false"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:http-request="handleImport"
|
||||
accept=".xlsx,.xls"
|
||||
v-auth="'purchase_purchasingcategory_import'"
|
||||
>
|
||||
<el-button icon="Upload" type="warning" :loading="importLoading"> 导入 </el-button>
|
||||
</el-upload>
|
||||
<el-button icon="Download" type="info" v-auth="'purchase_purchasingcategory_export'" @click="handleExport"> 导出 </el-button>
|
||||
<right-toolbar class="ml10" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 树形表格(懒加载:仅首屏加载根节点,展开时再加载子节点) -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
lazy
|
||||
:load="loadTreeNode"
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
row-key="code"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
<template #default="{ $index, row }">
|
||||
{{ getRowIndex($index, row) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="code" label="品目编码" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><DocumentCopy /></el-icon>
|
||||
<span style="margin-left: 4px">品目编码</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="品目名称" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Document /></el-icon>
|
||||
<span style="margin-left: 4px">品目名称</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="Edit"
|
||||
link
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingcategory_edit'"
|
||||
@click="formDialogRef.openDialog('edit', scope.row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Delete"
|
||||
link
|
||||
type="danger"
|
||||
v-auth="'purchase_purchasingcategory_del'"
|
||||
@click="handleDelete(scope.row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 树形表格(懒加载:仅首屏加载根节点,展开时再加载子节点) -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
lazy
|
||||
:load="loadTreeNode"
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
row-key="code"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
<template #default="{ $index, row }">
|
||||
{{ getRowIndex($index, row) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="code" label="品目编码" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><DocumentCopy /></el-icon>
|
||||
<span style="margin-left: 4px">品目编码</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="品目名称" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Document /></el-icon>
|
||||
<span style="margin-left: 4px">品目名称</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
<span style="margin-left: 4px">备注</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="Edit"
|
||||
link
|
||||
type="primary"
|
||||
v-auth="'purchase_purchasingcategory_edit'"
|
||||
@click="formDialogRef.openDialog('edit', scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button icon="Delete" link type="danger" v-auth="'purchase_purchasingcategory_del'" @click="handleDelete(scope.row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingCategory">
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { getTreeRoots, getTreeChildren, delObj, downloadTemplate, importData, exportData } from "/@/api/purchase/purchasingcategory";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { List, Document, DocumentCopy, EditPen } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { getTreeRoots, getTreeChildren, delObj, downloadTemplate, importData, exportData } from '/@/api/purchase/purchasingcategory';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { List, Document, DocumentCopy, EditPen } from '@element-plus/icons-vue';
|
||||
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
|
||||
const tableRef = ref()
|
||||
const formDialogRef = ref()
|
||||
const uploadRef = ref()
|
||||
const importLoading = ref(false)
|
||||
const tableRef = ref();
|
||||
const formDialogRef = ref();
|
||||
const uploadRef = ref();
|
||||
const importLoading = ref(false);
|
||||
|
||||
const queryTreeRoots = () => {
|
||||
return getTreeRoots().then((res: any) => {
|
||||
const list = res?.data ?? [];
|
||||
return { data: Array.isArray(list) ? list : [] };
|
||||
});
|
||||
return getTreeRoots().then((res: any) => {
|
||||
const list = res?.data ?? [];
|
||||
return { data: Array.isArray(list) ? list : [] };
|
||||
});
|
||||
};
|
||||
|
||||
const loadTreeNode = (row: any, treeNode: any, resolve: (data: any[]) => void) => {
|
||||
const parentCode = row?.code;
|
||||
if (!parentCode) {
|
||||
resolve([]);
|
||||
return;
|
||||
}
|
||||
getTreeChildren(parentCode)
|
||||
.then((res: any) => {
|
||||
const list = res?.data ?? [];
|
||||
resolve(Array.isArray(list) ? list : []);
|
||||
})
|
||||
.catch(() => resolve([]));
|
||||
const parentCode = row?.code;
|
||||
if (!parentCode) {
|
||||
resolve([]);
|
||||
return;
|
||||
}
|
||||
getTreeChildren(parentCode)
|
||||
.then((res: any) => {
|
||||
const list = res?.data ?? [];
|
||||
resolve(Array.isArray(list) ? list : []);
|
||||
})
|
||||
.catch(() => resolve([]));
|
||||
};
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: queryTreeRoots,
|
||||
queryForm: {},
|
||||
isPage: false,
|
||||
pageList: queryTreeRoots,
|
||||
queryForm: {},
|
||||
isPage: false,
|
||||
});
|
||||
|
||||
const { getDataList, tableStyle } = useTable(state);
|
||||
|
||||
const getRowIndex = (index: number, row: any) => {
|
||||
return index + 1;
|
||||
return index + 1;
|
||||
};
|
||||
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const deleteId = row.id || row.code;
|
||||
await delObj(deleteId);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
const deleteId = row.id || row.code;
|
||||
await delObj(deleteId);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleDownloadTemplate = async () => {
|
||||
try {
|
||||
const res: any = await downloadTemplate();
|
||||
downloadFile(res, '采购品目导入模板.xlsx');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '下载模板失败');
|
||||
}
|
||||
try {
|
||||
const res: any = await downloadTemplate();
|
||||
downloadFile(res, '采购品目导入模板.xlsx');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '下载模板失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleBeforeUpload = (file: File) => {
|
||||
const isExcel = file.name.endsWith('.xlsx') || file.name.endsWith('.xls');
|
||||
if (!isExcel) {
|
||||
useMessage().error('请上传Excel文件');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
const isExcel = file.name.endsWith('.xlsx') || file.name.endsWith('.xls');
|
||||
if (!isExcel) {
|
||||
useMessage().error('请上传Excel文件');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleImport = async (options: any) => {
|
||||
importLoading.value = true;
|
||||
try {
|
||||
const res: any = await importData(options.file);
|
||||
useMessage().success(res.msg || '导入成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导入失败');
|
||||
} finally {
|
||||
importLoading.value = false;
|
||||
}
|
||||
importLoading.value = true;
|
||||
try {
|
||||
const res: any = await importData(options.file);
|
||||
useMessage().success(res.msg || '导入成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导入失败');
|
||||
} finally {
|
||||
importLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
const res: any = await exportData();
|
||||
downloadFile(res, '采购品目数据.xlsx');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导出失败');
|
||||
}
|
||||
try {
|
||||
const res: any = await exportData();
|
||||
downloadFile(res, '采购品目数据.xlsx');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导出失败');
|
||||
}
|
||||
};
|
||||
|
||||
const downloadFile = (blob: Blob, fileName: string) => {
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = fileName;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = fileName;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,231 +1,205 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="state.visible"
|
||||
:title="state.title"
|
||||
width="700px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="state.formData"
|
||||
:rules="rules"
|
||||
label-width="140px">
|
||||
<el-form-item label="合同编号" prop="contractNo">
|
||||
<el-input
|
||||
v-model="state.formData.contractNo"
|
||||
placeholder="请输入合同编号"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同名称" prop="contractName">
|
||||
<el-input
|
||||
v-model="state.formData.contractName"
|
||||
placeholder="请输入合同名称"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额(元)" prop="money">
|
||||
<el-input-number
|
||||
v-model="state.formData.money"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
placeholder="请输入合同金额"
|
||||
style="width: 100%"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="采购申请ID" prop="purchaseId">
|
||||
<el-input
|
||||
v-model="state.formData.purchaseId"
|
||||
placeholder="请输入采购申请ID"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要招标" prop="isBidding">
|
||||
<el-radio-group
|
||||
v-model="state.formData.isBidding"
|
||||
:disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要法律顾问" prop="isLegalAdviser">
|
||||
<el-radio-group
|
||||
v-model="state.formData.isLegalAdviser"
|
||||
:disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="state.formData.isLegalAdviser === '1'"
|
||||
label="法律顾问意见"
|
||||
prop="legalAdviserOpinion">
|
||||
<el-input
|
||||
v-model="state.formData.legalAdviserOpinion"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入法律顾问意见"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否涉及多个部门" prop="isDepts">
|
||||
<el-radio-group
|
||||
v-model="state.formData.isDepts"
|
||||
:disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否全校合同" prop="isSchool">
|
||||
<el-radio-group
|
||||
v-model="state.formData.isSchool"
|
||||
:disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks">
|
||||
<el-input
|
||||
v-model="state.formData.remarks"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入备注"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer v-if="state.operation !== 'view'">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="state.loading">确定</el-button>
|
||||
</template>
|
||||
<template #footer v-else>
|
||||
<el-button @click="handleClose">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="state.visible"
|
||||
:title="state.title"
|
||||
width="700px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-form ref="formRef" :model="state.formData" :rules="rules" label-width="140px">
|
||||
<el-form-item label="合同编号" prop="contractNo">
|
||||
<el-input v-model="state.formData.contractNo" placeholder="请输入合同编号" :disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同名称" prop="contractName">
|
||||
<el-input v-model="state.formData.contractName" placeholder="请输入合同名称" :disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额(元)" prop="money">
|
||||
<el-input-number
|
||||
v-model="state.formData.money"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
placeholder="请输入合同金额"
|
||||
style="width: 100%"
|
||||
:disabled="state.operation === 'view'"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="采购申请ID" prop="purchaseId">
|
||||
<el-input v-model="state.formData.purchaseId" placeholder="请输入采购申请ID" :disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要招标" prop="isBidding">
|
||||
<el-radio-group v-model="state.formData.isBidding" :disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要法律顾问" prop="isLegalAdviser">
|
||||
<el-radio-group v-model="state.formData.isLegalAdviser" :disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="state.formData.isLegalAdviser === '1'" label="法律顾问意见" prop="legalAdviserOpinion">
|
||||
<el-input
|
||||
v-model="state.formData.legalAdviserOpinion"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入法律顾问意见"
|
||||
:disabled="state.operation === 'view'"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否涉及多个部门" prop="isDepts">
|
||||
<el-radio-group v-model="state.formData.isDepts" :disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否全校合同" prop="isSchool">
|
||||
<el-radio-group v-model="state.formData.isSchool" :disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks">
|
||||
<el-input v-model="state.formData.remarks" type="textarea" :rows="2" placeholder="请输入备注" :disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer v-if="state.operation !== 'view'">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="state.loading">确定</el-button>
|
||||
</template>
|
||||
<template #footer v-else>
|
||||
<el-button @click="handleClose">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingContractForm">
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { getObj, addObj, editObj } from "/@/api/purchase/purchasingcontract";
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
import { getObj, addObj, editObj } from '/@/api/purchase/purchasingcontract';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
const formRef = ref()
|
||||
const formRef = ref();
|
||||
|
||||
const state = reactive({
|
||||
visible: false,
|
||||
loading: false,
|
||||
operation: 'add' as 'add' | 'edit' | 'view',
|
||||
title: computed(() => {
|
||||
return state.operation === 'add' ? '新增合同' : state.operation === 'edit' ? '编辑合同' : '合同详情';
|
||||
}),
|
||||
formData: {
|
||||
id: '',
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
money: 0,
|
||||
purchaseId: '',
|
||||
isBidding: '0',
|
||||
isLegalAdviser: '0',
|
||||
legalAdviserOpinion: '',
|
||||
isDepts: '0',
|
||||
isSchool: '0',
|
||||
remarks: ''
|
||||
}
|
||||
visible: false,
|
||||
loading: false,
|
||||
operation: 'add' as 'add' | 'edit' | 'view',
|
||||
title: computed(() => {
|
||||
return state.operation === 'add' ? '新增合同' : state.operation === 'edit' ? '编辑合同' : '合同详情';
|
||||
}),
|
||||
formData: {
|
||||
id: '',
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
money: 0,
|
||||
purchaseId: '',
|
||||
isBidding: '0',
|
||||
isLegalAdviser: '0',
|
||||
legalAdviserOpinion: '',
|
||||
isDepts: '0',
|
||||
isSchool: '0',
|
||||
remarks: '',
|
||||
},
|
||||
});
|
||||
|
||||
const rules = {
|
||||
contractNo: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
|
||||
money: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
||||
purchaseId: [{ required: true, message: '请输入采购申请ID', trigger: 'blur' }],
|
||||
isBidding: [{ required: true, message: '请选择是否需要招标', trigger: 'change' }],
|
||||
isLegalAdviser: [{ required: true, message: '请选择是否需要法律顾问', trigger: 'change' }],
|
||||
isDepts: [{ required: true, message: '请选择是否涉及多部门', trigger: 'change' }],
|
||||
isSchool: [{ required: true, message: '请选择是否全校合同', trigger: 'change' }]
|
||||
contractNo: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
|
||||
money: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
||||
purchaseId: [{ required: true, message: '请输入采购申请ID', trigger: 'blur' }],
|
||||
isBidding: [{ required: true, message: '请选择是否需要招标', trigger: 'change' }],
|
||||
isLegalAdviser: [{ required: true, message: '请选择是否需要法律顾问', trigger: 'change' }],
|
||||
isDepts: [{ required: true, message: '请选择是否涉及多部门', trigger: 'change' }],
|
||||
isSchool: [{ required: true, message: '请选择是否全校合同', trigger: 'change' }],
|
||||
};
|
||||
|
||||
const openDialog = async (operation: 'add' | 'edit' | 'view', row?: any) => {
|
||||
state.operation = operation;
|
||||
state.visible = true;
|
||||
state.loading = false;
|
||||
|
||||
if (operation === 'add') {
|
||||
resetForm();
|
||||
state.formData.isBidding = '0';
|
||||
state.formData.isLegalAdviser = '0';
|
||||
state.formData.isDepts = '0';
|
||||
state.formData.isSchool = '0';
|
||||
} else if (row) {
|
||||
state.formData.id = row.id;
|
||||
await loadData();
|
||||
}
|
||||
state.operation = operation;
|
||||
state.visible = true;
|
||||
state.loading = false;
|
||||
|
||||
if (operation === 'add') {
|
||||
resetForm();
|
||||
state.formData.isBidding = '0';
|
||||
state.formData.isLegalAdviser = '0';
|
||||
state.formData.isDepts = '0';
|
||||
state.formData.isSchool = '0';
|
||||
} else if (row) {
|
||||
state.formData.id = row.id;
|
||||
await loadData();
|
||||
}
|
||||
};
|
||||
|
||||
const loadData = async () => {
|
||||
try {
|
||||
state.loading = true;
|
||||
const res: any = await getObj(state.formData.id);
|
||||
if (res.data) {
|
||||
Object.assign(state.formData, res.data);
|
||||
}
|
||||
} catch (err) {
|
||||
useMessage().error('加载数据失败');
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
try {
|
||||
state.loading = true;
|
||||
const res: any = await getObj(state.formData.id);
|
||||
if (res.data) {
|
||||
Object.assign(state.formData, res.data);
|
||||
}
|
||||
} catch (err) {
|
||||
useMessage().error('加载数据失败');
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const valid = await formRef.value?.validate().catch(() => false);
|
||||
if (!valid) return;
|
||||
const valid = await formRef.value?.validate().catch(() => false);
|
||||
if (!valid) return;
|
||||
|
||||
try {
|
||||
state.loading = true;
|
||||
if (state.operation === 'add') {
|
||||
await addObj(state.formData);
|
||||
useMessage().success('新增成功');
|
||||
} else {
|
||||
await editObj(state.formData);
|
||||
useMessage().success('修改成功');
|
||||
}
|
||||
handleClose();
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '操作失败');
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
try {
|
||||
state.loading = true;
|
||||
if (state.operation === 'add') {
|
||||
await addObj(state.formData);
|
||||
useMessage().success('新增成功');
|
||||
} else {
|
||||
await editObj(state.formData);
|
||||
useMessage().success('修改成功');
|
||||
}
|
||||
handleClose();
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '操作失败');
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
state.visible = false;
|
||||
resetForm();
|
||||
state.visible = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
formRef.value?.resetFields();
|
||||
state.formData = {
|
||||
id: '',
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
money: 0,
|
||||
purchaseId: '',
|
||||
isBidding: '0',
|
||||
isLegalAdviser: '0',
|
||||
legalAdviserOpinion: '',
|
||||
isDepts: '0',
|
||||
isSchool: '0',
|
||||
remarks: ''
|
||||
};
|
||||
formRef.value?.resetFields();
|
||||
state.formData = {
|
||||
id: '',
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
money: 0,
|
||||
purchaseId: '',
|
||||
isBidding: '0',
|
||||
isLegalAdviser: '0',
|
||||
legalAdviserOpinion: '',
|
||||
isDepts: '0',
|
||||
isSchool: '0',
|
||||
remarks: '',
|
||||
};
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,301 +1,263 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="合同编号" prop="contractNo">
|
||||
<el-input
|
||||
v-model="state.queryForm.contractNo"
|
||||
placeholder="请输入合同编号"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同名称" prop="contractName">
|
||||
<el-input
|
||||
v-model="state.queryForm.contractName"
|
||||
placeholder="请输入合同名称"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要招标" prop="isBidding">
|
||||
<el-select
|
||||
v-model="state.queryForm.isBidding"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 200px">
|
||||
<el-option label="否" value="0" />
|
||||
<el-option label="是" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="合同编号" prop="contractNo">
|
||||
<el-input v-model="state.queryForm.contractNo" placeholder="请输入合同编号" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同名称" prop="contractName">
|
||||
<el-input v-model="state.queryForm.contractName" placeholder="请输入合同名称" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要招标" prop="isBidding">
|
||||
<el-select v-model="state.queryForm.isBidding" placeholder="请选择" clearable style="width: 200px">
|
||||
<el-option label="否" value="0" />
|
||||
<el-option label="是" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
采购合同管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="FolderAdd"
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog('add')">
|
||||
新增
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
采购合同管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog('add')"> 新增 </el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contractNo" label="合同编号" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><DocumentCopy /></el-icon>
|
||||
<span style="margin-left: 4px">合同编号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contractName" label="合同名称" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Document /></el-icon>
|
||||
<span style="margin-left: 4px">合同名称</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="money" label="合同金额(元)" min-width="130" align="right">
|
||||
<template #header>
|
||||
<el-icon><Money /></el-icon>
|
||||
<span style="margin-left: 4px">合同金额(元)</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
{{ formatMoney(scope.row.money) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isBidding" label="是否需要招标" min-width="120" align="center">
|
||||
<template #header>
|
||||
<el-icon><Tickets /></el-icon>
|
||||
<span style="margin-left: 4px">是否需要招标</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isBidding === '1' ? 'warning' : 'info'" size="small">
|
||||
{{ scope.row.isBidding === '1' ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isLegalAdviser" label="是否需要法律顾问" min-width="140" align="center">
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">是否需要法律顾问</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isLegalAdviser === '1' ? 'warning' : 'info'" size="small">
|
||||
{{ scope.row.isLegalAdviser === '1' ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isDepts" label="是否涉及多部门" min-width="120" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isDepts === '1' ? 'warning' : 'info'" size="small">
|
||||
{{ scope.row.isDepts === '1' ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isSchool" label="是否全校合同" min-width="120" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isSchool === '1' ? 'success' : 'info'" size="small">
|
||||
{{ scope.row.isSchool === '1' ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="170" align="center">
|
||||
<template #header>
|
||||
<el-icon><Calendar /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="180">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="Edit"
|
||||
link
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog('edit', scope.row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="View"
|
||||
link
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog('view', scope.row)">
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Delete"
|
||||
link
|
||||
type="danger"
|
||||
@click="handleDelete(scope.row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contractNo" label="合同编号" min-width="150" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><DocumentCopy /></el-icon>
|
||||
<span style="margin-left: 4px">合同编号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contractName" label="合同名称" min-width="200" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Document /></el-icon>
|
||||
<span style="margin-left: 4px">合同名称</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="money" label="合同金额(元)" min-width="130" align="right">
|
||||
<template #header>
|
||||
<el-icon><Money /></el-icon>
|
||||
<span style="margin-left: 4px">合同金额(元)</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
{{ formatMoney(scope.row.money) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isBidding" label="是否需要招标" min-width="120" align="center">
|
||||
<template #header>
|
||||
<el-icon><Tickets /></el-icon>
|
||||
<span style="margin-left: 4px">是否需要招标</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isBidding === '1' ? 'warning' : 'info'" size="small">
|
||||
{{ scope.row.isBidding === '1' ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isLegalAdviser" label="是否需要法律顾问" min-width="140" align="center">
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">是否需要法律顾问</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isLegalAdviser === '1' ? 'warning' : 'info'" size="small">
|
||||
{{ scope.row.isLegalAdviser === '1' ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isDepts" label="是否涉及多部门" min-width="120" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isDepts === '1' ? 'warning' : 'info'" size="small">
|
||||
{{ scope.row.isDepts === '1' ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isSchool" label="是否全校合同" min-width="120" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isSchool === '1' ? 'success' : 'info'" size="small">
|
||||
{{ scope.row.isSchool === '1' ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="170" align="center">
|
||||
<template #header>
|
||||
<el-icon><Calendar /></el-icon>
|
||||
<span style="margin-left: 4px">创建时间</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="180">
|
||||
<template #default="scope">
|
||||
<el-button icon="Edit" link type="primary" @click="formDialogRef.openDialog('edit', scope.row)"> 编辑 </el-button>
|
||||
<el-button icon="View" link type="primary" @click="formDialogRef.openDialog('view', scope.row)"> 详情 </el-button>
|
||||
<el-button icon="Delete" link type="danger" @click="handleDelete(scope.row)"> 删除 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-model:current="state.queryForm.current"
|
||||
v-model:size="state.queryForm.size"
|
||||
:total="state.total"
|
||||
@getDataList="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<pagination v-model:current="state.queryForm.current" v-model:size="state.queryForm.size" :total="state.total" @getDataList="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
<!-- 编辑、新增表单对话框 -->
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingContract">
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { getPage, delObj } from "/@/api/purchase/purchasingcontract";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { Search, Document, DocumentCopy, List, Money, Tickets, User, Calendar } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { getPage, delObj } from '/@/api/purchase/purchasingcontract';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { Search, Document, DocumentCopy, List, Money, Tickets, User, Calendar } from '@element-plus/icons-vue';
|
||||
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
|
||||
const showSearch = ref(true)
|
||||
const tableRef = ref()
|
||||
const formDialogRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const showSearch = ref(true);
|
||||
const tableRef = ref();
|
||||
const formDialogRef = ref();
|
||||
const searchFormRef = ref();
|
||||
|
||||
const formatMoney = (money: number | string) => {
|
||||
if (money == null) return '-';
|
||||
const num = Number(money);
|
||||
return isNaN(num) ? money : num.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
if (money == null) return '-';
|
||||
const num = Number(money);
|
||||
return isNaN(num) ? money : num.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
};
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
isBidding: ''
|
||||
},
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
isBidding: '',
|
||||
},
|
||||
});
|
||||
|
||||
const { getDataList, tableStyle } = useTable(state);
|
||||
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modern-page-container {
|
||||
padding: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.page-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.search-card :deep(.el-card__body) {
|
||||
padding-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.content-card :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
margin-right: 8px;
|
||||
font-size: 18px;
|
||||
margin-right: 8px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.ml10 {
|
||||
margin-left: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.modern-table {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.el-table__header-wrapper) {
|
||||
background-color: #f5f7fa;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,280 +1,236 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="文件归档"
|
||||
width="900px"
|
||||
destroy-on-close
|
||||
append-to-body
|
||||
>
|
||||
<template #header>
|
||||
<div class="dialog-header">
|
||||
<span class="dialog-title">
|
||||
<el-icon><FolderOpened /></el-icon>
|
||||
文件归档 - {{ purchaseNo || purchaseId }}
|
||||
</span>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="downloading"
|
||||
@click="handleDownloadAll"
|
||||
>
|
||||
<el-icon><Download /></el-icon>
|
||||
下载全部文件
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-dialog v-model="visible" title="文件归档" width="900px" destroy-on-close append-to-body>
|
||||
<template #header>
|
||||
<div class="dialog-header">
|
||||
<span class="dialog-title">
|
||||
<el-icon><FolderOpened /></el-icon>
|
||||
文件归档 - {{ purchaseNo || purchaseId }}
|
||||
</span>
|
||||
<el-button type="primary" :loading="downloading" @click="handleDownloadAll">
|
||||
<el-icon><Download /></el-icon>
|
||||
下载全部文件
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="fileList"
|
||||
stripe
|
||||
border
|
||||
max-height="500px"
|
||||
class="file-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="fileTitle" label="文件名称" min-width="220" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<div class="file-name">
|
||||
<el-icon class="file-icon"><Document /></el-icon>
|
||||
<span>{{ row.fileTitle }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="fileTypeDesc" label="文件类型" width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="info">{{ row.fileTypeDesc || '未知类型' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
icon="View"
|
||||
@click="handlePreview(row)"
|
||||
>
|
||||
预览
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
icon="Download"
|
||||
@click="handleDownloadFile(row)"
|
||||
>
|
||||
下载
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table v-loading="loading" :data="fileList" stripe border max-height="500px" class="file-table">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="fileTitle" label="文件名称" min-width="220" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<div class="file-name">
|
||||
<el-icon class="file-icon"><Document /></el-icon>
|
||||
<span>{{ row.fileTitle }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="fileTypeDesc" label="文件类型" width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="info">{{ row.fileTypeDesc || '未知类型' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link icon="View" @click="handlePreview(row)"> 预览 </el-button>
|
||||
<el-button type="primary" link icon="Download" @click="handleDownloadFile(row)"> 下载 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div v-if="!loading && fileList.length === 0" class="empty-tip">
|
||||
<el-empty description="暂无文件" />
|
||||
</div>
|
||||
<div v-if="!loading && fileList.length === 0" class="empty-tip">
|
||||
<el-empty description="暂无文件" />
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- PDF预览弹窗 -->
|
||||
<el-dialog
|
||||
v-model="previewVisible"
|
||||
title="文件预览"
|
||||
width="90%"
|
||||
top="5vh"
|
||||
destroy-on-close
|
||||
append-to-body
|
||||
class="preview-dialog"
|
||||
>
|
||||
<div class="preview-container">
|
||||
<iframe
|
||||
v-if="previewUrl"
|
||||
:src="previewUrl"
|
||||
class="preview-iframe"
|
||||
frameborder="0"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- PDF预览弹窗 -->
|
||||
<el-dialog v-model="previewVisible" title="文件预览" width="90%" top="5vh" destroy-on-close append-to-body class="preview-dialog">
|
||||
<div class="preview-container">
|
||||
<iframe v-if="previewUrl" :src="previewUrl" class="preview-iframe" frameborder="0" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onUnmounted } from 'vue'
|
||||
import { FolderOpened, Download, Document } from '@element-plus/icons-vue'
|
||||
import { useMessage } from '/@/hooks/message'
|
||||
import { listDownloadUrls, getArchiveDownloadUrl, downloadFileById, previewFileById } from '/@/api/purchase/purchasingrequisition'
|
||||
import other from '/@/utils/other'
|
||||
import { ref, computed, onUnmounted } from 'vue';
|
||||
import { FolderOpened, Download, Document } from '@element-plus/icons-vue';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { listDownloadUrls, getArchiveDownloadUrl, downloadFileById, previewFileById } from '/@/api/purchase/purchasingrequisition';
|
||||
import other from '/@/utils/other';
|
||||
|
||||
interface FileItem {
|
||||
id: string
|
||||
fileTitle: string
|
||||
fileType: string
|
||||
fileTypeDesc: string
|
||||
downloadUrl: string
|
||||
id: string;
|
||||
fileTitle: string;
|
||||
fileType: string;
|
||||
fileTypeDesc: string;
|
||||
downloadUrl: string;
|
||||
}
|
||||
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const downloading = ref(false)
|
||||
const previewVisible = ref(false)
|
||||
const previewUrl = ref('')
|
||||
const previewLoading = ref(false)
|
||||
const purchaseId = ref('')
|
||||
const purchaseNo = ref('')
|
||||
const fileList = ref<FileItem[]>([])
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const downloading = ref(false);
|
||||
const previewVisible = ref(false);
|
||||
const previewUrl = ref('');
|
||||
const previewLoading = ref(false);
|
||||
const purchaseId = ref('');
|
||||
const purchaseNo = ref('');
|
||||
const fileList = ref<FileItem[]>([]);
|
||||
|
||||
const open = async (id: string, no?: string) => {
|
||||
purchaseId.value = id || ''
|
||||
purchaseNo.value = no || ''
|
||||
visible.value = true
|
||||
await loadFileList()
|
||||
}
|
||||
purchaseId.value = id || '';
|
||||
purchaseNo.value = no || '';
|
||||
visible.value = true;
|
||||
await loadFileList();
|
||||
};
|
||||
|
||||
const loadFileList = async () => {
|
||||
if (!purchaseId.value) {
|
||||
useMessage().warning('无法获取采购申请ID')
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await listDownloadUrls(purchaseId.value)
|
||||
if (res && res.data) {
|
||||
fileList.value = res.data as FileItem[]
|
||||
} else {
|
||||
fileList.value = []
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err?.msg || '获取文件列表失败')
|
||||
fileList.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
if (!purchaseId.value) {
|
||||
useMessage().warning('无法获取采购申请ID');
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await listDownloadUrls(purchaseId.value);
|
||||
if (res && res.data) {
|
||||
fileList.value = res.data as FileItem[];
|
||||
} else {
|
||||
fileList.value = [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err?.msg || '获取文件列表失败');
|
||||
fileList.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const isPdfFile = (fileName: string): boolean => {
|
||||
if (!fileName) return false
|
||||
const ext = fileName.toLowerCase().split('.').pop()
|
||||
return ext === 'pdf'
|
||||
}
|
||||
if (!fileName) return false;
|
||||
const ext = fileName.toLowerCase().split('.').pop();
|
||||
return ext === 'pdf';
|
||||
};
|
||||
|
||||
const handlePreview = async (row: FileItem) => {
|
||||
if (!row.id) {
|
||||
useMessage().warning('文件ID不存在')
|
||||
return
|
||||
}
|
||||
if (!row.id) {
|
||||
useMessage().warning('文件ID不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isPdfFile(row.fileTitle)) {
|
||||
useMessage().info('仅支持PDF格式文件预览,将为您下载文件')
|
||||
handleDownloadFile(row)
|
||||
return
|
||||
}
|
||||
if (!isPdfFile(row.fileTitle)) {
|
||||
useMessage().info('仅支持PDF格式文件预览,将为您下载文件');
|
||||
handleDownloadFile(row);
|
||||
return;
|
||||
}
|
||||
|
||||
previewLoading.value = true
|
||||
previewVisible.value = true
|
||||
previewUrl.value = ''
|
||||
previewLoading.value = true;
|
||||
previewVisible.value = true;
|
||||
previewUrl.value = '';
|
||||
|
||||
try {
|
||||
const res = await previewFileById(row.id)
|
||||
const blob = res as unknown as Blob
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
previewUrl.value = url
|
||||
} catch (err: any) {
|
||||
useMessage().error(err?.msg || '预览失败')
|
||||
previewVisible.value = false
|
||||
} finally {
|
||||
previewLoading.value = false
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await previewFileById(row.id);
|
||||
const blob = res as unknown as Blob;
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
previewUrl.value = url;
|
||||
} catch (err: any) {
|
||||
useMessage().error(err?.msg || '预览失败');
|
||||
previewVisible.value = false;
|
||||
} finally {
|
||||
previewLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleDownloadFile = async (row: FileItem) => {
|
||||
if (!row.id) {
|
||||
useMessage().warning('文件ID不存在')
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await downloadFileById(row.id)
|
||||
const blob = res as unknown as Blob
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = row.fileTitle || 'download'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
window.URL.revokeObjectURL(url)
|
||||
} catch (err: any) {
|
||||
useMessage().error(err?.msg || '下载失败')
|
||||
}
|
||||
}
|
||||
if (!row.id) {
|
||||
useMessage().warning('文件ID不存在');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await downloadFileById(row.id);
|
||||
const blob = res as unknown as Blob;
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = row.fileTitle || 'download';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (err: any) {
|
||||
useMessage().error(err?.msg || '下载失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleDownloadAll = () => {
|
||||
if (!purchaseId.value) {
|
||||
useMessage().warning('无法获取采购申请ID')
|
||||
return
|
||||
}
|
||||
downloading.value = true
|
||||
try {
|
||||
const url = getArchiveDownloadUrl(purchaseId.value)
|
||||
const fileName = `归档_${purchaseNo.value || purchaseId.value}.zip`
|
||||
other.downBlobFile(url, {}, fileName)
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
downloading.value = false
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
if (!purchaseId.value) {
|
||||
useMessage().warning('无法获取采购申请ID');
|
||||
return;
|
||||
}
|
||||
downloading.value = true;
|
||||
try {
|
||||
const url = getArchiveDownloadUrl(purchaseId.value);
|
||||
const fileName = `归档_${purchaseNo.value || purchaseId.value}.zip`;
|
||||
other.downBlobFile(url, {}, fileName);
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
downloading.value = false;
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
if (previewUrl.value) {
|
||||
window.URL.revokeObjectURL(previewUrl.value)
|
||||
}
|
||||
})
|
||||
if (previewUrl.value) {
|
||||
window.URL.revokeObjectURL(previewUrl.value);
|
||||
}
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.file-table {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
color: #409eff;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
padding: 40px 0;
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
width: 100%;
|
||||
height: calc(90vh - 120px);
|
||||
width: 100%;
|
||||
height: calc(90vh - 120px);
|
||||
}
|
||||
|
||||
.preview-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,7 +9,12 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-alert title="仅支持上传PDF格式文件,每个类型仅能上传1个文件,如需更新,请先删除原文件" type="info" :closable="false" style="margin-bottom: 16px" />
|
||||
<el-alert
|
||||
title="仅支持上传PDF格式文件,每个类型仅能上传1个文件,如需更新,请先删除原文件"
|
||||
type="info"
|
||||
:closable="false"
|
||||
style="margin-bottom: 16px"
|
||||
/>
|
||||
|
||||
<el-empty v-if="uploadedFileTypes.length === 0" description="该采购申请暂无上传材料" />
|
||||
|
||||
@@ -82,12 +87,7 @@ const fileTypeList: FileTypeItem[] = [
|
||||
|
||||
// 根据已上传文件类型过滤显示列表(排除履约验收110和采购文件130)
|
||||
const displayedFileTypes = computed(() => {
|
||||
return fileTypeList.filter(
|
||||
(item) =>
|
||||
uploadedFileTypes.value.includes(item.value) &&
|
||||
item.value !== '110' &&
|
||||
item.value !== '130'
|
||||
);
|
||||
return fileTypeList.filter((item) => uploadedFileTypes.value.includes(item.value) && item.value !== '110' && item.value !== '130');
|
||||
});
|
||||
|
||||
const open = async (id: string, no?: string) => {
|
||||
@@ -149,13 +149,13 @@ const handleSubmit = async () => {
|
||||
uploadedFileTypes.value
|
||||
.filter((ft) => ft !== '110' && ft !== '130')
|
||||
.forEach((fileType) => {
|
||||
const files = fileMap[fileType] || [];
|
||||
files.forEach((file) => {
|
||||
if (file.id) {
|
||||
allFileIds.push(file.id);
|
||||
}
|
||||
const files = fileMap[fileType] || [];
|
||||
files.forEach((file) => {
|
||||
if (file.id) {
|
||||
allFileIds.push(file.id);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (allFileIds.length === 0) {
|
||||
useMessage().warning('请至少保留或上传一个文件');
|
||||
|
||||
@@ -1,188 +1,201 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="160px" >
|
||||
<el-row :gutter="24">
|
||||
<!-- <el-col :span="12" class="mb20">-->
|
||||
<!-- <el-form-item label="验收日期" prop="acceptDate">-->
|
||||
<!-- <el-date-picker-->
|
||||
<!-- v-model="form.acceptDate"-->
|
||||
<!-- type="date"-->
|
||||
<!-- placeholder="请选择"-->
|
||||
<!-- format="YYYY-MM-DD"-->
|
||||
<!-- value-format="YYYY-MM-DD"-->
|
||||
<!-- style="width: 100%"-->
|
||||
<!-- :disabled="readonly"-->
|
||||
<!-- />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="160px">
|
||||
<el-row :gutter="24">
|
||||
<!-- <el-col :span="12" class="mb20">-->
|
||||
<!-- <el-form-item label="验收日期" prop="acceptDate">-->
|
||||
<!-- <el-date-picker-->
|
||||
<!-- v-model="form.acceptDate"-->
|
||||
<!-- type="date"-->
|
||||
<!-- placeholder="请选择"-->
|
||||
<!-- format="YYYY-MM-DD"-->
|
||||
<!-- value-format="YYYY-MM-DD"-->
|
||||
<!-- style="width: 100%"-->
|
||||
<!-- :disabled="readonly"-->
|
||||
<!-- />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
|
||||
<!-- 上传履约验收模版 -->
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="履约验收文件" prop="templateFileIds" :required="true">
|
||||
<upload-file v-model="templateFiles" :limit="1" :file-type="['pdf']" :data="{ purchaseId: purchaseId || '', fileType: '110' }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="readonly" />
|
||||
<el-link v-if="!readonly" type="primary" @click="handleDownloadTemplate" style="margin-top: 8px; display: inline-flex; align-items: center;">
|
||||
<el-icon><Download /></el-icon>
|
||||
<span style="margin-left: 4px;">下载{{ lyysTemplateLabel }}</span>
|
||||
</el-link>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 上传履约验收模版 -->
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="履约验收文件" prop="templateFileIds" :required="true">
|
||||
<upload-file
|
||||
v-model="templateFiles"
|
||||
:limit="1"
|
||||
:file-type="['pdf']"
|
||||
:data="{ purchaseId: purchaseId || '', fileType: '110' }"
|
||||
upload-file-url="/purchase/purchasingfiles/upload"
|
||||
:disabled="readonly"
|
||||
/>
|
||||
<el-link v-if="!readonly" type="primary" @click="handleDownloadTemplate" style="margin-top: 8px; display: inline-flex; align-items: center">
|
||||
<el-icon><Download /></el-icon>
|
||||
<span style="margin-left: 4px">下载{{ lyysTemplateLabel }}</span>
|
||||
</el-link>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入" :disabled="readonly" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入" :disabled="readonly" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch, onMounted } from 'vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { Download } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import UploadFile from "/@/components/Upload/index.vue";
|
||||
import { downloadTemplate } from "/@/api/purchase/purchasingAccept";
|
||||
import { ref, reactive, computed, watch, onMounted } from 'vue';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { Download } from '@element-plus/icons-vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import UploadFile from '/@/components/Upload/index.vue';
|
||||
import { downloadTemplate } from '/@/api/purchase/purchasingAccept';
|
||||
|
||||
/** 项目类型 A:货物 B:工程 C:服务 */
|
||||
const LYYS_TEMPLATE_MAP: Record<string, { label: string }> = {
|
||||
A: { label: '履约验收表模板(货物)' },
|
||||
B: { label: '履约验收表模板(工程)' },
|
||||
C: { label: '履约验收表模板(服务)' },
|
||||
}
|
||||
A: { label: '履约验收表模板(货物)' },
|
||||
B: { label: '履约验收表模板(工程)' },
|
||||
C: { label: '履约验收表模板(服务)' },
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: Record<string, any>
|
||||
readonly?: boolean
|
||||
purchaseId?: string
|
||||
/** 项目类型 A:货物 B:工程 C:服务,用于模版下载 */
|
||||
projectType?: string
|
||||
/** 预算金额,用于判断模板目录 */
|
||||
budget?: number
|
||||
batchNum?: number
|
||||
}>()
|
||||
modelValue: Record<string, any>;
|
||||
readonly?: boolean;
|
||||
purchaseId?: string;
|
||||
/** 项目类型 A:货物 B:工程 C:服务,用于模版下载 */
|
||||
projectType?: string;
|
||||
/** 预算金额,用于判断模板目录 */
|
||||
budget?: number;
|
||||
batchNum?: number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const formRef = ref<FormInstance>();
|
||||
// 文件对象数组,用于上传组件显示(包含id和fileTitle)
|
||||
const templateFiles = ref<any[]>([])
|
||||
const templateFiles = ref<any[]>([]);
|
||||
|
||||
const projectTypeKey = computed(() => (props.projectType === 'A' || props.projectType === 'B' || props.projectType === 'C' ? props.projectType : 'A'))
|
||||
const projectTypeKey = computed(() =>
|
||||
props.projectType === 'A' || props.projectType === 'B' || props.projectType === 'C' ? props.projectType : 'A'
|
||||
);
|
||||
const lyysTemplateLabel = computed(() => {
|
||||
const amountLabel = (props.budget && props.budget >= 50000) ? '(≥5万)' : '(<5万)'
|
||||
return LYYS_TEMPLATE_MAP[projectTypeKey.value]?.label + amountLabel || LYYS_TEMPLATE_MAP.A.label + amountLabel
|
||||
})
|
||||
const lyysTemplateDownloadName = computed(() => `${lyysTemplateLabel.value}.docx`)
|
||||
const amountLabel = props.budget && props.budget >= 50000 ? '(≥5万)' : '(<5万)';
|
||||
return LYYS_TEMPLATE_MAP[projectTypeKey.value]?.label + amountLabel || LYYS_TEMPLATE_MAP.A.label + amountLabel;
|
||||
});
|
||||
const lyysTemplateDownloadName = computed(() => `${lyysTemplateLabel.value}.docx`);
|
||||
|
||||
/** 下载模板 - 调用后台接口 */
|
||||
const handleDownloadTemplate = async () => {
|
||||
if (!props.purchaseId) {
|
||||
ElMessage.warning('采购ID不存在')
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await downloadTemplate(props.purchaseId)
|
||||
const blob = res as unknown as Blob
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = lyysTemplateDownloadName.value
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
window.URL.revokeObjectURL(url)
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.message || '下载模板失败')
|
||||
}
|
||||
}
|
||||
if (!props.purchaseId) {
|
||||
ElMessage.warning('采购ID不存在');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await downloadTemplate(props.purchaseId);
|
||||
const blob = res as unknown as Blob;
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = lyysTemplateDownloadName.value;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.message || '下载模板失败');
|
||||
}
|
||||
};
|
||||
|
||||
const form = reactive({
|
||||
acceptType: '2', // 固定为上传模式
|
||||
acceptDate: '',
|
||||
templateFileIds: [] as string[],
|
||||
remark: '',
|
||||
})
|
||||
acceptType: '2', // 固定为上传模式
|
||||
acceptDate: '',
|
||||
templateFileIds: [] as string[],
|
||||
remark: '',
|
||||
});
|
||||
|
||||
// 从外部数据初始化(仅在挂载和 modelValue 引用变化时执行)
|
||||
const initData = () => {
|
||||
const val = props.modelValue
|
||||
if (!val) return
|
||||
const val = props.modelValue;
|
||||
if (!val) return;
|
||||
|
||||
form.acceptType = '2'
|
||||
form.acceptDate = val.acceptDate || ''
|
||||
form.remark = val.remark || ''
|
||||
form.acceptType = '2';
|
||||
form.acceptDate = val.acceptDate || '';
|
||||
form.remark = val.remark || '';
|
||||
|
||||
// 处理文件数据:支持 _templateFiles 数组或 templateFileIds
|
||||
if (val._templateFiles && Array.isArray(val._templateFiles)) {
|
||||
templateFiles.value = val._templateFiles.map((f: any) => ({
|
||||
id: f.id,
|
||||
fileTitle: f.fileTitle,
|
||||
name: f.fileTitle || '',
|
||||
url: '',
|
||||
}))
|
||||
form.templateFileIds = val._templateFiles.map((f: any) => f.id)
|
||||
} else if (val.templateFileIds) {
|
||||
if (typeof val.templateFileIds === 'string') {
|
||||
const ids = val.templateFileIds.split(',').filter(Boolean)
|
||||
templateFiles.value = ids.map((id: string) => ({ id: id.trim(), name: '', url: '' }))
|
||||
form.templateFileIds = ids
|
||||
} else if (Array.isArray(val.templateFileIds)) {
|
||||
templateFiles.value = val.templateFileIds.map((item: any) => {
|
||||
if (typeof item === 'string') return { id: item, name: '', url: '' }
|
||||
return { id: item.id, fileTitle: item.fileTitle, name: item.fileTitle || '', url: '' }
|
||||
})
|
||||
form.templateFileIds = val.templateFileIds.map((item: any) => typeof item === 'string' ? item : item.id).filter(Boolean)
|
||||
}
|
||||
} else {
|
||||
templateFiles.value = []
|
||||
form.templateFileIds = []
|
||||
}
|
||||
}
|
||||
// 处理文件数据:支持 _templateFiles 数组或 templateFileIds
|
||||
if (val._templateFiles && Array.isArray(val._templateFiles)) {
|
||||
templateFiles.value = val._templateFiles.map((f: any) => ({
|
||||
id: f.id,
|
||||
fileTitle: f.fileTitle,
|
||||
name: f.fileTitle || '',
|
||||
url: '',
|
||||
}));
|
||||
form.templateFileIds = val._templateFiles.map((f: any) => f.id);
|
||||
} else if (val.templateFileIds) {
|
||||
if (typeof val.templateFileIds === 'string') {
|
||||
const ids = val.templateFileIds.split(',').filter(Boolean);
|
||||
templateFiles.value = ids.map((id: string) => ({ id: id.trim(), name: '', url: '' }));
|
||||
form.templateFileIds = ids;
|
||||
} else if (Array.isArray(val.templateFileIds)) {
|
||||
templateFiles.value = val.templateFileIds.map((item: any) => {
|
||||
if (typeof item === 'string') return { id: item, name: '', url: '' };
|
||||
return { id: item.id, fileTitle: item.fileTitle, name: item.fileTitle || '', url: '' };
|
||||
});
|
||||
form.templateFileIds = val.templateFileIds.map((item: any) => (typeof item === 'string' ? item : item.id)).filter(Boolean);
|
||||
}
|
||||
} else {
|
||||
templateFiles.value = [];
|
||||
form.templateFileIds = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 挂载时初始化
|
||||
onMounted(() => {
|
||||
initData()
|
||||
})
|
||||
initData();
|
||||
});
|
||||
|
||||
// 监听文件变化,更新 form.templateFileIds
|
||||
watch(templateFiles, (files) => {
|
||||
if (Array.isArray(files)) {
|
||||
form.templateFileIds = files.map((f: any) => f.id).filter(Boolean)
|
||||
} else {
|
||||
form.templateFileIds = []
|
||||
}
|
||||
}, { deep: true })
|
||||
watch(
|
||||
templateFiles,
|
||||
(files) => {
|
||||
if (Array.isArray(files)) {
|
||||
form.templateFileIds = files.map((f: any) => f.id).filter(Boolean);
|
||||
} else {
|
||||
form.templateFileIds = [];
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const rules: FormRules = {
|
||||
templateFileIds: [
|
||||
{
|
||||
validator: (_rule: any, value: any, callback: (e?: Error) => void) => {
|
||||
if (!value || (Array.isArray(value) && value.length === 0) || (typeof value === 'string' && !value.trim())) {
|
||||
callback(new Error('请上传履约验收文件'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
},
|
||||
trigger: 'change'
|
||||
},
|
||||
],
|
||||
}
|
||||
templateFileIds: [
|
||||
{
|
||||
validator: (_rule: any, value: any, callback: (e?: Error) => void) => {
|
||||
if (!value || (Array.isArray(value) && value.length === 0) || (typeof value === 'string' && !value.trim())) {
|
||||
callback(new Error('请上传履约验收文件'));
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const validate = () => formRef.value?.validate()
|
||||
const validate = () => formRef.value?.validate();
|
||||
|
||||
// 获取当前表单数据(供父组件调用)
|
||||
const getFormData = () => ({
|
||||
acceptType: form.acceptType,
|
||||
acceptDate: form.acceptDate,
|
||||
templateFileIds: [...form.templateFileIds],
|
||||
remark: form.remark,
|
||||
})
|
||||
acceptType: form.acceptType,
|
||||
acceptDate: form.acceptDate,
|
||||
templateFileIds: [...form.templateFileIds],
|
||||
remark: form.remark,
|
||||
});
|
||||
|
||||
defineExpose({ validate, form, getFormData, initData })
|
||||
defineExpose({ validate, form, getFormData, initData });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mb20 {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,356 +1,351 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="140px">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="项目名称">
|
||||
<el-input :model-value="projectName || form.projectName" readonly placeholder="-" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="需求部门">
|
||||
<el-input :model-value="deptName || form.deptName" readonly placeholder="-" disabled/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="是否签订合同" prop="hasContract">
|
||||
<el-radio-group v-model="form.hasContract">
|
||||
<el-radio label="0">否</el-radio>
|
||||
<el-radio label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20" v-if="form.hasContract === '1'">
|
||||
<el-form-item label="合同" prop="contractId">
|
||||
<el-select
|
||||
v-model="form.contractId"
|
||||
placeholder="请选择合同"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%"
|
||||
:loading="contractLoading"
|
||||
@visible-change="onContractSelectVisibleChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in contractOptions"
|
||||
:key="item.id"
|
||||
:label="item.contractName || item.contractNo || item.id"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="是否分期验收" prop="isInstallment">
|
||||
<el-radio-group v-model="form.isInstallment">
|
||||
<el-radio label="0">否</el-radio>
|
||||
<el-radio label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20" v-if="form.isInstallment === '1'">
|
||||
<el-form-item label="分期次数" prop="totalPhases">
|
||||
<el-input-number v-model="form.totalPhases" :min="1" :max="99" placeholder="请输入" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="供应商名称" prop="supplierName">
|
||||
<el-input v-model="form.supplierName" placeholder="选择合同后自动带出" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="资产管理员" prop="assetAdminId">
|
||||
<el-select
|
||||
v-model="form.assetAdminId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchAssetAdmin"
|
||||
:loading="assetAdminLoading"
|
||||
style="width: 100%"
|
||||
@change="onAssetAdminChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in assetAdminOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px;">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<div class="field-note">如入固定资产,必填</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="采购人员" prop="purchaserId">
|
||||
<el-select
|
||||
v-model="form.purchaserId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchPurchaser"
|
||||
:loading="purchaserLoading"
|
||||
style="width: 100%"
|
||||
@change="onPurchaserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in purchaserOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px;">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="140px">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="项目名称">
|
||||
<el-input :model-value="projectName || form.projectName" readonly placeholder="-" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="需求部门">
|
||||
<el-input :model-value="deptName || form.deptName" readonly placeholder="-" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="是否签订合同" prop="hasContract">
|
||||
<el-radio-group v-model="form.hasContract">
|
||||
<el-radio label="0">否</el-radio>
|
||||
<el-radio label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20" v-if="form.hasContract === '1'">
|
||||
<el-form-item label="合同" prop="contractId">
|
||||
<el-select
|
||||
v-model="form.contractId"
|
||||
placeholder="请选择合同"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%"
|
||||
:loading="contractLoading"
|
||||
@visible-change="onContractSelectVisibleChange"
|
||||
>
|
||||
<el-option v-for="item in contractOptions" :key="item.id" :label="item.contractName || item.contractNo || item.id" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="是否分期验收" prop="isInstallment">
|
||||
<el-radio-group v-model="form.isInstallment">
|
||||
<el-radio label="0">否</el-radio>
|
||||
<el-radio label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20" v-if="form.isInstallment === '1'">
|
||||
<el-form-item label="分期次数" prop="totalPhases">
|
||||
<el-input-number v-model="form.totalPhases" :min="1" :max="99" placeholder="请输入" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="供应商名称" prop="supplierName">
|
||||
<el-input v-model="form.supplierName" placeholder="选择合同后自动带出" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="资产管理员" prop="assetAdminId">
|
||||
<el-select
|
||||
v-model="form.assetAdminId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchAssetAdmin"
|
||||
:loading="assetAdminLoading"
|
||||
style="width: 100%"
|
||||
@change="onAssetAdminChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in assetAdminOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<div class="field-note">如入固定资产,必填</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="mb20">
|
||||
<el-form-item label="采购人员" prop="purchaserId">
|
||||
<el-select
|
||||
v-model="form.purchaserId"
|
||||
placeholder="请输入姓名或工号搜索"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
reserve-keyword
|
||||
:remote-method="searchPurchaser"
|
||||
:loading="purchaserLoading"
|
||||
style="width: 100%"
|
||||
@change="onPurchaserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in purchaserOptions"
|
||||
:key="item.teacherNo"
|
||||
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||
:value="item.teacherNo"
|
||||
>
|
||||
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||
<span style="color: #999; font-size: 12px; margin-left: 8px">{{ item.teacherNo }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8" class="mb20" v-if="form.hasContract === '0'">
|
||||
<el-form-item label="成交金额" prop="transactionAmount" :required="form.hasContract === '0'">
|
||||
<el-input-number
|
||||
v-model="form.transactionAmount"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
placeholder="请输入成交金额"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-col :span="8" class="mb20" v-if="form.hasContract === '0'">
|
||||
<el-form-item label="成交金额" prop="transactionAmount" :required="form.hasContract === '0'">
|
||||
<el-input-number v-model="form.transactionAmount" :min="0" :precision="2" placeholder="请输入成交金额" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch, onMounted } from 'vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { getContracts, searchTeachers } from '/@/api/purchase/purchasingrequisition'
|
||||
import { ref, reactive, watch, onMounted } from 'vue';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { getContracts, searchTeachers } from '/@/api/purchase/purchasingrequisition';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: Record<string, any>
|
||||
projectName?: string
|
||||
deptName?: string
|
||||
/** 采购申请ID,用于拉取合同列表 */
|
||||
purchaseId?: string | number
|
||||
/** 每次打开弹窗时变化,用于强制重置内部 form */
|
||||
resetKey?: number
|
||||
}>()
|
||||
modelValue: Record<string, any>;
|
||||
projectName?: string;
|
||||
deptName?: string;
|
||||
/** 采购申请ID,用于拉取合同列表 */
|
||||
purchaseId?: string | number;
|
||||
/** 每次打开弹窗时变化,用于强制重置内部 form */
|
||||
resetKey?: number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const contractOptions = ref<any[]>([])
|
||||
const contractLoading = ref(false)
|
||||
const contractLoaded = ref(false)
|
||||
const formRef = ref<FormInstance>();
|
||||
const contractOptions = ref<any[]>([]);
|
||||
const contractLoading = ref(false);
|
||||
const contractLoaded = ref(false);
|
||||
|
||||
// 采购人员相关
|
||||
const purchaserOptions = ref<any[]>([])
|
||||
const purchaserLoading = ref(false)
|
||||
const purchaserOptions = ref<any[]>([]);
|
||||
const purchaserLoading = ref(false);
|
||||
|
||||
// 资产管理员相关
|
||||
const assetAdminOptions = ref<any[]>([])
|
||||
const assetAdminLoading = ref(false)
|
||||
const assetAdminOptions = ref<any[]>([]);
|
||||
const assetAdminLoading = ref(false);
|
||||
|
||||
const form = reactive({
|
||||
hasContract: '0',
|
||||
contractId: '',
|
||||
isInstallment: '0',
|
||||
totalPhases: 1,
|
||||
projectName: '',
|
||||
deptName: '',
|
||||
supplierName: '',
|
||||
purchaserId: '',
|
||||
purchaserName: '',
|
||||
assetAdminId: '',
|
||||
assetAdminName: '',
|
||||
transactionAmount: null,
|
||||
...props.modelValue,
|
||||
})
|
||||
hasContract: '0',
|
||||
contractId: '',
|
||||
isInstallment: '0',
|
||||
totalPhases: 1,
|
||||
projectName: '',
|
||||
deptName: '',
|
||||
supplierName: '',
|
||||
purchaserId: '',
|
||||
purchaserName: '',
|
||||
assetAdminId: '',
|
||||
assetAdminName: '',
|
||||
transactionAmount: null,
|
||||
...props.modelValue,
|
||||
});
|
||||
|
||||
const syncFormFromModel = (val: Record<string, any> | undefined) => {
|
||||
Object.assign(form, val || {})
|
||||
// 加载已选人员信息用于回显
|
||||
if (form.purchaserId && form.purchaserName) {
|
||||
purchaserOptions.value = [{ teacherNo: form.purchaserId, realName: form.purchaserName, name: form.purchaserName }]
|
||||
}
|
||||
if (form.assetAdminId && form.assetAdminName) {
|
||||
assetAdminOptions.value = [{ teacherNo: form.assetAdminId, realName: form.assetAdminName, name: form.assetAdminName }]
|
||||
}
|
||||
}
|
||||
Object.assign(form, val || {});
|
||||
// 加载已选人员信息用于回显
|
||||
if (form.purchaserId && form.purchaserName) {
|
||||
purchaserOptions.value = [{ teacherNo: form.purchaserId, realName: form.purchaserName, name: form.purchaserName }];
|
||||
}
|
||||
if (form.assetAdminId && form.assetAdminName) {
|
||||
assetAdminOptions.value = [{ teacherNo: form.assetAdminId, realName: form.assetAdminName, name: form.assetAdminName }];
|
||||
}
|
||||
};
|
||||
|
||||
const loadContractOptions = async () => {
|
||||
if (contractLoaded.value || contractLoading.value) return
|
||||
if (form.hasContract !== '1') return
|
||||
contractLoading.value = true
|
||||
try {
|
||||
const res = await getContracts(props.purchaseId ? { id: props.purchaseId } : {})
|
||||
const list = res?.data
|
||||
contractOptions.value = Array.isArray(list) ? list : []
|
||||
contractLoaded.value = true
|
||||
// 回显时:列表中含当前合同,用其供应商名称填充(若尚未有值)
|
||||
if (form.contractId) {
|
||||
const c = contractOptions.value.find((it: any) => it.id === form.contractId)
|
||||
if (c?.supplierName) form.supplierName = c.supplierName
|
||||
}
|
||||
} catch (_) {
|
||||
contractOptions.value = []
|
||||
} finally {
|
||||
contractLoading.value = false
|
||||
}
|
||||
}
|
||||
if (contractLoaded.value || contractLoading.value) return;
|
||||
if (form.hasContract !== '1') return;
|
||||
contractLoading.value = true;
|
||||
try {
|
||||
const res = await getContracts(props.purchaseId ? { id: props.purchaseId } : {});
|
||||
const list = res?.data;
|
||||
contractOptions.value = Array.isArray(list) ? list : [];
|
||||
contractLoaded.value = true;
|
||||
// 回显时:列表中含当前合同,用其供应商名称填充(若尚未有值)
|
||||
if (form.contractId) {
|
||||
const c = contractOptions.value.find((it: any) => it.id === form.contractId);
|
||||
if (c?.supplierName) form.supplierName = c.supplierName;
|
||||
}
|
||||
} catch (_) {
|
||||
contractOptions.value = [];
|
||||
} finally {
|
||||
contractLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onContractSelectVisibleChange = (visible: boolean) => {
|
||||
if (visible && form.hasContract === '1' && contractOptions.value.length === 0) {
|
||||
loadContractOptions()
|
||||
}
|
||||
}
|
||||
if (visible && form.hasContract === '1' && contractOptions.value.length === 0) {
|
||||
loadContractOptions();
|
||||
}
|
||||
};
|
||||
|
||||
const searchPurchaser = async (query: string) => {
|
||||
if (!query) {
|
||||
purchaserOptions.value = []
|
||||
return
|
||||
}
|
||||
purchaserLoading.value = true
|
||||
try {
|
||||
const res = await searchTeachers(query)
|
||||
purchaserOptions.value = res?.data || []
|
||||
} catch (_) {
|
||||
purchaserOptions.value = []
|
||||
} finally {
|
||||
purchaserLoading.value = false
|
||||
}
|
||||
}
|
||||
if (!query) {
|
||||
purchaserOptions.value = [];
|
||||
return;
|
||||
}
|
||||
purchaserLoading.value = true;
|
||||
try {
|
||||
const res = await searchTeachers(query);
|
||||
purchaserOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
purchaserOptions.value = [];
|
||||
} finally {
|
||||
purchaserLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const searchAssetAdmin = async (query: string) => {
|
||||
if (!query) {
|
||||
assetAdminOptions.value = []
|
||||
return
|
||||
}
|
||||
assetAdminLoading.value = true
|
||||
try {
|
||||
const res = await searchTeachers(query)
|
||||
assetAdminOptions.value = res?.data || []
|
||||
} catch (_) {
|
||||
assetAdminOptions.value = []
|
||||
} finally {
|
||||
assetAdminLoading.value = false
|
||||
}
|
||||
}
|
||||
if (!query) {
|
||||
assetAdminOptions.value = [];
|
||||
return;
|
||||
}
|
||||
assetAdminLoading.value = true;
|
||||
try {
|
||||
const res = await searchTeachers(query);
|
||||
assetAdminOptions.value = res?.data || [];
|
||||
} catch (_) {
|
||||
assetAdminOptions.value = [];
|
||||
} finally {
|
||||
assetAdminLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onPurchaserChange = (teacherNo: string) => {
|
||||
if (!teacherNo) {
|
||||
form.purchaserId = ''
|
||||
form.purchaserName = ''
|
||||
return
|
||||
}
|
||||
const selected = purchaserOptions.value.find((item: any) => item.teacherNo === teacherNo)
|
||||
if (selected) {
|
||||
form.purchaserId = selected.teacherNo
|
||||
form.purchaserName = selected.realName || selected.name
|
||||
}
|
||||
}
|
||||
if (!teacherNo) {
|
||||
form.purchaserId = '';
|
||||
form.purchaserName = '';
|
||||
return;
|
||||
}
|
||||
const selected = purchaserOptions.value.find((item: any) => item.teacherNo === teacherNo);
|
||||
if (selected) {
|
||||
form.purchaserId = selected.teacherNo;
|
||||
form.purchaserName = selected.realName || selected.name;
|
||||
}
|
||||
};
|
||||
|
||||
const onAssetAdminChange = (teacherNo: string) => {
|
||||
if (!teacherNo) {
|
||||
form.assetAdminId = ''
|
||||
form.assetAdminName = ''
|
||||
return
|
||||
}
|
||||
const selected = assetAdminOptions.value.find((item: any) => item.teacherNo === teacherNo)
|
||||
if (selected) {
|
||||
form.assetAdminId = selected.teacherNo
|
||||
form.assetAdminName = selected.realName || selected.name
|
||||
}
|
||||
}
|
||||
if (!teacherNo) {
|
||||
form.assetAdminId = '';
|
||||
form.assetAdminName = '';
|
||||
return;
|
||||
}
|
||||
const selected = assetAdminOptions.value.find((item: any) => item.teacherNo === teacherNo);
|
||||
if (selected) {
|
||||
form.assetAdminId = selected.teacherNo;
|
||||
form.assetAdminName = selected.realName || selected.name;
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
syncFormFromModel(val)
|
||||
// 回显:已有合同ID时主动加载合同列表,以便下拉显示合同名称(后端已排除"其他申请"的合同,当前申请合同会在列表中)
|
||||
if (form.hasContract === '1' && form.contractId && props.purchaseId && !contractLoaded.value && !contractLoading.value) {
|
||||
loadContractOptions()
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
syncFormFromModel(val);
|
||||
// 回显:已有合同ID时主动加载合同列表,以便下拉显示合同名称(后端已排除"其他申请"的合同,当前申请合同会在列表中)
|
||||
if (form.hasContract === '1' && form.contractId && props.purchaseId && !contractLoaded.value && !contractLoading.value) {
|
||||
loadContractOptions();
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
// resetKey 变化时强制用 modelValue 覆盖内部 form,并重置合同列表以便重新拉取
|
||||
watch(() => props.resetKey, () => {
|
||||
syncFormFromModel(props.modelValue)
|
||||
contractLoaded.value = false
|
||||
contractOptions.value = []
|
||||
})
|
||||
watch(form, () => emit('update:modelValue', { ...form }), { deep: true })
|
||||
watch(
|
||||
() => props.resetKey,
|
||||
() => {
|
||||
syncFormFromModel(props.modelValue);
|
||||
contractLoaded.value = false;
|
||||
contractOptions.value = [];
|
||||
}
|
||||
);
|
||||
watch(form, () => emit('update:modelValue', { ...form }), { deep: true });
|
||||
|
||||
watch(() => form.hasContract, (val) => {
|
||||
if (val === '1') {
|
||||
contractLoaded.value = false
|
||||
loadContractOptions()
|
||||
} else {
|
||||
contractOptions.value = []
|
||||
contractLoaded.value = false
|
||||
}
|
||||
// hasContract 变化时触发 transactionAmount 校验
|
||||
formRef.value?.validateField('transactionAmount')
|
||||
})
|
||||
watch(
|
||||
() => form.hasContract,
|
||||
(val) => {
|
||||
if (val === '1') {
|
||||
contractLoaded.value = false;
|
||||
loadContractOptions();
|
||||
} else {
|
||||
contractOptions.value = [];
|
||||
contractLoaded.value = false;
|
||||
}
|
||||
// hasContract 变化时触发 transactionAmount 校验
|
||||
formRef.value?.validateField('transactionAmount');
|
||||
}
|
||||
);
|
||||
|
||||
// 选择合同后,自动带出合同供应商名称
|
||||
watch(
|
||||
() => form.contractId,
|
||||
(val) => {
|
||||
if (!val) {
|
||||
form.supplierName = ''
|
||||
return
|
||||
}
|
||||
const c = contractOptions.value.find((it: any) => it.id === val)
|
||||
if (c && c.supplierName) {
|
||||
form.supplierName = c.supplierName
|
||||
}
|
||||
}
|
||||
)
|
||||
() => form.contractId,
|
||||
(val) => {
|
||||
if (!val) {
|
||||
form.supplierName = '';
|
||||
return;
|
||||
}
|
||||
const c = contractOptions.value.find((it: any) => it.id === val);
|
||||
if (c && c.supplierName) {
|
||||
form.supplierName = c.supplierName;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
if (form.hasContract === '1') {
|
||||
loadContractOptions()
|
||||
}
|
||||
})
|
||||
if (form.hasContract === '1') {
|
||||
loadContractOptions();
|
||||
}
|
||||
});
|
||||
|
||||
const rules: FormRules = {
|
||||
hasContract: [{ required: true, message: '请选择是否签订合同', trigger: 'change' }],
|
||||
isInstallment: [{ required: true, message: '请选择是否分期验收', trigger: 'change' }],
|
||||
totalPhases: [{ required: true, message: '请输入分期次数', trigger: 'blur' }],
|
||||
transactionAmount: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
// 未签订合同时,成交金额为必填
|
||||
if (form.hasContract === '0' && (value === null || value === undefined || value === '')) {
|
||||
callback(new Error('未签订合同时,成交金额为必填'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
}
|
||||
hasContract: [{ required: true, message: '请选择是否签订合同', trigger: 'change' }],
|
||||
isInstallment: [{ required: true, message: '请选择是否分期验收', trigger: 'change' }],
|
||||
totalPhases: [{ required: true, message: '请输入分期次数', trigger: 'blur' }],
|
||||
transactionAmount: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
// 未签订合同时,成交金额为必填
|
||||
if (form.hasContract === '0' && (value === null || value === undefined || value === '')) {
|
||||
callback(new Error('未签订合同时,成交金额为必填'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const validate = () => formRef.value?.validate()
|
||||
const validate = () => formRef.value?.validate();
|
||||
|
||||
defineExpose({ validate, form })
|
||||
defineExpose({ validate, form });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mb20 {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.field-note {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,475 +1,456 @@
|
||||
<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 || ''
|
||||
|
||||
// 其他字段仅当存在已保存批次时回填
|
||||
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 || '',
|
||||
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) {
|
||||
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) {
|
||||
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 || '',
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
// 直接从子组件 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 ?? ''),
|
||||
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 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 ?? ''),
|
||||
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
|
||||
// acceptDate is now optional - removed the validation check
|
||||
|
||||
// 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: '',
|
||||
isInstallment: '0',
|
||||
totalPhases: 1,
|
||||
supplierName: '',
|
||||
purchaserId: '',
|
||||
purchaserName: '',
|
||||
assetAdminId: '',
|
||||
assetAdminName: '',
|
||||
transactionAmount: null,
|
||||
}
|
||||
hasContract: '0',
|
||||
contractId: '',
|
||||
isInstallment: '0',
|
||||
totalPhases: 1,
|
||||
supplierName: '',
|
||||
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>
|
||||
|
||||
@@ -1,229 +1,206 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="state.visible"
|
||||
:title="state.title"
|
||||
width="700px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="state.formData"
|
||||
:rules="rules"
|
||||
label-width="140px">
|
||||
<el-form-item label="合同编号" prop="contractNo">
|
||||
<el-input
|
||||
v-model="state.formData.contractNo"
|
||||
placeholder="请输入合同编号"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同名称" prop="contractName">
|
||||
<el-input
|
||||
v-model="state.formData.contractName"
|
||||
placeholder="请输入合同名称"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额(元)" prop="money">
|
||||
<el-input-number
|
||||
v-model="state.formData.money"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
placeholder="请输入合同金额"
|
||||
style="width: 100%"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要招标" prop="isBidding">
|
||||
<el-radio-group
|
||||
v-model="state.formData.isBidding"
|
||||
:disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要法律顾问" prop="isLegalAdviser">
|
||||
<el-radio-group
|
||||
v-model="state.formData.isLegalAdviser"
|
||||
:disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="state.formData.isLegalAdviser === '1'"
|
||||
label="法律顾问意见"
|
||||
prop="legalAdviserOpinion">
|
||||
<el-input
|
||||
v-model="state.formData.legalAdviserOpinion"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入法律顾问意见"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否涉及多个部门" prop="isDepts">
|
||||
<el-radio-group
|
||||
v-model="state.formData.isDepts"
|
||||
:disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否全校合同" prop="isSchool">
|
||||
<el-radio-group
|
||||
v-model="state.formData.isSchool"
|
||||
:disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks">
|
||||
<el-input
|
||||
v-model="state.formData.remarks"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入备注"
|
||||
:disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer v-if="state.operation !== 'view'">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="state.loading">确定</el-button>
|
||||
</template>
|
||||
<template #footer v-else>
|
||||
<el-button @click="handleClose">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="state.visible"
|
||||
:title="state.title"
|
||||
width="700px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-form ref="formRef" :model="state.formData" :rules="rules" label-width="140px">
|
||||
<el-form-item label="合同编号" prop="contractNo">
|
||||
<el-input v-model="state.formData.contractNo" placeholder="请输入合同编号" :disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同名称" prop="contractName">
|
||||
<el-input v-model="state.formData.contractName" placeholder="请输入合同名称" :disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额(元)" prop="money">
|
||||
<el-input-number
|
||||
v-model="state.formData.money"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
placeholder="请输入合同金额"
|
||||
style="width: 100%"
|
||||
:disabled="state.operation === 'view'"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要招标" prop="isBidding">
|
||||
<el-radio-group v-model="state.formData.isBidding" :disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要法律顾问" prop="isLegalAdviser">
|
||||
<el-radio-group v-model="state.formData.isLegalAdviser" :disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="state.formData.isLegalAdviser === '1'" label="法律顾问意见" prop="legalAdviserOpinion">
|
||||
<el-input
|
||||
v-model="state.formData.legalAdviserOpinion"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入法律顾问意见"
|
||||
:disabled="state.operation === 'view'"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否涉及多个部门" prop="isDepts">
|
||||
<el-radio-group v-model="state.formData.isDepts" :disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否全校合同" prop="isSchool">
|
||||
<el-radio-group v-model="state.formData.isSchool" :disabled="state.operation === 'view'">
|
||||
<el-radio value="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks">
|
||||
<el-input v-model="state.formData.remarks" type="textarea" :rows="2" placeholder="请输入备注" :disabled="state.operation === 'view'" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer v-if="state.operation !== 'view'">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="state.loading">确定</el-button>
|
||||
</template>
|
||||
<template #footer v-else>
|
||||
<el-button @click="handleClose">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="ContractDialog">
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { addObj, editObj } from "/@/api/purchase/purchasingcontract";
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
import { addObj, editObj } from '/@/api/purchase/purchasingcontract';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
const formRef = ref()
|
||||
const formRef = ref();
|
||||
|
||||
const state = reactive({
|
||||
visible: false,
|
||||
loading: false,
|
||||
operation: 'add' as 'add' | 'edit' | 'view',
|
||||
title: computed(() => {
|
||||
return state.operation === 'add' ? '新增合同' : state.operation === 'edit' ? '编辑合同' : '合同详情';
|
||||
}),
|
||||
formData: {
|
||||
id: '',
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
money: 0,
|
||||
purchaseId: '',
|
||||
isBidding: '0',
|
||||
isLegalAdviser: '0',
|
||||
legalAdviserOpinion: '',
|
||||
isDepts: '0',
|
||||
isSchool: '0',
|
||||
remarks: ''
|
||||
},
|
||||
purchaseNo: ''
|
||||
visible: false,
|
||||
loading: false,
|
||||
operation: 'add' as 'add' | 'edit' | 'view',
|
||||
title: computed(() => {
|
||||
return state.operation === 'add' ? '新增合同' : state.operation === 'edit' ? '编辑合同' : '合同详情';
|
||||
}),
|
||||
formData: {
|
||||
id: '',
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
money: 0,
|
||||
purchaseId: '',
|
||||
isBidding: '0',
|
||||
isLegalAdviser: '0',
|
||||
legalAdviserOpinion: '',
|
||||
isDepts: '0',
|
||||
isSchool: '0',
|
||||
remarks: '',
|
||||
},
|
||||
purchaseNo: '',
|
||||
});
|
||||
|
||||
const rules = {
|
||||
contractNo: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
|
||||
money: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
||||
isBidding: [{ required: true, message: '请选择是否需要招标', trigger: 'change' }],
|
||||
isLegalAdviser: [{ required: true, message: '请选择是否需要法律顾问', trigger: 'change' }],
|
||||
isDepts: [{ required: true, message: '请选择是否涉及多部门', trigger: 'change' }],
|
||||
isSchool: [{ required: true, message: '请选择是否全校合同', trigger: 'change' }]
|
||||
contractNo: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
|
||||
money: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
||||
isBidding: [{ required: true, message: '请选择是否需要招标', trigger: 'change' }],
|
||||
isLegalAdviser: [{ required: true, message: '请选择是否需要法律顾问', trigger: 'change' }],
|
||||
isDepts: [{ required: true, message: '请选择是否涉及多部门', trigger: 'change' }],
|
||||
isSchool: [{ required: true, message: '请选择是否全校合同', trigger: 'change' }],
|
||||
};
|
||||
|
||||
const openDialog = (purchaseApply: any, contract: any) => {
|
||||
state.visible = true;
|
||||
state.loading = false;
|
||||
state.purchaseNo = purchaseApply?.purchaseNo || '';
|
||||
state.formData.purchaseId = purchaseApply?.id || purchaseApply?.purchaseId || '';
|
||||
|
||||
if (contract && contract.id) {
|
||||
state.operation = 'edit';
|
||||
state.formData = {
|
||||
id: contract.id,
|
||||
contractNo: contract.contractNo || '',
|
||||
contractName: contract.contractName || '',
|
||||
money: contract.money || 0,
|
||||
purchaseId: contract.purchaseId || state.formData.purchaseId,
|
||||
isBidding: contract.isBidding || '0',
|
||||
isLegalAdviser: contract.isLegalAdviser || '0',
|
||||
legalAdviserOpinion: contract.legalAdviserOpinion || '',
|
||||
isDepts: contract.isDepts || '0',
|
||||
isSchool: contract.isSchool || '0',
|
||||
remarks: contract.remarks || ''
|
||||
};
|
||||
} else {
|
||||
state.operation = 'add';
|
||||
state.formData = {
|
||||
id: '',
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
money: 0,
|
||||
purchaseId: state.formData.purchaseId,
|
||||
isBidding: '0',
|
||||
isLegalAdviser: '0',
|
||||
legalAdviserOpinion: '',
|
||||
isDepts: '0',
|
||||
isSchool: '0',
|
||||
remarks: ''
|
||||
};
|
||||
}
|
||||
state.visible = true;
|
||||
state.loading = false;
|
||||
state.purchaseNo = purchaseApply?.purchaseNo || '';
|
||||
state.formData.purchaseId = purchaseApply?.id || purchaseApply?.purchaseId || '';
|
||||
|
||||
if (contract && contract.id) {
|
||||
state.operation = 'edit';
|
||||
state.formData = {
|
||||
id: contract.id,
|
||||
contractNo: contract.contractNo || '',
|
||||
contractName: contract.contractName || '',
|
||||
money: contract.money || 0,
|
||||
purchaseId: contract.purchaseId || state.formData.purchaseId,
|
||||
isBidding: contract.isBidding || '0',
|
||||
isLegalAdviser: contract.isLegalAdviser || '0',
|
||||
legalAdviserOpinion: contract.legalAdviserOpinion || '',
|
||||
isDepts: contract.isDepts || '0',
|
||||
isSchool: contract.isSchool || '0',
|
||||
remarks: contract.remarks || '',
|
||||
};
|
||||
} else {
|
||||
state.operation = 'add';
|
||||
state.formData = {
|
||||
id: '',
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
money: 0,
|
||||
purchaseId: state.formData.purchaseId,
|
||||
isBidding: '0',
|
||||
isLegalAdviser: '0',
|
||||
legalAdviserOpinion: '',
|
||||
isDepts: '0',
|
||||
isSchool: '0',
|
||||
remarks: '',
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const valid = await formRef.value?.validate().catch(() => false);
|
||||
if (!valid) return;
|
||||
const valid = await formRef.value?.validate().catch(() => false);
|
||||
if (!valid) return;
|
||||
|
||||
try {
|
||||
state.loading = true;
|
||||
if (state.operation === 'add') {
|
||||
await addObj(state.formData);
|
||||
useMessage().success('新增成功');
|
||||
} else {
|
||||
await editObj(state.formData);
|
||||
useMessage().success('修改成功');
|
||||
}
|
||||
handleClose();
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '操作失败');
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
try {
|
||||
state.loading = true;
|
||||
if (state.operation === 'add') {
|
||||
await addObj(state.formData);
|
||||
useMessage().success('新增成功');
|
||||
} else {
|
||||
await editObj(state.formData);
|
||||
useMessage().success('修改成功');
|
||||
}
|
||||
handleClose();
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '操作失败');
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
state.visible = false;
|
||||
formRef.value?.resetFields();
|
||||
state.formData = {
|
||||
id: '',
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
money: 0,
|
||||
purchaseId: '',
|
||||
isBidding: '0',
|
||||
isLegalAdviser: '0',
|
||||
legalAdviserOpinion: '',
|
||||
isDepts: '0',
|
||||
isSchool: '0',
|
||||
remarks: ''
|
||||
};
|
||||
state.visible = false;
|
||||
formRef.value?.resetFields();
|
||||
state.formData = {
|
||||
id: '',
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
money: 0,
|
||||
purchaseId: '',
|
||||
isBidding: '0',
|
||||
isLegalAdviser: '0',
|
||||
legalAdviserOpinion: '',
|
||||
isDepts: '0',
|
||||
isSchool: '0',
|
||||
remarks: '',
|
||||
};
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,65 +1,69 @@
|
||||
<template>
|
||||
<el-table :data="records" stripe v-loading="loading" max-height="400">
|
||||
<el-table-column prop="operateTypeDesc" label="操作类型" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getOperateTypeStyle(scope.row.operateType)">
|
||||
{{ scope.row.operateTypeDesc }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operateRoleDesc" label="操作角色" width="100" />
|
||||
<el-table-column prop="operateByName" label="操作人" width="100" />
|
||||
<el-table-column prop="currentVersion" label="文件版本" width="80" align="center" />
|
||||
<el-table-column prop="remark" label="批注意见" min-width="200" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
{{ scope.row.remark || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operateTime" label="操作时间" width="160" />
|
||||
</el-table>
|
||||
<el-table :data="records" stripe v-loading="loading" max-height="400">
|
||||
<el-table-column prop="operateTypeDesc" label="操作类型" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getOperateTypeStyle(scope.row.operateType)">
|
||||
{{ scope.row.operateTypeDesc }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operateRoleDesc" label="操作角色" width="100" />
|
||||
<el-table-column prop="operateByName" label="操作人" width="100" />
|
||||
<el-table-column prop="currentVersion" label="文件版本" width="80" align="center" />
|
||||
<el-table-column prop="remark" label="批注意见" min-width="200" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
{{ scope.row.remark || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operateTime" label="操作时间" width="160" />
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { getAuditRecords } from '/@/api/purchase/docProcess'
|
||||
import { ref, watch } from 'vue';
|
||||
import { getAuditRecords } from '/@/api/purchase/docProcess';
|
||||
|
||||
const props = defineProps<{
|
||||
applyId: number | string
|
||||
}>()
|
||||
applyId: number | string;
|
||||
}>();
|
||||
|
||||
const records = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const records = ref<any[]>([]);
|
||||
const loading = ref(false);
|
||||
|
||||
const loadRecords = async () => {
|
||||
if (!props.applyId) return
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getAuditRecords(props.applyId)
|
||||
records.value = res.data || []
|
||||
} catch (e) {
|
||||
records.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
if (!props.applyId) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getAuditRecords(props.applyId);
|
||||
records.value = res.data || [];
|
||||
} catch (e) {
|
||||
records.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const refresh = () => {
|
||||
loadRecords()
|
||||
}
|
||||
loadRecords();
|
||||
};
|
||||
|
||||
const getOperateTypeStyle = (type: string) => {
|
||||
const styleMap: Record<string, string> = {
|
||||
'UPLOAD': 'primary',
|
||||
'CONFIRM': 'success',
|
||||
'RETURN': 'warning',
|
||||
'COMPLETE': 'success'
|
||||
}
|
||||
return styleMap[type] || 'info'
|
||||
}
|
||||
const styleMap: Record<string, string> = {
|
||||
UPLOAD: 'primary',
|
||||
CONFIRM: 'success',
|
||||
RETURN: 'warning',
|
||||
COMPLETE: 'success',
|
||||
};
|
||||
return styleMap[type] || 'info';
|
||||
};
|
||||
|
||||
watch(() => props.applyId, () => {
|
||||
loadRecords()
|
||||
}, { immediate: true })
|
||||
watch(
|
||||
() => props.applyId,
|
||||
() => {
|
||||
loadRecords();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
defineExpose({ refresh })
|
||||
</script>
|
||||
defineExpose({ refresh });
|
||||
</script>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,402 +1,397 @@
|
||||
<template>
|
||||
<div class="reviewer-setting">
|
||||
<el-form :model="formData" label-width="100px" v-loading="loading">
|
||||
<!-- 当前采购代表 -->
|
||||
<el-form-item label="当前代表" v-if="currentRepresentor.teacherName">
|
||||
<el-tag type="success">{{ currentRepresentor.teacherName }} ({{ currentRepresentor.teacherNo }})</el-tag>
|
||||
<el-tag v-if="currentRepresentor.representorType" type="info" style="margin-left: 8px;">{{ getRepresentorTypeLabel(currentRepresentor.representorType) }}</el-tag>
|
||||
</el-form-item>
|
||||
<div class="reviewer-setting">
|
||||
<el-form :model="formData" label-width="100px" v-loading="loading">
|
||||
<!-- 当前采购代表 -->
|
||||
<el-form-item label="当前代表" v-if="currentRepresentor.teacherName">
|
||||
<el-tag type="success">{{ currentRepresentor.teacherName }} ({{ currentRepresentor.teacherNo }})</el-tag>
|
||||
<el-tag v-if="currentRepresentor.representorType" type="info" style="margin-left: 8px">{{
|
||||
getRepresentorTypeLabel(currentRepresentor.representorType)
|
||||
}}</el-tag>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 选择方式 -->
|
||||
<el-form-item label="选择方式">
|
||||
<el-radio-group v-model="formData.selectMode" @change="handleSelectModeChange">
|
||||
<el-radio label="DESIGNATED">指定人员</el-radio>
|
||||
<el-radio label="RANDOM">随机抽取</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 选择方式 -->
|
||||
<el-form-item label="选择方式">
|
||||
<el-radio-group v-model="formData.selectMode" @change="handleSelectModeChange">
|
||||
<el-radio label="DESIGNATED">指定人员</el-radio>
|
||||
<el-radio label="RANDOM">随机抽取</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 指定人员模式 -->
|
||||
<el-form-item v-if="formData.selectMode === 'DESIGNATED'" label="选择人员" required>
|
||||
<org-selector
|
||||
v-model:orgList="selectedUserList"
|
||||
type="user"
|
||||
:multiple="false"
|
||||
@update:orgList="handleUserChange" />
|
||||
</el-form-item>
|
||||
<!-- 指定人员模式 -->
|
||||
<el-form-item v-if="formData.selectMode === 'DESIGNATED'" label="选择人员" required>
|
||||
<org-selector v-model:orgList="selectedUserList" type="user" :multiple="false" @update:orgList="handleUserChange" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 随机抽取模式 -->
|
||||
<template v-if="formData.selectMode === 'RANDOM'">
|
||||
<el-form-item label="选择候选人" required>
|
||||
<org-selector
|
||||
v-model:orgList="candidateUserList"
|
||||
type="user"
|
||||
:multiple="true"
|
||||
@update:orgList="handleCandidateChange" />
|
||||
</el-form-item>
|
||||
<!-- 随机抽取模式 -->
|
||||
<template v-if="formData.selectMode === 'RANDOM'">
|
||||
<el-form-item label="选择候选人" required>
|
||||
<org-selector v-model:orgList="candidateUserList" type="user" :multiple="true" @update:orgList="handleCandidateChange" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 候选人列表 -->
|
||||
<el-form-item label="候选人列表" v-if="candidates.length > 0">
|
||||
<el-table :data="candidates" stripe size="small" max-height="200">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="teacherNo" label="工号" width="120" />
|
||||
<el-table-column prop="teacherName" label="姓名" />
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
<!-- 候选人列表 -->
|
||||
<el-form-item label="候选人列表" v-if="candidates.length > 0">
|
||||
<el-table :data="candidates" stripe size="small" max-height="200">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="teacherNo" label="工号" width="120" />
|
||||
<el-table-column prop="teacherName" label="姓名" />
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 随机抽取结果 -->
|
||||
<el-form-item label="抽取结果">
|
||||
<div class="random-roller">
|
||||
<span v-if="rollingName" class="rolling">{{ rollingName }}</span>
|
||||
<span v-else-if="selectedCandidate.teacherName" class="selected">
|
||||
已抽取:{{ selectedCandidate.teacherName }} ({{ selectedCandidate.teacherNo }})
|
||||
</span>
|
||||
<span v-else class="placeholder">点击下方按钮进行随机抽取</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- 随机抽取结果 -->
|
||||
<el-form-item label="抽取结果">
|
||||
<div class="random-roller">
|
||||
<span v-if="rollingName" class="rolling">{{ rollingName }}</span>
|
||||
<span v-else-if="selectedCandidate.teacherName" class="selected">
|
||||
已抽取:{{ selectedCandidate.teacherName }} ({{ selectedCandidate.teacherNo }})
|
||||
</span>
|
||||
<span v-else class="placeholder">点击下方按钮进行随机抽取</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 随机抽取按钮 -->
|
||||
<el-form-item v-if="candidates.length > 1">
|
||||
<el-button type="primary" :loading="rolling" @click="handleRandomSelect">
|
||||
{{ rolling ? '抽取中...' : '随机抽取' }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<!-- 随机抽取按钮 -->
|
||||
<el-form-item v-if="candidates.length > 1">
|
||||
<el-button type="primary" :loading="rolling" @click="handleRandomSelect">
|
||||
{{ rolling ? '抽取中...' : '随机抽取' }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<!-- 人员类型选择 -->
|
||||
<el-form-item label="人员类型">
|
||||
<el-select v-model="formData.representorType" placeholder="请选择人员类型" clearable style="width: 200px;">
|
||||
<el-option
|
||||
v-for="item in representorTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 人员类型选择 -->
|
||||
<el-form-item label="人员类型">
|
||||
<el-select v-model="formData.representorType" placeholder="请选择人员类型" clearable style="width: 200px">
|
||||
<el-option v-for="item in representorTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 保存按钮 -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="saving" :disabled="!canSave" @click="handleSave">
|
||||
保存设置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<!-- 保存按钮 -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="saving" :disabled="!canSave" @click="handleSave"> 保存设置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="ReviewerSetting">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useMessage } from '/@/hooks/message'
|
||||
import { useDict } from '/@/hooks/dict'
|
||||
import { getReviewerSetting, setReviewerSetting, randomSelectReviewer } from '/@/api/purchase/docProcess'
|
||||
import orgSelector from '/@/components/OrgSelector/index.vue'
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { getReviewerSetting, setReviewerSetting, randomSelectReviewer } from '/@/api/purchase/docProcess';
|
||||
import orgSelector from '/@/components/OrgSelector/index.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
applyId: string | number
|
||||
}>()
|
||||
applyId: string | number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'saved'): void
|
||||
}>()
|
||||
(e: 'saved'): void;
|
||||
}>();
|
||||
|
||||
// 常量
|
||||
const SELECT_MODE = {
|
||||
DESIGNATED: 'DESIGNATED',
|
||||
RANDOM: 'RANDOM',
|
||||
} as const
|
||||
DESIGNATED: 'DESIGNATED',
|
||||
RANDOM: 'RANDOM',
|
||||
} as const;
|
||||
|
||||
// 字典数据
|
||||
const { PURCHASE_REPRESENTOR_TYPE: representorTypeDict } = useDict('PURCHASE_REPRESENTOR_TYPE')
|
||||
const { PURCHASE_REPRESENTOR_TYPE: representorTypeDict } = useDict('PURCHASE_REPRESENTOR_TYPE');
|
||||
|
||||
// 人员类型选项
|
||||
const representorTypeOptions = computed(() => {
|
||||
return (representorTypeDict.value || []).map((item: any) => ({
|
||||
value: item.value,
|
||||
label: item.label
|
||||
}))
|
||||
})
|
||||
return (representorTypeDict.value || []).map((item: any) => ({
|
||||
value: item.value,
|
||||
label: item.label,
|
||||
}));
|
||||
});
|
||||
|
||||
// 表单数据
|
||||
const formData = ref({
|
||||
selectMode: 'DESIGNATED' as 'DESIGNATED' | 'RANDOM',
|
||||
teacherNo: '',
|
||||
teacherName: '',
|
||||
candidates: [] as Array<{ teacherNo: string; teacherName: string }>,
|
||||
representorType: ''
|
||||
})
|
||||
selectMode: 'DESIGNATED' as 'DESIGNATED' | 'RANDOM',
|
||||
teacherNo: '',
|
||||
teacherName: '',
|
||||
candidates: [] as Array<{ teacherNo: string; teacherName: string }>,
|
||||
representorType: '',
|
||||
});
|
||||
|
||||
// 当前采购代表(已有设置)
|
||||
const currentRepresentor = ref({
|
||||
teacherNo: '',
|
||||
teacherName: '',
|
||||
representorType: ''
|
||||
})
|
||||
teacherNo: '',
|
||||
teacherName: '',
|
||||
representorType: '',
|
||||
});
|
||||
|
||||
// 用户选择相关
|
||||
const selectedUserList = ref<any[]>([])
|
||||
const candidateUserList = ref<any[]>([])
|
||||
const selectedUserList = ref<any[]>([]);
|
||||
const candidateUserList = ref<any[]>([]);
|
||||
|
||||
// 候选人列表
|
||||
const candidates = ref<Array<{ teacherNo: string; teacherName: string }>>([])
|
||||
const candidates = ref<Array<{ teacherNo: string; teacherName: string }>>([]);
|
||||
|
||||
// 随机抽取相关
|
||||
const rolling = ref(false)
|
||||
const rollingName = ref('')
|
||||
const selectedCandidate = ref<{ teacherNo: string; teacherName: string }>({ teacherNo: '', teacherName: '' })
|
||||
let rollInterval: ReturnType<typeof setInterval> | null = null
|
||||
const rolling = ref(false);
|
||||
const rollingName = ref('');
|
||||
const selectedCandidate = ref<{ teacherNo: string; teacherName: string }>({ teacherNo: '', teacherName: '' });
|
||||
let rollInterval: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
|
||||
// 是否可以保存
|
||||
const canSave = computed(() => {
|
||||
if (formData.value.selectMode === SELECT_MODE.DESIGNATED) {
|
||||
return formData.value.teacherNo && formData.value.teacherName
|
||||
} else {
|
||||
return formData.value.teacherNo && formData.value.teacherName && candidates.value.length > 0
|
||||
}
|
||||
})
|
||||
if (formData.value.selectMode === SELECT_MODE.DESIGNATED) {
|
||||
return formData.value.teacherNo && formData.value.teacherName;
|
||||
} else {
|
||||
return formData.value.teacherNo && formData.value.teacherName && candidates.value.length > 0;
|
||||
}
|
||||
});
|
||||
|
||||
// 处理选择方式变化
|
||||
const handleSelectModeChange = () => {
|
||||
formData.value.teacherNo = ''
|
||||
formData.value.teacherName = ''
|
||||
formData.value.candidates = []
|
||||
selectedUserList.value = []
|
||||
candidateUserList.value = []
|
||||
candidates.value = []
|
||||
selectedCandidate.value = { teacherNo: '', teacherName: '' }
|
||||
rollingName.value = ''
|
||||
}
|
||||
formData.value.teacherNo = '';
|
||||
formData.value.teacherName = '';
|
||||
formData.value.candidates = [];
|
||||
selectedUserList.value = [];
|
||||
candidateUserList.value = [];
|
||||
candidates.value = [];
|
||||
selectedCandidate.value = { teacherNo: '', teacherName: '' };
|
||||
rollingName.value = '';
|
||||
};
|
||||
|
||||
// 获取人员类型标签
|
||||
const getRepresentorTypeLabel = (value: string): string => {
|
||||
const option = representorTypeOptions.value.find((item: any) => item.value === value)
|
||||
return option ? option.label : value
|
||||
}
|
||||
const option = representorTypeOptions.value.find((item: any) => item.value === value);
|
||||
return option ? option.label : value;
|
||||
};
|
||||
|
||||
// 处理指定人员变化
|
||||
const handleUserChange = (list: any[]) => {
|
||||
if (list && list.length > 0) {
|
||||
const user = list[0]
|
||||
formData.value.teacherNo = user.username || user.userName || ''
|
||||
formData.value.teacherName = user.name || user.realName || ''
|
||||
} else {
|
||||
formData.value.teacherNo = ''
|
||||
formData.value.teacherName = ''
|
||||
}
|
||||
}
|
||||
if (list && list.length > 0) {
|
||||
const user = list[0];
|
||||
formData.value.teacherNo = user.username || user.userName || '';
|
||||
formData.value.teacherName = user.name || user.realName || '';
|
||||
} else {
|
||||
formData.value.teacherNo = '';
|
||||
formData.value.teacherName = '';
|
||||
}
|
||||
};
|
||||
|
||||
// 处理候选人变化
|
||||
const handleCandidateChange = (list: any[]) => {
|
||||
candidates.value = (list || []).map(user => ({
|
||||
teacherNo: user.username || user.userName || '',
|
||||
teacherName: user.name || user.realName || ''
|
||||
}))
|
||||
// 重置已选结果
|
||||
if (candidates.value.length > 0) {
|
||||
selectedCandidate.value = { ...candidates.value[0] }
|
||||
formData.value.teacherNo = selectedCandidate.value.teacherNo
|
||||
formData.value.teacherName = selectedCandidate.value.teacherName
|
||||
} else {
|
||||
selectedCandidate.value = { teacherNo: '', teacherName: '' }
|
||||
formData.value.teacherNo = ''
|
||||
formData.value.teacherName = ''
|
||||
}
|
||||
}
|
||||
candidates.value = (list || []).map((user) => ({
|
||||
teacherNo: user.username || user.userName || '',
|
||||
teacherName: user.name || user.realName || '',
|
||||
}));
|
||||
// 重置已选结果
|
||||
if (candidates.value.length > 0) {
|
||||
selectedCandidate.value = { ...candidates.value[0] };
|
||||
formData.value.teacherNo = selectedCandidate.value.teacherNo;
|
||||
formData.value.teacherName = selectedCandidate.value.teacherName;
|
||||
} else {
|
||||
selectedCandidate.value = { teacherNo: '', teacherName: '' };
|
||||
formData.value.teacherNo = '';
|
||||
formData.value.teacherName = '';
|
||||
}
|
||||
};
|
||||
|
||||
// 随机抽取动画
|
||||
const startRollingAnimation = (finalCandidate: { teacherNo: string; teacherName: string }) => {
|
||||
if (candidates.value.length === 0) return
|
||||
if (candidates.value.length === 0) return;
|
||||
|
||||
if (rollInterval) {
|
||||
clearInterval(rollInterval)
|
||||
rollInterval = null
|
||||
}
|
||||
if (rollInterval) {
|
||||
clearInterval(rollInterval);
|
||||
rollInterval = null;
|
||||
}
|
||||
|
||||
rollingName.value = ''
|
||||
rolling.value = true
|
||||
rollingName.value = '';
|
||||
rolling.value = true;
|
||||
|
||||
let currentIndex = 0
|
||||
const totalDuration = 2000
|
||||
const intervalTime = 80
|
||||
let currentIndex = 0;
|
||||
const totalDuration = 2000;
|
||||
const intervalTime = 80;
|
||||
|
||||
rollInterval = setInterval(() => {
|
||||
rollingName.value = candidates.value[currentIndex].teacherName
|
||||
currentIndex = (currentIndex + 1) % candidates.value.length
|
||||
}, intervalTime)
|
||||
rollInterval = setInterval(() => {
|
||||
rollingName.value = candidates.value[currentIndex].teacherName;
|
||||
currentIndex = (currentIndex + 1) % candidates.value.length;
|
||||
}, intervalTime);
|
||||
|
||||
setTimeout(() => {
|
||||
if (rollInterval) {
|
||||
clearInterval(rollInterval)
|
||||
rollInterval = null
|
||||
}
|
||||
rolling.value = false
|
||||
rollingName.value = ''
|
||||
selectedCandidate.value = finalCandidate
|
||||
formData.value.teacherNo = finalCandidate.teacherNo
|
||||
formData.value.teacherName = finalCandidate.teacherName
|
||||
}, totalDuration)
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (rollInterval) {
|
||||
clearInterval(rollInterval);
|
||||
rollInterval = null;
|
||||
}
|
||||
rolling.value = false;
|
||||
rollingName.value = '';
|
||||
selectedCandidate.value = finalCandidate;
|
||||
formData.value.teacherNo = finalCandidate.teacherNo;
|
||||
formData.value.teacherName = finalCandidate.teacherName;
|
||||
}, totalDuration);
|
||||
};
|
||||
|
||||
// 执行随机抽取
|
||||
const handleRandomSelect = async () => {
|
||||
if (candidates.value.length < 2) {
|
||||
useMessage().warning('请至少选择2位候选人')
|
||||
return
|
||||
}
|
||||
if (candidates.value.length < 2) {
|
||||
useMessage().warning('请至少选择2位候选人');
|
||||
return;
|
||||
}
|
||||
|
||||
rolling.value = true
|
||||
try {
|
||||
const res = await randomSelectReviewer({
|
||||
applyId: props.applyId,
|
||||
selectMode: SELECT_MODE.RANDOM,
|
||||
candidates: candidates.value
|
||||
})
|
||||
const result = res?.data || res
|
||||
if (result?.teacherNo) {
|
||||
startRollingAnimation({
|
||||
teacherNo: result.teacherNo,
|
||||
teacherName: result.teacherName || ''
|
||||
})
|
||||
}
|
||||
} catch (e: any) {
|
||||
rolling.value = false
|
||||
useMessage().error(e?.msg || '随机抽取失败')
|
||||
}
|
||||
}
|
||||
rolling.value = true;
|
||||
try {
|
||||
const res = await randomSelectReviewer({
|
||||
applyId: props.applyId,
|
||||
selectMode: SELECT_MODE.RANDOM,
|
||||
candidates: candidates.value,
|
||||
});
|
||||
const result = res?.data || res;
|
||||
if (result?.teacherNo) {
|
||||
startRollingAnimation({
|
||||
teacherNo: result.teacherNo,
|
||||
teacherName: result.teacherName || '',
|
||||
});
|
||||
}
|
||||
} catch (e: any) {
|
||||
rolling.value = false;
|
||||
useMessage().error(e?.msg || '随机抽取失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 保存设置
|
||||
const handleSave = async () => {
|
||||
if (!canSave.value) {
|
||||
useMessage().warning('请完善设置信息')
|
||||
return
|
||||
}
|
||||
if (!canSave.value) {
|
||||
useMessage().warning('请完善设置信息');
|
||||
return;
|
||||
}
|
||||
|
||||
saving.value = true
|
||||
try {
|
||||
const params: any = {
|
||||
applyId: props.applyId,
|
||||
selectMode: formData.value.selectMode,
|
||||
teacherNo: formData.value.teacherNo,
|
||||
teacherName: formData.value.teacherName,
|
||||
representorType: formData.value.representorType
|
||||
}
|
||||
saving.value = true;
|
||||
try {
|
||||
const params: any = {
|
||||
applyId: props.applyId,
|
||||
selectMode: formData.value.selectMode,
|
||||
teacherNo: formData.value.teacherNo,
|
||||
teacherName: formData.value.teacherName,
|
||||
representorType: formData.value.representorType,
|
||||
};
|
||||
|
||||
if (formData.value.selectMode === SELECT_MODE.RANDOM) {
|
||||
params.candidates = candidates.value
|
||||
}
|
||||
if (formData.value.selectMode === SELECT_MODE.RANDOM) {
|
||||
params.candidates = candidates.value;
|
||||
}
|
||||
|
||||
await setReviewerSetting(params)
|
||||
useMessage().success('保存成功')
|
||||
emit('saved')
|
||||
await loadData()
|
||||
} catch (e: any) {
|
||||
useMessage().error(e?.msg || '保存失败')
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
await setReviewerSetting(params);
|
||||
useMessage().success('保存成功');
|
||||
emit('saved');
|
||||
await loadData();
|
||||
} catch (e: any) {
|
||||
useMessage().error(e?.msg || '保存失败');
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载数据
|
||||
const loadData = async () => {
|
||||
if (!props.applyId) return
|
||||
if (!props.applyId) return;
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getReviewerSetting(props.applyId)
|
||||
const data = res?.data || res
|
||||
if (data) {
|
||||
currentRepresentor.value = {
|
||||
teacherNo: data.teacherNo || '',
|
||||
teacherName: data.teacherName || '',
|
||||
representorType: data.representorType || ''
|
||||
}
|
||||
formData.value.selectMode = data.selectMode || SELECT_MODE.DESIGNATED
|
||||
formData.value.teacherNo = data.teacherNo || ''
|
||||
formData.value.teacherName = data.teacherName || ''
|
||||
formData.value.representorType = data.representorType || ''
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getReviewerSetting(props.applyId);
|
||||
const data = res?.data || res;
|
||||
if (data) {
|
||||
currentRepresentor.value = {
|
||||
teacherNo: data.teacherNo || '',
|
||||
teacherName: data.teacherName || '',
|
||||
representorType: data.representorType || '',
|
||||
};
|
||||
formData.value.selectMode = data.selectMode || SELECT_MODE.DESIGNATED;
|
||||
formData.value.teacherNo = data.teacherNo || '';
|
||||
formData.value.teacherName = data.teacherName || '';
|
||||
formData.value.representorType = data.representorType || '';
|
||||
|
||||
if (data.candidateList && data.candidateList.length > 0) {
|
||||
candidates.value = data.candidateList
|
||||
formData.value.candidates = data.candidateList
|
||||
// 回显候选人
|
||||
candidateUserList.value = data.candidateList.map((c: any) => ({
|
||||
username: c.teacherNo,
|
||||
userName: c.teacherNo,
|
||||
name: c.teacherName,
|
||||
realName: c.teacherName
|
||||
}))
|
||||
}
|
||||
if (data.candidateList && data.candidateList.length > 0) {
|
||||
candidates.value = data.candidateList;
|
||||
formData.value.candidates = data.candidateList;
|
||||
// 回显候选人
|
||||
candidateUserList.value = data.candidateList.map((c: any) => ({
|
||||
username: c.teacherNo,
|
||||
userName: c.teacherNo,
|
||||
name: c.teacherName,
|
||||
realName: c.teacherName,
|
||||
}));
|
||||
}
|
||||
|
||||
if (data.teacherNo && data.selectMode === SELECT_MODE.DESIGNATED) {
|
||||
selectedUserList.value = [{
|
||||
username: data.teacherNo,
|
||||
userName: data.teacherNo,
|
||||
name: data.teacherName,
|
||||
realName: data.teacherName
|
||||
}]
|
||||
}
|
||||
if (data.teacherNo && data.selectMode === SELECT_MODE.DESIGNATED) {
|
||||
selectedUserList.value = [
|
||||
{
|
||||
username: data.teacherNo,
|
||||
userName: data.teacherNo,
|
||||
name: data.teacherName,
|
||||
realName: data.teacherName,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (data.selectMode === SELECT_MODE.RANDOM && data.teacherNo) {
|
||||
selectedCandidate.value = {
|
||||
teacherNo: data.teacherNo,
|
||||
teacherName: data.teacherName || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// 忽略错误
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
if (data.selectMode === SELECT_MODE.RANDOM && data.teacherNo) {
|
||||
selectedCandidate.value = {
|
||||
teacherNo: data.teacherNo,
|
||||
teacherName: data.teacherName || '',
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// 忽略错误
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
loadData();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (rollInterval) {
|
||||
clearInterval(rollInterval)
|
||||
rollInterval = null
|
||||
}
|
||||
})
|
||||
if (rollInterval) {
|
||||
clearInterval(rollInterval);
|
||||
rollInterval = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.reviewer-setting {
|
||||
padding: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.random-roller {
|
||||
padding: 12px 16px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-radius: 4px;
|
||||
min-height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-radius: 4px;
|
||||
min-height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.rolling {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--el-color-primary);
|
||||
animation: blink 0.1s infinite;
|
||||
}
|
||||
.rolling {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--el-color-primary);
|
||||
animation: blink 0.1s infinite;
|
||||
}
|
||||
|
||||
.selected {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
.selected {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: var(--el-text-color-placeholder);
|
||||
}
|
||||
.placeholder {
|
||||
color: var(--el-text-color-placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.7; }
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,252 +1,241 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="采购编号" prop="purchaseNo">
|
||||
<el-input
|
||||
v-model="state.queryForm.purchaseNo"
|
||||
placeholder="请输入采购编号"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input
|
||||
v-model="state.queryForm.projectName"
|
||||
placeholder="请输入项目名称"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<!-- 审核状态筛选 - 仅审核模式显示 -->
|
||||
<el-form-item v-if="mode === 'audit'" label="审核状态" prop="docAuditStatus">
|
||||
<el-select
|
||||
v-model="state.queryForm.docAuditStatus"
|
||||
placeholder="请选择审核状态"
|
||||
clearable
|
||||
style="width: 200px">
|
||||
<el-option label="待上传" value="PENDING_UPLOAD" />
|
||||
<el-option label="草稿" value="DRAFT" />
|
||||
<el-option label="资产管理处审核中" value="ASSET_REVIEWING" />
|
||||
<el-option label="需求部门审核中" value="DEPT_REVIEWING" />
|
||||
<el-option label="内审部门审核中" value="AUDIT_REVIEWING" />
|
||||
<el-option label="资产管理处确认中" value="ASSET_CONFIRMING" />
|
||||
<el-option label="已完成" value="COMPLETED" />
|
||||
<el-option label="已退回" value="RETURNED" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="采购编号" prop="purchaseNo">
|
||||
<el-input v-model="state.queryForm.purchaseNo" placeholder="请输入采购编号" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input v-model="state.queryForm.projectName" placeholder="请输入项目名称" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<!-- 审核状态筛选 - 仅审核模式显示 -->
|
||||
<el-form-item v-if="mode === 'audit'" label="审核状态" prop="docAuditStatus">
|
||||
<el-select v-model="state.queryForm.docAuditStatus" placeholder="请选择审核状态" clearable style="width: 200px">
|
||||
<el-option label="待上传" value="PENDING_UPLOAD" />
|
||||
<el-option label="草稿" value="DRAFT" />
|
||||
<el-option label="资产管理处审核中" value="ASSET_REVIEWING" />
|
||||
<el-option label="需求部门审核中" value="DEPT_REVIEWING" />
|
||||
<el-option label="内审部门审核中" value="AUDIT_REVIEWING" />
|
||||
<el-option label="资产管理处确认中" value="ASSET_CONFIRMING" />
|
||||
<el-option label="已完成" value="COMPLETED" />
|
||||
<el-option label="已退回" value="RETURNED" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon">
|
||||
<component :is="titleIcon" />
|
||||
</el-icon>
|
||||
{{ pageTitle }}
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon">
|
||||
<component :is="titleIcon" />
|
||||
</el-icon>
|
||||
{{ pageTitle }}
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="purchaseNo" label="采购编号" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="projectName" label="项目名称" min-width="200" show-overflow-tooltip />
|
||||
<!-- 需求部门 - 仅审核模式显示 -->
|
||||
<el-table-column v-if="mode === 'audit'" prop="deptName" label="需求部门" min-width="150" show-overflow-tooltip />
|
||||
<!-- 预算金额 - 仅审核模式显示 -->
|
||||
<el-table-column v-if="mode === 'audit'" prop="budget" label="预算金额(元)" width="120" align="right">
|
||||
<template #default="scope">
|
||||
{{ scope.row.budget ? Number(scope.row.budget).toLocaleString() : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 文件状态 -->
|
||||
<el-table-column :prop="statusProp" label="文件状态" width="140" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getStatusType(getRowStatus(scope.row))">
|
||||
{{ getStatusLabel(getRowStatus(scope.row)) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 当前版本 - 仅审核模式显示 -->
|
||||
<el-table-column v-if="mode === 'audit'" prop="currentDocVersion" label="当前版本" width="100" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.row.currentDocVersion || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 操作 -->
|
||||
<el-table-column label="操作" align="center" fixed="right" width="120">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" link icon="View" @click="handleProcess(scope.row)">
|
||||
{{ actionLabel }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="purchaseNo" label="采购编号" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="projectName" label="项目名称" min-width="200" show-overflow-tooltip />
|
||||
<!-- 需求部门 - 仅审核模式显示 -->
|
||||
<el-table-column v-if="mode === 'audit'" prop="deptName" label="需求部门" min-width="150" show-overflow-tooltip />
|
||||
<!-- 预算金额 - 仅审核模式显示 -->
|
||||
<el-table-column v-if="mode === 'audit'" prop="budget" label="预算金额(元)" width="120" align="right">
|
||||
<template #default="scope">
|
||||
{{ scope.row.budget ? Number(scope.row.budget).toLocaleString() : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 文件状态 -->
|
||||
<el-table-column :prop="statusProp" label="文件状态" width="140" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getStatusType(getRowStatus(scope.row))">
|
||||
{{ getStatusLabel(getRowStatus(scope.row)) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 当前版本 - 仅审核模式显示 -->
|
||||
<el-table-column v-if="mode === 'audit'" prop="currentDocVersion" label="当前版本" width="100" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.row.currentDocVersion || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 操作 -->
|
||||
<el-table-column label="操作" align="center" fixed="right" width="120">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" link icon="View" @click="handleProcess(scope.row)">
|
||||
{{ actionLabel }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="state.pagination && state.pagination.total && state.pagination.total > 0"
|
||||
:total="state.pagination.total"
|
||||
:current="state.pagination.current"
|
||||
:size="state.pagination.size"
|
||||
@sizeChange="sizeChangeHandle"
|
||||
@currentChange="currentChangeHandle"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="state.pagination && state.pagination.total && state.pagination.total > 0"
|
||||
:total="state.pagination.total"
|
||||
:current="state.pagination.current"
|
||||
:size="state.pagination.size"
|
||||
@sizeChange="sizeChangeHandle"
|
||||
@currentChange="currentChangeHandle"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 处理弹窗 -->
|
||||
<!-- {{mode}}-->
|
||||
<DocProcessDialog ref="docProcessDialogRef" :mode="mode" @refresh="getDataList" />
|
||||
</div>
|
||||
<!-- 处理弹窗 -->
|
||||
<!-- {{mode}}-->
|
||||
<DocProcessDialog ref="docProcessDialogRef" :mode="mode" @refresh="getDataList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingDocProcess">
|
||||
import { ref, reactive, computed, defineAsyncComponent, onMounted } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { getDocProcessList } from "/@/api/purchase/docProcess";
|
||||
import { Search, DocumentCopy, DocumentChecked, List } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, computed, defineAsyncComponent, onMounted } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { getDocProcessList } from '/@/api/purchase/docProcess';
|
||||
import { Search, DocumentCopy, DocumentChecked, List } from '@element-plus/icons-vue';
|
||||
import { useUserInfo } from '/@/stores/userInfo';
|
||||
|
||||
// 引入组件
|
||||
const DocProcessDialog = defineAsyncComponent(() => import('./DocProcessDialog.vue'));
|
||||
|
||||
const userInfoStore = useUserInfo()
|
||||
const docProcessDialogRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const userInfoStore = useUserInfo();
|
||||
const docProcessDialogRef = ref();
|
||||
const searchFormRef = ref();
|
||||
const showSearch = ref(true);
|
||||
|
||||
// 从用户角色自动判断模式
|
||||
const mode = computed(() => {
|
||||
const roleCodes = userInfoStore.userInfos.roleCodes || [];
|
||||
// 有 PURCHASE_AGENT 角色则显示代理模式
|
||||
if (roleCodes.includes('PURCHASE_AGENT')) {
|
||||
return 'agent';
|
||||
}
|
||||
// 其他情况显示审核模式
|
||||
return 'audit';
|
||||
})
|
||||
const roleCodes = userInfoStore.userInfos.roleCodes || [];
|
||||
// 有 PURCHASE_AGENT 角色则显示代理模式
|
||||
if (roleCodes.includes('PURCHASE_AGENT')) {
|
||||
return 'agent';
|
||||
}
|
||||
// 其他情况显示审核模式
|
||||
return 'audit';
|
||||
});
|
||||
|
||||
// 页面标题
|
||||
const pageTitle = computed(() => {
|
||||
return mode.value === 'agent' ? '招标代理工作台' : '招标文件审核'
|
||||
})
|
||||
return mode.value === 'agent' ? '招标代理工作台' : '招标文件审核';
|
||||
});
|
||||
|
||||
// 标题图标
|
||||
const titleIcon = computed(() => {
|
||||
return mode.value === 'agent' ? DocumentCopy : DocumentChecked
|
||||
})
|
||||
return mode.value === 'agent' ? DocumentCopy : DocumentChecked;
|
||||
});
|
||||
|
||||
// 操作按钮标签
|
||||
const actionLabel = computed(() => {
|
||||
return mode.value === 'agent' ? '处理' : '审核'
|
||||
})
|
||||
return mode.value === 'agent' ? '处理' : '审核';
|
||||
});
|
||||
|
||||
// 状态字段
|
||||
const statusProp = computed(() => {
|
||||
return mode.value === 'agent' ? 'status' : 'docAuditStatus'
|
||||
})
|
||||
return mode.value === 'agent' ? 'status' : 'docAuditStatus';
|
||||
});
|
||||
|
||||
// 查询表单
|
||||
const getQueryForm = () => {
|
||||
const base: any = {
|
||||
purchaseNo: '',
|
||||
projectName: '',
|
||||
}
|
||||
if (mode.value === 'audit') {
|
||||
base.docAuditStatus = ''
|
||||
}
|
||||
return base
|
||||
}
|
||||
const base: any = {
|
||||
purchaseNo: '',
|
||||
projectName: '',
|
||||
};
|
||||
if (mode.value === 'audit') {
|
||||
base.docAuditStatus = '';
|
||||
}
|
||||
return base;
|
||||
};
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: (params?: any) => getDocProcessList(mode.value, params),
|
||||
queryForm: getQueryForm(),
|
||||
createdIsNeed: true
|
||||
pageList: (params?: any) => getDocProcessList(mode.value, params),
|
||||
queryForm: getQueryForm(),
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
const { getDataList, tableStyle, sizeChangeHandle, currentChangeHandle } = useTable(state);
|
||||
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 获取行状态(兼容两种字段名)
|
||||
const getRowStatus = (row: any) => {
|
||||
return mode.value === 'agent' ? row.status : row.docAuditStatus
|
||||
}
|
||||
return mode.value === 'agent' ? row.status : row.docAuditStatus;
|
||||
};
|
||||
|
||||
const getStatusType = (status: string) => {
|
||||
const typeMap: Record<string, string> = {
|
||||
'PENDING_UPLOAD': 'info',
|
||||
'DRAFT': 'info',
|
||||
'ASSET_REVIEWING': 'warning',
|
||||
'DEPT_REVIEWING': 'warning',
|
||||
'AUDIT_REVIEWING': 'warning',
|
||||
'ASSET_CONFIRMING': 'primary',
|
||||
'COMPLETED': 'success',
|
||||
'RETURNED': 'danger'
|
||||
};
|
||||
return typeMap[status] || 'info';
|
||||
const typeMap: Record<string, string> = {
|
||||
PENDING_UPLOAD: 'info',
|
||||
DRAFT: 'info',
|
||||
ASSET_REVIEWING: 'warning',
|
||||
DEPT_REVIEWING: 'warning',
|
||||
AUDIT_REVIEWING: 'warning',
|
||||
ASSET_CONFIRMING: 'primary',
|
||||
COMPLETED: 'success',
|
||||
RETURNED: 'danger',
|
||||
};
|
||||
return typeMap[status] || 'info';
|
||||
};
|
||||
|
||||
const getStatusLabel = (status: string) => {
|
||||
const labelMap: Record<string, string> = {
|
||||
'PENDING_UPLOAD': '待上传',
|
||||
'DRAFT': '草稿',
|
||||
'ASSET_REVIEWING': '资产管理处审核中',
|
||||
'DEPT_REVIEWING': '需求部门审核中',
|
||||
'AUDIT_REVIEWING': '内审部门审核中',
|
||||
'ASSET_CONFIRMING': '资产管理处确认中',
|
||||
'COMPLETED': '已完成',
|
||||
'RETURNED': '已退回'
|
||||
};
|
||||
return labelMap[status] || '-';
|
||||
const labelMap: Record<string, string> = {
|
||||
PENDING_UPLOAD: '待上传',
|
||||
DRAFT: '草稿',
|
||||
ASSET_REVIEWING: '资产管理处审核中',
|
||||
DEPT_REVIEWING: '需求部门审核中',
|
||||
AUDIT_REVIEWING: '内审部门审核中',
|
||||
ASSET_CONFIRMING: '资产管理处确认中',
|
||||
COMPLETED: '已完成',
|
||||
RETURNED: '已退回',
|
||||
};
|
||||
return labelMap[status] || '-';
|
||||
};
|
||||
|
||||
const handleProcess = (row: any) => {
|
||||
docProcessDialogRef.value?.open(row);
|
||||
docProcessDialogRef.value?.open(row);
|
||||
};
|
||||
|
||||
// 监听路由参数变化,重新加载数据
|
||||
onMounted(() => {
|
||||
// 重置查询表单
|
||||
state.queryForm = getQueryForm()
|
||||
// 重置查询表单
|
||||
state.queryForm = getQueryForm();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,120 +1,115 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:title="dialogTitle"
|
||||
width="90%"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
class="form-iframe-dialog"
|
||||
@close="handleClose"
|
||||
>
|
||||
<div class="form-iframe-content">
|
||||
<iframe
|
||||
ref="iframeRef"
|
||||
:src="iframeSrc"
|
||||
frameborder="0"
|
||||
class="form-iframe"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:title="dialogTitle"
|
||||
width="90%"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
class="form-iframe-dialog"
|
||||
@close="handleClose"
|
||||
>
|
||||
<div class="form-iframe-content">
|
||||
<iframe ref="iframeRef" :src="iframeSrc" frameborder="0" class="form-iframe" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingRequisitionForm">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { ref, computed, watch } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
dictData?: Record<string, any>
|
||||
}>()
|
||||
dictData?: Record<string, any>;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'refresh'): void
|
||||
}>()
|
||||
(e: 'refresh'): void;
|
||||
}>();
|
||||
|
||||
const visible = ref(false)
|
||||
const iframeRef = ref<HTMLIFrameElement>()
|
||||
const mode = ref<'add' | 'edit' | 'view'>('add')
|
||||
const rowId = ref<string | number>('')
|
||||
const visible = ref(false);
|
||||
const iframeRef = ref<HTMLIFrameElement>();
|
||||
const mode = ref<'add' | 'edit' | 'view'>('add');
|
||||
const rowId = ref<string | number>('');
|
||||
|
||||
const dialogTitle = computed(() => {
|
||||
const titles = {
|
||||
add: '新增采购申请',
|
||||
edit: '编辑采购申请',
|
||||
view: '查看采购申请',
|
||||
}
|
||||
return titles[mode.value] || titles.add
|
||||
})
|
||||
const titles = {
|
||||
add: '新增采购申请',
|
||||
edit: '编辑采购申请',
|
||||
view: '查看采购申请',
|
||||
};
|
||||
return titles[mode.value] || titles.add;
|
||||
});
|
||||
|
||||
const iframeSrc = computed(() => {
|
||||
const baseUrl = window.location.origin + window.location.pathname
|
||||
let src = `${baseUrl}#/purchase/purchasingrequisition/add`
|
||||
if (mode.value !== 'add' && rowId.value) {
|
||||
src += `?mode=${mode.value}&id=${rowId.value}`
|
||||
}
|
||||
return src
|
||||
})
|
||||
const baseUrl = window.location.origin + window.location.pathname;
|
||||
let src = `${baseUrl}#/purchase/purchasingrequisition/add`;
|
||||
if (mode.value !== 'add' && rowId.value) {
|
||||
src += `?mode=${mode.value}&id=${rowId.value}`;
|
||||
}
|
||||
return src;
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
visible.value = false
|
||||
window.removeEventListener('message', handleMessage)
|
||||
}
|
||||
visible.value = false;
|
||||
window.removeEventListener('message', handleMessage);
|
||||
};
|
||||
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
if (event.data?.type === 'purchasingrequisition:submitSuccess') {
|
||||
handleClose()
|
||||
emit('refresh')
|
||||
} else if (event.data?.type === 'purchasingrequisition:close') {
|
||||
handleClose()
|
||||
}
|
||||
}
|
||||
if (event.data?.type === 'purchasingrequisition:submitSuccess') {
|
||||
handleClose();
|
||||
emit('refresh');
|
||||
} else if (event.data?.type === 'purchasingrequisition:close') {
|
||||
handleClose();
|
||||
}
|
||||
};
|
||||
|
||||
const openDialog = (openMode: 'add' | 'edit' | 'view', row?: any) => {
|
||||
mode.value = openMode
|
||||
rowId.value = row?.id ?? ''
|
||||
visible.value = true
|
||||
window.addEventListener('message', handleMessage)
|
||||
}
|
||||
mode.value = openMode;
|
||||
rowId.value = row?.id ?? '';
|
||||
visible.value = true;
|
||||
window.addEventListener('message', handleMessage);
|
||||
};
|
||||
|
||||
watch(visible, (val) => {
|
||||
if (!val) {
|
||||
window.removeEventListener('message', handleMessage)
|
||||
}
|
||||
})
|
||||
if (!val) {
|
||||
window.removeEventListener('message', handleMessage);
|
||||
}
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
})
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.form-iframe-content {
|
||||
width: 100%;
|
||||
height: 70vh;
|
||||
min-height: 500px;
|
||||
max-height: calc(100vh - 200px);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 70vh;
|
||||
min-height: 500px;
|
||||
max-height: calc(100vh - 200px);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.form-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 500px;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
.form-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 500px;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.form-iframe-dialog.el-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 90vh;
|
||||
margin-top: 5vh !important;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 90vh;
|
||||
margin-top: 5vh !important;
|
||||
}
|
||||
.form-iframe-dialog .el-dialog__body {
|
||||
padding: 20px;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: 20px;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,84 +1,73 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="实施采购"
|
||||
width="800px"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
@close="handleClose"
|
||||
>
|
||||
<ImplementContent
|
||||
ref="implementContentRef"
|
||||
@close="handleContentClose"
|
||||
@saved="handleContentSaved"
|
||||
/>
|
||||
<el-dialog v-model="visible" title="实施采购" width="800px" :close-on-click-modal="false" destroy-on-close @close="handleClose">
|
||||
<ImplementContent ref="implementContentRef" @close="handleContentClose" @saved="handleContentSaved" />
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" :loading="confirming" @click="handleConfirm">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" :loading="confirming" @click="handleConfirm">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="ImplementForm">
|
||||
import { ref, nextTick } from 'vue'
|
||||
import ImplementContent from './implement.vue'
|
||||
import { ref, nextTick } from 'vue';
|
||||
import ImplementContent from './implement.vue';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'refresh'): void
|
||||
}>()
|
||||
(e: 'refresh'): void;
|
||||
}>();
|
||||
|
||||
const visible = ref(false)
|
||||
const implementContentRef = ref<InstanceType<typeof ImplementContent>>()
|
||||
const confirming = ref(false)
|
||||
const pendingRow = ref<{ id: string | number } | null>(null)
|
||||
const visible = ref(false);
|
||||
const implementContentRef = ref<InstanceType<typeof ImplementContent>>();
|
||||
const confirming = ref(false);
|
||||
const pendingRow = ref<{ id: string | number } | null>(null);
|
||||
|
||||
const handleClose = () => {
|
||||
visible.value = false
|
||||
}
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const handleContentClose = () => {
|
||||
visible.value = false
|
||||
emit('refresh')
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
};
|
||||
|
||||
const handleContentSaved = () => {
|
||||
emit('refresh')
|
||||
}
|
||||
emit('refresh');
|
||||
};
|
||||
|
||||
const handleConfirm = async () => {
|
||||
confirming.value = true
|
||||
try {
|
||||
await implementContentRef.value?.handleConfirm()
|
||||
visible.value = false
|
||||
emit('refresh')
|
||||
} finally {
|
||||
confirming.value = false
|
||||
}
|
||||
}
|
||||
confirming.value = true;
|
||||
try {
|
||||
await implementContentRef.value?.handleConfirm();
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} finally {
|
||||
confirming.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const openDialog = async (row: { id: string | number }) => {
|
||||
pendingRow.value = row
|
||||
visible.value = true
|
||||
// 等待 dialog 及内部组件挂载完成后再调用 open
|
||||
await nextTick()
|
||||
if (pendingRow.value) {
|
||||
implementContentRef.value?.open(pendingRow.value)
|
||||
pendingRow.value = null
|
||||
}
|
||||
}
|
||||
pendingRow.value = row;
|
||||
visible.value = true;
|
||||
// 等待 dialog 及内部组件挂载完成后再调用 open
|
||||
await nextTick();
|
||||
if (pendingRow.value) {
|
||||
implementContentRef.value?.open(pendingRow.value);
|
||||
pendingRow.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
})
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,120 +1,86 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="FolderAdd"
|
||||
@click="openUploadDialog()"
|
||||
v-auth="'purchase_template_add'">
|
||||
新增模板
|
||||
</el-button>
|
||||
<el-alert type="info" :closable="false" class="mb3 mt-3" show-icon>
|
||||
此处模版中的模版编码对应用户端下载模版匹配,请勿随意修改或删除。正常情况下如有发生模版变化,重新上传即可。如有新增模版,请联系管理员进行处理。
|
||||
</el-alert>
|
||||
</div>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div class="header-actions">
|
||||
<el-button type="primary" icon="FolderAdd" @click="openUploadDialog()" v-auth="'purchase_template_add'"> 新增模板 </el-button>
|
||||
<el-alert type="info" :closable="false" class="mb3 mt-3" show-icon>
|
||||
此处模版中的模版编码对应用户端下载模版匹配,请勿随意修改或删除。正常情况下如有发生模版变化,重新上传即可。如有新增模版,请联系管理员进行处理。
|
||||
</el-alert>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<el-table :data="tableData" v-loading="loading" stripe class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="templateTitle" label="模板类型名称" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="templateType" label="模板类型编码" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="templateName" label="模板名称" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column prop="updateTime" label="更新时间" width="180" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="260" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link icon="Download" @click="handleDownload(row)" v-auth="'purchase_template_view'"> 下载 </el-button>
|
||||
<el-button type="primary" link icon="UploadFilled" @click="openUploadDialog(row)" v-auth="'purchase_template_add'">
|
||||
重新上传
|
||||
</el-button>
|
||||
<el-button type="primary" link icon="Edit" @click="openEditDialog(row)" v-auth="'purchase_template_add'"> 编辑 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-table :data="tableData" v-loading="loading" stripe class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="templateTitle" label="模板类型名称" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="templateType" label="模板类型编码" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="templateName" label="模板名称" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column prop="updateTime" label="更新时间" width="180" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="260" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
icon="Download"
|
||||
@click="handleDownload(row)"
|
||||
v-auth="'purchase_template_view'">
|
||||
下载
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
icon="UploadFilled"
|
||||
@click="openUploadDialog(row)"
|
||||
v-auth="'purchase_template_add'">
|
||||
重新上传
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
icon="Edit"
|
||||
@click="openEditDialog(row)"
|
||||
v-auth="'purchase_template_add'">
|
||||
编辑
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
<el-dialog v-model="uploadDialogVisible" title="上传模板" width="450px" destroy-on-close>
|
||||
<el-form :model="uploadForm" label-width="100px">
|
||||
<el-form-item label="模板类型编码" required>
|
||||
<el-input v-model="uploadForm.templateType" placeholder="例如: business_negotiation, inquiry" :disabled="!!uploadForm.lockType" />
|
||||
</el-form-item>
|
||||
<el-form-item label="模板类型名称">
|
||||
<el-input v-model="uploadForm.templateTitle" placeholder="例如: 部门采购询价模版" />
|
||||
</el-form-item>
|
||||
<el-form-item label="模板文件" required>
|
||||
<el-upload
|
||||
class="upload-block"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
:file-list="fileList"
|
||||
:on-change="handleFileChange"
|
||||
:on-remove="handleFileRemove"
|
||||
>
|
||||
<el-button type="primary" icon="UploadFilled">选择文件</el-button>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">支持 doc、docx 等 Word 模板文件,上传后前端下载将使用该文件。</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="uploadDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="uploading" @click="handleUploadConfirm">上 传</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="uploadDialogVisible" title="上传模板" width="450px" destroy-on-close>
|
||||
<el-form :model="uploadForm" label-width="100px">
|
||||
<el-form-item label="模板类型编码" required>
|
||||
<el-input
|
||||
v-model="uploadForm.templateType"
|
||||
placeholder="例如: business_negotiation, inquiry"
|
||||
:disabled="!!uploadForm.lockType"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="模板类型名称">
|
||||
<el-input
|
||||
v-model="uploadForm.templateTitle"
|
||||
placeholder="例如: 部门采购询价模版"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="模板文件" required>
|
||||
<el-upload
|
||||
class="upload-block"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
:file-list="fileList"
|
||||
:on-change="handleFileChange"
|
||||
:on-remove="handleFileRemove"
|
||||
>
|
||||
<el-button type="primary" icon="UploadFilled">选择文件</el-button>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">支持 doc、docx 等 Word 模板文件,上传后前端下载将使用该文件。</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="uploadDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="uploading" @click="handleUploadConfirm">上 传</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="editDialogVisible" title="编辑模板" width="420px" destroy-on-close>
|
||||
<el-form :model="editForm" label-width="100px">
|
||||
<el-form-item label="模板类型编码">
|
||||
<el-input v-model="editForm.templateType" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="模板类型名称" required>
|
||||
<el-input v-model="editForm.templateTitle" placeholder="请输入模板类型名称" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="editDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="editing" @click="handleEditConfirm">保 存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog v-model="editDialogVisible" title="编辑模板" width="420px" destroy-on-close>
|
||||
<el-form :model="editForm" label-width="100px">
|
||||
<el-form-item label="模板类型编码">
|
||||
<el-input v-model="editForm.templateType" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="模板类型名称" required>
|
||||
<el-input v-model="editForm.templateTitle" placeholder="请输入模板类型名称" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="editDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="editing" @click="handleEditConfirm">保 存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PurchasingTemplateManage">
|
||||
@@ -129,143 +95,142 @@ const tableData = ref<any[]>([]);
|
||||
const uploadDialogVisible = ref(false);
|
||||
const uploading = ref(false);
|
||||
const uploadForm = reactive<{
|
||||
templateType: string;
|
||||
templateTitle: string;
|
||||
lockType?: boolean;
|
||||
templateType: string;
|
||||
templateTitle: string;
|
||||
lockType?: boolean;
|
||||
}>({
|
||||
templateType: '',
|
||||
templateTitle: '',
|
||||
lockType: false,
|
||||
templateType: '',
|
||||
templateTitle: '',
|
||||
lockType: false,
|
||||
});
|
||||
const editDialogVisible = ref(false);
|
||||
const editing = ref(false);
|
||||
const editForm = reactive<{
|
||||
id: number | null;
|
||||
templateType: string;
|
||||
templateTitle: string;
|
||||
id: number | null;
|
||||
templateType: string;
|
||||
templateTitle: string;
|
||||
}>({
|
||||
id: null,
|
||||
templateType: '',
|
||||
templateTitle: '',
|
||||
id: null,
|
||||
templateType: '',
|
||||
templateTitle: '',
|
||||
});
|
||||
|
||||
const fileList = ref<any[]>([]);
|
||||
const currentFile = ref<File | null>(null);
|
||||
|
||||
const fetchData = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await listTemplates();
|
||||
tableData.value = (res && res.data) || [];
|
||||
} catch (e) {
|
||||
tableData.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await listTemplates();
|
||||
tableData.value = (res && res.data) || [];
|
||||
} catch (e) {
|
||||
tableData.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(fetchData);
|
||||
|
||||
const openUploadDialog = (row?: any) => {
|
||||
uploadDialogVisible.value = true;
|
||||
uploadForm.templateType = row?.templateType || '';
|
||||
uploadForm.templateTitle = row?.templateTitle || '';
|
||||
uploadForm.lockType = !!row?.templateType;
|
||||
fileList.value = [];
|
||||
currentFile.value = null;
|
||||
uploadDialogVisible.value = true;
|
||||
uploadForm.templateType = row?.templateType || '';
|
||||
uploadForm.templateTitle = row?.templateTitle || '';
|
||||
uploadForm.lockType = !!row?.templateType;
|
||||
fileList.value = [];
|
||||
currentFile.value = null;
|
||||
};
|
||||
|
||||
const handleFileChange = (file: any, files: any[]) => {
|
||||
fileList.value = files.slice(-1);
|
||||
currentFile.value = file.raw || null;
|
||||
fileList.value = files.slice(-1);
|
||||
currentFile.value = file.raw || null;
|
||||
};
|
||||
|
||||
const handleFileRemove = () => {
|
||||
fileList.value = [];
|
||||
currentFile.value = null;
|
||||
fileList.value = [];
|
||||
currentFile.value = null;
|
||||
};
|
||||
|
||||
const handleUploadConfirm = async () => {
|
||||
if (!uploadForm.templateType || !uploadForm.templateType.trim()) {
|
||||
useMessage().error('请填写模板类型编码');
|
||||
return;
|
||||
}
|
||||
if (!currentFile.value) {
|
||||
useMessage().error('请选择要上传的模板文件');
|
||||
return;
|
||||
}
|
||||
uploading.value = true;
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('type', uploadForm.templateType.trim());
|
||||
if (uploadForm.templateTitle && uploadForm.templateTitle.trim()) {
|
||||
formData.append('title', uploadForm.templateTitle.trim());
|
||||
}
|
||||
formData.append('file', currentFile.value);
|
||||
await uploadTemplate(formData);
|
||||
useMessage().success('模板上传成功');
|
||||
uploadDialogVisible.value = false;
|
||||
await fetchData();
|
||||
} catch (e) {
|
||||
useMessage().error('模板上传失败');
|
||||
} finally {
|
||||
uploading.value = false;
|
||||
}
|
||||
if (!uploadForm.templateType || !uploadForm.templateType.trim()) {
|
||||
useMessage().error('请填写模板类型编码');
|
||||
return;
|
||||
}
|
||||
if (!currentFile.value) {
|
||||
useMessage().error('请选择要上传的模板文件');
|
||||
return;
|
||||
}
|
||||
uploading.value = true;
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('type', uploadForm.templateType.trim());
|
||||
if (uploadForm.templateTitle && uploadForm.templateTitle.trim()) {
|
||||
formData.append('title', uploadForm.templateTitle.trim());
|
||||
}
|
||||
formData.append('file', currentFile.value);
|
||||
await uploadTemplate(formData);
|
||||
useMessage().success('模板上传成功');
|
||||
uploadDialogVisible.value = false;
|
||||
await fetchData();
|
||||
} catch (e) {
|
||||
useMessage().error('模板上传失败');
|
||||
} finally {
|
||||
uploading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleDownload = async (row: any) => {
|
||||
if (!row?.templateType) {
|
||||
useMessage().error('缺少模板类型编码');
|
||||
return;
|
||||
}
|
||||
const url = getTemplateDownloadUrl(row.templateType);
|
||||
const fileName = row.templateName || row.templateTitle || row.templateType;
|
||||
try {
|
||||
await (window as any).other?.downBlobFile?.(url, {}, fileName) ||
|
||||
// 兼容直接使用工具函数
|
||||
(await import('/@/utils/other')).default.downBlobFile(url, {}, fileName);
|
||||
} catch (e) {
|
||||
// 如果工具函数不可用,则退回 window.open
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
if (!row?.templateType) {
|
||||
useMessage().error('缺少模板类型编码');
|
||||
return;
|
||||
}
|
||||
const url = getTemplateDownloadUrl(row.templateType);
|
||||
const fileName = row.templateName || row.templateTitle || row.templateType;
|
||||
try {
|
||||
(await (window as any).other?.downBlobFile?.(url, {}, fileName)) ||
|
||||
// 兼容直接使用工具函数
|
||||
(await import('/@/utils/other')).default.downBlobFile(url, {}, fileName);
|
||||
} catch (e) {
|
||||
// 如果工具函数不可用,则退回 window.open
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
const openEditDialog = (row: any) => {
|
||||
editDialogVisible.value = true;
|
||||
editForm.id = row?.id ?? null;
|
||||
editForm.templateType = row?.templateType || '';
|
||||
editForm.templateTitle = row?.templateTitle || '';
|
||||
editDialogVisible.value = true;
|
||||
editForm.id = row?.id ?? null;
|
||||
editForm.templateType = row?.templateType || '';
|
||||
editForm.templateTitle = row?.templateTitle || '';
|
||||
};
|
||||
|
||||
const handleEditConfirm = async () => {
|
||||
if (!editForm.id) {
|
||||
useMessage().error('缺少模板ID');
|
||||
return;
|
||||
}
|
||||
if (!editForm.templateTitle || !editForm.templateTitle.trim()) {
|
||||
useMessage().error('请输入模板类型名称');
|
||||
return;
|
||||
}
|
||||
editing.value = true;
|
||||
try {
|
||||
await updateTemplateTitle({
|
||||
id: editForm.id,
|
||||
templateTitle: editForm.templateTitle.trim(),
|
||||
});
|
||||
useMessage().success('保存成功');
|
||||
editDialogVisible.value = false;
|
||||
await fetchData();
|
||||
} catch (e) {
|
||||
useMessage().error('保存失败');
|
||||
} finally {
|
||||
editing.value = false;
|
||||
}
|
||||
if (!editForm.id) {
|
||||
useMessage().error('缺少模板ID');
|
||||
return;
|
||||
}
|
||||
if (!editForm.templateTitle || !editForm.templateTitle.trim()) {
|
||||
useMessage().error('请输入模板类型名称');
|
||||
return;
|
||||
}
|
||||
editing.value = true;
|
||||
try {
|
||||
await updateTemplateTitle({
|
||||
id: editForm.id,
|
||||
templateTitle: editForm.templateTitle.trim(),
|
||||
});
|
||||
useMessage().success('保存成功');
|
||||
editDialogVisible.value = false;
|
||||
await fetchData();
|
||||
} catch (e) {
|
||||
useMessage().error('保存失败');
|
||||
} finally {
|
||||
editing.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.upload-block {
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user