Vue2 实现一个简单的数据报告功能 1
调研过程就不做细究,方案不止一种,我当时找到了 4 种,各有优缺点,最后还是选择了如下的方式,因为更适合我们的项目。
1. 需求
先说说我们的需求吧,就是有些用户会在每周或者每月做数据统计汇总,我们发现,用户在制作报告的过程中,很多时候就是写好了一个 Word 模板,然后再从我们系统去获取数据填入,不同的用户使用的模板不一样,但是数据基本一致,所以我们想将这个过程简化,让用户能更快速的制作出一个报告。
2. 使用 file-saver + html-docx-js 实现导出 Word
- 安装:
yarn add file-saver html-docx-js - 使用(并没有写样式):
<template>
<div>
<button @click="exportWord">导出为Word</button>
<div ref="testDoc">
<h1>测试标题1</h1>
<h2>测试标题2</h2>
<h3>测试标题3</h3>
<h4>测试标题4</h4>
<h5>测试标题5</h5>
<p>测试段落</p>
<table>
<thead>
<th>标题1</th>
<th>标题2</th>
<th>标题3</th>
<th>标题4</th>
</thead>
<tbody>
<tr>
<td>1111</td>
<td>2222</td>
<td>3333</td>
<td>4444</td>
</tr>
<tr>
<td>1111</td>
<td>2222</td>
<td>3333</td>
<td>4444</td>
</tr>
<tr>
<td>1111</td>
<td>2222</td>
<td>3333</td>
<td>4444</td>
</tr>
</tbody>
</table>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
</ol>
<!-- 图片用线上地址或者base64格式 -->
<img src="https://img0.baidu.com/it/u=3580555748,3972654988&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500" alt="">
</div>
</div>
</template>
<script>
import { asBlob } from 'html-docx-js/dist/html-docx'
import saveAs from 'file-saver'
export default {
methods: {
exportWord () {
// this.$refs.testDoc.$el
const content = this.$refs.testDoc
const page = `<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>${content.innerHTML}</body></html>`
const converted = asBlob(page)
saveAs(converted, `测试.docx`)
}
}
}
</script>
点击导出按钮查看文件,效果如下(图片在第二页,没截取了):
可以看到,该有的结构都有,只是还没有写样式,一旦有了样式,那就好看了。所以基于此可以做一些简单的 word 文件的导出需求了。截取一张我们项目中使用到的最终导出的 Word 效果图吧(因为涉及到部分隐私数据,所以打码了):
大概说说实现步骤吧,感兴趣的可以自己去研究下。
首要的功能已经实现,就是将 HTML 导出为 Word,接下来就是实现部分样式(样式要用内联那种哟,而且样式也不是百分百的兼容,细节还等待你去发现),将数据填充上去。为什么导出 Word,说白了就是将部分能从系统抓取的数据展示出来,然后用户就可以基于此做一个报告出来,不用在网站上到处找数据去做报告。
3. 一些核心功能的实现
这里就简单的说一些核心功能的实现方式(完全的实现还是比较复杂,如果以后空闲了,我再出一个更详细的,可能还要分几篇来写)。
从我们的需求中可以看到,用户是基于自己的 Word 模板来制作各自的数据报告,所以,我们得实现定制化模板的功能,基于这个模板,一键生成数据报告。那么这个模板具体有些什么?其实很简单,当然是文字 + 图表了 (哈哈哈,开个玩笑)。我们将它细分为如下功能模块。
- 标题模块
- 段落模块
- 表格模块
- 数据图模块
- 有序/无序列表模块
- 样式设置模块
分析到这里,是不是有点儿奇奇怪怪的感觉,感觉这个功能是不是在哪里见过?好吧,这不就是一个富文本编辑器嘛,只不过我们是特殊化定制的富文本编辑器。
模板分析到这里,接下来就是数据了,模板的作用就是后面生成报告的时候,直接将数据填充上去,就是一个报告了,那么如何将数据填充?其实也简单,留个坑位,到时候直接替换即可。我们将数据分为如下几种情况,分别有不同的替换方式。
- 段落中的数据:例如:
本周新增了 20 人,这个 20 就是我们要替换的数据,这种使用的是占位,有点儿像 Vue 的{{}},为了和 Vue 区分开,最后就变成了这种,本周新增了 {%newPeopleWeek%} 人,在生成报告的时候用正则替换即可。这种适用于标题模块,段落模块,有序/无序列表模块,因为展示的都是一些非结构化的数据。 - 表格中的数据:表格我们分为两种
- 用户就想要得一个什么都没有的表格,内容用户自己添加,不涉及到数据。这个比较简单,就是生成一个普通的表格,内容用户自己去编辑,行列也由用户自己去增加删除。
- 用户想展示数据的表格。这种表格就比较简单了,和后端约定好数据结构,然后通过这个结构去生成对应的表格即可,用户想要生成这种表格,就是在点击生成表格模块的时候选择自己想要展示得一个数据源,到时候生成报告的时候,将这个数据源 ID 给后端,他返回对应的数据即可。一般这就结束了,但是用户不同,我们不知道他们想展示什么数据,只有一个大概的范围,所以给出了数据源这个概念,万一部分用户只想展示这个数据源中部分列数据,怎么办?害,再增加个选择功能即可,每行再增加个删除功能,但是删除了怎么回退?增加个操作列表,记录历史操作,撤销就是,有点儿感觉没得,是不是有点儿像 命令模式 的感觉(后期也是用命令模式来实现的)。最后大概就像下面这样。
- charts 数据:图这种数据和表格类似,也是结构化的数据,我们制作模板的时候依然只是选择数据源,后期生成报告的时候根据数据源 ID 去拿到对应的数据展示成图表即可,因为 Word 还没有强大到兼容我们的交互式图表,所以我们这里在生成图表后直接通过截图保存即可。一般这也就结束了,但是的用户是不同的人,我们不知道他到底想怎么去展示这种数据,有些用户喜欢饼图,有些喜欢折线图,有些喜欢柱状图,怎么办?害,继续加呗,根据这份数据去生成不同的图表,简单。最后大约就是像下面这样(当然还有有些其他的特殊定制化图表,实现步骤都差不多,只是数据结构不一样罢了)。
4. 最后
由于篇幅和时间关系,所以就没有更细致的解析,后面如果我空闲了再出一版更为详细的。如果你刚好有这方面的需求,可以按照这个思路来实现一个,有其他疑问再一起讨论即可。