From 40f5cf2a8c324bf08fd5f0aec2e9da00e5f59f76 Mon Sep 17 00:00:00 2001
From: yubo <autumnal_wind@yeah.net>
Date: 星期六, 11 四月 2026 20:29:40 +0800
Subject: [PATCH] fix(user): 在职员工界面优化
---
src/views/user/components/EmpBaseEdit.vue | 1115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 1,115 insertions(+), 0 deletions(-)
diff --git a/src/views/user/components/EmpBaseEdit.vue b/src/views/user/components/EmpBaseEdit.vue
new file mode 100644
index 0000000..bb1359c
--- /dev/null
+++ b/src/views/user/components/EmpBaseEdit.vue
@@ -0,0 +1,1115 @@
+<template>
+ <el-dialog title="基本信息" :visible.sync="visible" width="50%" class="baseinfo" @close="handleClose">
+ <el-container>
+ <el-aside width="200px">
+ <!-- 头像显示区域 -->
+ <div class="avatar-wrapper">
+ <img
+ v-if="empBaseInfoImageUrl"
+ :src="empBaseInfoImageUrl"
+ class="avatar"
+ @click="openUploadChoice"
+ >
+ <div v-else class="avatar-uploader-placeholder" @click="openUploadChoice">
+ <i class="el-icon-plus avatar-uploader-icon" />
+ <div class="upload-tip">点击上传照片</div>
+ </div>
+ </div>
+ </el-aside>
+ <el-main>
+ <el-form
+ ref="empBaseInfoForm"
+ :model="empBaseInfoForm"
+ :rules="isAdd ? addRules : rules"
+ label-position="right"
+ label-width="120px"
+ >
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="档案号" prop="archivesNumb">
+ <el-input v-model="empBaseInfoForm.archivesNumb" />
+ </el-form-item>
+ <el-form-item label="员工编号" prop="empNumb">
+ <el-input v-model="empBaseInfoForm.empNumb" />
+ </el-form-item>
+ <el-form-item label="身份证号码" prop="certificateNumb">
+ <el-input
+ v-model="empBaseInfoForm.certificateNumb"
+ @input="generateUserInfo(0,empBaseInfoForm.certificateNumb)"
+ />
+ </el-form-item>
+ <el-form-item label="员工类别" prop="empType">
+ <el-select v-model="empBaseInfoForm.empType" placeholder="请选择员工类型">
+ <el-option
+ v-for="dict in empTypeOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="民族" prop="nation">
+ <el-select v-model="empBaseInfoForm.nation" filterable placeholder="请选择民族">
+ <el-option
+ v-for="dict in nationOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="婚姻状态" prop="marriage">
+ <el-select v-model="empBaseInfoForm.marriage" placeholder="请选择婚姻状态">
+ <el-option
+ v-for="dict in marriageOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="身高(cm)" prop="stature">
+ <el-input v-model="empBaseInfoForm.stature" />
+ </el-form-item>
+ <el-form-item label="政治面貌" prop="politics">
+ <el-select v-model="empBaseInfoForm.politics" placeholder="请选择政治面貌">
+ <el-option
+ v-for="dict in statusOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="学历" prop="education">
+ <el-select v-model="empBaseInfoForm.education" placeholder="请选择学历">
+ <el-option
+ v-for="dict in educationOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="籍贯" prop="nativePlaceName">
+ <el-autocomplete
+ v-model="empBaseInfoForm.nativePlaceName"
+ class="inline-input"
+ :fetch-suggestions="querySearch"
+ placeholder="请输入籍贯"
+ @select="placeNameSelect"
+ />
+ </el-form-item>
+ <el-form-item label="现住址" prop="currentAddress">
+ <el-input v-model="empBaseInfoForm.currentAddress" />
+ </el-form-item>
+ <el-form-item label="电话号码" prop="telePhone">
+ <el-input v-model="empBaseInfoForm.telePhone" />
+ </el-form-item>
+ <el-form-item label="招聘介绍人" prop="introducer">
+ <el-input v-model="empBaseInfoForm.introducer" />
+ </el-form-item>
+ <el-form-item label="银行名称">
+ <el-input v-model="empBaseInfoForm.bankName" />
+ </el-form-item>
+ <el-form-item label="社保档位" prop="insuranceType">
+ <el-select v-model="empBaseInfoForm.insuranceType" placeholder="请选择社保档位">
+ <el-option
+ v-for="dict in insuranceTypeOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="家庭成员及关系1" prop="family">
+ <el-input v-model="empBaseInfoForm.family" />
+ </el-form-item>
+ <el-form-item label="家庭成员及关系2" prop="urgencyPhone">
+ <el-input v-model="empBaseInfoForm.urgencyPhone" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="姓名" prop="empName">
+ <el-input v-model="empBaseInfoForm.empName" />
+ </el-form-item>
+ <el-form-item label="部门(护卫点)" required message="请选择护卫点" prop="deptId">
+ <treeselect
+ v-model="empBaseInfoForm.deptId"
+ :multiple="false"
+ :options="depts"
+ :clear-value-text="$t('common.clear')"
+ placeholder="请选择部门(护卫点)"
+ style="width:100%"
+ @select="empDeptNameSelect"
+ />
+ </el-form-item>
+ <el-form-item label="岗位" prop="jobName">
+ <el-autocomplete
+ v-model="empBaseInfoForm.jobName"
+ class="inline-input"
+ :fetch-suggestions="querySearchJob"
+ placeholder="请输入岗位"
+ @select="jobNameSelect"
+ />
+ </el-form-item>
+ <el-form-item label="性别" prop="sex">
+ <el-select v-model="empBaseInfoForm.sex" placeholder="请选择性别">
+ <el-option
+ v-for="dict in sexOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="身份证有效期" prop="certificateValidity">
+ <el-date-picker
+ v-model="empBaseInfoForm.certificateValidity"
+ type="date"
+ value-format="yyyy-MM-dd"
+ placeholder="选择日期"
+ />
+ </el-form-item>
+ <el-form-item label="年龄" prop="age">
+ <el-input v-model="empBaseInfoForm.age" />
+ </el-form-item>
+ <el-form-item label="出生日期" prop="birthdate">
+ <el-date-picker
+ v-model="empBaseInfoForm.birthdate"
+ type="date"
+ value-format="yyyy-MM-dd"
+ placeholder="选择日期"
+ />
+ </el-form-item>
+ <el-form-item label="入职日期" prop="entryDate">
+ <el-date-picker
+ v-model="empBaseInfoForm.entryDate"
+ type="date"
+ value-format="yyyy-MM-dd"
+ placeholder="选择日期"
+ @input="calculateSeniority"
+ />
+ </el-form-item>
+ <el-form-item label="入司工龄" prop="seniority">
+ <el-input v-model="empBaseInfoForm.seniority" />
+ </el-form-item>
+ <el-form-item label="户籍地址" prop="censusAddress">
+ <el-input v-model="empBaseInfoForm.censusAddress" />
+ </el-form-item>
+ <el-form-item label="保安员证号" prop="guardNumb">
+ <el-input v-model="empBaseInfoForm.guardNumb" />
+ </el-form-item>
+ <el-form-item label="保安员回执" prop="returnReceipt">
+ <el-input v-model="empBaseInfoForm.returnReceipt" />
+ </el-form-item>
+ <el-form-item label="档案情况" prop="archivesStatus">
+ <el-select v-model="empBaseInfoForm.archivesStatus" placeholder="请选择档案情况">
+ <el-option
+ v-for="dict in archivesStatusOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="银行账号">
+ <el-input v-model="empBaseInfoForm.bankNumb" />
+ </el-form-item>
+ <el-form-item label="社保电脑号" prop="socialNumb">
+ <el-input v-model="empBaseInfoForm.socialNumb" />
+ </el-form-item>
+ <el-form-item label="员工手册" prop="handbookStatus">
+ <el-select v-model="empBaseInfoForm.handbookStatus" placeholder="请选择员工手册">
+ <el-option
+ v-for="dict in handbookStatusOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="工作证" prop="empCardStatus">
+ <el-select v-model="empBaseInfoForm.empCardStatus" placeholder="请选择工作证">
+ <el-option
+ v-for="dict in empCardStatusOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item label="相关证件" prop="certificateList">
+ <el-select v-model="empBaseInfoForm.certificateList" multiple placeholder="请选择相关证件">
+ <el-option
+ v-for="dict in certificateListOptions"
+ :key="dict.dicItemCode"
+ :label="dict.dicItemName"
+ :value="dict.dicItemCode"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ </el-main>
+ </el-container>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="putEmpBase('empBaseInfoForm')">保 存</el-button>
+ <el-button type="primary" @click="putEmpBaseContinue('empBaseInfoForm')">保存并继续新增</el-button>
+ <el-button @click="handleClose">取 消</el-button>
+ </div>
+
+ <!-- 上传方式选择弹窗 -->
+ <el-dialog
+ title="选择上传方式"
+ :visible.sync="uploadChoiceDialogVisible"
+ width="400px"
+ :close-on-click-modal="false"
+ append-to-body
+ >
+ <div class="upload-choice-container">
+ <div class="upload-choice-item" @click="choiceCamera">
+ <i class="el-icon-camera" />
+ <span>拍照上传</span>
+ </div>
+ <div class="upload-choice-item" @click="choiceFile">
+ <i class="el-icon-folder-opened" />
+ <span>文件上传</span>
+ </div>
+ </div>
+ </el-dialog>
+
+ <!-- 摄像头拍照弹窗 -->
+ <el-dialog
+ title="拍照上传"
+ :visible.sync="cameraDialogVisible"
+ width="640px"
+ :close-on-click-modal="false"
+ append-to-body
+ @close="closeCamera"
+ >
+ <div class="camera-container">
+ <!-- 视频预览 -->
+ <video
+ v-show="!capturedImage"
+ ref="video"
+ class="camera-video"
+ autoplay
+ playsinline
+ />
+ <!-- 画布(用于拍照) -->
+ <canvas ref="canvas" style="display: none;" />
+
+ <!-- 拍照结果预览 -->
+ <img
+ v-if="capturedImage"
+ :src="capturedImage"
+ class="captured-image"
+ >
+ </div>
+
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="closeCamera">取消</el-button>
+ <el-button
+ v-if="!capturedImage"
+ type="primary"
+ @click="takePhoto"
+ >
+ 拍照
+ </el-button>
+ <el-button
+ v-if="capturedImage"
+ @click="retakePhoto"
+ >
+ 重拍
+ </el-button>
+ <el-button
+ v-if="capturedImage"
+ type="primary"
+ @click="confirmPhoto"
+ >
+ 确认使用
+ </el-button>
+ </div>
+ </el-dialog>
+ </el-dialog>
+</template>
+
+<script>
+import Treeselect from '@riophae/vue-treeselect'
+import '@riophae/vue-treeselect/dist/vue-treeselect.css'
+import { calculateSeniority, toCardGetUserInfo } from '@/utils/myUtil'
+import { pages } from '@/settings'
+import dictMixin from '@/utils/dictMixin'
+
+export default {
+ name: 'EmpBaseEdit',
+ components: { Treeselect },
+ mixins: [dictMixin],
+ props: {
+ dialogVisible: {
+ type: Boolean,
+ default: false
+ },
+ isAdd: {
+ type: Boolean,
+ default: false
+ },
+ employeeData: {
+ type: Object,
+ default: () => ({})
+ },
+ depts: {
+ type: Array,
+ default: () => []
+ }
+ },
+ data() {
+ return {
+ empBaseInfoForm: {
+ imagePath: '',
+ empId: '',
+ customerId: '',
+ archivesNumb: '',
+ deptId: null,
+ deptName: '',
+ empNumb: '',
+ allDeptName: '',
+ empName: '',
+ sex: '1',
+ JobId: '',
+ jobName: '',
+ empType: '01',
+ certificateType: '',
+ certificateNumb: '',
+ nation: '01',
+ certificateValidity: '',
+ marriage: '1',
+ age: '',
+ stature: '',
+ birthdate: '',
+ politics: '13',
+ entryDate: '',
+ education: '17',
+ seniority: '',
+ nativePlace: '',
+ nativePlaceName: '',
+ censusAddress: '',
+ currentAddress: '',
+ guardNumb: '',
+ telePhone: '',
+ returnReceipt: '',
+ introducer: '',
+ archivesStatus: '0',
+ bankName: '',
+ bankNumb: '',
+ insuranceType: '',
+ socialNumb: '',
+ family: '',
+ handbookStatus: '0',
+ urgencyPhone: '',
+ empCardStatus: '0',
+ certificateList: '',
+ createTime: '',
+ creator: '',
+ modifyTime: '',
+ modifier: '',
+ delFlag: '0',
+ empStatus: 0,
+ version: '',
+ entryType: '20'
+ },
+ empBaseInfoImageUrl: '',
+ uploadChoiceDialogVisible: false,
+ cameraDialogVisible: false,
+ capturedImage: '',
+ stream: null,
+ restaurants: [{ value: '北京市', code: '110000' },
+ { value: '天津市', code: '120000' },
+ { value: '河北省', code: '130000' },
+ { value: '山西省', code: '140000' },
+ { value: '内蒙古自治区', code: '150000' },
+ { value: '辽宁省', code: '210000' },
+ { value: '吉林省', code: '220000' },
+ { value: '黑龙江省', code: '230000' },
+ { value: '上海市', code: '310000' },
+ { value: '江苏省', code: '320000' },
+ { value: '浙江省', code: '330000' },
+ { value: '安徽省', code: '340000' },
+ { value: '福建省', code: '350000' },
+ { value: '江西省', code: '360000' },
+ { value: '山东省', code: '370000' },
+ { value: '河南省', code: '410000' },
+ { value: '湖北省', code: '420000' },
+ { value: '湖南省', code: '430000' },
+ { value: '广东省', code: '440000' },
+ { value: '广西壮族自治区', code: '450000' },
+ { value: '海南省', code: '460000' },
+ { value: '重庆市', code: '500000' },
+ { value: '四川省', code: '510000' },
+ { value: '贵州省', code: '520000' },
+ { value: '云南省', code: '530000' },
+ { value: '西藏自治区', code: '540000' },
+ { value: '陕西省', code: '610000' },
+ { value: '甘肃省', code: '620000' },
+ { value: '青海省', code: '630000' },
+ { value: '宁夏回族自治区', code: '640000' },
+ { value: '新疆维吾尔自治区', code: '650000' },
+ { value: '台湾省', code: '710000' },
+ { value: '香港特别行政区', code: '810000' },
+ { value: '澳门特别行政区', code: '820000' }],
+ restaurJob: [{ value: '总经理', code: '2942725270000031' },
+ { value: '总秘', code: '2942725270000032' },
+ { value: '总助', code: '2942725270000033' },
+ { value: '经理', code: '2942725270000022' },
+ { value: '副经理', code: '2942725270000015' },
+ { value: '助理', code: '2942725270000030' },
+ { value: '项目经理', code: '2942725270000027' },
+ { value: '大队长', code: '2942725270000006' },
+ { value: '大队长兼内勤', code: '2942725270000007' },
+ { value: '中队长', code: '2942725270000029' },
+ { value: '队长', code: '2942725270000011' },
+ { value: '分队长', code: '2942725270000013' },
+ { value: '副队长', code: '2942725270000014' },
+ { value: '班长', code: '2942725270000002' },
+ { value: '保安员', code: '2942725270000003' },
+ { value: '内勤', code: '2942725270000024' },
+ { value: '保洁', code: '2942725270000004' },
+ { value: '电工', code: '2942725270000010' },
+ { value: '绿化工', code: '2942725270000023' },
+ { value: '出纳', code: '2942725270000005' },
+ { value: '人事专员', code: '2942725270000025' },
+ { value: '司机', code: '2942725270000026' },
+ { value: '购买保险', code: '2942725270000016' },
+ { value: '广州燃气中队长', code: '2942725270000018' },
+ { value: '管理员', code: '2942725270000017' },
+ { value: '监控员', code: '2942725270000021' },
+ { value: '员工', code: '2942725270000028' }],
+ rules: {
+ archivesNumb: [{ max: 20, message: this.$t('rules.noMoreThan20'), trigger: 'blur' }],
+ empName: [{ required: true, message: '请输入姓名', trigger: 'blur' },
+ { min: 2, max: 50, message: this.$t('rules.noMoreThan50'), trigger: 'blur' }],
+ empNumb: [{ required: true, message: '请输入员工编号', trigger: 'blur' },
+ { min: 2, max: 20, message: this.$t('rules.noMoreThan20'), trigger: 'blur' }],
+ deptName: [
+ { required: true, message: '请选择护卫点', trigger: 'input' }
+ ],
+ certificateNumb: [{ required: true, message: '请输入身份证号', trigger: 'blur' }],
+ jobName: [{ required: true, message: '请选择岗位', trigger: 'change' }],
+ nativePlaceName: [{ required: true, message: '请选择籍贯', trigger: 'change' }],
+ bankName: [{ required: true, message: '请输入银行名称', trigger: 'blur' }, {
+ max: 36,
+ message: '长度不超过36个字符',
+ trigger: 'blur'
+ }],
+ insuranceType: [{ required: true, message: '请选择社保档位', trigger: 'change' }],
+ entryDate: [{ required: true, message: '请选择入职日期', trigger: 'change' }],
+ seniority: [{ required: true, message: '请输入入司工龄', trigger: 'blur' }],
+ archivesStatus: [{ required: true, message: '请选择档案情况', trigger: 'change' }],
+ bankNumb: [{ required: true, message: '请输入银行账号', trigger: 'blur' }, {
+ max: 32,
+ message: '长度不超过32个字符',
+ trigger: 'blur'
+ }],
+ empType: [{ required: true, message: '请选择员工类型', trigger: 'change' }],
+ censusAddress: [{ max: 128, message: '长度不超过128个字符', trigger: 'blur' }],
+ currentAddress: [{ max: 128, message: '长度不超过128个字符', trigger: 'blur' }],
+ guardNumb: [{ max: 40, message: '长度不超过40个字符', trigger: 'blur' }],
+ telePhone: [{ max: 30, message: '长度不超过30个字符', trigger: 'blur' }],
+ returnReceipt: [{ max: 40, message: '长度不超过40个字符', trigger: 'blur' }],
+ introducer: [{ max: 32, message: '长度不超过32个字符', trigger: 'blur' }],
+ socialNumb: [{ max: 40, message: '长度不超过40个字符', trigger: 'blur' }],
+ family: [{ max: 128, message: '长度不超过128个字符', trigger: 'blur' }],
+ certificateValidity: [{ required: true, message: '请选择身份证有效期', trigger: 'change' }],
+ urgencyPhone: [{ max: 30, message: '长度不超过30个字符', trigger: 'blur' }]
+ },
+ addRules: {
+ empName: [{ required: true, message: '请输入姓名', trigger: 'blur' },
+ { min: 2, max: 50, message: this.$t('rules.noMoreThan50'), trigger: 'blur' }],
+ empNumb: [{ required: true, message: '请输入员工编号', trigger: 'blur' },
+ { min: 2, max: 20, message: this.$t('rules.noMoreThan20'), trigger: 'blur' }],
+ certificateNumb: [{ required: true, message: '请输入身份证号', trigger: 'blur' }]
+ }
+ }
+ },
+ computed: {
+ visible: {
+ get() {
+ return this.dialogVisible
+ },
+ set(val) {
+ this.$emit('update:dialogVisible', val)
+ }
+ },
+ statusOptions() {
+ return this.getDictOptions('PLITICAL')
+ },
+ empTypeOptions() {
+ return this.getDictOptions('EMPTYPE')
+ },
+ nationOptions() {
+ return this.getDictOptions('NATION')
+ },
+ marriageOptions() {
+ return this.getDictOptions('MARRIAGE')
+ },
+ educationOptions() {
+ return this.getDictOptions('EDUCATION')
+ },
+ nativePlaceOptions() {
+ return this.getDictOptions('NATIVEPLACE')
+ },
+ archivesStatusOptions() {
+ return this.getDictOptions('archivesStatus')
+ },
+ insuranceTypeOptions() {
+ return this.getDictOptions('INSURANCETYPE')
+ },
+ empCardStatusOptions() {
+ return this.getDictOptions('empCardStatus')
+ },
+ handbookStatusOptions() {
+ return this.getDictOptions('handbookStatus')
+ },
+ certificateListOptions() {
+ return this.getDictOptions('certificateList')
+ },
+ sexOptions() {
+ return this.getDictOptions('sex')
+ }
+ },
+ watch: {
+ employeeData: {
+ handler(newVal) {
+ if (Object.keys(newVal).length > 0) {
+ this.loadEmployeeData(newVal)
+ } else {
+ this.cleanEmpBase()
+ }
+ },
+ immediate: true,
+ deep: true
+ }
+ },
+ mounted() {
+ this.initDictTypes(['PLITICAL', 'EMPTYPE', 'NATION', 'MARRIAGE', 'EDUCATION', 'NATIVEPLACE', 'archivesStatus', 'INSURANCETYPE', 'empCardStatus', 'handbookStatus', 'certificateList', 'sex'])
+ this.initJob()
+ },
+ methods: {
+ initJob() {
+ this.$get('system/position/dicJob').then((r) => {
+ this.restaurJob = r.data.data
+ })
+ },
+ loadEmployeeData(row) {
+ let certificateList = []
+ if (row.certificateList && typeof row.certificateList === 'string') {
+ certificateList = row.certificateList.split(',')
+ row.certificateList = certificateList
+ }
+
+ this.empBaseInfoForm.empId = row.empId
+ this.empBaseInfoForm.customerId = row.customerId
+ this.empBaseInfoForm.archivesNumb = row.archivesNumb
+ this.empBaseInfoForm.deptId = row.deptId
+ this.empBaseInfoForm.deptName = row.deptName
+ this.empBaseInfoForm.empNumb = row.empNumb
+ this.empBaseInfoForm.empName = row.empName
+ this.empBaseInfoForm.JobId = row.JobId
+ this.empBaseInfoForm.jobName = row.jobName
+ this.empBaseInfoForm.empType = row.empType
+ this.empBaseInfoForm.certificateType = row.certificateType
+ this.empBaseInfoForm.nation = row.nation
+ this.empBaseInfoForm.certificateValidity = row.certificateValidity
+ this.empBaseInfoForm.marriage = row.marriage
+ this.empBaseInfoForm.certificateNumb = row.certificateNumb
+ if (!row.birthdate) {
+ var userinfo = toCardGetUserInfo(this.empBaseInfoForm.certificateNumb)
+ if (userinfo !== null) {
+ this.empBaseInfoForm.age = userinfo.age
+ this.empBaseInfoForm.birthdate = userinfo.birth
+ this.empBaseInfoForm.sex = userinfo.sex
+ }
+ } else {
+ this.empBaseInfoForm.age = row.age
+ this.empBaseInfoForm.birthdate = row.birthdate
+ this.empBaseInfoForm.sex = row.sex
+ }
+ this.empBaseInfoForm.stature = row.stature
+ this.empBaseInfoForm.politics = row.politics
+ this.empBaseInfoForm.entryDate = row.entryDate
+ this.empBaseInfoForm.entryType = row.entryType
+ this.empBaseInfoForm.education = row.education
+ this.empBaseInfoForm.seniority = row.seniority
+ this.empBaseInfoForm.nativePlace = row.nativePlace
+ this.empBaseInfoForm.nativePlaceName = row.nativePlaceName
+ this.empBaseInfoForm.censusAddress = row.censusAddress
+ this.empBaseInfoForm.currentAddress = row.currentAddress
+ this.empBaseInfoForm.guardNumb = row.guardNumb
+ this.empBaseInfoForm.telePhone = row.telePhone
+ this.empBaseInfoForm.returnReceipt = row.returnReceipt
+ this.empBaseInfoForm.introducer = row.introducer
+ this.empBaseInfoForm.archivesStatus = row.archivesStatus
+ this.empBaseInfoForm.bankName = row.bankName
+ this.empBaseInfoForm.bankNumb = row.bankNumb
+ this.empBaseInfoForm.insuranceType = row.insuranceType
+ this.empBaseInfoForm.insuranceTypeName = row.insuranceTypeName
+ this.empBaseInfoForm.socialNumb = row.socialNumb
+ this.empBaseInfoForm.family = row.family
+ this.empBaseInfoForm.handbookStatus = row.handbookStatus
+ this.empBaseInfoForm.urgencyPhone = row.urgencyPhone
+ this.empBaseInfoForm.empCardStatus = row.empCardStatus
+ this.empBaseInfoForm.certificateList = row.certificateList
+ this.empBaseInfoForm.createTime = row.createTime
+ this.empBaseInfoForm.creator = row.creator
+ this.empBaseInfoForm.modifyTime = row.modifyTime
+ this.empBaseInfoForm.modifier = row.modifier
+ this.empBaseInfoForm.delFlag = row.delFlag
+ this.empBaseInfoForm.version = row.version
+ this.empBaseInfoImageUrl = pages.getEmpBaseInfoImage + row.empId + '?t=' + parseInt(100 * Math.random())
+ },
+ cleanEmpBase() {
+ this.empBaseInfoForm.empId = ''
+ this.empBaseInfoForm.customerId = ''
+ this.empBaseInfoForm.archivesNumb = ''
+ this.empBaseInfoForm.deptId = ''
+ this.empBaseInfoForm.deptName = ''
+ this.empBaseInfoForm.empNumb = ''
+ this.empBaseInfoForm.empName = ''
+ this.empBaseInfoForm.sex = ''
+ this.empBaseInfoForm.JobId = ''
+ this.empBaseInfoForm.jobName = ''
+ this.empBaseInfoForm.empType = ''
+ this.empBaseInfoForm.certificateType = ''
+ this.empBaseInfoForm.certificateNumb = ''
+ this.empBaseInfoForm.nation = ''
+ this.empBaseInfoForm.certificateValidity = ''
+ this.empBaseInfoForm.marriage = ''
+ this.empBaseInfoForm.age = ''
+ this.empBaseInfoForm.stature = ''
+ this.empBaseInfoForm.birthdate = ''
+ this.empBaseInfoForm.politics = ''
+ this.empBaseInfoForm.entryDate = ''
+ this.empBaseInfoForm.education = ''
+ this.empBaseInfoForm.seniority = ''
+ this.empBaseInfoForm.nativePlace = ''
+ this.empBaseInfoForm.nativePlaceName = ''
+ this.empBaseInfoForm.censusAddress = ''
+ this.empBaseInfoForm.currentAddress = ''
+ this.empBaseInfoForm.guardNumb = ''
+ this.empBaseInfoForm.telePhone = ''
+ this.empBaseInfoForm.returnReceipt = ''
+ this.empBaseInfoForm.introducer = ''
+ this.empBaseInfoForm.archivesStatus = ''
+ this.empBaseInfoForm.bankName = ''
+ this.empBaseInfoForm.bankNumb = ''
+ this.empBaseInfoForm.insuranceType = ''
+ this.empBaseInfoForm.socialNumb = ''
+ this.empBaseInfoForm.family = ''
+ this.empBaseInfoForm.handbookStatus = ''
+ this.empBaseInfoForm.urgencyPhone = ''
+ this.empBaseInfoForm.empCardStatus = ''
+ this.empBaseInfoForm.certificateList = ''
+ this.empBaseInfoForm.createTime = ''
+ this.empBaseInfoForm.creator = ''
+ this.empBaseInfoForm.modifyTime = ''
+ this.empBaseInfoForm.modifier = ''
+ this.empBaseInfoForm.delFlag = ''
+ this.empBaseInfoForm.version = ''
+ this.empBaseInfoForm.imagePath = ''
+ this.empBaseInfoImageUrl = ''
+ },
+ putEmpBase(formName) {
+ const validateRules = this.isAdd ? this.addRules : this.rules
+ this.$refs[formName].validate((valid) => {
+ if (valid) {
+ this.submitEmpInfo()
+ }
+ }, validateRules)
+ },
+ putEmpBaseContinue(formName) {
+ const validateRules = this.isAdd ? this.addRules : this.rules
+ this.$refs[formName].validate((valid) => {
+ if (valid) {
+ this.submitEmpInfo(true)
+ }
+ }, validateRules)
+ },
+ submitEmpInfo(continueAdd = false) {
+ if (this.isAdd) {
+ this.$post('hr/empBaseInfo/addInEmp', { ...this.empBaseInfoForm }).then((r) => {
+ this.$message({
+ message: this.$t('tips.addSuccess'),
+ type: 'success'
+ })
+
+ this.$emit('success')
+
+ this.cleanEmpBase()
+
+ if (!continueAdd) {
+ this.handleClose()
+ }
+
+ if (r.data != null) {
+ if (r.data.data.empStatus === '0') {
+ this.$emit('employee-exists', r.data.data)
+ } else {
+ this.$emit('need-open-archives', {
+ empId: r.data.data.empId,
+ empName: r.data.data.empName,
+ certificateNumb: r.data.data.certificateNumb,
+ dimissionType: r.data.data.dimissionType,
+ remark: r.data.data.remark
+ })
+ }
+ }
+ })
+ } else {
+ this.$put('hr/empBaseInfo', { ...this.empBaseInfoForm }).then(() => {
+ this.$message({
+ message: this.$t('tips.updateSuccess'),
+ type: 'success'
+ })
+ this.$emit('success')
+ this.cleanEmpBase()
+ this.handleClose()
+ })
+ }
+ },
+ handleClose() {
+ this.cleanEmpBase()
+ this.$emit('close')
+ },
+ generateUserInfo(index, val) {
+ var userinfo = toCardGetUserInfo(val)
+ if (userinfo === null) {
+ return
+ }
+ this.empBaseInfoForm.age = userinfo.age
+ this.empBaseInfoForm.birthdate = userinfo.birth
+ this.empBaseInfoForm.sex = userinfo.sex
+ },
+ calculateSeniority(val) {
+ this.empBaseInfoForm.seniority = calculateSeniority(val)
+ },
+ querySearch(queryString, cb) {
+ var restaurants = this.restaurants
+ var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
+ cb(results)
+ },
+ createFilter(queryString) {
+ return (restaurant) => {
+ return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
+ }
+ },
+ placeNameSelect(item) {
+ this.empBaseInfoForm.nativePlaceName = item.value
+ this.empBaseInfoForm.nativePlace = item.code
+ },
+ querySearchJob(queryString, cb) {
+ const restaurants = this.restaurJob
+ const results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
+ cb(results)
+ },
+ jobNameSelect(item) {
+ this.empBaseInfoForm.jobName = item.value
+ this.empBaseInfoForm.JobId = item.code
+ },
+ empDeptNameSelect(val) {
+ this.empBaseInfoForm.deptId = val.id
+ this.empBaseInfoForm.deptName = val.label
+ this.empBaseInfoForm.allDeptName = val.allDeptName
+ },
+ getImageBlob(url, cb) {
+ var xhr = new XMLHttpRequest()
+ xhr.open('get', url, true)
+ xhr.responseType = 'blob'
+ xhr.onload = function() {
+ if (this.status === 200) {
+ if (cb) cb(this.response)
+ }
+ }
+ xhr.send()
+ },
+ preView(url) {
+ var this_ = this
+ const reader = new FileReader()
+ this.getImageBlob(url, function(blob) {
+ reader.readAsDataURL(blob)
+ })
+ reader.onload = function(e) {
+ var img = document.createElement('img')
+ img.src = e.target.result
+ this_.empBaseInfoForm.imagePath = e.target.result
+ }
+ },
+ handlePictureCardPreview(file) {
+ this.empBaseInfoImageUrl = URL.createObjectURL(file.raw)
+ if (file.size < 4400000) {
+ var fileName = file.name
+ var suffix = fileName.substring(fileName.lastIndexOf('.') + 1).toUpperCase()
+ if (suffix === 'JPG' || suffix === 'PNG') {
+ this.preView(this.empBaseInfoImageUrl)
+ } else {
+ this.$message.error('只能上传jpg/png文件,且不超过4MB,请重新上传!')
+ }
+ } else {
+ this.$message.error('图片大小超过4M,请重新上传')
+ }
+ },
+ openUploadChoice() {
+ this.uploadChoiceDialogVisible = true
+ },
+ choiceCamera() {
+ this.uploadChoiceDialogVisible = false
+ this.cameraDialogVisible = true
+ this.$nextTick(() => {
+ this.initCamera()
+ })
+ },
+ choiceFile() {
+ this.uploadChoiceDialogVisible = false
+ const input = document.createElement('input')
+ input.type = 'file'
+ input.accept = 'image/*'
+ input.onchange = (e) => {
+ const file = e.target.files[0]
+ if (file) {
+ this.handleFileUpload(file)
+ }
+ }
+ input.click()
+ },
+ handleFileUpload(file) {
+ const isImage = file.type.startsWith('image/')
+ if (!isImage) {
+ this.$message.error('请上传图片文件')
+ return
+ }
+ const isLt10M = file.size / 1024 / 1024 < 10
+ if (!isLt10M) {
+ this.$message.error('图片大小不能超过10MB')
+ return
+ }
+ const imageUrl = URL.createObjectURL(file)
+ this.empBaseInfoImageUrl = imageUrl
+ const reader = new FileReader()
+ reader.onload = (e) => {
+ this.empBaseInfoForm.imagePath = e.target.result
+ this.$message.success('照片上传成功')
+ }
+ reader.readAsDataURL(file)
+ },
+ openCamera() {
+ this.cameraDialogVisible = true
+ this.$nextTick(() => {
+ this.initCamera()
+ })
+ },
+ async initCamera() {
+ try {
+ this.stream = await navigator.mediaDevices.getUserMedia({
+ video: {
+ width: { ideal: 640 },
+ height: { ideal: 480 },
+ facingMode: 'user'
+ },
+ audio: false
+ })
+
+ const video = this.$refs.video
+ if (video) {
+ video.srcObject = this.stream
+ }
+ } catch (error) {
+ this.$message.error('无法访问摄像头,请检查摄像头权限设置')
+ console.error('摄像头初始化失败:', error)
+ }
+ },
+ takePhoto() {
+ const video = this.$refs.video
+ const canvas = this.$refs.canvas
+
+ if (!video || !canvas) return
+
+ canvas.width = video.videoWidth || 640
+ canvas.height = video.videoHeight || 480
+
+ const ctx = canvas.getContext('2d')
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
+
+ this.capturedImage = canvas.toDataURL('image/jpeg', 0.9)
+
+ this.stopCamera()
+ },
+ retakePhoto() {
+ this.capturedImage = ''
+ this.initCamera()
+ },
+ confirmPhoto() {
+ if (this.capturedImage) {
+ this.empBaseInfoImageUrl = this.capturedImage
+ this.empBaseInfoForm.imagePath = this.capturedImage
+ this.closeCamera()
+ this.$message.success('照片已保存')
+ }
+ },
+ closeCamera() {
+ this.stopCamera()
+ this.cameraDialogVisible = false
+ this.capturedImage = ''
+ },
+ stopCamera() {
+ if (this.stream) {
+ this.stream.getTracks().forEach(track => {
+ track.stop()
+ })
+ this.stream = null
+ }
+
+ const video = this.$refs.video
+ if (video) {
+ video.srcObject = null
+ }
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.baseinfo .el-container {
+ .el-aside {
+ background-color: #fff;
+ }
+
+ .el-main {
+ background-color: #fff;
+ }
+}
+
+.el-autocomplete {
+ width: 100%;
+}
+
+.el-select {
+ width: 100%;
+}
+
+.el-aside {
+ padding: 20px;
+ background: #f3f5f8;
+ height: 600px;
+
+ .el-tree {
+ height: 100%;
+ }
+}
+
+.avatar-wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-bottom: 10px;
+
+ .avatar {
+ width: 150px;
+ height: 150px;
+ border-radius: 4px;
+ cursor: pointer;
+ object-fit: cover;
+ border: 1px dashed #d9d9d9;
+
+ &:hover {
+ border-color: #409eff;
+ }
+ }
+
+ .avatar-uploader-placeholder {
+ width: 150px;
+ height: 150px;
+ border: 1px dashed #d9d9d9;
+ border-radius: 4px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ background-color: #fafafa;
+
+ &:hover {
+ border-color: #409eff;
+ background-color: #f0f9ff;
+ }
+
+ .avatar-uploader-icon {
+ font-size: 28px;
+ color: #8c939d;
+ line-height: 1;
+ margin-bottom: 8px;
+ }
+
+ .upload-tip {
+ font-size: 12px;
+ color: #8c939d;
+ }
+ }
+}
+
+.upload-choice-container {
+ display: flex;
+ justify-content: space-around;
+ padding: 20px 0;
+
+ .upload-choice-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ width: 120px;
+ height: 120px;
+ border: 2px dashed #d9d9d9;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: all 0.3s;
+
+ &:hover {
+ border-color: #409eff;
+ background-color: #f5f7fa;
+ }
+
+ i {
+ font-size: 40px;
+ color: #409eff;
+ margin-bottom: 10px;
+ }
+
+ span {
+ font-size: 14px;
+ color: #606266;
+ }
+ }
+}
+
+.camera-container {
+ text-align: center;
+
+ .camera-video {
+ width: 100%;
+ max-width: 600px;
+ height: auto;
+ border-radius: 4px;
+ background: #000;
+ }
+
+ .captured-image {
+ width: 100%;
+ max-width: 600px;
+ height: auto;
+ border-radius: 4px;
+ }
+}
+</style>
--
Gitblit v1.8.0