员工详情
员工详情页
需求:重置密码;展示员工的个人信息和岗位信息(支持图片的上传----上传到第三方平台:腾讯云)
详情页的基本布局和路由
- 建立详情页路由
router/modules/employees.js
- 配置二级路由,并且控制左侧菜单不显示
- 动态路由参数的获取方式:
- 1、$route.params.id;
- 2、利用路由映射的props:true 配置,组件中通过props获取即可
{
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>
总结:配置路由;准备模板;控制跳转
获取用户信息
- 发送请求获取数据
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
}
}
}
**注意**
:这里接口中读取的是后端的密文,我们并不能解密,所以我们不回显原密码! 我们设定了一个临时的字段 newPassword,用它来存储我们的修改值,最后保存的时候,把newPassword 进行提交
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/user-info.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>
本章节个人数据过于
**繁杂,庞大**
,同学们在开发期间,拷贝代码即可,我们只写关键部位的代码
- 定义user-info的数据
<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>
- 在detail.vue组件中,注册并使用
<el-tab-pane label="个人详情">
<!-- 放置个人详情 -->
<user-info />
</el-tab-pane>
import UserInfo from './components/user-info.vue'
components: {
UserInfo
},
总结:准备模板和数据,然后导入组件并使用
封装岗位组件
封装岗位组件
**src/views/employee/components/job-info.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>
- 在detail.vue组件中,注册并使用
<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 { reqGetUserDetailById } from '@/api/user'
created() {
this.getUserBaseInfo()
this.getUserDetailInfo()
},
methods: {
// 获取员工基本信息(上面的表单)
async getUserBaseInfo () {
try {
const ret = await reqGetUserDetailById(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
账号注册 (实名认证)
**目标**
: 配置一个腾讯云cos 由于上课的开发的特殊性,我们不希望把所有的图片都上传到我们自己的官方服务器上, 这里我们可以采用一个腾讯云的图片方案
上边图的意思就是说,我们找一个可以免费上传图片的服务器,帮我们
**代管图片**
,我们在自己的数据库里只保存一个地址就行, 这其实也是很多项目的处理方案,会有一个**公共的文件服务器**
第一步,我们必须先拥有一个腾迅云的开发者账号(有时会有腾讯云的广告电话)
请按照腾讯云的注册方式,注册自己的账号
第二步,实名认证
选择个人账户
填写个人身份信息
下一步,扫描二维码授权
手机端授权
总结:注册腾讯云账号;登录系统;进行实名认证(填充个人相关信息)
开通服务
- 点击云产品 - 对象存储
- 点击开通服务
创建存储桶
到这一步,账号的部分就操作完毕,接下来,我们需要来创建一个存储图片的存储桶 登录 对象存储控制台 ,创建存储桶。设置存储桶的权限为
**公有读,私有写**
设置cors规则
AllowHeader 需配成*
,如下图所示
因为我们本身没有域名,所以这里设置成
*****
,仅限于测试,正式环境的话,这里需要配置真实的域名地址
封装上传图片组件分析
**目标**
梳理整个的上传过程
初始化 cos 对象参数
名称 | 描述 |
---|---|
SecretId | 开发者拥有的项目身份识别 ID,用以身份认证,可在 API 密钥管理 |
页面获取 | |
SecretKey | 开发者拥有的项目身份密钥,可在 API 密钥管理 |
页面获取 |
注意,上述的参数我们在本次开发过程中,直接将参数放置在前端代码中存储, 但是腾讯云本身是不建议这么做的,因为
**敏感信息**
放在前端很容易被捕获,一般放在后台, 前端准备参数, 交给后台和腾讯云交互, 交互时, 需要秘钥, 秘钥在后台存着的 由于我们本次是测试研发,所以这个过程可以忽略 正确的做法应该是,通过网站调用接口换取敏感信息
实例化 上传sdk (这边还没用到, 先没配)
var cos = new COS({
SecretId: 'AKIDbw8bAXta6HCsIh45ev0qXWJp9hT7uJ2Y', // 身份识别 ID
SecretKey: 'Odg90oQ2EDwHhzELG8qidXB2UhHabonc', // 身份密钥
});
到目前为止,我们上传图片准备的内容就已经OK,接下来,我们在
**src/componets**
新建一个**ImageUpload**
组件
该上传组件需要满足什么要求呢?
- 可以显示传入的图片 (本地预览)
- 可以删除传入的图片
- 可以上传图片到云服务器
- 上传到腾讯云之后,可以返回图片地址,覆盖显示
- 上传成功之后,可以回调成功函数
封装上传组件代码实现
**目标**
实现上传组件的代码部分 JavaScript SDK 需浏览器支持基本的 HTML5 特性(支持 IE10 以上浏览器), 以便支持 ajax 上传文件和计算文件 MD5 值。
新建文件上传组件
- 安装JavaScript SDK
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) // 注册导入上传组件
}
}
总结:新建一个通用上传文件的组件,通过插件进行全局注册,然后在主页中进行测试。
点击图片进行预览
- 限定上传的图片数量和action
<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, // 控制显示弹层
imgUrl: ''
}
},
preview(file) {
// 这里应该弹出一个层 层里是点击的图片地址
this.imgUrl = file.url
this.showDialog = true
},
- 预览弹层
<el-dialog width="600px" top="8vh" title="图片预览" :visible.sync="showDialog">
<img width="100%" :src="imgUrl" alt="">
</el-dialog>
总结:
- 显示选择的图片列表 file-list
- 预览图片 on-preview
根据上传数量控制上传按钮
需求:当选中的图片大于等于一张时隐藏加号效果
- 控制上传显示
computed: {
// 设定一个计算属性 判断是否已经上传完了一张
isMultiple () {
return this.fileList.length >= 1
}
},
- 模板布局
<el-upload
list-type="picture-card"
:file-list="fileList"
:on-preview="preview"
:limit="1"
action=""
:class='{"hide-plus": isMultiple}'
>
<i class="el-icon-plus" />
</el-upload>
<style lang="scss" scoped>
.hide-plus {
::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"
:class="{disabled: fileComputed }"
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的http-request属性配的函数
:http-request="upload"
// 自定义上传动作 有个参数 有个file对象
handleUpload(params) {
// 进行上传操作
console.log(params.file)
}
- 添加文件时, 将页面的 fileList 同步到 this.fileList (数据中)
// 添加文件, 用户选了就应该新增文件预览
handleChange(file, fileList) {
// console.log(fileList)
// console.log(fileList.length)
this.fileList = fileList
},
总结
- 监听选中文件的事件 on-change
- 如果想手动上传文件,而不是默认上传给action,那么需要配置 http-request,该配置函数中可以进行手动上传操作
上传之前校验检查
控制上传图片的类型和上传大小, 如果不满足条件 返回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
},
总结:选择文件之前进行相关类型检测(文件类型和文件大小)
上传到腾讯云
- 上传动作为el-upload的http-request属性
:http-request="handleUpload"
// 自定义上传动作 有个参数 有个file对象,是我们需要上传到腾讯云服务器的内容
handleUpload(params) {
console.log(params.file)
}
我们需要在该方法中,调用腾讯云的上传方法
身份ID和密钥可以通过腾讯云平台获取
登录 访问管理控制台 ,获取您的项目 SecretId 和 SecretKey。
import COS from 'cos-js-sdk-v5' // 导入腾讯云的包(sdk)
const cos = new COS({
SecretId: 'AKIDe8LHxOcZHhqjLglZ6OREk0zra5MOAhyy', // 身份识别ID
SecretKey: 'lFUUDfqqa8PQAdokPnulLegRwA8qITN0' // 身份秘钥
})
// 进行上传操作
handleUpload(params) {
// console.log(params.file)
if (params.file) {
// 执行上传操作
cos.putObject({
Bucket: 'wh-1306446112', /* 存储桶 */
Region: 'ap-beijing', /* 存储桶所在地域,必须字段 */
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: 'AKIDbw8bAXta6HCsIh45ev0qXWJp9hT7uJ2Y', // 身份识别 ID
SecretKey: 'Odg90oQ2EDwHhzELG8qidXB2UhHabonc' // 身份密钥
})
- 配置相关的请求参数
handleUpload (params) {
cos.putObject({
// 存储桶名称
Bucket: 'wh-1306446112',
// 存储桶所在地址
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)
})
},
总结
- 这种上传方式仅仅用于测试,不太安全(秘钥容易泄露)
- 正规的流程应该把秘钥存储在后端服务器中
上传成功之后处理返回数据
如何处理返回成功的返回数据, 应该在上传完图片, 得到图片地址之后,
- 需要做的事情:
- 更新当前上传的对应图片的 status => 更新成 success
- 更新当前上传的对应图片的 url => 更新成腾讯云拿到的 Location (拼上前缀)
问题: this.fileList 是一个数组, 我怎么知道更新谁呢 ? params.file.uid 就是唯一标识 解决: 通过 params.file.uid 决定修改 this.fileList 中的哪个对象
- 处理返回数据
handleUpload (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的进度条显示当前的上传进度
- 放置进度条
<!-- 进度条组件 -->
<div v-if="isShow">上传进度:<el-progress style="width: 180px;" :percentage="percent" /></div>
- 通过腾讯云sdk监听上传进度
// 执行上传操作
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))
// 显示进度条
this.isShow = true
this.percent = progressData.percent * 100
if (progressData.percent === 1) {
// 进度完成
this.isShow = false
this.percent = 0
}
}
}
- 最后上传完, 延迟500毫秒关闭
handleUpload(params) {
if (params.file) {
this.isShow = true
// 执行上传操作
...
}, (err, data) => {
...
setTimeout(() => {
this.isShow = false
this.percent = 0
}, 500)
})
}
}
总结:基于腾讯云API的回调监控上传的进度
在员工详情中应用上传组件
配置上传图片组件的数量
- 组件接收参数
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="{'hide-plus': isMultiple}"
>
<i class="el-icon-plus" />
</el-upload>
- 父组件传入数量
<image-upload :limit="1"/>
总结:如果有相关信息需要定制,需要抽取组件的属性
员工的头像
在
**user-info.vue**
中放置上传组件
- 模板布局
<!-- 员工照片 -->
<el-row class="inline-info">
<el-col :span="12">
<el-form-item label="员工头像">
<image-upload ref="myAvatar" :limit="1" />
</el-form-item>
</el-col>
</el-row>
- 读取时初始化头像
// 获取员工基本信息(上面的表单)
async getUserBaseInfo () {
try {
const ret = await reqGetUserDetailById(this.userId)
if (!ret.success) {
this.$message.error(ret.message)
} else {
this.userInfo = ret.data
if (this.userInfo.staffPhoto) {
// 证明原来有头像数据,初始化头像效果
this.$refs.myAvatar.fileList = [{
url: this.userInfo.staffPhoto
}]
}
}
} catch {
this.$message.error('获取用户基本信息失败')
}
},
- 当点击保存更新时,获取图片的内容, 进行提交
async saveUser() {
// 去读取 员工上传的头像
const fileList = this.$refs.staffPhoto.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="员工照片">
<!-- ref不要重名 -->
<image-upload ref="myPhoto" :default-img="formData.staffPhoto" :limit="2" />
</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) {
const photos = this.formData.staffPhoto.split(';')
if (photos.length > 0) {
this.$refs.myPhoto.fileList = photos.map(item => {
return {
url: item
}
})
}
}
}
} 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 {
if (!this.$refs.myPhoto.isAllSuccess) {
this.$message.error('请等待上传图片成功后再提交表单')
return
}
// 处理选中的员工照片
const fileList = this.$refs.myPhoto.fileList
const photos = fileList.map(item => {
return item.url
})
const ret = await reqUpdatePersonal({
...this.formData,
// 定制照片数据格式
staffPhoto: photos.join(';'),
// 当前修改的用户的id
id: this.userId
})
if (!ret.success) {
this.$message.error(ret.message)
} else {
this.$message.success(ret.message)
}
} catch {
this.$message.error('更新用户基本信息失败')
}
}
}
总结:上传员工的照片,支持多张照片上传(封装成功上传的状态位)
员工列表显示图片
**目标**
:在员工列表中心显示图片 员工的头像可以在列表项中添加一列来进行显示, 处理下图片异常
- 基于ElementUI提供的图片组件定制列表的员工头像
<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, 需要重新错误检测)
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的用法是(把info字符串转换为二维码)
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='previewImg(scope.row.staffPhoto)' class='staff' :src='scope.row.staffPhoto'>
<div slot="error">
<img class="staff" :src="defaultImage">
</div>
</el-image>
</template>
</el-table-column>
总结:控制二维码弹窗的显示和隐藏。
二维码生成演示
- 我们尝试将canvas标签放到dialog的弹层中
<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'
previewImg (url) {
if (!url) return
this.showCodeDialog = true
// 把url转换为二维码并绘制到canvas画布中
// 注意:这里无法直接获取this.$refs.myCanvas元素的
this.$nextTick(() => {
// 如果这里url写的是网址,就会跳转到对应的网址(二维码分享效果)
QrCode.toCanvas(this.$refs.myCanvas, url)
})
},
总结:
- 二维码的绘制方式
- 关于$nextTick用法的理解