需求:重置密码;展示员工的个人信息和岗位信息(支持图片的上传----上传到第三方平台:腾讯云)
router/modules/employees.js
{ path: 'detail/:id', // 动态路由参数 component: () => import('@/views/employees/detail'), hidden: true, meta: { title: '员工详情' } }
<template> <div class="employees-detail-container"> <div class="app-container"> <el-card> <el-tabs> <el-tab-pane label="登录账号设置"> <!-- 放置表单 --> <el-form label-width="120px" style="margin-left: 120px; margin-top:30px"> <el-form-item label="姓名:"> <el-input style="width:300px" /> </el-form-item> <el-form-item label="密码:"> <el-input style="width:300px" type="password" /> </el-form-item> <el-form-item> <el-button type="primary">更新</el-button> </el-form-item> </el-form> </el-tab-pane> <el-tab-pane label="个人详情"> <!-- 内容 --> </el-tab-pane> <el-tab-pane label="岗位信息"> <!-- 内容 --> </el-tab-pane> </el-tabs> </el-card> </div> </div> </template> <script> export default { name: 'EmployeesDetail' } </script>
<el-button type="text" size="small" @click="$router.push(`/employees/detail/${scope.row.id}`)">查看</el-button>
总结:配置路由;准备模板;控制跳转
注意:动态路由的参数传递方式:1、基于$route.parems.id ;2、基于路由映射的props进行控制
import { reqGetUserDetailById } from '@/api/user.js' export default { name: 'EmployeesDetail', data () { return { pwdInfo: { username: '', password: '' } } }, created () { this.loadUserInfo() }, methods: { // 加载用户名和密码 async loadUserInfo () { const ret = await getDetailInfo(this.id) this.pwdInfo.username = ret.data.username } } }
注意
:这里接口中读取的是后端的密文,我们并不能解密,所以我们不回显原密码!
data() { return { pwdInfo: { username: '', newPassword: '' }, rules: { username: [ { required: true, message: '姓名不能为空', trigger: ['blur', 'change'] } ], password: [ { required: true, message: '密码不可以为空', trigger: ['blur', 'change'] }, { min: 6, max: 9, message: '密码必须是6-9位', trigger: ['blur', 'change'] } ] } } },
<!-- 放置表单 --> <el-form ref="pwdForm" :model="pwdInfo" :rules="rules" label-width="120px" style="margin-left: 120px; margin-top:30px"> <el-form-item label="姓名:" prop="username"> <el-input v-model="pwdInfo.username" style="width:300px" /> </el-form-item> <el-form-item label="密码:" prop="password"> <el-input v-model="pwdInfo.password" style="width:300px" type="password" /> </el-form-item> <el-form-item> <el-button type="primary" @click="handleUpdate">更新</el-button> </el-form-item> </el-form>
总结:调用接口,获取数据,填充表单
注意:密码不需要填充表单(加密密码无法反解)
src/api/employees.js
export function reqSaveUserDetailById(data) { return request({ method: 'put', url: `/sys/user/${data.id}`, data }) }
src/views/employees/detail.vue
<el-button type="primary" @click="handleSubmit">更新</el-button>
import { reqSaveUserDetailById } from '@/api/employees' // 重置密码 handleUpdate () { this.$refs.pwdForm.validate(async valid => { if (!valid) return // 调用接口更新 const ret = await reqSaveUserDetailById({ ...this.pwdInfo, id: this.id }) this.$message.success(ret.message) }) },
总结:
- 提交表单时,需要提交输入的明文密码
- 对象的解构赋值用法
我们将员工个人信息分为三部分,账户,个人, 岗位,这个小节我们对个人组件和岗位组件进行封装
封装个人组件
src/views/employees/components/UserInfo.vue
<template> <div class="user-info"> <!-- 个人信息 --> <el-form label-width="220px"> <!-- 工号 入职时间 --> <el-row class="inline-info"> <el-col :span="12"> <el-form-item label="工号"> <el-input v-model="userInfo.workNumber" class="inputW" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="入职时间"> <el-date-picker v-model="userInfo.timeOfEntry" type="date" class="inputW" value-format="YYYY-MM-DD" /> </el-form-item> </el-col> </el-row> <!-- 姓名 部门 --> <el-row class="inline-info"> <el-col :span="12"> <el-form-item label="姓名"> <el-input v-model="userInfo.username" class="inputW" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="部门"> <el-input v-model="userInfo.departmentName" class="inputW" /> </el-form-item> </el-col> </el-row> <!--手机 聘用形式 --> <el-row class="inline-info"> <el-col :span="12"> <el-form-item label="手机"> <el-input v-model="userInfo.mobile" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="聘用形式"> <el-select v-model="userInfo.formOfEmployment" class="inputW"> <el-option v-for="item in EmployeeEnum.hireType" :key="item.id" :label="item.value" :value="item.id" /> </el-select> </el-form-item> </el-col> </el-row> <!-- 员工照片 --> <el-row class="inline-info"> <el-col :span="12"> <el-form-item label="员工头像"> <!-- 放置上传图片 --> </el-form-item> </el-col> </el-row> <!-- 保存个人信息 --> <el-row class="inline-info" type="flex" justify="center"> <el-col :span="12"> <el-button type="primary" @click="saveUser">保存更新</el-button> <el-button @click="$router.back()">返回</el-button> </el-col> </el-row> </el-form> <!-- 基础信息 --> <el-form label-width="220px"> <div class="block"> <div class="title">基础信息</div> <el-form-item label="最高学历"> <el-select v-model="formData.theHighestDegreeOfEducation" class="inputW2"> <el-option v-for="item in EmployeeEnum.highestDegree" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <!-- 个人头像 --> <!-- 员工照片 --> <el-form-item label="员工照片"> <!-- 放置上传图片 --> </el-form-item> <el-form-item label="国家/地区"> <el-select v-model="formData.nationalArea" class="inputW2"> <el-option v-for="item in EmployeeEnum.isOverseas" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="护照号"> <el-input v-model="formData.passportNo" placeholder="正规护照格式" class="inputW" /> </el-form-item> <el-form-item label="身份证号"> <el-input v-model="formData.idNumber" placeholder="正规身份证格式" class="inputW" /> </el-form-item> <el-form-item label="籍贯"> <el-input v-model="formData.nativePlace" placeholder="籍贯地址" class="inputW5" /> </el-form-item> <el-form-item label="民族"> <el-input v-model="formData.nation" placeholder="请输入民族" class="inputW2" /> </el-form-item> <el-form-item label="婚姻状况"> <el-select v-model="formData.maritalStatus" class="inputW2"> <el-option v-for="item in EmployeeEnum.maritaStatus" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="生日"> <el-input v-model="formData.birthday" placeholder="示例 0323" class="inputW" /> </el-form-item> <el-form-item label="年龄"> <el-input v-model="formData.age" type="number" class="inputW2" /> </el-form-item> <el-form-item label="星座"> <el-select v-model="formData.constellation" class="inputW2"> <el-option v-for="item in EmployeeEnum.constellation" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="血型"> <el-select v-model="formData.bloodType" class="inputW2"> <el-option v-for="item in EmployeeEnum.bloodType" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="户籍所在地"> <el-input v-model="formData.domicile" class="inputW5" /> </el-form-item> <el-form-item label="政治面貌"> <el-input v-model="formData.politicalOutlook" class="inputW2" /> </el-form-item> <el-form-item label="入党时间"> <el-date-picker v-model="formData.timeToJoinTheParty" type="date" placeholder="选择日期" class="inputW" value-format="yyyy-MM-dd" /> </el-form-item> <el-form-item label="存档机构"> <el-input v-model="formData.archivingOrganization" placeholder="请输入" /> </el-form-item> <el-form-item label="子女状态"> <el-input v-model="formData.stateOfChildren" placeholder="请输入" /> </el-form-item> <el-form-item label="子女有无商业险"> <el-radio-group v-model="formData.doChildrenHaveCommercialInsurance"> <el-radio label="1">有</el-radio> <el-radio label="2">无</el-radio> </el-radio-group> </el-form-item> <el-form-item label="有无违法违纪状态"> <el-input v-model="formData.isThereAnyViolationOfLawOrDiscipline" placeholder="请输入" /> </el-form-item> <el-form-item label="有无重大病史"> <el-input v-model="formData.areThereAnyMajorMedicalHistories" placeholder="请输入" /> </el-form-item> </div> <!-- 通讯信息 --> <div class="block"> <div class="title">通讯信息</div> <el-form-item label="QQ"> <el-input v-model="formData.qq" placeholder="请输入" class="inputW" /> </el-form-item> <el-form-item label="微信"> <el-input v-model="formData.wechat" placeholder="请输入" class="inputW" /> </el-form-item> <el-form-item label="现居住地"> <el-input v-model="formData.placeOfResidence" placeholder="请输入" /> </el-form-item> <el-form-item label="通讯地址"> <el-input v-model="formData.postalAddress" placeholder="请输入" /> </el-form-item> <el-form-item label="联系手机"> <el-input v-model="formData.contactTheMobilePhone" placeholder="11位字符" maxlength="11" class="inputW" @change.native="handlePhone(2)" /> </el-form-item> <el-form-item label="个人邮箱"> <el-input v-model="formData.personalMailbox" placeholder="请输入" type="mail" class="inputW" /> </el-form-item> <el-form-item label="紧急联系人"> <el-input v-model="formData.emergencyContact" placeholder="请输入" class="inputW" /> </el-form-item> <el-form-item label="紧急联系电话"> <el-input v-model="formData.emergencyContactNumber" placeholder="11位字符" class="inputW" /> </el-form-item> </div> <!-- 账号信息 --> <div class="block"> <div class="title">账号信息</div> <el-form-item label="社保电脑号"> <el-input v-model="formData.socialSecurityComputerNumber" placeholder="请输入" class="inputW" /> </el-form-item> <el-form-item label="公积金账号"> <el-input v-model="formData.providentFundAccount" placeholder="请输入" class="inputW" /> </el-form-item> <el-form-item label="银行卡号"> <el-input v-model="formData.bankCardNumber" placeholder="请输入" class="inputW" /> </el-form-item> <el-form-item label="开户行"> <el-input v-model="formData.openingBank" placeholder="请输入" class="inputW" /> </el-form-item> </div> <!-- 教育信息 --> <div class="block"> <div class="title">教育信息</div> <el-form-item label="学历类型"> <el-select v-model="formData.educationalType" placeholder="请选择"> <el-option v-for="item in EmployeeEnum.educationType" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="毕业学校"> <el-input v-model="formData.graduateSchool" placeholder="请输入" class="inputW2" /> </el-form-item> <el-form-item label="入学时间"> <el-date-picker v-model="formData.enrolmentTime" type="data" placeholder="请输入时间" class="inputW" value-format="yyyy-MM-dd" /> </el-form-item> <el-form-item label="毕业时间"> <el-date-picker v-model="formData.graduationTime" type="data" placeholder="请输入时间" class="inputW" value-format="yyyy-MM-dd" /> </el-form-item> <el-form-item label="专业"> <el-input v-model="formData.major" placeholder="请输入" class="inputW" /> </el-form-item> </div> <!-- 从业信息 --> <div class="block"> <div class="title">从业信息</div> <el-form-item label="上家公司"> <el-input v-model="formData.homeCompany" placeholder="请输入" class="inputW" /> </el-form-item> <el-form-item label="职称"> <el-input v-model="formData.title" placeholder="请输入" class="inputW" /> </el-form-item> <el-form-item label="有无竞业限制"> <el-input v-model="formData.isThereAnyCompetitionRestriction" placeholder="请输入" style="width:80%" /> </el-form-item> <el-form-item label="备注"> <el-input v-model="formData.remarks" type="textarea" placeholder="请输入备注" style="width:80%" /> </el-form-item> <!-- 保存员工信息 --> <el-row class="inline-info" type="flex" justify="center"> <el-col :span="12"> <el-button type="primary" @click="savePersonal">保存更新</el-button> <el-button @click="$router.back()">返回</el-button> </el-col> </el-row> </div> </el-form> </div> </template>
本章节个人数据过于**
繁杂,庞大
**,同学们在开发期间,拷贝代码即可,我们只写关键部位的代码
<script> import EmployeeEnum from '@/api/constant/employees' export default { data() { return { EmployeeEnum, // 员工枚举数据 userInfo: { workNumber: '', // 工号 timeOfEntry: '', // 入职时间 username: '', // 姓名 departmentName: '', // 部门 mobile: '', // 手机 formOfEmployment: '' // 聘用形式 }, formData: { userId: '', username: '', // 用户名 sex: '', // 性别 mobile: '', // 手机 companyId: '', // 公司id departmentName: '', // 部门名称 // onTheJobStatus: '', // 在职状态 no dateOfBirth: '', // 出生日期 timeOfEntry: '', // 入职时间 theHighestDegreeOfEducation: '', // 最高学历 nationalArea: '', // 国家 passportNo: '', // 护照号 idNumber: '', // 身份证号 idCardPhotoPositive: '', // 身份证照正 idCardPhotoBack: '', // 身份证照正 nativePlace: '', // 籍贯 nation: '', // 民族 englishName: '', // 英文名字 maritalStatus: '', // 婚姻状况 staffPhoto: '', // 员工照片 birthday: '', // 生日 zodiac: '', // 属相 age: '', // 年龄 constellation: '', // 星座 bloodType: '', // 血型 domicile: '', // 户籍所在地 politicalOutlook: '', // 政治面貌 timeToJoinTheParty: '', // 入党时间 archivingOrganization: '', // 存档机构 stateOfChildren: '', // 子女状态 doChildrenHaveCommercialInsurance: '1', // 保险状态 isThereAnyViolationOfLawOrDiscipline: '', // 违法违纪状态 areThereAnyMajorMedicalHistories: '', // 重大病史 qq: '', // QQ wechat: '', // 微信 residenceCardCity: '', // 居住证城市 dateOfResidencePermit: '', // 居住证办理日期 residencePermitDeadline: '', // 居住证截止日期 placeOfResidence: '', // 现居住地 postalAddress: '', // 通讯地址 contactTheMobilePhone: '', // 联系手机 personalMailbox: '', // 个人邮箱 emergencyContact: '', // 紧急联系人 emergencyContactNumber: '', // 紧急联系电话 socialSecurityComputerNumber: '', // 社保电脑号 providentFundAccount: '', // 公积金账号 bankCardNumber: '', // 银行卡号 openingBank: '', // 开户行 educationalType: '', // 学历类型 graduateSchool: '', // 毕业学校 enrolmentTime: '', // 入学时间 graduationTime: '', // 毕业时间 major: '', // 专业 graduationCertificate: '', // 毕业证书 certificateOfAcademicDegree: '', // 学位证书 homeCompany: '', // 上家公司 title: '', // 职称 resume: '', // 简历 isThereAnyCompetitionRestriction: '', // 有无竞业限制 proofOfDepartureOfFormerCompany: '', // 前公司离职证明 remarks: '' // 备注 } } }, computed: { userId() { return this.$route.params.id } }, methods: { saveUser() { }, savePersonal() { } } } </script>
<el-tab-pane label="个人详情"> <!-- 放置个人详情 --> <user-info /> </el-tab-pane>
import UserInfo from './components/user-info.vue' components: { UserInfo },
总结:准备模板和数据,然后导入组件并使用
封装岗位组件**
src/views/employee/components/JobInfo.vue
**
<template> <div class="job-info"> <!-- 基础信息 --> <el-form label-width="220px"> <div class="block"> <div class="title">基础信息</div> <el-form-item label="岗位"> <el-input v-model="formData.post" placeholder="请输入" class="inputW" /> </el-form-item> <!-- <el-form-item label="转正日期"> <el-date-picker v-model="formData.dateOfCorrection" type="date" placeholder="选择日期" value-format="yyyy-MM-dd" /> </el-form-item> --> <el-form-item label="转正状态"> <el-select v-model="formData.stateOfCorrection" placeholder="请选择" disabled> <el-option v-for="item in EmployeeEnum.stateOfCorrection" :key="item.value" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="职级"> <el-input v-model="formData.rank" class="inputW" /> </el-form-item> <el-form-item label="转正评价"> <el-input v-model="formData.correctionEvaluation" type="textarea" placeholder="1-300位字符" /> </el-form-item> <el-form-item label="汇报对象"> <el-select v-model="formData.reportId" filterable placeholder="请选择" class="inputW"> <el-option v-for="item in list" :key="item.id" :label="item.username" :value="item.id" /> </el-select> </el-form-item> <el-form-item label="HRBP"> <el-select v-model="formData.hrbp" filterable placeholder="请选择" class="inputW"> <el-option v-for="item in list" :key="item.id" :label="item.username" :value="item.id" class="inputW" /> </el-select> </el-form-item> <el-form-item class="formInfo" label="调整司龄(天):"> <el-input v-model="formData.adjustmentAgedays" type="number" placeholder="请输入" class="inputW" /> </el-form-item> <el-form-item label="首次参加工作时间"> <el-date-picker v-model="formData.workingTimeForTheFirstTime" type="date" placeholder="选择日期" value-format="yyyy-MM-dd" /> </el-form-item> <el-form-item label="调整工龄"> <el-input v-model="formData.adjustmentOfLengthOfService" placeholder="0.00年" class="inputW" disabled /> </el-form-item> </div> <!-- 合同信息 --> <div class="block"> <div class="title">合同信息</div> <el-form-item class="formInfo" label="首次合同开始时间:"> <el-date-picker v-model="formData.initialContractStartTime" type="date" placeholder="选择日期" value-format="yyyy-MM-dd" /> </el-form-item> <el-form-item label="首次合同结束时间"> <el-date-picker v-model="formData.firstContractTerminationTime" type="date" placeholder="选择日期" value-format="yyyy-MM-dd" /> </el-form-item> <el-form-item label="现合同开始时间"> <el-date-picker v-model="formData.currentContractStartTime" type="date" placeholder="选择日期" value-format="yyyy-MM-dd" /> </el-form-item> <el-form-item label="现合同结束时间"> <el-date-picker v-model="formData.closingTimeOfCurrentContract " type="date" placeholder="选择日期" value-format="yyyy-MM-dd" /> </el-form-item> <el-form-item label="合同期限"> <el-select v-model="formData.contractPeriod" class="filter-item"> <el-option v-for="item in EmployeeEnum.contractPeriod" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="续签次数"> <el-select v-model="formData.renewalNumber" class="filter-item"> <el-option v-for="item in EmployeeEnum.renewalCount" :key="item.id" :label="item.value" :value="item.id" /> </el-select> </el-form-item> </div> <!-- 招聘信息 --> <div class="block"> <div class="title">招聘信息</div> <el-form-item label="其他招聘渠道"> <el-select v-model="formData.otherRecruitmentChannels" placeholder="请选择"> <el-option v-for="item in EmployeeEnum.resumeSource" :key="item.id" :label="item.value" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="招聘渠道"> <el-select v-model="formData.recruitmentChannels" placeholder="请选择"> <el-option v-for="item in EmployeeEnum.resumeSource" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="社招/校招"> <el-select v-model="formData.socialRecruitment" placeholder="请选择"> <el-option v-for="item in EmployeeEnum.hireSourceType" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="推荐企业/人"> <el-input v-model="formData.recommenderBusinessPeople" placeholder="请输入" class="infoPosition inputW" /> </el-form-item> </div> <!-- 从业信息 --> <el-form-item> <el-button type="primary" @click="saveJob">保存更新</el-button> <el-button @click="$router.back()">返回</el-button> </el-form-item> </el-form> </div> </template>
<script> import EmployeeEnum from '@/api/constant/employees' export default { data() { return { list: [], EmployeeEnum, formData: { adjustmentAgedays: '', // 调整司龄天 adjustmentOfLengthOfService: '', // 调整工龄天 closingTimeOfCurrentContract: '', // 现合同结束时间 companyId: '', // 公司ID contractDocuments: '', // 合同文件 contractPeriod: '', // 合同期限 correctionEvaluation: '', // 转正评价 currentContractStartTime: '', // 现合同开始时间 firstContractTerminationTime: '', // 首次合同结束时间 hrbp: '', // HRBP initialContractStartTime: '', // 首次合同开始时间 otherRecruitmentChannels: '', // 其他招聘渠道 post: '', // 岗位 rank: null, // 职级 recommenderBusinessPeople: '', // 推荐企业人 recruitmentChannels: '', // 招聘渠道 renewalNumber: '', // 续签次数 reportId: '', // 汇报对象 reportName: null, // 汇报对象 socialRecruitment: '', // 社招校招 stateOfCorrection: '', // 转正状态 taxableCity: '', // 纳税城市 userId: '', // 员工ID workMailbox: '', // 工作邮箱 workingCity: '', // 工作城市 workingTimeForTheFirstTime: '' // 首次参加工作时间 } } }, computed: { userId() { return this.$route.params.id } }, methods: { saveJob() { } } } </script>
<el-tab-pane label="岗位详情"> <job-info /> </el-tab-pane>
import JobInfo from './components/job-info.vue' components: { JobInfo },
总结:准备模板和数据并使用组件
这个环节里面大部分都是繁杂的属性和重复的过程,所以该环节直接将过程代码拷贝到项目中即可
/** * * 读取用户详情的基础信息 (个人详情-下面的接口) * **/ export function reqGetPersonalDetail(id) { return request({ method: 'get', url: `/employees/${id}/personalInfo` }) } /** * * 更新用户详情的基础信息 (个人详情-下面的接口) * **/ export function reqUpdatePersonal(data) { return request({ method: 'put', url: `/employees/${data.userId}/personalInfo`, data }) } /** ** * 获取用户的岗位信息 (岗位信息) * ****/ export function reqGetJobDetail(id) { return request({ method: 'get', url: `/employees/${id}/jobs` }) } /** * 保存岗位信息 (岗位信息) * ****/ export function reqUpdateJob(data) { return request({ method: 'put', url: `/employees/${data.userId}/jobs`, data }) }
user-info
需要注意:这里的保存实际上分成了两个接口,这是接口的设计,我们只能遵守import { reqGetPersonalDetail, reqUpdatePersonal, reqSaveUserDetailById } from '@/api/employees' import { getDetailInfo } from '@/api/user' created() { this.getUserBaseInfo() this.getUserDetailInfo() }, methods: { // 获取员工基本信息(上面的表单) async getUserBaseInfo () { try { const ret = await getDetailInfo(this.userId) if (!ret.success) { this.$message.error(ret.message) } else { this.userInfo = ret.data } } catch { this.$message.error('获取用户基本信息失败') } }, // 获取详细信息(下面的表单) async getUserDetailInfo () { try { const ret = await reqGetPersonalDetail(this.userId) if (!ret.success) { this.$message.error(ret.message) } else { this.formData = ret.data } } catch { this.$message.error('获取用户详细信息失败') } }, async saveUser() { try { const ret = await reqSaveUserDetailById(this.userInfo) if (!ret.success) { this.$message.error(ret.message) } else { this.$message.success(ret.message) } } catch { this.$message.error('更新用户基本信息失败') } }, async savePersonal() { try { console.log(this.formData, this.userId) const ret = await reqUpdatePersonal({ ...this.formData, // 当前修改的用户的id id: this.userId }) if (!ret.success) { this.$message.error(ret.message) } else { this.$message.success(ret.message) } } catch { this.$message.error('更新用户基本信息失败') } } }
总结:
- 获取个人信息
- 保存个人信息
job-info
// 获取员工的简单列表 export function reqGetEmployeeSimple () { return request({ url: '/sys/user/simple' }) }
import { reqGetEmployeeSimple, reqGetJobDetail, reqUpdateJob } from '@/api/employees' computed: { userId() { return this.$route.params.id } }, created() { // 获取岗位信息 this.getJobInfo() // 获取下拉列表数据 this.getList() }, methods: { // 获取岗位信息 async getJobInfo () { try { const ret = await reqGetJobDetail(this.userId) if (!ret.success) { this.$message.error(ret.message) } else { this.formData = ret.data } } catch { this.$message.error('获取岗位信息失败') } }, // 获取下拉列表数据 async getList () { try { const ret = await reqGetEmployeeSimple() if (!ret.success) { this.$message.error(ret.message) } else { this.list = ret.data } } catch { this.$message.error('获取岗位信息失败') } }, // 报错岗位信息 async saveJob() { try { const ret = await reqUpdateJob({ ...this.formData, userId: this.userId }) if (!ret.success) { this.$message.error(ret.message) } else { this.$message.success('更新岗位信息成功') } } catch { this.$message.error('更新岗位信息失败') } } }
总结:
- 获取岗位信息
- 保存岗位信息
目标
: 配置一个腾讯云cos由于上课的开发的特殊性,我们不希望把所有的图片都上传到我们自己的官方服务器上,
这里我们可以采用一个腾讯云的图片方案
上边图的意思就是说,我们找一个可以免费上传图片的服务器,帮我们**
代管图片
,我们在自己的数据库里只保存一个地址就行, 这其实也是很多项目的处理方案,会有一个公共的文件服务器
**
第一步,我们必须先拥有一个腾迅云的开发者账号(有时会有腾讯云的广告电话)
请按照腾讯云的注册方式,注册自己的账号
第二步,实名认证
选择个人账户
填写个人身份信息
下一步,扫描二维码授权
手机端授权
总结:注册腾讯云账号;登录系统;进行实名认证(填充个人相关信息)
到这一步,账号的部分就操作完毕,接下来,我们需要来创建一个存储图片的存储桶
登录 对象存储控制台 ,创建存储桶。设置存储桶的权限为
公有读,私有写
总结:存储桶可以理解为存储图片的一个位置(分组)
注意:选择所属地域;添加自定义存储桶名称;访问权限选择共有读私有写
AllowHeader 需配成*
,如下图所示
注意:因为我们本身没有域名,所以这里设置成**
*
**,仅限于测试,正式环境的话,这里需要配置真实的域名地址
目标
梳理整个的上传过程
初始化 cos 对象参数
名称 | 描述 |
---|---|
SecretId | 开发者拥有的项目身份识别 ID,用以身份认证,可在 API 密钥管理 页面获取 |
SecretKey | 开发者拥有的项目身份密钥,可在 API 密钥管理 页面获取 |
注意,上述的参数我们在本次开发过程中,直接将参数放置在前端代码中存储,
但是腾讯云本身是不建议这么做的,因为**
敏感信息
**放在前端很容易被捕获,一般放在后台, 前端准备参数, 交给后台和腾讯云交互, 交互时, 需要秘钥, 秘钥在后台存着的由于我们本次是测试研发,所以这个过程可以忽略
正确的做法应该是,通过网站调用接口换取敏感信息
相关文档
实例化 上传sdk (这边还没用到, 先没配)
var cos = new COS({ SecretId: 'AKIDc3E9nAG5dtulOlsiHdljSt3wYtwkIafT', // 身份识别 ID SecretKey: 'Zrsc8QRZS4PTFkyuZx4uUnqc7PQAcokP', // 身份密钥 });
到目前为止,我们上传图片准备的内容就已经OK,接下来,我们在**
src/componets
** 新建一个**ImageUpload
** 组件
该上传组件需要满足什么要求呢?
**
目标
**实现上传组件的代码部分JavaScript SDK 需浏览器支持基本的 HTML5 特性(支持 IE10 以上浏览器),
以便支持 ajax 上传文件和计算文件 MD5 值。
npm i cos-js-sdk-v5
src/components/ImageUpload/index.vue
上传组件,我们可以沿用element的el-upload组件,并且采用照片墙的模式
list-type="picture-card"
<template> <el-upload list-type="picture-card" action=""> <i class="el-icon-plus" /> </el-upload> </template>
import PageTools from './PageTools' import UploadExcel from './UploadExcel' import ImageUpload from './ImageUpload' export default { install(Vue) { Vue.component('PageTools', PageTools) // 注册工具栏组件 Vue.component('UploadExcel', UploadExcel) // 注册导入excel组件 Vue.component('ImageUpload', ImageUpload) // 注册导入上传组件 } }
总结:新建一个通用上传文件的组件,通过插件进行全局注册,然后在用户详细信息页面使用组件即可。
<template> <div class="upload-box"> <el-upload :on-preview="preview" :file-list="fileList" list-type="picture-card" :limit="1" action="#" > <i class="el-icon-plus" /> </el-upload> </div> </template>
action为什么给#, 因为我们要上传到腾讯云,需要自定义的上传方式,action给个#防止报错
data() { return { fileList: [ { url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100' } ], showDialog: false, // 控制显示弹层 currentImg: '' } },
preview(file) { // 这里应该弹出一个层 层里是点击的图片地址 this.currentImg = file.url this.showDialog = true },
<el-dialog width="600px" top="8vh" title="图片预览" :visible.sync="showDialog"> <img width="100%" :src="currentImg" alt=""> </el-dialog>
总结:
- 显示选择的图片列表 file-list
- 预览图片 on-preview
- 弹窗的使用
需求:当选中的图片大于等于一张时隐藏加号效果
computed: { // 设定一个计算属性 判断是否已经上传完了一张 imgLen () { return this.fileList.length >= 1 } },
<el-upload list-type="picture-card" :file-list="fileList" :on-preview="preview" :limit="1" action="" :class='{hideplus: imgLen}' > <i class="el-icon-plus" /> </el-upload> <style scoped lang="scss"> .my-img-upload { width: 500px; .hideplus { ::v-deep .el-upload--picture-card { display: none; } } } </style>
小拓展: 如果希望能够定制, 图片的限制数量, 而不是永远只是一张, 这里的数字 1, 是可以通过父传子传过来的
注意:scss中的深度选择器需要使用 ::v-deep
点击删除按钮, 看似删除成功了, 但是 fileList 数据没有删除, 需要处理
<el-upload :on-preview="preview" :on-remove="handleRemove" :file-list="fileList" :limit="1" list-type="picture-card" action="#" > <i class="el-icon-plus" /> </el-upload>
// 控制删除动作 handleRemove (file, fileList) { // 参数一file表示要删除的文件信息 // 参数二fileList表示删除之后剩余的文件信息 // console.log(fileList) // file表示当前处理的文件信息 // this.fileList = this.fileList.filter(item => { // return item.uid !== file.uid // }) this.fileList = fileList },
总结:
- 监听删除的动作 on-remove(el-upload组件的选项)
- 删除事件的回调参数一表示要删除的文件信息,参数二表示删除后剩余的图片信息
默认选中图片时,会自动上传文件到action指向的地址,但是我们希望手动上传
点击 + 号, 进行上传动作, 会触发 el-upload的http-request属性配的函数
:http-request="handleUpload" // 自定义上传动作 有个参数 有个file对象 handleUpload(params) { // 进行上传操作 console.log(params.file) }
// 添加文件, 用户选了就应该新增文件预览 handleChange(file, fileList) { // console.log(fileList) // console.log(fileList.length) this.fileList = fileList },
总结
- 监听选中文件的事件 on-change
- 如果想手动上传文件,而不是默认上传给action,那么需要配置 http-request,该配置函数中可以进行手动上传操作(必须保证 auto-upload 值为 true)
this.$refs.upload.submit()
<!-- 自动上传:选中图片后,自动把图片文件传递给action指向的url地址 --> <!-- 手动上传:选中图片后,仅仅触发一个函数,该函数中需要自己写代码上传文件 -->
控制上传图片的类型和上传大小, 如果不满足条件 返回false上传就会停止
:before-upload="beforeUpload" // 配置上传前的校验, 只要通过校验, 才能进行上传 // 选择文件之前进行验证 beforeUpload (file) { // 检测文件的类型 const types = ['image/png', 'image/jpeg', 'image/gif'] if (!types.includes(file.type)) { // 不支持的格式 this.$message.error('必须上传png,jpeg,gif三种类型之一') return false } // 检测文件的大小(限制1M以内) if (file.size / 1024 / 1024 > 1) { this.$message.error('图片不可以超过1M') return false } return true },
总结:选择文件之前进行相关类型检测(文件类型和文件大小)
:http-request="handleUpload" // 自定义上传动作 有个参数 有个file对象,是我们需要上传到腾讯云服务器的内容 handleUpload(params) { console.log(params.file) }
我们需要在该方法中,调用腾讯云的上传方法
登录 访问管理控制台 ,获取您的项目 SecretId 和 SecretKey。
npm i cos-js-sdk-v5
import COS from 'cos-js-sdk-v5' // 导入腾讯云的包(sdk) const cos = new COS({ SecretId: 'AKIDc3E9nAG5dtulOlsiHdljSt3wYtwkIafT', // 身份识别 ID SecretKey: 'Zrsc8QRZS4PTFkyuZx4uUnqc7PQAcokP' // 身份密钥 }) // 进行上传操作 handleUpload(params) { // console.log(params.file) if (params.file) { // 执行上传操作 cos.putObject({ Bucket: 'jepson-75-1256203106', /* 存储桶名称 */ Region: 'ap-shanghai', /* 存储桶所在地域,必须字段 */ Key: params.file.name, /* 文件名 */ StorageClass: 'STANDARD', // 上传模式, 标准模式(默认即可) Body: params.file, // 上传文件对象 onProgress: (progressData) => { console.log(JSON.stringify(progressData)) } }, (err, data) => { console.log(err || data) }) } }
import COS from 'cos-js-sdk-v5' // 导入腾讯云的包(sdk) const cos = new COS({ SecretId: 'AKIDc3E9nAG5dtulOlsiHdljSt3wYtwkIafT', // 身份识别 ID SecretKey: 'Zrsc8QRZS4PTFkyuZx4uUnqc7PQAcokP' // 身份密钥 })
handleUpload (params) { cos.putObject({ // 存储桶名称 Bucket: 'abc-1252553968', // 存储桶所在地址 Region: 'ap-beijing', // 上传的文件名称 Key: params.file.name, // 上传模式 StorageClass: 'STANDARD', // 上传的文件对象 Body: params.file, // 监控上传的进度 onProgress: function(progressData) { console.log(JSON.stringify(progressData)) } }, function(err, data) { // 上传完成的回调 console.log(err || data) }) },
总结
- 这种上传方式仅仅用于测试,不太安全(秘钥容易泄露)
- 正规的流程应该把秘钥存储在后端服务器中
如何处理返回成功的数据, 应该在上传完图片, 得到图片地址,
问题: this.fileList 是一个数组, 我怎么知道更新谁呢 ? params.file.uid 就是唯一标识
解决: 通过 params.file.uid 决定修改 this.fileList 中的哪个对象
upload(params) { if (!params.file) return // 将文件对象, 上传到腾讯云 cos.putObject({ Bucket: 'jepsonpp-75-1256203106', // 存储桶的名字 Region: 'ap-shanghai', // 存储桶地域 Key: params.file.name, // 上传到存储桶的文件名, 如果希望不重名, 可以对文件名进行处理 StorageClass: 'STANDARD', // 上传模式, 标准模式 Body: params.file, // 上传的文件对象 // 上传的进度, 上传的过程中实时触发onProgress, 可以做进度条的展示 onProgress: progressData => { // console.log(progressData) } }, (err, data) => { // 上传完成的回调 if (err) { this.$message.error('上传图片失败') return } // data表示上传成功后后端返回的数据 // 选中图片后,this.fileList中本来已经有了选中的这张图片的信息 // 上传成功后需要把对应的图片的地址修改为腾讯云上传成功的地址,并且修改完成状态 if (data.statusCode === 200) { const imgInfo = this.fileList.find(item => { return item.uid === params.file.uid }) imgInfo.status = 'success' imgInfo.url = 'https://' + data.Location } else { this.$message.error('上传图片失败') } }) }
总结
- 腾讯云返回上传的结果后需要更新图片的地址和状态
为了再上传图片过程中显示进度条,我们可以使用element-ui的进度条显示当前的上传进度
<el-upload :before-upload="checkUpload" :on-change="onChange" :http-request="handleUpload" :on-remove="onRemove" :class="{hideplus: imgLen}" :on-preview="preview" :file-list="fileList" list-type="picture-card" action="http://baidu.com"> <i class="el-icon-plus" /> </el-upload> <el-progress v-if="isUploading" class="progress-tip" type="circle" :percentage="percent" />
// 手动实现文件上传操作 handleUpload (params) { // console.log(params.file) // 手动上传文件到腾讯云 if (params.file) { // 显示进度条 this.isUploading = true // 执行上传的动作 cos.putObject({ // 存储桶名称 Bucket: 'byte-1252553968', // 存储桶所在地域,必须字段 Region: 'ap-beijing', // 文件名称 Key: params.file.name, // 上传模式, 标准模式(默认即可) StorageClass: 'STANDARD', // 上传文件对象 Body: params.file, // 监听上传的进度 onProgress: (progressData) => { // 更新进度 this.percent = progressData.percent * 100 } }, (err, data) => { // 上传的结果:如果err有值,证明上传失败了,如果err是null表示上传成功 // data表示上传成功后,腾讯云返回的图片地址 // console.log(err || data) if (err) { this.isUploading = false return this.$message.error('上传文件失败') } // 上传成功 if (data.statusCode === 200) { // 获取腾讯云上的图片地址 const fileInfo = this.fileList.find(item => item.uid === params.file.uid) if (fileInfo) { // 图片右上角会出现对勾 fileInfo.status = 'success' // 更新图片地址 fileInfo.url = 'https://' + data.Location } } else { this.$message.error('上传图片失败') } setTimeout(() => { this.isUploading = false this.percent = 0 }, 500) }) } },
总结:
- 基于腾讯云API的回调监控上传的进度 onProgress
- 基于el-progress组件实现进度提示
props: { limit: { type: Number, default: 1 } }, computed: { // 判断是否选中了多张图片 isMultiple () { return this.fileList.length >= this.limit } },
<el-upload list-type="picture-card" :file-list="fileList" :on-preview="preview" :on-remove="handleRemove" :on-change="handleChange" :before-upload="beforeUpload" :http-request="handleUpload" :limit="limit" action="" :class="{hideplus: isMultiple}" > <i class="el-icon-plus" /> </el-upload>
<image-upload :limit="1"/>
总结:如果有相关信息需要定制,需要抽取组件的属性
<ImageUpload :default-img="userInfo.staffPhoto" :limit="1" />
export default { name: 'ImageUpload', props: { // 控制上传图片的数量 limit: { type: Number, default: 1 }, // 获取默认的图片地址 defaultImg: { type: String, default: '' } }, }, created () { this.fileList.push({ url: this.defaultImg }) },"
总结:支持默认显示已有的头像
在**
user-info.vue
**中放置上传组件
<!-- 员工照片 --> <el-row class="inline-info"> <el-col :span="12"> <el-form-item label="员工头像"> <image-upload ref="avatarRef" :default-img='userInfo.staffPhoto' :limit="1" /> </el-form-item> </el-col> </el-row>
watch: { defaultImg (url) { this.fileList = [{ url }] } },
async saveUser() { // 去读取 员工上传的头像 const fileList = this.$refs.avatrRef.fileList // 读取上传组件的数据 // 进行提交 ... },
// 判断图片是否全部上传成功了 const fileList = this.$refs.myAvatar.fileList const isSuccess = fileList.every(item => { return item.status === 'success' }) if (!isSuccess) { this.$message.error('请等待上传图片成功后再提交表单') return }
employees/components/user-info.vue
async saveUser() { try { // 判断图片是否全部上传成功了 const fileList = this.$refs.myAvatar.fileList const isSuccess = fileList.every(item => { return item.status === 'success' }) if (!isSuccess) { this.$message.error('请等待上传图片成功后再提交表单') return } const ret = await reqSaveUserDetailById({ ...this.userInfo, // 获取子组件中上传成功的图片的地址 staffPhoto: this.$refs.myAvatar.fileList[0].url }) if (!ret.success) { this.$message.error(ret.message) } else { this.$message.success(ret.message) } } catch { this.$message.error('更新用户基本信息失败') } },
总结:
- 把上传成功的头像更新到自己的服务器中
- 需要初始化原有的默认头像
注意:默认头像的处理需要使用侦听器(默认是没有头像的,调用接口获取到头像后进行更新操作)
<el-form-item label="员工照片"> <ImageUpload :default-img="urlList" :limit="3" /> </el-form-item>
// 获取详细信息(下面的表单) async getUserDetailInfo () { try { const ret = await reqGetPersonalDetail(this.userId) if (!ret.success) { this.$message.error(ret.message) } else { this.formData = ret.data // 获取照片数据进行初始化 if (this.formData.staffPhoto) { // 获取员工的照片(如果是多张图片,会把多个url地址用;隔开) if (ret.data.staffPhoto) { // 获取多张员工照片 this.urlList = ret.data.staffPhoto.split(';') } } } } catch { this.$message.error('获取用户详细信息失败') } },
computed: { // 判断是否选中了多张图片 isMultiple () { return this.fileList.length >= this.limit }, // 判断是否所有的图片都上传成功了 isAllSuccess () { return this.fileList.every(item => { return item.status === 'success' }) } },
async savePersonal () { try { // 获取最新的员工照片信息 // photos = ['http://abc.com/a.png', 'http://abc.com/b.png'] // photos = 'http://abc.com/a.png;http://abc.com/b.png' const fileList = this.$refs.myPhoto.fileList const successList = fileList.filter(item => item.status === 'success') if (successList.length === 0) { return this.$message.error('请上传所有照片') } // 上传成功 const photos = successList.map(item => item.url).join(';') const ret = await reqUpdatePersonal({ ...this.formData, // 腾讯云多张图片地址 staffPhoto: photos, // 当前修改的用户的id id: this.userId }) if (!ret.success) { this.$message.error(ret.message) } else { this.$message.success(ret.message) } } catch { this.$message.error('更新用户基本信息失败') } }
总结:上传员工的照片,支持多张照片上传
注意:默认照片数据类型是数组
目标
:在员工列表中心显示图片员工的头像可以在列表项中添加一列来进行显示, 处理下图片异常
<el-table-column label="头像" prop="staffPhoto" sortable=""> <template v-slot='scope'> <el-image class='staff' :src='scope.row.staffPhoto'> <div slot="error"> <img class="staff" :src="defaultImage"> </div> </el-image> </template> </el-table-column>
<el-table-column label="头像" prop="staffPhoto"> <template #default="scope"> <img v-imgerror="defaultImg" class="staff" :src="scope.row.staffPhoto" alt=""> </template> </el-table-column> data() { return { ... defaultImg: 'https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2146034403,1504718527&fm=26&gp=0.jpg' } }, <style lang="scss" scoped> .employees-container { .staff { width: 70px; height: 70px; border-radius: 50%; } } </style>
我们尝试用之前的指令来处理图片的异常问题,但是发现只有两三张图片能显示
这是因为有的员工的头像的地址为空(null),给img赋值空的src不能触发错误事件,针对这一特点,我们需要对指令进行升级
插入节点的钩子里面判断空, 然后在组件更新之后的钩子中同样判断空 (发送请求回来, 会赋值给img src, 需要重新错误检测)
https://cn.vuejs.org/v2/guide/custom-directive.html
export const imgerror = { // 指的是指令所在元素被插入到页面中时执行的一个钩子 // el 指令所在的元素 img标签 // binding 指令相关的参数对象, 指令名, 指令值binding.value inserted(el, binding) { // 如果src没有赋值, 给默认src el.src = el.src || binding.value // console.log('指令所在元素, 被插入到页面中了') el.onerror = function() { // console.log('图片加载失败了, 重新指定一个有效的src') el.src = binding.value } }, // 如果手动把src的值置空(删除头像),显示默认头像 componentUpdated(el, binding) { // 如果src没有赋值, 给默认src el.src = el.src || binding.value } }
总结:
- 作用域插槽定制列的模板
- 基于ElementUI提供的组件可以处理图片加载失败的情况
- 基于自定义指令方式也可以处理图片加载失败的情况
目标
基于 (图片地址 / 网页地址) 生成二维码二维码功能将来工作中也很常见, 我们需要根据信息 或者 链接地址, 生成一个二维码! 比如: 做地址分享, 做手机图片预览等
npm i qrcode
QrCode.toCanvas(dom, info)
dom为一个canvas的dom对象, info为转化二维码的信息
需求:点击头像,打开弹窗,显示二维码,扫码打开图片的链接。
<!-- 分享展示, 预览的二维码的弹层 --> <el-dialog title="二维码" :visible="showCodeDialog" @close="showCodeDialog = false"> 二维码 </el-dialog>
<el-table-column label="头像" prop="staffPhoto" sortable=""> <template v-slot='scope'> <el-image @click='showCodeDialog=true' class='staff' :src='scope.row.staffPhoto'> <div slot="error"> <img class="staff" :src="defaultImage"> </div> </el-image> </template> </el-table-column>
总结:控制二维码弹窗的显示和隐藏。
<el-dialog width="300px" title="二维码" :visible="showCodeDialog" @close="showCodeDialog = false"> <el-row type="flex" justify="center"> <canvas ref="myCanvas" /> </el-row> </el-dialog>
import QrCode from 'qrcode' clickShowCodeDialog(url) { if (!url) return this.showCodeDialog = true this.$nextTick(() => { // 如果这里 url 写的是网址, 就会跳转到对应网址 (二维码分享效果) QrCode.toCanvas(this.$refs.myCanvas, url) }) }
总结:
- 二维码的绘制方式(绘制图片到canvas画布上)
- 关于$nextTick用法的理解
目标
完成个人信息和工作信息的打印功能
将来能够打印
// 员工打印页 { path: 'print/:id', component: () => import('@/views/employees/print'), hidden: true, meta: { title: '员工打印' } }
computed: { userId () { return this.$route.params.id } }
<el-tab-pane label="个人详情"> <el-tooltip class="tooltip-box" content="打印基本个人信息"> <router-link :to="`/employees/print/${userId}?type=personal`"> <i class="el-icon-printer" /> </router-link> </el-tooltip> <user-info /> </el-tab-pane> <el-tab-pane label="岗位信息"> <el-tooltip class="tooltip-box" content="打印基本岗位信息"> <router-link :to="`/employees/print/${userId}?type=job`"> <i class="el-icon-printer" /> </router-link> </el-tooltip> <job-info /> </el-tab-pane>
<style lang="scss" scoped> .employees-detail-container { .el-tab-pane { padding-top: 10px; } .tooltip-box { position: absolute; right: 30px; top: 10px; z-index: 999; } } </style>
<template> <div id="myPrint" class="dashboard-container"> <div class="app-container"> <el-card> <el-breadcrumb separator="/" class="titInfo "> <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item> <el-breadcrumb-item> <router-link :to="{'path':'/employees'}">员工管理</router-link> </el-breadcrumb-item> <el-breadcrumb-item>打印</el-breadcrumb-item> </el-breadcrumb> <div v-if="type === 'personal'"> <h2 class="centInfo">员工信息表</h2> <table cellspacing="0" width="100%" class="tableList"> <tr class="title"> <td colspan="8" class="centInfo">基本信息</td> </tr> <tr> <th style="width:10%">姓名</th> <td colspan="6" style="width:80%">{{ formData.username }}</td> <td rowspan="5" style="width:10%"><img style="width:155px;height:218px" :src="formData.staffPhoto"></td> </tr> <tr> <th>性别</th> <td colspan="6">{{ formData.sex }}</td> </tr> <tr> <th>手机</th> <td colspan="6">{{ formData.mobile }}</td> </tr> <tr> <th>出生日期</th> <td colspan="6">{{ formData.dateOfBirth | formatDate }}</td> </tr> <tr> <th>最高学历</th> <td colspan="6">{{ formData.theHighestDegreeOfEducation }}</td> </tr> <tr> <th style="width:10%">是否可编辑</th> <td style="width:35%">{{ formData.isItEditable }}</td> <th style="width:10%">是否隐藏号码</th> <td colspan="5" style="width:45%">{{ formData.doYouHideNumbers }}</td> </tr> <tr> <th>国家地区</th> <td>{{ formData.nationalArea }}</td> <th>护照号</th> <td colspan="5">{{ formData.passportNo }}</td> </tr> <tr> <th>身份证号</th> <td>{{ formData.idNumber }}</td> <th>身份证照片</th> <td colspan="5">{{ formData.iDCardPhoto }}</td> </tr> <tr> <th>籍贯</th> <td>{{ formData.nativePlace }}</td> <th>民族</th> <td colspan="5">{{ formData.nation }}</td> </tr> <tr> <th>英文名</th> <td>{{ formData.englishName }}</td> <th>婚姻状况</th> <td colspan="5">{{ formData.maritalStatus }}</td> </tr> <tr> <th>员工照片</th> <td>{{ formData.staffPhoto }}</td> <th>生日</th> <td colspan="5">{{ formData.birthday }}</td> </tr> <tr> <th>属相</th> <td>{{ formData.zodiac }}</td> <th>年龄</th> <td colspan="5">{{ formData.age }}</td> </tr> <tr> <th>星座</th> <td>{{ formData.constellation }}</td> <th>血型</th> <td colspan="5">{{ formData.bloodType }}</td> </tr> <tr> <th>户籍所在地</th> <td>{{ formData.domicile }}</td> <th>政治面貌</th> <td colspan="5">{{ formData.politicalOutlook }}</td> </tr> <tr> <th>入党时间</th> <td>{{ formData.timeToJoinTheParty }}</td> <th>存档机构</th> <td colspan="5">{{ formData.archivingOrganization }}</td> </tr> <tr> <th>子女状态</th> <td>{{ formData.stateOfChildren }}</td> <th>子女有无商业保险</th> <td colspan="5">{{ formData.doChildrenHaveCommercialInsurance }}</td> </tr> <tr> <th>有无违法违纪行为</th> <td>{{ formData.isThereAnyViolationOfLawOrDiscipline }}</td> <th>有无重大病史</th> <td colspan="5">{{ formData.areThereAnyMajorMedicalHistories }}</td> </tr> <tr class="title"> <td colspan="8" class="centInfo">通讯信息</td> </tr> <tr> <th>QQ</th> <td>{{ formData.qQ }}</td> <th>微信</th> <td colspan="5">{{ formData.weChat }}</td> </tr> <tr> <th>居住证城市</th> <td>{{ formData.residenceCardCity }}</td> <th>居住证办理日期</th> <td colspan="5">{{ formData.dateOfResidencePermit }}</td> </tr> <tr> <th>居住证截止日期</th> <td>{{ formData.residencePermitDeadline }}</td> <th>现居住地</th> <td colspan="5">{{ formData.placeOfResidence }}</td> </tr> <tr> <th>通讯地址</th> <td>{{ formData.postalAddress }}</td> <th>联系手机</th> <td colspan="5">{{ formData.contactTheMobilePhone }}</td> </tr> <tr> <th>个人邮箱</th> <td>{{ formData.personalMailbox }}</td> <th>紧急联系人</th> <td colspan="5">{{ formData.emergencyContact }}</td> </tr> <tr> <th>紧急联系电话</th> <td colspan="7">{{ formData.emergencyContactNumber }}</td> </tr> <tr class="title"> <td colspan="8" class="centInfo">账号信息</td> </tr> <tr> <th>社保电脑号</th> <td>{{ formData.socialSecurityComputerNumber }}</td> <th>公积金账号</th> <td colspan="5">{{ formData.providentFundAccount }}</td> </tr> <tr> <th>银行卡号</th> <td>{{ formData.bankCardNumber }}</td> <th>开户行</th> <td colspan="5">{{ formData.openingBank }}</td> </tr> <tr class="title"> <td colspan="8" class="centInfo">教育信息</td> </tr> <tr> <th>学历类型</th> <td>{{ formData.educationalType }}</td> <th>毕业学校</th> <td colspan="5">{{ formData.graduateSchool }}</td> </tr> <tr> <th>入学时间</th> <td>{{ formData.enrolmentTime }}</td> <th>毕业时间</th> <td colspan="5">{{ formData.graduationTime }}</td> </tr> <tr> <th>专业</th> <td>{{ formData.major }}</td> <th>毕业证书</th> <td colspan="5">{{ formData.graduationCertificate }}</td> </tr> <tr> <th>学位证书</th> <td colspan="7">{{ formData.certificateOfAcademicDegree }}</td> </tr> <tr class="title"> <td colspan="8" class="centInfo">从业信息</td> </tr> <tr> <th>上家公司</th> <td>{{ formData.homeCompany }}</td> <th>职称</th> <td colspan="5">{{ formData.title }}</td> </tr> <tr> <th>简历</th> <td>{{ formData.resume }}</td> <th>有无竞业限制</th> <td colspan="5">{{ formData.isThereAnyCompetitionRestriction }}</td> </tr> <tr> <th>前公司离职证明</th> <td>{{ formData.proofOfDepartureOfFormerCompany }}</td> <th>备注</th> <td colspan="5">{{ formData.remarks }}</td> </tr> </table> <div class="foot">签字:___________日期:___________</div> </div> <div v-else> <h2 class="centInfo">岗位信息表</h2> <table cellspacing="0" width="100%" class="tableList"> <tr class="title"> <td colspan="4" class="centInfo">基本信息</td> </tr> <tr> <th style="width:10%">姓名</th> <td style="width:40%">{{ formData.username }}</td> <th style="width:10%">入职日期</th> <td style="width:40%">{{ formData.dateOfEntry }}</td> </tr> <tr> <th>部门</th> <td>{{ formData.departmentName }}</td> <th>岗位</th> <td>{{ formData.post }}</td> </tr> <tr> <th>工作邮箱</th> <td>{{ formData.workMailbox }}</td> <th>工号</th> <td>{{ formData.workNumber }}</td> </tr> <tr> <th>转正日期</th> <td>{{ formData.dateOfCorrection }}</td> <th>转正状态</th> <td>{{ formData.stateOfCorrection }}</td> </tr> <tr> <th>职级</th> <td>{{ formData.rank }}</td> <th>汇报对象</th> <td>{{ formData.reportName }}</td> </tr> <tr> <th>HRBP</th> <td>{{ formData.hRBP }}</td> <th>聘用形式</th> <td>{{ formData.formOfEmployment }}</td> </tr> <tr> <th>管理形式</th> <td>{{ formData.formOfManagement }}</td> <th>调整司龄</th> <td>{{ formData.adjustmentAgedays }}</td> </tr> <tr> <th>司龄</th> <td>{{ formData.ageOfDivision }}</td> <th>首次参加工作时间</th> <td>{{ formData.workingTimeForTheFirstTime }}</td> </tr> <tr> <th>调整工龄天</th> <td>{{ formData.adjustmentOfLengthOfService }}</td> <th>工龄</th> <td>{{ formData.workingYears }}</td> </tr> <tr> <th>纳税城市</th> <td>{{ formData.taxableCity }}</td> <th>转正评价</th> <td>{{ formData.correctionEvaluation }}</td> </tr> <tr class="title"> <td colspan="4" class="centInfo">合同信息</td> </tr> <tr> <th>首次合同开始时间</th> <td>{{ formData.initialContractStartTime }}</td> <th>首次合同结束时间</th> <td>{{ formData.firstContractTerminationTime }}</td> </tr> <tr> <th>现合同开始时间</th> <td>{{ formData.currentContractStartTime }}</td> <th>现合同结束时间</th> <td>{{ formData.closingTimeOfCurrentContract }}</td> </tr> <tr> <th>合同期限</th> <td>{{ formData.contractPeriod }}</td> <th>合同文件</th> <td>{{ formData.contractDocuments }}</td> </tr> <tr> <th>续签次数</th> <td colspan="3">{{ formData.renewalNumber }}</td> </tr> <tr class="title"> <td colspan="4" class="centInfo">招聘信息</td> </tr> <tr> <th>其他招聘渠道</th> <td>{{ formData.otherRecruitmentChannels }}</td> <th>招聘渠道</th> <td>{{ formData.recruitmentChannels }}</td> </tr> <tr> <th>社招校招</th> <td>{{ formData.socialRecruitment }}</td> <th>推荐企业人</th> <td>{{ formData.recommenderBusinessPeople }}</td> </tr> </table> <div class="foot">签字:___________日期:___________</div> </div> </el-card> </div> </div> </template> <script> import { reqGetPersonalDetail, reqGetJobDetail } from '@/api/employees' import { getDetailInfo as reqGetUserDetailById } from '@/api/user' export default { data() { return { formData: {} } }, computed: { userId() { return this.$route.params.id }, type() { return this.$route.query.type } }, // 创建完毕状态 created() { if (this.type === 'personal') { this.getPersonalDetail() } else { this.getJobDetail() } }, // 组件更新 methods: { async getPersonalDetail() { const { data: userInfo } = await reqGetUserDetailById(this.userId) // 获取个人基本信息(顶部) const { data: detail } = await reqGetPersonalDetail(this.userId) // 获取个人基本信息(底部) this.formData = { ...detail, ...userInfo } }, async getJobDetail() { const { data: userInfo } = await reqGetUserDetailById(this.userId) const { data: jobInfo } = await reqGetJobDetail(this.userId) // 获取个人基本信息 this.formData = { ...jobInfo, ...userInfo } } } } </script> <style lang="scss"> .foot { padding: 30px 0; text-align: right; } </style>
总结:
- 该页面内容实际上就是读取个人和详情的接口数据,根据传入的type类型决定显示个人还是岗位
- type为**
personal
时显示个人,为job
**时显示岗位注意:路由的参数传递方式
- Restful风格 this.$route.params.id
- 查询字符串风格 this.$route.query.type
$ npm i vue-print-nb
它的用法是
import Print from 'vue-print-nb' Vue.use(Print)
<div id="printbox">
<div style="text-align: right; margin-top: 10px;"> <el-button v-print="{ id: 'printbox' }" type="primary" size="small">打印</el-button> </div>
总结:基于第三方包实现打印功能
注意:第三方包扩展了一个指令 v-print