Vue project actual combat human resources platform system (10) picture upload and print employee information

foreword

1. Configure Tencent Cloud space to store pictures

Let's find a server that can upload pictures for free and host the pictures for us. We only need to save one address in our database.
This server is a public file server, where we use Tencent Cloud to save pictures

1.1 Configuration steps

1、注册一个腾迅云的开发者账号
2、实名认证
3、点击领取免费产品
4、选择对象存储COS
5、点击0元试用,开通服务
6、登录对象存储控制台 ,创建存储桶。设置存储桶的权限为公有读,私有写
7、设置cors规则
8、把AllowHeader配成*
9、配置完成

2. Image upload process analysis

Our new image upload component needs to meet the following requirements:

1. 可以显示传入的图片地址
2. 可以删除传入的图片地址
3. 可以上传图片到云服务器
4. 上传到腾讯云之后,可以返回图片地址,显示
5. 上传成功之后,可以回调成功函数

3. Implement the file upload component

3.1 Installation dependencies

$ npm i cos-js-sdk-v5 --save

3.2 Basic layout of upload image component

Add the following code in 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 Global Registration Components

Add the following code in 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 Click the picture to preview

First, create a preview image dialog in src/components/ImageUpload/index.vue:

<el-dialog :visible.sync="showDialog" title="图片预览">
  <img :src="imgUrl" alt="" style="width:100%">
</el-dialog>

Then, bind the on-preview event of the el-upload component to pop up the preview image dialog box:

    <!-- 给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 Control the number of pictures uploaded

Add the following code in src/components/ImageUpload/index.vue:
Bind a class attribute to el-upload, and hide the new picture button when the length of the picture array is equal to 1, so that the number of uploaded pictures can be controlled:

    <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 Delete pictures and add pictures

Add the following code in src/components/ImageUpload/index.vue:
Bind an image upload array to el-upload, delete events and add events:

<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 Control the type and size of uploaded pictures

Add the following code in 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 Upload pictures to Tencent Cloud

Uploading pictures requires SecretId and SecretKey, which can be obtained by logging in to the management console, as shown in the following figure:
insert image description here

Add the following code in 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 Progress bar display of uploading pictures

Add the following code in src/components/ImageUpload/index.vue:
Use the el-progress component to display the progress bar:

<el-progress v-if="showPercent" style="width: 180px" :percentage="percent" />

Monitor upload progress through Tencent Cloud 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
          }
        }

4. Apply the upload component in employee details

Apply the upload component in 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 }]
      }
    },

Save pictures when saving employee information:

  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. Print employee information

5.1 Create a new print page and route

Create a new print.vue component in the src/views/employees/ directory. The basic layout is as follows:

<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>

Bind data and events:

<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 Printing with vue-print-nb

First, install dependencies:

$ npm i vue-print-nb

Then register the component in src/components/index.vue:

import Print from 'vue-print-nb'
Vue.use(Print);

Finally, use the v-print command in src/views/employees/print.vue to print

  <el-row type="flex" justify="end">
          <el-button v-print="printObj" size="small" type="primary">打印</el-button>
   </el-row>

   printObj: {
    
    
        id: 'myPrint'
   }

Summarize

Guess you like

Origin blog.csdn.net/qq_40652101/article/details/127069441