亮神知识库 亮神知识库
首页
  • 手写代码

    • 手写代码系列
  • 基础知识

    • 基础
    • JS底层
    • CSS
  • 原理
  • 浏览器
  • HTTP
  • 网络安全
  • babel
  • webpack基础
  • webpack进阶
  • Vite
  • TypeScript
  • Vue2
  • Vue3
  • Node基础

    • glob
    • 模块化机制
    • 事件循环
    • KOA2框架原理
    • Node子进程
    • cluster原理(了解)
  • 教育行业2021

    • B端
    • C端
    • 工具
  • 游戏行业2025
  • 刷题
  • 杂(待整理)
  • 学习
  • 面试
  • 实用技巧
  • 心情杂货
  • 年度总结
  • 友情链接
关于
  • 分类
  • 标签
  • 归档
  • 收藏
GitHub (opens new window)

亮神

前程明亮,未来可期
首页
  • 手写代码

    • 手写代码系列
  • 基础知识

    • 基础
    • JS底层
    • CSS
  • 原理
  • 浏览器
  • HTTP
  • 网络安全
  • babel
  • webpack基础
  • webpack进阶
  • Vite
  • TypeScript
  • Vue2
  • Vue3
  • Node基础

    • glob
    • 模块化机制
    • 事件循环
    • KOA2框架原理
    • Node子进程
    • cluster原理(了解)
  • 教育行业2021

    • B端
    • C端
    • 工具
  • 游戏行业2025
  • 刷题
  • 杂(待整理)
  • 学习
  • 面试
  • 实用技巧
  • 心情杂货
  • 年度总结
  • 友情链接
关于
  • 分类
  • 标签
  • 归档
  • 收藏
GitHub (opens new window)
  • 教育行业2021

    • B端

      • 批量下载图片
        • 需求场景
        • 任务
        • 实现
        • 结果
        • 总结
      • 业务组件库
      • 公共组件库
      • 单点登录
      • 微前端系统
    • C端

    • 工具

  • 项目
  • 教育行业2021
  • B端
0zcl
2025-06-19
目录

批量下载图片

提示

STAR:Situation(情景),Task(任务),Action(行动)和 Result(结果)

XXX 项目出现 XXX 问题,我作为 XXX,负责其中的 XXX 部分,我通过 XXX 方式(或技术方案)成功解决了该问题,使 XXX 提高了 XXX,XXX 增长了 XXX

在项目经历描述中,通过交代清楚你在团队中的位置,以及大略描述你在团队中起到的作用

# 需求场景

班主任制作海报再分享给家长的过程中,需要手动选画作,而制作一张海报需3-5分钟,导致效率、分享意愿不高问题。希望去除需选画作的步骤,系统以近三个月老师点评得分最高(如得分相同则随机挑选)的画作为默认画作。实现自动挑选画作并生成海报。

poster

# 任务

作为前端开发,独立负责海报下载功能开发。并需要将批量下载功能封装到业务组件库中。

# 实现

  1. 后端实现。在做批量下载功能时,一般是让后端去实现。前端直接调个接口即可。批量下载邀请卡就是这样做的。
// src/api/teach/studentList.js
export function batchDownloadCard(data) {
  return hllUcRequest({
    headers: {
      'Content-type': 'application/json;charset=UTF-8'
    },
    url: '/transfer/poster/batch/qrcode',
    method: 'post',
    responseType: 'blob',
    timeout: 1000 * 60 * 10,
    data
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13

responseType (opens new window)属性设置为“blob”,将二进制文件读取为Blob类型的数据。再利用Blob对象创建指定压缩包并下载即可。

batchDownload() {
  this.batchDownloadLoading = true
  batchDownloadCard(sendData).then(res => {
    var reader = new FileReader()
    const today = moment(new Date()).format('MM-DD')
    reader.onload = e => {
      try {
        var msg = JSON.parse(e.target.result)
      } catch (error) {
        return this.downLoadFn(res, `${today}批量下载邀请卡.zip`)
      } finally {
        this.batchDownloadLoading = false
      }
      // 错误提示
      if (msg.hasOwnProperty('code')) {
        return this.$message.error(msg.msg)
      }
    }
    reader.readAsText(res)
  }).finally(e => {
    this.batchDownloadLoading_1 = false
  })
}

downLoadFn(data, filename) {
  const b = new Blob([data])
  const url = URL.createObjectURL(b)
  const link = document.createElement('a')
  link.href = url
  link.download = filename
  link.click()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  1. 前端实现。下载邀请卡后端实现了,但下载画作邀请卡后端以”之前是前端实现的“以及”后端实现有性能问题“,就把锅甩给我。说干就干
  • 把旧的代码抽离到组件
  • 优化并删掉一些旧的lj代码
  • 前端实现批量下载功能。下面只讲这一点 海报生成使用<code>html2canvas</code>, 压缩包生成使用<code>jszip + file-saver</code>
import html2canvas from 'html2canvas'
import moment from 'moment'
import JSZip from 'jszip/dist/jszip'
import FileSaver from 'file-saver'

methods: {
  async batchDownload(data) {
    this.userIds = data.userIds
    this.rbkdImgUrl = IMG2_61INFO_URL_OBJ[localStorage.getItem('studentRecordEnv') || 'PROD']
    if (this.userIds && this.userIds.length) {
      try {
        const failMessage = await this.getInfo()
        await this.renderPoster()
        if (failMessage) {
          this.errorMsgList = failMessage.split(';')
          this.dialogVisible = true
        }
      }
      finally {
        this.$emit('loadEnd')
      }

    } else {
      this.$message.error('传入的学员ID有问题, 请联系管理员~')
    }
  },
  // 获取批量信息
  getInfo() {
    return new Promise((resolve, reject) => {
      getBatchInfo({ userIds: this.userIds }).then(res => {
        if ([0, 200].includes(res.code)) {
          this.batchInfo = res.data
          res.data.failMessage ? resolve(res.data.failMessage) : resolve()
        }
        reject('批量获取学员数据失败', res.msg)
      })
    })
  },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

学员海报图片如下:

batchDownload() 先调getInfo()获取批量信息;再执行renderPoster()。renderPoster是核心。

  1. 获取生成海报所需的图片URL。画作图,海报背景图,用户头像图,二维码图
  2. 加载图片。使用Promise.all确定图片都加载完成才执行下一步。也保证了执行html2canvas生成图片前,海报DOM渲染完毕
  3. DOM --> 图片 --> base64。
async renderPoster() {
  const jsZip = new JSZip()
  for (let i = 0, len = this.batchInfo.paintContentCreateInfoVOS.length; i < len; i++) {
    // 1-画作图
    this.currentPaintUrl = this.ossImgUrl + paintContentCreateInfoVOS.noFrameImgUrl
    // 2-海报背景图
    this.currentPosterUrl = this.rbkdImgUrl + this.currentPaintParams.materialPicUrl
    // 3-用户头像图
    this.currentHeadUrl = paintContentCreateInfoVOS.headUrl ? `data:image/png;base64,${paintContentCreateInfoVOS.headUrl}` : ''
    try {
      await Promise.all([
        this.loadImage(this.currentPosterUrl),
        this.currentHeadUrl ? this.loadImage(this.currentHeadUrl) : Promise.resolve(),
        this.loadImage(this.currentQrcodeUrl) // 4-二维码图
      ])
    } catch (error) {
      continue
    }
    // 下载相关的信息
    const downloadInfo = this.getDownloadInfo({
      userId,
      userName: paintContentCreateInfoVOS.userName,
      posterName: paintContentCreateInfoVOS.title
    })
    const imgName = `${downloadInfo.userId}_${downloadInfo.userName}_${downloadInfo.posterName}_${downloadInfo.downloadDate}.png`
    // DOM --> 图片 --> base64
    let imgData = await this.getBase64({ userId: downloadInfo.userId })
    imgData = imgData.replace(/^data:image\/(png|jpg|jpeg);base64,/, '')
    jsZip.file(imgName, imgData, { base64: true })
  } // end for
  // 生成压缩包
  jsZip.generateAsync({ type: 'blob' }).then(content => {
    FileSaver.saveAs(content, `${today}批量下载画作邀请卡.zip`)
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

renderPoster循环生成图片,最后生成压缩包。再<code>this.$emit('loadEnd')</code>,组件抛出加载完成事件。至此完成。

processon

流程图如上,这个功能是2,3个月前开发的,现在看看,总的也说不上有啥难点。但还是比较考验综合能力的。

把DOM转base64, loadImage, getImgSize,downLoadFn抽离一下。

# 结果

邀请卡生成量增加1.9w, 增幅74.3%;画作邀请卡的生成数3w/天,用户分享率达86.30%;人效增幅上提升了74.3%;转介绍例子数增加42%;

# 总结

批量合成画作下载:

班主任在制作海报时,需要手动选画作,导致海报制作效率和分享意愿不高。希望去除手动选画作步骤,自动挑选画作并批量下载。我负责海报批量下载功能开发,并将批量下载功能封装到组件库中。批量合成下载有两种方式,一种是后端实现合成,前端直接调接口,下载成压缩包即可;另一种是前端实现,通过html2canvas合成海报,jszip+file-saver生成压缩包。功能上线后,人效增长74%,转介绍例子数增加42%

前端实现流程:先获取批量信息列表,for循环信息列表来合成画作图片,其中先加载合成海报所需的图片,加载完成,也就是DOM渲染完成后,再把海报DOM转成图片base64, 再生成压缩包

编辑 (opens new window)
上次更新: 2025/07/24, 10:06:21
业务组件库

业务组件库→

最近更新
01
2024年
07-20
02
2023年
07-20
03
2022年
07-20
更多文章>
Theme by Vdoing | Copyright © 2025-2025 亮神 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式