ad77e25e868008e33a701084fd0e8c00a06cc6a0..c7043ff58f55df9c75ae161b3c134039dc895616
2026-04-11 yubo
fix(user): 在职员工界面优化
c7043f 对比 | 目录
2026-04-11 yubo
style(user): 调整员工编号列宽度
11ab4e 对比 | 目录
3个文件已添加
3个文件已修改
2993 ■■■■ 已修改文件
.env.development 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/position.js 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/user/archivesChange.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/user/components/CloseArchivesDialog.vue 253 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/user/components/EmpBaseEdit.vue 1115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/user/inemployees.vue 1570 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
@@ -2,7 +2,7 @@
ENV = 'development'
# base api
VUE_APP_BASE_API = 'http://192.168.5.12:8301/'
VUE_APP_BASE_API = 'http://localhost:8301/'
# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
# to control whether the babel-plugin-dynamic-import-node plugin is enabled.
src/api/position.js
New file
@@ -0,0 +1,52 @@
import request from './request'
// 获取岗位字典列表(用于下拉选择)
export function getDicJob() {
  return request({
    url: 'system/position/dicJob',
    method: 'get'
  })
}
// 获取岗位列表(完整信息)
export function getJobList(params) {
  return request({
    url: 'system/position/list',
    method: 'get',
    params
  })
}
// 根据岗位ID获取岗位详情
export function getJobById(jobId) {
  return request({
    url: `system/position/${jobId}`,
    method: 'get'
  })
}
// 新增岗位
export function addJob(data) {
  return request({
    url: 'system/position',
    method: 'post',
    data
  })
}
// 修改岗位
export function updateJob(data) {
  return request({
    url: 'system/position',
    method: 'put',
    data
  })
}
// 删除岗位
export function deleteJob(jobIds) {
  return request({
    url: `system/position/${jobIds}`,
    method: 'delete'
  })
}
src/views/user/archivesChange.vue
@@ -4207,7 +4207,6 @@
      })
    },
    setArchives(val) {
      debugger
      let certificateList = []
      if (val.certificateList && typeof val.certificateList === 'string') {
        certificateList = val.certificateList.split(',')
src/views/user/components/CloseArchivesDialog.vue
New file
@@ -0,0 +1,253 @@
<template>
  <el-dialog
    title="关闭档案"
    :visible.sync="dialogVisible"
    width="70%"
    @close="handleClose"
  >
    <el-form
      ref="gbdaForm"
      :model="formData"
      :rules="rules"
      label-position="right"
      label-width="120px"
    >
      <el-row>
        <el-col span="24">
          <el-form-item label="离职类型" prop="dimissionType">
            <el-radio-group v-model="formData.dimissionType" @change="handleDimissionTypeChange">
              <el-radio
                v-for="dict in dimissionTypeOptions"
                :key="dict.dicItemCode"
                :label="Number(dict.dicItemCode)"
              >
                {{ dict.dicItemName }}
              </el-radio>
            </el-radio-group>
          </el-form-item>
        </el-col>
        <el-col v-if="selectDimissionType === 4" span="12">
          <el-form-item label="自离天数" prop="selfLeaveDay">
            <el-input v-model="formData.selfLeaveDay" onkeyup="value=value.replace(/[^0-9.]/g,'')" />
          </el-form-item>
        </el-col>
        <el-col v-if="selectDimissionType === 4" span="12">
          <el-form-item label="报告人" prop="reporter">
            <el-input v-model="formData.reporter" />
          </el-form-item>
        </el-col>
        <el-col span="24">
          <el-form-item label="离职操作" prop="afterOperation">
            <el-checkbox-group v-model="formData.afterOperation">
              <el-checkbox label="1">解除劳动合同</el-checkbox>
              <el-checkbox label="2">禁用登录账号</el-checkbox>
            </el-checkbox-group>
          </el-form-item>
        </el-col>
        <el-col span="24">
          <el-form-item label="关闭日期" prop="dimissionDate">
            <el-date-picker
              v-model="formData.dimissionDate"
              type="date"
              value-format="yyyy-MM-dd"
              placeholder="选择日期"
              style="width: 100%"
            />
          </el-form-item>
          <el-form-item label="备注说明" prop="remark">
            <el-input v-model="formData.remark" type="textarea" :rows="4" />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button @click="handleCancel">取 消</el-button>
      <el-button type="primary" @click="handleConfirm">确 定</el-button>
    </div>
  </el-dialog>
</template>
<script>
export default {
  name: 'CloseArchivesDialog',
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    employees: {
      type: Array,
      default: () => []
    },
    dimissionTypeOptions: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      formData: {
        empIds: '',
        dgryNames: '',
        entryDates: '',
        dimissionType: 1,
        dimissionDate: '',
        remark: '',
        afterOperation: ['1'],
        certificateNumb: '',
        deptNames: '',
        selfLeaveDay: '',
        reporter: ''
      },
      rules: {
        dimissionType: [
          { required: true, message: '请选择离职类型', trigger: 'change' }
        ],
        dimissionDate: [
          { required: true, message: '请选择关闭日期', trigger: 'change' }
        ],
        selfLeaveDay: [
          { required: true, validator: this.validSelfLeaveDay }
        ],
        reporter: [
          { required: true, validator: this.validReporter }
        ],
        remark: [
          { max: 500, message: '长度不超过500个字符', trigger: 'blur' }
        ]
      },
      selectDimissionType: 1
    }
  },
  computed: {
    dialogVisible: {
      get() {
        return this.visible
      },
      set(val) {
        this.$emit('update:visible', val)
      }
    }
  },
  watch: {
    employees: {
      handler(val) {
        if (val && val.length > 0) {
          this.initFormData(val)
        }
      },
      immediate: false
    }
  },
  methods: {
    // 初始化表单数据
    initFormData(employees) {
      const ids = []
      const names = []
      const dates = []
      const numbers = []
      const deptNames = []
      employees.forEach(emp => {
        ids.push(emp.empId)
        names.push(emp.empName)
        dates.push(emp.entryDate)
        numbers.push(emp.certificateNumb)
        deptNames.push(emp.allDeptName)
      })
      // 默认关闭日期为当天
      const now = new Date()
      const year = now.getFullYear()
      const month = String(now.getMonth() + 1).padStart(2, '0')
      const day = String(now.getDate()).padStart(2, '0')
      this.formData = {
        empIds: ids.join(','),
        dgryNames: names.join(','),
        entryDates: dates.join(','),
        dimissionType: 1,
        dimissionDate: year + '-' + month + '-' + day,
        remark: '',
        afterOperation: ['1'],
        certificateNumb: numbers.join(','),
        deptNames: deptNames.join(','),
        selfLeaveDay: '',
        reporter: ''
      }
      this.selectDimissionType = 1
    },
    // 切换离职类型
    handleDimissionTypeChange(value) {
      this.selectDimissionType = value
    },
    // 自离天数验证
    validSelfLeaveDay(rule, value, callback) {
      const type = this.formData.dimissionType
      if (type === 4) {
        if (!value) {
          callback(new Error('自动离职时自离天数不能为空!'))
        } else {
          callback()
        }
      } else {
        callback()
      }
    },
    // 报告人验证
    validReporter(rule, value, callback) {
      const type = this.formData.dimissionType
      if (type === 4) {
        if (!value) {
          callback(new Error('自动离职时报告人不能为空!'))
        } else {
          if (value.length > 32) {
            callback(new Error('自动离职时报告人最多32个字符!'))
          } else {
            callback()
          }
        }
      } else {
        callback()
      }
    },
    // 确认提交
    handleConfirm() {
      this.$refs.gbdaForm.validate((valid) => {
        if (valid) {
          this.$post('hr/empBaseInfo/dimission', { ...this.formData }).then(() => {
            this.$message({
              message: '员工档案关闭成功',
              type: 'success'
            })
            this.dialogVisible = false
            this.$emit('success')
          })
        }
      })
    },
    // 取消
    handleCancel() {
      this.dialogVisible = false
      this.$emit('close')
    },
    // 关闭对话框
    handleClose() {
      if (this.$refs.gbdaForm) {
        this.$refs.gbdaForm.resetFields()
      }
      this.selectDimissionType = 1
      this.$emit('close')
    }
  }
}
</script>
<style scoped>
</style>
src/views/user/components/EmpBaseEdit.vue
New file
@@ -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>
src/views/user/inemployees.vue
@@ -259,7 +259,7 @@
            show-overflow-tooltip
            prop="empNumb"
            label="编号"
            width="80"
            width="100"
            sortable="custom"
            :sort-orders="['ascending', 'descending']"
          />
@@ -270,7 +270,7 @@
            sortable="custom"
            :sort-orders="['ascending', 'descending']"
          />
          <el-table-column show-overflow-tooltip prop="jobName" label="岗位" width="80" />
          <el-table-column show-overflow-tooltip prop="jobName" label="岗位" width="120" />
          <el-table-column
            show-overflow-tooltip
            prop="empName"
@@ -343,326 +343,25 @@
        />
      </el-main>
    </el-container>
    <el-dialog title="基本信息" :visible.sync="dialogShowXzyg" width="50%" class="baseinfo">
      <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="showXzyg()">取 消</el-button>
      </div>
    </el-dialog>
    <el-dialog title="员工调岗" :visible.sync="dialogShowYgdg" width="50%">
      <el-form ref="ygdgForm" :model="ygdgForm" :rules="ygdgRules" label-position="right" label-width="120px">
        <el-row>
          <el-col span="24">
            <el-form-item label="调岗人员">
              <input v-model="ygdgForm.empIds" type="hidden">
              <el-input v-model="ygdgForm.empNames" type="textarea" />
            </el-form-item>
            <el-form-item label="现部门(护卫点)" required message="请选择护卫点" prop="deptId">
              <treeselect
                v-model="ygdgForm.deptId"
                :multiple="false"
                :options="depts"
                :clear-value-text="$t('common.clear')"
                placeholder="请选择部门(护卫点)"
                style="width:100%"
                @select="deptNameSelect"
              />
            </el-form-item>
            <el-form-item label="现岗位" prop="jobId">
              <el-autocomplete
                v-model="ygdgForm.newJobName"
                class="inline-input"
                :fetch-suggestions="querySearchJob"
                placeholder="请输入岗位"
                @select="jobNameSelect"
              />
            </el-form-item>
            <el-form-item label="调岗类型" prop="changeType">
              <el-select v-model="ygdgForm.changeType" placeholder="请选择">
                <el-option
                  v-for="dict in changeTypeOptions"
                  :key="dict.dicItemCode"
                  :label="dict.dicItemName"
                  :value="dict.dicItemCode"
                />
              </el-select>
            </el-form-item>
            <el-form-item label="调岗日期" prop="changeDate">
              <el-date-picker
                v-model="ygdgForm.changeDate"
                type="date"
                value-format="yyyy-MM-dd"
                placeholder="选择日期"
              />
            </el-form-item>
            <el-form-item label="理由描述" prop="changeReason">
              <el-input v-model="ygdgForm.changeReason" type="textarea" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="showYgdg(1,'')">取 消</el-button>
        <el-button type="primary" @click="showYgdg(2,'ygdgForm')">确 定</el-button>
      </div>
    </el-dialog>
    <emp-base-edit
      ref="empBaseEdit"
      :dialog-visible="dialogShowXzyg"
      :is-add="isAdd"
      :employee-data="currentEmployeeData"
      :depts="depts"
      @success="handleEmpSaveSuccess"
      @close="dialogShowXzyg = false"
      @employee-exists="handleEmployeeExists"
      @need-open-archives="handleNeedOpenArchives"
    />
    <job-change-dialog
      :visible.sync="dialogShowYgdg"
      :employees="selectedEmployees"
      :depts="depts"
      :change-type-options="changeTypeOptions"
      @success="handleJobChangeSuccess"
      @close="handleJobChangeClose"
    />
    <el-dialog title="导入员工信息" :visible.sync="dialogShowDryg" width="50%">
      <el-form :model="baseicInformationForm" label-position="right" label-width="120px">
        <el-row>
@@ -692,60 +391,13 @@
        <el-button type="primary" @click="showDryg(2)">确 定</el-button>
      </div>
    </el-dialog>
    <el-dialog title="关闭档案" :visible.sync="dialogShowGbda" width="70%">
      <el-form ref="gbdaForm" :model="gbdaForm" :rules="gbdaRules" label-position="right" label-width="120px">
        <el-row>
          <el-col span="24">
            <el-form-item label="离职类型" prop="dimissionType">
              <el-radio-group v-model="gbdaForm.dimissionType" @change="changeDimissionType">
                <el-radio :label="1">合同期满</el-radio>
                <el-radio :label="2">公司劝退</el-radio>
                <el-radio :label="3">公司辞退</el-radio>
                <el-radio :label="4">自动离职</el-radio>
                <el-radio :label="5">试用期内</el-radio>
                <el-radio :label="6">正常离职</el-radio>
                <el-radio :label="7">到龄退休</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col v-if="selectDimissionType === 4" span="12">
            <el-form-item label="自离天数" prop="selfLeaveDay">
              <el-input v-model="gbdaForm.selfLeaveDay" onkeyup="value=value.replace(/[^0-9.]/g,'')" />
            </el-form-item>
          </el-col>
          <el-col v-if="selectDimissionType === 4" span="12">
            <el-form-item label="报告人" prop="reporter">
              <el-input v-model="gbdaForm.reporter" />
            </el-form-item>
          </el-col>
          <el-col span="24">
            <el-form-item label="离职操作" prop="afterOperation">
              <el-checkbox-group v-model="gbdaForm.afterOperation">
                <el-checkbox label="1">解除劳动合同</el-checkbox>
                <el-checkbox label="2">禁用登录账号</el-checkbox>
              </el-checkbox-group>
            </el-form-item>
          </el-col>
          <el-col span="24">
            <el-form-item label="关闭日期" prop="dimissionDate">
              <el-date-picker
                v-model="gbdaForm.dimissionDate"
                type="date"
                value-format="yyyy-MM-dd"
                placeholder="选择日期"
              />
            </el-form-item>
            <el-form-item label="备注说明" prop="remark">
              <el-input v-model="gbdaForm.remark" type="textarea" :rows="4" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="showGbda(1,'')">取 消</el-button>
        <el-button type="primary" @click="showGbda(2,'gbdaForm')">确 定</el-button>
      </div>
    </el-dialog>
    <close-archives-dialog
      :visible.sync="dialogShowGbda"
      :employees="selectedCloseEmployees"
      :dimission-type-options="dimissionTypeOptions"
      @success="handleCloseArchivesSuccess"
      @close="handleCloseArchivesClose"
    />
    <el-dialog title="导出员工" :visible.sync="dialogShowDcyg" width="40%">
      <div style="font-size: 16px;font-weight: 400;height: 35px;margin-top: -30px;color: #409EFF;">
        请勾选需要导出的字段
@@ -1081,15 +733,21 @@
import Pagination from '@/components/Pagination'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { calculateSeniority, toCardGetUserInfo, dateToString } from '@/utils/myUtil'
import { dateToString } from '@/utils/myUtil'
import ArchivesEdit from './archivesEdit'
import { pages } from '@/settings'
import EmpBaseEdit from './components/EmpBaseEdit'
import JobChangeDialog from './components/JobChangeDialog.vue'
import CloseArchivesDialog from './components/CloseArchivesDialog.vue'
import dictMixin from '../../utils/dictMixin'
export default {
  components: {
    EmpBaseEdit,
    ArchivesEdit,
    Pagination, Treeselect
    Pagination,
    Treeselect,
    JobChangeDialog,
    CloseArchivesDialog
  },
  mixins: [dictMixin],
  data() {
@@ -1123,210 +781,13 @@
        num: 1
      },
      baseicInformationForm: {},
      empBaseInfoImageUrl: '',
      // 上传方式选择弹窗
      uploadChoiceDialogVisible: false,
      // 摄像头相关
      cameraDialogVisible: false,
      capturedImage: '',
      stream: null,
      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'
      },
      ygdgForm: {
        empIds: [],
        empNames: [],
        oldDeptNames: [],
        oldJobNames: [],
        changeType: '',
        changeDate: '',
        changeReason: '',
        jobId: '',
        newJobName: '',
        deptId: '',
        newDeptName: '',
        allDeptName: ''
      },
      gbdaForm: {
        dgryIds: '',
        dimissionType: 1,
        dimissionDate: new Date(),
        remark: '',
        afterOperation: []
      },
      isAdd: false,
      currentEmployeeData: {},
      selectedEmployees: [],
      selectedCloseEmployees: [],
      depts: [],
      fileList: [],
      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' }]
      },
      gbdaRules: {
        dimissionType: [{ required: true, message: '请选择离职类型', trigger: 'change' }],
        dimissionDate: [{ required: true, message: '请选择关闭日期', trigger: 'change' }],
        selfLeaveDay: [{ required: true, validator: this.validSelfLeaveDay }],
        reporter: [{ required: true, validator: this.validReporter }],
        remark: [{ max: 500, message: '长度不超过500个字符', trigger: 'blur' }]
      },
      ygdgRules: {
        changeType: [{ required: true, message: '请选择调岗类型', trigger: 'change' }],
        changeDate: [{ required: true, message: '请选择调岗日期', trigger: 'change' }],
        jobId: [{ required: true, message: '请选择现岗位', trigger: 'change' }],
        deptId: [{ required: true, message: '请选择现部门', trigger: 'change' }],
        changeReason: [{ max: 500, message: '长度不超过500个字符', trigger: 'blur' }]
      },
      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' }],
      restaurJob: [],
      headerHeight: '30px',
      advancedQueryShow: false,
      dialogTableVisible: false,
@@ -1342,7 +803,6 @@
      cityOptions: ['archivesNumb', 'allDeptName', 'jobName', 'empName', 'certificateNumb', 'certificateValidity', 'sexName', 'nationName', 'age', 'marriageName', 'stature', 'birthdate', 'politicsName', 'empTypeName', 'educationName', 'nativePlaceName', 'censusAddress', 'currentAddress', 'guardNumb', 'returnReceipt', 'archivesStatusName', 'bankName', 'bankNumb', 'telePhone', 'entryDate', 'insuranceTypeName', 'socialNumb', 'introducer', 'seniority', 'empCardStatusName', 'certificateListName', 'urgencyPhone', 'handbookStatusName', 'family', 'empStatusName', 'dimissionDate', 'entryTypeName', 'dimissionTypeName', 'empNumb', 'annualLeave'],
      checkedCities: [],
      tableData: [],
      selectDimissionType: 1,
      inTypeOptions: [],
      openArchivesForm: {}
    }
@@ -1606,336 +1066,11 @@
        this.advancedQueryShow = true
      }
    },
    calculateSeniority(val) {
      this.empBaseInfoForm.seniority = calculateSeniority(val)
    },
    // 获取图片的Blob值
    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) {
        // 获取bolb里面数据时,生成预览
        var img = document.createElement('img')
        img.src = e.target.result
        this_.empBaseInfoForm.imagePath = e.target.result
      }
    },
    // 图片预览
    handlePictureCardPreview(file) {
      this.empBaseInfoImageUrl = URL.createObjectURL(file.raw) // 获取URL
      // 判断图片大小
      if (file.size < 4400000) {
        // 判断图片格式是否为jpg,png,jepg,gif
        var fileName = file.name
        // var suffixIndex=fileName.lastIndexOf(".")
        // var suffix=fileName.substring(suffixIndex+1).toUpperCase()
        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
      }
      // 验证文件大小(限制10MB)
      const isLt10M = file.size / 1024 / 1024 < 10
      if (!isLt10M) {
        this.$message.error('图片大小不能超过10MB')
        return
      }
      // 生成预览URL
      const imageUrl = URL.createObjectURL(file)
      this.empBaseInfoImageUrl = imageUrl
      // 读取文件为Base64
      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
        })
        // 将视频流绑定到 video 元素
        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
        // 设置表单数据(Base64格式)
        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
      }
    },
    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 = ''
    },
    editEmpBase(row) {
      console.log(row)
      this.isAdd = false
      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
      let certificateList = []
      if (row.certificateList && typeof row.certificateList === 'string') {
        certificateList = row.certificateList.split(',')
        row.certificateList = certificateList
      }
      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 = ''
      this.empBaseInfoImageUrl = pages.getEmpBaseInfoImage + row.empId + '?t=' + parseInt(100 * Math.random())
      this.showXzyg(1)
    },
    putEmpBase(formName) {
      // 根据新增/编辑模式使用不同的验证规则
      const validateRules = this.isAdd ? this.addRules : this.rules
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.submitEmpInfo()
          // 刷新、清空、关闭操作已移至 submitEmpInfo 的成功回调中
        }
      }, validateRules)
    },
    putEmpBaseContinue(formName) {
      // 根据新增/编辑模式使用不同的验证规则
      const validateRules = this.isAdd ? this.addRules : this.rules
      this.$refs[formName].validate((valid) => {
        if (valid) {
          // 传入 true 表示保存并继续新增,不关闭对话框
          this.submitEmpInfo(true)
        }
      }, validateRules)
      this.currentEmployeeData = { ...row }
      this.dialogShowXzyg = true
    },
    delEmp() {
      var selection = this.$refs.multipleTable.store.states.selection
@@ -1970,19 +1105,50 @@
    },
    showXzyg(val) {
      if (val === 0) {
        // this.cleanEmpBase()
        this.isAdd = true
        this.currentEmployeeData = {}
      }
      if (!this.dialogShowXzyg) {
        // this.isAdd = true
        this.dialogShowXzyg = true
      } else {
        // this.isAdd = false
        this.dialogShowXzyg = false
      }
      this.fetch({
        ...this.queryParams,
        ...this.sort
      })
    },
    handleEmpSaveSuccess() {
      this.search()
    },
    handleEmployeeExists(data) {
      this.$confirm('该员工已存在,是否修改?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.editEmpBase(data)
      })
    },
    handleNeedOpenArchives(data) {
      const tempName = this.selectDictLabel(this.dimissionTypeOptions, data.dimissionType)
      var msg = '该员工已存在,' + tempName + '状态!\n\r'
      msg += data.remark + '\n\r'
      msg += '由于' + data.empName + '已离职,是否重新打开档案?'
      this.$confirm(msg, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.openArchivesForm = {
          empId: data.empId,
          empName: data.empName,
          certificateNumb: data.certificateNumb,
          openType: 21,
          openDate: this.getDateString(),
          remark: ''
        }
        this.dialogShowDkda = true
      })
    },
    handleCheckAllChange(val) {
@@ -2018,103 +1184,25 @@
    editSuccess() {
      this.search()
    },
    showYgdg(operate, formName) {
      switch (operate) {
        case 0:
          var selection = this.$refs.multipleTable.store.states.selection
          if (selection.length === 0) {
            this.$message({
              message: '请先选中需要调岗的人员',
              type: 'error'
            })
          } else {
            var ids = []
            var names = []
            var deptNames = []
            var jobNames = []
            for (var i = 0; i < selection.length; i++) {
              var data = selection[i]
              ids.push(data.empId)
              names.push(data.empName)
              deptNames.push(data.allDeptName)
              jobNames.push(data.jobName)
            }
            this.ygdgForm = {
              empIds: ids.join(','),
              empNames: names.join(','),
              oldDeptNames: deptNames.join(','),
              oldJobNames: jobNames.join(',')
            }
            this.dialogShowYgdg = true
          }
          break
        case 1:
          this.dialogShowYgdg = false
          break
        case 2:
          this.$refs[formName].validate((valid) => {
            if (valid) {
              this.$post('hr/empBaseInfo/jobChange', { ...this.ygdgForm }).then(() => {
                this.dialogShowYgdg = false
                this.$message({
                  message: this.$t('员工调岗成功'),
                  type: 'success'
                })
                this.fetch({
                  ...this.queryParams,
                  ...this.sort
                })
              })
            }
    showYgdg(operate) {
      if (operate === 0) {
        const selection = this.$refs.multipleTable.store.states.selection
        if (selection.length === 0) {
          this.$message({
            message: '请先选中需要调岗的人员',
            type: 'error'
          })
          break
        } else {
          this.selectedEmployees = selection
          this.dialogShowYgdg = true
        }
      }
    },
    querySearch(queryString, cb) {
      var restaurants = this.restaurants
      var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
      // 调用 callback 返回建议列表的数据
      cb(results)
    handleJobChangeSuccess() {
      this.search()
    },
    createFilter(queryString) {
      return (restaurant) => {
        return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
      }
    },
    placeNameSelect(item) {
      this.empBaseInfoForm.nativePlaceName = item.value
      this.empBaseInfoForm.nativePlace = item.code
    },
    deptNameSelect(node) {
      this.ygdgForm.deptId = node.deptId
      this.ygdgForm.newDeptName = node.label
      this.ygdgForm.allDeptName = node.allDeptName
    },
    querySearchJob(queryString, cb) {
      const restaurants = this.restaurJob
      const results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
      // 调用 callback 返回建议列表的数据
      cb(results)
    },
    jobNameSelect(item) {
      this.empBaseInfoForm.jobName = item.value
      this.empBaseInfoForm.JobId = item.code
      this.ygdgForm.newJobName = item.value
      this.ygdgForm.jobId = item.code
    }, empDeptNameSelect(val) {
      this.empBaseInfoForm.deptId = val.id
      this.empBaseInfoForm.deptName = val.label
      this.empBaseInfoForm.allDeptName = val.allDeptName
    },
    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
    handleJobChangeClose() {
      this.selectedEmployees = []
    },
    showDryg(operate) {
      switch (operate) {
@@ -2129,99 +1217,25 @@
          break
      }
    },
    changeDimissionType(value) {
      this.selectDimissionType = value
    },
    validSelfLeaveDay(rule, value, callback) {
      const type = this.gbdaForm.dimissionType
      if (type === 2) {
        if (!value) {
          callback(new Error('自动离职时自离天数不能为空!'))
        } else {
          callback()
        }
      } else {
        callback()
      }
    },
    validReporter(rule, value, callback) {
      const type = this.gbdaForm.dimissionType
      if (type === 2) {
        if (!value) {
          callback(new Error('自动离职时报告人不能为空!'))
        } else {
          if (value.length > 32) {
            callback(new Error('自动离职时报告人最多32个字符!'))
          } else {
            callback()
          }
        }
      } else {
        callback()
      }
    },
    showGbda(operate, formName) {
      switch (operate) {
        case 0:
          var selection = this.$refs.multipleTable.store.states.selection
          if (selection.length === 0) {
            this.$message({
              message: '请先选中需要关闭档案的人员',
              type: 'error'
            })
          } else {
            var ids = []
            var names = []
            var dates = []
            var numbers = []
            var deptNames = []
            for (var i = 0; i < selection.length; i++) {
              var data = selection[i]
              ids.push(data.empId)
              names.push(data.empName)
              dates.push(data.entryDate)
              numbers.push(data.certificateNumb)
              deptNames.push(data.allDeptName)
            }
            const nowDate = new Date()
            const year = nowDate.getFullYear()
            const month = nowDate.getMonth() + 1
            const day = nowDate.getDate()
            this.gbdaForm = {
              empIds: ids.join(','),
              dgryNames: names.join(','),
              entryDates: dates.join(','),
              dimissionType: 1,
              dimissionDate: year + '-' + month + '-' + day,
              remark: '',
              afterOperation: ['1'],
              certificateNumb: numbers.join(','),
              deptNames: deptNames.join(',')
            }
            this.dialogShowGbda = true
          }
          break
        case 1:
          this.dialogShowGbda = false
          break
        case 2:
          this.$refs[formName].validate((valid) => {
            if (valid) {
              this.$post('hr/empBaseInfo/dimission', { ...this.gbdaForm }).then(() => {
                this.dialogShowGbda = false
                this.$message({
                  message: this.$t('员工档案关闭成功'),
                  type: 'success'
                })
                this.fetch({
                  ...this.queryParams,
                  ...this.sort
                })
              })
            }
    showGbda(operate) {
      if (operate === 0) {
        const selection = this.$refs.multipleTable.store.states.selection
        if (selection.length === 0) {
          this.$message({
            message: '请先选中需要关闭档案的人员',
            type: 'error'
          })
          break
        } else {
          this.selectedCloseEmployees = selection
          this.dialogShowGbda = true
        }
      }
    },
    handleCloseArchivesSuccess() {
      this.search()
    },
    handleCloseArchivesClose() {
      this.selectedCloseEmployees = []
    },
    doDcda() {
      this.$confirm('是否确定要导出档案,请耐心等待?', '提示', {
@@ -2346,93 +1360,6 @@
    getDateString() {
      return dateToString(new Date())
    },
    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.fetch({
            ...this.queryParams,
            ...this.sort
          })
          // 清空表单
          this.cleanEmpBase()
          // 如果不是继续新增,则关闭对话框
          if (!continueAdd) {
            this.showXzyg()
          }
          // 处理员工已存在的情况
          if (r.data != null) {
            if (r.data.data.empStatus === '0') {
              this.$confirm('该员工已存在,是否修改?', '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
              }).then(() => {
                this.editEmpBase(r.data.data)
              })
            } else {
              let tempName
              switch (r.data.data.dimissionType) {
                case '1':
                  tempName = '合同期满'
                  break
                case '2':
                  tempName = '公司劝退'
                  break
                case '3':
                  tempName = '公司辞退'
                  break
                case '4':
                  tempName = '自动离职'
                  break
                case '5':
                  tempName = '试用期内'
                  break
                case '6':
                  tempName = '正常离职'
                  break
              }
              var msg = '该员工已存在,' + tempName + '状态!\n\r'
              msg += r.data.data.remark + '\n\r'
              msg += '由于' + r.data.data.empName + '已离职,是否重新打开档案?'
              this.$confirm(msg, '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
              }).then(() => {
                this.openArchivesForm = {
                  empId: r.data.data.empId,
                  empName: r.data.data.empName,
                  certificateNumb: r.data.data.certificateNumb,
                  openType: 21,
                  openDate: this.getDateString(),
                  remark: ''
                }
                this.dialogShowDkda = true
              })
            }
          }
        })
      } else {
        this.$put('hr/empBaseInfo', { ...this.empBaseInfoForm }).then(() => {
          this.$message({
            message: this.$t('tips.updateSuccess'),
            type: 'success'
          })
          this.$emit('success')
          this.cleanEmpBase()
          this.fetch({
            ...this.queryParams,
            ...this.sort
          })
          this.showXzyg()
        })
      }
    },
    changeSort(val) {
      this.sort.field = val.prop
      this.sort.order = val.order
@@ -2492,281 +1419,8 @@
}
</script>
<style lang="scss">
.zzyg-table {
  .el-table th, .el-table td {
    padding: 7px 0;
  }
}
.fj-checkbox {
  .el-checkbox__input.is-checked .el-checkbox__inner {
    border-color: #a32c30;;
    background: #a32c30;;
  }
  .el-checkbox__label {
    color: #000 !important;
  }
}
@import '@/styles/inemployees-global.scss';
</style>
<style lang="scss" scoped>
.baseinfo .el-container {
  .el-aside {
    background-color: #fff;
  }
  .el-main {
    background-color: #fff;
  }
}
.el-main {
  height: 600px;
}
.el-autocomplete {
  width: 100%;
}
.el-select {
  width: 100%;
}
.el-aside {
  padding: 20px;
  background: #f3f5f8;
  height: 600px;
  .el-tree {
    height: 100%;
  }
}
.searchTable {
  margin-top: 10px;
  border-collapse: collapse;
  width: 100%;
  tr {
    border-bottom: 1px dashed #d9dadb;
  }
  .td {
    width: 90px;
    text-align: right;
  }
  .td-group {
    padding-left: 20px;
  }
}
.searchTable td,
.searchTable th {
  color: #000;
  height: 50px;
  background-color: #fff;
}
#ygxq table {
  border-collapse: collapse;
  margin: 0 auto;
  text-align: center;
  width: 100%;
  margin-top: 20px;
}
#ygxq table td,
#ygxq table th {
  border: 1px solid #DDDCDC;
  color: #666;
  height: 30px;
}
#ygxq table thead th {
  background-color: #CCE8EB;
  width: 100px;
}
#ygxq table tr:nth-child(odd) {
  background: #fff;
}
#ygxq table tr:nth-child(even) {
  background: #F5FAFA;
}
.tdTitle {
  font-size: 14px;
  font-weight: 700;
  text-align: left;
}
.link_button {
  color: #169BD5;
}
.del_button {
  color: #D9001B;
}
#dcygTable {
  border-collapse: collapse;
  tr {
    width: 100%;
    border-bottom: 1px dashed #ccc;
    > td:nth-child(even) {
      width: 100px;
      text-align: left;
    }
  }
}
#dcygTable td {
  width: 160px;
  text-align: center;
  height: 35px;
  line-height: 35px;
  font-size: 15px;
  font-weight: 400;
}
.search-btn {
  display: inline-block;
  width: 3.64vw;
  height: 3.2vh;
  line-height: 3.2vh;
  text-align: center;
  background-color: #a00515;
  color: #fff;
  margin-left: 1vw;
  box-sizing: border-box;
  cursor: pointer;
  vertical-align: middle;
}
.sup-search-btn {
  display: inline-block;
  width: 5.2vw;
  height: 3.2vh;
  line-height: 3.2vh;
  text-align: center;
  margin-left: 1vw;
  color: #a00515;
  border: 1px solid #a00515;
  box-sizing: border-box;
  cursor: pointer;
  vertical-align: middle;
}
// 头像包装器
.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;
  }
}
@import '@/styles/inemployees-scoped.scss';
</style>