|
|
@@ -0,0 +1,368 @@
|
|
|
+<template>
|
|
|
+ <div class="min-h-screen bg-gray-50 p-8">
|
|
|
+ <div class="mx-auto">
|
|
|
+ <!-- 头部区域 -->
|
|
|
+ <div class="mb-6 flex items-center justify-between">
|
|
|
+ <h1 class="text-2xl font-bold text-gray-900">安保人员管理</h1>
|
|
|
+ <el-button type="primary" class="!rounded-button" @click="handleAdd">
|
|
|
+ <el-icon class="mr-1">
|
|
|
+ <Plus />
|
|
|
+ </el-icon>新增安保人员
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 搜索区域 -->
|
|
|
+ <div class="mb-6 flex gap-4 rounded-lg bg-white p-4 shadow-sm">
|
|
|
+ <el-input v-model="searchForm.name" placeholder="请输入姓名搜索" class="max-w-xs" clearable>
|
|
|
+ <template #prefix>
|
|
|
+ <el-icon>
|
|
|
+ <Search />
|
|
|
+ </el-icon>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ <el-input v-model="searchForm.phone" placeholder="请输入手机号搜索" class="max-w-xs" clearable>
|
|
|
+ <template #prefix>
|
|
|
+ <el-icon>
|
|
|
+ <Phone />
|
|
|
+ </el-icon>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ <el-button type="primary" class="!rounded-button" @click="handleSearch">
|
|
|
+ 搜索
|
|
|
+ </el-button>
|
|
|
+ <el-button class="!rounded-button" @click="handleReset">重置</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 表格区域 -->
|
|
|
+ <div class="rounded-lg bg-white p-6 shadow-sm">
|
|
|
+ <el-table :data="tableData" stripe style="width: 100%">
|
|
|
+ <el-table-column type="index" label="序号" />
|
|
|
+ <el-table-column label="头像">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-avatar :size="50" :src="row.avatar" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="name" label="姓名" />
|
|
|
+ <el-table-column prop="gender" label="性别" />
|
|
|
+ <el-table-column prop="IDNO" label="证件号码" />
|
|
|
+ <el-table-column prop="phone" label="手机号" width="130" />
|
|
|
+ <el-table-column prop="DEPARTMENT" label="所属部门" />
|
|
|
+ <el-table-column prop="PositionLevel" label="职位级别" />
|
|
|
+ <el-table-column prop="entryTime" label="入职时间" />
|
|
|
+ <el-table-column prop="contractPeriod" label="合同期限" />
|
|
|
+ <el-table-column prop="PPS" label="试用期状态" />
|
|
|
+ <el-table-column prop="DirectSupervisor" label="直属领导" />
|
|
|
+ <el-table-column prop="WorkLocation" label="工作地点" />
|
|
|
+ <el-table-column prop="certName" label="证书名称" />
|
|
|
+ <el-table-column prop="certStatus" label="证书状态">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-tag :type="getCertStatusType(row.certStatus)" class="whitespace-nowrap">
|
|
|
+ {{ row.certStatus }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" fixed="right" width="150">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button type="primary" link class="!rounded-button" @click="handleEdit(row)">
|
|
|
+ 编辑
|
|
|
+ </el-button>
|
|
|
+ <el-button type="danger" link class="!rounded-button" @click="handleDelete(row)">
|
|
|
+ 删除
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <div class="mt-4 flex justify-end">
|
|
|
+ <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :total="total"
|
|
|
+ :page-sizes="[10, 20, 30, 50]" layout="total, sizes, prev, pager, next" @size-change="handleSizeChange"
|
|
|
+ @current-change="handleCurrentChange" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 新增/编辑弹窗 -->
|
|
|
+ <el-dialog v-model="dialogVisible" :title="dialogType === 'add' ? '新增安保人员' : '编辑安保人员'" width="600px">
|
|
|
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="100px" class="mt-4">
|
|
|
+ <el-form-item label="姓名" prop="name">
|
|
|
+ <el-input v-model="form.name" placeholder="请输入姓名" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="手机号" prop="phone">
|
|
|
+ <el-input v-model="form.phone" placeholder="请输入手机号" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="出生日期" prop="certDate">
|
|
|
+ <el-date-picker v-model="form.certDate" type="date" placeholder="出生日期"
|
|
|
+ :default-value="new Date(2010, 9, 1)" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <span class="dialog-footer">
|
|
|
+ <el-button class="!rounded-button" @click="dialogVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" class="!rounded-button" @click="handleSubmit">确认</el-button>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { ref, reactive } from 'vue';
|
|
|
+import {
|
|
|
+ Plus,
|
|
|
+ Search,
|
|
|
+ Phone,
|
|
|
+ Upload,
|
|
|
+} from '@element-plus/icons-vue';
|
|
|
+import type { FormInstance, FormRules } from 'element-plus';
|
|
|
+import { clientDel, clientGet, clientPost, clientPut } from '@/utils/request.ts'
|
|
|
+import type { BaseResponse } from '@/utils/type.ts'
|
|
|
+
|
|
|
+
|
|
|
+interface IntroductItem {
|
|
|
+ id: string;
|
|
|
+ parkName: string;
|
|
|
+ remarks: string;
|
|
|
+ totalArea: string;
|
|
|
+ enteredCompany: string;
|
|
|
+ numberBuildings: string;
|
|
|
+ parkPersonnel: string;
|
|
|
+ standardFactory: string;
|
|
|
+ parkingLot: string;
|
|
|
+ productionLand: string;
|
|
|
+ officeLand: string;
|
|
|
+ greenVegetation: string;
|
|
|
+ infrastructure: string;
|
|
|
+ developmentArea: string;
|
|
|
+ createTime: string;
|
|
|
+ businessType: string;
|
|
|
+ updateTime: string;
|
|
|
+ isEnable: number;
|
|
|
+ filePath?: string;
|
|
|
+ file?: File;
|
|
|
+}
|
|
|
+
|
|
|
+interface IntroductResponse extends BaseResponse {
|
|
|
+ data: IntroductItem[]
|
|
|
+}
|
|
|
+const searchForm = reactive({
|
|
|
+ name: '',
|
|
|
+ phone: '',
|
|
|
+});
|
|
|
+
|
|
|
+const tableData = ref([
|
|
|
+ {
|
|
|
+ avatar: 'https://ai-public.mastergo.com/ai/img_res/ab6b2a2731dd9309532c1d31e77e37d8.jpg',
|
|
|
+ name: '邵建国',
|
|
|
+ gender: '男',
|
|
|
+ IDNO: '430524199808084151',
|
|
|
+ DEPARTMENT: '保安一部',
|
|
|
+ PositionLevel: '二级',
|
|
|
+ entryTime: '2025-01-02',
|
|
|
+ contractPeriod: '一年',
|
|
|
+ PPS: '实习',
|
|
|
+ DirectSupervisor: '张三',
|
|
|
+ WorkLocation: '综合楼',
|
|
|
+ phone: '13812345678',
|
|
|
+ certName: '安保人员资格证',
|
|
|
+ certStatus: '有效',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ avatar: 'https://ai-public.mastergo.com/ai/img_res/adb4757a51078fd93278243eabcbf90a.jpg',
|
|
|
+ name: '李志强',
|
|
|
+ gender: '男',
|
|
|
+ IDNO: '430524199808084151',
|
|
|
+ DEPARTMENT: '保安一部',
|
|
|
+ PositionLevel: '二级',
|
|
|
+ entryTime: '2025-01-02',
|
|
|
+ contractPeriod: '一年',
|
|
|
+ PPS: '实习',
|
|
|
+ DirectSupervisor: '张三',
|
|
|
+ WorkLocation: '综合楼',
|
|
|
+ phone: '13812345678',
|
|
|
+ certName: '安保人员资格证',
|
|
|
+ certStatus: '有效',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ avatar: 'https://ai-public.mastergo.com/ai/img_res/4e3ef5f71c53f38ea1cf35689071b390.jpg',
|
|
|
+ name: '王秀英',
|
|
|
+ gender: '男',
|
|
|
+ IDNO: '430524199808084151',
|
|
|
+ DEPARTMENT: '保安一部',
|
|
|
+ PositionLevel: '二级',
|
|
|
+ entryTime: '2025-01-02',
|
|
|
+ contractPeriod: '一年',
|
|
|
+ PPS: '实习',
|
|
|
+ DirectSupervisor: '张三',
|
|
|
+ WorkLocation: '综合楼',
|
|
|
+ phone: '13812345678',
|
|
|
+ certName: '安保人员资格证',
|
|
|
+ certStatus: '有效',
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
+const currentPage = ref(1);
|
|
|
+const pageSize = ref(10);
|
|
|
+const total = ref(100);
|
|
|
+
|
|
|
+const dialogVisible = ref(false);
|
|
|
+const dialogType = ref<'add' | 'edit'>('add');
|
|
|
+const formRef = ref<FormInstance>();
|
|
|
+
|
|
|
+const form = reactive({
|
|
|
+ avatar: '',
|
|
|
+ name: '',
|
|
|
+ phone: '',
|
|
|
+ cert: '',
|
|
|
+ certDate: [],
|
|
|
+});
|
|
|
+
|
|
|
+
|
|
|
+const getData = async () => {
|
|
|
+ const res = await clientGet<null, IntroductResponse>('/park/securityPersonnel/getList')
|
|
|
+ if (res.code === 200) {
|
|
|
+ console.log("获取到数据:", res.data)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+getData();
|
|
|
+
|
|
|
+const rules: FormRules = {
|
|
|
+ name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
|
|
+ phone: [
|
|
|
+ { required: true, message: '请输入手机号', trigger: 'blur' },
|
|
|
+ {
|
|
|
+ pattern: /^1[3-9]\d{9}$/,
|
|
|
+ message: '请输入正确的手机号',
|
|
|
+ trigger: 'blur',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ cert: [{ required: true, message: '请上传证书', trigger: 'change' }],
|
|
|
+ certDate: [{ required: true, message: '请选择证书有效期', trigger: 'change' }],
|
|
|
+};
|
|
|
+
|
|
|
+const handleSearch = () => {
|
|
|
+ // 实现搜索逻辑
|
|
|
+};
|
|
|
+
|
|
|
+const handleReset = () => {
|
|
|
+ searchForm.name = '';
|
|
|
+ searchForm.phone = '';
|
|
|
+};
|
|
|
+
|
|
|
+const handleAdd = () => {
|
|
|
+ dialogType.value = 'add';
|
|
|
+ dialogVisible.value = true;
|
|
|
+ Object.assign(form, {
|
|
|
+ avatar: '',
|
|
|
+ name: '',
|
|
|
+ phone: '',
|
|
|
+ cert: '',
|
|
|
+ certDate: [],
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ // try {
|
|
|
+ // const formData = new FormData();
|
|
|
+ // Object.entries(addForm.value).forEach(([key, value]) => {
|
|
|
+ // if (key === 'file' && value instanceof File) {
|
|
|
+ // formData.append('file', value);
|
|
|
+ // } else {
|
|
|
+ // formData.append(key, String(value));
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+
|
|
|
+ // const res = await clientPost<FormData, BaseResponse>('/park/parkInfo/save', formData, {
|
|
|
+ // headers: {
|
|
|
+ // 'Content-Type': 'multipart/form-data',
|
|
|
+ // },
|
|
|
+ // });
|
|
|
+
|
|
|
+ // if (res.code === 200) {
|
|
|
+ // getData();
|
|
|
+ // dialogVisible.value = false;
|
|
|
+ // ElMessage.success('新增成功');
|
|
|
+ // addForm.value = initData;
|
|
|
+ // }
|
|
|
+ // } catch (error) {
|
|
|
+ // console.error('新增失败', error);
|
|
|
+ // ElMessage.error('新增失败');
|
|
|
+ // }
|
|
|
+};
|
|
|
+
|
|
|
+const handleEdit = (row: any) => {
|
|
|
+ dialogType.value = 'edit';
|
|
|
+ dialogVisible.value = true;
|
|
|
+ Object.assign(form, row);
|
|
|
+};
|
|
|
+
|
|
|
+const handleDelete = (row: any) => {
|
|
|
+ ElMessageBox.confirm('确认删除该安保人员?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning',
|
|
|
+ }).then(() => {
|
|
|
+ ElMessage({
|
|
|
+ type: 'success',
|
|
|
+ message: '删除成功',
|
|
|
+ });
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleSizeChange = (val: number) => {
|
|
|
+ pageSize.value = val;
|
|
|
+};
|
|
|
+
|
|
|
+const handleCurrentChange = (val: number) => {
|
|
|
+ currentPage.value = val;
|
|
|
+};
|
|
|
+
|
|
|
+const handleAvatarSuccess = (response: any) => {
|
|
|
+ form.avatar = response.url;
|
|
|
+};
|
|
|
+
|
|
|
+const handleCertSuccess = (response: any) => {
|
|
|
+ form.cert = response.url;
|
|
|
+};
|
|
|
+
|
|
|
+const handleSubmit = async () => {
|
|
|
+ if (!formRef.value) return;
|
|
|
+ await formRef.value.validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ ElMessage({
|
|
|
+ type: 'success',
|
|
|
+ message: dialogType.value === 'add' ? '添加成功' : '修改成功',
|
|
|
+ });
|
|
|
+ dialogVisible.value = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const getCertStatusType = (status: string) => {
|
|
|
+ const statusMap: Record<string, string> = {
|
|
|
+ 有效: 'success',
|
|
|
+ 即将过期: 'warning',
|
|
|
+ 已过期: 'danger',
|
|
|
+ };
|
|
|
+ return statusMap[status] || 'info';
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.avatar-uploader {
|
|
|
+ width: 100px;
|
|
|
+ height: 100px;
|
|
|
+}
|
|
|
+
|
|
|
+.avatar-uploader-icon {
|
|
|
+ font-size: 28px;
|
|
|
+ width: 100px;
|
|
|
+ height: 100px;
|
|
|
+}
|
|
|
+
|
|
|
+.avatar-image {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|