Newer
Older
xc-business-system / src / views / resource / person / register / component / basic.vue
<!-- 人员登记 基本信息 -->
<script name="RegisterBasic" lang="ts" setup>
import type { UploadProps } from 'element-plus'
import { ElLoading, ElMessage, ElMessageBox, dayjs } from 'element-plus'
import type { IStaffBasicInfo } from '../person-regitster'
import FilterSysUser from '@/views/resource/common/filterSysUser.vue'
import type { IDictType } from '@/commonInterface/resource-interface'
import nationList from '@/assets/json/nation-code.json'
import FilePreviewDialog from '@/components/filePreview/filePreviewDialog.vue'
import ImagePreviewDialog from '@/components/ImagePreview/imagePreviewDialog.vue'
import { UploadFile } from '@/api/file'
import { getPhotoUrl } from '@/api/system/tool'
import { addStaffBasic, getStaffBasic, updateStaffBasic } from '@/api/resource/register'
import { getDictByCode } from '@/api/system/dict'

const props = defineProps({
  operation: { type: String, default: '' },
})

const emit = defineEmits(['afterAddBasic', 'returnToList'])

const staffBasicInfo = ref<IStaffBasicInfo>({
  id: '',
  account: '', // 账号
  pictureFile: '', // 照片文件
  staffNo: '', // 人员编号
  staffName: '', // 姓名
  idCard: '', // 身份证号
  birthday: '', // 生日
  nativePlace: '', // 籍贯
  education: '', // 学历
  educationName: '',
  educationFile: '', // 教育科研文件
  recordDate: '', // 建档日期
  officerNo: '', // 军官/文职证号
  gender: '', // 性别
  genderName: '',
  graduationDate: '', // 毕业时间
  nation: '', // 民族
  degree: '', // 学位
  degreeName: '',
  deptId: '', // 工作部门
  deptName: '',
  station: '', // 岗位
  major: '', // 从事专业
  certificateNumber: '', // 证号
  engageDate: '', // 从事专业时间
  partyDate: '', // 党团时间
  enlistmentDate: '', // 入伍时间
  staffType: '', // 人员类别
  staffTypeName: '',
  workingExperience: '', // 工作简历
  rankExperience: '', // 军衔/时间
  titleExperience: '', // 职称职务/时间
  treatmentExperience: '', // 待遇级别/时间
  rewardsPunishments: '', // 奖惩情况
  remark: '', // 备注
})

const basicFormRef = ref()
const refFilterDialog = ref()
const refFilePreviewDlg = ref()
const refImagePreviewDlg = ref()

const educationDict = ref<IDictType[]>([])
const genderDict = ref<IDictType[]>([])
const degreeDict = ref<IDictType[]>([])
const staffTypeDict = ref<IDictType[]>([])

// 身份证号码验证规则
const validateIDcard = (rule: any, value: any, callback: any) => {
  const rr = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[X])$)$/
  if (rr.test(value)) {
    // 校验成功后自动填充出生日期和性别字段
    // 获取生日
    const idCardStr = staffBasicInfo.value.idCard
    staffBasicInfo.value.birthday = `${idCardStr.substring(6, 10)}-${idCardStr.substring(10, 12)}-${idCardStr.substring(12, 14)}`

    // 获取性别 第17位  奇数为男 偶数为女
    if (Number(idCardStr.substring(16, 17)) % 2) {
      const tarList = genderDict.value.filter(item => item.name === '男')
      if (tarList.length > 0) {
        staffBasicInfo.value.gender = tarList[0].value
        staffBasicInfo.value.genderName = tarList[0].name
      }
    }
    else {
      const tarList = genderDict.value.filter(item => item.name === '女')
      if (tarList.length > 0) {
        staffBasicInfo.value.gender = tarList[0].value
        staffBasicInfo.value.genderName = tarList[0].name
      }
    }

    callback()
  }
  else {
    // 校验失败将出生日期和性别字段清除
    staffBasicInfo.value.birthday = ''
    staffBasicInfo.value.gender = ''

    callback(new Error('验证失败'))
  }
}

const staffBasicRules = ref({
  staffName: [{ required: true, message: '姓名不能为空', trigger: ['change', 'blur'] }],
  gender: [{ required: true, message: '性别不能为空', trigger: ['change', 'blur'] }],
  staffType: [{ required: true, message: '人员类别不能为空', trigger: ['change', 'blur'] }],
  deptName: [{ required: true, message: '工作部门不能为空', trigger: ['change', 'blur'] }],
  birthday: [{ required: true, message: '出生时间不能为空', trigger: ['change', 'blur'] }],
  nativePlace: [{ required: true, message: '籍贯不能为空', trigger: 'blur' }],
  nation: [{ required: true, message: '民族不能为空', trigger: ['change', 'blur'] }],
  graduationDate: [{ required: true, message: '毕业时间不能为空,请选择', trigger: 'blur' }],
  enlistmentDate: [{ required: true, message: '入伍时间不能为空,请选择', trigger: 'blur' }],
  partyDate: [{ required: true, message: '党团时间不能为空,请选择', trigger: 'blur' }],
  education: [{ required: true, message: '学历不能为空,请选择', trigger: ['change', 'blur'] }],
  degree: [{ required: true, message: '学位不能为空,请选择', trigger: ['change', 'blur'] }],
  idCard: [{ required: true, message: '身份证号码为空或不符合规范', trigger: 'blur', validator: validateIDcard }],
  officerNo: [{ required: true, message: '军官/文职证号不能为空', trigger: 'blur' }],
  recordDate: [{ required: true, message: '建档时间不能为空,请选择', trigger: 'blur' }],
  station: [{ required: true, message: '岗位不能为空', trigger: 'blur' }],
  major: [{ required: true, message: '从事专业不能为空', trigger: 'blur' }],
  engageDate: [{ required: true, message: '从事专业时间不能为空,请选择', trigger: 'blur' }],

}) // 表单验证规则

// 逻辑

// 上传请求
const uploadAvatarFile: any = (file: any) => {
  const fd = new FormData()
  fd.append('multipartFile', file.file)
  const loading = ElLoading.service({
    lock: true,
    background: 'rgba(255, 255, 255, 0.8)',
  })
  UploadFile(fd).then((res) => {
    if (res.code === 200) {
      ElMessage.success('上传成功')
      staffBasicInfo.value.pictureFile = res.data[0]
      loading.close()
    }
  }).catch(() => {
    loading.close()
    ElMessage.error('上传失败')
  })
}

// 上传之前的验证
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
  if (rawFile.type !== 'image/jpeg' && rawFile.type !== 'image/png' && rawFile.type !== 'image/jpg') {
    ElMessage.error('只能上传png/jpeg/jpg格式的图片')
    return false
  }
  else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error('图片不能大于2MB')
    return false
  }
  return true
}

// 上传教育档案文件附件请求
const uploadEducationFile: any = (file: any) => {
  const fd = new FormData()
  fd.append('multipartFile', file.file)
  const loading = ElLoading.service({
    lock: true,
    background: 'rgba(255, 255, 255, 0.8)',
  })
  UploadFile(fd).then((res) => {
    if (res.code === 200) {
      ElMessage.success('教育档案附件上传成功')
      staffBasicInfo.value.educationFile = res.data[0]
      loading.close()
    }
  }).catch(() => {
    loading.close()
    ElMessage.error('教育档案附件上传失败')
  })
}

// 从用户账号中筛选进行人员登记
const showFilterSysUser = () => {
  refFilterDialog.value.showOrHideFilterDialog(true)
}

const recordSelectedHandler = (row: any) => {
  refFilterDialog.value.showOrHideFilterDialog(false)

  staffBasicInfo.value.staffName = row.name
  staffBasicInfo.value.account = row.account
  staffBasicInfo.value.deptId = row.deptId
  staffBasicInfo.value.deptName = row.deptName
  staffBasicInfo.value.major = row.deptName // 默认与工作部门一致,可编辑
  staffBasicInfo.value.staffType = row.avatar // 使用avata字段代替人员类型
}

const openFilePreviewDialog = (filename: string) => {
  if (filename.lastIndexOf('.pdf') > 0) {
    refFilePreviewDlg.value.initDialog(filename)
  }
  else {
    refImagePreviewDlg.value.initDialog(filename)
  }
}

const reloadStaffBasic = (staffId: string) => {
  getStaffBasic({
    id: staffId,
  }).then((res) => {
    if (res.code === 200) {
      staffBasicInfo.value = res.data
    }
  })
}

// 查询人员基本信息
const getStaffBasicById = (staffId: string) => {
  if (sessionStorage.getItem('staffBasicInfo') === null || sessionStorage.getItem('staffBasicInfo') === undefined) {
    getStaffBasic({
      id: staffId,
    }).then((res) => {
      if (res.code === 200) {
        staffBasicInfo.value = res.data
      }
    })
  }
  else {
    staffBasicInfo.value = JSON.parse(sessionStorage.getItem('staffBasicInfo')!)
  }
}

// 新增
const addStaffBase = () => {
  addStaffBasic(staffBasicInfo.value).then((res) => {
    if (res.code === 200) {
      // 提示保存成功
      ElMessage.success('保存成功')
      // 设置返回的人员id
      emit('afterAddBasic', res.data.id)
      // 提示是否继续添加其他信息
      ElMessageBox.confirm(
        '是否继续添加其他信息',
        '提示',
        {
          confirmButtonText: '确认',
          cancelButtonText: '取消',
          type: 'warning',
        },
      ).then(() => {
        // 确认操作 停留在当前页 继续添加教育等其他信息
      }).catch(() => {
        // 取消操作 返回到列表页
        emit('returnToList')
      })
    }
    else {
      // 提示失败信息
      ElMessage.error(`保存失败:${res.message}`)
    }
  })
}
// 编辑
const updateStaffBase = () => {
  updateStaffBasic(staffBasicInfo.value).then((res) => {
    if (res.code === 200) {
      // 提示保存成功
      ElMessage.success('保存成功')
    }
    else {
      // 提示失败信息
      ElMessage.error(`保存失败:${res.message}`)
    }
  })
}

// 保存基本信息
const saveBasicForm = async () => {
  if (!basicFormRef) { return }

  await basicFormRef.value.validate((valid: boolean, fields: any) => {
    if (valid === true) {
      ElMessageBox.confirm(
        '确认保存吗?',
        '提示',
        {
          confirmButtonText: '确认',
          cancelButtonText: '取消',
          type: 'warning',
        },
      ).then(() => {
        if (props.operation === 'create') {
          addStaffBase()
        }
        else if (props.operation === 'update') {
          updateStaffBase()
        }
      })
    }
  })
}

const searchDate = reactive({
  disableTodayAfter: (date: string) => {
    const today = dayjs()
    const target = dayjs(date)
    return target.diff(today, 'day') >= 0
  },
})

const autoSetEngageDate = () => {
  if (staffBasicInfo.value.recordDate !== '' && staffBasicInfo.value.engageDate === '') {
    staffBasicInfo.value.engageDate = staffBasicInfo.value.recordDate
  }
}

// 查询学历字典值
const getEducationDict = async () => {
  await getDictByCode('bizEducation').then((res) => {
    if (res.code === 200) {
      educationDict.value = res.data
      sessionStorage.setItem('educationDict', JSON.stringify(educationDict.value))
    }
  })
}

// 查询性别字典值
const getGenderDict = async () => {
  await getDictByCode('sex').then((res) => {
    if (res.code === 200) {
      genderDict.value = res.data
    }
  })
}

// 查询学位字典值
const getDegreeDict = async () => {
  await getDictByCode('bizDegree').then((res) => {
    if (res.code === 200) {
      degreeDict.value = res.data
    }
  })
}

// 查询人员类别字典值
const getStaffTypeDict = async () => {
  await getDictByCode('bizStaffType').then((res) => {
    if (res.code === 200) {
      staffTypeDict.value = res.data
    }
  })
}

// 查询训练场地字典值
const getTrainSiteDict = async () => {
  await getDictByCode('bizTrainSite').then((res) => {
    if (res.code === 200) {
      sessionStorage.setItem('bizTrainSite', JSON.stringify(res.data))
    }
  })
}

// 查询训练方式字典值
const getTrainWayDict = async () => {
  await getDictByCode('bizTrainWay').then((res) => {
    if (res.code === 200) {
      sessionStorage.setItem('bizTrainWay', JSON.stringify(res.data))
    }
  })
}

const getCertTypeDict = async () => {
  await getDictByCode('bizCertType').then((res) => {
    if (res.code === 200) {
      sessionStorage.setItem('bizCertType', JSON.stringify(res.data))
    }
  })
}

// 图片预览地址
const photoUrl = ref('')
watch(() => staffBasicInfo.value.pictureFile, (newVal) => {
  if (newVal !== undefined) {
    getPhotoUrl(newVal).then((res) => {
      if (res.code === 200) {
        photoUrl.value = res.data
      }
    })
  }
})

// 教育档案预览地址
const educationFileUrl = ref('')
watch(() => staffBasicInfo.value.educationFile, (newVal) => {
  if (newVal !== undefined) {
    getPhotoUrl(newVal).then((res) => {
      if (res.code === 200) {
        educationFileUrl.value = res.data
      }
    })
  }
})

// 监听性别 显示中文 立即监听
watch(() => staffBasicInfo.value.gender, (newVal) => {
  getGenderDict()
  getCertTypeDict()
  getEducationDict()
  getTrainSiteDict()
  getTrainWayDict()
  getDegreeDict()
  getStaffTypeDict()
}, { immediate: true })

defineExpose({
  saveBasicForm,
  getStaffBasicById,
  reloadStaffBasic,
})
</script>

<template>
  <app-container>
    <el-form ref="basicFormRef" :model="staffBasicInfo" :rules="staffBasicRules" label-position="right" label-width="120px" border stripe>
      <!-- 第一行 -->
      <el-row :gutter="24">
        <!-- 第一行 第一列 -->
        <el-col :span="8">
          <el-form-item label="姓名" prop="staffName">
            <el-input v-model="staffBasicInfo.staffName" placeholder="请输入姓名,必填项" :disabled="true">
              <template #append>
                <el-button size="small" :disabled="props.operation !== 'create'" @click="showFilterSysUser">
                  选择
                </el-button>
              </template>
            </el-input>
            <el-input v-model="staffBasicInfo.account" type="hidden" />
          </el-form-item>

          <el-form-item label="性别" prop="gender">
            <el-input v-model="staffBasicInfo.gender" type="hidden" />
            <el-input v-model="staffBasicInfo.genderName" placeholder="自动从身份证号获取" :disabled="true" />
          </el-form-item>

          <el-form-item label="籍贯" prop="nativePlace">
            <el-input v-model="staffBasicInfo.nativePlace" :disabled="props.operation === 'detail'" placeholder="请输入籍贯" />
          </el-form-item>

          <el-form-item label="人员类别" prop="staffType">
            <el-select v-model="staffBasicInfo.staffType" placeholder="请选择人员类别" disabled style="width: 100%;">
              <el-option v-for="item in staffTypeDict" :key="item.id" :label="item.name" :value="item.value" />
            </el-select>
          </el-form-item>

          <el-form-item label="入伍时间" prop="enlistmentDate">
            <el-date-picker
              v-model="staffBasicInfo.enlistmentDate" type="month"
              format="YYYY-MM" value-format="YYYY-MM-DD"
              :disabled-date="searchDate.disableTodayAfter"
              placeholder="请选择入伍时间" :disabled="props.operation === 'detail'" style="width: 100%;"
            />
          </el-form-item>

          <el-form-item label="学历" prop="education">
            <el-select v-model="staffBasicInfo.education" placeholder="请选择学历" :disabled="props.operation === 'detail'" style="width: 100%;">
              <el-option v-for="item in educationDict" :key="item.id" :label="item.name" :value="item.value" />
            </el-select>
          </el-form-item>

          <el-form-item label="毕业时间" prop="graduationDate">
            <el-date-picker
              v-model="staffBasicInfo.graduationDate" type="month"
              format="YYYY-MM" value-format="YYYY-MM-DD"
              :disabled-date="searchDate.disableTodayAfter"
              placeholder="请选择毕业时间" :disabled="props.operation === 'detail'" style="width: 100%;"
            />
          </el-form-item>

          <el-form-item label="工作部门" prop="deptName">
            <el-input v-model="staffBasicInfo.deptName" placeholder="自动从人员信息获取" :disabled="true" style="width: 100%;" />
            <el-input v-model="staffBasicInfo.deptId" type="hidden" />
          </el-form-item>

          <el-form-item label="从事专业" prop="major">
            <el-input v-model="staffBasicInfo.major" :disabled="props.operation === 'detail'" placeholder="请输入从事计量专业" />
          </el-form-item>
        </el-col>

        <!-- 第一行 第二列 -->
        <el-col :span="8">
          <el-form-item label="身份证号" prop="idCard">
            <el-input ref="idCard" v-model="staffBasicInfo.idCard" placeholder="请输入身份证号,必填项" :disabled="props.operation === 'detail'" :clearable="true" />
          </el-form-item>

          <el-form-item label="出生时间" prop="birthday">
            <el-input v-model="staffBasicInfo.birthday" placeholder="自动从身份证号获取" :disabled="true" />
          </el-form-item>

          <el-form-item label="民族" prop="nation">
            <el-select v-model="staffBasicInfo.nation" placeholder="请选择民族" style="width: 100%;" :disabled="props.operation === 'detail'" :filterable="true" :clearable="true">
              <el-option v-for="item in nationList" :key="item.id" :label="item.text" :value="item.text" />
            </el-select>
          </el-form-item>

          <el-form-item label="军官/文职证号" prop="officerNo">
            <el-input v-model="staffBasicInfo.officerNo" placeholder="请输入证件号(军官证/文职证)" :disabled="props.operation === 'detail'" />
          </el-form-item>

          <el-form-item label="党团时间" prop="partyDate">
            <el-date-picker
              v-model="staffBasicInfo.partyDate" type="month"
              format="YYYY-MM" value-format="YYYY-MM-DD"
              :disabled-date="searchDate.disableTodayAfter"
              placeholder="请选择党团时间" :disabled="props.operation === 'detail'" style="width: 100%;"
            />
          </el-form-item>

          <el-form-item label="学位" prop="degree">
            <el-select v-model="staffBasicInfo.degree" placeholder="请选择学位" :disabled="props.operation === 'detail'" style="width: 100%;" :clearable="true">
              <el-option v-for="item in degreeDict" :key="item.id" :label="item.name" :value="item.value" />
            </el-select>
          </el-form-item>

          <el-form-item label="建档时间" prop="recordDate">
            <el-date-picker
              v-model="staffBasicInfo.recordDate" type="date"
              format="YYYY-MM-DD" value-format="YYYY-MM-DD"
              :disabled-date="searchDate.disableTodayAfter"
              placeholder="请选择建档时间" :disabled="props.operation === 'detail'" style="width: 100%;"
              @change="autoSetEngageDate"
            />
          </el-form-item>

          <el-form-item label="岗位" prop="station">
            <el-input v-model="staffBasicInfo.station" :disabled="props.operation === 'detail'" placeholder="请输入岗位" />
          </el-form-item>

          <el-form-item label="从事专业时间" prop="engageDate">
            <el-date-picker
              v-model="staffBasicInfo.engageDate" type="date"
              format="YYYY-MM-DD" value-format="YYYY-MM-DD"
              :disabled-date="searchDate.disableTodayAfter"
              placeholder="请选择从事专业时间" :disabled="props.operation === 'detail'" style="width: 100%;"
            />
          </el-form-item>
        </el-col>

        <!-- 第一行 第三列 -->
        <el-col :span="8">
          <el-form-item>
            <el-upload
              class="avatar-uploader"
              :show-file-list="false"
              :http-request="uploadAvatarFile"
              :before-upload="beforeAvatarUpload"
              accept="image/png, image/jpeg,image/jpg"
              :disabled="props.operation === 'detail'"
            >
              <img v-if="staffBasicInfo.pictureFile" :src="photoUrl" class="avatar">
              <el-icon v-else class="avatar-uploader-icon">
                <plus />
              </el-icon>
            </el-upload>
          </el-form-item>
        </el-col>
      </el-row>

      <!-- 第二行 -->
      <el-row :gutter="24">
        <el-col :span="8">
          <el-form-item label="军衔/时间">
            <el-input v-model="staffBasicInfo.rankExperience" placeholder="请输入军衔及获得时间" type="textarea" :rows="3" :disabled="props.operation === 'detail'" />
          </el-form-item>
        </el-col>

        <el-col :span="8">
          <el-form-item label="待遇级别/时间">
            <el-input v-model="staffBasicInfo.treatmentExperience" placeholder="请输入待遇级别及获得时间" type="textarea" :rows="3" :disabled="props.operation === 'detail'" />
          </el-form-item>
        </el-col>

        <el-col :span="8">
          <el-form-item label="职称职务/时间">
            <el-input v-model="staffBasicInfo.titleExperience" placeholder="请输入职称职务及获得时间" type="textarea" :rows="3" :disabled="props.operation === 'detail'" />
          </el-form-item>
        </el-col>
      </el-row>
      <!-- 教育档案附件 -->
      <!-- <el-row :gutter="24">
        <el-col :span="20">
          <el-form-item label="教育档案附件" prop="file">
            <el-input v-model="staffBasicInfo.educationFile" type="hidden" />
            <el-link @click="openFilePreviewDialog(staffBasicInfo.educationFile!)">
              {{ staffBasicInfo.educationFile }}
            </el-link>

            <el-upload
              :show-file-list="false"
              :http-request="uploadEducationFile"
              style="width: 50%; margin-left: 20px;"
            >
              <el-button v-if="props.operation !== 'detail'" type="primary">
                <template v-if="staffBasicInfo.educationFile !== ''">
                  替换
                </template>
                <template v-else>
                  上传
                </template>
              </el-button>
            </el-upload>
          </el-form-item>
        </el-col>
      </el-row> -->

      <!-- 第三行 -->
      <el-row :gutter="24">
        <el-col :span="24">
          <el-form-item label="工作简历">
            <el-input v-model="staffBasicInfo.workingExperience" placeholder="请输入工作简历" type="textarea" :rows="3" :disabled="props.operation === 'detail'" />
          </el-form-item>
        </el-col>
      </el-row>

      <!-- 第四行 -->
      <el-row :gutter="24">
        <el-col :span="24">
          <el-form-item label="奖惩情况">
            <el-input v-model="staffBasicInfo.rewardsPunishments" placeholder="请输入奖惩情况" type="textarea" :rows="3" :disabled="props.operation === 'detail'" />
          </el-form-item>
        </el-col>
      </el-row>

      <!-- 第五行 -->
      <el-row :gutter="24">
        <el-col :span="24">
          <el-form-item label="备注">
            <el-input v-model="staffBasicInfo.remark" placeholder="请输入备注信息" type="textarea" :rows="1" :disabled="props.operation === 'detail'" />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>

    <filter-sys-user ref="refFilterDialog" @record-selected="recordSelectedHandler" />
    <file-preview-dialog ref="refFilePreviewDlg" />
    <image-preview-dialog ref="refImagePreviewDlg" />
  </app-container>
</template>

<style scoped>
.avatar-uploader .avatar {
  width: 300px;
  height: 400px;
  display: block;
}
</style>

<style>
.avatar-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 300px;
  height: 400px;
  text-align: center;
}
</style>