This commit is contained in:
2025-09-04 10:37:24 +08:00
36 changed files with 2262 additions and 1197 deletions

View File

@ -6,7 +6,7 @@ VITE_APP_ENV = 'development'
# 开发环境
# 李陈杰 209
VITE_APP_BASE_API = 'http://192.168.110.209:8899'
VITE_APP_BASE_API = 'http://192.168.110.149:8899'
# 曾涛
# VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# 罗成

View File

@ -69,7 +69,8 @@
"vue-types": "5.1.3",
"vue3-print-nb": "^0.1.4",
"vue3-scroll-seamless": "^1.0.6",
"vxe-table": "4.5.22"
"vxe-table": "4.5.22",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@eslint/js": "9.15.0",

View File

@ -24,3 +24,11 @@ export const exportWord = (params) => {
method: 'post'
});
};
// 导出模版
export const exportExcel = (params) => {
return request({
url: '/design/collect/exportExcel',
method: 'post',
params: params
});
};

View File

@ -75,3 +75,11 @@ export const inventoryList = (id: any) => {
method: 'get'
});
};
//获取材料表信息
export const getMaterialInfo = (id: any) => {
return request({
url: '/materials/materials/listByFormCode/' + id,
method: 'get'
});
};

View File

@ -195,3 +195,35 @@ export const changeProject = (id: string | number) => {
method: 'get'
});
};
/**
* 打卡规则
* @param id
*/
export const attendanceRuleEdit = (data) => {
return request({
url: '/project/attendanceRule',
method: 'put',
data
});
};
/**
* 打卡规则
* @param id
*/
export const attendanceRuleAdd = (data) => {
return request({
url: '/project/attendanceRule',
method: 'post',
data
});
};
/**
* 获取规则
* @param id
*/
export const byProjectIdDetail = (id) => {
return request({
url: '/project/attendanceRule/byProjectId/' + id,
method: 'get'
});
};

View File

@ -71,7 +71,7 @@ export function getRoleList(deptId?: number | string): AxiosPromise<any[]> {
url: '/system/role/listNoPage',
method: 'get',
params: {
deptId
deptId,
}
});
}

View File

@ -26,11 +26,11 @@
<el-tooltip effect="dark" placement="bottom">
<ProjectSelector />
</el-tooltip>
<!-- <el-tooltip content="搜索" effect="dark" placement="bottom">
<el-tooltip content="搜索" effect="dark" placement="bottom">
<div class="right-menu-item hover-effect" @click="openSearchMenu">
<svg-icon class-name="search-icon" icon-class="search" />
</div>
</el-tooltip> -->
</el-tooltip>
<!-- 消息 -->
<el-tooltip :content="proxy.$t('navbar.message')" effect="dark" placement="bottom">
<div>

View File

@ -5,7 +5,7 @@
<el-form :model="queryForm" :inline="true">
<el-form-item label="版本号" prop="versions">
<el-select v-model="queryForm.versions" placeholder="选择版本号" @change="changeVersions">
<el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.id" />
<el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.versions" />
</el-select>
</el-form-item>
<el-form-item label="表名" prop="sheet">
@ -166,7 +166,8 @@ const getTableData = async () => {
const params = {
projectId: currentProject.value?.id,
sheet: queryForm.value.sheet,
versions: queryForm.value.versions
versions: queryForm.value.versions,
type: '1'
};
const res = await getTreeLimit(params);
loading.value = false;

View File

@ -210,7 +210,8 @@ const getListTable = async () => {
const res = await getTreeLimit({
projectId: currentProject.value?.id,
versions: form.value.versions,
sheet: form.value.sheet
sheet: form.value.sheet,
type: '0'
});
if (res.code == 200) {
tableData.value = res.data;

View File

@ -5,7 +5,7 @@
<el-form :model="queryForm" :inline="true">
<el-form-item label="版本号" prop="versions">
<el-select v-model="queryForm.versions" placeholder="选择版本号" @change="changeVersions">
<el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.id" />
<el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.versions" />
</el-select>
</el-form-item>
<el-form-item label="表名" prop="sheet">
@ -184,7 +184,8 @@ const getTableData = async () => {
const params = {
projectId: currentProject.value?.id,
sheet: queryForm.value.sheet,
versions: queryForm.value.versions
versions: queryForm.value.versions,
type: '0'
};
const res = await getTreeLimit(params);
loading.value = false;
@ -288,7 +289,7 @@ const handleExport = () => {
projectId: currentProject.value?.id,
sheet: queryForm.value.sheet
},
`限价一览表${queryForm.value.sheet}.xlsx`
`投标成本核算${queryForm.value.sheet}.xlsx`
);
};
// 审核

View File

@ -138,9 +138,14 @@
<el-table-column prop="useQuantity" label="剩余量" align="center">
<template #default="scope">
{{
(scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) == 0
(scope.row.quantity ? Number(scope.row.quantity) : 0) -
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) -
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) ==
0
? ''
: (scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
: (scope.row.quantity ? Number(scope.row.quantity) : 0) -
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) -
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
}}
</template>
</el-table-column>
@ -149,12 +154,16 @@
<el-table-column prop="price" label="总价" align="center">
<template #default="scope">
{{
((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) *
((scope.row.quantity ? Number(scope.row.quantity) : 0) -
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) -
(scope.row.selectNum ? Number(scope.row.selectNum) : 0)) *
Number(scope.row.unitPrice) ==
0
? ''
: (
((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) *
((scope.row.quantity ? Number(scope.row.quantity) : 0) -
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) -
(scope.row.selectNum ? Number(scope.row.selectNum) : 0)) *
Number(scope.row.unitPrice)
).toFixed(2)
}}
@ -328,18 +337,10 @@ const getVersionNums = async () => {
getSheetName();
} else {
treeForm.value.versions = '';
ElMessage({
message: '获取版本号失败',
type: 'warning'
});
}
}
} catch (error) {
console.log(error);
ElMessage({
message: '获取版本号失败',
type: 'warning'
});
}
};
//获取表名
@ -356,19 +357,11 @@ const getSheetName = async () => {
treeForm.value.sheet = res.data[0];
} else {
treeForm.value.sheet = '';
ElMessage({
message: '获取表名失败',
type: 'warning'
});
}
getTreeList();
}
} catch (error) {
console.log(error);
ElMessage({
message: '获取表名失败',
type: 'warning'
});
}
};
const handleSelection = (selection: any) => {

View File

@ -124,7 +124,7 @@ const loading = ref(false);
const options = ref<any[]>([]);
const sheets = ref<any[]>([]);
const tableData = ref<any[]>([]);
const isExpandAll = ref(false);
const isExpandAll = ref(true);
const reviewStatus = ref('');
const versionObj: any = ref({});
const versionMap = new Map();
@ -150,18 +150,10 @@ const getVersionNums = async () => {
getSheetName();
} else {
queryForm.value.versions = '';
ElMessage({
message: '获取版本号失败',
type: 'warning'
});
}
}
} catch (error) {
console.log(error);
ElMessage({
message: '获取版本号失败',
type: 'warning'
});
}
};
//选择版本号
@ -193,19 +185,11 @@ const getSheetName = async () => {
queryForm.value.sheet = res.data[0];
} else {
queryForm.value.sheet = '';
ElMessage({
message: '获取表名失败',
type: 'warning'
});
}
getTableData();
}
} catch (error) {
console.log(error);
ElMessage({
message: '获取表名失败',
type: 'warning'
});
}
};
//获取表格

View File

@ -65,7 +65,7 @@
>
<el-row :gutter="8" class="items-top">
<!-- 1. 专业选择核心统一所有角色的专业来源 -->
<el-col :span="3" class="mb-4 sm:mb-0 pl-4" style="margin-top:8px;">
<el-col :span="3" class="mb-4 sm:mb-0 pl-4" style="margin-top: 8px">
<el-form-item
:prop="`designers.${configIndex}.userMajor`"
:rules="[
@ -76,7 +76,8 @@
label-width="60px"
label="专业"
>
<el-select filterable
<el-select
filterable
v-model="form.designers[configIndex].userMajor"
placeholder="请选择专业"
class="w-full transition-all duration-300 border-gray-300"
@ -109,7 +110,8 @@
label="设计"
label-width="50px"
>
<el-select filterable
<el-select
filterable
v-model="person.userId"
placeholder="选择人员"
class="w-full transition-all duration-300 border-gray-300"
@ -165,7 +167,8 @@
label="校审"
label-width="50px"
>
<el-select filterable
<el-select
filterable
v-model="person.userId"
placeholder="选择人员"
class="w-full transition-all duration-300 border-gray-300"
@ -221,7 +224,8 @@
label="审定"
label-width="50px"
>
<el-select filterable
<el-select
filterable
v-model="person.userId"
placeholder="选择人员"
class="w-full transition-all duration-300 border-gray-300"
@ -277,7 +281,8 @@
label="审核"
label-width="50px"
>
<el-select filterable
<el-select
filterable
v-model="person.userId"
placeholder="选择人员"
class="w-full transition-all duration-300 border-gray-300"
@ -318,7 +323,7 @@
</el-col>
<!-- 操作列 -->
<el-col :span="2" class="text-right pr-4">
<el-col :span="2" class="pr-4 mt-2 text-right">
<el-button
type="text"
class="text-red-500 hover:text-red-700 transition-colors"

View File

@ -6,7 +6,7 @@
<el-card v-if="index < 3" shadow="always">
<el-form :model="state.queryForm" :inline="true">
<el-form-item label="版本号" prop="versions">
<el-select v-model="state.queryForm.versions" placeholder="选择版本号">
<el-select v-model="state.queryForm.versions" placeholder="选择版本号" @change="handleChangeVersion">
<el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" />
</el-select>
</el-form-item>
@ -166,6 +166,7 @@ const handleTabChange = (tab) => {
onMounted(async () => {
await getVersionNums();
});
// 获取版本号
async function getVersionNums(isSheet = true) {
try {

View File

@ -16,7 +16,7 @@
<!-- 表单区域 -->
<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">
<h3 class="text-lg font-semibold text-gray-800">标工程清单</h3>
<h3 class="text-lg font-semibold text-gray-800">标工程清单</h3>
</div>
<div class="p-6">
<el-form

View File

@ -49,7 +49,32 @@
<!-- 资料文件区域 -->
<div class="mb-8">
<div class="flex items-center justify-between mb-5">
<h3 class="text-lg font-semibold text-blue-700">资料文件清单</h3>
<div style="display: flex; align-items: center">
<h3 class="text-lg font-semibold text-blue-700" style="margin-right: 20px">资料文件清单</h3>
<el-upload
class="upload-excel"
action="#"
v-if="!form.id || form.status == 'draft'"
ref="uploadRef"
:auto-upload="false"
:on-change="importTemplate"
:show-file-list="false"
:accept="'.xlsx,.xls'"
:limit="1"
>
<el-button type="primary" icon="Upload">导入文件</el-button>
</el-upload>
<el-button
v-if="!form.id || form.status == 'draft'"
type="primary"
style="margin-left: 20px"
icon="Download"
@click="exportTemplate"
class="transition-all hover:bg-blue-600"
>
导出模版
</el-button>
</div>
<el-button type="primary" size="small" @click="addDocumentItem" v-if="!disabledAll" icon="Plus" class="transition-all hover:bg-blue-600">
添加资料
</el-button>
@ -180,11 +205,11 @@ import { ref, reactive, computed, onMounted, onUnmounted, watch, getCurrentInsta
import { useUserStoreHook } from '@/store/modules/user';
import { ElMessage, ElLoading, FormRules } from 'element-plus';
import { systemUserList } from '@/api/design/appointment';
import { collectBatch, byProjectId, exportWord } from '@/api/design/received';
import { collectBatch, byProjectId, exportWord, exportExcel } from '@/api/design/received';
import { getUser } from '@/api/system/user';
import type { ComponentInternalInstance, ElFormInstance } from 'element-plus';
import { getInfo } from '@/api/login';
import * as XLSX from 'xlsx';
// 全局实例与状态管理
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userStore = useUserStoreHook();
@ -200,7 +225,7 @@ const documentsFormRef = ref<ElFormInstance>();
const userList = ref<any[]>([]);
const userMap = new Map<string, string>(); // 存储用户ID与昵称映射
const disabledAll = ref(false); // 表单是否全部禁用
const uploadRef = ref<any>();
// 表单核心数据
const form = reactive({
projectId: currentProject.value?.id,
@ -445,7 +470,66 @@ const onLoad = async () => {
console.error('文件导出错误:', error);
}
};
const exportTemplate = async () => {
// 导出模版
proxy?.download(
'design/collect/exportExcel',
{
deptId: userStore.deptId
},
`收资清单表格.xlsx`
);
};
const importTemplate = async (files, fileList) => {
// 导入表格数据
const file = fileList[0].raw; // 获取原始文件对象
const reader = new FileReader();
let obj = {
id: '编码',
name: '人员',
fliename: '目录名',
remark: '备注'
};
reader.onload = (e) => {
try {
// 读取文件内容
const data = new Uint8Array(e.target.result);
// 解析Excel
const workbook = XLSX.read(data, { type: 'array' });
// 获取第一个工作表名称
const firstSheetName = workbook.SheetNames[0];
// 获取第一个工作表内容
const worksheet = workbook.Sheets[firstSheetName];
// 转换为JSON格式
const jsonData = XLSX.utils.sheet_to_json(worksheet);
if (jsonData.length === 0) {
ElMessage.info('Excel文件中没有数据');
return;
}
let arr = [];
// 判断form.documents 是否对象
jsonData.forEach((item, index) => {
if (item[obj.id]) {
arr.push({
id: Date.now() + index,
catalogueName: item[obj.fliename],
remark: item[obj.remark],
userId: item[obj.id]
});
}
});
form.documents = arr;
uploadRef.value.clearFiles();
console.log(arr);
} catch (err) {}
};
// 以ArrayBuffer方式读取文件
reader.readAsArrayBuffer(file);
};
/** 页面挂载初始化 */
onMounted(() => {
// 先获取当前用户信息,再获取部门用户列表,最后回显表单数据

View File

@ -151,16 +151,7 @@
/></el-select>
</el-form-item>
<el-form-item v-if="uploadForm.type == '3'" label="蓝图" prop="fileIds">
<<<<<<< HEAD
<file-upload
:fileType="['pdf']"
:isShowTip="false"
:fileSize="100"
. v-model="uploadForm.fileIds"
></file-upload>
=======
<file-upload :fileType="['pdf']" :isShowTip="false" :fileSize="100" v-model="uploadForm.fileIds"></file-upload>
>>>>>>> 8a3f338e2734575bcb743e917b1232bedc76f105
</el-form-item>
<el-form-item v-if="uploadForm.type == '3'" label="抄送人">
<el-select multiple filterable clearable v-model="form.userIds" placeholder="请选择抄送人">
@ -434,7 +425,7 @@ const cancel = () => {
};
// 获取人员列表
const getDesignUserList = async () => {
const res = await copyUserList({});
const res = await copyUserList({ projectId: currentProject.value?.id, userType: 2 });
if (res.code === 200) {
userCoryList.value = res.data;
}

View File

@ -81,7 +81,7 @@
<el-table v-loading="loading" :data="formalitiesAreConsolidatedList" @selection-change="handleSelectionChange" row-key="id" default-expand-all>
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="手续办理清单模板父级" align="center" prop="formalitiesPname" /> -->
<el-table-column label="手续办理清单" align="center" prop="formalitiesName" />
<el-table-column label="手续办理清单" align="left" prop="formalitiesName" />
<el-table-column label="计划开始时间" align="center" prop="planTheStartTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.planTheStartTime, '{y}-{m}-{d}') }}</span>

View File

@ -1,13 +1,11 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<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" label-width="auto">
<el-form-item label="材料名称" prop="materialsName">
<el-input v-model="queryParams.materialsName" placeholder="请输入材料名称" clearable
@keyup.enter="handleQuery" />
<el-input v-model="queryParams.materialsName" placeholder="请输入材料名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="材料提供商" prop="companyId">
<el-select v-model="queryParams.companyId" clearable placeholder="全部">
@ -27,22 +25,20 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['materials:materials:add']"> 新增
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['materials:materials:add']"> 新增 </el-button>
</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="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
v-hasPermi="['materials:materials:edit']">修改
<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="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-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>
</el-row>
@ -72,25 +68,28 @@
<el-table-column fixed="right" label="操作" align="center" class-name="small-padding fixed-width" width="320">
<template #default="scope">
<el-space>
<el-button link type="primary" icon="View" @click="handleShowDrawer(scope.row)"
v-hasPermi="['materials:materials:query']">
<el-button link type="primary" icon="View" @click="handleShowDrawer(scope.row)" v-hasPermi="['materials:materials:query']">
详情
</el-button>
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['materials:materials:edit']"> 修改 </el-button>
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['materials:materials:remove']">
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materials:edit']"> 修改 </el-button>
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materials:remove']">
删除
</el-button>
<el-button v-hasPermi="['materials:materialsInventory:edit']" link type="primary" icon="Plus"
@click="handleAddMaterialsInventory(scope.row)"> 出入库 </el-button>
<el-button
v-hasPermi="['materials:materialsInventory:edit']"
link
type="primary"
icon="Plus"
@click="handleAddMaterialsInventory(scope.row)"
>
出入库
</el-button>
</el-space>
</template>
</el-table-column>
</el-table>
<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-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@ -121,12 +120,17 @@
<el-form-item label="材料文件" prop="fileOssIdMap">
<div :key="item.value" v-for="item in materials_file_type">
<h3>{{ item.label }}</h3>
<file-upload v-model="ossIdMap[item.value]" :limit="1" :file-size="50" :file-type="['pdf']"
<file-upload
v-model="ossIdMap[item.value]"
:limit="1"
:file-size="50"
:file-type="['pdf']"
@update:model-value="
(args) => {
handleOssUpdate(args, item.value);
}
" />
"
/>
</div>
</el-form-item>
</el-form>
@ -137,8 +141,7 @@
</div>
</template>
</el-dialog>
<materials-inventory-add-dialog :materials-id="currentMaterialsId" :project-id="currentProject.id" ref="dialogRef"
@submit="getList" />
<materials-inventory-add-dialog :materials-id="currentMaterialsId" :project-id="currentProject.id" ref="dialogRef" @submit="getList" />
<el-dialog title="材料详情" v-model="showDetailDrawer" width="700px">
<materials-detail-drawer :materials-id="currentMaterialsId" />
</el-dialog>

View File

@ -73,7 +73,10 @@
<el-row>
<el-col :span="12">
<el-form-item label="表单编号" prop="formCode">
<el-input v-model="form.formCode" placeholder="请输入表单编号" />
<!-- <el-input v-model="form.formCode" placeholder="请输入表单编号" /> -->
<el-select v-model="form.formCode" placeholder="请选择表单编号" @change="(value) => formCodeChange(value)">
<el-option v-for="item in options" :key="item.formCode" :label="item.formCode" :value="item.formCode" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
@ -123,11 +126,11 @@
<el-col :span="12">
<el-form-item
label="名称"
:prop="`itemList.${index}.name`"
:prop="`itemList.${index}.materialsId`"
:rules="[{ required: true, message: '名称不能为空', trigger: 'blur' }]"
>
<el-select v-model="item.inventoryId" placeholder="请选择名称" @change="(value) => getNameChange(value, index, item)">
<el-option v-for="opt in optionsName" :key="opt.id" :label="opt.materialsName" :value="opt.id" />
<el-select v-model="item.materialsId" placeholder="请选择名称" @change="(value) => getNameChange(value, index, item)">
<el-option v-for="opt in optionsName" :key="opt.id" :label="`${opt.materialsName}_${opt.createTime}`" :value="opt.id" />
</el-select>
</el-form-item>
</el-col>
@ -168,13 +171,9 @@
</el-col> -->
<el-col :span="12">
<el-form-item label="领取" :prop="`itemList.${index}.issuedQuantity`">
<el-input
v-model.number="item.issuedQuantity"
disabled
placeholder="请输入领取数量"
@input="handleIssuedChange(index)"
@blur="handleIssuedChange(index)"
/>
<el-select v-model="item.issuedQuantity" placeholder="请选择数量">
<el-option v-for="opt in item.outList" :key="opt.id" :label="opt.number" :value="opt.number" />
</el-select>
</el-form-item>
</el-col>
<!-- <el-col :span="12">
@ -247,7 +246,8 @@ import {
addMaterialIssue,
updateMaterialIssue,
inventoryList,
getMaterialName
getMaterialName,
getMaterialInfo
} from '@/api/materials/materialIssue';
import { MaterialIssueVO, MaterialIssueQuery, MaterialIssueForm } from '@/api/materials/materialIssue/types';
@ -307,6 +307,7 @@ const getInitFormData = () => {
itemList: [
{
id: undefined,
specification: undefined,
unit: undefined,
stockQuantity: undefined,
@ -314,7 +315,8 @@ const getInitFormData = () => {
remainingQuantity: undefined,
name: undefined, // 数量验收的名称
remark: undefined,
materialsId: undefined
materialsId: undefined,
outList: []
}
]
};
@ -365,7 +367,7 @@ const computeMaterialName = () => {
.map((item) => item.name.trim())
.filter((name, index, self) => self.indexOf(name) === index); // 去重(如需保留重复则删除这行)
form.value.materialName = validNames.join(',');
// form.value.materialName = validNames.join(',');
};
/** 查询物料领料单列表 */
@ -404,6 +406,7 @@ const getNameChange = (value, index, item) => {
item.unit = selected.weightId;
item.issuedQuantity = selected.number;
item.stockQuantity = Number(selected.inventoryNumber) || 0;
item.outList = selected.outList || [];
// calculateRemaining(index); // 计算剩余数量
}
};
@ -529,8 +532,27 @@ const handleAdd = () => {
dialog.title = '添加物料领料单';
// 新增时初始计算材料名称
computeMaterialName();
getFormData();
};
const options = ref([]);
//新增获取表单数据
const getFormData = async () => {
const res = await getMaterialInfo(currentProject.value.id);
if (res.code == 200) {
options.value = res.data;
}
};
const formCodeChange = (value) => {
console.log(value);
const selected = options.value.find((opt) => opt.formCode === value);
if (selected) {
form.value.materialName = selected.materialName;
form.value.orderingUnit = selected.orderingUnit;
form.value.supplierUnit = selected.supplierUnit;
optionsName.value = selected.materials;
}
};
/** 修改按钮操作 */
const handleUpdate = async (row?: MaterialIssueVO) => {
reset();
@ -597,6 +619,7 @@ const submitForm = () => {
remainingQuantity: Number(item.remainingQuantity)
}))
};
console.log('提交数据:', submitData);
if (form.value.id) {
await updateMaterialIssue(submitData);
@ -638,10 +661,13 @@ const addItem = () => {
// 删除数量验收条目
const removeItem = (index: number) => {
if (form.value.itemList.length > 1) {
console.log(111111);
console.log(itemWatchStopFns.value[index]);
// 停止该条目的监听
if (itemWatchStopFns.value[index]) {
itemWatchStopFns.value[index]();
}
// if (itemWatchStopFns.value[index]) {
// itemWatchStopFns.value[index]();
// }
form.value.itemList.splice(index, 1);
itemWatchStopFns.value.splice(index, 1);
// 删除后重新计算材料名称
@ -682,7 +708,7 @@ watch(
onMounted(() => {
getList();
getName();
// getName();
});
// 监听项目id刷新数据
@ -692,7 +718,7 @@ const listeningProject = watch(
queryParams.value.projectId = nid;
form.value.projectId = nid;
getList();
getName();
// getName();
}
);

View File

@ -42,7 +42,7 @@
<thead>
<tr>
<th colspan="2">领料单位</th>
<td class="th-bg" colspan="2">{{ formData.placeholder }}</td>
<td class="th-bg" colspan="2">{{ formData.issueUnit }}</td>
<th colspan="2">保管单位</th>
<td class="th-bg" colspan="2">{{ formData.storageUnit }}</td>
</tr>

View File

@ -30,6 +30,9 @@
>一键全部保存</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>
@ -38,6 +41,7 @@
<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"
@ -264,6 +268,17 @@ const formRules = reactive({
],
compileDate: [{ required: true, message: '请选择编制日期', trigger: 'change' }]
});
// 展开状态
const isExpandAll = ref(false);
const tableRef = ref(null);
// 切换展开状态
const toggleExpandAll = () => {
isExpandAll.value = !isExpandAll.value;
console.log(isExpandAll.value);
state.tableData.forEach((row) => {
tableRef.value.toggleRowExpansion(row, isExpandAll.value);
});
};
// 获取主表数据
async function getMasterDataList() {
try {

View File

@ -81,7 +81,7 @@
<el-form-item label="计划产值(元)" prop="planValue">
<el-input v-model="form.planValue" placeholder="请输入计划产值" type="number" />
</el-form-item>
<el-form-item label="计划月份(元)" prop="planMonth">
<el-form-item label="计划月份" prop="planMonth">
<el-date-picker v-model="form.planMonth" type="month" value-format="YYYY-MM" placeholder="请选择计划月份" />
</el-form-item>
<el-form-item label="产值类型" prop="valueType">

View File

@ -431,6 +431,7 @@ const handleView = async (row: LandBlockVO) => {
formM.landId = row.id;
// 打开弹窗
dialogMatrix.visible = true;
dialogMatrix.title = `关联方阵(地块:${row.landName || row.landCode}`;
};

View File

@ -144,13 +144,16 @@
</el-table-column> -->
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180" />
<el-table-column fixed="right" label="操作" align="center" class-name="small-padding fixed-width" width="400">
<el-table-column fixed="right" label="操作" align="center" width="500">
<template #default="scope">
<el-space>
<el-button link type="primary" icon="Edit" @click="handleCheckRules(scope.row)" v-hasPermi="['project:attendanceRule:byProjectId']"
>打卡规则
</el-button>
<!-- <el-button link type="primary" icon="Edit" @click="handleScope(scope.row)" v-hasPermi="['project:project:edit']">打卡范围 </el-button> -->
<el-button link type="primary" icon="FolderOpened" @click="handleShowUpload(scope.row)" v-hasPermi="['project:project:edit']"
>导入安全协议书
</el-button>
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:project:edit']">修改 </el-button>
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:project:remove']">删除 </el-button>
<el-button link type="primary" icon="upload" @click="handleUpload(scope.row)" v-hasPermi="['project:project:saveTenderFile']"
@ -160,7 +163,6 @@
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改项目对话框 -->
@ -253,78 +255,6 @@
</el-col>
</el-row>
</div>
<div class="block-box">
<div class="">打卡设置</div>
<el-row :gutter="20">
<el-col :span="12" :offset="0">
<el-form-item label="打卡开始时间" prop="playCardStart" label-width="110px">
<!-- <el-time-picker value-format="HH:mm" v-model="form.playCardStart" placeholder="请输入打卡开始时间" /> -->
<el-time-select
v-model="form.playCardStart"
style="width: 100%"
class="mr-4"
placeholder="请输入打卡开始时间"
value-format="HH:mm"
start="00:00"
step="00:15"
end="23:59"
/>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="打卡结束时间" prop="playCardEnd" label-width="110px">
<!-- <el-time-picker value-format="HH:mm" v-model="form.playCardEnd" placeholder="请输入打卡结束时间" /> -->
<el-time-select
v-model="form.playCardEnd"
style="width: 100%"
:min-time="form.playCardStart"
class="mr-4"
placeholder="请输入打卡结束时间"
value-format="HH:mm"
start="00:00"
step="00:15"
end="23:59"
/>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="打卡类型" prop="playCardStart" label-width="110px">
<!-- <el-time-picker value-format="HH:mm" v-model="form.playCardStart" placeholder="请输入打卡开始时间" /> -->
<el-time-select
v-model="form.playCardStart"
style="width: 100%"
class="mr-4"
placeholder="请输入打卡开始时间"
value-format="HH:mm"
start="00:00"
step="00:15"
end="23:59"
/>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="工作日" prop="playCardEnd" label-width="110px">
<!-- <el-time-picker value-format="HH:mm" v-model="form.playCardEnd" placeholder="请输入打卡结束时间" /> -->
<el-time-select
v-model="form.playCardEnd"
style="width: 100%"
:min-time="form.playCardStart"
class="mr-4"
placeholder="请输入打卡结束时间"
value-format="HH:mm"
start="00:00"
step="00:15"
end="23:59"
/>
</el-form-item>
</el-col>
<!-- <el-col :span="24" :offset="0">
<el-form-item label="安全协议书" prop="securityAgreement">
<file-upload v-model="form.securityAgreement" :limit="1" :file-type="['pdf']" :file-size="50" />
</el-form-item>
</el-col> -->
</el-row>
</div>
</el-form>
<template #footer>
<div class="dialog-footer">
@ -342,13 +272,12 @@
</div>
</template>
</el-dialog>
<!-- //选取项目地址弹窗 -->
<el-dialog v-model="amapStatus" :title="form.projectName + '-获取经纬度'" width="80%">
<el-dialog draggable v-model="amapStatus" :title="form.projectName + '-获取经纬度'" width="80%">
<amap height="620px" @setLocation="setPoi"></amap>
</el-dialog>
<!-- 选取方阵地址 -->
<el-dialog title="设置方阵" v-model="polygonStatus" width="1400px" :close-on-click-modal="false">
<el-dialog draggable title="设置方阵" v-model="polygonStatus" width="1400px" :close-on-click-modal="false">
<open-layers-map
:project-id="projectId"
:design-id="designId"
@ -356,7 +285,7 @@
@close="polygonStatus = false"
></open-layers-map>
</el-dialog>
<el-dialog title="添加子项目" v-model="childProjectStatus" width="400">
<el-dialog draggable title="添加子项目" v-model="childProjectStatus" width="400">
<span>填写子项目名称</span>
<el-input v-model="childProjectForm.projectName"></el-input>
<template #footer>
@ -366,7 +295,7 @@
</span>
</template>
</el-dialog>
<el-dialog title="上传文件" v-model="fileVisble" width="400">
<el-dialog draggable title="上传文件" v-model="fileVisble" width="400">
<file-upload v-model="fileForm.tenderFiles" :limit="10" :file-type="['pdf']" :file-size="50" />
<template #footer>
<div class="dialog-footer">
@ -375,6 +304,86 @@
</div>
</template>
</el-dialog>
<el-dialog draggable title="打卡规则" v-model="ruleFlag" width="800">
<template #footer>
<el-form ref="projectFormRef" :model="form" :rules="rules" label-width="100px">
<el-row :gutter="20">
<el-col :span="12" :offset="0">
<el-form-item label="上班时间" prop="clockInTime">
<el-time-select
v-model="form.clockInTime"
style="width: 100%"
class="mr-4"
placeholder="请输入打卡开始时间"
value-format="HH:mm"
start="00:00"
step="00:15"
end="23:59"
/>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="下班时间" prop="clockOutTime">
<el-time-select
v-model="form.clockOutTime"
style="width: 100%"
:min-time="form.clockInTime"
class="mr-4"
placeholder="请输入打卡结束时间"
value-format="HH:mm"
start="00:00"
step="00:15"
end="23:59"
/>
</el-form-item>
</el-col>
<el-col :span="24" :offset="0">
<el-form-item label="打卡类型" prop="type">
<el-radio-group v-model="form.type">
<el-radio value="1" size="large">无限制</el-radio>
<el-radio value="2" size="large">范围内打卡</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="打卡类型" prop="weekday">
<el-checkbox-group v-model="form.weekday" size="small">
<el-checkbox label="星期一" value="1" />
<el-checkbox label="星期二" value="2" />
<el-checkbox label="星期三" value="3" />
<el-checkbox label="星期四" value="4" />
<el-checkbox label="星期五" value="5" />
<el-checkbox label="星期六" value="6" />
<el-checkbox label="星期日" value="7" />
</el-checkbox-group>
</el-form-item>
</el-col> </el-row
></el-form>
<div class="dialog-footer">
<el-button type="primary" @click="ruleSubmit"> 提交</el-button>
<el-button @click="ruleFlag = false">取消</el-button>
</div>
</template>
</el-dialog>
<el-dialog draggable title="打卡范围" v-model="ScopeFlag" width="600">
<div v-for="(item, i) of punchRangeList" :key="i" class="options_item">
<el-row>
<el-col :span="1"> <el-color-picker v-model="item.punchColor" show-alpha /></el-col>
<el-col :span="12"> <el-input v-model="item.punchName" placeholder="请输入打卡范围名称" class="ml-8" /></el-col>
<el-col :span="10" style="text-align: right; margin-top: 5px">
<el-button link type="primary" icon="view">预览</el-button>
<el-button link type="primary" icon="plus">添加</el-button>
<el-button link type="primary" icon="delete">移除</el-button>
</el-col>
</el-row>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="scopeSubmit"> 提交</el-button>
<el-button @click="ScopeFlag = false">取消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@ -382,14 +391,14 @@
import {
addChildProject,
addProject,
addProjectFacilities,
addProjectPilePoint,
addProjectSquare,
delProject,
uploadProjectFile,
getProject,
listProject,
updateProject
updateProject,
attendanceRuleAdd,
attendanceRuleEdit,
byProjectIdDetail
} from '@/api/project/project';
import { ProjectForm, ProjectQuery, ProjectVO, childProjectQuery, locationType } from '@/api/project/project/types';
import amap from '@/components/amap/index.vue';
@ -413,6 +422,14 @@ const polygonStatus = ref(false);
const dxfFile = ref(null);
const projectId = ref<string>('');
const designId = ref<string>('');
const ruleFlag = ref(false);
const ScopeFlag = ref(false);
const punchRangeList = ref<any>([
{
punchName: '',
punchColor: '#1983ff'
}
]);
const childProjectForm = reactive<childProjectQuery>({
projectName: '',
pid: '',
@ -432,7 +449,7 @@ const fileForm = ref({
const jsonData = ref(null);
const fullscreenLoading = ref(false);
const initFormData: ProjectForm = {
const initFormData = {
id: undefined,
projectName: undefined,
shortName: undefined,
@ -451,13 +468,15 @@ const initFormData: ProjectForm = {
lat: undefined,
plan: undefined,
onStreamTime: undefined,
playCardStart: undefined,
playCardEnd: undefined,
clockInTime: undefined,
clockOutTime: undefined,
designTotal: undefined,
securityAgreement: undefined,
sort: 0,
showHidden: undefined,
isDelete: undefined
isDelete: undefined,
type: '1',
weekday: []
};
const data = reactive<PageData<ProjectForm, ProjectQuery>>({
form: { ...initFormData },
@ -480,8 +499,6 @@ const data = reactive<PageData<ProjectForm, ProjectQuery>>({
lat: undefined,
plan: undefined,
onStreamTime: undefined,
playCardStart: undefined,
playCardEnd: undefined,
designTotal: undefined,
securityAgreement: undefined,
sort: undefined,
@ -490,8 +507,8 @@ const data = reactive<PageData<ProjectForm, ProjectQuery>>({
params: {}
},
rules: {
playCardStart: [{ required: true, message: '打卡开始时间不能为空', trigger: 'blur' }],
playCardEnd: [{ required: true, message: '打卡结束时间不能为空', trigger: 'blur' }],
clockInTime: [{ required: true, message: '打卡开始时间不能为空', trigger: 'blur' }],
clockOutTime: [{ required: true, message: '打卡结束时间不能为空', trigger: 'blur' }],
projectName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
shortName: [{ required: true, message: '项目简称不能为空', trigger: 'blur' }],
principalPhone: [{ required: true, message: '负责人电话不能为空', trigger: 'blur' }],
@ -692,7 +709,48 @@ const handleSetChild = async () => {
}
}
};
const handleScope = (row) => {
// 打卡范围
ScopeFlag.value = true;
projectId.value = row.id;
};
const scopeSubmit = () => {
// 提交打卡范围
};
// 添加规则
const handleCheckRules = async (row?: ProjectVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await byProjectIdDetail(_id);
if (res.data) {
res.data.weekday = res.data.weekday.split(',');
Object.assign(form.value, res.data);
}
projectId.value = row.id;
ruleFlag.value = true;
};
const ruleSubmit = async () => {
console.log(form.value);
projectFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
let obj = {
weekday: form.value.weekday.join(','),
projectId: projectId.value,
id: projectId.value,
clockInTime: form.value.clockInTime,
clockOutTime: form.value.clockOutTime,
type: form.value.type
};
if (form.value.id) {
await attendanceRuleEdit(obj);
} else {
await attendanceRuleAdd(obj);
}
ruleFlag.value = false;
await getList();
}
});
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(

View File

@ -0,0 +1,258 @@
<template>
<div class="p-2 editInfo">
<el-form label-position="top" ref="userFormRef" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="10">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="2"></el-col>
<el-col :span="10">
<el-form-item label="归属部门" prop="deptId">
<el-tree-select
v-model="form.deptId"
:data="enabledDeptOptions"
:props="{ value: 'id', label: 'label', children: 'children' }"
value-key="id"
placeholder="请选择归属部门"
check-strictly
@change="handleDeptChange"
/>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
</el-form-item> </el-col
><el-col :span="2"></el-col>
<el-col :span="10">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
</el-form-item> </el-col
><el-col :span="2"></el-col>
<el-col :span="10">
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择">
<el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item> </el-col
><el-col :span="2"></el-col>
<el-col :span="10">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择">
<el-option
v-for="item in postOptions"
:key="item.postId"
:label="item.postName"
:value="item.postId"
:disabled="item.status == '1'"
></el-option>
</el-select>
</el-form-item> </el-col
><el-col :span="2"></el-col>
<el-col :span="10">
<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-col>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- <div class="box_submit">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel()"> </el-button>
</div> -->
</div>
</template>
<script setup name="Profile" lang="ts">
import api from '@/api/system/user';
import { listProject } from '@/api/project/project';
import { getProjectByDeptId, getRoleList, optionselect } from '@/api/system/post';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
const enabledDeptOptions = ref([]);
const deptOptions = ref([]);
const projectOptions = ref<any[]>([]);
const postOptions = ref([]);
const roleOptions = ref([]);
const userFormRef = ref<ElFormInstance>();
const initFormData = {
userId: undefined,
deptId: undefined,
userName: '',
nickName: undefined,
password: '',
phonenumber: undefined,
email: undefined,
sex: undefined,
projectRoles: [
{
projectId: '',
roleIds: []
}
],
status: '0',
remark: '',
postIds: [],
filePath: undefined
};
const initData = {
form: { ...initFormData },
rules: {
userName: [
{ required: true, message: '用户名称不能为空', trigger: 'blur' },
{
min: 2,
max: 20,
message: '用户名称长度必须介于 2 和 20 之间',
trigger: 'blur'
}
],
nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
password: [
{ required: true, message: '用户密码不能为空', trigger: 'blur' },
{
min: 5,
max: 20,
message: '用户密码长度必须介于 5 和 20 之间',
trigger: 'blur'
},
{ pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' }
],
email: [
{
type: 'email',
message: '请输入正确的邮箱地址',
trigger: ['blur', 'change']
}
],
phonenumber: [
{ required: true, message: '请输入手机号码', trigger: 'blur' },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: '请输入正确的手机号码',
trigger: 'blur'
}
]
}
};
const data = reactive(initData);
const { form, rules } = toRefs(data);
/** 查询部门下拉树结构 */
const getDeptTree = async () => {
const res = await api.deptTreeSelect({ isShow: '1' });
deptOptions.value = res.data;
enabledDeptOptions.value = filterDisabledDept(res.data);
const projectList = await listProject();
projectOptions.value = projectList.rows;
};
/** 过滤禁用的部门 */
const filterDisabledDept = (deptList) => {
return deptList.filter((dept) => {
if (dept.disabled) {
return false;
}
if (dept.children && dept.children.length) {
dept.children = filterDisabledDept(dept.children);
}
return true;
});
};
async function handleDeptChange(value: number | string) {
proxy?.$emit('setDeptId', value);
const response = await optionselect(value);
const roleList = await getRoleList(value);
roleOptions.value = roleList.data;
postOptions.value = response.data;
form.value.postIds = [];
form.value.projectRoles = [
{
projectId: '',
roleIds: []
}
];
}
const submitForm = () => {
userFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
proxy?.$modal.msgSuccess('操作成功');
proxy?.$emit('submit', false);
}
});
};
const cancel = () => {
proxy?.$emit('close', false);
};
/** 重置操作表单 */
const reset = () => {
form.value = { ...initFormData };
form.value.projectRoles = [
{
projectId: '',
roleIds: []
}
];
userFormRef.value?.resetFields();
};
// 打开弹框调用参数
const open = async (row?: any) => {
reset();
if (row) {
// 编辑
const { data } = await api.getUser(row.userId);
Object.assign(form.value, data.user);
postOptions.value = data.posts;
roleOptions.value = data.roles;
form.value.postIds = data.postIds;
form.value.projectRoles = data.projectRoles;
form.value.password = '';
const roleList = await getRoleList(form.value.deptId);
roleOptions.value = roleList.data;
} else {
// 新增
const { data } = await api.getUser();
postOptions.value = data.posts;
}
};
const getInfoForm = () => {
return form.value;
};
onMounted(() => {
getDeptTree();
});
defineExpose({ open, getInfoForm });
</script>
<style lang="scss" scoped>
.editInfo {
position: relative;
height: 100%;
.box_submit {
position: absolute;
right: 10px;
bottom: 10px;
}
}
</style>

View File

@ -0,0 +1,477 @@
<template>
<div class="roleInfo">
<div class="title_detail">
<span>当前选定角色信息预览</span>
<div style="margin-top: 10px">
<el-table :data="roleList" border height="150">
<el-table-column label="所属部门" align="center" prop="deptName" />
<el-table-column label="关联项目" align="center" prop="projectName" />
<el-table-column label="web端担任角色" align="center" prop="webRoles" />
<el-table-column label="APP端担任角色" align="center" prop="appRoles" />
</el-table>
</div>
</div>
<div class="title_detail" style="margin-top: 20px">
<span>选择或修改当前角色信息</span>
<div style="margin-top: 10px" class="box_detail">
<!-- 项目列表选择区 -->
<div class="project_list">
<span>关联项目模块</span>
<div class="project-items">
<div
v-for="item in projectOptions"
:key="item.id"
class="project-item"
:class="{ 'project-item-selected': isProjectSelected(item.id) }"
@click="toggleProjectSelection(item)"
>
<div class="project-item-content">
<el-checkbox v-model="item.checked" :value="item.id" class="project-checkbox" @change="handleProjectCheck(item, $event)" />
<span class="project-name">{{ item.projectName }}</span>
</div>
</div>
</div>
</div>
<!-- 角色分配区 -->
<div class="post_list">
<span>关联项目角色分配</span>
<div v-if="selectedProjects.length === 0" class="no-selection">请从左侧选择项目进行角色分配</div>
<div v-for="(project, index) in selectedProjects" :key="project.id" class="project-role-container">
<div class="project-header">
<span class="project-title">{{ project.projectName }}</span>
<el-button type="text" class="remove-project" @click="removeProject(project.id)"> 移除 </el-button>
</div>
<div class="role-assignment">
<div class="role-group">
<label class="role-label">web端角色</label>
<el-checkbox-group v-model="project.webRoles" @change="updateRoleList">
<el-checkbox v-for="role in allRoles" :key="role.roleId" :value="role.roleId">
{{ role.roleName }}
</el-checkbox>
</el-checkbox-group>
</div>
<div class="role-group">
<label class="role-label">APP端角色</label>
<el-checkbox-group v-model="project.appRoles" @change="updateRoleList">
<el-checkbox v-for="role in AppRoles" :key="role.roleId" :value="role.roleId">
{{ role.roleName }}
</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="box_submit">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel()"> </el-button>
</div>
</div>
</template>
<script setup name="RoleProjectManagement" lang="ts">
import { ref, reactive, toRefs, getCurrentInstance, ComponentInternalInstance, defineExpose, watch } from 'vue';
import { ElFormInstance } from 'element-plus';
import api from '@/api/system/user';
import { listProject } from '@/api/project/project';
import { getRoleList } from '@/api/system/post';
// 类型定义
interface Project {
id: number | string;
projectName: string;
checked: boolean;
webRoles: string[];
appRoles: string[];
}
interface Role {
roleId: number | string;
roleName: string;
roleSort?: number;
}
interface RoleInfo {
userNick: string;
deptName: string;
postName: string;
projectName: string;
webRoles: string;
appRoles: string;
}
// 组件实例
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 响应式数据
const projectOptions = ref<Project[]>([]);
const selectedProjects = ref<Project[]>([]);
const allRoles = ref<Role[]>([]); // web端角色
const AppRoles = ref<Role[]>([]); // APP端角色
const roleList = ref<RoleInfo[]>([]);
// 表单初始数据
const initFormData = {
userId: undefined,
deptId: undefined,
userName: '',
nickName: undefined,
password: '',
phonenumber: undefined,
email: undefined,
sex: undefined,
projectRoles: [] as Array<{ projectId: number | string; webRoles: string[]; appRoles: string[] }>,
status: '0',
remark: '',
postIds: [],
filePath: undefined,
deptName: '' // 新增部门名称字段
};
const data = reactive({
form: { ...initFormData }
});
const deptName = ref('');
const { form } = toRefs(data);
// 核心方法:更新预览列表
const updateRoleList = () => {
if (selectedProjects.value.length === 0) {
roleList.value = [];
return;
}
roleList.value = selectedProjects.value.map((project) => {
// 处理web端角色名称
var webRoleNames = project.webRoles
.map((roleId) => {
const role = allRoles.value.find((r) => r.roleId === roleId);
return role ? role.roleName : '';
})
.filter(Boolean);
// 处理APP端角色名称
var appRoleNames = project.appRoles
.map((roleId) => {
const role = AppRoles.value.find((r) => r.roleId === roleId);
return role ? role.roleName : '';
})
.filter(Boolean);
webRoleNames = [...new Set(webRoleNames)];
appRoleNames = [...new Set(appRoleNames)];
return {
deptName: deptName.value,
projectName: project.projectName,
webRoles: webRoleNames.length > 0 ? webRoleNames.join('') : '无',
appRoles: appRoleNames.length > 0 ? appRoleNames.join('') : '无'
};
});
};
// 监听已选项目变化,自动更新预览列表
watch(
selectedProjects,
() => {
updateRoleList();
},
{ deep: true }
);
// 检查项目是否被选中
const isProjectSelected = (projectId: number | string) => {
return selectedProjects.value.some((p) => p.id === projectId);
};
// 切换项目选择状态
const toggleProjectSelection = (project: Project) => {
// handleProjectCheck(project, !project.checked);
};
// 处理项目勾选状态变化
const handleProjectCheck = (project: Project, checked: boolean) => {
// project.checked = checked;
const index = selectedProjects.value.findIndex((p) => p.id === project.id);
if (checked && index === -1) {
// 添加选中的项目
selectedProjects.value.push({
...project,
webRoles: [],
appRoles: []
});
} else if (!checked && index !== -1) {
// 移除取消选中的项目
selectedProjects.value.splice(index, 1);
}
};
// 移除项目
const removeProject = (projectId: number | string) => {
// 更新选中项目列表
selectedProjects.value = selectedProjects.value.filter((p) => p.id !== projectId);
// 更新项目选项的勾选状态
const project = projectOptions.value.find((p) => p.id === projectId);
if (project) {
project.checked = false;
}
};
// 提交表单
const submitForm = async () => {
// 整理项目角色数据
form.value.projectRoles = selectedProjects.value.map((project) => ({
projectId: project.id,
roleIds: [...new Set(project.webRoles), ...new Set(project.appRoles)]
}));
// 提交数据
try {
if (form.value.userId) {
await api.updateUser(form.value);
} else {
await api.addUser(form.value);
}
proxy?.$modal.msgSuccess('操作成功');
proxy?.$emit('submit', form.value);
cancel();
} catch (error) {
proxy?.$modal.msgError('操作失败,请重试');
console.error('提交失败:', error);
}
};
// 取消操作
const cancel = () => {
resetForm();
proxy?.$emit('close');
};
// 重置表单
const resetForm = () => {
data.form = { ...initFormData };
projectOptions.value.forEach((p) => (p.checked = false));
selectedProjects.value = [];
roleList.value = [];
};
// 初始化数据
const initData = async () => {
try {
// 获取项目列表
const projectRes = await listProject();
projectOptions.value = projectRes.rows.map((item: any) => ({
id: item.id,
projectName: item.projectName,
checked: false
}));
} catch (error) {
proxy?.$modal.msgError('数据加载失败');
console.error('初始化数据失败:', error);
}
};
// 打开弹窗时调用
const open = async (row?: any, deptId?: any) => {
resetForm();
await initData();
deptName.value = row.deptName;
console.log(row);
if (row) {
try {
if (!row.createTime) {
form.value = { ...row };
// 获取角色列表
if (form.value.deptId) {
deptId = form.value.deptId;
}
const roleRes = await getRoleList(deptId);
allRoles.value = roleRes.data.filter((item: Role) => item.roleSort === 1);
AppRoles.value = roleRes.data.filter((item: Role) => item.roleSort !== 1);
} else {
const { data } = await api.getUser(row.userId);
Object.assign(form.value, data.user);
// 获取角色列表
if (form.value.deptId) {
deptId = form.value.deptId;
}
const roleRes = await getRoleList(deptId);
// 区分web端和app端角色
allRoles.value = roleRes.data.filter((item: Role) => item.roleSort === 1);
AppRoles.value = roleRes.data.filter((item: Role) => item.roleSort !== 1);
// 加载项目角色数据
if (data.projectRoles && data.projectRoles.length) {
data.projectRoles.forEach((pr: any) => {
const project = projectOptions.value.find((p) => p.id === pr.projectId);
if (project) {
project.checked = true;
selectedProjects.value.push({
...project,
webRoles: pr.roleIds || [],
appRoles: pr.roleIds || []
});
}
});
}
}
} catch (error) {
proxy?.$modal.msgError('加载用户数据失败');
console.error('加载用户数据失败:', error);
}
}
};
// 暴露方法
defineExpose({ open });
</script>
<style lang="scss">
.roleInfo {
position: relative;
height: 100%;
padding-bottom: 60px;
box-sizing: border-box;
.title_detail {
> span {
font-size: 16px;
font-weight: 600;
color: #333;
display: inline-block;
padding-bottom: 5px;
border-bottom: 2px solid #409eff;
}
.box_detail {
display: flex;
gap: 15px;
margin-top: 15px;
> div {
height: 350px;
padding: 15px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
overflow-y: auto;
box-sizing: border-box;
}
.project_list {
width: 320px;
background-color: #fff;
.project-items {
margin-top: 10px;
}
.project-item {
padding: 10px 12px;
margin-bottom: 8px;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
border: 1px solid #eee;
&:hover {
background-color: #f5f7fa;
border-color: #e4e7ed;
}
.project-item-content {
display: flex;
align-items: center;
}
.project-checkbox {
margin-right: 8px;
}
.project-name {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.project-item-selected {
background-color: #ecf5ff;
border-color: #c6e2ff;
}
}
.post_list {
flex: 1;
background-color: #fff;
.no-selection {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: #909399;
font-size: 14px;
}
.project-role-container {
padding: 15px;
margin-bottom: 15px;
background-color: #f9f9f9;
border-radius: 4px;
border: 1px solid #f0f0f0;
.project-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
.project-title {
font-weight: 500;
color: #333;
font-size: 14px;
}
.remove-project {
color: #f56c6c;
padding: 0 5px;
&:hover {
color: #e4393c;
}
}
}
.role-assignment {
.role-group {
margin-bottom: 15px;
.role-label {
display: inline-block;
width: 110px;
color: #606266;
font-size: 14px;
}
.el-checkbox-group {
display: inline-block;
margin-left: 10px;
.el-checkbox {
margin-right: 15px;
margin-bottom: 8px;
}
}
}
}
}
}
}
}
.box_submit {
position: absolute;
right: 20px;
bottom: 0px;
display: flex;
gap: 10px;
}
}
</style>

View File

@ -0,0 +1,788 @@
<template>
<div class="p-2">
<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">
<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="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 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 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-button type="primary" icon="Search" @click="handleQuery" @v-has-permi="['system:user:query']">搜索</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-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()"> 新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-dropdown class="mt-[1px]">
<el-button plain type="info">
更多
<el-icon class="el-icon--right">
<arrow-down />
</el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:import']" icon="Top" @click="handleImport">导入数据 </el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:export']" icon="Download" @click="handleExport"> 导出数据 </el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-col>
<right-toolbar v-model:show-search="showSearch" :columns="columns" :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="50" align="center" />
<el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
<el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
<el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
<el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
<el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" />
<el-table-column v-if="columns[5].visible" key="status" label="状态" align="center">
<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 v-if="columns[6].visible" label="创建时间" align="center" prop="createTime" width="160">
<template #default="scope">
<span>{{ scope.row.createTime }}</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="230" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top">
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top">
<el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top">
<el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top">
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="编辑关联项目" placement="top">
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdateProject(scope.row)"></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="上传证书目录" placement="top">
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Upload" @click="handleUploadCert(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<el-dialog v-model="shuttleVisible" title="编辑关联项目" width="auto" destroy-on-close>
<shuttle-frame :userId="selectedUserId" @close="shuttleVisible = false" />
</el-dialog>
<pagination
v-show="total > 0"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
:total="total"
@pagination="getList"
/>
</el-card>
</el-col>
</el-row>
<!-- 添加或修改用户配置对话框 -->
<el-dialog draggable ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body @close="closeDialog">
<el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="归属部门" prop="deptId">
<el-tree-select
v-model="form.deptId"
:data="enabledDeptOptions"
:props="{ value: 'id', label: 'label', children: 'children' }"
value-key="id"
placeholder="请选择归属部门"
check-strictly
@change="handleDeptChange"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择">
<el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择">
<el-option
v-for="item in postOptions"
:key="item.postId"
:label="item.postName"
:value="item.postId"
:disabled="item.status == '1'"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-row :gutter="20" v-for="(item, index) in form.projectRoles">
<el-col :span="11" :offset="0">
<el-form-item label="项目列表">
<el-select v-model="item.projectId" placeholder="请选择">
<el-option v-for="dict in projectOptions" :key="dict.id" :label="dict.shortName" :value="dict.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="11" :offset="0">
<el-form-item label="角色">
<el-select v-model="item.roleIds" filterable multiple placeholder="请选择">
<el-option
v-for="item in roleOptions"
:key="item.roleId"
:label="item.roleName"
:value="item.roleId"
:disabled="item.status == '1'"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="1" :offset="0">
<el-button type="primary" circle icon="Plus" @click="handleAddProject" v-if="index == 0"></el-button>
<el-button type="danger" circle icon="Delete" @click="delProject(index)" v-else></el-button>
</el-col>
</el-row>
</el-col>
<el-col :span="12">
<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-col>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</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>
<!-- 用户导入对话框 -->
<el-dialog draggable v-model="upload.open" :title="upload.title" width="400px" append-to-body>
<el-upload
ref="uploadRef"
:limit="1"
accept=".xlsx, .xls"
:headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:auto-upload="false"
drag
>
<el-icon class="el-icon--upload">
<i-ep-upload-filled />
</el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="text-center el-upload__tip">
<div class="el-upload__tip">
<el-checkbox v-model="upload.updateSupport" />
是否更新已经存在的用户数据
</div>
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板 </el-link>
</div>
</template>
</el-upload>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</template>
</el-dialog>
<el-dialog title="上传证书目录" v-model="certDialog" width="30%" destroy-on-close>
<!-- <File-upload v-model="fileUpload" :limit="5"></File-upload> -->
<ImageUpload v-model="fileUpload" :limit="5"></ImageUpload>
<template #footer>
<span>
<el-button @click="certDialog = false">取消</el-button>
<el-button type="primary" @click="uploadCert">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup name="User" lang="ts">
import api, { uploadCertList } from '@/api/system/user';
import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
import { RoleVO } from '@/api/system/role/types';
import { PostVO } from '@/api/system/post/types';
import { globalHeaders } from '@/utils/request';
import { to } from 'await-to-js';
import { getProjectByDeptId, getRoleList, optionselect } from '@/api/system/post';
import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue';
import { listProject } from '@/api/project/project';
import editInfo from './comm/editInfo.vue';
const router = useRouter();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
const userList = ref<UserVO[]>();
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<number | string>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const deptName = ref('');
const deptOptions = ref<DeptTreeVO[]>([]);
const enabledDeptOptions = ref<DeptTreeVO[]>([]);
const initPassword = ref<string>('');
const postOptions = ref<PostVO[]>([]);
const roleOptions = ref<RoleVO[]>([]);
const projectOptions = ref<any[]>([]);
/*** 用户导入参数 */
const upload = reactive<ImportOption>({
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: '',
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: globalHeaders(),
// 上传的地址
url: import.meta.env.VITE_APP_BASE_API + '/system/user/importData'
});
// 列显隐信息
const columns = ref<FieldOption[]>([
{ key: 0, label: `用户编号`, visible: false, children: [] },
{ key: 1, label: `用户名称`, visible: true, children: [] },
{ key: 2, label: `用户昵称`, visible: true, children: [] },
{ key: 3, label: `部门`, visible: true, children: [] },
{ key: 4, label: `手机号码`, visible: true, children: [] },
{ key: 5, label: `状态`, visible: true, children: [] },
{ key: 6, label: `创建时间`, visible: true, children: [] }
]);
const deptTreeRef = ref<ElTreeInstance>();
const queryFormRef = ref<ElFormInstance>();
const userFormRef = ref<ElFormInstance>();
const uploadRef = ref<ElUploadInstance>();
const formDialogRef = ref<ElDialogInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: UserForm = {
userId: undefined,
deptId: undefined,
userName: '',
nickName: undefined,
password: '',
phonenumber: undefined,
email: undefined,
sex: undefined,
projectRoles: [
{
projectId: '',
roleIds: []
}
],
status: '0',
remark: '',
postIds: [],
filePath: undefined
};
const initData: PageData<UserForm, UserQuery> = {
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
userName: '',
phonenumber: '',
status: '',
deptId: '',
roleId: ''
},
rules: {
userName: [
{ required: true, message: '用户名称不能为空', trigger: 'blur' },
{
min: 2,
max: 20,
message: '用户名称长度必须介于 2 和 20 之间',
trigger: 'blur'
}
],
nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
password: [
{ required: true, message: '用户密码不能为空', trigger: 'blur' },
{
min: 5,
max: 20,
message: '用户密码长度必须介于 5 和 20 之间',
trigger: 'blur'
},
{ pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' }
],
email: [
{
type: 'email',
message: '请输入正确的邮箱地址',
trigger: ['blur', 'change']
}
],
phonenumber: [
{ required: true, message: '请输入手机号码', trigger: 'blur' },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: '请输入正确的手机号码',
trigger: 'blur'
}
]
}
};
const data = reactive<PageData<UserForm, UserQuery>>(initData);
const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data);
/** 通过条件过滤节点 */
const filterNode = (value: string, data: any) => {
if (!value) return true;
return data.label.indexOf(value) !== -1;
};
/** 根据名称筛选部门树 */
watchEffect(
() => {
deptTreeRef.value?.filter(deptName.value);
},
{
flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发此属性控制在DOM元素更新后运行
}
);
/** 查询用户列表 */
const getList = async () => {
loading.value = true;
const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
loading.value = false;
userList.value = res.rows;
total.value = res.total;
};
/** 查询部门下拉树结构 */
const getDeptTree = async () => {
const res = await api.deptTreeSelect({ isShow: '1' });
deptOptions.value = res.data;
enabledDeptOptions.value = filterDisabledDept(res.data);
const projectList = await listProject();
projectOptions.value = projectList.rows;
};
/** 过滤禁用的部门 */
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;
});
};
/** 节点单击事件 */
const handleNodeClick = (data: DeptVO) => {
queryParams.value.deptId = data.id;
handleQuery();
};
/** 部门选择变化 */
const handleAddProject = () => {
form.value.projectRoles.push({
projectId: '',
roleIds: []
});
};
/** 删除项目 */
const delProject = (index: number) => {
form.value.projectRoles.splice(index, 1);
};
/** 搜索按钮操作 */
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?: UserVO) => {
const userIds = row?.userId || ids.value;
const [err] = await to(proxy?.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') as any);
if (!err) {
await api.delUser(userIds);
await getList();
proxy?.$modal.msgSuccess('删除成功');
}
};
/** 用户状态修改 */
const handleStatusChange = async (row: UserVO) => {
let text = row.status === '0' ? '启用' : '停用';
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
await api.changeUserStatus(row.userId, row.status);
proxy?.$modal.msgSuccess(text + '成功');
} catch (err) {
row.status = row.status === '0' ? '1' : '0';
}
};
/** 跳转角色分配 */
const handleAuthRole = (row: UserVO) => {
const userId = row.userId;
router.push('/system/user-auth/role/' + userId);
};
/** 重置密码按钮操作 */
const handleResetPwd = async (row: UserVO) => {
const [err, res] = await to(
ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: '用户密码长度必须介于 5 和 20 之间',
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return '不能包含非法字符:< > " \' \\ |';
}
}
})
);
if (!err && res) {
await api.resetUserPwd(row.userId, res.value);
proxy?.$modal.msgSuccess('修改成功,新密码是:' + res.value);
}
};
/** 选择条数 */
const handleSelectionChange = (selection: UserVO[]) => {
ids.value = selection.map((item) => item.userId);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 导入按钮操作 */
const handleImport = () => {
upload.title = '用户导入';
upload.open = true;
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'system/user/export',
{
...queryParams.value
},
`user_${new Date().getTime()}.xlsx`
);
};
/** 下载模板操作 */
const importTemplate = () => {
proxy?.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`);
};
/**文件上传中处理 */
const handleFileUploadProgress = () => {
upload.isUploading = true;
};
/** 文件上传成功处理 */
const handleFileSuccess = (response: any, file: UploadFile) => {
upload.open = false;
upload.isUploading = false;
uploadRef.value?.handleRemove(file);
ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
dangerouslyUseHTMLString: true
});
getList();
};
/** 提交上传文件 */
function submitFileForm() {
uploadRef.value?.submit();
}
/** 重置操作表单 */
const reset = () => {
form.value = { ...initFormData };
form.value.projectRoles = [
{
projectId: '',
roleIds: []
}
];
userFormRef.value?.resetFields();
};
/** 取消按钮 */
const cancel = () => {
dialog.visible = false;
reset();
};
/** 新增按钮操作 */
const handleAdd = async () => {
reset();
const { data } = await api.getUser();
dialog.visible = true;
dialog.title = '新增用户';
postOptions.value = data.posts;
form.value.password = initPassword.value.toString();
};
/** 修改按钮操作 */
const handleUpdate = async (row?: UserForm) => {
reset();
const userId = row?.userId || ids.value[0];
const { data } = await api.getUser(userId);
dialog.visible = true;
dialog.title = '修改用户';
Object.assign(form.value, data.user);
postOptions.value = data.posts;
roleOptions.value = data.roles;
form.value.postIds = data.postIds;
form.value.projectRoles = data.projectRoles;
form.value.password = '';
const roleList = await getRoleList(form.value.deptId);
roleOptions.value = roleList.data;
};
const validate = () => {
for (let i = 0; i < form.value.projectRoles.length; i++) {
const item = form.value.projectRoles[i];
if (!item.projectId || item.projectId.length === 0) {
proxy?.$modal.msgError(`${i + 1} 行“项目列表”未填写`);
return false; // 阻止提交
}
if (!item.roleIds || item.roleIds.length === 0) {
proxy?.$modal.msgError(`${i + 1} 行“角色”未填写`);
return false; // 阻止提交
}
}
return true;
};
/** 提交按钮 */
const submitForm = () => {
const isValid = validate();
if (!isValid) return;
userFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/**
* 关闭用户弹窗
*/
const closeDialog = () => {
dialog.visible = false;
resetForm();
};
/**
* 重置表单
*/
const resetForm = () => {
userFormRef.value?.resetFields();
userFormRef.value?.clearValidate();
form.value.id = undefined;
form.value.status = '1';
};
onMounted(() => {
getDeptTree(); // 初始化部门数据
getList(); // 初始化列表数据
proxy?.getConfigKey('sys.user.initPassword').then((response) => {
initPassword.value = response.data;
});
});
async function handleDeptChange(value: number | string) {
const response = await optionselect(value);
const roleList = await getRoleList(value);
roleOptions.value = roleList.data;
postOptions.value = response.data;
form.value.postIds = [];
form.value.projectRoles = [
{
projectId: [],
roleIds: []
}
];
}
const shuttleVisible = ref(false);
const selectedUserId = ref<number>();
const handleUpdateProject = (row) => {
if (row) {
selectedUserId.value = row.userId;
shuttleVisible.value = true;
}
};
const certDialog = ref(false);
const certId = ref<string | number>(undefined);
const fileUpload = ref<string>();
//上传证书
const handleUploadCert = (row: UserVO) => {
certId.value = row.userId;
fileUpload.value = row.filePath;
certDialog.value = true;
};
const uploadCert = async () => {
if (!fileUpload.value) {
proxy?.$modal.msgError('请上传证书目录');
return;
}
let res = await uploadCertList({
userId: certId.value,
fileId: fileUpload.value
});
console.log(res);
certDialog.value = false;
proxy?.$modal.msgSuccess('上传证书目录成功');
};
</script>
<style lang="scss" scoped></style>

View File

@ -5,14 +5,22 @@
<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-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">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<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">
@ -20,24 +28,27 @@
<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-input v-model="queryParams.phonenumber" 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-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 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-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-button type="primary" icon="Search" @click="handleQuery"
@v-has-permi="['system:user:query']">搜索</el-button>
<el-button type="primary" icon="Search" @click="handleQuery" @v-has-permi="['system:user:query']">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
@ -50,18 +61,15 @@
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
<el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()"> 新增
</el-button>
<el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()"> 新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit"
@click="handleUpdate()">
<el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete"
@click="handleDelete()">
<el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
删除
</el-button>
</el-col>
@ -76,34 +84,26 @@
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:import']" icon="Top" @click="handleImport">导入数据
</el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:export']" icon="Download" @click="handleExport"> 导出数据
</el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:import']" icon="Top" @click="handleImport">导入数据 </el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:export']" icon="Download" @click="handleExport"> 导出数据 </el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-col>
<right-toolbar v-model:show-search="showSearch" :columns="columns" :search="true"
@query-table="getList"></right-toolbar>
<right-toolbar v-model:show-search="showSearch" :columns="columns" :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="50" align="center" />
<el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
<el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName"
:show-overflow-tooltip="true" />
<el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName"
:show-overflow-tooltip="true" />
<el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName"
:show-overflow-tooltip="true" />
<el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber"
width="120" />
<el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
<el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
<el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
<el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" />
<el-table-column v-if="columns[5].visible" key="status" label="状态" align="center">
<template #default="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
@change="handleStatusChange(scope.row)"></el-switch>
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
@ -116,30 +116,24 @@
<el-table-column label="操作" fixed="right" width="230" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top">
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit"
@click="handleUpdate(scope.row)"></el-button>
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top">
<el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete"
@click="handleDelete(scope.row)"></el-button>
<el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top">
<el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key"
@click="handleResetPwd(scope.row)"></el-button>
<el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top">
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck"
@click="handleAuthRole(scope.row)"></el-button>
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="编辑关联项目" placement="top">
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit"
@click="handleUpdateProject(scope.row)"></el-button>
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdateProject(scope.row)"></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="上传证书目录" placement="top">
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Upload"
@click="handleUploadCert(scope.row)"></el-button>
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Upload" @click="handleUploadCert(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
@ -148,117 +142,47 @@
<shuttle-frame :userId="selectedUserId" @close="shuttleVisible = false" />
</el-dialog>
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
:total="total" @pagination="getList" />
<pagination
v-show="total > 0"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
:total="total"
@pagination="getList"
/>
</el-card>
</el-col>
</el-row>
<!-- 添加或修改用户配置对话框 -->
<el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body
@close="closeDialog">
<el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="归属部门" prop="deptId">
<el-tree-select v-model="form.deptId" :data="enabledDeptOptions"
:props="{ value: 'id', label: 'label', children: 'children' }" value-key="id" placeholder="请选择归属部门"
check-strictly @change="handleDeptChange" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择">
<el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label"
:value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择">
<el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId"
:disabled="item.status == '1'"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-row :gutter="20" v-for="(item, index) in form.projectRoles">
<el-col :span="11" :offset="0">
<el-form-item label="项目列表">
<el-select v-model="item.projectId" placeholder="请选择">
<el-option v-for="dict in projectOptions" :key="dict.id" :label="dict.shortName"
:value="dict.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="11" :offset="0">
<el-form-item label="角色">
<el-select v-model="item.roleIds" filterable multiple placeholder="请选择">
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName"
:value="item.roleId" :disabled="item.status == '1'"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="1" :offset="0">
<el-button type="primary" circle icon="Plus" @click="handleAddProject" v-if="index == 0"></el-button>
<el-button type="danger" circle icon="Delete" @click="delProject(index)" v-else></el-button>
</el-col>
</el-row>
</el-col>
<el-col :span="12">
<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-col>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</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>
<el-dialog draggable ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="1300px" append-to-body @close="closeDialog">
<div class="boxDetial">
<div class="tab_info">
<span @click="onTab(1)" :class="{ active: type == 1 }">基本资料</span>
<span @click="onTab(2)" :class="{ active: type == 2 }">角色信息</span>
</div>
<div class="tab_content" v-show="type == 1">
<editInfo ref="editInfoRef" @close="dialog.visible = false" @submit="getList" @setDeptId="setDeptId"></editInfo>
</div>
<div class="tab_content" v-show="type == 2">
<roleInfo ref="roleInfoRef" @close="dialog.visible = false" @submit="getList"></roleInfo>
</div>
</div>
</template>
</el-dialog>
<!-- 用户导入对话框 -->
<el-dialog draggable v-model="upload.open" :title="upload.title" width="400px" append-to-body>
<el-upload ref="uploadRef" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
:on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<el-upload
ref="uploadRef"
:limit="1"
accept=".xlsx, .xls"
:headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:auto-upload="false"
drag
>
<el-icon class="el-icon--upload">
<i-ep-upload-filled />
</el-icon>
@ -270,8 +194,7 @@
是否更新已经存在的用户数据
</div>
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline"
@click="importTemplate">下载模板 </el-link>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板 </el-link>
</div>
</template>
</el-upload>
@ -307,7 +230,8 @@ import { to } from 'await-to-js';
import { getProjectByDeptId, getRoleList, optionselect } from '@/api/system/post';
import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue';
import { listProject } from '@/api/project/project';
import editInfo from './comm/editInfo.vue';
import roleInfo from './comm/roleInfo.vue';
const router = useRouter();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
@ -326,7 +250,8 @@ const initPassword = ref<string>('');
const postOptions = ref<PostVO[]>([]);
const roleOptions = ref<RoleVO[]>([]);
const projectOptions = ref<any[]>([]);
const editInfoRef = ref<InstanceType<typeof editInfo> | null>(null);
const roleInfoRef = ref<InstanceType<typeof roleInfo> | null>(null);
/*** 用户导入参数 */
const upload = reactive<ImportOption>({
// 是否显示弹出层(用户导入)
@ -358,7 +283,8 @@ const queryFormRef = ref<ElFormInstance>();
const userFormRef = ref<ElFormInstance>();
const uploadRef = ref<ElUploadInstance>();
const formDialogRef = ref<ElDialogInstance>();
const deptIdRole = ref<number>();
const type = ref(1);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
@ -452,7 +378,9 @@ watchEffect(
flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发此属性控制在DOM元素更新后运行
}
);
const setDeptId = (deptId: number) => {
deptIdRole.value = deptId;
};
/** 查询用户列表 */
const getList = async () => {
loading.value = true;
@ -637,8 +565,12 @@ const cancel = () => {
const handleAdd = async () => {
reset();
const { data } = await api.getUser();
type.value = 1;
dialog.visible = true;
dialog.title = '新增用户';
nextTick(() => {
editInfoRef.value?.open();
});
postOptions.value = data.posts;
form.value.password = initPassword.value.toString();
};
@ -646,19 +578,13 @@ const handleAdd = async () => {
/** 修改按钮操作 */
const handleUpdate = async (row?: UserForm) => {
reset();
const userId = row?.userId || ids.value[0];
const { data } = await api.getUser(userId);
dialog.visible = true;
dialog.title = '修改用户';
Object.assign(form.value, data.user);
postOptions.value = data.posts;
roleOptions.value = data.roles;
form.value.postIds = data.postIds;
form.value.projectRoles = data.projectRoles;
form.value.password = '';
const roleList = await getRoleList(form.value.deptId);
roleOptions.value = roleList.data;
type.value = 1;
form.value = row;
nextTick(() => {
editInfoRef.value?.open(row);
});
};
const validate = () => {
@ -764,6 +690,46 @@ const uploadCert = async () => {
certDialog.value = false;
proxy?.$modal.msgSuccess('上传证书目录成功');
};
const onTab = (val) => {
type.value = val;
if (val == 2) {
let obj = editInfoRef.value?.getInfoForm();
form.value = obj;
nextTick(() => {
roleInfoRef.value?.open(form.value, deptIdRole.value);
});
}
};
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.boxDetial {
display: flex;
justify-content: space-between;
align-items: center;
height: 680px;
.tab_info {
height: 100%;
width: 200px;
background: #f0f2f5;
padding: 10px;
text-align: center;
display: flex;
flex-direction: column;
font-size: 18px;
> span {
margin-bottom: 10px;
cursor: pointer;
}
.active {
color: #1890ff;
}
}
.tab_content {
height: 100%;
width: calc(100% - 200px);
padding: 20px 10px;
background: #ccc;
}
}
</style>

View File

@ -10,7 +10,7 @@
<el-option v-for="item in options" :key="item.versions" :label="item.versions" :value="item.versions" />
</el-select>
</el-form-item>
<el-form-item label="表名" prop="sheet">
<el-form-item label="表名" prop="sheet" v-if="activeTab != '3'">
<el-select v-model="queryForm.sheet" placeholder="选择表名" @change="changeSheet">
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
</el-select>
@ -139,7 +139,7 @@ const sheets = ref([]);
const options = ref([]);
const tableData = ref([]);
const tableRef = ref();
const isExpandAll = ref(false);
const isExpandAll = ref(true);
const loading = ref(false);
const versionMap = new Map();

View File

@ -191,9 +191,14 @@
<el-table-column prop="useQuantity" label="剩余量" align="center">
<template #default="scope">
{{
(scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) == 0
(scope.row.quantity ? Number(scope.row.quantity) : 0) -
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) -
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) ==
0
? ''
: (scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
: (scope.row.quantity ? Number(scope.row.quantity) : 0) -
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) -
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
}}
</template>
</el-table-column>
@ -219,12 +224,16 @@
<el-table-column prop="price" label="总价" align="center">
<template #default="scope">
{{
((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) *
((scope.row.quantity ? Number(scope.row.quantity) : 0) -
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) -
(scope.row.selectNum ? Number(scope.row.selectNum) : 0)) *
Number(scope.row.unitPrice) ==
0
? ''
: (
((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) *
((scope.row.quantity ? Number(scope.row.quantity) : 0) -
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) -
(scope.row.selectNum ? Number(scope.row.selectNum) : 0)) *
Number(scope.row.unitPrice)
).toFixed(2)
}}
@ -459,19 +468,11 @@ const getSheetName = async () => {
treeForm.value.sheet = res.data[0];
} else {
treeForm.value.sheet = '';
ElMessage({
message: '获取表名失败',
type: 'warning'
});
}
getTreeList();
}
} catch (error) {
console.log(error);
ElMessage({
message: '获取表名失败',
type: 'warning'
});
}
};
const handleSelection = (selection: any) => {

View File

@ -234,17 +234,17 @@
<!-- 第十一行注册人员数量仅劳务类型显示 -->
<el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'">
<el-col :span="12">
<el-form-item label="一建建造师" prop="build1">
<el-input v-model="form.build1" placeholder="请输入一建建造师数量" clearable />
<el-form-item label="一建建造师" prop="firstBuildingNumber">
<el-input v-model="form.firstBuildingNumber" placeholder="请输入一建建造师数量" clearable />
</el-form-item>
<el-form-item label="二建建造师" prop="build2">
<el-input v-model="form.build2" placeholder="请输入二建建造师数量" clearable />
<el-form-item label="二建建造师" prop="secondBuildingNumber">
<el-input v-model="form.secondBuildingNumber" placeholder="请输入二建建造师数量" clearable />
</el-form-item>
<el-form-item label="注册造价工程师" prop="build3">
<el-input v-model="form.build3" placeholder="请输入注册造价工程师数量" clearable />
<el-form-item label="注册造价工程师" prop="registeredEngineerNumber">
<el-input v-model="form.registeredEngineerNumber" placeholder="请输入注册造价工程师数量" clearable />
</el-form-item>
<el-form-item label="其他(分别写)" prop="build4">
<el-input v-model="form.build4" placeholder="请输入其他人员数量" clearable />
<el-form-item label="其他(分别写)" prop="otherBuildingNumber">
<el-input v-model="form.otherBuildingNumber" placeholder="请输入其他人员数量" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
@ -254,17 +254,17 @@
<!-- 第十二行职称人员数量仅劳务类型显示 -->
<el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'">
<el-col :span="12">
<el-form-item label="高级工程师人数" prop="personnelNumber1">
<el-input v-model="form.personnelNumber1" placeholder="请输高级工程师数量" clearable />
<el-form-item label="高级工程师人数" prop="seniorEngineerNumber">
<el-input v-model="form.seniorEngineerNumber" placeholder="请输高级工程师数量" clearable />
</el-form-item>
<el-form-item label="工程师数量" prop="personnelNumber2">
<el-input v-model="form.personnelNumber2" placeholder="请输入工程师数量" clearable />
<el-form-item label="工程师数量" prop="engineerNumber">
<el-input v-model="form.engineerNumber" placeholder="请输入工程师数量" clearable />
</el-form-item>
<el-form-item label="助理工程师数量" prop="personnelNumber3">
<el-input v-model="form.personnelNumber3" placeholder="请输入助理工程师数量" clearable />
<el-form-item label="助理工程师数量" prop="assistantEngineerNumber">
<el-input v-model="form.assistantEngineerNumber" placeholder="请输入助理工程师数量" clearable />
</el-form-item>
<el-form-item label="其他人员数量" prop="personnelNumber4">
<el-input v-model="form.personnelNumber4" placeholder="请输入其他人员数量" clearable />
<el-form-item label="其他人员数量" prop="otherPersonnelNumber">
<el-input v-model="form.otherPersonnelNumber" placeholder="请输入其他人员数量" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
@ -285,8 +285,8 @@
:data="form"
uploadUrl="/supplierInput/supplierInput"
:limit="1"
:onUploadSuccess="handleUploadSuccess"
@handleChange="change"
@handleChange="handleFileChange"
@handleRemove="handleFileRemove"
showFileList
>
<div><el-button type="primary">上传文件</el-button><br /></div>
@ -309,7 +309,7 @@
<script setup name="SupplierInput" lang="ts">
import { ComponentInternalInstance, getCurrentInstance, onMounted, ref, reactive, toRefs, computed } from 'vue';
import { ElFormInstance } from 'element-plus';
import { listSupplierInput, getSupplierInput, delSupplierInput } from '@/api/supplierInput/supplierInput/index';
import { listSupplierInput, getSupplierInput, delSupplierInput, updateSupplierInput } from '@/api/supplierInput/supplierInput/index';
import { SupplierInputVO, SupplierInputQuery, SupplierInputForm, PageData, DialogOption } from '@/api/supplierInput/supplierInput/types';
import Pagination from '@/components/Pagination/index.vue';
import RightToolbar from '@/components/RightToolbar/index.vue';
@ -369,14 +369,14 @@ const initFormData: any = {
inputFile: undefined,
// state: '0', // 新增默认待审核
// 新增:用于表单输入的单独字段
build1: undefined, // 一建建造师
build2: undefined, // 二建建造师
build3: undefined, // 注册造价工程师
build4: undefined, // 其他注册人员
personnelNumber1: undefined, // 高级工程师
personnelNumber2: undefined, // 工程师
personnelNumber3: undefined, // 助理工程师
personnelNumber4: undefined // 其他职称人员
firstBuildingNumber: undefined, // 一建建造师
secondBuildingNumber: undefined, // 二建建造师
registeredEngineerNumber: undefined, // 注册造价工程师
otherBuildingNumber: undefined, // 其他注册人员
seniorEngineerNumber: undefined, // 高级工程师
engineerNumber: undefined, // 工程师
assistantEngineerNumber: undefined, // 助理工程师
otherPersonnelNumber: undefined // 其他职称人员
};
// 核心数据(表单+查询参数)
const data = reactive<PageData<SupplierInputForm, SupplierInputQuery>>({
@ -411,14 +411,14 @@ const rules = computed(() => {
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' }
],
id: [{ required: true, message: 'ID不能为空', trigger: 'blur' }],
build1: [{ required: true, message: '请输入一建建造师数量', trigger: 'change' }],
build2: [{ required: true, message: '请输入二建建造师数量', trigger: 'change' }],
build3: [{ required: true, message: '请输入注册造价工程师数量', trigger: 'change' }],
build4: [{ required: true, message: '请输入其他数量', trigger: 'change' }],
personnelNumber1: [{ required: true, message: '请输入高级工程师数量', trigger: 'change' }],
personnelNumber2: [{ required: true, message: '请输入工程师数量', trigger: 'change' }],
personnelNumber3: [{ required: true, message: '请输入助理工程师数量', trigger: 'change' }],
personnelNumber4: [{ required: true, message: '请输入其他数量', trigger: 'change' }]
firstBuildingNumber: [{ required: true, message: '请输入一建建造师数量', trigger: 'change' }],
secondBuildingNumber: [{ required: true, message: '请输入二建建造师数量', trigger: 'change' }],
registeredEngineerNumber: [{ required: true, message: '请输入注册造价工程师数量', trigger: 'change' }],
otherBuildingNumber: [{ required: true, message: '请输入其他数量', trigger: 'change' }],
seniorEngineerNumber: [{ required: true, message: '请输入高级工程师数量', trigger: 'change' }],
engineerNumber: [{ required: true, message: '请输入工程师数量', trigger: 'change' }],
assistantEngineerNumber: [{ required: true, message: '请输入助理工程师数量', trigger: 'change' }],
otherPersonnelNumber: [{ required: true, message: '请输入其他数量', trigger: 'change' }]
};
// 仅当类型为"劳务"时,添加安全生产许可证+人员数量校验
@ -430,15 +430,15 @@ const rules = computed(() => {
safeCodeData: [{ required: true, message: '请选择安全生产许可证发证日期', trigger: 'change' }],
safeCertificateValidity: [{ required: true, message: '请选择安全生产许可证有效期', trigger: 'change' }],
// 注册人员数量校验
build1: [{ required: true, message: '请输入一建建造师数量', trigger: 'blur' }],
build2: [{ required: true, message: '请输入二建建造师数量', trigger: 'blur' }],
build3: [{ required: true, message: '请输入注册造价工程师数量', trigger: 'blur' }],
build4: [{ required: true, message: '请输入其他注册人员数量', trigger: 'blur' }],
firstBuildingNumber: [{ required: true, message: '请输入一建建造师数量', trigger: 'blur' }],
secondBuildingNumber: [{ required: true, message: '请输入二建建造师数量', trigger: 'blur' }],
registeredEngineerNumber: [{ required: true, message: '请输入注册造价工程师数量', trigger: 'blur' }],
otherBuildingNumber: [{ required: true, message: '请输入其他注册人员数量', trigger: 'blur' }],
// 职称人员数量校验
personnelNumber1: [{ required: true, message: '请输入高级工程师数量', trigger: 'blur' }],
personnelNumber2: [{ required: true, message: '请输入工程师数量', trigger: 'blur' }],
personnelNumber3: [{ required: true, message: '请输入助理工程师数量', trigger: 'blur' }],
personnelNumber4: [{ required: true, message: '请输入其他职称人员数量', trigger: 'blur' }]
seniorEngineerNumber: [{ required: true, message: '请输入高级工程师数量', trigger: 'blur' }],
engineerNumber: [{ required: true, message: '请输入工程师数量', trigger: 'blur' }],
assistantEngineerNumber: [{ required: true, message: '请输入助理工程师数量', trigger: 'blur' }],
otherPersonnelNumber: [{ required: true, message: '请输入其他职称人员数量', trigger: 'blur' }]
};
}
@ -455,22 +455,26 @@ const handleTypeChange = () => {
form.value.registeredNumber = undefined;
form.value.personnelNumber = undefined;
// 清空表单单独字段
form.value.build1 = form.value.build2 = form.value.build3 = form.value.build4 = undefined;
form.value.personnelNumber1 = form.value.personnelNumber2 = form.value.personnelNumber3 = form.value.personnelNumber4 = undefined;
form.value.firstBuildingNumber =
form.value.secondBuildingNumber =
form.value.registeredEngineerNumber =
form.value.otherBuildingNumber =
undefined;
form.value.seniorEngineerNumber = form.value.engineerNumber = form.value.assistantEngineerNumber = form.value.otherPersonnelNumber = undefined;
}
// 重置隐藏字段的校验状态,避免错误提示残留
supplierInputFormRef.value?.clearValidate([
'safeCode',
'safeCodeData',
'safeCertificateValidity',
'build1',
'build2',
'build3',
'build4',
'personnelNumber1',
'personnelNumber2',
'personnelNumber3',
'personnelNumber4'
'firstBuildingNumber',
'secondBuildingNumber',
'registeredEngineerNumber',
'otherBuildingNumber',
'seniorEngineerNumber',
'engineerNumber',
'assistantEngineerNumber',
'otherPersonnelNumber'
]);
};
@ -517,18 +521,18 @@ const resetQuery = () => {
const splitBackEndStrToForm = (resData: any) => {
if (resData.registeredNumber) {
const registeredArr = resData.registeredNumber.split(',');
form.value.build1 = registeredArr[0] || undefined; // 一建建造师
form.value.build2 = registeredArr[1] || undefined; // 二建建造师
form.value.build3 = registeredArr[2] || undefined; // 注册造价工程师
form.value.build4 = registeredArr[3] || undefined; // 其他注册人员
form.value.firstBuildingNumber = registeredArr[0] || undefined; // 一建建造师
form.value.secondBuildingNumber = registeredArr[1] || undefined; // 二建建造师
form.value.registeredEngineerNumber = registeredArr[2] || undefined; // 注册造价工程师
form.value.otherBuildingNumber = registeredArr[3] || undefined; // 其他注册人员
}
if (resData.personnelNumber) {
const personnelArr = resData.personnelNumber.split(',');
form.value.personnelNumber1 = personnelArr[0] || undefined; // 高级工程师
form.value.personnelNumber2 = personnelArr[1] || undefined; // 工程师
form.value.personnelNumber3 = personnelArr[2] || undefined; // 助理工程师
form.value.personnelNumber4 = personnelArr[3] || undefined; // 其他职称人员
form.value.seniorEngineerNumber = personnelArr[0] || undefined; // 高级工程师
form.value.engineerNumber = personnelArr[1] || undefined; // 工程师
form.value.assistantEngineerNumber = personnelArr[2] || undefined; // 助理工程师
form.value.otherPersonnelNumber = personnelArr[3] || undefined; // 其他职称人员
}
};
/** 审核过程按钮操作 */
@ -572,6 +576,7 @@ const handleAdd = () => {
dialog.title = '添加供应商入库';
};
const editFileId = ref('');
const handleUpdate = async (row?: SupplierInputVO) => {
reset();
const _id = row?.id || ids.value[0];
@ -579,7 +584,8 @@ const handleUpdate = async (row?: SupplierInputVO) => {
try {
const res = await getSupplierInput(_id);
const resData = res.data || {};
const resData: any = res.data || {};
editFileId.value = resData.fileId;
// 1. 基础字段回显
form.value = { ...form.value, ...resData, inputFile: '' };
// 2. 核心修复:拆分后端拼接字符串到表单单独字段
@ -594,24 +600,52 @@ const handleUpdate = async (row?: SupplierInputVO) => {
}
};
const fileStatus = ref(false);
const updateFileStatus = ref(true);
const isUpdateFile = ref(false); //记录是否在修改页面时是否有新上传的文件
const handleFileChange = (file, fileList) => {
if (form.value.id) {
updateFileStatus.value = true;
isUpdateFile.value = true; //记录是否在修改页面时是否有新上传的文件
}
fileStatus.value = true;
};
const handleFileRemove = (file, fileList) => {
if (form.value.id) {
updateFileStatus.value = false;
isUpdateFile.value = false; //记录是否在修改页面时是否有新上传的文件
}
fileStatus.value = false;
};
/** 提交表单 */
const submitForm = () => {
supplierInputFormRef.value?.validate(async (valid: boolean) => {
if (!valid) return;
if (form.value.supplierType === '劳务') {
form.value.registeredNumber = [form.value.build1, form.value.build2, form.value.build3, form.value.build4].join(',');
form.value.registeredNumber = [
form.value.firstBuildingNumber,
form.value.secondBuildingNumber,
form.value.registeredEngineerNumber,
form.value.otherBuildingNumber
].join(',');
form.value.personnelNumber = [
form.value.personnelNumber1,
form.value.personnelNumber2,
form.value.personnelNumber3,
form.value.personnelNumber4
form.value.seniorEngineerNumber,
form.value.engineerNumber,
form.value.assistantEngineerNumber,
form.value.otherPersonnelNumber
].join(',');
}
buttonLoading.value = true;
try {
if (fileUploadRef.value) {
await fileUploadRef.value.submitUpload().then((res) => {
console.log(res);
if (form.value.fileId === editFileId.value && !isUpdateFile.value) {
console.log(1111111111);
editFormData();
} else {
fileUploadRef.value.submitUpload().then((res) => {
if (res == 'noFile') {
proxy?.$modal.msgError('请上传文件');
return;
@ -621,6 +655,7 @@ const submitForm = () => {
getList();
});
}
}
} catch (error) {
proxy?.$modal.msgError('提交失败,请重试');
} finally {
@ -628,7 +663,14 @@ const submitForm = () => {
}
});
};
const editFormData = async () => {
const res = await updateSupplierInput(form.value);
if ((res.code = 200)) {
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
getList();
}
};
/** 删除操作 */
const handleDelete = async (row?: SupplierInputVO) => {
const _ids = row?.id || ids.value;

View File

@ -122,41 +122,41 @@
</el-row>
<el-row class="mb-4" v-if="form.supplierType === '劳务'">
<el-col :span="12">
<el-form-item label="一建建造师" prop="build1">
<el-input v-model="form.build1" placeholder="请输入一建建造师数量" clearable />
<el-form-item label="一建建造师" prop="firstBuildingNumber">
<el-input v-model="form.firstBuildingNumber" placeholder="请输入一建建造师数量" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="二建建造师" prop="build2">
<el-input v-model="form.build2" placeholder="请输入二建建造师数量" clearable />
<el-form-item label="二建建造师" prop="secondBuildingNumber">
<el-input v-model="form.secondBuildingNumber" placeholder="请输入二建建造师数量" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="其他(分别写)" prop="build4">
<el-input v-model="form.build3" placeholder="请输入其他人员数量" clearable />
<el-form-item label="其他(分别写)" prop="otherBuildingNumber">
<el-input v-model="form.otherBuildingNumber" placeholder="请输入其他人员数量" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="注册造价工程师" prop="build3">
<el-input v-model="form.build4" placeholder="请输入注册造价工程师数量" clearable />
<el-form-item label="注册造价工程师" prop="registeredEngineerNumber">
<el-input v-model="form.registeredEngineerNumber" placeholder="请输入注册造价工程师数量" clearable />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24" class="mb-4" v-if="form.supplierType === '劳务'">
<el-col :span="12">
<el-form-item label="高级工程师人数" prop="personnelNumber1">
<el-input v-model="form.personnelNumber1" placeholder="请输高级工程师数量" clearable />
<el-form-item label="高级工程师人数" prop="seniorEngineerNumber">
<el-input v-model="form.seniorEngineerNumber" placeholder="请输高级工程师数量" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="工程师数量" prop="personnelNumber2">
<el-input v-model="form.personnelNumber2" placeholder="请输入工程师数量" clearable />
<el-form-item label="工程师数量" prop="engineerNumber">
<el-input v-model="form.engineerNumber" placeholder="请输入工程师数量" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="助理工程师数量" prop="personnelNumber3">
<el-input v-model="form.personnelNumber3" placeholder="请输入助理工程师数量" clearable />
<el-form-item label="助理工程师数量" prop="assistantEngineerNumber">
<el-input v-model="form.assistantEngineerNumber" placeholder="请输入助理工程师数量" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="其他人员数量" prop="personnelNumber4">
<el-input v-model="form.personnelNumber4" placeholder="请输入其他人员数量" clearable />
<el-form-item label="其他人员数量" prop="otherPersonnelNumber">
<el-input v-model="form.otherPersonnelNumber" placeholder="请输入其他人员数量" clearable />
</el-form-item>
</el-col>
</el-row>
@ -270,14 +270,14 @@ const initFormData = {
inputFile: undefined,
state: '0', // 新增默认待审核
// 新增:用于表单输入的单独字段
build1: undefined, // 一建建造师
build2: undefined, // 二建建造师
build3: undefined, // 注册造价工程师
build4: undefined, // 其他注册人员
personnelNumber1: undefined, // 高级工程师
personnelNumber2: undefined, // 工程师
personnelNumber3: undefined, // 助理工程师
personnelNumber4: undefined // 其他职称人员
firstBuildingNumber: undefined, // 一建建造师
secondBuildingNumber: undefined, // 二建建造师
registeredEngineerNumber: undefined, // 注册造价工程师
otherBuildingNumber: undefined, // 其他注册人员
seniorEngineerNumber: undefined, // 高级工程师
engineerNumber: undefined, // 工程师
assistantEngineerNumber: undefined, // 助理工程师
otherPersonnelNumber: undefined
};
const data = reactive<PageData<LeaveForm, LeaveQuery>>({
form: { ...initFormData },
@ -332,17 +332,27 @@ const getInfo = () => {
buttonLoading.value = false;
nextTick(async () => {
const res = await getSupplierInput(routeParams.value.id);
console.log(res, '------------------res');
Object.assign(form.value, res.data);
form.value.registeredNumber = form.value.registeredNumber?.split(',');
form.value.build1 = form.value.registeredNumber[0] || '';
form.value.build2 = form.value.registeredNumber[1] || '';
form.value.build3 = form.value.registeredNumber[2] || '';
form.value.build4 = form.value.registeredNumber[3] || '';
form.value.personnelNumber = form.value.personnelNumber?.split(',');
form.value.personnelNumber1 = form.value.personnelNumber[0] || '';
form.value.personnelNumber2 = form.value.personnelNumber[1] || '';
form.value.personnelNumber3 = form.value.personnelNumber[2] || '';
form.value.personnelNumber4 = form.value.personnelNumber[3] || '';
// form.value.firstBuildingNumber=res.data.firstBuildingNumber, // 一建建造师
// secondBuildingNumber: undefined, // 二建建造师
// registeredEngineerNumber: undefined, // 注册造价工程师
// otherBuildingNumber: undefined, // 其他注册人员
// seniorEngineerNumber: undefined, // 高级工程师
// engineerNumber: undefined, // 工程师
// assistantEngineerNumber: undefined, // 助理工程师
// otherPersonnelNumber: undefined
// form.value.registeredNumber = form.value.registeredNumber?.split(',');
// form.value.build1 = form.value.registeredNumber[0] || '';
// form.value.build2 = form.value.registeredNumber[1] || '';
// form.value.build3 = form.value.registeredNumber[2] || '';
// form.value.build4 = form.value.registeredNumber[3] || '';
// form.value.personnelNumber = form.value.personnelNumber?.split(',');
// form.value.personnelNumber1 = form.value.personnelNumber[0] || '';
// form.value.personnelNumber2 = form.value.personnelNumber[1] || '';
// form.value.personnelNumber3 = form.value.personnelNumber[2] || '';
// form.value.personnelNumber4 = form.value.personnelNumber[3] || '';
loading.value = false;
buttonLoading.value = false;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long