前言
目录
一、配置腾讯云空间存储图片
我们找一个可以免费上传图片的服务器,帮我们代管图片,我们在自己的数据库里只保存一个地址就行。
这个服务器就是一个公共的文件服务器,在这里我们使用腾讯云来保存图片
1.1 配置步骤
1、注册一个腾迅云的开发者账号
2、实名认证
3、点击领取免费产品
4、选择对象存储COS
5、点击0元试用,开通服务
6、登录对象存储控制台 ,创建存储桶。设置存储桶的权限为公有读,私有写
7、设置cors规则
8、把AllowHeader配成*
9、配置完成
二、图片上传流程解析
我们新建的图片上传组件需要满足以下几个需求:
1. 可以显示传入的图片地址
2. 可以删除传入的图片地址
3. 可以上传图片到云服务器
4. 上传到腾讯云之后,可以返回图片地址,显示
5. 上传成功之后,可以回调成功函数
三、实现文件上传组件
3.1 安装依赖
$ npm i cos-js-sdk-v5 --save
3.2 上传图片组件的基本布局
在src/components/ImageUpload/index.vue中添加如下代码:
<template>
<el-upload list-type="picture-card">
<i class="el-icon-plus" />
</el-upload>
</template>
注意:这里使用element的el-upload组件,并且采用照片墙的模式
3.3 全局注册组件
在src/components/index.vue中添加如下代码:
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) // 注册导入上传组件
}
}
3.4 点击图片进行预览
首先,在src/components/ImageUpload/index.vue中新建一个预览图片对话框:
<el-dialog :visible.sync="showDialog" title="图片预览">
<img :src="imgUrl" alt="" style="width:100%">
</el-dialog>
然后,绑定el-upload组件的on-preview事件来弹出预览图片对话框:
<!-- 给action一个#号 就不会报错了 -->
<el-upload
list-type="picture-card"
:limit="1"
action="#"
:on-preview="preview"
>
<i class="el-icon-plus" />
</el-upload>
data() {
return {
fileList: [], // 图片地址设置为数组
showDialog: false, // 控制显示弹层
imgUrl: ''
}
},
methods:{
preview(file) {
// 这里应该弹出一个层 层里是点击的图片地址
this.imgUrl = file.url
this.showDialog = true
}
}
3.5 控制图片上传数量
在src/components/ImageUpload/index.vue中添加如下代码:
给el-upload绑定一个class属性,当图片数组长度等于1时隐藏新增图片按钮,这样就可以控制图片的上传数量:
<el-upload
list-type="picture-card"
:limit="1"
action="#"
:on-preview="preview"
:class="{disabled: fileComputed }"
>
<i class="el-icon-plus" />
</el-upload>
computed: {
// 设定一个计算属性 判断是否已经上传完了一张
fileComputed() {
return this.fileList.length === 1
}
},
<style>
.disabled .el-upload--picture-card {
display: none
}
</style>
3.6 删除图片和添加图片
在src/components/ImageUpload/index.vue中添加如下代码:
给el-upload绑定一个图片上传数组,删除事件和添加事件:
<el-upload
list-type="picture-card"
:limit="1"
action="#"
:file-list="fileList"
:on-preview="preview"
:class="{disabled: fileComputed }"
:on-remove="handleRemove"
:on-change="changeFile"
>
handleRemove(file) {
// file是点击删除的文件
// 将原来的文件给排除掉了 剩下的就是最新的数组了
this.fileList = this.fileList.filter(item => item.uid !== file.uid)
},
// 修改文件时触发
// fileList参数是当前传进来的最新参数 我们只需要将其转化成数组即可
// 上传成功之后 还会进来 需要实现上传代码的逻辑 这里才会成功
changeFile(file, fileList) {
this.fileList = fileList.map(item => item)
}
3.7 控制上传图片的类型和大小
在src/components/ImageUpload/index.vue中添加如下代码:
<el-upload
list-type="picture-card"
:limit="1"
action="#"
:file-list="fileList"
:on-preview="preview"
:class="{disabled: fileComputed }"
:on-remove="handleRemove"
:on-change="changeFile"
:before-upload="beforeUpload"
>
beforeUpload(file) {
// 要开始做文件上传的检查了
// 文件类型 文件大小
const types = ['image/jpeg', 'image/gif', 'image/bmp', 'image/png']
if (!types.includes(file.type)) {
this.$message.error('上传图片只能是 JPG、GIF、BMP、PNG 格式!')
return false
}
// 检查大小
const maxSize = 5 * 1024 * 1024
if (maxSize < file.size) {
this.$message.error('图片大小最大不能超过5M')
return false
}
// 已经确定当前上传的就是当前的这个file了
this.currentFileUid = file.uid
return true
}
3.8 将图片上传到腾讯云
上传图片需要用到SecretId,SecretKey,可以登录访问管理控制台来获取,如下图所示:
在src/components/ImageUpload/index.vue中添加如下代码:
<el-upload
list-type="picture-card"
:limit="1"
action="#"
:file-list="fileList"
:on-preview="preview"
:class="{disabled: fileComputed }"
:on-remove="handleRemove"
:on-change="changeFile"
:before-upload="beforeUpload"
:http-request="upload"
>
import COS from 'cos-js-sdk-v5' // 引入腾讯云cos包
// 实例化COS对象
const cos = new COS({
// 将获取到的秘钥和key复制到这里
SecretId: 'xxxxxxx', // 身份识别 ID
SecretKey: 'xxxxxx' // 身份密钥
})
// 进行上传操作
// 将上传成功的地址 回写到了fileList中 upload组件就会根据fileList的变化而去渲染视图
upload(params) {
if (params.file) {
// 执行上传操作
// 上传到腾讯云 =》 哪个存储桶 哪个地域的存储桶 文件 格式 名称 回调
cos.putObject({
Bucket: 'xxxx, // 存储桶名
Region: 'ap-beijing', // 地域
Key: params.file.name, // 文件名
Body: params.file, // 要上传的文件对象
StorageClass: 'STANDARD' // 上传的模式类型 直接默认 标准模式即可
}, (err, data) => {
// data中有一个statusCode === 200 的时候说明上传成功
if (!err && data.statusCode === 200) {
// 此时说明文件上传成功 要获取成功的返回地址
// 我们要将fileList中的数据的url地址变成现在上传成功的地址
// 需要知道当前上传成功的是哪一张图片
this.fileList = this.fileList.map(item => {
// 去找谁的uid等于刚刚记录下来的id
if (item.uid === this.currentFileUid) {
// 将成功的地址赋值给原来的url属性
// upload 为true 表示这张图片已经上传完毕 这个属性要为我们后期应用的时候做标记
// 保存 => 图片有大有小 => 上传速度有快又慢 =>要根据有没有upload这个标记来决定是否去保存
return {
url: 'http://' + data.Location, upload: true }
}
return item
})
}
})
}
}
3.9 上传图片的进度条显示
在src/components/ImageUpload/index.vue中添加如下代码:
使用el-progress组件实现进度条展示:
<el-progress v-if="showPercent" style="width: 180px" :percentage="percent" />
通过腾讯云sdk监听上传进度:
cos.putObject({
// 配置
Bucket: 'laogao-1302806742', // 存储桶名称
Region: 'ap-guangzhou', // 存储桶地域
Key: params.file.name, // 文件名作为key
StorageClass: 'STANDARD', // 此类写死
Body: params.file, // 将本地的文件赋值给腾讯云配置
// 进度条
onProgress: (params) => {
this.percent = params.percent * 100
}
}
四、在员工详情中应用上传组件
在src/views/employees/components/user-info.vue中应用上传组件
<!-- 员工照片 -->
<el-row class="inline-info">
<el-col :span="12">
<el-form-item label="员工头像">
<!-- 放置上传图片 -->
<image-upload ref="staffPhoto" />
</el-form-item>
</el-col>
</el-row>
async getUserDetailById() {
this.userInfo = await getUserDetailById(this.userId)
if (this.userInfo.staffPhoto) {
// 这里我们赋值,同时需要给赋值的地址一个标记 upload: true
this.$refs.staffPhoto.fileList = [{
url: this.userInfo.staffPhoto, upload: true }]
}
},
保存员工信息时保存图片:
async saveUser() {
// 去读取 员工上传的头像
const fileList = this.$refs.staffPhoto.fileList // 读取上传组件的数据
if (fileList.some(item => !item.upload)) {
// 如果此时去找 upload为false的图片 找到了说明 有图片还没有上传完成
this.$message.warning('您当前还有图片没有上传完成!')
return
}
// 通过合并 得到一个新对象
await saveUserDetailById({
...this.userInfo, staffPhoto: fileList && fileList.length ? fileList[0].url : '' })
this.$message.success('保存基本信息成功')
},
五、打印员工信息
5.1 新建打印页面及路由
在src/views/employees/目录下新建print.vue组件,基本布局如下:
<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>
<el-row type="flex" justify="end">
<!-- 利用v-print指令完成页面的打印 -->
<el-button v-print="printObj" size="mini" type="primary">打印</el-button>
</el-row>
<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>{
{
formData.nativePlace }}</td>
<th>民族</th>
<td colspan="5">{
{
formData.nation }}</td>
</tr>
<tr>
<th>员工照片</th>
<td>{
{
formData.staffPhoto }}</td>
<th>生日</th>
<td colspan="5">{
{
formData.birthday }}</td>
</tr>
<tr>
<th>户籍所在地</th>
<td>{
{
formData.domicile }}</td>
<th>政治面貌</th>
<td colspan="5">{
{
formData.politicalOutlook }}</td>
</tr>
</table>
</el-card>
</div>
</div>
</template>
绑定数据和事件:
<script>
import {
getPersonalDetail, getJobDetail } from '@/api/employees'
import {
getUserDetailById } from '@/api/user'
export default {
data() {
return {
formData: {
},
userId: this.$route.params.id,
}
},
// 创建完毕状态
created() {
this.getPersonalDetail()
},
// 组件更新
methods: {
async getPersonalDetail() {
this.formData = await getPersonalDetail(this.userId) // 获取个人基本信息
},
}
}
</script>
<style lang="scss">
.foot {
padding: 30px 0;
text-align: right;
}
</style>
在src/router/modules/employees.js中添加路由:
{
path: 'print/:id',
component: () => import('@/views/employees/print'),
hidden: true,
meta: {
title: '员工打印'
}
}]
5.2 利用vue-print-nb进行打印
首先,安装依赖:
$ npm i vue-print-nb
然后在src/components/index.vue中注册该组件:
import Print from 'vue-print-nb'
Vue.use(Print);
最后在src/views/employees/print.vue中使用v-print指令的方式进行打印
<el-row type="flex" justify="end">
<el-button v-print="printObj" size="small" type="primary">打印</el-button>
</el-row>
printObj: {
id: 'myPrint'
}