Merge branch 'main' of http://192.168.110.2:3000/taoge/mk_system into fs
This commit is contained in:
@ -12,7 +12,7 @@ VITE_APP_BASE_API = 'http://192.168.110.180:8899'
|
|||||||
# 罗成
|
# 罗成
|
||||||
# VITE_APP_BASE_API = 'http://192.168.110.188:8899'
|
# VITE_APP_BASE_API = 'http://192.168.110.188:8899'
|
||||||
# 朱银
|
# 朱银
|
||||||
# VITE_APP_BASE_API = 'http://192.168.110.149:8899'
|
VITE_APP_BASE_API = 'http://192.168.110.180:8899'
|
||||||
#曾涛
|
#曾涛
|
||||||
# VITE_APP_BASE_API = 'http://192.168.110.171:8899'
|
# VITE_APP_BASE_API = 'http://192.168.110.171:8899'
|
||||||
|
|
||||||
|
@ -14,6 +14,18 @@ export const listCompany = (query?: CompanyQuery): AxiosPromise<CompanyVO[]> =>
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
|
}; /**
|
||||||
|
* 查询材料提供商
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const supplierInputGet = (query?) => {
|
||||||
|
return request({
|
||||||
|
url: '/supplierInput/supplierInput/getList',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,18 +20,20 @@ export const getMenu = (menuId: string | number): AxiosPromise<MenuVO> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 查询菜单下拉树结构
|
// 查询菜单下拉树结构
|
||||||
export const treeselect = (): AxiosPromise<MenuTreeOption[]> => {
|
export const treeselect = (params?: any): AxiosPromise<MenuTreeOption[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/menu/treeselect',
|
url: '/system/menu/treeselect',
|
||||||
method: 'get'
|
method: 'get',
|
||||||
|
params
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 根据角色ID查询菜单下拉树结构
|
// 根据角色ID查询菜单下拉树结构
|
||||||
export const roleMenuTreeselect = (roleId: string | number): AxiosPromise<RoleMenuTree> => {
|
export const roleMenuTreeselect = (roleId: string | number, params?: any): AxiosPromise<RoleMenuTree> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/menu/roleMenuTreeselect/' + roleId,
|
url: '/system/menu/roleMenuTreeselect/' + roleId,
|
||||||
method: 'get'
|
method: 'get',
|
||||||
|
params
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ export function getRoleList(deptId?: number | string): AxiosPromise<any[]> {
|
|||||||
url: '/system/role/listNoPage',
|
url: '/system/role/listNoPage',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: {
|
params: {
|
||||||
deptId,
|
deptId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -147,10 +147,11 @@ export const authUserSelectAll = (data: any) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 根据角色ID查询部门树结构
|
// 根据角色ID查询部门树结构
|
||||||
export const deptTreeSelect = (roleId: string | number): AxiosPromise<RoleDeptTree> => {
|
export const deptTreeSelect = (roleId: string | number, params?) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/role/deptTree/' + roleId,
|
url: '/system/role/deptTree/' + roleId,
|
||||||
method: 'get'
|
method: 'get',
|
||||||
|
params
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,8 +59,9 @@
|
|||||||
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
||||||
<el-table-column prop="num" label="编号" />
|
<el-table-column prop="num" label="编号" />
|
||||||
<el-table-column prop="name" label="工程或费用名称" />
|
<el-table-column prop="name" label="工程或费用名称" />
|
||||||
<el-table-column prop="unit" label="单位" />
|
<el-table-column prop="unit" label="单位" align="center" />
|
||||||
<el-table-column prop="quantity" label="数量" />
|
<el-table-column prop="quantity" label="数量" align="center" />
|
||||||
|
<el-table-column prop="specification" label="规格" align="center" />
|
||||||
<el-table-column prop="remark" label="单价" align="center">
|
<el-table-column prop="remark" label="单价" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>{{ scope.row.unitPrice }}</span>
|
<span>{{ scope.row.unitPrice }}</span>
|
||||||
@ -210,8 +211,6 @@ const tableRef = ref<any>();
|
|||||||
|
|
||||||
const toggleExpandAll = () => {
|
const toggleExpandAll = () => {
|
||||||
isExpandAll.value = !isExpandAll.value;
|
isExpandAll.value = !isExpandAll.value;
|
||||||
console.log(isExpandAll.value);
|
|
||||||
|
|
||||||
tableData.value.forEach((row) => {
|
tableData.value.forEach((row) => {
|
||||||
tableRef.value.toggleRowExpansion(row, isExpandAll.value);
|
tableRef.value.toggleRowExpansion(row, isExpandAll.value);
|
||||||
});
|
});
|
||||||
@ -249,7 +248,7 @@ const handleExport = () => {
|
|||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
sheet: queryForm.value.sheet
|
sheet: queryForm.value.sheet
|
||||||
},
|
},
|
||||||
`限价一览表${queryForm.value.sheet}.xlsx`
|
`投标成本核算清单${queryForm.value.sheet}.xlsx`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
// 审核
|
// 审核
|
||||||
|
@ -59,8 +59,9 @@
|
|||||||
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
||||||
<el-table-column prop="num" label="编号" />
|
<el-table-column prop="num" label="编号" />
|
||||||
<el-table-column prop="name" label="工程或费用名称" />
|
<el-table-column prop="name" label="工程或费用名称" />
|
||||||
<el-table-column prop="unit" label="单位" />
|
<el-table-column prop="unit" label="单位" align="center" />
|
||||||
<el-table-column prop="quantity" label="数量">
|
<el-table-column prop="specification" label="规格" align="center"/>
|
||||||
|
<el-table-column prop="quantity" label="数量" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
||||||
</template>
|
</template>
|
||||||
|
@ -60,8 +60,10 @@
|
|||||||
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
||||||
<el-table-column prop="num" label="编号" />
|
<el-table-column prop="num" label="编号" />
|
||||||
<el-table-column prop="name" label="工程或费用名称" />
|
<el-table-column prop="name" label="工程或费用名称" />
|
||||||
<el-table-column prop="unit" label="单位" />
|
<el-table-column prop="unit" label="单位" align="center" />
|
||||||
<el-table-column prop="quantity" label="数量">
|
<el-table-column prop="taxRate" label="税率" align="center" />
|
||||||
|
<el-table-column prop="specification" label="规格" align="center" />
|
||||||
|
<el-table-column prop="quantity" label="数量" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
||||||
</template>
|
</template>
|
||||||
@ -307,7 +309,7 @@ const handleExport = () => {
|
|||||||
versions: queryForm.value.versions,
|
versions: queryForm.value.versions,
|
||||||
type: '1'
|
type: '1'
|
||||||
},
|
},
|
||||||
`限价一览表${queryForm.value.sheet}.xlsx`
|
`限价一览${queryForm.value.sheet}.xlsx`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
// 审批
|
// 审批
|
||||||
|
@ -93,9 +93,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-form-item label="附图">
|
<el-form-item label="附图">
|
||||||
<file-Upload v-model="form.attachmentsImg" :file-type="['pdf', 'png', 'jpg', 'jpeg', 'gif', 'bmp']">
|
<file-Upload :fileSize="50" v-model="form.attachmentsImg" :file-type="['png', 'jpg', 'jpeg']"> </file-Upload>
|
||||||
<el-button type="primary">上传附件</el-button>
|
|
||||||
</file-Upload>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 变更原因 -->
|
<!-- 变更原因 -->
|
||||||
<el-form-item label="变更原因">
|
<el-form-item label="变更原因">
|
||||||
@ -114,7 +112,7 @@
|
|||||||
<el-input v-model="form.content" type="textarea" :rows="6" placeholder="请输入内容" />
|
<el-input v-model="form.content" type="textarea" :rows="6" placeholder="请输入内容" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="附件" prop="attachments">
|
<el-form-item label="附件" prop="attachments">
|
||||||
<file-upload v-model="form.attachments" :limit="1" :file-type="['pdf']"></file-upload>
|
<file-upload :fileSize="50" v-model="form.attachments" :limit="1" :file-type="['pdf']"></file-upload>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="变更费用估算" prop="costEstimation">
|
<el-form-item label="变更费用估算" prop="costEstimation">
|
||||||
<el-input v-model="form.costEstimation" :rows="6" type="number" placeholder="请输入变更费用估算" />
|
<el-input v-model="form.costEstimation" :rows="6" type="number" placeholder="请输入变更费用估算" />
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<!-- 表单区域 -->
|
<!-- 表单区域 -->
|
||||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||||
<h3 class="text-lg font-semibold text-gray-800">招标工程清单</h3>
|
<h3 class="text-lg font-semibold text-gray-800">投标工程量清单</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<el-form
|
<el-form
|
||||||
|
@ -113,7 +113,7 @@ const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
|||||||
//按钮组件
|
//按钮组件
|
||||||
const flowCodeOptions = [
|
const flowCodeOptions = [
|
||||||
{
|
{
|
||||||
value: currentProject.value?.id + '_materialsPlans',
|
value: currentProject.value?.id + '_equipmentList',
|
||||||
label: '物资设备清单审核'
|
label: '物资设备清单审核'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
<el-option v-for="item in [flowCodeOptions[optionIndex]]" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -98,6 +98,7 @@ const flowCodeOptions = ref([
|
|||||||
label: '资金设计变更审批'
|
label: '资金设计变更审批'
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
const optionIndex = ref<number>(0);
|
||||||
|
|
||||||
const flowCode = ref<string>('');
|
const flowCode = ref<string>('');
|
||||||
const status = ref<string>('');
|
const status = ref<string>('');
|
||||||
@ -272,12 +273,12 @@ const submit = async (status, data) => {
|
|||||||
} else {
|
} else {
|
||||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||||
if (form.value.costEstimation == '0') {
|
if (form.value.costEstimation == '0') {
|
||||||
flowCodeOptions.value = [flowCodeOptions.value[0]];
|
optionIndex.value = 0;
|
||||||
} else {
|
} else {
|
||||||
console.log('🚀 ~ submit ~ flowCodeOptions.value:', flowCodeOptions.value[1]);
|
console.log('🚀 ~ submit ~ flowCodeOptions.value:', flowCodeOptions.value[1]);
|
||||||
flowCodeOptions.value = [flowCodeOptions.value[1]];
|
optionIndex.value = 1;
|
||||||
}
|
}
|
||||||
flowCode.value = flowCodeOptions.value[0].value;
|
flowCode.value = flowCodeOptions.value[optionIndex.value].value;
|
||||||
dialogVisible.visible = true;
|
dialogVisible.visible = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</span>
|
</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<!-- <el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
type="success"
|
type="success"
|
||||||
plain
|
plain
|
||||||
@ -73,7 +73,7 @@
|
|||||||
v-hasPermi="['formalities:formalitiesAreConsolidated:edit']"
|
v-hasPermi="['formalities:formalitiesAreConsolidated:edit']"
|
||||||
>修改</el-button
|
>修改</el-button
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col> -->
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
@ -27,19 +27,6 @@
|
|||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['materials:materials:add']"> 新增 </el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['materials:materials:add']"> 新增 </el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['materials:materials:edit']"
|
|
||||||
>修改
|
|
||||||
</el-button>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['materials:materials:remove']"
|
|
||||||
>删除
|
|
||||||
</el-button>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['materials:materials:export']">导出 </el-button>
|
|
||||||
</el-col>
|
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
@ -92,35 +79,41 @@
|
|||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改材料名称对话框 -->
|
<!-- 添加或修改材料名称对话框 -->
|
||||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
|
||||||
<el-form ref="materialsFormRef" :model="form" :rules="rules" label-width="120px">
|
<el-form ref="materialsFormRef" :model="form" :rules="rules" label-width="120px">
|
||||||
<el-form-item label="材料名称" prop="materialsName">
|
<el-row>
|
||||||
<el-input v-model="form.materialsName" placeholder="请输入材料名称" />
|
<el-col :span="12">
|
||||||
</el-form-item>
|
<el-form-item label="材料名称" prop="materialsName"> <el-input v-model="form.materialsName" placeholder="请输入材料名称" /> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
<el-col :span="12">
|
||||||
<el-form-item label="规格型号名称" prop="typeSpecificationName">
|
<el-form-item label="规格型号名称" prop="typeSpecificationName">
|
||||||
<el-input v-model="form.typeSpecificationName" placeholder="请输入规格型号名称" />
|
<el-input v-model="form.typeSpecificationName" placeholder="请输入规格型号名称" /> </el-form-item
|
||||||
</el-form-item>
|
></el-col>
|
||||||
<el-form-item label="材料供应商" prop="companyId">
|
<el-col :span="12"
|
||||||
|
><el-form-item label="材料提供商" prop="companyId">
|
||||||
<el-select v-model="form.companyId" clearable placeholder="请选择材料提供商">
|
<el-select v-model="form.companyId" clearable placeholder="请选择材料提供商">
|
||||||
<el-option v-for="item in companyOptions" :key="item.value" :label="item.label" :value="item.value" />
|
<el-option v-for="item in companyOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
</el-select>
|
</el-select> </el-form-item
|
||||||
</el-form-item>
|
></el-col>
|
||||||
<el-form-item label="使用部位" prop="usePart">
|
<el-col :span="12">
|
||||||
<el-input v-model="form.usePart" placeholder="请输入使用部位" />
|
<el-form-item label="使用部位" prop="usePart"> <el-input v-model="form.usePart" placeholder="请输入使用部位" /> </el-form-item
|
||||||
</el-form-item>
|
></el-col>
|
||||||
<el-form-item label="计量单位" prop="weightId">
|
<el-col :span="12"
|
||||||
<el-input v-model="form.weightId" placeholder="请输入计量单位" />
|
><el-form-item label="计量单位" prop="weightId"> <el-input v-model="form.weightId" placeholder="请输入计量单位" /> </el-form-item
|
||||||
</el-form-item>
|
></el-col>
|
||||||
|
<el-col :span="12">
|
||||||
<el-form-item label="预计材料数量" prop="quantityCount">
|
<el-form-item label="预计材料数量" prop="quantityCount">
|
||||||
<el-input v-model="form.quantityCount" placeholder="请输入预计材料数量" />
|
<el-input v-model="form.quantityCount" type="number" min="0" placeholder="请输入预计材料数量" /> </el-form-item
|
||||||
</el-form-item>
|
></el-col>
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-col :span="24">
|
||||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
<el-form-item label="备注" prop="remark"> <el-input type="textarea" v-model="form.remark" placeholder="请输入备注" /> </el-form-item
|
||||||
</el-form-item>
|
></el-col>
|
||||||
|
<el-col :span="12" :key="item.value" v-for="item in materials_file_type">
|
||||||
<el-form-item label="材料文件" prop="fileOssIdMap">
|
<el-form-item label="材料文件" prop="fileOssIdMap">
|
||||||
<div :key="item.value" v-for="item in materials_file_type">
|
<div>
|
||||||
<h3>{{ item.label }}</h3>
|
<h3>{{ item.label }}</h3>
|
||||||
<file-upload
|
<file-upload
|
||||||
|
:isShowTip="false"
|
||||||
v-model="ossIdMap[item.value]"
|
v-model="ossIdMap[item.value]"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-size="50"
|
:file-size="50"
|
||||||
@ -131,9 +124,12 @@
|
|||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div> </el-form-item
|
||||||
</el-form-item>
|
></el-col>
|
||||||
|
<el-col :span="24" style="color: rgb(237 70 61)">注意:请上传pdf格式文件</el-col>
|
||||||
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
@ -154,7 +150,7 @@ import { MaterialsForm, MaterialsQuery, MaterialsVO } from '@/api/materials/mate
|
|||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import MaterialsInventoryTable from '@/views/materials/materials/component/MaterialsInventoryTable.vue';
|
import MaterialsInventoryTable from '@/views/materials/materials/component/MaterialsInventoryTable.vue';
|
||||||
import MaterialsInventoryAddDialog from '@/views/materials/materials/component/MaterialsInventoryAddDialog.vue';
|
import MaterialsInventoryAddDialog from '@/views/materials/materials/component/MaterialsInventoryAddDialog.vue';
|
||||||
import { listCompany } from '@/api/materials/company';
|
import { listCompany, supplierInputGet } from '@/api/materials/company';
|
||||||
import { CompanyVO } from '@/api/materials/company/types';
|
import { CompanyVO } from '@/api/materials/company/types';
|
||||||
import MaterialsDetailDrawer from '@/views/materials/materials/component/MaterialsDetailDrawer.vue';
|
import MaterialsDetailDrawer from '@/views/materials/materials/component/MaterialsDetailDrawer.vue';
|
||||||
|
|
||||||
@ -230,14 +226,14 @@ const getList = async () => {
|
|||||||
/** 获取当前项目下的公司列表 */
|
/** 获取当前项目下的公司列表 */
|
||||||
const getCompanyList = async () => {
|
const getCompanyList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const companyRes = await listCompany({
|
const companyRes = await supplierInputGet({
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 1000,
|
|
||||||
projectId: currentProject.value?.id
|
projectId: currentProject.value?.id
|
||||||
});
|
});
|
||||||
companyOptions.value = companyRes.rows.map((company: CompanyVO) => ({
|
console.log(companyRes);
|
||||||
|
|
||||||
|
companyOptions.value = companyRes.data.map((company) => ({
|
||||||
value: company.id,
|
value: company.id,
|
||||||
label: company.companyName
|
label: company.supplierName
|
||||||
}));
|
}));
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
};
|
};
|
||||||
@ -366,6 +362,7 @@ const listeningProject = watch(
|
|||||||
(nid, oid) => {
|
(nid, oid) => {
|
||||||
queryParams.value.projectId = nid;
|
queryParams.value.projectId = nid;
|
||||||
form.value.projectId = nid;
|
form.value.projectId = nid;
|
||||||
|
getCompanyList();
|
||||||
getList();
|
getList();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
:leave-active-class="proxy?.animate.searchAnimate.leave">
|
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
@ -16,8 +15,7 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="材料名称" prop="materialName">
|
<el-form-item label="材料名称" prop="materialName">
|
||||||
<el-input v-model="queryParams.materialName" placeholder="请输入设备材料名称" clearable
|
<el-input v-model="queryParams.materialName" placeholder="请输入设备材料名称" clearable @keyup.enter="handleQuery" />
|
||||||
@keyup.enter="handleQuery" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="订货单位" prop="orderingUnit">
|
<el-form-item label="订货单位" prop="orderingUnit">
|
||||||
<el-input v-model="queryParams.orderingUnit" placeholder="请输入订货单位" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.orderingUnit" placeholder="请输入订货单位" clearable @keyup.enter="handleQuery" />
|
||||||
@ -38,8 +36,7 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd"
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['materials:materialReceive:add']">新增</el-button>
|
||||||
v-hasPermi="['materials:materialReceive:add']">新增</el-button>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -50,8 +47,9 @@
|
|||||||
<el-table-column label="表单编号" align="center" prop="formCode" />
|
<el-table-column label="表单编号" align="center" prop="formCode" />
|
||||||
<el-table-column label="材料来源" align="center" prop="projectName">
|
<el-table-column label="材料来源" align="center" prop="projectName">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag :type="scope.row.materialSource == '1' ? 'success' : 'warning'">{{ scope.row.materialSource == '1' ?
|
<el-tag :type="scope.row.materialSource == '1' ? 'success' : 'warning'">{{
|
||||||
'甲供材料' : '乙供材料' }}</el-tag>
|
scope.row.materialSource == '1' ? '甲供材料' : '乙供材料'
|
||||||
|
}}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="设备材料名称" align="center" prop="materialName" />
|
<el-table-column label="设备材料名称" align="center" prop="materialName" />
|
||||||
@ -77,20 +75,28 @@
|
|||||||
<!-- <el-button link type="primary" icon="edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialReceive:edit']"
|
<!-- <el-button link type="primary" icon="edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialReceive:edit']"
|
||||||
>修改</el-button
|
>修改</el-button
|
||||||
> -->
|
> -->
|
||||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)"
|
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['materials:materialReceive:query']"
|
||||||
v-hasPermi="['materials:materialReceive:query']">查看</el-button>
|
>查看</el-button
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
|
>
|
||||||
v-hasPermi="['materials:materialReceive:remove']">删除</el-button>
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materialReceive:remove']"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
v-model:limit="queryParams.pageSize" @pagination="getList" />
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 添加或修改物料接收单对话框 -->
|
<!-- 添加或修改物料接收单对话框 -->
|
||||||
<el-dialog :close-on-click-modal="false" :close-on-press-escape="false" draggable :title="dialog.title"
|
<el-dialog
|
||||||
v-model="dialog.visible" width="800px" append-to-body>
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
draggable
|
||||||
|
:title="dialog.title"
|
||||||
|
v-model="dialog.visible"
|
||||||
|
width="800px"
|
||||||
|
append-to-body
|
||||||
|
>
|
||||||
<el-form ref="materialReceiveFormRef" :model="form" :rules="rules" label-width="110px">
|
<el-form ref="materialReceiveFormRef" :model="form" :rules="rules" label-width="110px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -108,10 +114,8 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col v-if="form.materialSource == '2'" :span="12">
|
<el-col v-if="form.materialSource == '2'" :span="12">
|
||||||
<el-form-item label="采购单编号" prop="docId">
|
<el-form-item label="采购单编号" prop="docId">
|
||||||
<el-select @change="handleSelect" v-model="form.docId" filterable placeholder="请选择采购单"
|
<el-select @change="handleSelect" v-model="form.docId" filterable placeholder="请选择采购单" style="width: 100%">
|
||||||
style="width: 100%">
|
<el-option v-for="item in purchaseDocList" :key="item.id" :label="item.docCode" :value="item.id"></el-option>
|
||||||
<el-option v-for="item in purchaseDocList" :key="item.id" :label="item.docCode"
|
|
||||||
:value="item.id"></el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -130,11 +134,20 @@
|
|||||||
<el-input disabled v-model="form.projectName" placeholder="请输入工程名称" />
|
<el-input disabled v-model="form.projectName" placeholder="请输入工程名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="12" :offset="0"
|
||||||
|
><el-form-item label="材料名称" prop="materialName">
|
||||||
|
<el-input v-model="form.materialName" placeholder="请输入设备材料名称" clearable /> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
|
||||||
<el-col :span="12" v-if="form.materialSource == '2'">
|
<el-col :span="12" v-if="form.materialSource == '2'">
|
||||||
<el-form-item label="合同编号" prop="contractName">
|
<el-form-item label="合同编号" prop="contractName">
|
||||||
<el-select v-model="form.contractName" filterable placeholder="请选择合同" style="width: 100%">
|
<el-select v-model="form.contractName" filterable placeholder="请选择合同" style="width: 100%">
|
||||||
<el-option v-for="item in contractNameList" :key="item.contractCode" :label="item.contractCode"
|
<el-option
|
||||||
:value="item.contractCode"></el-option>
|
v-for="item in contractNameList"
|
||||||
|
:key="item.contractCode"
|
||||||
|
:label="item.contractCode"
|
||||||
|
:value="item.contractCode"
|
||||||
|
></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -149,48 +162,59 @@
|
|||||||
<div class="detail">
|
<div class="detail">
|
||||||
<div class="detail-header">
|
<div class="detail-header">
|
||||||
<span>数量验收</span>
|
<span>数量验收</span>
|
||||||
<el-button type="primary" v-if="form.materialSource == '1'" link @click="addItem"
|
<el-button type="primary" v-if="form.materialSource == '1'" link @click="addItem" icon="Plus">添加数量验收</el-button>
|
||||||
icon="Plus">添加数量验收</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(item, index) in form.itemList" :key="item.id" class="detail-item">
|
<div v-for="(item, index) in form.itemList" :key="item.id" class="detail-item">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="名称" :prop="`itemList.${index}.name`"
|
<el-form-item label="名称" :prop="`itemList.${index}.name`" :rules="{ required: true, message: '名称不能为空', trigger: 'blur' }">
|
||||||
:rules="{ required: true, message: '名称不能为空', trigger: 'blur' }">
|
|
||||||
<el-input :disabled="form.materialSource == '2'" v-model="item.name" placeholder="请输入名称" />
|
<el-input :disabled="form.materialSource == '2'" v-model="item.name" placeholder="请输入名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="规格" :prop="`itemList.${index}.specification`"
|
<el-form-item
|
||||||
:rules="{ required: true, message: '规格不能为空', trigger: 'blur' }">
|
label="规格"
|
||||||
<el-input :disabled="form.materialSource == '2'" v-model="item.specification"
|
:prop="`itemList.${index}.specification`"
|
||||||
placeholder="请输入规格" />
|
:rules="{ required: true, message: '规格不能为空', trigger: 'blur' }"
|
||||||
|
>
|
||||||
|
<el-input :disabled="form.materialSource == '2'" v-model="item.specification" placeholder="请输入规格" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="单位" :prop="`itemList.${index}.unit`"
|
<el-form-item label="单位" :prop="`itemList.${index}.unit`" :rules="{ required: true, message: '单位不能为空', trigger: 'blur' }">
|
||||||
:rules="{ required: true, message: '单位不能为空', trigger: 'blur' }">
|
|
||||||
<el-input :disabled="form.materialSource == '2'" v-model="item.unit" placeholder="请输入单位" />
|
<el-input :disabled="form.materialSource == '2'" v-model="item.unit" placeholder="请输入单位" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="数量" :prop="`itemList.${index}.quantity`" :rules="rules.quantityRule"
|
<el-form-item label="数量" :prop="`itemList.${index}.quantity`" :rules="rules.quantityRule" ref="quantityFormItemRefs[index]">
|
||||||
ref="quantityFormItemRefs[index]">
|
<el-input
|
||||||
<el-input :disabled="form.materialSource == '2'" type="number" v-model.number="item.quantity"
|
:disabled="form.materialSource == '2'"
|
||||||
placeholder="请输入数量" min="0" @input="handleQuantityInput(index)"
|
type="number"
|
||||||
@blur="handleQuantityBlur(index)" />
|
v-model.number="item.quantity"
|
||||||
|
placeholder="请输入数量"
|
||||||
|
min="0"
|
||||||
|
@input="handleQuantityInput(index)"
|
||||||
|
@blur="handleQuantityBlur(index)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="验收" :prop="`itemList.${index}.acceptedQuantity`"
|
<el-form-item label="验收" :prop="`itemList.${index}.acceptedQuantity`" :rules="rules.acceptedQuantityRule">
|
||||||
:rules="rules.acceptedQuantityRule">
|
<el-input
|
||||||
<el-input type="number" v-model.number="item.acceptedQuantity" placeholder="请输入验收" min="0"
|
type="number"
|
||||||
@input="handleAcceptedInput(index)" />
|
v-model.number="item.acceptedQuantity"
|
||||||
|
placeholder="请输入验收"
|
||||||
|
min="0"
|
||||||
|
@input="handleAcceptedInput(index)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="缺件" :prop="`itemList.${index}.shortageQuantity`"
|
<el-form-item
|
||||||
:rules="{ required: true, message: '缺件数量不能为空', trigger: 'blur' }">
|
label="缺件"
|
||||||
|
:prop="`itemList.${index}.shortageQuantity`"
|
||||||
|
:rules="{ required: true, message: '缺件数量不能为空', trigger: 'blur' }"
|
||||||
|
>
|
||||||
<el-input type="number" min="0" v-model="item.shortageQuantity" placeholder="自动计算" readonly />
|
<el-input type="number" min="0" v-model="item.shortageQuantity" placeholder="自动计算" readonly />
|
||||||
<span class="tips">*自动计算(数量-验收数量)</span>
|
<span class="tips">*自动计算(数量-验收数量)</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -212,26 +236,22 @@
|
|||||||
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="合格证文件" prop="certCountFileId">
|
<el-form-item label="合格证文件" prop="certCountFileId">
|
||||||
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']"
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.certCountFileId" />
|
||||||
v-model="form.certCountFileId" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="出厂报告文件" prop="reportCountFileId">
|
<el-form-item label="出厂报告文件" prop="reportCountFileId">
|
||||||
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']"
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.reportCountFileId" />
|
||||||
v-model="form.reportCountFileId" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="技术资料文件" prop="techDocCountFileId">
|
<el-form-item label="技术资料文件" prop="techDocCountFileId">
|
||||||
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']"
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.techDocCountFileId" />
|
||||||
v-model="form.techDocCountFileId" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="厂家资质文件" prop="licenseCountFileId">
|
<el-form-item label="厂家资质文件" prop="licenseCountFileId">
|
||||||
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']"
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.licenseCountFileId" />
|
||||||
v-model="form.licenseCountFileId" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
<el-form-item label="使用部位" prop="usePart">
|
<el-form-item label="物资名称" prop="materialsName">
|
||||||
<el-input v-model="queryParams.usePart" placeholder="请输入使用部位" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.materialsName" placeholder="请输入物资名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
@ -16,13 +16,20 @@
|
|||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
<!-- 外层表格:使用expandedRowKeys控制展开状态 -->
|
||||||
<!-- 外层表格:添加ref用于控制展开状态 -->
|
<el-table
|
||||||
<el-table ref="outerTableRef" v-loading="loading" :data="materialsUseInventoryList" @expand-change="handleExpandChange" border>
|
ref="outerTableRef"
|
||||||
|
v-loading="loading"
|
||||||
|
:data="materialsUseInventoryList"
|
||||||
|
@expand-change="handleExpandChange"
|
||||||
|
border
|
||||||
|
:expanded-row-keys="expandedRowKeys"
|
||||||
|
>
|
||||||
<el-table-column type="expand">
|
<el-table-column type="expand">
|
||||||
<template #default="props">
|
<template #default="props">
|
||||||
<div style="margin-left: 60px">
|
<div style="margin-left: 60px">
|
||||||
<el-table :data="materialsUseRecordList" border v-loading="loadingChild">
|
<!-- 子表格:使用当前行的独立数据 -->
|
||||||
|
<el-table :data="getChildData(props.row.id)" border v-loading="getChildLoading(props.row.id)">
|
||||||
<el-table-column label="序号" align="center" type="index" width="60" />
|
<el-table-column label="序号" align="center" type="index" width="60" />
|
||||||
<el-table-column label="使用数量" align="center" prop="useNumber" />
|
<el-table-column label="使用数量" align="center" prop="useNumber" />
|
||||||
<el-table-column label="剩余量" align="center" prop="residueNumber" />
|
<el-table-column label="剩余量" align="center" prop="residueNumber" />
|
||||||
@ -35,19 +42,20 @@
|
|||||||
type="primary"
|
type="primary"
|
||||||
icon="delete"
|
icon="delete"
|
||||||
v-if="scope.row.ishow"
|
v-if="scope.row.ishow"
|
||||||
@click="handleDelete(scope.row)"
|
@click="handleDelete(scope.row, props.row.id)"
|
||||||
v-hasPermi="['materials:materialsUseRecord:remove']"
|
v-hasPermi="['materials:materialsUseRecord:remove']"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
<!-- 子分页:使用当前行的独立分页参数 -->
|
||||||
<pagination
|
<pagination
|
||||||
v-show="totalChild > 0"
|
v-show="getChildTotal(props.row.id) > 0"
|
||||||
:total="totalChild"
|
:total="getChildTotal(props.row.id)"
|
||||||
v-model:page="queryParamsChild.pageNum"
|
v-model:page="getChildQueryParams(props.row.id).pageNum"
|
||||||
v-model:limit="queryParamsChild.pageSize"
|
v-model:limit="getChildQueryParams(props.row.id).pageSize"
|
||||||
@pagination="getListChild"
|
@pagination="(page, limit) => handleChildPagination(props.row.id, page, limit)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -104,39 +112,53 @@ import {
|
|||||||
updateMaterialsUseRecord
|
updateMaterialsUseRecord
|
||||||
} from '@/api/materials/materialsUseRecord';
|
} from '@/api/materials/materialsUseRecord';
|
||||||
import { MaterialsUseRecordVO, MaterialsUseRecordQuery, MaterialsUseRecordForm } from '@/api/materials/materialsUseRecord/types';
|
import { MaterialsUseRecordVO, MaterialsUseRecordQuery, MaterialsUseRecordForm } from '@/api/materials/materialsUseRecord/types';
|
||||||
import { getCurrentInstance, ComponentInternalInstance, onMounted, ref, reactive, toRefs, computed } from 'vue';
|
import { getCurrentInstance, ComponentInternalInstance, onMounted, ref, reactive, toRefs, computed, watch, WatchStopHandle } from 'vue';
|
||||||
import { ElFormInstance, ElTable } from 'element-plus';
|
import { ElFormInstance, ElTable } from 'element-plus';
|
||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
|
|
||||||
// 类型定义补充(若项目中无全局DialogOption类型需添加)
|
// 类型定义补充
|
||||||
interface DialogOption {
|
interface DialogOption {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 子列表状态接口:为每个父行存储独立数据
|
||||||
|
interface ChildRowState {
|
||||||
|
list: MaterialsUseRecordVO[];
|
||||||
|
queryParams: MaterialsUseRecordQuery & {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
inventoryId: number;
|
||||||
|
projectId?: number;
|
||||||
|
};
|
||||||
|
loading: boolean;
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
|
||||||
// 核心数据响应式定义
|
// 核心数据响应式定义
|
||||||
const materialsUseRecordList = ref<MaterialsUseRecordVO[]>([]);
|
const materialsUseInventoryList = ref<any[]>([]);
|
||||||
const materialsUseInventoryList = ref<any[]>([]); // 外层列表数据类型可根据实际接口返回调整
|
|
||||||
const buttonLoading = ref(false);
|
const buttonLoading = ref(false);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const loadingChild = ref(true);
|
|
||||||
const showSearch = ref(true);
|
const showSearch = ref(true);
|
||||||
const ids = ref<Array<string | number>>([]);
|
const ids = ref<Array<string | number>>([]);
|
||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const totalChild = ref(0);
|
const expandedRowKeys = ref<number[]>([]); // 控制展开行的ID集合
|
||||||
|
|
||||||
|
// 子列表状态管理:使用对象存储不同父行的子数据,key为inventoryId
|
||||||
|
const childRowStates = ref<Record<number, ChildRowState>>({});
|
||||||
|
|
||||||
// 组件Ref定义
|
// 组件Ref定义
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const materialsUseRecordFormRef = ref<ElFormInstance>();
|
const materialsUseRecordFormRef = ref<ElFormInstance>();
|
||||||
const outerTableRef = ref<InstanceType<typeof ElTable> | undefined>(undefined); // 外层表格Ref(控制展开)
|
const outerTableRef = ref<InstanceType<typeof ElTable> | undefined>(undefined);
|
||||||
const currentExpandInventoryId = ref<number | undefined>(undefined); // 存储当前展开行的inventoryId
|
const currentOperateInventoryId = ref<number | undefined>(undefined); // 当前操作的父行ID
|
||||||
|
|
||||||
// 对话框与表单数据
|
// 对话框与表单数据
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
@ -160,72 +182,132 @@ const data = reactive({
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
outPut: 1,
|
outPut: 1,
|
||||||
usePart: undefined // 补充usePart字段(与表单prop对应)
|
materialsName: undefined,
|
||||||
} as MaterialsUseRecordQuery & { outPut?: number; usePart?: string },
|
usePart: undefined
|
||||||
queryParamsChild: {
|
} as MaterialsUseRecordQuery & {
|
||||||
pageNum: 1,
|
outPut?: number;
|
||||||
pageSize: 10,
|
materialsName?: string;
|
||||||
inventoryId: undefined,
|
usePart?: string;
|
||||||
usePart: undefined,
|
},
|
||||||
useNumber: undefined,
|
|
||||||
residueNumber: undefined
|
|
||||||
} as MaterialsUseRecordQuery,
|
|
||||||
rules: {
|
rules: {
|
||||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
|
||||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||||
inventoryId: [{ required: true, message: '库存ID不能为空', trigger: 'blur' }],
|
inventoryId: [{ required: true, message: '库存ID不能为空', trigger: 'blur' }],
|
||||||
usePart: [{ required: true, message: '使用部位不能为空', trigger: 'blur' }],
|
usePart: [{ required: true, message: '使用部位不能为空', trigger: 'blur' }],
|
||||||
useNumber: [{ required: true, message: '使用数量不能为空', trigger: 'blur' }],
|
useNumber: [{ required: true, message: '使用数量不能为空', trigger: 'blur' }]
|
||||||
residueNumber: [{ required: true, message: '剩余量不能为空', trigger: 'blur' }]
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryParams, form, rules, queryParamsChild } = toRefs(data);
|
const { form, rules } = toRefs(data);
|
||||||
|
const queryParams = ref<typeof data.queryParams>({ ...data.queryParams });
|
||||||
|
|
||||||
/** 查询材料使用登记列表(外层列表) */
|
// ------------------------------ 子列表状态工具函数 ------------------------------
|
||||||
|
/** 获取或初始化指定父行的子列表状态 */
|
||||||
|
const getOrInitChildState = (inventoryId: number): ChildRowState => {
|
||||||
|
if (!childRowStates.value[inventoryId]) {
|
||||||
|
childRowStates.value[inventoryId] = {
|
||||||
|
list: [],
|
||||||
|
loading: false,
|
||||||
|
total: 0,
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
inventoryId,
|
||||||
|
projectId: currentProject.value?.id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return childRowStates.value[inventoryId];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取指定父行的子列表数据 */
|
||||||
|
const getChildData = (inventoryId: number): MaterialsUseRecordVO[] => {
|
||||||
|
return getOrInitChildState(inventoryId).list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取指定父行的子列表加载状态 */
|
||||||
|
const getChildLoading = (inventoryId: number): boolean => {
|
||||||
|
return getOrInitChildState(inventoryId).loading;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取指定父行的子列表总条数 */
|
||||||
|
const getChildTotal = (inventoryId: number): number => {
|
||||||
|
return getOrInitChildState(inventoryId).total;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取指定父行的子分页参数 */
|
||||||
|
const getChildQueryParams = (inventoryId: number) => {
|
||||||
|
return getOrInitChildState(inventoryId).queryParams;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------------ 核心业务逻辑 ------------------------------
|
||||||
|
/** 查询外层列表数据 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
const res = await listMaterialsUseInventory(queryParams.value);
|
const res = await listMaterialsUseInventory(queryParams.value);
|
||||||
materialsUseInventoryList.value = res.rows;
|
materialsUseInventoryList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
|
// 保持已展开行的状态
|
||||||
|
if (expandedRowKeys.value.length > 0 && outerTableRef.value) {
|
||||||
|
expandedRowKeys.value.forEach((id) => {
|
||||||
|
const targetRow = materialsUseInventoryList.value.find((item) => item.id === id);
|
||||||
|
targetRow && outerTableRef.value!.toggleRowExpansion(targetRow, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 处理外层表格展开/折叠:记录当前展开行的inventoryId */
|
/** 处理外层表格展开/折叠 */
|
||||||
const handleExpandChange = (row: any) => {
|
const handleExpandChange = async (row: any, expandedRows: any[]) => {
|
||||||
currentExpandInventoryId.value = row.id; // 记录展开行ID
|
const inventoryId = row.id;
|
||||||
queryParamsChild.value.inventoryId = row.id;
|
// 更新展开行ID集合
|
||||||
getListChild();
|
expandedRowKeys.value = expandedRows.map((item) => item.id);
|
||||||
|
|
||||||
|
// 展开时加载子数据(仅首次加载)
|
||||||
|
const childState = getOrInitChildState(inventoryId);
|
||||||
|
if (expandedRows.some((item) => item.id === inventoryId) && childState.list.length === 0) {
|
||||||
|
await getListChild(inventoryId);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 查询材料子级登记列表(内层列表) */
|
/** 查询指定父行的子列表数据 */
|
||||||
const getListChild = async () => {
|
const getListChild = async (inventoryId: number) => {
|
||||||
loadingChild.value = true;
|
const childState = getOrInitChildState(inventoryId);
|
||||||
|
childState.loading = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await listMaterialsUseRecord(queryParamsChild.value);
|
const res = await listMaterialsUseRecord(childState.queryParams);
|
||||||
materialsUseRecordList.value = res.rows;
|
childState.list = res.rows;
|
||||||
// 控制首行删除按钮显示
|
// 控制首行删除按钮显示
|
||||||
if (res.rows.length > 0) {
|
if (childState.list.length > 0) {
|
||||||
materialsUseRecordList.value[0].ishow = true;
|
childState.list[0].ishow = true;
|
||||||
}
|
}
|
||||||
totalChild.value = res.total;
|
childState.total = res.total;
|
||||||
} finally {
|
} finally {
|
||||||
loadingChild.value = false;
|
childState.loading = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 处理子列表分页变化 */
|
||||||
|
const handleChildPagination = async (inventoryId: number, page: number, limit: number) => {
|
||||||
|
const childState = getOrInitChildState(inventoryId);
|
||||||
|
childState.queryParams.pageNum = page;
|
||||||
|
childState.queryParams.pageSize = limit;
|
||||||
|
await getListChild(inventoryId);
|
||||||
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
|
currentOperateInventoryId.value = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData, projectId: currentProject.value?.id };
|
||||||
materialsUseRecordFormRef.value?.resetFields();
|
materialsUseRecordFormRef.value?.resetFields();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -238,10 +320,16 @@ const handleQuery = () => {
|
|||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
|
queryParams.value = {
|
||||||
|
...data.queryParams,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
projectId: currentProject.value?.id
|
||||||
|
};
|
||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 多选框选中数据(当前模板未使用,保留原逻辑) */
|
/** 多选框选中数据处理 */
|
||||||
const handleSelectionChange = (selection: MaterialsUseRecordVO[]) => {
|
const handleSelectionChange = (selection: MaterialsUseRecordVO[]) => {
|
||||||
ids.value = selection.map((item) => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length !== 1;
|
single.value = selection.length !== 1;
|
||||||
@ -252,75 +340,85 @@ const handleSelectionChange = (selection: MaterialsUseRecordVO[]) => {
|
|||||||
const handleAdd = async (row: any) => {
|
const handleAdd = async (row: any) => {
|
||||||
reset();
|
reset();
|
||||||
form.value.inventoryId = row.id;
|
form.value.inventoryId = row.id;
|
||||||
|
currentOperateInventoryId.value = row.id;
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '添加材料使用登记';
|
dialog.title = '添加材料使用登记';
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 修改按钮操作(当前模板未使用,保留原逻辑) */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: MaterialsUseRecordVO) => {
|
const handleUpdate = async (row?: MaterialsUseRecordVO) => {
|
||||||
|
if (!row && ids.value.length === 0) return;
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
const _id = row?.id || ids.value[0];
|
const _id = row?.id || ids.value[0];
|
||||||
const res = await getMaterialsUseRecord(_id);
|
const res = await getMaterialsUseRecord(_id);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
|
currentOperateInventoryId.value = form.value.inventoryId;
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '修改材料使用登记';
|
dialog.title = '修改材料使用登记';
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 提交按钮:核心优化逻辑(刷新外层列表+保留展开状态) */
|
/** 提交表单操作 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
materialsUseRecordFormRef.value?.validate(async (valid: boolean) => {
|
materialsUseRecordFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (!valid || !currentOperateInventoryId.value) return;
|
||||||
|
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
try {
|
try {
|
||||||
// 1. 执行添加/修改接口请求
|
// 执行添加或修改操作
|
||||||
await addMaterialsUseRecord(form.value);
|
const apiFn = form.value.id ? updateMaterialsUseRecord : addMaterialsUseRecord;
|
||||||
// 2. 刷新外层列表(确保外层数据同步,如剩余量)
|
await apiFn(form.value);
|
||||||
|
|
||||||
|
// 刷新外层列表和当前操作行的子列表
|
||||||
await getList();
|
await getList();
|
||||||
// 3. 刷新当前展开行的子列表
|
await getListChild(currentOperateInventoryId.value);
|
||||||
await getListChild();
|
|
||||||
// 4. 恢复展开状态:根据记录的inventoryId重新展开行
|
|
||||||
if (currentExpandInventoryId.value && outerTableRef.value) {
|
|
||||||
const targetRow = materialsUseInventoryList.value.find((item) => item.id === currentExpandInventoryId.value);
|
|
||||||
if (targetRow) {
|
|
||||||
outerTableRef.value.toggleRowExpansion(targetRow, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
} finally {
|
} finally {
|
||||||
buttonLoading.value = false;
|
buttonLoading.value = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除操作 */
|
||||||
const handleDelete = async (row?: MaterialsUseRecordVO) => {
|
const handleDelete = async (row: MaterialsUseRecordVO, inventoryId: number) => {
|
||||||
const _ids = row?.id || ids.value;
|
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm(`是否确认删除材料使用登记编号为"${_ids}"的数据项?`);
|
await proxy?.$modal.confirm(`是否确认删除该记录?`);
|
||||||
await delMaterialsUseRecord(_ids);
|
await delMaterialsUseRecord(row.id);
|
||||||
await getList();
|
await getList();
|
||||||
await getListChild();
|
await getListChild(inventoryId);
|
||||||
if (currentExpandInventoryId.value && outerTableRef.value) {
|
|
||||||
const targetRow = materialsUseInventoryList.value.find((item) => item.id === currentExpandInventoryId.value);
|
|
||||||
if (targetRow) {
|
|
||||||
outerTableRef.value.toggleRowExpansion(targetRow, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
await getListChild();
|
} catch (error) {
|
||||||
} finally {
|
// 取消删除时不做处理
|
||||||
loading.value = false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 导出按钮操作(保留原逻辑) */
|
/** 导出操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download('materials/materialsUseRecord/export', { ...queryParams.value }, `materialsUseRecord_${new Date().getTime()}.xlsx`);
|
proxy?.download('materials/materialsUseRecord/export', { ...queryParams.value }, `materialsUseRecord_${new Date().getTime()}.xlsx`);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 页面挂载时加载外层列表 */
|
// 监听项目ID变化刷新数据
|
||||||
|
const listeningProject: WatchStopHandle = watch(
|
||||||
|
() => currentProject.value?.id,
|
||||||
|
(newId) => {
|
||||||
|
queryParams.value.projectId = newId;
|
||||||
|
form.value.projectId = newId;
|
||||||
|
// 更新所有子列表的项目ID
|
||||||
|
Object.values(childRowStates.value).forEach((state) => {
|
||||||
|
state.queryParams.projectId = newId;
|
||||||
|
});
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 页面卸载时清理监听
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面挂载时加载数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
619
src/views/materials/overallPlanMaterialSupply/index copy.vue
Normal file
619
src/views/materials/overallPlanMaterialSupply/index copy.vue
Normal file
@ -0,0 +1,619 @@
|
|||||||
|
<template>
|
||||||
|
<div class="overall-plan-material-supply">
|
||||||
|
<el-card shadow="always">
|
||||||
|
<template #header>
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-form :inline="true">
|
||||||
|
<el-form-item v-if="state.masterData.status == 'draft'">
|
||||||
|
<el-button type="primary" icon="edit" @click="clickApprovalSheet1()">审批</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="state.masterData.status == 'waiting' || state.masterData.status == 'finish'">
|
||||||
|
<el-button icon="view" @click="lookApprovalFlow()" type="warning">查看流程</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<file-upload
|
||||||
|
upload-url="/design/totalsupplyplan/import"
|
||||||
|
v-model="file"
|
||||||
|
:limit="1"
|
||||||
|
:file-type="['xls', 'xlsx']"
|
||||||
|
:on-upload-success="handleSuccess"
|
||||||
|
>
|
||||||
|
<el-button :disabled="state.masterData.status == 'finish'" type="primary" plain icon="upload">导入</el-button>
|
||||||
|
</file-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button icon="Finished" @click="editApprovalSheet()" type="success" :disabled="state.masterData.status == 'finish'"
|
||||||
|
>一键全部保存</el-button
|
||||||
|
>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="toggleExpandAll">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<right-toolbar @queryTable="getMasterDataList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 本地数据懒加载表格 -->
|
||||||
|
<el-table
|
||||||
|
:data="state.tableData"
|
||||||
|
v-loading="state.loading.list"
|
||||||
|
ref="tableRef"
|
||||||
|
stripe
|
||||||
|
style="width: 100%; margin-bottom: 20px; height: calc(100vh - 230px)"
|
||||||
|
row-key="id"
|
||||||
|
border
|
||||||
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
|
:lazy="true"
|
||||||
|
:load="loadLocalChildNodes"
|
||||||
|
@expand-change="handleExpandChange"
|
||||||
|
>
|
||||||
|
<el-table-column align="center" prop="num" label="编号" />
|
||||||
|
<el-table-column prop="name" label="工程或费用名称" width="180" />
|
||||||
|
<el-table-column prop="unit" label="单位" />
|
||||||
|
<el-table-column prop="specification" label="规格型号" width="80" />
|
||||||
|
<el-table-column prop="quantity" label="数量" width="100" />
|
||||||
|
<el-table-column prop="batchNumber" label="批次号" width="200" />
|
||||||
|
|
||||||
|
<!-- 优化的输入框列 -->
|
||||||
|
<el-table-column prop="brand" label="品牌">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input
|
||||||
|
v-model.lazy="row.brand"
|
||||||
|
:disabled="state.masterData.status != 'draft'"
|
||||||
|
v-if="!row.hasChildren"
|
||||||
|
placeholder=""
|
||||||
|
clearable
|
||||||
|
:key="`brand-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'brand')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="texture" label="材质">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input
|
||||||
|
v-model.lazy="row.texture"
|
||||||
|
:disabled="state.masterData.status != 'draft'"
|
||||||
|
v-if="!row.hasChildren"
|
||||||
|
placeholder=""
|
||||||
|
clearable
|
||||||
|
:key="`texture-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'texture')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="qualityStandard" label="质量标准">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input
|
||||||
|
:disabled="state.masterData.status != 'draft'"
|
||||||
|
v-model.lazy="row.qualityStandard"
|
||||||
|
v-if="!row.hasChildren"
|
||||||
|
placeholder=""
|
||||||
|
clearable
|
||||||
|
:key="`qualityStandard-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'qualityStandard')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="partUsed" label="使用部位">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input
|
||||||
|
:disabled="state.masterData.status != 'draft'"
|
||||||
|
v-model.lazy="row.partUsed"
|
||||||
|
v-if="!row.hasChildren"
|
||||||
|
placeholder=""
|
||||||
|
clearable
|
||||||
|
:key="`partUsed-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'partUsed')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="deliveryPoints" label="交货地点">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input
|
||||||
|
:disabled="state.masterData.status != 'draft'"
|
||||||
|
v-model.lazy="row.deliveryPoints"
|
||||||
|
v-if="!row.hasChildren"
|
||||||
|
placeholder=""
|
||||||
|
clearable
|
||||||
|
:key="`deliveryPoints-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'deliveryPoints')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="预计使用日期" width="150">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="row.dateService"
|
||||||
|
v-if="!row.hasChildren"
|
||||||
|
type="date"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
:disabled="state.masterData.status != 'draft'"
|
||||||
|
placeholder="请选择日期"
|
||||||
|
:key="`dateService-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'dateService')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="remark" label="备注" />
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 编辑弹窗 -->
|
||||||
|
<el-dialog v-model="visible" title="修改物料信息" :width="800" :close-on-click-modal="false" @close="handleClose">
|
||||||
|
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" class="space-y-4">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="批次号" prop="batchNumber">
|
||||||
|
<el-input disabled v-model="formData.batchNumber" placeholder="请输入批次号" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="品牌" prop="brand">
|
||||||
|
<el-input v-model="formData.brand" placeholder="请输入品牌" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="材质" prop="texture">
|
||||||
|
<el-input v-model="formData.texture" placeholder="请输入材质" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="质量标准" prop="qualityStandard">
|
||||||
|
<el-input v-model="formData.qualityStandard" placeholder="请输入质量标准" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="使用部位" prop="partUsed">
|
||||||
|
<el-input v-model="formData.partUsed" placeholder="请输入使用部位" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="交货地点" prop="deliveryPoints">
|
||||||
|
<el-input v-model="formData.deliveryPoints" placeholder="请输入交货地点" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="预计使用日期" prop="dateService">
|
||||||
|
<el-date-picker v-model="formData.dateService" type="date" placeholder="选择预计使用日期" format="YYYY-MM-DD" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="formData.remark" placeholder="请输入备注信息" type="textarea" rows="3" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="handleClose">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="billofQuantities">
|
||||||
|
import { ref, reactive, onMounted, computed, getCurrentInstance, watch, onUnmounted } from 'vue';
|
||||||
|
import { ElMessage, ElLoading } from 'element-plus';
|
||||||
|
import {
|
||||||
|
obtainMasterDataList,
|
||||||
|
totalsupplyplan,
|
||||||
|
totalSupplyplanDetails,
|
||||||
|
materialChangeSupplyplan,
|
||||||
|
totalSupplyplanBatchEdit
|
||||||
|
} from '@/api/materials/overallPlanMaterialSupply/index';
|
||||||
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
|
||||||
|
// 全局状态与实例获取
|
||||||
|
const userStore = useUserStoreHook();
|
||||||
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
|
||||||
|
// 基础状态管理
|
||||||
|
const visible = ref(false);
|
||||||
|
const formRef = ref(null);
|
||||||
|
const tableRef = ref(null);
|
||||||
|
const file = ref(null);
|
||||||
|
const isExpandAll = ref(false);
|
||||||
|
const expandRowKeys = ref([]);
|
||||||
|
const editDataMap = ref(new Map()); // 用Map存储修改的数据,提高查询效率
|
||||||
|
const loadingInstance = ref(null);
|
||||||
|
const fullTreeData = ref([]); // 存储完整树形数据,用于本地懒加载
|
||||||
|
|
||||||
|
// 页面核心状态
|
||||||
|
const state = reactive({
|
||||||
|
tableData: [], // 初始只存放根节点
|
||||||
|
queryForm: {
|
||||||
|
projectId: currentProject.value?.id,
|
||||||
|
versions: '',
|
||||||
|
sheet: '',
|
||||||
|
pageSize: 20,
|
||||||
|
pageNum: 1
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
versions: false,
|
||||||
|
sheets: false,
|
||||||
|
list: false
|
||||||
|
},
|
||||||
|
masterData: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const formData = reactive({
|
||||||
|
batchNumber: '',
|
||||||
|
brand: '',
|
||||||
|
compileDate: '',
|
||||||
|
dateService: '',
|
||||||
|
deliveryPoints: '',
|
||||||
|
id: undefined,
|
||||||
|
name: '',
|
||||||
|
num: '',
|
||||||
|
partUsed: '',
|
||||||
|
planNumber: '',
|
||||||
|
projectId: undefined,
|
||||||
|
qualityStandard: '',
|
||||||
|
quantity: 0,
|
||||||
|
remark: '',
|
||||||
|
specification: '',
|
||||||
|
status: '',
|
||||||
|
texture: '',
|
||||||
|
unit: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const formRules = reactive({
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '请输入名称', trigger: 'blur' },
|
||||||
|
{ max: 100, message: '名称长度不能超过100个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
num: [
|
||||||
|
{ required: true, message: '请输入编号', trigger: 'blur' },
|
||||||
|
{ max: 50, message: '编号长度不能超过50个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
quantity: [
|
||||||
|
{ required: true, message: '请输入数量', trigger: 'blur' },
|
||||||
|
{ type: 'number', min: 0, message: '数量不能为负数', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
compileDate: [{ required: true, message: '请选择编制日期', trigger: 'change' }]
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地数据懒加载实现:从完整数据中筛选子节点
|
||||||
|
*/
|
||||||
|
const loadLocalChildNodes = (row, treeNode, resolve) => {
|
||||||
|
// 避免重复加载
|
||||||
|
if (row.children && row.children.length > 0) {
|
||||||
|
resolve(row.children);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示加载状态
|
||||||
|
loadingInstance.value = ElLoading.service({
|
||||||
|
target: tableRef.value.$el,
|
||||||
|
text: '加载子节点中...',
|
||||||
|
background: 'rgba(255, 255, 255, 0.8)'
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 从完整数据中筛选当前行的子节点(假设父ID对应子节点的pid)
|
||||||
|
const childNodes = fullTreeData.value.filter((node) => node.pid === row.id);
|
||||||
|
|
||||||
|
// 标记子节点是否有子节点
|
||||||
|
const formattedChildren = childNodes.map((node) => ({
|
||||||
|
...node,
|
||||||
|
hasChildren: fullTreeData.value.some((child) => child.pid === node.id)
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 缓存子节点到当前行
|
||||||
|
row.children = formattedChildren;
|
||||||
|
resolve(formattedChildren);
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(`加载子节点异常:${error.message}`);
|
||||||
|
resolve([]);
|
||||||
|
} finally {
|
||||||
|
loadingInstance.value?.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理展开状态变化
|
||||||
|
*/
|
||||||
|
const handleExpandChange = (row, expanded) => {
|
||||||
|
if (expanded) {
|
||||||
|
if (!expandRowKeys.value.includes(row.id)) {
|
||||||
|
expandRowKeys.value.push(row.id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expandRowKeys.value = expandRowKeys.value.filter((id) => id !== row.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一键展开/收起
|
||||||
|
*/
|
||||||
|
const toggleExpandAll = async () => {
|
||||||
|
isExpandAll.value = !isExpandAll.value;
|
||||||
|
|
||||||
|
if (isExpandAll.value) {
|
||||||
|
loadingInstance.value = ElLoading.service({
|
||||||
|
target: tableRef.value.$el,
|
||||||
|
text: '正在加载所有节点...',
|
||||||
|
background: 'rgba(255, 255, 255, 0.8)'
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 递归加载所有层级子节点
|
||||||
|
const loadAllChildren = (nodes) => {
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
const children = fullTreeData.value.filter((child) => child.sid === node.id);
|
||||||
|
const formattedChildren = children.map((child) => ({
|
||||||
|
...child,
|
||||||
|
hasChildren: fullTreeData.value.some((c) => c.sid === child.id)
|
||||||
|
}));
|
||||||
|
node.children = formattedChildren;
|
||||||
|
if (formattedChildren.length > 0) {
|
||||||
|
loadAllChildren(formattedChildren);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
loadAllChildren(state.tableData);
|
||||||
|
// 展开所有节点
|
||||||
|
state.tableData.forEach((row) => {
|
||||||
|
tableRef.value.toggleRowExpansion(row, true);
|
||||||
|
});
|
||||||
|
ElMessage.success('所有节点已展开');
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(`一键展开失败:${error.message}`);
|
||||||
|
} finally {
|
||||||
|
loadingInstance.value?.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 收起所有节点
|
||||||
|
state.tableData.forEach((row) => {
|
||||||
|
tableRef.value.toggleRowExpansion(row, false);
|
||||||
|
});
|
||||||
|
expandRowKeys.value = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理输入框变化(优化性能)
|
||||||
|
*/
|
||||||
|
const handleInputChange = (row, field) => {
|
||||||
|
// 只记录修改过的数据,避免全量对比
|
||||||
|
if (!editDataMap.value.has(row.id)) {
|
||||||
|
editDataMap.value.set(row.id, { ...row });
|
||||||
|
}
|
||||||
|
const storedData = editDataMap.value.get(row.id);
|
||||||
|
storedData[field] = row[field];
|
||||||
|
editDataMap.value.set(row.id, storedData);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取主数据列表(核心优化:拆分根节点和完整数据)
|
||||||
|
*/
|
||||||
|
async function getMasterDataList() {
|
||||||
|
try {
|
||||||
|
state.loading.list = true;
|
||||||
|
// 获取主数据
|
||||||
|
const masterDataRes = await obtainMasterDataList({
|
||||||
|
projectId: currentProject.value?.id
|
||||||
|
});
|
||||||
|
const { data: masterData } = masterDataRes;
|
||||||
|
|
||||||
|
if (!masterData[0]?.id) {
|
||||||
|
state.tableData = [];
|
||||||
|
fullTreeData.value = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.masterData = masterData[0];
|
||||||
|
|
||||||
|
// 获取完整供应计划数据
|
||||||
|
const supplyPlanRes = await totalsupplyplan({ id: masterData[0].id });
|
||||||
|
const allData = supplyPlanRes.rows || [];
|
||||||
|
|
||||||
|
// 存储完整数据到本地
|
||||||
|
fullTreeData.value = [...allData];
|
||||||
|
|
||||||
|
// 初始只加载根节点(pid为空或0的节点)
|
||||||
|
const rootNodes = allData.filter((item) => !item.pid || item.pid === 0);
|
||||||
|
|
||||||
|
// 标记根节点是否有子节点
|
||||||
|
state.tableData = rootNodes.map((node) => ({
|
||||||
|
...node,
|
||||||
|
hasChildren: allData.some((child) => child.pid === node.id)
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 初始化可编辑数据映射
|
||||||
|
editDataMap.value.clear();
|
||||||
|
allData.forEach((item) => {
|
||||||
|
if (!item.hasChildren) {
|
||||||
|
// 只关注叶子节点
|
||||||
|
editDataMap.value.set(item.id, { ...item });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(`数据加载失败:${error.message}`);
|
||||||
|
state.tableData = [];
|
||||||
|
fullTreeData.value = [];
|
||||||
|
} finally {
|
||||||
|
state.loading.list = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情
|
||||||
|
*/
|
||||||
|
async function totalSupplyplanDetail(id) {
|
||||||
|
try {
|
||||||
|
const result = await totalSupplyplanDetails(id);
|
||||||
|
if (result?.code === 200) {
|
||||||
|
const detailData = result.data || {};
|
||||||
|
|
||||||
|
// 清空表单并赋值
|
||||||
|
Object.keys(formData).forEach((key) => {
|
||||||
|
formData[key] = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理日期格式
|
||||||
|
const formatDate = (date) => {
|
||||||
|
if (!date) return '';
|
||||||
|
const d = typeof date === 'string' ? new Date(date) : date;
|
||||||
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(formData, {
|
||||||
|
...detailData,
|
||||||
|
compileDate: formatDate(detailData.compileDate),
|
||||||
|
dateService: formatDate(detailData.dateService)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ElMessage.error(`获取详情失败: ${result?.msg || '未知错误'}`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
ElMessage.error(`接口请求失败: ${err.message}`);
|
||||||
|
console.error('详情接口错误:', err);
|
||||||
|
} finally {
|
||||||
|
state.loading.list = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一键保存修改
|
||||||
|
*/
|
||||||
|
const editApprovalSheet = async () => {
|
||||||
|
state.loading.list = true;
|
||||||
|
try {
|
||||||
|
// 只提交修改过的数据(从Map中获取)
|
||||||
|
const modifiedData = Array.from(editDataMap.value.values());
|
||||||
|
if (modifiedData.length === 0) {
|
||||||
|
ElMessage.info('没有数据需要修改');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await totalSupplyplanBatchEdit(modifiedData);
|
||||||
|
ElMessage.success('修改成功');
|
||||||
|
getMasterDataList(); // 重新加载数据
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(`保存失败:${error.message}`);
|
||||||
|
} finally {
|
||||||
|
state.loading.list = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交表单
|
||||||
|
*/
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
await formRef.value.validate();
|
||||||
|
await materialChangeSupplyplan(formData);
|
||||||
|
ElMessage.success('修改成功');
|
||||||
|
handleClose();
|
||||||
|
getMasterDataList();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('表单验证失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出数据
|
||||||
|
*/
|
||||||
|
const handleExport = async () => {
|
||||||
|
proxy?.download('/design/totalsupplyplan/export', { projectId: currentProject.value?.id }, `物资供应总计划.xlsx`, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭弹窗
|
||||||
|
*/
|
||||||
|
const handleClose = () => {
|
||||||
|
visible.value = false;
|
||||||
|
formRef.value?.resetFields();
|
||||||
|
Object.keys(formData).forEach((key) => {
|
||||||
|
formData[key] = undefined;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批
|
||||||
|
*/
|
||||||
|
function clickApprovalSheet1() {
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.push({
|
||||||
|
path: `/approval/overallPlanMaterialSupply/indexEdit`,
|
||||||
|
query: { id: state.masterData.id, type: 'update' }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查看流程
|
||||||
|
*/
|
||||||
|
function lookApprovalFlow() {
|
||||||
|
proxy.$router.push({
|
||||||
|
path: `/approval/overallPlanMaterialSupply/indexEdit`,
|
||||||
|
query: { id: state.masterData.id, type: 'view' }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听项目变化
|
||||||
|
*/
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value?.id,
|
||||||
|
(nid) => {
|
||||||
|
if (nid) getMasterDataList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 导入成功处理
|
||||||
|
const handleSuccess = () => {
|
||||||
|
ElMessage.success('导入成功');
|
||||||
|
getMasterDataList();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生命周期
|
||||||
|
onMounted(() => {
|
||||||
|
if (currentProject.value?.id) {
|
||||||
|
getMasterDataList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
loadingInstance.value?.close();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.overall-plan-material-supply {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-y-4 > .el-row {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-y-4 > .el-row:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="overall-plan-material-supply">
|
<div class="overall-plan-material-supply">
|
||||||
<!-- tabPosition="left" -->
|
|
||||||
<el-card shadow="always">
|
<el-card shadow="always">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
@ -30,14 +29,16 @@
|
|||||||
>一键全部保存</el-button
|
>一键全部保存</el-button
|
||||||
>
|
>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<!-- <el-form-item>
|
||||||
<el-button type="primary" @click="toggleExpandAll">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button>
|
<el-button type="primary" @click="toggleExpandAll">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
</el-form>
|
</el-form>
|
||||||
<right-toolbar @queryTable="getMasterDataList"></right-toolbar>
|
<right-toolbar @queryTable="getMasterDataList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 本地数据懒加载表格 -->
|
||||||
<el-table
|
<el-table
|
||||||
:data="state.tableData"
|
:data="state.tableData"
|
||||||
v-loading="state.loading.list"
|
v-loading="state.loading.list"
|
||||||
@ -47,6 +48,9 @@
|
|||||||
row-key="id"
|
row-key="id"
|
||||||
border
|
border
|
||||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
|
:lazy="true"
|
||||||
|
:load="loadLocalChildNodes"
|
||||||
|
@expand-change="handleExpandChange"
|
||||||
>
|
>
|
||||||
<el-table-column align="center" prop="num" label="编号" />
|
<el-table-column align="center" prop="num" label="编号" />
|
||||||
<el-table-column prop="name" label="工程或费用名称" width="180" />
|
<el-table-column prop="name" label="工程或费用名称" width="180" />
|
||||||
@ -54,87 +58,95 @@
|
|||||||
<el-table-column prop="specification" label="规格型号" width="80" />
|
<el-table-column prop="specification" label="规格型号" width="80" />
|
||||||
<el-table-column prop="quantity" label="数量" width="100" />
|
<el-table-column prop="quantity" label="数量" width="100" />
|
||||||
<el-table-column prop="batchNumber" label="批次号" width="200" />
|
<el-table-column prop="batchNumber" label="批次号" width="200" />
|
||||||
|
|
||||||
|
<!-- 优化的输入框列 -->
|
||||||
<el-table-column prop="brand" label="品牌">
|
<el-table-column prop="brand" label="品牌">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="row.brand"
|
v-model.lazy="row.brand"
|
||||||
:disabled="state.masterData.status != 'draft'"
|
:disabled="state.masterData.status != 'draft'"
|
||||||
v-if="!(row.children && row.children.length > 0)"
|
v-if="!row.hasChildren"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
clearable
|
clearable
|
||||||
|
:key="`brand-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'brand')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column prop="texture" label="材质">
|
<el-table-column prop="texture" label="材质">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="row.texture"
|
v-model.lazy="row.texture"
|
||||||
:disabled="state.masterData.status != 'draft'"
|
:disabled="state.masterData.status != 'draft'"
|
||||||
v-if="!(row.children && row.children.length > 0)"
|
v-if="!row.hasChildren"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
clearable
|
clearable
|
||||||
|
:key="`texture-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'texture')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column prop="qualityStandard" label="质量标准">
|
<el-table-column prop="qualityStandard" label="质量标准">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-input
|
<el-input
|
||||||
:disabled="state.masterData.status != 'draft'"
|
:disabled="state.masterData.status != 'draft'"
|
||||||
v-model="row.qualityStandard"
|
v-model.lazy="row.qualityStandard"
|
||||||
v-if="!(row.children && row.children.length > 0)"
|
v-if="!row.hasChildren"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
clearable
|
clearable
|
||||||
|
:key="`qualityStandard-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'qualityStandard')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column prop="partUsed" label="使用部位">
|
<el-table-column prop="partUsed" label="使用部位">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-input
|
<el-input
|
||||||
:disabled="state.masterData.status != 'draft'"
|
:disabled="state.masterData.status != 'draft'"
|
||||||
v-model="row.partUsed"
|
v-model.lazy="row.partUsed"
|
||||||
v-if="!(row.children && row.children.length > 0)"
|
v-if="!row.hasChildren"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
clearable
|
clearable
|
||||||
|
:key="`partUsed-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'partUsed')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column prop="deliveryPoints" label="交货地点">
|
<el-table-column prop="deliveryPoints" label="交货地点">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-input
|
<el-input
|
||||||
:disabled="state.masterData.status != 'draft'"
|
:disabled="state.masterData.status != 'draft'"
|
||||||
v-model="row.deliveryPoints"
|
v-model.lazy="row.deliveryPoints"
|
||||||
v-if="!(row.children && row.children.length > 0)"
|
v-if="!row.hasChildren"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
clearable
|
clearable
|
||||||
|
:key="`deliveryPoints-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'deliveryPoints')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="预计使用日期" width="150">
|
<el-table-column label="预计使用日期" width="150">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="row.dateService"
|
v-model="row.dateService"
|
||||||
v-if="!(row.children && row.children.length > 0)"
|
v-if="!row.hasChildren"
|
||||||
type="date"
|
type="date"
|
||||||
value-format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
||||||
:disabled="state.masterData.status != 'draft'"
|
:disabled="state.masterData.status != 'draft'"
|
||||||
placeholder="请选择日期"
|
placeholder="请选择日期"
|
||||||
|
:key="`dateService-${row.id}`"
|
||||||
|
@change="handleInputChange(row, 'dateService')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="remark" label="备注" />
|
<el-table-column prop="remark" label="备注" />
|
||||||
<!-- <el-table-column label="操作">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-button
|
|
||||||
:disabled="state.masterData.status == 'waiting' || state.masterData.status == 'finish'"
|
|
||||||
type="primary"
|
|
||||||
v-hasPermi="['design:totalsupplyplan:edit']"
|
|
||||||
@click="editApprovalSheet(row)"
|
|
||||||
>修改</el-button
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
</el-table-column> -->
|
|
||||||
</el-table>
|
</el-table>
|
||||||
<!-- 编辑 -->
|
<!-- 编辑弹窗 -->
|
||||||
<el-dialog v-model="visible" title="修改物料信息" :width="800" :close-on-click-modal="false" @close="handleClose">
|
<el-dialog v-model="visible" title="修改物料信息" :width="800" :close-on-click-modal="false" @close="handleClose">
|
||||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" class="space-y-4">
|
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" class="space-y-4">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
@ -149,7 +161,6 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<!-- 物料属性区域 -->
|
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="材质" prop="texture">
|
<el-form-item label="材质" prop="texture">
|
||||||
@ -162,7 +173,6 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<!-- 日期与状态区域 -->
|
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="使用部位" prop="partUsed">
|
<el-form-item label="使用部位" prop="partUsed">
|
||||||
@ -175,7 +185,6 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<!-- 其他信息区域 -->
|
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="预计使用日期" prop="dateService">
|
<el-form-item label="预计使用日期" prop="dateService">
|
||||||
@ -200,7 +209,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="billofQuantities">
|
<script setup name="billofQuantities">
|
||||||
import { ref, reactive, onMounted, computed, getCurrentInstance } from 'vue';
|
import { ref, reactive, onMounted, computed, getCurrentInstance, watch, onUnmounted } from 'vue';
|
||||||
|
import { ElMessage, ElLoading } from 'element-plus';
|
||||||
import {
|
import {
|
||||||
obtainMasterDataList,
|
obtainMasterDataList,
|
||||||
totalsupplyplan,
|
totalsupplyplan,
|
||||||
@ -209,13 +219,26 @@ import {
|
|||||||
totalSupplyplanBatchEdit
|
totalSupplyplanBatchEdit
|
||||||
} from '@/api/materials/overallPlanMaterialSupply/index';
|
} from '@/api/materials/overallPlanMaterialSupply/index';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
|
||||||
|
// 全局状态与实例获取
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
|
|
||||||
|
// 基础状态管理
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const formRef = ref(null);
|
const formRef = ref(null);
|
||||||
|
const tableRef = ref(null);
|
||||||
|
const file = ref(null);
|
||||||
|
const isExpandAll = ref(false);
|
||||||
|
const expandRowKeys = ref([]);
|
||||||
|
const editDataMap = ref(new Map()); // 用Map存储修改的数据,提高查询效率
|
||||||
|
const loadingInstance = ref(null);
|
||||||
|
const fullTreeData = ref([]); // 存储完整树形数据,用于本地懒加载
|
||||||
|
|
||||||
|
// 页面核心状态
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tableData: [],
|
tableData: [], // 初始只存放根节点
|
||||||
queryForm: {
|
queryForm: {
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
versions: '',
|
versions: '',
|
||||||
@ -228,9 +251,9 @@ const state = reactive({
|
|||||||
sheets: false,
|
sheets: false,
|
||||||
list: false
|
list: false
|
||||||
},
|
},
|
||||||
// 主id
|
|
||||||
masterData: {}
|
masterData: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 表单数据
|
// 表单数据
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
batchNumber: '',
|
batchNumber: '',
|
||||||
@ -252,6 +275,7 @@ const formData = reactive({
|
|||||||
texture: '',
|
texture: '',
|
||||||
unit: ''
|
unit: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
const formRules = reactive({
|
const formRules = reactive({
|
||||||
name: [
|
name: [
|
||||||
@ -268,82 +292,190 @@ const formRules = reactive({
|
|||||||
],
|
],
|
||||||
compileDate: [{ required: true, message: '请选择编制日期', trigger: 'change' }]
|
compileDate: [{ required: true, message: '请选择编制日期', trigger: 'change' }]
|
||||||
});
|
});
|
||||||
// 展开状态
|
|
||||||
const isExpandAll = ref(false);
|
/**
|
||||||
const tableRef = ref(null);
|
* 本地数据懒加载实现:从完整数据中筛选子节点
|
||||||
// 切换展开状态
|
*/
|
||||||
const toggleExpandAll = () => {
|
const loadLocalChildNodes = (row, treeNode, resolve) => {
|
||||||
|
// 避免重复加载
|
||||||
|
if (row.children && row.children.length > 0) {
|
||||||
|
resolve(row.children);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示加载状态
|
||||||
|
loadingInstance.value = ElLoading.service({
|
||||||
|
target: tableRef.value.$el,
|
||||||
|
text: '加载中...',
|
||||||
|
background: 'rgba(255, 255, 255, 0.8)'
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 从完整数据中筛选当前行的子节点(假设父ID对应子节点的pid)
|
||||||
|
const childNodes = fullTreeData.value.filter((node) => node.pid === row.sid);
|
||||||
|
|
||||||
|
// 标记子节点是否有子节点
|
||||||
|
const formattedChildren = childNodes.map((node) => ({
|
||||||
|
...node,
|
||||||
|
hasChildren: fullTreeData.value.some((child) => child.pid === node.sid)
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 缓存子节点到当前行
|
||||||
|
row.children = formattedChildren;
|
||||||
|
resolve(formattedChildren);
|
||||||
|
} catch (error) {
|
||||||
|
resolve([]);
|
||||||
|
} finally {
|
||||||
|
loadingInstance.value?.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理展开状态变化
|
||||||
|
*/
|
||||||
|
const handleExpandChange = (row, expanded) => {
|
||||||
|
if (expanded) {
|
||||||
|
if (!expandRowKeys.value.includes(row.id)) {
|
||||||
|
expandRowKeys.value.push(row.id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expandRowKeys.value = expandRowKeys.value.filter((id) => id !== row.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一键展开/收起
|
||||||
|
*/
|
||||||
|
const toggleExpandAll = async () => {
|
||||||
isExpandAll.value = !isExpandAll.value;
|
isExpandAll.value = !isExpandAll.value;
|
||||||
console.log(isExpandAll.value);
|
|
||||||
state.tableData.forEach((row) => {
|
if (isExpandAll.value) {
|
||||||
tableRef.value.toggleRowExpansion(row, isExpandAll.value);
|
loadingInstance.value = ElLoading.service({
|
||||||
|
target: tableRef.value.$el,
|
||||||
|
text: '正在加载...',
|
||||||
|
background: 'rgba(255, 255, 255, 0.8)'
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 递归加载所有层级子节点
|
||||||
|
const loadAllChildren = (nodes) => {
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
const children = fullTreeData.value.filter((child) => child.pid === node.sid);
|
||||||
|
const formattedChildren = children.map((child) => ({
|
||||||
|
...child,
|
||||||
|
hasChildren: fullTreeData.value.some((c) => c.pid === child.sid)
|
||||||
|
}));
|
||||||
|
node.children = formattedChildren;
|
||||||
|
if (formattedChildren.length > 0) {
|
||||||
|
loadAllChildren(formattedChildren);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 获取主表数据
|
|
||||||
|
loadAllChildren(state.tableData);
|
||||||
|
// 展开所有节点
|
||||||
|
state.tableData.forEach((row) => {
|
||||||
|
tableRef.value.toggleRowExpansion(row, true);
|
||||||
|
});
|
||||||
|
ElMessage.success('所有节点已展开');
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(`一键展开失败:${error.message}`);
|
||||||
|
} finally {
|
||||||
|
loadingInstance.value?.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 收起所有节点
|
||||||
|
state.tableData.forEach((row) => {
|
||||||
|
tableRef.value.toggleRowExpansion(row, false);
|
||||||
|
});
|
||||||
|
expandRowKeys.value = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理输入框变化(优化性能)
|
||||||
|
*/
|
||||||
|
const handleInputChange = (row, field) => {
|
||||||
|
// 只记录修改过的数据,避免全量对比
|
||||||
|
if (!editDataMap.value.has(row.id)) {
|
||||||
|
editDataMap.value.set(row.id, { ...row });
|
||||||
|
}
|
||||||
|
const storedData = editDataMap.value.get(row.id);
|
||||||
|
storedData[field] = row[field];
|
||||||
|
editDataMap.value.set(row.id, storedData);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 获取主数据列表(核心优化:拆分根节点和完整数据)
|
||||||
|
*/
|
||||||
async function getMasterDataList() {
|
async function getMasterDataList() {
|
||||||
try {
|
try {
|
||||||
// 获取主数据列表
|
|
||||||
state.loading.list = true;
|
state.loading.list = true;
|
||||||
|
// 获取主数据
|
||||||
const masterDataRes = await obtainMasterDataList({
|
const masterDataRes = await obtainMasterDataList({
|
||||||
projectId: currentProject.value?.id
|
projectId: currentProject.value?.id
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: masterData } = masterDataRes;
|
const { data: masterData } = masterDataRes;
|
||||||
console.log('masterData', masterData);
|
|
||||||
|
|
||||||
if (!masterData[0].id) {
|
if (!masterData[0]?.id) {
|
||||||
console.warn('未获取到有效的主数据ID');
|
|
||||||
state.tableData = [];
|
state.tableData = [];
|
||||||
|
fullTreeData.value = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.masterData = masterData[0];
|
state.masterData = masterData[0];
|
||||||
|
// 获取完整供应计划数据
|
||||||
// 获取供应计划
|
const supplyPlanRes = await totalsupplyplan({ id: masterData[0].id, projectId: currentProject.value?.id });
|
||||||
const supplyPlanRes = await totalsupplyplan({ id: masterData[0].id });
|
const allData = supplyPlanRes.rows || [];
|
||||||
|
// 存储完整数据到本地
|
||||||
// 处理结果
|
fullTreeData.value = [...allData];
|
||||||
if (supplyPlanRes.list == null) {
|
// 初始只加载根节点(pid为空或0的节点)
|
||||||
// state.tableData = supplyPlanRes.rows || [];
|
const rootNodes = allData.filter((item) => !item.pid || item.pid == 0);
|
||||||
state.tableData = proxy?.handleTree(supplyPlanRes.rows, 'sid', 'pid');
|
// 标记根节点是否有子节点
|
||||||
console.log('state.tableData', state.tableData);
|
state.tableData = rootNodes.map((node) => ({
|
||||||
} else {
|
...node,
|
||||||
// 根据实际业务逻辑处理有list的情况
|
hasChildren: allData.some((child) => child.pid === node.sid)
|
||||||
state.tableData = [];
|
}));
|
||||||
|
// 初始化可编辑数据映射
|
||||||
|
editDataMap.value.clear();
|
||||||
|
allData.forEach((item) => {
|
||||||
|
if (!item.hasChildren) {
|
||||||
|
// 只关注叶子节点
|
||||||
|
editDataMap.value.set(item.id, { ...item });
|
||||||
}
|
}
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取主数据列表失败:', error);
|
|
||||||
// 错误情况下给默认值,避免页面出错
|
|
||||||
state.tableData = [];
|
state.tableData = [];
|
||||||
|
fullTreeData.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
state.loading.list = false;
|
state.loading.list = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 获取详情
|
|
||||||
// 修改获取详情的方法
|
/**
|
||||||
|
* 获取详情
|
||||||
|
*/
|
||||||
async function totalSupplyplanDetail(id) {
|
async function totalSupplyplanDetail(id) {
|
||||||
try {
|
try {
|
||||||
const result = await totalSupplyplanDetails(id);
|
const result = await totalSupplyplanDetails(id);
|
||||||
if (result?.code === 200) {
|
if (result?.code === 200) {
|
||||||
const detailData = result.data || {};
|
const detailData = result.data || {};
|
||||||
// 1. 清空原有表单数据
|
|
||||||
|
// 清空表单并赋值
|
||||||
Object.keys(formData).forEach((key) => {
|
Object.keys(formData).forEach((key) => {
|
||||||
formData[key] = undefined;
|
formData[key] = undefined;
|
||||||
});
|
});
|
||||||
// 2. 处理日期格式(假设接口返回的是Date对象或ISO字符串)
|
|
||||||
|
// 处理日期格式
|
||||||
const formatDate = (date) => {
|
const formatDate = (date) => {
|
||||||
if (!date) return '';
|
if (!date) return '';
|
||||||
// 若为字符串,先转为Date对象
|
|
||||||
const d = typeof date === 'string' ? new Date(date) : date;
|
const d = typeof date === 'string' ? new Date(date) : date;
|
||||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
||||||
};
|
};
|
||||||
// 3. 合并数据到formData(响应式赋值)
|
|
||||||
Object.assign(formData, {
|
Object.assign(formData, {
|
||||||
...detailData,
|
...detailData,
|
||||||
// 单独处理日期字段,转为表单可识别的字符串格式
|
|
||||||
compileDate: formatDate(detailData.compileDate),
|
compileDate: formatDate(detailData.compileDate),
|
||||||
dateService: formatDate(detailData.dateService)
|
dateService: formatDate(detailData.dateService)
|
||||||
});
|
});
|
||||||
console.log('表单数据已更新:', formData);
|
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(`获取详情失败: ${result?.msg || '未知错误'}`);
|
ElMessage.error(`获取详情失败: ${result?.msg || '未知错误'}`);
|
||||||
}
|
}
|
||||||
@ -354,87 +486,113 @@ async function totalSupplyplanDetail(id) {
|
|||||||
state.loading.list = false;
|
state.loading.list = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 修改
|
|
||||||
|
/**
|
||||||
|
* 一键保存修改
|
||||||
|
*/
|
||||||
const editApprovalSheet = async () => {
|
const editApprovalSheet = async () => {
|
||||||
state.loading.list = true;
|
state.loading.list = true;
|
||||||
await totalSupplyplanBatchEdit(state.tableData);
|
|
||||||
proxy.$modal.msgSuccess('修改成功');
|
|
||||||
|
|
||||||
state.loading.list = false;
|
|
||||||
};
|
|
||||||
// 提交表单
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
try {
|
try {
|
||||||
// 表单验证
|
// 只提交修改过的数据(从Map中获取)
|
||||||
await formRef.value.validate();
|
const modifiedData = Array.from(editDataMap.value.values());
|
||||||
// 触发提交事件
|
if (modifiedData.length === 0) {
|
||||||
editMaterialSupply(formData);
|
ElMessage.info('没有数据需要修改');
|
||||||
handleClose();
|
|
||||||
} catch (error) {
|
|
||||||
// 验证失败不提交
|
|
||||||
console.error('表单验证失败:', error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
// 修改物资
|
await totalSupplyplanBatchEdit(modifiedData);
|
||||||
function editMaterialSupply(formData) {
|
|
||||||
materialChangeSupplyplan(formData).then((res) => {
|
|
||||||
if (res.code === 200) {
|
|
||||||
ElMessage.success('修改成功');
|
ElMessage.success('修改成功');
|
||||||
getMasterDataList();
|
getMasterDataList(); // 重新加载数据
|
||||||
} else {
|
} catch (error) {
|
||||||
ElMessage.error('修改失败');
|
ElMessage.error(`保存失败:${error.message}`);
|
||||||
|
} finally {
|
||||||
|
state.loading.list = false;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleExport = async () => {
|
|
||||||
proxy?.download(
|
|
||||||
'/design/totalsupplyplan/export',
|
|
||||||
{
|
|
||||||
projectId: currentProject.value?.id
|
|
||||||
},
|
|
||||||
`物资供应总计划.xlsx`,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 关闭弹窗
|
/**
|
||||||
|
* 提交表单
|
||||||
|
*/
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
await formRef.value.validate();
|
||||||
|
await materialChangeSupplyplan(formData);
|
||||||
|
ElMessage.success('修改成功');
|
||||||
|
handleClose();
|
||||||
|
getMasterDataList();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('表单验证失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出数据
|
||||||
|
*/
|
||||||
|
const handleExport = async () => {
|
||||||
|
proxy?.download('/design/totalsupplyplan/export', { projectId: currentProject.value?.id }, `物资供应总计划.xlsx`, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭弹窗
|
||||||
|
*/
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
// 清空表单数据
|
formRef.value?.resetFields();
|
||||||
Object.keys(formData).forEach((key) => {
|
Object.keys(formData).forEach((key) => {
|
||||||
formData[key] = undefined;
|
formData[key] = undefined;
|
||||||
});
|
});
|
||||||
// 重置表单验证状态
|
|
||||||
formRef.value?.resetFields();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 审批
|
/**
|
||||||
|
* 审批
|
||||||
|
*/
|
||||||
function clickApprovalSheet1() {
|
function clickApprovalSheet1() {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/approval/overallPlanMaterialSupply/indexEdit`,
|
path: `/approval/overallPlanMaterialSupply/indexEdit`,
|
||||||
query: {
|
query: { id: state.masterData.id, type: 'update' }
|
||||||
id: state.masterData.id,
|
|
||||||
type: 'update'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 审核流程
|
|
||||||
|
/**
|
||||||
|
* 查看流程
|
||||||
|
*/
|
||||||
function lookApprovalFlow() {
|
function lookApprovalFlow() {
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/approval/overallPlanMaterialSupply/indexEdit`,
|
path: `/approval/overallPlanMaterialSupply/indexEdit`,
|
||||||
query: {
|
query: { id: state.masterData.id, type: 'view' }
|
||||||
id: state.masterData.id,
|
|
||||||
type: 'view'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
|
||||||
|
/**
|
||||||
|
* 监听项目变化
|
||||||
|
*/
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value?.id,
|
||||||
|
(nid) => {
|
||||||
|
if (nid) getMasterDataList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 导入成功处理
|
||||||
|
const handleSuccess = () => {
|
||||||
|
ElMessage.success('导入成功');
|
||||||
getMasterDataList();
|
getMasterDataList();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生命周期
|
||||||
|
onMounted(() => {
|
||||||
|
if (currentProject.value?.id) {
|
||||||
|
getMasterDataList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
loadingInstance.value?.close();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.overall-plan-material-supply {
|
.overall-plan-material-supply {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
@ -51,9 +51,10 @@
|
|||||||
size="small"
|
size="small"
|
||||||
icon="Plus"
|
icon="Plus"
|
||||||
type="primary"
|
type="primary"
|
||||||
|
v-if="scope.row.purchaseSubmission == '0'"
|
||||||
link
|
link
|
||||||
@click="handleAddSon(scope.row)"
|
@click="handleAddSon(scope.row)"
|
||||||
>添加</el-button
|
>提交</el-button
|
||||||
>
|
>
|
||||||
<el-button type="primary" v-hasPermi="['cailiaoshebei:physicalsupply:edit']" size="small" icon="Edit" link @click="handleEdit(scope.row)"
|
<el-button type="primary" v-hasPermi="['cailiaoshebei:physicalsupply:edit']" size="small" icon="Edit" link @click="handleEdit(scope.row)"
|
||||||
>修改</el-button
|
>修改</el-button
|
||||||
@ -113,7 +114,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="运算周期(天)" prop="executionCycle">
|
<el-form-item label="运算周期(天)" prop="executionCycle">
|
||||||
<el-input v-model.number="formData.executionCycle" placeholder="请输入运算周期" type="number"></el-input>
|
<el-input v-model.number="formData.executionCycle" min="0" placeholder="请输入运算周期" type="number"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -121,12 +122,12 @@
|
|||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="安装量" prop="installationQuantity">
|
<el-form-item label="安装量" prop="installationQuantity">
|
||||||
<el-input v-model="formData.installationQuantity" placeholder="请输入安装量"></el-input>
|
<el-input v-model="formData.installationQuantity" min="0" type="number" placeholder="请输入安装量"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="安装比例" prop="installationRatio">
|
<el-form-item label="安装比例" prop="installationRatio">
|
||||||
<el-input v-model="formData.installationRatio" placeholder="请输入安装比例" suffix="%"></el-input>
|
<el-input v-model="formData.installationRatio" min="0" type="number" placeholder="请输入安装比例" suffix="%"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -296,22 +297,7 @@ const handleSearch = () => {
|
|||||||
// 刷新数据
|
// 刷新数据
|
||||||
const refreshData = () => {
|
const refreshData = () => {
|
||||||
fetchData();
|
fetchData();
|
||||||
ElMessage.success('数据已刷新');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 分页大小改变
|
|
||||||
const handleSizeChange = (val) => {
|
|
||||||
pageSize.value = val;
|
|
||||||
currentPage.value = 1;
|
|
||||||
fetchData();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 当前页改变
|
|
||||||
const handleCurrentChange = (val) => {
|
|
||||||
currentPage.value = val;
|
|
||||||
fetchData();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 新增
|
// 新增
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
dialogType.value = 'add';
|
dialogType.value = 'add';
|
||||||
@ -476,6 +462,17 @@ const jumpRouter = (row) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value?.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
fetchData();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
// 初始化页面
|
// 初始化页面
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchData();
|
fetchData();
|
||||||
|
@ -30,9 +30,7 @@
|
|||||||
:row-class-name="tableRowClassName"
|
:row-class-name="tableRowClassName"
|
||||||
>
|
>
|
||||||
<!-- 基础信息列 -->
|
<!-- 基础信息列 -->
|
||||||
<el-table-column prop="id" label="ID" width="180" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="batch" label="批次" align="center"></el-table-column>
|
<el-table-column prop="batch" label="批次" align="center"></el-table-column>
|
||||||
<el-table-column prop="physicalsupplyId" label="使用情况ID" width="180" align="center"></el-table-column>
|
|
||||||
<!-- 时间相关列 -->
|
<!-- 时间相关列 -->
|
||||||
<el-table-column prop="issuanceTime" label="联系单下达时间" min-width="160" align="center">
|
<el-table-column prop="issuanceTime" label="联系单下达时间" min-width="160" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
@ -86,13 +86,14 @@ const handleTabChange = (tab) => {
|
|||||||
activeTab.value = tab;
|
activeTab.value = tab;
|
||||||
data.queryParams.valueType = '1';
|
data.queryParams.valueType = '1';
|
||||||
// data.queryParams.month = '';
|
// data.queryParams.month = '';
|
||||||
|
getList();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 查询项目总产值分配列表 */
|
/** 查询项目总产值分配列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
const res = await listOutTable(queryParams.value);
|
const res = await listOutTable({ ...queryParams.value, type: activeTab.value });
|
||||||
valueAllocationList.value = res.rows;
|
valueAllocationList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -161,7 +161,7 @@
|
|||||||
:total="detailTotalWork"
|
:total="detailTotalWork"
|
||||||
v-model:page="detailQueryParamsWork.pageNum"
|
v-model:page="detailQueryParamsWork.pageNum"
|
||||||
v-model:limit="detailQueryParamsWork.pageSize"
|
v-model:limit="detailQueryParamsWork.pageSize"
|
||||||
@pagination="getPvModuleList"
|
@pagination="getDailyBookList"
|
||||||
layout="total, sizes, prev, pager, next"
|
layout="total, sizes, prev, pager, next"
|
||||||
:isSmall="5"
|
:isSmall="5"
|
||||||
/>
|
/>
|
||||||
@ -436,10 +436,10 @@ const handleView = (row: any, obj: any) => {
|
|||||||
|
|
||||||
// 获取已填日报
|
// 获取已填日报
|
||||||
const getDailyBookList = (doneTime: string) => {
|
const getDailyBookList = (doneTime: string) => {
|
||||||
detialWordList.value = [];
|
// detialWordList.value = [];
|
||||||
getDailyBook({
|
getDailyBook({
|
||||||
id: formDetail.value.id,
|
id: formDetail.value.id,
|
||||||
...detailQueryParams.value
|
...detailQueryParamsWork.value
|
||||||
}).then((res: any) => {
|
}).then((res: any) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
detialWordList.value = res.rows || [];
|
detialWordList.value = res.rows || [];
|
||||||
|
@ -298,6 +298,11 @@ const getList = async () => {
|
|||||||
const res = await getProjectSquare(currentProject.value?.id);
|
const res = await getProjectSquare(currentProject.value?.id);
|
||||||
if (res.data.length === 0) {
|
if (res.data.length === 0) {
|
||||||
proxy?.$modal.msgWarning('当前项目下没有方阵,请先创建方阵');
|
proxy?.$modal.msgWarning('当前项目下没有方阵,请先创建方阵');
|
||||||
|
matrixOptions.value = [];
|
||||||
|
queryParams.value.projectId = '';
|
||||||
|
form.value.projectId = '';
|
||||||
|
tabList.value = [];
|
||||||
|
activeTab.value = '';
|
||||||
} else {
|
} else {
|
||||||
let matrixList = res.data.map((item) => {
|
let matrixList = res.data.map((item) => {
|
||||||
return {
|
return {
|
||||||
@ -472,6 +477,7 @@ const matrixValue = ref<number | undefined>(matrixOptions.value.length > 0 ? mat
|
|||||||
const resetMatrix = () => {
|
const resetMatrix = () => {
|
||||||
matrixValue.value = undefined;
|
matrixValue.value = undefined;
|
||||||
queryParams.value.matrixId = undefined;
|
queryParams.value.matrixId = undefined;
|
||||||
|
queryParams.value.projectId = undefined;
|
||||||
matrixOptions.value = [];
|
matrixOptions.value = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -491,8 +497,6 @@ onMounted(() => {
|
|||||||
const listeningProject = watch(
|
const listeningProject = watch(
|
||||||
() => currentProject.value?.id,
|
() => currentProject.value?.id,
|
||||||
(nid, oid) => {
|
(nid, oid) => {
|
||||||
queryParams.value.projectId = nid;
|
|
||||||
form.value.projectId = nid;
|
|
||||||
resetMatrix();
|
resetMatrix();
|
||||||
getList();
|
getList();
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@
|
|||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:enterRoad:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:enterRoad:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<!-- <el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Plus" @click="downloadTemplate" v-hasPermi="['land:enterRoad:import']">模板下载</el-button>
|
<el-button type="success" plain icon="Plus" @click="downloadTemplate" v-hasPermi="['land:enterRoad:import']">模板下载</el-button>
|
||||||
</el-col>
|
</el-col> -->
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-upload
|
<el-upload
|
||||||
ref="uploadRef"
|
ref="uploadRef"
|
||||||
|
@ -36,9 +36,9 @@
|
|||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:landBlock:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:landBlock:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<!-- <el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Plus" @click="downloadTemplate" v-hasPermi="['land:enterRoad:import']">模板下载</el-button>
|
<el-button type="success" plain icon="Plus" @click="downloadTemplate" v-hasPermi="['land:enterRoad:import']">模板下载</el-button>
|
||||||
</el-col>
|
</el-col> -->
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-upload ref="uploadRef" class="upload-demo" :http-request="handleImport" :show-file-list="false">
|
<el-upload ref="uploadRef" class="upload-demo" :http-request="handleImport" :show-file-list="false">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
@ -234,7 +234,7 @@ const showSearch = ref(true);
|
|||||||
const uploadRef = ref<any>(null);
|
const uploadRef = ref<any>(null);
|
||||||
|
|
||||||
// 方阵表单模型(核心修复:使用reactive并显式声明结构)
|
// 方阵表单模型(核心修复:使用reactive并显式声明结构)
|
||||||
const formM = reactive<MatrixForm>({
|
const formM = ref<MatrixForm>({
|
||||||
landId: undefined,
|
landId: undefined,
|
||||||
unitBoList: [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }]
|
unitBoList: [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }]
|
||||||
});
|
});
|
||||||
@ -424,11 +424,11 @@ const getfangzhenList = async () => {
|
|||||||
/** 关联方阵 */
|
/** 关联方阵 */
|
||||||
const handleView = async (row: LandBlockVO) => {
|
const handleView = async (row: LandBlockVO) => {
|
||||||
if (!row?.id) return proxy?.$modal.msgWarning('请选择有效的地块');
|
if (!row?.id) return proxy?.$modal.msgWarning('请选择有效的地块');
|
||||||
|
console.log('🚀 ~ handleView ~ row:', row);
|
||||||
// 重置方阵表单
|
// 重置方阵表单
|
||||||
resetMatrix();
|
resetMatrix();
|
||||||
// 绑定当前地块ID
|
// 绑定当前地块ID
|
||||||
formM.landId = row.id;
|
formM.value.landId = row.id;
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
dialogMatrix.visible = true;
|
dialogMatrix.visible = true;
|
||||||
|
|
||||||
@ -437,7 +437,7 @@ const handleView = async (row: LandBlockVO) => {
|
|||||||
|
|
||||||
/** 新增方阵表单项 */
|
/** 新增方阵表单项 */
|
||||||
const addUnitBoItem = () => {
|
const addUnitBoItem = () => {
|
||||||
formM.unitBoList.push({
|
formM.value.unitBoList.push({
|
||||||
unitProjectArea: '',
|
unitProjectArea: '',
|
||||||
unitProjectStatus: '',
|
unitProjectStatus: '',
|
||||||
unitProjectId: []
|
unitProjectId: []
|
||||||
@ -448,10 +448,10 @@ const addUnitBoItem = () => {
|
|||||||
|
|
||||||
/** 删除方阵表单项 */
|
/** 删除方阵表单项 */
|
||||||
const removeUnitBoItem = (index: number) => {
|
const removeUnitBoItem = (index: number) => {
|
||||||
if (formM.unitBoList.length <= 1) {
|
if (formM.value.unitBoList.length <= 1) {
|
||||||
return proxy?.$modal.msgWarning('至少保留一项方阵配置');
|
return proxy?.$modal.msgWarning('至少保留一项方阵配置');
|
||||||
}
|
}
|
||||||
formM.unitBoList.splice(index, 1);
|
formM.value.unitBoList.splice(index, 1);
|
||||||
landBlockFormMatrixRef.value?.clearValidate();
|
landBlockFormMatrixRef.value?.clearValidate();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -459,11 +459,11 @@ const removeUnitBoItem = (index: number) => {
|
|||||||
const submitFormMatrix = () => {
|
const submitFormMatrix = () => {
|
||||||
landBlockFormMatrixRef.value?.validate(async (valid: boolean) => {
|
landBlockFormMatrixRef.value?.validate(async (valid: boolean) => {
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
if (!formM.landId) return proxy?.$modal.msgWarning('地块ID异常,请重新选择地块');
|
if (!formM.value.landId) return proxy?.$modal.msgWarning('地块ID异常,请重新选择地块');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 处理方阵数据(修复ID拆分逻辑)
|
// 处理方阵数据(修复ID拆分逻辑)
|
||||||
const unitBoListParams = formM.unitBoList.map((item) => {
|
const unitBoListParams = formM.value.unitBoList.map((item) => {
|
||||||
// 取级联选择的最后一层值
|
// 取级联选择的最后一层值
|
||||||
const lastLevelValue = item.unitProjectId[item.unitProjectId.length - 1];
|
const lastLevelValue = item.unitProjectId[item.unitProjectId.length - 1];
|
||||||
if (!lastLevelValue) throw new Error('请选择完整的方阵');
|
if (!lastLevelValue) throw new Error('请选择完整的方阵');
|
||||||
@ -482,7 +482,7 @@ const submitFormMatrix = () => {
|
|||||||
|
|
||||||
// 调用关联接口
|
// 调用关联接口
|
||||||
const res = await LandUnit({
|
const res = await LandUnit({
|
||||||
landId: formM.landId,
|
landId: formM.value.landId,
|
||||||
unitBoList: unitBoListParams
|
unitBoList: unitBoListParams
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -507,12 +507,12 @@ const cancelMatrix = () => {
|
|||||||
|
|
||||||
/** 方阵表单重置 */
|
/** 方阵表单重置 */
|
||||||
const resetMatrix = () => {
|
const resetMatrix = () => {
|
||||||
formM.landId = undefined;
|
|
||||||
formM.unitBoList = [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }];
|
|
||||||
if (landBlockFormMatrixRef.value) {
|
if (landBlockFormMatrixRef.value) {
|
||||||
landBlockFormMatrixRef.value.resetFields();
|
landBlockFormMatrixRef.value.resetFields();
|
||||||
landBlockFormMatrixRef.value.clearValidate();
|
landBlockFormMatrixRef.value.clearValidate();
|
||||||
}
|
}
|
||||||
|
formM.value.landId = undefined;
|
||||||
|
formM.value.unitBoList = [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }];
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 监听项目变化,刷新数据 */
|
/** 监听项目变化,刷新数据 */
|
||||||
|
413
src/views/system/appMenu/index.vue
Normal file
413
src/views/system/appMenu/index.vue
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2">
|
||||||
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
|
<el-form-item label="菜单名称" prop="menuName">
|
||||||
|
<el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态" prop="status">
|
||||||
|
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable>
|
||||||
|
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<template #header>
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button v-hasPermi="['system:menu:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增 </el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
ref="menuTableRef"
|
||||||
|
v-loading="loading"
|
||||||
|
:data="menuList"
|
||||||
|
row-key="menuId"
|
||||||
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
|
:default-expand-all="isExpandAll"
|
||||||
|
>
|
||||||
|
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
||||||
|
<el-table-column prop="icon" label="图标" align="center" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<svg-icon :icon-class="scope.row.icon" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
|
||||||
|
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
|
||||||
|
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
|
||||||
|
<el-table-column prop="status" label="状态" width="80">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createTime">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.createTime }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column fixed="right" label="操作" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="修改" placement="top">
|
||||||
|
<el-button v-hasPermi="['system:menu:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="新增" placement="top">
|
||||||
|
<el-button v-hasPermi="['system:menu:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="删除" placement="top">
|
||||||
|
<el-button v-hasPermi="['system:menu:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-bod width="750px">
|
||||||
|
<el-form ref="menuFormRef" :model="form" :rules="rules" label-width="100px">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="上级菜单">
|
||||||
|
<el-tree-select
|
||||||
|
v-model="form.parentId"
|
||||||
|
:data="menuOptions"
|
||||||
|
:props="{ value: 'menuId', label: 'menuName', children: 'children' }"
|
||||||
|
value-key="menuId"
|
||||||
|
placeholder="选择上级菜单"
|
||||||
|
check-strictly
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="菜单类型" prop="menuType">
|
||||||
|
<el-radio-group v-model="form.menuType">
|
||||||
|
<el-radio value="M">目录</el-radio>
|
||||||
|
<el-radio value="C">菜单</el-radio>
|
||||||
|
<el-radio value="F">按钮</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.menuType !== 'F'" :span="24">
|
||||||
|
<el-form-item label="菜单图标" prop="icon">
|
||||||
|
<!-- 图标选择器 -->
|
||||||
|
<icon-select v-model="form.icon" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="菜单名称" prop="menuName">
|
||||||
|
<el-input v-model="form.menuName" placeholder="请输入菜单名称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="显示排序" prop="orderNum">
|
||||||
|
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.menuType !== 'F'" :span="12">
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<question-filled />
|
||||||
|
</el-icon> </el-tooltip
|
||||||
|
>是否外链
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<el-radio-group v-model="form.isFrame">
|
||||||
|
<el-radio label="0">是</el-radio>
|
||||||
|
<el-radio label="1">否</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.menuType !== 'F'" :span="12">
|
||||||
|
<el-form-item prop="path">
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<question-filled />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
路由地址
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<el-input v-model="form.path" placeholder="请输入路由地址" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.menuType === 'C'" :span="12">
|
||||||
|
<el-form-item prop="component">
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<question-filled />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
组件路径
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<el-input v-model="form.component" placeholder="请输入组件路径" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.menuType !== 'M'" :span="12">
|
||||||
|
<el-form-item>
|
||||||
|
<el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="控制器中定义的权限字符,如:@SaCheckPermission('system:user:list')" placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<question-filled />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
权限字符
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.menuType === 'C'" :span="12">
|
||||||
|
<el-form-item>
|
||||||
|
<el-input v-model="form.queryParam" placeholder="请输入路由参数" maxlength="255" />
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<question-filled />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
路由参数
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.menuType === 'C'" :span="12">
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<question-filled />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
是否缓存
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<el-radio-group v-model="form.isCache">
|
||||||
|
<el-radio label="0">缓存</el-radio>
|
||||||
|
<el-radio label="1">不缓存</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.menuType !== 'F'" :span="12">
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<question-filled />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
显示状态
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<el-radio-group v-model="form.visible">
|
||||||
|
<el-radio v-for="dict in sys_show_hide" :key="dict.value" :label="dict.value">{{ dict.label }} </el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<question-filled />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
菜单状态
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<el-radio-group v-model="form.status">
|
||||||
|
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">
|
||||||
|
{{ dict.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="Menu" lang="ts">
|
||||||
|
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from '@/api/system/menu';
|
||||||
|
import { MenuForm, MenuQuery, MenuVO } from '@/api/system/menu/types';
|
||||||
|
import { MenuTypeEnum } from '@/enums/MenuTypeEnum';
|
||||||
|
|
||||||
|
interface MenuOptionsType {
|
||||||
|
menuId: number;
|
||||||
|
menuName: string;
|
||||||
|
children: MenuOptionsType[] | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_show_hide', 'sys_normal_disable'));
|
||||||
|
|
||||||
|
const menuList = ref<MenuVO[]>([]);
|
||||||
|
const loading = ref(true);
|
||||||
|
const showSearch = ref(true);
|
||||||
|
const menuOptions = ref<MenuOptionsType[]>([]);
|
||||||
|
const isExpandAll = ref(false);
|
||||||
|
|
||||||
|
const dialog = reactive<DialogOption>({
|
||||||
|
visible: false,
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
const menuFormRef = ref<ElFormInstance>();
|
||||||
|
const initFormData = {
|
||||||
|
path: '',
|
||||||
|
menuId: undefined,
|
||||||
|
parentId: 0,
|
||||||
|
menuName: '',
|
||||||
|
icon: '',
|
||||||
|
menuType: MenuTypeEnum.M,
|
||||||
|
orderNum: 1,
|
||||||
|
isFrame: '1',
|
||||||
|
isCache: '0',
|
||||||
|
visible: '0',
|
||||||
|
status: '0',
|
||||||
|
menuSource: '2'
|
||||||
|
};
|
||||||
|
const data = reactive<PageData<MenuForm, MenuQuery>>({
|
||||||
|
form: { ...initFormData },
|
||||||
|
queryParams: {
|
||||||
|
menuName: undefined,
|
||||||
|
status: undefined,
|
||||||
|
menuSource: 2
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
menuName: [{ required: true, message: '菜单名称不能为空', trigger: 'blur' }],
|
||||||
|
orderNum: [{ required: true, message: '菜单顺序不能为空', trigger: 'blur' }],
|
||||||
|
path: [{ required: true, message: '路由地址不能为空', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const menuTableRef = ref<ElTableInstance>();
|
||||||
|
|
||||||
|
const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data);
|
||||||
|
/** 查询菜单列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await listMenu(queryParams.value);
|
||||||
|
const data = proxy?.handleTree<MenuVO>(res.data, 'menuId');
|
||||||
|
if (data) {
|
||||||
|
menuList.value = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
/** 查询菜单下拉树结构 */
|
||||||
|
const getTreeselect = async () => {
|
||||||
|
menuOptions.value = [];
|
||||||
|
const response = await listMenu();
|
||||||
|
const menu: MenuOptionsType = { menuId: 0, menuName: '主类目', children: [] };
|
||||||
|
menu.children = proxy?.handleTree<MenuOptionsType>(response.data, 'menuId');
|
||||||
|
menuOptions.value.push(menu);
|
||||||
|
};
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
reset();
|
||||||
|
dialog.visible = false;
|
||||||
|
};
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = { ...initFormData };
|
||||||
|
menuFormRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields();
|
||||||
|
handleQuery();
|
||||||
|
};
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
const handleAdd = (row?: MenuVO) => {
|
||||||
|
reset();
|
||||||
|
getTreeselect();
|
||||||
|
row && row.menuId ? (form.value.parentId = row.menuId) : (form.value.parentId = 0);
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '添加菜单';
|
||||||
|
};
|
||||||
|
/** 展开/折叠操作 */
|
||||||
|
const handleToggleExpandAll = () => {
|
||||||
|
isExpandAll.value = !isExpandAll.value;
|
||||||
|
toggleExpandAll(menuList.value, isExpandAll.value);
|
||||||
|
};
|
||||||
|
/** 展开/折叠所有 */
|
||||||
|
const toggleExpandAll = (data: MenuVO[], status: boolean) => {
|
||||||
|
data.forEach((item: MenuVO) => {
|
||||||
|
menuTableRef.value?.toggleRowExpansion(item, status);
|
||||||
|
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
const handleUpdate = async (row: MenuVO) => {
|
||||||
|
reset();
|
||||||
|
await getTreeselect();
|
||||||
|
if (row.menuId) {
|
||||||
|
const { data } = await getMenu(row.menuId);
|
||||||
|
form.value = data;
|
||||||
|
}
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '修改菜单';
|
||||||
|
};
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = () => {
|
||||||
|
menuFormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
dialog.visible = false;
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (row: MenuVO) => {
|
||||||
|
await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
|
||||||
|
await delMenu(row.menuId);
|
||||||
|
await getList();
|
||||||
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
</script>
|
160
src/views/system/appRole/authUser.vue
Normal file
160
src/views/system/appRole/authUser.vue
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2">
|
||||||
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
|
<div v-show="showSearch" class="search">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
|
<el-form-item label="用户名称" prop="userName">
|
||||||
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号码" prop="phonenumber">
|
||||||
|
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
<el-card shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="openSelectUser">添加用户</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button v-hasPermi="['system:role:remove']" type="danger" plain icon="CircleClose" :disabled="multiple" @click="cancelAuthUserAll">
|
||||||
|
批量取消授权
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar v-model:show-search="showSearch" :search="true" @query-table="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="状态" align="center" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.createTime }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="取消授权" placement="top">
|
||||||
|
<el-button v-hasPermi="['system:role:remove']" link type="primary" icon="CircleClose" @click="cancelAuthUser(scope.row)"> </el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
|
<select-user ref="selectRef" :role-id="queryParams.roleId" @ok="handleQuery" />
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="AuthUser" lang="ts">
|
||||||
|
import { allocatedUserList, authUserCancel, authUserCancelAll } from '@/api/system/role';
|
||||||
|
import { UserQuery } from '@/api/system/user/types';
|
||||||
|
import { UserVO } from '@/api/system/user/types';
|
||||||
|
import SelectUser from './selectUser.vue';
|
||||||
|
import { RouteLocationNormalized } from 'vue-router';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
||||||
|
|
||||||
|
const userList = ref<UserVO[]>([]);
|
||||||
|
const loading = ref(true);
|
||||||
|
const showSearch = ref(true);
|
||||||
|
const multiple = ref(true);
|
||||||
|
const total = ref(0);
|
||||||
|
const userIds = ref<Array<string | number>>([]);
|
||||||
|
|
||||||
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
const selectRef = ref<InstanceType<typeof SelectUser>>();
|
||||||
|
|
||||||
|
const queryParams = reactive<UserQuery>({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
roleId: route.params.roleId as string,
|
||||||
|
userName: undefined,
|
||||||
|
phonenumber: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 查询授权用户列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await allocatedUserList(queryParams);
|
||||||
|
userList.value = res.rows;
|
||||||
|
total.value = res.total;
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
// 返回按钮
|
||||||
|
const handleClose = () => {
|
||||||
|
const obj: RouteLocationNormalized = {
|
||||||
|
path: '/system/role',
|
||||||
|
fullPath: '',
|
||||||
|
hash: '',
|
||||||
|
matched: [],
|
||||||
|
meta: undefined,
|
||||||
|
name: undefined,
|
||||||
|
params: undefined,
|
||||||
|
query: undefined,
|
||||||
|
redirectedFrom: undefined
|
||||||
|
};
|
||||||
|
proxy?.$tab.closeOpenPage(obj);
|
||||||
|
};
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNum = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields();
|
||||||
|
handleQuery();
|
||||||
|
};
|
||||||
|
// 多选框选中数据
|
||||||
|
const handleSelectionChange = (selection: UserVO[]) => {
|
||||||
|
userIds.value = selection.map((item) => item.userId);
|
||||||
|
multiple.value = !selection.length;
|
||||||
|
};
|
||||||
|
/** 打开授权用户表弹窗 */
|
||||||
|
const openSelectUser = () => {
|
||||||
|
selectRef.value?.show();
|
||||||
|
};
|
||||||
|
/** 取消授权按钮操作 */
|
||||||
|
const cancelAuthUser = async (row: UserVO) => {
|
||||||
|
await proxy?.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?');
|
||||||
|
await authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
|
||||||
|
await getList();
|
||||||
|
proxy?.$modal.msgSuccess('取消授权成功');
|
||||||
|
};
|
||||||
|
/** 批量取消授权按钮操作 */
|
||||||
|
const cancelAuthUserAll = async () => {
|
||||||
|
const roleId = queryParams.roleId;
|
||||||
|
const uIds = userIds.value.join(',');
|
||||||
|
await proxy?.$modal.confirm('是否取消选中用户授权数据项?');
|
||||||
|
await authUserCancelAll({ roleId: roleId, userIds: uIds });
|
||||||
|
await getList();
|
||||||
|
proxy?.$modal.msgSuccess('取消授权成功');
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
574
src/views/system/appRole/index.vue
Normal file
574
src/views/system/appRole/index.vue
Normal file
@ -0,0 +1,574 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2">
|
||||||
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
|
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="权限字符" prop="roleKey">
|
||||||
|
<el-input v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态" prop="status">
|
||||||
|
<el-select v-model="queryParams.status" placeholder="角色状态" clearable>
|
||||||
|
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['system:role:query']">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<!-- 部门树 -->
|
||||||
|
<el-col :lg="4" :xs="24" style="">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
||||||
|
<el-tree
|
||||||
|
ref="deptTreeRef"
|
||||||
|
class="mt-2"
|
||||||
|
node-key="id"
|
||||||
|
:data="deptOptions"
|
||||||
|
:props="{ label: 'label', children: 'children' }"
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
highlight-current
|
||||||
|
default-expand-all
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :lg="20" :xs="24">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<template #header>
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()"
|
||||||
|
>修改</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
|
||||||
|
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
||||||
|
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
|
||||||
|
<el-table-column label="显示顺序" prop="roleSort" width="100" />
|
||||||
|
<el-table-column label="状态" align="center" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createTime">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column fixed="right" label="操作" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip v-if="scope.row.roleId !== 1" content="修改" placement="top">
|
||||||
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip v-if="scope.row.roleId !== 1" content="删除" placement="top">
|
||||||
|
<el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip v-if="scope.row.roleId !== 1" content="数据权限" placement="top">
|
||||||
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip v-if="scope.row.roleId !== 1" content="分配用户" placement="top">
|
||||||
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="User" @click="handleAuthUser(scope.row)"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination
|
||||||
|
v-if="total > 0"
|
||||||
|
v-model:total="total"
|
||||||
|
v-model:page="queryParams.pageNum"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
|
<el-form ref="roleFormRef" :model="form" :rules="rules" label-width="110px">
|
||||||
|
<el-form-item label="所属部门" prop="deptId">
|
||||||
|
<el-cascader
|
||||||
|
:options="deptOptions"
|
||||||
|
v-model="form.deptId"
|
||||||
|
placeholder="请选择所属部门"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
:show-all-levels="false"
|
||||||
|
:props="{ value: 'id', emitPath: false, checkStrictly: true }"
|
||||||
|
>
|
||||||
|
</el-cascader>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
|
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="roleKey">
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="控制器中定义的权限字符,如:@SaCheckRole('admin')" placement="top">
|
||||||
|
<el-icon><question-filled /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
权限字符
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<el-input v-model="form.roleKey" placeholder="请输入权限字符" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="角色顺序" prop="roleSort">
|
||||||
|
<el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-radio-group v-model="form.status">
|
||||||
|
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="菜单权限">
|
||||||
|
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand(Boolean($event), 'menu')">展开/折叠</el-checkbox>
|
||||||
|
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
|
||||||
|
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
|
||||||
|
<el-tree
|
||||||
|
ref="menuRef"
|
||||||
|
class="tree-border"
|
||||||
|
:data="menuOptions"
|
||||||
|
show-checkbox
|
||||||
|
node-key="id"
|
||||||
|
:check-strictly="!form.menuCheckStrictly"
|
||||||
|
empty-text="加载中,请稍候"
|
||||||
|
:props="{ label: 'label', children: 'children' }"
|
||||||
|
></el-tree>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="是否为特殊角色">
|
||||||
|
<el-switch v-model="form.isSpecial" active-value="1" inactive-value="0" active-text="是" inactive-text="否"> </el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注">
|
||||||
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 分配角色数据权限对话框 -->
|
||||||
|
<el-dialog v-model="openDataScope" :title="dialog.title" width="500px" append-to-body>
|
||||||
|
<el-form ref="dataScopeRef" :model="form" label-width="80px">
|
||||||
|
<el-form-item label="角色名称">
|
||||||
|
<el-input v-model="form.roleName" :disabled="true" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="权限字符">
|
||||||
|
<el-input v-model="form.roleKey" :disabled="true" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="权限范围">
|
||||||
|
<el-select v-model="form.dataScope" @change="dataScopeSelectChange">
|
||||||
|
<el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-show="form.dataScope === '2'" label="数据权限">
|
||||||
|
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand(Boolean($event), 'dept')">展开/折叠</el-checkbox>
|
||||||
|
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
|
||||||
|
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
|
||||||
|
<el-tree
|
||||||
|
ref="deptRef"
|
||||||
|
class="tree-border"
|
||||||
|
:data="deptOptions"
|
||||||
|
show-checkbox
|
||||||
|
default-expand-all
|
||||||
|
node-key="id"
|
||||||
|
:check-strictly="!form.deptCheckStrictly"
|
||||||
|
empty-text="加载中,请稍候"
|
||||||
|
:props="{ label: 'label', children: 'children' }"
|
||||||
|
></el-tree>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitDataScope">确 定</el-button>
|
||||||
|
<el-button @click="cancelDataScope">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="Role" lang="ts">
|
||||||
|
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from '@/api/system/role';
|
||||||
|
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
|
||||||
|
import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
|
||||||
|
import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
|
||||||
|
import api, { uploadCertList } from '@/api/system/user';
|
||||||
|
import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
||||||
|
|
||||||
|
const roleList = ref<RoleVO[]>();
|
||||||
|
const loading = ref(true);
|
||||||
|
const showSearch = ref(true);
|
||||||
|
const ids = ref<Array<string | number>>([]);
|
||||||
|
const single = ref(true);
|
||||||
|
const multiple = ref(true);
|
||||||
|
const total = ref(0);
|
||||||
|
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||||
|
const menuOptions = ref<MenuTreeOption[]>([]);
|
||||||
|
const menuExpand = ref(false);
|
||||||
|
const menuNodeAll = ref(false);
|
||||||
|
const deptExpand = ref(true);
|
||||||
|
const deptNodeAll = ref(false);
|
||||||
|
const deptOptions = ref<DeptTreeVO[]>([]);
|
||||||
|
const enabledDeptOptions = ref<DeptTreeVO[]>([]);
|
||||||
|
|
||||||
|
const openDataScope = ref(false);
|
||||||
|
const deptName = ref('');
|
||||||
|
|
||||||
|
/** 数据范围选项*/
|
||||||
|
const dataScopeOptions = ref([
|
||||||
|
{ value: '1', label: '全部数据权限' },
|
||||||
|
{ value: '2', label: '自定数据权限' },
|
||||||
|
{ value: '3', label: '本部门数据权限' },
|
||||||
|
{ value: '4', label: '本部门及以下数据权限' },
|
||||||
|
{ value: '5', label: '仅本人数据权限' },
|
||||||
|
{ value: '6', label: '部门及以下或本人数据权限' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
const roleFormRef = ref<ElFormInstance>();
|
||||||
|
const dataScopeRef = ref<ElFormInstance>();
|
||||||
|
const menuRef = ref<ElTreeInstance>();
|
||||||
|
const deptRef = ref<ElTreeInstance>();
|
||||||
|
const deptTreeRef = ref<ElTreeInstance>();
|
||||||
|
|
||||||
|
const initForm = {
|
||||||
|
roleId: undefined,
|
||||||
|
roleSort: 1,
|
||||||
|
status: '0',
|
||||||
|
roleName: '',
|
||||||
|
roleKey: '',
|
||||||
|
menuCheckStrictly: true,
|
||||||
|
deptCheckStrictly: true,
|
||||||
|
remark: '',
|
||||||
|
dataScope: '1',
|
||||||
|
menuIds: [],
|
||||||
|
deptId: '',
|
||||||
|
isSpecial: null,
|
||||||
|
deptIds: [],
|
||||||
|
roleSource: '2'
|
||||||
|
};
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
form: { ...initForm },
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
roleName: '',
|
||||||
|
roleKey: '',
|
||||||
|
deptId: '',
|
||||||
|
status: '',
|
||||||
|
roleSource: '2'
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
roleName: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
|
||||||
|
roleKey: [{ required: true, message: '权限字符不能为空', trigger: 'blur' }],
|
||||||
|
roleSort: [{ required: true, message: '角色顺序不能为空', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const { form, queryParams, rules } = toRefs(data);
|
||||||
|
|
||||||
|
const dialog = reactive<DialogOption>({
|
||||||
|
visible: false,
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 通过条件过滤节点 */
|
||||||
|
const filterNode = (value: string, data: any) => {
|
||||||
|
if (!value) return true;
|
||||||
|
return data.label.indexOf(value) !== -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 节点单击事件 */
|
||||||
|
const handleNodeClick = (data: DeptVO) => {
|
||||||
|
queryParams.value.deptId = data.id as string;
|
||||||
|
handleQuery();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询角色列表
|
||||||
|
*/
|
||||||
|
const getList = () => {
|
||||||
|
loading.value = true;
|
||||||
|
listRole(proxy?.addDateRange(queryParams.value, dateRange.value)).then((res) => {
|
||||||
|
roleList.value = res.rows;
|
||||||
|
total.value = res.total;
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索按钮操作
|
||||||
|
*/
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 重置 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
dateRange.value = ['', ''];
|
||||||
|
queryFormRef.value?.resetFields();
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
queryParams.value.deptId = undefined;
|
||||||
|
deptTreeRef.value?.setCurrentKey(undefined);
|
||||||
|
handleQuery();
|
||||||
|
};
|
||||||
|
/**删除按钮操作 */
|
||||||
|
const handleDelete = async (row?: RoleVO) => {
|
||||||
|
const roleids = row?.roleId || ids.value;
|
||||||
|
await proxy?.$modal.confirm('是否确认删除角色编号为' + roleids + '数据项目');
|
||||||
|
await delRole(roleids);
|
||||||
|
getList();
|
||||||
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = () => {
|
||||||
|
proxy?.download(
|
||||||
|
'system/role/export',
|
||||||
|
{
|
||||||
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`role_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/** 多选框选中数据 */
|
||||||
|
const handleSelectionChange = (selection: RoleVO[]) => {
|
||||||
|
ids.value = selection.map((item: RoleVO) => item.roleId);
|
||||||
|
single.value = selection.length != 1;
|
||||||
|
multiple.value = !selection.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 角色状态修改 */
|
||||||
|
const handleStatusChange = async (row: RoleVO) => {
|
||||||
|
let text = row.status === '0' ? '启用' : '停用';
|
||||||
|
try {
|
||||||
|
await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
|
||||||
|
await changeRoleStatus(row.roleId, row.status);
|
||||||
|
proxy?.$modal.msgSuccess(text + '成功');
|
||||||
|
} catch {
|
||||||
|
row.status = row.status === '0' ? '1' : '0';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 分配用户 */
|
||||||
|
const handleAuthUser = (row: RoleVO) => {
|
||||||
|
router.push('/system/role-auth/user/' + row.roleId);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 查询菜单树结构 */
|
||||||
|
const getMenuTreeselect = async () => {
|
||||||
|
const res = await menuTreeselect({ menuSource: '2' });
|
||||||
|
menuOptions.value = res.data;
|
||||||
|
};
|
||||||
|
/** 所有部门节点数据 */
|
||||||
|
const getDeptAllCheckedKeys = (): any => {
|
||||||
|
// 目前被选中的部门节点
|
||||||
|
let checkedKeys = deptRef.value?.getCheckedKeys();
|
||||||
|
// 半选中的部门节点
|
||||||
|
let halfCheckedKeys = deptRef.value?.getHalfCheckedKeys();
|
||||||
|
if (halfCheckedKeys) {
|
||||||
|
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||||
|
}
|
||||||
|
return checkedKeys;
|
||||||
|
};
|
||||||
|
/** 重置新增的表单以及其他数据 */
|
||||||
|
const reset = () => {
|
||||||
|
menuRef.value?.setCheckedKeys([]);
|
||||||
|
menuExpand.value = false;
|
||||||
|
menuNodeAll.value = false;
|
||||||
|
deptExpand.value = true;
|
||||||
|
deptNodeAll.value = false;
|
||||||
|
form.value = { ...initForm };
|
||||||
|
roleFormRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 添加角色 */
|
||||||
|
const handleAdd = () => {
|
||||||
|
reset();
|
||||||
|
getMenuTreeselect();
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '添加角色';
|
||||||
|
};
|
||||||
|
/** 修改角色 */
|
||||||
|
const handleUpdate = async (row?: RoleVO) => {
|
||||||
|
reset();
|
||||||
|
const roleId = row?.roleId || ids.value[0];
|
||||||
|
const { data } = await getRole(roleId);
|
||||||
|
Object.assign(form.value, data);
|
||||||
|
form.value.roleSort = Number(form.value.roleSort);
|
||||||
|
const res = await getRoleMenuTreeselect(roleId);
|
||||||
|
dialog.title = '修改角色';
|
||||||
|
dialog.visible = true;
|
||||||
|
res.checkedKeys.forEach((v) => {
|
||||||
|
nextTick(() => {
|
||||||
|
menuRef.value?.setChecked(v, true, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 根据角色ID查询菜单树结构 */
|
||||||
|
const getRoleMenuTreeselect = (roleId: string | number) => {
|
||||||
|
return roleMenuTreeselect(roleId, { menuSource: '2' }).then((res): RoleMenuTree => {
|
||||||
|
menuOptions.value = res.data.menus;
|
||||||
|
return res.data;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 根据角色ID查询部门树结构 */
|
||||||
|
const getRoleDeptTreeSelect = async (roleId: string | number) => {
|
||||||
|
const res = await deptTreeSelect(roleId, { roleSource: '2' });
|
||||||
|
deptOptions.value = res.data.depts;
|
||||||
|
return res.data;
|
||||||
|
};
|
||||||
|
/** 树权限(展开/折叠)*/
|
||||||
|
const handleCheckedTreeExpand = (value: boolean, type: string) => {
|
||||||
|
if (type == 'menu') {
|
||||||
|
let treeList = menuOptions.value;
|
||||||
|
for (let i = 0; i < treeList.length; i++) {
|
||||||
|
if (menuRef.value) {
|
||||||
|
menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type == 'dept') {
|
||||||
|
let treeList = deptOptions.value;
|
||||||
|
for (let i = 0; i < treeList.length; i++) {
|
||||||
|
if (deptRef.value) {
|
||||||
|
deptRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/** 树权限(全选/全不选) */
|
||||||
|
const handleCheckedTreeNodeAll = (value: any, type: string) => {
|
||||||
|
if (type == 'menu') {
|
||||||
|
menuRef.value?.setCheckedNodes(value ? (menuOptions.value as any) : []);
|
||||||
|
} else if (type == 'dept') {
|
||||||
|
deptRef.value?.setCheckedNodes(value ? (deptOptions.value as any) : []);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/** 树权限(父子联动) */
|
||||||
|
const handleCheckedTreeConnect = (value: any, type: string) => {
|
||||||
|
if (type == 'menu') {
|
||||||
|
form.value.menuCheckStrictly = value;
|
||||||
|
} else if (type == 'dept') {
|
||||||
|
form.value.deptCheckStrictly = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/** 所有菜单节点数据 */
|
||||||
|
const getMenuAllCheckedKeys = (): any => {
|
||||||
|
// 目前被选中的菜单节点
|
||||||
|
let checkedKeys = menuRef.value?.getCheckedKeys();
|
||||||
|
// 半选中的菜单节点
|
||||||
|
let halfCheckedKeys = menuRef.value?.getHalfCheckedKeys();
|
||||||
|
if (halfCheckedKeys) {
|
||||||
|
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||||
|
}
|
||||||
|
return checkedKeys;
|
||||||
|
};
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = () => {
|
||||||
|
roleFormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
form.value.menuIds = getMenuAllCheckedKeys();
|
||||||
|
form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
dialog.visible = false;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
reset();
|
||||||
|
dialog.visible = false;
|
||||||
|
};
|
||||||
|
/** 选择角色权限范围触发 */
|
||||||
|
const dataScopeSelectChange = (value: string) => {
|
||||||
|
if (value !== '2') {
|
||||||
|
deptRef.value?.setCheckedKeys([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/** 分配数据权限操作 */
|
||||||
|
const handleDataScope = async (row: RoleVO) => {
|
||||||
|
const response = await getRole(row.roleId);
|
||||||
|
Object.assign(form.value, response.data);
|
||||||
|
const res = await getRoleDeptTreeSelect(row.roleId);
|
||||||
|
openDataScope.value = true;
|
||||||
|
dialog.title = '分配数据权限';
|
||||||
|
await nextTick(() => {
|
||||||
|
deptRef.value?.setCheckedKeys(res.checkedKeys);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 提交按钮(数据权限) */
|
||||||
|
const submitDataScope = async () => {
|
||||||
|
if (form.value.roleId) {
|
||||||
|
form.value.deptIds = getDeptAllCheckedKeys();
|
||||||
|
await dataScope(form.value);
|
||||||
|
proxy?.$modal.msgSuccess('修改成功');
|
||||||
|
openDataScope.value = false;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/** 取消按钮(数据权限)*/
|
||||||
|
const cancelDataScope = () => {
|
||||||
|
dataScopeRef.value?.resetFields();
|
||||||
|
form.value = { ...initForm };
|
||||||
|
openDataScope.value = false;
|
||||||
|
};
|
||||||
|
/** 查询部门下拉树结构 */
|
||||||
|
const getDeptTree = async () => {
|
||||||
|
const res = await api.deptTreeSelect({ isShow: '1' });
|
||||||
|
deptOptions.value = res.data;
|
||||||
|
enabledDeptOptions.value = filterDisabledDept(res.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 过滤禁用的部门 */
|
||||||
|
const filterDisabledDept = (deptList: DeptTreeVO[]) => {
|
||||||
|
return deptList.filter((dept) => {
|
||||||
|
if (dept.disabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (dept.children && dept.children.length) {
|
||||||
|
dept.children = filterDisabledDept(dept.children);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getDeptTree(); // 初始化部门数据
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
</script>
|
132
src/views/system/appRole/selectUser.vue
Normal file
132
src/views/system/appRole/selectUser.vue
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<template>
|
||||||
|
<el-row>
|
||||||
|
<el-dialog v-model="visible" title="选择用户" width="800px" top="5vh" append-to-body>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
|
<el-form-item label="用户名称" prop="userName">
|
||||||
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号码" prop="phonenumber">
|
||||||
|
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-row>
|
||||||
|
<el-table ref="tableRef" :data="userList" height="260px" @row-click="clickRow" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55"></el-table-column>
|
||||||
|
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="状态" align="center" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination v-if="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
|
</el-row>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="handleSelectUser">确 定</el-button>
|
||||||
|
<el-button @click="visible = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="SelectUser" lang="ts">
|
||||||
|
import { authUserSelectAll, unallocatedUserList } from '@/api/system/role';
|
||||||
|
import { UserVO } from '@/api/system/user/types';
|
||||||
|
import { UserQuery } from '@/api/system/user/types';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
roleId: {
|
||||||
|
type: [Number, String],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
||||||
|
|
||||||
|
const userList = ref<UserVO[]>([]);
|
||||||
|
const visible = ref(false);
|
||||||
|
const total = ref(0);
|
||||||
|
const userIds = ref<Array<string | number>>([]);
|
||||||
|
|
||||||
|
const queryParams = reactive<UserQuery>({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
roleId: undefined,
|
||||||
|
userName: undefined,
|
||||||
|
phonenumber: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableRef = ref<ElTableInstance>();
|
||||||
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
|
const show = () => {
|
||||||
|
queryParams.roleId = props.roleId;
|
||||||
|
getList();
|
||||||
|
visible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择行
|
||||||
|
*/
|
||||||
|
const clickRow = (row: any) => {
|
||||||
|
// ele的bug
|
||||||
|
tableRef.value?.toggleRowSelection(row, false);
|
||||||
|
};
|
||||||
|
/** 多选框选中数据 */
|
||||||
|
const handleSelectionChange = (selection: UserVO[]) => {
|
||||||
|
userIds.value = selection.map((item: UserVO) => item.userId);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 查询数据 */
|
||||||
|
const getList = async () => {
|
||||||
|
const res = await unallocatedUserList(queryParams);
|
||||||
|
userList.value = res.rows;
|
||||||
|
total.value = res.total;
|
||||||
|
};
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNum = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields();
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const emit = defineEmits(['ok']);
|
||||||
|
/**选择授权用户操作 */
|
||||||
|
const handleSelectUser = async () => {
|
||||||
|
const roleId = queryParams.roleId;
|
||||||
|
const ids = userIds.value.join(',');
|
||||||
|
if (ids == '') {
|
||||||
|
proxy?.$modal.msgError('请选择要分配的用户');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await authUserSelectAll({ roleId, userIds: ids });
|
||||||
|
proxy?.$modal.msgSuccess('分配成功');
|
||||||
|
emit('ok');
|
||||||
|
visible.value = false;
|
||||||
|
};
|
||||||
|
// 暴露
|
||||||
|
defineExpose({
|
||||||
|
show
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
@ -34,6 +34,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- 关键修改:开启lazy模式,使用本地数据筛选子节点 -->
|
||||||
<el-table
|
<el-table
|
||||||
ref="menuTableRef"
|
ref="menuTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
@ -41,6 +42,9 @@
|
|||||||
row-key="menuId"
|
row-key="menuId"
|
||||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
:default-expand-all="isExpandAll"
|
:default-expand-all="isExpandAll"
|
||||||
|
lazy
|
||||||
|
:load="loadChildren"
|
||||||
|
:has-children="hasChildren"
|
||||||
>
|
>
|
||||||
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
||||||
<el-table-column prop="icon" label="图标" align="center" width="100">
|
<el-table-column prop="icon" label="图标" align="center" width="100">
|
||||||
@ -77,7 +81,7 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-bod width="750px">
|
<el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-body width="750px">
|
||||||
<el-form ref="menuFormRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="menuFormRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
@ -103,7 +107,6 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col v-if="form.menuType !== 'F'" :span="24">
|
<el-col v-if="form.menuType !== 'F'" :span="24">
|
||||||
<el-form-item label="菜单图标" prop="icon">
|
<el-form-item label="菜单图标" prop="icon">
|
||||||
<!-- 图标选择器 -->
|
|
||||||
<icon-select v-model="form.icon" />
|
<icon-select v-model="form.icon" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -122,10 +125,9 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
|
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
|
||||||
<el-icon>
|
<el-icon><question-filled /></el-icon>
|
||||||
<question-filled />
|
</el-tooltip>
|
||||||
</el-icon> </el-tooltip
|
是否外链
|
||||||
>是否外链
|
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<el-radio-group v-model="form.isFrame">
|
<el-radio-group v-model="form.isFrame">
|
||||||
@ -139,9 +141,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
|
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
|
||||||
<el-icon>
|
<el-icon><question-filled /></el-icon>
|
||||||
<question-filled />
|
|
||||||
</el-icon>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
路由地址
|
路由地址
|
||||||
</span>
|
</span>
|
||||||
@ -154,9 +154,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
|
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
|
||||||
<el-icon>
|
<el-icon><question-filled /></el-icon>
|
||||||
<question-filled />
|
|
||||||
</el-icon>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
组件路径
|
组件路径
|
||||||
</span>
|
</span>
|
||||||
@ -170,9 +168,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
<el-tooltip content="控制器中定义的权限字符,如:@SaCheckPermission('system:user:list')" placement="top">
|
<el-tooltip content="控制器中定义的权限字符,如:@SaCheckPermission('system:user:list')" placement="top">
|
||||||
<el-icon>
|
<el-icon><question-filled /></el-icon>
|
||||||
<question-filled />
|
|
||||||
</el-icon>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
权限字符
|
权限字符
|
||||||
</span>
|
</span>
|
||||||
@ -185,9 +181,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
|
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
|
||||||
<el-icon>
|
<el-icon><question-filled /></el-icon>
|
||||||
<question-filled />
|
|
||||||
</el-icon>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
路由参数
|
路由参数
|
||||||
</span>
|
</span>
|
||||||
@ -199,9 +193,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
|
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
|
||||||
<el-icon>
|
<el-icon><question-filled /></el-icon>
|
||||||
<question-filled />
|
|
||||||
</el-icon>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
是否缓存
|
是否缓存
|
||||||
</span>
|
</span>
|
||||||
@ -217,9 +209,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
|
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
|
||||||
<el-icon>
|
<el-icon><question-filled /></el-icon>
|
||||||
<question-filled />
|
|
||||||
</el-icon>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
显示状态
|
显示状态
|
||||||
</span>
|
</span>
|
||||||
@ -234,9 +224,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
|
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
|
||||||
<el-icon>
|
<el-icon><question-filled /></el-icon>
|
||||||
<question-filled />
|
|
||||||
</el-icon>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
菜单状态
|
菜单状态
|
||||||
</span>
|
</span>
|
||||||
@ -264,6 +252,20 @@
|
|||||||
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from '@/api/system/menu';
|
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from '@/api/system/menu';
|
||||||
import { MenuForm, MenuQuery, MenuVO } from '@/api/system/menu/types';
|
import { MenuForm, MenuQuery, MenuVO } from '@/api/system/menu/types';
|
||||||
import { MenuTypeEnum } from '@/enums/MenuTypeEnum';
|
import { MenuTypeEnum } from '@/enums/MenuTypeEnum';
|
||||||
|
import { ElFormInstance, ElTableInstance } from 'element-plus';
|
||||||
|
import { ComponentInternalInstance, getCurrentInstance, onMounted, ref, reactive, toRefs } from 'vue';
|
||||||
|
|
||||||
|
// 类型定义
|
||||||
|
interface DialogOption {
|
||||||
|
visible: boolean;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PageData<T, U> {
|
||||||
|
form: T;
|
||||||
|
queryParams: U;
|
||||||
|
rules: Record<string, any[]>;
|
||||||
|
}
|
||||||
|
|
||||||
interface MenuOptionsType {
|
interface MenuOptionsType {
|
||||||
menuId: number;
|
menuId: number;
|
||||||
@ -271,20 +273,29 @@ interface MenuOptionsType {
|
|||||||
children: MenuOptionsType[] | undefined;
|
children: MenuOptionsType[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 全局变量
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_show_hide', 'sys_normal_disable'));
|
const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_show_hide', 'sys_normal_disable'));
|
||||||
|
|
||||||
|
// 1. 存储完整数据的数组(一次性获取后本地保存)
|
||||||
|
const fullMenuList = ref<MenuVO[]>([]);
|
||||||
|
// 2. 子节点缓存(优化查询性能)
|
||||||
|
const childrenCache = ref<Record<number, MenuVO[]>>({});
|
||||||
|
|
||||||
|
// 页面状态
|
||||||
const menuList = ref<MenuVO[]>([]);
|
const menuList = ref<MenuVO[]>([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const showSearch = ref(true);
|
const showSearch = ref(true);
|
||||||
const menuOptions = ref<MenuOptionsType[]>([]);
|
const menuOptions = ref<MenuOptionsType[]>([]);
|
||||||
const isExpandAll = ref(false);
|
const isExpandAll = ref(false);
|
||||||
|
|
||||||
|
// 弹窗状态
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 表单相关
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const menuFormRef = ref<ElFormInstance>();
|
const menuFormRef = ref<ElFormInstance>();
|
||||||
const initFormData = {
|
const initFormData = {
|
||||||
@ -298,35 +309,114 @@ const initFormData = {
|
|||||||
isFrame: '1',
|
isFrame: '1',
|
||||||
isCache: '0',
|
isCache: '0',
|
||||||
visible: '0',
|
visible: '0',
|
||||||
status: '0'
|
status: '0',
|
||||||
|
menuSource: 1
|
||||||
};
|
};
|
||||||
const data = reactive<PageData<MenuForm, MenuQuery>>({
|
const data = reactive({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
menuName: undefined,
|
menuName: undefined,
|
||||||
status: undefined
|
status: undefined,
|
||||||
|
menuSource: 1
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
menuName: [{ required: true, message: '菜单名称不能为空', trigger: 'blur' }],
|
menuName: [{ required: true, message: '菜单名称不能为空', trigger: 'blur' }],
|
||||||
orderNum: [{ required: true, message: '菜单顺序不能为空', trigger: 'blur' }],
|
orderNum: [{ required: true, message: '菜单顺序不能为空', trigger: 'blur' }],
|
||||||
path: [{ required: true, message: '路由地址不能为空', trigger: 'blur' }]
|
path: [
|
||||||
|
{
|
||||||
|
required: (() => data.form.menuType !== 'F') as any,
|
||||||
|
message: '路由地址不能为空',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const menuTableRef = ref<ElTableInstance>();
|
const menuTableRef = ref<ElTableInstance>();
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data);
|
const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data);
|
||||||
/** 查询菜单列表 */
|
|
||||||
|
/**
|
||||||
|
* 初始化加载:一次性获取所有数据并处理
|
||||||
|
* 仅在表格展示根节点,子节点通过懒加载从本地数据中筛选
|
||||||
|
*/
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
// 1. 一次性获取所有数据
|
||||||
const res = await listMenu(queryParams.value);
|
const res = await listMenu(queryParams.value);
|
||||||
const data = proxy?.handleTree<MenuVO>(res.data, 'menuId');
|
fullMenuList.value = res.data || [];
|
||||||
if (data) {
|
|
||||||
menuList.value = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 2. 构建缓存(提前计算所有节点的子节点)
|
||||||
|
buildChildrenCache();
|
||||||
|
console.log(11111);
|
||||||
|
|
||||||
|
// 3. 只展示根节点(parentId=0)
|
||||||
|
menuList.value = filterChildren(0);
|
||||||
|
} catch (err) {
|
||||||
|
proxy?.$modal.msgError('加载菜单失败');
|
||||||
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建子节点缓存
|
||||||
|
* 一次性处理所有数据,建立父ID到子节点列表的映射
|
||||||
|
*/
|
||||||
|
const buildChildrenCache = () => {
|
||||||
|
const cache: Record<number, MenuVO[]> = {};
|
||||||
|
|
||||||
|
// 初始化所有可能的父ID
|
||||||
|
fullMenuList.value.forEach((item) => {
|
||||||
|
if (!cache[item.parentId!]) {
|
||||||
|
cache[item.parentId!] = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 为每个父ID添加子节点
|
||||||
|
fullMenuList.value.forEach((item) => {
|
||||||
|
if (cache[item.parentId!]) {
|
||||||
|
// 标记节点是否有子节点(用于显示展开图标)
|
||||||
|
const hasChildren = fullMenuList.value.some((child) => child.parentId == item.menuId);
|
||||||
|
cache[item.parentId!].push({ ...item, hasChildren });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 按排序号排序子节点
|
||||||
|
// Object.keys(cache).forEach((parentId) => {
|
||||||
|
// cache[Number(parentId)].sort((a, b) => (a.orderNum || 0) - (b.orderNum || 0));
|
||||||
|
// });
|
||||||
|
|
||||||
|
childrenCache.value = cache;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从缓存中筛选指定父节点的子节点
|
||||||
|
* @param parentId 父节点ID
|
||||||
|
* @returns 子节点列表
|
||||||
|
*/
|
||||||
|
const filterChildren = (parentId: number): MenuVO[] => {
|
||||||
|
return childrenCache.value[parentId] || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 懒加载子节点实现
|
||||||
|
* 从本地缓存中获取子节点,不发起额外请求
|
||||||
|
*/
|
||||||
|
const loadChildren = async (row, treeNode: any, resolve: (data: MenuVO[]) => void) => {
|
||||||
|
const parentId = row.menuId;
|
||||||
|
console.log(childrenCache.value);
|
||||||
|
// 从缓存获取子节点并返回
|
||||||
|
resolve(filterChildren(parentId));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断节点是否有子节点
|
||||||
|
* @param row 节点数据
|
||||||
|
* @returns 是否有子节点
|
||||||
|
*/
|
||||||
|
const hasChildren = (row: MenuVO) => {
|
||||||
|
return row.hasChildren || false;
|
||||||
|
};
|
||||||
|
|
||||||
/** 查询菜单下拉树结构 */
|
/** 查询菜单下拉树结构 */
|
||||||
const getTreeselect = async () => {
|
const getTreeselect = async () => {
|
||||||
menuOptions.value = [];
|
menuOptions.value = [];
|
||||||
@ -335,11 +425,13 @@ const getTreeselect = async () => {
|
|||||||
menu.children = proxy?.handleTree<MenuOptionsType>(response.data, 'menuId');
|
menu.children = proxy?.handleTree<MenuOptionsType>(response.data, 'menuId');
|
||||||
menuOptions.value.push(menu);
|
menuOptions.value.push(menu);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
@ -350,11 +442,13 @@ const reset = () => {
|
|||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
getList();
|
getList();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = (row?: MenuVO) => {
|
const handleAdd = (row?: MenuVO) => {
|
||||||
reset();
|
reset();
|
||||||
@ -363,18 +457,24 @@ const handleAdd = (row?: MenuVO) => {
|
|||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '添加菜单';
|
dialog.title = '添加菜单';
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 展开/折叠操作 */
|
/** 展开/折叠操作 */
|
||||||
const handleToggleExpandAll = () => {
|
const handleToggleExpandAll = () => {
|
||||||
isExpandAll.value = !isExpandAll.value;
|
isExpandAll.value = !isExpandAll.value;
|
||||||
toggleExpandAll(menuList.value, isExpandAll.value);
|
toggleExpandAll(menuList.value, isExpandAll.value);
|
||||||
};
|
};
|
||||||
/** 展开/折叠所有 */
|
|
||||||
|
/** 展开/折叠所有节点 */
|
||||||
const toggleExpandAll = (data: MenuVO[], status: boolean) => {
|
const toggleExpandAll = (data: MenuVO[], status: boolean) => {
|
||||||
data.forEach((item: MenuVO) => {
|
data.forEach((item: MenuVO) => {
|
||||||
menuTableRef.value?.toggleRowExpansion(item, status);
|
menuTableRef.value?.toggleRowExpansion(item, status);
|
||||||
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
|
// 如果有子节点,递归处理
|
||||||
|
if (item.hasChildren) {
|
||||||
|
toggleExpandAll(filterChildren(item.menuId!), status);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row: MenuVO) => {
|
const handleUpdate = async (row: MenuVO) => {
|
||||||
reset();
|
reset();
|
||||||
@ -386,25 +486,38 @@ const handleUpdate = async (row: MenuVO) => {
|
|||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '修改菜单';
|
dialog.title = '修改菜单';
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
menuFormRef.value?.validate(async (valid: boolean) => {
|
menuFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
|
// 保存数据到后端
|
||||||
|
if (form.value.menuId) {
|
||||||
|
await updateMenu(form.value);
|
||||||
|
} else {
|
||||||
|
await addMenu(form.value);
|
||||||
|
}
|
||||||
|
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
|
|
||||||
|
// 重新加载所有数据并重建缓存
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row: MenuVO) => {
|
const handleDelete = async (row: MenuVO) => {
|
||||||
await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
|
await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
|
||||||
await delMenu(row.menuId);
|
await delMenu(row.menuId);
|
||||||
|
|
||||||
|
// 重新加载所有数据并重建缓存
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 初始化加载所有数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
:leave-active-class="proxy?.animate.searchAnimate.leave">
|
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
@ -13,19 +12,11 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态" prop="status">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-select v-model="queryParams.status" placeholder="角色状态" clearable>
|
<el-select v-model="queryParams.status" placeholder="角色状态" clearable>
|
||||||
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label"
|
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
:value="dict.value" />
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建时间" style="width: 308px">
|
|
||||||
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
|
|
||||||
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
|
|
||||||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"></el-date-picker>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery"
|
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['system:role:query']">搜索</el-button>
|
||||||
v-hasPermi="['system:role:query']">搜索</el-button>
|
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@ -37,9 +28,18 @@
|
|||||||
<el-col :lg="4" :xs="24" style="">
|
<el-col :lg="4" :xs="24" style="">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
||||||
<el-tree ref="deptTreeRef" class="mt-2" node-key="id" :data="deptOptions"
|
<el-tree
|
||||||
:props="{ label: 'label', children: 'children' }" :expand-on-click-node="false"
|
ref="deptTreeRef"
|
||||||
:filter-node-method="filterNode" highlight-current default-expand-all @node-click="handleNodeClick" />
|
class="mt-2"
|
||||||
|
node-key="id"
|
||||||
|
:data="deptOptions"
|
||||||
|
:props="{ label: 'label', children: 'children' }"
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
highlight-current
|
||||||
|
default-expand-all
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="20" :xs="24">
|
<el-col :lg="20" :xs="24">
|
||||||
@ -47,25 +47,21 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="10">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus"
|
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
@click="handleAdd()">新增</el-button>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit"
|
<el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()"
|
||||||
@click="handleUpdate()">修改</el-button>
|
>修改</el-button
|
||||||
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0"
|
<el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()"
|
||||||
@click="handleDelete()">删除</el-button>
|
>删除</el-button
|
||||||
</el-col>
|
>
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download"
|
|
||||||
@click="handleExport">导出</el-button>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
<el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
|
<el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
|
||||||
@ -74,8 +70,7 @@
|
|||||||
<el-table-column label="显示顺序" prop="roleSort" width="100" />
|
<el-table-column label="显示顺序" prop="roleSort" width="100" />
|
||||||
<el-table-column label="状态" align="center" width="100">
|
<el-table-column label="状态" align="center" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
|
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||||
@change="handleStatusChange(scope.row)"></el-switch>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime">
|
<el-table-column label="创建时间" align="center" prop="createTime">
|
||||||
@ -87,27 +82,28 @@
|
|||||||
<el-table-column fixed="right" label="操作" width="180">
|
<el-table-column fixed="right" label="操作" width="180">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="修改" placement="top">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="修改" placement="top">
|
||||||
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit"
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
@click="handleUpdate(scope.row)"></el-button>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="删除" placement="top">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="删除" placement="top">
|
||||||
<el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete"
|
<el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
@click="handleDelete(scope.row)"></el-button>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="数据权限" placement="top">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="数据权限" placement="top">
|
||||||
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="CircleCheck"
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)"></el-button>
|
||||||
@click="handleDataScope(scope.row)"></el-button>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="分配用户" placement="top">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="分配用户" placement="top">
|
||||||
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="User"
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="User" @click="handleAuthUser(scope.row)"></el-button>
|
||||||
@click="handleAuthUser(scope.row)"></el-button>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-if="total > 0" v-model:total="total" v-model:page="queryParams.pageNum"
|
<pagination
|
||||||
v-model:limit="queryParams.pageSize" @pagination="getList" />
|
v-if="total > 0"
|
||||||
|
v-model:total="total"
|
||||||
|
v-model:page="queryParams.pageNum"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -115,8 +111,15 @@
|
|||||||
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="roleFormRef" :model="form" :rules="rules" label-width="110px">
|
<el-form ref="roleFormRef" :model="form" :rules="rules" label-width="110px">
|
||||||
<el-form-item label="所属部门" prop="deptId">
|
<el-form-item label="所属部门" prop="deptId">
|
||||||
<el-cascader :options="deptOptions" v-model="form.deptId" placeholder="请选择所属部门" clearable filterable
|
<el-cascader
|
||||||
:show-all-levels="false" :props="{ value: 'id', emitPath: false, checkStrictly: true }" @change="">
|
:options="deptOptions"
|
||||||
|
v-model="form.deptId"
|
||||||
|
placeholder="请选择所属部门"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
:show-all-levels="false"
|
||||||
|
:props="{ value: 'id', emitPath: false, checkStrictly: true }"
|
||||||
|
>
|
||||||
</el-cascader>
|
</el-cascader>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="角色名称" prop="roleName">
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
@ -138,23 +141,26 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态">
|
<el-form-item label="状态">
|
||||||
<el-radio-group v-model="form.status">
|
<el-radio-group v-model="form.status">
|
||||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
|
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
|
||||||
}}</el-radio>
|
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="菜单权限">
|
<el-form-item label="菜单权限">
|
||||||
<el-checkbox v-model="menuExpand"
|
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand(Boolean($event), 'menu')">展开/折叠</el-checkbox>
|
||||||
@change="handleCheckedTreeExpand(Boolean($event), 'menu')">展开/折叠</el-checkbox>
|
|
||||||
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
|
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
|
||||||
<el-checkbox v-model="form.menuCheckStrictly"
|
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
|
||||||
@change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
|
<el-tree
|
||||||
<el-tree ref="menuRef" class="tree-border" :data="menuOptions" show-checkbox node-key="id"
|
ref="menuRef"
|
||||||
:check-strictly="!form.menuCheckStrictly" empty-text="加载中,请稍候"
|
class="tree-border"
|
||||||
:props="{ label: 'label', children: 'children' }"></el-tree>
|
:data="menuOptions"
|
||||||
|
show-checkbox
|
||||||
|
node-key="id"
|
||||||
|
:check-strictly="!form.menuCheckStrictly"
|
||||||
|
empty-text="加载中,请稍候"
|
||||||
|
:props="{ label: 'label', children: 'children' }"
|
||||||
|
></el-tree>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="是否为特殊角色">
|
<el-form-item label="是否为特殊角色">
|
||||||
<el-switch v-model="form.isSpecial" active-value="1" inactive-value="0" active-text="是" inactive-text="否">
|
<el-switch v-model="form.isSpecial" active-value="1" inactive-value="0" active-text="是" inactive-text="否"> </el-switch>
|
||||||
</el-switch>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="备注">
|
<el-form-item label="备注">
|
||||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
||||||
@ -179,19 +185,24 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="权限范围">
|
<el-form-item label="权限范围">
|
||||||
<el-select v-model="form.dataScope" @change="dataScopeSelectChange">
|
<el-select v-model="form.dataScope" @change="dataScopeSelectChange">
|
||||||
<el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label"
|
<el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
||||||
:value="item.value"></el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-show="form.dataScope === '2'" label="数据权限">
|
<el-form-item v-show="form.dataScope === '2'" label="数据权限">
|
||||||
<el-checkbox v-model="deptExpand"
|
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand(Boolean($event), 'dept')">展开/折叠</el-checkbox>
|
||||||
@change="handleCheckedTreeExpand(Boolean($event), 'dept')">展开/折叠</el-checkbox>
|
|
||||||
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
|
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
|
||||||
<el-checkbox v-model="form.deptCheckStrictly"
|
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
|
||||||
@change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
|
<el-tree
|
||||||
<el-tree ref="deptRef" class="tree-border" :data="deptOptions" show-checkbox default-expand-all node-key="id"
|
ref="deptRef"
|
||||||
:check-strictly="!form.deptCheckStrictly" empty-text="加载中,请稍候"
|
class="tree-border"
|
||||||
:props="{ label: 'label', children: 'children' }"></el-tree>
|
:data="deptOptions"
|
||||||
|
show-checkbox
|
||||||
|
default-expand-all
|
||||||
|
node-key="id"
|
||||||
|
:check-strictly="!form.deptCheckStrictly"
|
||||||
|
empty-text="加载中,请稍候"
|
||||||
|
:props="{ label: 'label', children: 'children' }"
|
||||||
|
></el-tree>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -252,7 +263,7 @@ const menuRef = ref<ElTreeInstance>();
|
|||||||
const deptRef = ref<ElTreeInstance>();
|
const deptRef = ref<ElTreeInstance>();
|
||||||
const deptTreeRef = ref<ElTreeInstance>();
|
const deptTreeRef = ref<ElTreeInstance>();
|
||||||
|
|
||||||
const initForm: RoleForm = {
|
const initForm = {
|
||||||
roleId: undefined,
|
roleId: undefined,
|
||||||
roleSort: 1,
|
roleSort: 1,
|
||||||
status: '0',
|
status: '0',
|
||||||
@ -265,10 +276,11 @@ const initForm: RoleForm = {
|
|||||||
menuIds: [],
|
menuIds: [],
|
||||||
deptId: '',
|
deptId: '',
|
||||||
isSpecial: null,
|
isSpecial: null,
|
||||||
deptIds: []
|
deptIds: [],
|
||||||
|
roleSource: '1'
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = reactive<PageData<RoleForm, RoleQuery>>({
|
const data = reactive({
|
||||||
form: { ...initForm },
|
form: { ...initForm },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
@ -276,7 +288,8 @@ const data = reactive<PageData<RoleForm, RoleQuery>>({
|
|||||||
roleName: '',
|
roleName: '',
|
||||||
roleKey: '',
|
roleKey: '',
|
||||||
deptId: '',
|
deptId: '',
|
||||||
status: ''
|
status: '',
|
||||||
|
roleSource: '1'
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
roleName: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
|
roleName: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
|
||||||
@ -377,7 +390,7 @@ const handleAuthUser = (row: RoleVO) => {
|
|||||||
|
|
||||||
/** 查询菜单树结构 */
|
/** 查询菜单树结构 */
|
||||||
const getMenuTreeselect = async () => {
|
const getMenuTreeselect = async () => {
|
||||||
const res = await menuTreeselect();
|
const res = await menuTreeselect({ menuSource: '1' });
|
||||||
menuOptions.value = res.data;
|
menuOptions.value = res.data;
|
||||||
};
|
};
|
||||||
/** 所有部门节点数据 */
|
/** 所有部门节点数据 */
|
||||||
@ -427,14 +440,14 @@ const handleUpdate = async (row?: RoleVO) => {
|
|||||||
};
|
};
|
||||||
/** 根据角色ID查询菜单树结构 */
|
/** 根据角色ID查询菜单树结构 */
|
||||||
const getRoleMenuTreeselect = (roleId: string | number) => {
|
const getRoleMenuTreeselect = (roleId: string | number) => {
|
||||||
return roleMenuTreeselect(roleId).then((res): RoleMenuTree => {
|
return roleMenuTreeselect(roleId, { menuSource: '1' }).then((res): RoleMenuTree => {
|
||||||
menuOptions.value = res.data.menus;
|
menuOptions.value = res.data.menus;
|
||||||
return res.data;
|
return res.data;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
/** 根据角色ID查询部门树结构 */
|
/** 根据角色ID查询部门树结构 */
|
||||||
const getRoleDeptTreeSelect = async (roleId: string | number) => {
|
const getRoleDeptTreeSelect = async (roleId: string | number) => {
|
||||||
const res = await deptTreeSelect(roleId);
|
const res = await deptTreeSelect(roleId, { roleSource: '1' });
|
||||||
deptOptions.value = res.data.depts;
|
deptOptions.value = res.data.depts;
|
||||||
return res.data;
|
return res.data;
|
||||||
};
|
};
|
||||||
|
@ -219,6 +219,10 @@ const removeProject = (projectId: number | string) => {
|
|||||||
// 提交表单
|
// 提交表单
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
// 整理项目角色数据
|
// 整理项目角色数据
|
||||||
|
if (form.value.projectRoles.length == 0) {
|
||||||
|
proxy?.$modal.msgWarning('请选择项目角色');
|
||||||
|
return;
|
||||||
|
}
|
||||||
form.value.projectRoles = selectedProjects.value.map((project) => ({
|
form.value.projectRoles = selectedProjects.value.map((project) => ({
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
roleIds: [...new Set(project.webRoles), ...new Set(project.appRoles)]
|
roleIds: [...new Set(project.webRoles), ...new Set(project.appRoles)]
|
||||||
@ -273,7 +277,6 @@ const open = async (row?: any, deptId?: any) => {
|
|||||||
resetForm();
|
resetForm();
|
||||||
await initData();
|
await initData();
|
||||||
deptName.value = row.deptName;
|
deptName.value = row.deptName;
|
||||||
console.log(row);
|
|
||||||
if (row) {
|
if (row) {
|
||||||
try {
|
try {
|
||||||
if (!row.createTime) {
|
if (!row.createTime) {
|
||||||
@ -283,19 +286,20 @@ const open = async (row?: any, deptId?: any) => {
|
|||||||
deptId = form.value.deptId;
|
deptId = form.value.deptId;
|
||||||
}
|
}
|
||||||
const roleRes = await getRoleList(deptId);
|
const roleRes = await getRoleList(deptId);
|
||||||
allRoles.value = roleRes.data.filter((item: Role) => item.roleSort === 1);
|
allRoles.value = roleRes.data.filter((item: Role) => item.roleSource == '1');
|
||||||
AppRoles.value = roleRes.data.filter((item: Role) => item.roleSort !== 1);
|
AppRoles.value = roleRes.data.filter((item: Role) => item.roleSource != '1');
|
||||||
} else {
|
} else {
|
||||||
const { data } = await api.getUser(row.userId);
|
// const { data } = await api.getUser(row.userId);
|
||||||
Object.assign(form.value, data.user);
|
const data = row;
|
||||||
|
Object.assign(form.value, row);
|
||||||
// 获取角色列表
|
// 获取角色列表
|
||||||
if (form.value.deptId) {
|
if (form.value.deptId) {
|
||||||
deptId = form.value.deptId;
|
deptId = form.value.deptId;
|
||||||
}
|
}
|
||||||
const roleRes = await getRoleList(deptId);
|
const roleRes = await getRoleList(deptId);
|
||||||
// 区分web端和app端角色
|
// 区分web端和app端角色
|
||||||
allRoles.value = roleRes.data.filter((item: Role) => item.roleSort === 1);
|
allRoles.value = roleRes.data.filter((item: Role) => item.roleSource == '1');
|
||||||
AppRoles.value = roleRes.data.filter((item: Role) => item.roleSort !== 1);
|
AppRoles.value = roleRes.data.filter((item: Role) => item.roleSource != '1');
|
||||||
// 加载项目角色数据
|
// 加载项目角色数据
|
||||||
if (data.projectRoles && data.projectRoles.length) {
|
if (data.projectRoles && data.projectRoles.length) {
|
||||||
data.projectRoles.forEach((pr: any) => {
|
data.projectRoles.forEach((pr: any) => {
|
||||||
|
@ -58,11 +58,13 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
</transition>
|
</transition>
|
||||||
<el-card shadow="never" class="mb8">
|
<el-card shadow="never" class="mb8">
|
||||||
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
<el-table ref="tableAllRef" v-loading="loading" :data="tableData" row-key="id" border lazy :expand-row-keys="expandRowKeys">
|
||||||
<el-table-column prop="num" label="编号" />
|
<el-table-column prop="num" label="编号" />
|
||||||
<el-table-column prop="name" label="工程或费用名称" />
|
<el-table-column prop="name" label="工程或费用名称" />
|
||||||
<el-table-column prop="unit" label="单位" />
|
<el-table-column prop="unit" label="单位" align="center" />
|
||||||
<el-table-column prop="quantity" label="数量">
|
|
||||||
|
<el-table-column prop="specification" label="规格" align="center" />
|
||||||
|
<el-table-column prop="quantity" label="数量" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
||||||
</template>
|
</template>
|
||||||
@ -90,6 +92,11 @@
|
|||||||
{{ scope.row.price != 0 ? Number(scope.row.price).toFixed(2) : null }}
|
{{ scope.row.price != 0 ? Number(scope.row.price).toFixed(2) : null }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column prop="taxRate" label="税率" width="100" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.taxRate !== false ? scope.row.taxRate : '' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="operate" label="操作" align="center">
|
<el-table-column prop="operate" label="操作" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
@ -111,64 +118,141 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, watch, onMounted, onUnmounted } from 'vue';
|
||||||
|
import { getCurrentInstance, ComponentInternalInstance } from 'vue';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import { obtainAllVersionNumbers, sheetList, getTableList, updatePrice, importExcelFile } from '@/api/tender/index';
|
import { obtainAllVersionNumbers, sheetList, getTableList, updatePrice, importExcelFile } from '@/api/tender/index';
|
||||||
|
|
||||||
|
// 类型定义
|
||||||
|
interface QueryForm {
|
||||||
|
versions: string;
|
||||||
|
sheet: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TableRow {
|
||||||
|
id: string | number;
|
||||||
|
num?: string;
|
||||||
|
name?: string;
|
||||||
|
unit?: string;
|
||||||
|
taxRate?: string | number;
|
||||||
|
specification?: string;
|
||||||
|
quantity?: number;
|
||||||
|
unitPrice?: number;
|
||||||
|
price?: number;
|
||||||
|
remark?: string;
|
||||||
|
children?: TableRow[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VersionItem {
|
||||||
|
versions: string;
|
||||||
|
status: string;
|
||||||
|
id?: string | number;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实例与状态初始化
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
|
||||||
|
// 标签页配置
|
||||||
const tabList = [
|
const tabList = [
|
||||||
{
|
{ label: '招采工程量清单', value: '2' },
|
||||||
label: '招采工程量清单',
|
{ label: '物资设备清单', value: '3' }
|
||||||
value: '2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '物资设备清单',
|
|
||||||
value: '3'
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
const queryForm = ref({
|
|
||||||
versions: '',
|
|
||||||
sheet: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
const versionsData = ref<any>({});
|
|
||||||
|
|
||||||
|
// 响应式状态
|
||||||
|
const queryForm = ref<QueryForm>({ versions: '', sheet: '' });
|
||||||
|
const versionsData = ref<VersionItem>({});
|
||||||
const activeTab = ref('2');
|
const activeTab = ref('2');
|
||||||
const sheets = ref([]);
|
const sheets = ref<string[]>([]);
|
||||||
const options = ref([]);
|
const options = ref<VersionItem[]>([]);
|
||||||
const tableData = ref([]);
|
const tableData = ref<TableRow[]>([]);
|
||||||
const tableRef = ref();
|
const tableAllRef = ref<any>(null);
|
||||||
|
const uploadRef = ref<any>(null);
|
||||||
const isExpandAll = ref(true);
|
const isExpandAll = ref(true);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const versionMap = new Map();
|
const versionMap = new Map<string, VersionItem>();
|
||||||
|
const expandRowKeys = ref<string[] | number[]>([]); // 控制表格展开的行ID
|
||||||
|
const modifyPrice = new Map<string | number, TableRow>();
|
||||||
|
|
||||||
// 切换tab
|
// 切换标签页
|
||||||
const handleTabChange = (tab: string) => {
|
const handleTabChange = (tab: string) => {
|
||||||
activeTab.value = tab;
|
activeTab.value = tab;
|
||||||
tableData.value = [];
|
tableData.value = [];
|
||||||
versionsData.value = {};
|
versionsData.value = {};
|
||||||
|
isExpandAll.value = true;
|
||||||
|
expandRowKeys.value = [];
|
||||||
getVersionNums();
|
getVersionNums();
|
||||||
};
|
};
|
||||||
//切换版本
|
|
||||||
const changeVersions = (value) => {
|
// 切换版本号
|
||||||
versionsData.value = options.value.find((item) => item.versions == value);
|
const changeVersions = (value: string) => {
|
||||||
|
versionsData.value = options.value.find((item) => item.versions === value) || {};
|
||||||
getSheetName();
|
getSheetName();
|
||||||
};
|
};
|
||||||
//切换表格
|
|
||||||
const changeSheet = (val: any) => {
|
// 切换表名
|
||||||
|
const changeSheet = (val: string) => {
|
||||||
getTableData();
|
getTableData();
|
||||||
};
|
};
|
||||||
//展开树
|
|
||||||
const toggleExpandAll = () => {
|
// 一键展开/收起
|
||||||
|
const toggleExpandAll = async () => {
|
||||||
isExpandAll.value = !isExpandAll.value;
|
isExpandAll.value = !isExpandAll.value;
|
||||||
console.log(isExpandAll.value);
|
if (!tableData.value.length || !tableAllRef.value) return;
|
||||||
tableData.value.forEach((row) => {
|
|
||||||
tableRef.value.toggleRowExpansion(row, isExpandAll.value);
|
if (isExpandAll.value) {
|
||||||
|
// 收集所有已加载节点的ID
|
||||||
|
const allExpandIds = collectAllNodeIds(tableData.value);
|
||||||
|
expandRowKeys.value = allExpandIds;
|
||||||
|
|
||||||
|
// 处理懒加载节点
|
||||||
|
await loadAndExpandAllLazyNodes();
|
||||||
|
} else {
|
||||||
|
// 全部收起
|
||||||
|
expandRowKeys.value = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 辅助函数:递归收集所有节点ID(包括子节点)
|
||||||
|
const collectAllNodeIds = (nodes: TableRow[]): (string | number)[] => {
|
||||||
|
let ids: (string | number)[] = [];
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
ids.push(node.id);
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
ids = [...ids, ...collectAllNodeIds(node.children)];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
return ids;
|
||||||
};
|
};
|
||||||
|
|
||||||
//获取版本号
|
// 辅助函数:加载并展开所有懒加载子节点
|
||||||
|
const loadAndExpandAllLazyNodes = async () => {
|
||||||
|
if (!tableAllRef.value) return;
|
||||||
|
try {
|
||||||
|
// 获取所有可能有子节点的父节点
|
||||||
|
const parentNodes = tableData.value.filter((node) => node.hasChildren || (node.children && node.children.length === 0));
|
||||||
|
if (!parentNodes.length) return;
|
||||||
|
|
||||||
|
// 逐个加载并展开子节点
|
||||||
|
for (const parent of parentNodes) {
|
||||||
|
if (tableAllRef.value.loadOrToggleRow) {
|
||||||
|
await tableAllRef.value.loadOrToggleRow(parent);
|
||||||
|
}
|
||||||
|
await nextTick();
|
||||||
|
// 递归展开子节点的子节点
|
||||||
|
if (parent.children && parent.children.length > 0) {
|
||||||
|
const childIds = collectAllNodeIds(parent.children);
|
||||||
|
expandRowKeys.value = [...new Set([...expandRowKeys.value, ...childIds])];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载并展开懒加载节点失败:', error);
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 获取版本号列表
|
||||||
const getVersionNums = async () => {
|
const getVersionNums = async () => {
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
@ -179,93 +263,126 @@ const getVersionNums = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const res = await obtainAllVersionNumbers(params);
|
const res = await obtainAllVersionNumbers(params);
|
||||||
if (res.code == 200) {
|
if (res.code === 200) {
|
||||||
options.value = res.data;
|
options.value = res.data;
|
||||||
if (res.data.length > 0) {
|
versionMap.clear();
|
||||||
res.data.forEach((item: any) => {
|
options.value.forEach((item) => versionMap.set(item.versions, item));
|
||||||
versionMap.set(item.versions, item);
|
|
||||||
});
|
if (options.value.length > 0) {
|
||||||
queryForm.value.versions = res.data[0].versions;
|
queryForm.value.versions = options.value[0].versions;
|
||||||
versionsData.value = options.value.find((item) => item.versions == queryForm.value.versions);
|
versionsData.value = options.value[0];
|
||||||
getSheetName();
|
getSheetName();
|
||||||
} else {
|
} else {
|
||||||
queryForm.value.versions = '';
|
queryForm.value.versions = '';
|
||||||
// getSheetName();
|
sheets.value = [];
|
||||||
|
tableData.value = [];
|
||||||
|
expandRowKeys.value = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.error('获取版本号失败:', error);
|
||||||
|
ElMessage.error('获取版本号失败,请刷新重试');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//获取表名
|
|
||||||
|
// 获取表名列表
|
||||||
const getSheetName = async () => {
|
const getSheetName = async () => {
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
versions: queryForm.value.versions
|
versions: queryForm.value.versions
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await sheetList(params);
|
const res = await sheetList(params);
|
||||||
if (res.code == 200) {
|
if (res.code === 200) {
|
||||||
sheets.value = res.data;
|
sheets.value = res.data;
|
||||||
if (res.data.length > 0) {
|
if (sheets.value.length > 0) {
|
||||||
queryForm.value.sheet = res.data[0];
|
queryForm.value.sheet = sheets.value[0];
|
||||||
} else {
|
} else {
|
||||||
queryForm.value.sheet = '';
|
queryForm.value.sheet = '';
|
||||||
|
tableData.value = [];
|
||||||
|
expandRowKeys.value = [];
|
||||||
}
|
}
|
||||||
getTableData();
|
getTableData();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.error('获取表名失败:', error);
|
||||||
|
ElMessage.error('获取表名失败,请刷新重试');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取表格数据
|
// 获取表格数据
|
||||||
const getTableData = async () => {
|
const getTableData = async () => {
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
versions: queryForm.value.versions,
|
versions: queryForm.value.versions,
|
||||||
sheet: queryForm.value.sheet,
|
sheet: queryForm.value.sheet,
|
||||||
type: activeTab.value
|
type: activeTab.value
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await getTableList(params);
|
const res = await getTableList(params);
|
||||||
if (res.code == 200) {
|
if (res.code === 200) {
|
||||||
tableData.value = res.data;
|
tableData.value = res.data;
|
||||||
|
if (isExpandAll.value) {
|
||||||
|
// 展开全部
|
||||||
|
isExpandAll.value = false;
|
||||||
|
toggleExpandAll();
|
||||||
|
}
|
||||||
|
modifyPrice.clear();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.error('获取表格数据失败:', error);
|
||||||
|
ElMessage.error('获取表格数据失败,请刷新重试');
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//导入
|
|
||||||
const importExcel = (options: any): any => {
|
// 导入Excel
|
||||||
let formData = new FormData();
|
const importExcel = (options: any): void => {
|
||||||
|
if (!queryForm.value.versions || (activeTab.value !== '3' && !queryForm.value.sheet)) {
|
||||||
|
ElMessage.warning('请先选择版本号和表名(物资设备清单无需选择表名)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
formData.append('file', options.file);
|
formData.append('file', options.file);
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
importExcelFile(
|
importExcelFile(
|
||||||
{ projectId: currentProject.value?.id, sheet: queryForm.value.sheet, versions: queryForm.value.versions, type: activeTab.value },
|
{
|
||||||
|
projectId: currentProject.value?.id,
|
||||||
|
sheet: queryForm.value.sheet,
|
||||||
|
versions: queryForm.value.versions,
|
||||||
|
type: activeTab.value
|
||||||
|
},
|
||||||
formData
|
formData
|
||||||
)
|
)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const { code } = res;
|
if (res.code === 200) {
|
||||||
if (code == 200) {
|
proxy?.$modal.msgSuccess(res.msg || '导入成功');
|
||||||
proxy.$modal.msgSuccess(res.msg || '导入成功');
|
|
||||||
getTableData();
|
getTableData();
|
||||||
} else {
|
} else {
|
||||||
proxy.$modal.msgError(res.msg || '导入失败');
|
proxy?.$modal.msgError(res.msg || '导入失败');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
proxy.$modal.msgError(err.msg || '导入失败');
|
proxy?.$modal.msgError(err.msg || '导入失败');
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
//导出
|
|
||||||
|
// 导出Excel
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
|
if (!queryForm.value.versions || (activeTab.value !== '3' && !queryForm.value.sheet)) {
|
||||||
|
ElMessage.warning('请先选择版本号和表名(物资设备清单无需选择表名)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
proxy?.download(
|
proxy?.download(
|
||||||
'/tender/tenderPlanLimitList/export',
|
'/tender/tenderPlanLimitList/export',
|
||||||
{
|
{
|
||||||
@ -274,90 +391,108 @@ const handleExport = () => {
|
|||||||
versions: queryForm.value.versions,
|
versions: queryForm.value.versions,
|
||||||
type: activeTab.value
|
type: activeTab.value
|
||||||
},
|
},
|
||||||
`招标一览表${queryForm.value.sheet}.xlsx`
|
`招标一览_${queryForm.value.sheet || (activeTab.value === '3' ? '物资设备清单' : '')}_v${queryForm.value.versions}.xlsx`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
const modifyPrice = new Map();
|
|
||||||
|
|
||||||
const changePrice = (row: any) => {
|
// 记录待修改价格的行
|
||||||
|
const changePrice = (row: TableRow) => {
|
||||||
|
if (row.id && row.unitPrice !== undefined) {
|
||||||
modifyPrice.set(row.id, row);
|
modifyPrice.set(row.id, row);
|
||||||
// if (!row.unitPrice) {
|
} else if (row.id) {
|
||||||
// modifyPrice.delete(row.id);
|
modifyPrice.delete(row.id);
|
||||||
// }
|
}
|
||||||
};
|
};
|
||||||
//修改单价
|
|
||||||
const handleSave = (row?: any, type?: any) => {
|
// 保存价格修改
|
||||||
try {
|
const handleSave = (row?: TableRow, type?: 'single' | 'all') => {
|
||||||
if (type == 'single') {
|
if (versionsData.value.status !== 'draft') {
|
||||||
|
ElMessage.warning('仅草稿状态可修改单价');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let updateList: TableRow[] = [];
|
||||||
|
if (type === 'single' && row?.id) {
|
||||||
|
updateList = [{ ...row, type: activeTab.value }];
|
||||||
|
} else if (type === 'all') {
|
||||||
|
updateList = Array.from(modifyPrice.values()).map((item) => ({ ...item, type: activeTab.value }));
|
||||||
|
if (updateList.length === 0) {
|
||||||
|
ElMessage.warning('暂无待修改的单价数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const list = [{ ...row, type: activeTab.value }];
|
updatePrice(updateList)
|
||||||
updatePrice(list).then((res) => {
|
.then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code === 200) {
|
||||||
ElMessage({
|
ElMessage.success('修改成功');
|
||||||
message: '修改成功',
|
|
||||||
type: 'success'
|
|
||||||
});
|
|
||||||
getTableData();
|
getTableData();
|
||||||
|
modifyPrice.clear();
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg || '修改失败');
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
.catch((err) => {
|
||||||
if (type == 'all') {
|
ElMessage.error(err.msg || '修改失败');
|
||||||
loading.value = true;
|
})
|
||||||
const list = [];
|
.finally(() => {
|
||||||
modifyPrice.forEach((item) => {
|
|
||||||
list.push({ ...item, type: activeTab.value });
|
|
||||||
});
|
|
||||||
updatePrice(list).then((res) => {
|
|
||||||
if (res.code == 200) {
|
|
||||||
ElMessage({
|
|
||||||
message: '修改成功',
|
|
||||||
type: 'success'
|
|
||||||
});
|
|
||||||
getTableData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage({
|
|
||||||
message: '修改失败',
|
|
||||||
type: 'error'
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 审核按钮操作 */
|
// 审核/查看流程
|
||||||
const handleAudit = async () => {
|
const handleAudit = () => {
|
||||||
let id = versionMap.get(queryForm.value.versions).id;
|
const versionItem = versionMap.get(queryForm.value.versions);
|
||||||
console.log(id);
|
if (!versionItem?.id) {
|
||||||
if (activeTab.value == '2') {
|
ElMessage.warning('请先选择有效的版本号');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeTab.value === '2') {
|
||||||
proxy?.$tab.openPage('/approval/tenderBidd/indexEdit', '招采工程量清单审核', {
|
proxy?.$tab.openPage('/approval/tenderBidd/indexEdit', '招采工程量清单审核', {
|
||||||
id: id,
|
id: versionItem.id,
|
||||||
type: 'update'
|
type: 'update'
|
||||||
});
|
});
|
||||||
}
|
} else if (activeTab.value === '3') {
|
||||||
if (activeTab.value == '3') {
|
|
||||||
proxy?.$tab.openPage('/approval/tenderBidd/indexEdit2', '物资设备清单审核', {
|
proxy?.$tab.openPage('/approval/tenderBidd/indexEdit2', '物资设备清单审核', {
|
||||||
id: id,
|
id: versionItem.id,
|
||||||
type: 'update'
|
type: 'update'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//监听项目id刷新数据
|
// 监听项目切换
|
||||||
const listeningProject = watch(
|
const listeningProject = watch(
|
||||||
() => currentProject.value?.id,
|
() => currentProject.value?.id,
|
||||||
(nid, oid) => {
|
(newId, oldId) => {
|
||||||
|
if (newId && newId !== oldId) {
|
||||||
getVersionNums();
|
getVersionNums();
|
||||||
|
} else {
|
||||||
|
tableData.value = [];
|
||||||
|
options.value = [];
|
||||||
|
sheets.value = [];
|
||||||
|
queryForm.value = { versions: '', sheet: '' };
|
||||||
|
versionsData.value = {};
|
||||||
|
expandRowKeys.value = [];
|
||||||
|
versionMap.clear();
|
||||||
|
modifyPrice.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
onUnmounted(() => {
|
|
||||||
listeningProject();
|
// 生命周期钩子
|
||||||
});
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getVersionNums();
|
getVersionNums();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss">
|
||||||
|
.mb8 {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -195,7 +195,9 @@
|
|||||||
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) -
|
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) -
|
||||||
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) ==
|
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) ==
|
||||||
0
|
0
|
||||||
? ''
|
? activeTab == 2
|
||||||
|
? 0
|
||||||
|
: ''
|
||||||
: (scope.row.quantity ? Number(scope.row.quantity) : 0) -
|
: (scope.row.quantity ? Number(scope.row.quantity) : 0) -
|
||||||
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) -
|
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) -
|
||||||
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
|
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
|
||||||
@ -613,6 +615,7 @@ const changeBiddingTime = (value: any, row: any) => {
|
|||||||
};
|
};
|
||||||
//修改合同金额
|
//修改合同金额
|
||||||
const changeContractPrice = (value: any, row: any) => {
|
const changeContractPrice = (value: any, row: any) => {
|
||||||
|
if (value <= Number(row.price)) {
|
||||||
updateTenderPlan({
|
updateTenderPlan({
|
||||||
...row
|
...row
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
@ -624,6 +627,9 @@ const changeContractPrice = (value: any, row: any) => {
|
|||||||
getList();
|
getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
ElMessage.error('合同金额不能大于限价金额');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//上传投标文件
|
//上传投标文件
|
||||||
|
@ -104,8 +104,9 @@
|
|||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="近三年营业额" prop="pastThreeYears">
|
<el-form-item label="近三年营业额" prop="pastThreeYears">
|
||||||
<el-input v-model="form.pastThreeYears" placeholder="请输入近三年营业额" clearable />
|
<el-input v-model="form.pastThreeYears" placeholder="请输入近三年营业额" clearable />
|
||||||
</el-form-item> </el-col
|
</el-form-item>
|
||||||
><el-col :span="12">
|
</el-col>
|
||||||
|
<!-- <el-col :span="12">
|
||||||
<el-form-item label="生产许可证编号" prop="safeCode">
|
<el-form-item label="生产许可证编号" prop="safeCode">
|
||||||
<el-input v-model="form.safeCode" placeholder="请输入许可证编号" clearable />
|
<el-input v-model="form.safeCode" placeholder="请输入许可证编号" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -118,7 +119,7 @@
|
|||||||
<el-form-item label="生产许可证发证日期" prop="safeCertificateValidity">
|
<el-form-item label="生产许可证发证日期" prop="safeCertificateValidity">
|
||||||
<el-date-picker v-model="form.safeCertificateValidity" type="date" placeholder="请选择发证日期" />
|
<el-date-picker v-model="form.safeCertificateValidity" type="date" placeholder="请选择发证日期" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col> -->
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row class="mb-4" v-if="form.supplierType === '劳务'">
|
<el-row class="mb-4" v-if="form.supplierType === '劳务'">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
|
Reference in New Issue
Block a user