下载资料模板,导入员工资料,详情修正,入退场记录

This commit is contained in:
Teo
2025-04-03 18:06:21 +08:00
parent c8a8d64127
commit 33165ac3e5
11 changed files with 398 additions and 94 deletions

View File

@ -1,4 +1,4 @@
import request from '@/utils/request'; import request, { download } from '@/utils/request';
import { AxiosPromise } from 'axios'; import { AxiosPromise } from 'axios';
import { import {
ConstructionUserForm, ConstructionUserForm,
@ -9,7 +9,8 @@ import {
ConstructionUserPlayCardForm, ConstructionUserPlayCardForm,
ConstructionUserSalaryForm, ConstructionUserSalaryForm,
ConstructionUserExitForm, ConstructionUserExitForm,
ConstructionUserTemplateForm ConstructionUserTemplateForm,
ConstructionUserMembeForm
} from '@/api/project/constructionUser/types'; } from '@/api/project/constructionUser/types';
/** /**
@ -159,9 +160,31 @@ export const getConstructionUserExit = (query: ConstructionUserExitForm) => {
* @param query * @param query
*/ */
export const dowloadConstructionUserTemplate = (query: ConstructionUserTemplateForm) => { export const dowloadConstructionUserTemplate = (query: ConstructionUserTemplateForm) => {
let { projectId } = query;
const fileName = projectId + '_project.zip';
return download('/project/constructionUserFile/exportFileTemplate', query, fileName);
};
/**
* 施工人员退场
* @param data
*/
export const delConstructionUserMember = (data: ConstructionUserMembeForm) => {
return request({ return request({
url: '/project/constructionUserFile/exportFileTemplate', url: '/project/projectTeamMember/',
method: 'get', method: 'delete',
params: query data
});
};
/**
* 上传施工人员文件压缩包,批量导入存储施工人员文件
* @param data
*/
export const importConstructionUserInfo = (file: string) => {
return request({
url: '/project/constructionUserFile/upload/zip',
method: 'post',
data: { file }
}); });
}; };

View File

@ -197,6 +197,25 @@ export interface skipType {
id: string | number; id: string | number;
} }
export interface ConstructionUserMembeForm {
/**
* 用户id
*/
id: string | number;
/**
* 用户姓名
*/
userName: string | number;
/**
* 文件路径
*/
filePath: string;
/**
* 备注
*/
remark: string | number;
}
export interface ConstructionUserTemplateForm { export interface ConstructionUserTemplateForm {
/** /**
* 项目id * 项目id
@ -300,6 +319,10 @@ export interface ConstructionUserForm extends BaseEntity {
* 分包公司id * 分包公司id
*/ */
contractorId?: string | number; contractorId?: string | number;
/**
* 结算方式
*/
wageMeasureUnit?: string | number;
/** /**
* 班组id * 班组id

View File

@ -40,6 +40,10 @@ export interface ConstructionUserExitVO {
* 用户id * 用户id
*/ */
userId: string | number; userId: string | number;
/**
* 文件路径地址
*/
pathUrl: Array<string>;
/** /**
* 身份证号码 * 身份证号码

View File

@ -24,6 +24,11 @@ export interface ProjectTeamMemberVO {
*/ */
postId: string | number; postId: string | number;
/**
* 施工人员姓名
*/
memberName: string;
/** /**
* 备注 * 备注
*/ */

View File

@ -16,8 +16,9 @@
:list-type="isConstruction ? 'picture-card' : 'text'" :list-type="isConstruction ? 'picture-card' : 'text'"
> >
<!-- 上传按钮 --> <!-- 上传按钮 -->
<el-button v-if="!isConstruction" type="primary">选取文件</el-button> <el-button v-if="!isConstruction && !isImportInfo" type="primary">选取文件</el-button>
<el-icon v-else><Plus /></el-icon> <el-button v-if="isImportInfo" type="warning" plain icon="Edit">导入员工资料 </el-button>
<el-icon v-if="isConstruction"><Plus /></el-icon>
<template #file="{ file }"> <template #file="{ file }">
<div class="pdf" v-if="isConstruction"> <div class="pdf" v-if="isConstruction">
<img src="@/assets/icons/svg/pdf.png" alt="" /> <img src="@/assets/icons/svg/pdf.png" alt="" />
@ -47,7 +48,12 @@
的文件 的文件
</div> </div>
<!-- 文件列表 --> <!-- 文件列表 -->
<transition-group v-if="!isConstruction" class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul"> <transition-group
v-if="!isConstruction && !isImportInfo"
class="upload-file-list el-upload-list el-upload-list--text"
name="el-fade-in-linear"
tag="ul"
>
<li v-for="(file, index) in fileList" :key="file.uid" class="el-upload-list__item ele-upload-list__item-content"> <li v-for="(file, index) in fileList" :key="file.uid" class="el-upload-list__item ele-upload-list__item-content">
<el-link :href="`${file.url}`" :underline="false" target="_blank"> <el-link :href="`${file.url}`" :underline="false" target="_blank">
<span class="el-icon-document"> {{ getFileName(file.name) }} </span> <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
@ -75,11 +81,15 @@ const props = defineProps({
// 大小限制(MB) // 大小限制(MB)
fileSize: propTypes.number.def(5), fileSize: propTypes.number.def(5),
// 文件类型, 例如['png', 'jpg', 'jpeg'] // 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf', 'png', 'jpg', 'jpeg', 'zip']),
// 是否显示提示 // 是否显示提示
isShowTip: propTypes.bool.def(true), isShowTip: propTypes.bool.def(true),
//是否为施工人员上传 //是否为施工人员上传
isConstruction: propTypes.bool.def(false) isConstruction: propTypes.bool.def(false),
//是否为导入资料
isImportInfo: propTypes.bool.def(false),
//ip地址
uploadUrl: propTypes.string.def('/resource/oss/upload')
}); });
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -88,7 +98,7 @@ const number = ref(0);
const uploadList = ref<any[]>([]); const uploadList = ref<any[]>([]);
const baseUrl = import.meta.env.VITE_APP_BASE_API; const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadFileUrl = ref(baseUrl + '/resource/oss/upload'); // 上传文件服务器地址 const uploadFileUrl = ref(baseUrl + props.uploadUrl); // 上传文件服务器地址
const headers = ref(globalHeaders()); const headers = ref(globalHeaders());
const fileList = ref<any[]>([]); const fileList = ref<any[]>([]);
@ -99,6 +109,7 @@ const fileUploadRef = ref<ElUploadInstance>();
watch( watch(
() => props.modelValue, () => props.modelValue,
async (val) => { async (val) => {
if (props.isImportInfo) return;
if (val) { if (val) {
let temp = 1; let temp = 1;
// 首先将值转为数组 // 首先将值转为数组
@ -203,6 +214,13 @@ const handleDelete = (index: string | number, type?: string) => {
// 上传结束处理 // 上传结束处理
const uploadedSuccessfully = () => { const uploadedSuccessfully = () => {
if (props.isImportInfo) {
emit('update:modelValue', 'ok');
fileUploadRef.value?.clearFiles();
proxy?.$modal.closeLoading();
proxy?.$modal.msgSuccess('导入成功');
return;
}
if (number.value > 0 && uploadList.value.length === number.value) { if (number.value > 0 && uploadList.value.length === number.value) {
fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value); fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value);
console.log('🚀 ~ uploadedSuccessfully ~ fileList.value:', fileList.value); console.log('🚀 ~ uploadedSuccessfully ~ fileList.value:', fileList.value);
@ -259,16 +277,15 @@ const listToString = (list: any[], separator?: string) => {
} }
} }
.upload-file-uploader { .upload-file-list {
margin-bottom: 5px; margin: 0;
} .el-upload-list__item {
.upload-file-list .el-upload-list__item {
border: 1px solid #e4e7ed; border: 1px solid #e4e7ed;
line-height: 2; line-height: 2;
margin-bottom: 10px; margin-bottom: 0;
position: relative; position: relative;
} }
}
.upload-file-list .ele-upload-list__item-content { .upload-file-list .ele-upload-list__item-content {
display: flex; display: flex;

View File

@ -81,6 +81,7 @@ declare global {
form: T; form: T;
queryParams: D; queryParams: D;
rules: ElFormRules; rules: ElFormRules;
memberRules?: ElFormRules;
} }
/** /**

View File

@ -180,6 +180,7 @@ export function download(url: string, params: any, fileName: string) {
return service.post(url, params, { return service.post(url, params, {
transformRequest: [ transformRequest: [
(params: any) => { (params: any) => {
return tansParams(params); return tansParams(params);
} }
], ],
@ -188,6 +189,7 @@ export function download(url: string, params: any, fileName: string) {
}).then(async (resp: any) => { }).then(async (resp: any) => {
const isLogin = blobValidate(resp); const isLogin = blobValidate(resp);
if (isLogin) { if (isLogin) {
console.log("🚀 ~ download ~ resp:", resp)
const blob = new Blob([resp]); const blob = new Blob([resp]);
FileSaver.saveAs(blob, fileName); FileSaver.saveAs(blob, fileName);
} else { } else {

View File

@ -1,50 +1,138 @@
<template> <template>
<div> <div>
<el-descriptions v-loading="loading" title="用户信息" direction="vertical" border> <div class="block_box">
<el-descriptions-item :rowspan="3" :width="200" label="人脸照"> <span>用户信息</span>
<el-form label-width="130px">
<el-row :gutter="20" justify="space-around">
<el-col :span="12">
<el-form-item label="人脸照">
<el-image :src="userDetail?.facePicUrl" style="width: 150px; height: 150px" /> <el-image :src="userDetail?.facePicUrl" style="width: 150px; height: 150px" />
</el-descriptions-item> </el-form-item>
<el-descriptions-item label="姓名">{{ userDetail?.userName }}</el-descriptions-item> </el-col>
<el-descriptions-item label="联系电话">{{ userDetail?.phone }}</el-descriptions-item> <el-col :span="12">
<el-descriptions-item label="性别"> <el-form-item label="姓名">
{{ userDetail?.userName }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话">
{{ userDetail?.phone }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="性别">
<dict-tag :options="user_sex_type" :value="userDetail?.sex" /> <dict-tag :options="user_sex_type" :value="userDetail?.sex" />
</el-descriptions-item> </el-form-item>
<el-descriptions-item label="年龄">{{ dayjs().diff(dayjs(userDetail?.sfzBirth), 'year') }}</el-descriptions-item> </el-col>
<el-descriptions-item label="民族">{{ userDetail?.nation }}</el-descriptions-item> <el-col :span="12">
<el-descriptions-item label="籍贯">{{ userDetail?.nativePlace }}</el-descriptions-item> <el-form-item label="年龄">
<el-descriptions-item label="身份证号码">{{ userDetail?.sfzNumber }}</el-descriptions-item> {{ dayjs().diff(dayjs(userDetail?.sfzBirth), 'year') }}
<el-descriptions-item label="身份证有效期"> </el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="民族">
{{ userDetail?.nation }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="籍贯">
{{ userDetail?.nativePlace }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="身份证号码">
{{ userDetail?.sfzNumber }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="身份证号码">
{{ userDetail?.sfzNumber }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="身份证有效开始期">
{{ dayjs(userDetail?.sfzStart).format('YYYY 年 MM 月 DD 日') }} {{ dayjs(userDetail?.sfzStart).format('YYYY 年 MM 月 DD 日') }}
{{ dayjs(userDetail?.sfzEnd).format('YYYY 年 MM 月 DD 日') }} </el-form-item>
</el-descriptions-item> </el-col>
<el-descriptions-item label="身份证地址">{{ userDetail?.sfzSite }}</el-descriptions-item> <el-col :span="12">
</el-descriptions> <el-form-item label="身份证有效结束期">
<br /> {{ dayjs(userDetail?.sfzEnd).format('YYYY 年 MM 月 DD 日') }}
<el-descriptions v-loading="loading" title="银行卡" direction="vertical" border> </el-form-item>
<el-descriptions-item label="银行卡号">{{ userDetail?.yhkNumber }}</el-descriptions-item> </el-col>
<el-descriptions-item label="银行开户行">{{ userDetail?.yhkOpeningBank }}</el-descriptions-item> <el-col :span="12">
<el-descriptions-item label="持卡人">{{ userDetail?.yhkCardholder }}</el-descriptions-item> <el-form-item label="身份证地址">
</el-descriptions> {{ userDetail?.sfzSite }}
<br /> </el-form-item>
<el-descriptions v-loading="loading" title="单位信息" direction="vertical" border> </el-col>
<el-descriptions-item label="施工单位">{{ userDetail?.contractorVo?.name }}</el-descriptions-item> </el-row>
<el-descriptions-item label="工种"> </el-form>
</div>
<div class="block_box">
<span>银行卡</span>
<el-form label-width="130px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="银行卡号">
{{ userDetail?.yhkNumber }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="银行开户行">
{{ userDetail?.yhkOpeningBank }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="持卡人">
{{ userDetail?.yhkCardholder }}
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<div class="block_box">
<span>单位信息</span>
<el-form label-width="130px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="施工单位">
{{ userDetail?.contractorVo?.name }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工种">
<dict-tag :options="type_of_work" :value="userDetail?.typeOfWork" /> <dict-tag :options="type_of_work" :value="userDetail?.typeOfWork" />
</el-descriptions-item> </el-form-item>
</el-descriptions> </el-col>
<br /> </el-row>
<el-descriptions :column="2" v-loading="loading" title="其他信息" direction="vertical" border> </el-form>
<el-descriptions-item label="班组">{{ userDetail?.teamVo?.teamName }}</el-descriptions-item> </div>
<el-descriptions-item label="打卡状态"> <div class="block_box">
<span>其他信息</span>
<el-form label-width="130px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="班组">
{{ userDetail?.teamVo?.teamName }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="打卡状态">
<dict-tag :options="user_clock_type" :value="userDetail?.clock" /> <dict-tag :options="user_clock_type" :value="userDetail?.clock" />
</el-descriptions-item> </el-form-item>
<el-descriptions-item label="入场时间"> </el-col>
<el-col :span="12">
<el-form-item label="入场时间">
{{ userDetail?.entryDate ? dayjs(userDetail?.entryDate).format('YYYY 年 MM 月 DD 日 HH:mm:ss') : '' }} {{ userDetail?.entryDate ? dayjs(userDetail?.entryDate).format('YYYY 年 MM 月 DD 日 HH:mm:ss') : '' }}
</el-descriptions-item> </el-form-item>
<el-descriptions-item label="离场时间"> </el-col>
<el-col :span="12">
<el-form-item label="离场时间">
{{ userDetail?.leaveDate ? dayjs(userDetail?.leaveDate).format('YYYY 年 MM 月 DD 日 HH:mm:ss') : '' }} {{ userDetail?.leaveDate ? dayjs(userDetail?.leaveDate).format('YYYY 年 MM 月 DD 日 HH:mm:ss') : '' }}
</el-descriptions-item> </el-form-item>
</el-descriptions> </el-col>
</el-row>
</el-form>
</div>
</div> </div>
</template> </template>
@ -85,3 +173,16 @@ watch(
} }
); );
</script> </script>
<style lang="scss" scoped>
.block_box {
border: 1px solid #9eccfa;
border-radius: 6px;
padding: 10px 20px 20px 10px;
margin: 15px;
> span {
color: #409eff;
font-weight: 700;
font-size: 14px;
}
}
</style>

View File

@ -79,13 +79,21 @@
</el-col> </el-col>
<el-row @mouseover="informationStatus = true" :gutter="10" @mouseout="informationStatus = false"> <el-row @mouseover="informationStatus = true" :gutter="10" @mouseout="informationStatus = false">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="success" plain @click="statusDialog = true">员工资料 </el-button> <el-button type="success" plain>员工资料 </el-button>
</el-col> </el-col>
<el-col :span="1.5" v-show="informationStatus"> <el-col :span="1.5" v-show="informationStatus">
<el-button type="primary" plain icon="Edit" @click="downloadTemplate">下载资料模板 </el-button> <el-button type="primary" plain icon="Edit" @click="downloadTemplate">下载资料模板 </el-button>
</el-col> </el-col>
<el-col :span="1.5" v-show="informationStatus"> <el-col :span="1.5" v-show="informationStatus">
<el-button type="warning" plain icon="Edit" @click="statusDialog = true">导入员工资料 </el-button> <!-- <el-button type="warning" plain icon="Edit" @click="importInformation">导入员工资料 </el-button> -->
<file-upload
v-model="filePath"
isImportInfo
:isShowTip="false"
uploadUrl="/project/constructionUserFile/upload/zip"
:limit="1"
:file-size="50"
/>
</el-col> </el-col>
</el-row> </el-row>
@ -132,15 +140,17 @@
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="日薪(元)" align="center" min-width="180"> <el-table-column label="薪水" align="center" min-width="180">
<template #default="scope"> <template #default="scope">
<span>{{ scope.row.salary ? scope.row.salary : scope.row.standardSalary }}</span> <span class="flex justify-center">
{{ scope.row.salary ? scope.row.salary : scope.row.standardSalary }}
(<dict-tag :options="wage_measure_unit_type" :value="scope.row.wageMeasureUnit"></dict-tag>)
</span>
<div class="text-blue text-sm cursor-pointer" @click="openSalaryDialog(scope.row)">{{ scope.row.salary ? '取消变更' : '变更' }}</div> <div class="text-blue text-sm cursor-pointer" @click="openSalaryDialog(scope.row)">{{ scope.row.salary ? '取消变更' : '变更' }}</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="入场时间" align="center" prop="entryDate" min-width="180" /> <el-table-column label="入场时间" align="center" prop="entryDate" min-width="180" />
<el-table-column label="离场时间" align="center" prop="leaveDate" min-width="180" /> <el-table-column label="离场时间" align="center" prop="leaveDate" min-width="180" />
<el-table-column label="薪水" align="center" prop="salary" />
<el-table-column label="状态" align="center" prop="status"> <el-table-column label="状态" align="center" prop="status">
<template #default="scope"> <template #default="scope">
{{ scope.row.status == 0 ? '在职' : '离职' }} {{ scope.row.status == 0 ? '在职' : '离职' }}
@ -166,7 +176,7 @@
删除 删除
</el-button> </el-button>
<el-tooltip content="红点:部分上传,绿点:已上传,无点:未上传" placement="right" effect="dark"> <el-tooltip content="红点:部分上传,绿点:已上传,无点:未上传" placement="right" effect="dark">
<el-badge is-dot type="primary"> <el-badge :is-dot="scope.row.fileUploadStatus != '1'" :type="uploadStatusColor(scope.row.fileUploadStatus)">
<el-button link type="primary" icon="FolderAdd" @click="handleUpload(scope.row)">文件上传 </el-button> <el-button link type="primary" icon="FolderAdd" @click="handleUpload(scope.row)">文件上传 </el-button>
</el-badge> </el-badge>
</el-tooltip> </el-tooltip>
@ -184,7 +194,7 @@
<div class="msg">用户信息</div> <div class="msg">用户信息</div>
<div class="el-row"> <div class="el-row">
<div class="el-col el-col-24"> <div class="el-col el-col-24">
<el-form-item label="人脸照" prop="pacePhoto"> <el-form-item label="人脸照" prop="facePic">
<image-upload v-model="form.facePic" :limit="1" :is-show-tip="false" /> <image-upload v-model="form.facePic" :limit="1" :is-show-tip="false" />
</el-form-item> </el-form-item>
</div> </div>
@ -299,6 +309,13 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</div> </div>
<div class="el-col el-col-12">
<el-form-item label="结算方式" prop="wageMeasureUnit">
<el-select v-model="form.wageMeasureUnit" clearable placeholder="请选择结算方式">
<el-option v-for="item in wage_measure_unit_type" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</div>
<div class="el-col el-col-12"> <div class="el-col el-col-12">
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" style="width: 240px" /> <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" style="width: 240px" />
@ -351,7 +368,11 @@
</el-dialog> </el-dialog>
<el-dialog :title="skipName + '-切换人脸'" v-model="showFaceDrawer" width="770px"> <el-dialog :title="skipName + '-切换人脸'" v-model="showFaceDrawer" width="770px">
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
<el-form :model="form" ref="constructionUserFormRef" :rules="rules">
<el-form-item>
<image-upload v-model="form.facePic" :limit="1" :is-show-tip="false" /> <image-upload v-model="form.facePic" :limit="1" :is-show-tip="false" />
</el-form-item>
</el-form>
</div> </div>
<template #footer> <template #footer>
<span <span
@ -374,8 +395,8 @@
</template> </template>
</el-dialog> </el-dialog>
<el-dialog title="温馨提示" v-model="salaryStatus" width="30%"> <el-dialog title="温馨提示" v-model="salaryStatus" width="30%">
<span>请输入薪资(/)</span> <span>请输入薪资</span>
<el-input class="mt-xl" v-model="changeSalary" placeholder="" size="normal" clearable @change=""></el-input> <el-input class="mt-xl" v-model="changeSalary" placeholder="" clearable @change=""></el-input>
<template #footer> <template #footer>
<span> <span>
<el-button type="primary" @click="handleSalary">确认</el-button> <el-button type="primary" @click="handleSalary">确认</el-button>
@ -386,8 +407,18 @@
<el-dialog title="入场退场记录" v-model="exitStatus" width="600px"> <el-dialog title="入场退场记录" v-model="exitStatus" width="600px">
<div v-for="(item, index) in exitList"> <div v-for="(item, index) in exitList">
<el-timeline> <el-timeline>
<el-timeline-item v-for="(itm, idx) in 2" :key="idx" :timestamp="item.entryDate" :color="green"> <el-timeline-item color="#0bbd87" class="mb">
{{ item.entryDate }} {{ '入场时间:' + item.entryDate }}
</el-timeline-item>
<el-timeline-item color="rgb(255, 73, 73)">
<div class="mb">{{ '退场时间:' + item.entryDate }}</div>
<div class="pl-xl">
<span class="text-coolgray font-bold">退场文件<image-preview v-for="itm in item.pathUrl" :src="itm" width="100px" class="mr" /></span
><br />
<p class="mt text-coolgray">
备注<span class="text-blue">{{ item.remark }}</span>
</p>
</div>
</el-timeline-item> </el-timeline-item>
</el-timeline> </el-timeline>
</div> </div>
@ -415,7 +446,8 @@ import {
updateConstructionUserPlayCardOneStatus, updateConstructionUserPlayCardOneStatus,
updateConstructionUserSalary, updateConstructionUserSalary,
getConstructionUserExit, getConstructionUserExit,
dowloadConstructionUserTemplate dowloadConstructionUserTemplate,
importConstructionUserInfo
} from '@/api/project/constructionUser'; } from '@/api/project/constructionUser';
import { import {
ConstructionUserForm, ConstructionUserForm,
@ -440,10 +472,10 @@ import {
ConstructionUserFileQuery ConstructionUserFileQuery
} from '@/api/project/constructionUserFile/types'; } from '@/api/project/constructionUserFile/types';
import { ElLoadingService } from 'element-plus'; import { ElLoadingService } from 'element-plus';
const imgurl = 'http://zmkg.cqet.top:8899/wxfile/upload_file/2024-12-03/1.jpg';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { type_of_work, user_sex_type, user_clock_type, user_file_type, user_status_type } = toRefs<any>( const { type_of_work, user_sex_type, user_clock_type, user_file_type, user_status_type, wage_measure_unit_type } = toRefs<any>(
proxy?.useDict('type_of_work', 'user_sex_type', 'user_clock_type', 'user_file_type', 'user_status_type') proxy?.useDict('type_of_work', 'user_sex_type', 'user_clock_type', 'user_file_type', 'user_status_type', 'wage_measure_unit_type')
); );
// 获取用户 store // 获取用户 store
const userStore = useUserStoreHook(); const userStore = useUserStoreHook();
@ -466,6 +498,7 @@ const playCardLoding = ref(false);
const salaryStatus = ref(false); const salaryStatus = ref(false);
const exitStatus = ref(false); const exitStatus = ref(false);
const informationStatus = ref(false); const informationStatus = ref(false);
const filePath = ref<string>('');
const exitList = ref<ConstructionUserExitVO[]>([]); const exitList = ref<ConstructionUserExitVO[]>([]);
const changeSalary = ref<string>(''); const changeSalary = ref<string>('');
const vocationalStatus = ref<number>(null); const vocationalStatus = ref<number>(null);
@ -477,7 +510,7 @@ const dialog = reactive<DialogOption>({
visible: false, visible: false,
title: '' title: ''
}); });
const baseUrl = import.meta.env.VITE_APP_BASE_API;
//人员迁移条件 //人员迁移条件
const skipObject: skipType = reactive({ const skipObject: skipType = reactive({
id: '', id: '',
@ -507,6 +540,7 @@ const initFormData: ConstructionUserForm = {
sfzNumber: undefined, sfzNumber: undefined,
sfzStart: undefined, sfzStart: undefined,
sfzEnd: undefined, sfzEnd: undefined,
wageMeasureUnit: undefined,
sfzSite: undefined, sfzSite: undefined,
sfzBirth: undefined, sfzBirth: undefined,
nativePlace: undefined, nativePlace: undefined,
@ -555,8 +589,28 @@ const data = reactive<PageData<ConstructionUserForm, ConstructionUserQuery>>({
params: {} params: {}
}, },
rules: { rules: {
id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }], clock: [{ required: true, message: '打卡不能为空', trigger: 'blur' }],
clock: [{ required: true, message: '打卡不能为空', trigger: 'blur' }] facePic: [{ required: true, message: '人脸照不能为空', trigger: 'blur' }],
userName: [{ required: true, message: '人员姓名不能为空', trigger: 'blur' }],
projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }],
contractorId: [{ required: true, message: '分包公司id不能为空', trigger: 'blur' }],
teamId: [{ required: true, message: '班组id不能为空', trigger: 'blur' }],
phone: [{ required: true, message: '联系电话不能为空', trigger: 'blur' }],
nation: [{ required: true, message: '民族不能为空', trigger: 'blur' }],
sfzFrontPic: [{ required: true, message: '身份证正面图片不能为空', trigger: 'blur' }],
sfzBackPic: [{ required: true, message: '身份证背面图片不能为空', trigger: 'blur' }],
sfzNumber: [{ required: true, message: '身份证号码不能为空', trigger: 'blur' }],
sfzStart: [{ required: true, message: '身份证有效开始期不能为空', trigger: 'blur' }],
sfzEnd: [{ required: true, message: '身份证有效结束期不能为空', trigger: 'blur' }],
sfzSite: [{ required: true, message: '身份证地址不能为空', trigger: 'blur' }],
sfzBirth: [{ required: true, message: '身份证出生日期不能为空', trigger: 'blur' }],
nativePlace: [{ required: true, message: '籍贯不能为空', trigger: 'blur' }],
yhkPic: [{ required: true, message: '银行卡图片不能为空', trigger: 'blur' }],
yhkNumber: [{ required: true, message: '银行卡号不能为空', trigger: 'blur' }],
yhkOpeningBank: [{ required: true, message: '开户行不能为空', trigger: 'blur' }],
typeOfWork: [{ required: true, message: '工种(字典type_of_work)不能为空', trigger: 'blur' }],
wageMeasureUnit: [{ required: true, message: '工资计量单位不能为空', trigger: 'blur' }],
userRole: [{ required: true, message: '用户角色(1=普通用户,2=管理员)不能为空', trigger: 'blur' }]
} }
}); });
@ -581,6 +635,18 @@ const uploadPath = computed(() => {
return list; return list;
}); });
/** 返回文件上传状态 */
const uploadStatusColor = computed(() => (str: string) => {
switch (str) {
case '3':
return 'success';
case '2':
return 'danger';
default:
return 'info';
}
});
const { queryParams, form, rules } = toRefs(data); const { queryParams, form, rules } = toRefs(data);
/** 查询施工人员列表 */ /** 查询施工人员列表 */
@ -733,10 +799,13 @@ const downloadTemplate = async () => {
text: 'Loading', text: 'Loading',
background: 'rgba(0, 0, 0, 0.7)' background: 'rgba(0, 0, 0, 0.7)'
}); });
await dowloadConstructionUserTemplate({ projectId: currentProject.value.id }); const res = await dowloadConstructionUserTemplate({ projectId: currentProject.value.id });
loadingInstance.close(); loadingInstance.close();
}; };
//导入资料
const importInformation = async () => {};
/** 人员迁移 */ /** 人员迁移 */
const handleChange = async (row: ConstructionUserVO) => { const handleChange = async (row: ConstructionUserVO) => {
const _id = row?.id || ids.value[0]; const _id = row?.id || ids.value[0];
@ -761,7 +830,7 @@ const handleExit = async (row: ConstructionUserVO) => {
const _id = row?.id || ids.value[0]; const _id = row?.id || ids.value[0];
currentUserId.value = _id; currentUserId.value = _id;
const res = await getConstructionUserExit({ userId: _id }); const res = await getConstructionUserExit({ userId: _id });
exitList.value = res.data; exitList.value = res.rows;
exitStatus.value = true; exitStatus.value = true;
}; };
@ -777,6 +846,7 @@ const handleUpload = async (row: ConstructionUserVO) => {
/** 提交按钮 */ /** 提交按钮 */
const submitForm = () => { const submitForm = () => {
constructionUserFormRef.value?.validate(async (valid: boolean) => { constructionUserFormRef.value?.validate(async (valid: boolean) => {
console.log(valid);
if (valid) { if (valid) {
buttonLoading.value = true; buttonLoading.value = true;
if (form.value.id) { if (form.value.id) {
@ -788,6 +858,8 @@ const submitForm = () => {
dialog.visible = false; dialog.visible = false;
showFaceDrawer.value = false; showFaceDrawer.value = false;
await getList(); await getList();
} else {
console.log(12);
} }
}); });
}; };

View File

@ -66,8 +66,8 @@
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:projectTeamMember:edit']"> <el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:projectTeamMember:edit']">
修改 修改
</el-button> </el-button>
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:projectTeamMember:remove']"> <el-button link type="danger" icon="Position" @click="handleExit(scope.row)" v-hasPermi="['project:projectTeamMember:remove']">
删除 退场
</el-button> </el-button>
</el-space> </el-space>
</template> </template>
@ -85,7 +85,7 @@
<!-- 添加或修改项目班组下的成员对话框 --> <!-- 添加或修改项目班组下的成员对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="projectTeamMemberFormRef" :model="form" :rules="rules" label-width="80px"> <el-form ref="projectTeamMemberFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="施工人员" prop="memberId"> <el-form-item label="施工人员" prop="memberId" v-if="!form.id">
<el-select v-model="form.memberId" clearable placeholder="请选择人员" filterable> <el-select v-model="form.memberId" clearable placeholder="请选择人员" filterable>
<el-option v-for="item in userNotInTeamOpt" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in userNotInTeamOpt" :key="item.value" :label="item.label" :value="item.value" />
<pagination <pagination
@ -114,6 +114,27 @@
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
<!-- 上传退场记录 -->
<el-dialog title="员工离场" v-model="memberStatus" width="30%">
<el-form :model="memberForm" ref="memberFormRef" :rules="memberRules" label-width="100px" :inline="false">
<el-form-item label="用户名">
<el-input v-model="memberForm.userName" disabled></el-input>
</el-form-item>
<el-form-item label="退场文件">
<file-upload v-model="memberForm.filePath" :limit="10" :is-show-tip="false" :file-size="50" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="memberForm.remark" placeholder="请输入备注" type="textarea"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span>
<el-button type="primary" @click="submitMemberForm" :loading="buttonLoading">确定</el-button>
<el-button @click="memberStatus = false">取消</el-button>
</span>
</template>
</el-dialog>
</div> </div>
</template> </template>
@ -129,8 +150,8 @@ import {
} from '@/api/project/projectTeamMember'; } from '@/api/project/projectTeamMember';
import { computed, reactive, ref } from 'vue'; import { computed, reactive, ref } from 'vue';
import { useUserStoreHook } from '@/store/modules/user'; import { useUserStoreHook } from '@/store/modules/user';
import { listConstructionUser } from '@/api/project/constructionUser'; import { listConstructionUser, delConstructionUserMember } from '@/api/project/constructionUser';
import { ConstructionUserQuery, ConstructionUserVO } from '@/api/project/constructionUser/types'; import { ConstructionUserQuery, ConstructionUserVO, ConstructionUserMembeForm } from '@/api/project/constructionUser/types';
// 获取用户 store // 获取用户 store
const userStore = useUserStoreHook(); const userStore = useUserStoreHook();
@ -138,10 +159,16 @@ const userStore = useUserStoreHook();
const currentProject = computed(() => userStore.selectedProject); const currentProject = computed(() => userStore.selectedProject);
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { user_post_type } = toRefs<any>(proxy?.useDict('user_post_type')); const { user_post_type } = toRefs<any>(proxy?.useDict('user_post_type'));
const memberStatus = ref(false);
interface Props { interface Props {
projectTeamVo: ProjectTeamVO; projectTeamVo: ProjectTeamVO;
} }
const memberForm = reactive<ConstructionUserMembeForm>({
id: undefined,
filePath: undefined,
remark: undefined,
userName: undefined
});
const props = defineProps<Props>(); const props = defineProps<Props>();
// 是否可见 // 是否可见
@ -160,6 +187,9 @@ const data = reactive<PageData<ProjectTeamMemberForm, ProjectTeamMemberQuery>>({
}, },
rules: { rules: {
id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }] id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }]
},
memberRules: {
filePath: [{ required: true, message: '请上传退场文件', trigger: 'blur' }]
} }
}); });
const buttonLoading = ref(false); const buttonLoading = ref(false);
@ -170,12 +200,13 @@ const multiple = ref(true);
const total = ref(0); const total = ref(0);
const queryFormRef = ref<ElFormInstance>(); const queryFormRef = ref<ElFormInstance>();
const projectTeamMemberFormRef = ref<ElFormInstance>(); const projectTeamMemberFormRef = ref<ElFormInstance>();
const memberFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({ const dialog = reactive<DialogOption>({
visible: false, visible: false,
title: '' title: ''
}); });
const { queryParams, form, rules } = toRefs(data); const { queryParams, form, rules, memberRules } = toRefs(data);
const projectTeamMemberList = ref<ProjectTeamMemberVO[]>([]); const projectTeamMemberList = ref<ProjectTeamMemberVO[]>([]);
/** 查询项目班组下的成员列表 */ /** 查询项目班组下的成员列表 */
const getList = async () => { const getList = async () => {
@ -277,6 +308,31 @@ const submitForm = () => {
}); });
}; };
/** 确定退场按钮 */
const submitMemberForm = async () => {
memberFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
await delConstructionUserMember(memberForm).finally(() => (buttonLoading.value = false));
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
memberForm.filePath = undefined;
memberForm.remark = undefined;
}
});
memberStatus.value = false;
};
/** 退场按钮操作 */
const handleExit = async (row?: ProjectTeamMemberVO) => {
const _ids = row?.id || ids.value;
memberForm.userName = row?.memberName;
console.log('🚀 ~ handleDelete ~ row:', row);
memberForm.id = row?.id;
memberStatus.value = true;
};
/** 删除按钮操作 */ /** 删除按钮操作 */
const handleDelete = async (row?: ProjectTeamMemberVO) => { const handleDelete = async (row?: ProjectTeamMemberVO) => {
const _ids = row?.id || ids.value; const _ids = row?.id || ids.value;

View File

@ -86,7 +86,7 @@
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog :title="currentRow.teamName" v-model="visible"> <el-dialog :title="currentRow.teamName" v-model="visible" width="1000px">
<user-list-dialog :projectTeamVo="currentRow" /> <user-list-dialog :projectTeamVo="currentRow" />
</el-dialog> </el-dialog>
</div> </div>