IndexLineChart.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. <template>
  2. <div style="height: 100%; width: 100%">
  3. <div class="chart-title">
  4. <div class="name" :title="title">
  5. {{ title }}
  6. </div>
  7. <div class="operation">
  8. <!-- <el-button size="mini" plain @click="initChart()">
  9. <span class="icon iconfont icontjfx"></span>
  10. </el-button>
  11. <el-button size="mini" plain @click="initTable()">
  12. <span class="icon iconfont icontongjibiao"></span>
  13. </el-button> -->
  14. <el-radio v-model="showType" label="chart">chart</el-radio>
  15. <el-radio v-model="showType" label="table">表格</el-radio>
  16. <div class="operation-btn" @click="downLoadInfo()">
  17. <img class="icon" :src="require('../../images/download.png')" />
  18. <label>下载</label>
  19. </div>
  20. <!-- <div class="operation-btn">
  21. <img class="icon" :src="require('../../images/expand.png')" />
  22. <label>展开</label>
  23. </div> -->
  24. </div>
  25. </div>
  26. <div class="dataContainer">
  27. <div class="IndexLineChart" ref="chart" v-if="!isShowTable"></div>
  28. <el-table id="dataTable" :data="tableData" v-if="isShowTable" style="width: 100%; height: 100%; overflow: auto">
  29. <el-table-column
  30. v-for="item of tabelColumn"
  31. :key="item.value"
  32. :prop="item.prop"
  33. :label="item.label"
  34. show-overflow-tooltip
  35. ></el-table-column>
  36. </el-table>
  37. </div>
  38. </div>
  39. </template>
  40. <script lang='ts'>
  41. import echarts, { ECharts } from 'echarts'
  42. import html2canvas from 'html2canvas'
  43. import XLSX from 'xlsx'
  44. import FileSaver from 'file-saver'
  45. import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
  46. @Component({ name: 'IndexLineChart', components: {} })
  47. export default class IndexLineChart extends Vue {
  48. @Prop({ type: Object, default: () => ({}) }) chartData!: any
  49. @Watch('chartData', { immediate: true })
  50. onChangeMethod() {
  51. this.$nextTick(() => {
  52. this.initialChart()
  53. })
  54. }
  55. @Prop({ type: Boolean, default: false }) isActive!: boolean
  56. @Watch('isActive', { immediate: true })
  57. refetchData(active: boolean) {
  58. if (active) this.onResize()
  59. }
  60. get title() {
  61. return `${this.chartData.siteName}:${this.chartData.indexName}${
  62. this.chartData.unit ? `(${this.chartData.unit})` : ''
  63. }`
  64. }
  65. myChart = null
  66. isShowTable = false
  67. tableData = []
  68. tabelColumn = [
  69. {
  70. prop: 'siteName',
  71. label: '厂站'
  72. },
  73. {
  74. prop: 'indexName',
  75. label: '指标'
  76. },
  77. {
  78. prop: 'staType',
  79. label: '统计内容'
  80. },
  81. {
  82. prop: 'data',
  83. label: '指标值'
  84. },
  85. {
  86. prop: 'time',
  87. label: '时间'
  88. }
  89. ]
  90. showType = 'chart'
  91. @Watch('showType', { immediate: true })
  92. showTypeChangeMethod(type) {
  93. this.$nextTick(() => {
  94. type == 'chart' ? this.initChart() : this.initTable()
  95. })
  96. }
  97. destroyChart() {
  98. if (this.myChart != null) {
  99. this.myChart.dispose()
  100. this.myChart = null
  101. }
  102. }
  103. onResize() {
  104. if (this.myChart) {
  105. this.myChart.resize()
  106. }
  107. }
  108. initialChart() {
  109. this.destroyChart()
  110. const { xData: xaxis, seriesData, tableData, siteName, indexName } = this.chartData
  111. //表格数据
  112. this.tableData = tableData.map((i) => {
  113. return {
  114. ...i,
  115. siteName,
  116. indexName
  117. }
  118. })
  119. //
  120. let seriesValue = []
  121. seriesData.forEach((item) => {
  122. seriesValue.push({
  123. name: item.name,
  124. data: item.data,
  125. type: 'line',
  126. smooth: true
  127. // symbol: 'none'
  128. })
  129. })
  130. let option = {
  131. grid: {
  132. bottom: 20,
  133. top: 50,
  134. right: 20,
  135. left: 20,
  136. containLabel: true
  137. },
  138. tooltip: {
  139. trigger: 'axis'
  140. },
  141. xAxis: {
  142. type: 'category',
  143. axisLine: { show: false },
  144. axisTick: { show: false },
  145. data: xaxis
  146. },
  147. yAxis: {
  148. type: 'value',
  149. name: '',
  150. nameTextStyle: {
  151. padding: [0, 0, 0, -40],
  152. align: 'left',
  153. color: '#2D74E7',
  154. fontWeight: '500',
  155. fontSize: '14',
  156. fontFamily: 'Source Han Sans CN'
  157. },
  158. nameGap: 30,
  159. axisLine: { show: false },
  160. axisTick: { show: false }
  161. },
  162. series: seriesValue
  163. }
  164. this.creatChart(option, this.$refs.chart)
  165. }
  166. creatChart(option, ref) {
  167. this.myChart = echarts.init(ref) //this.$refs.chart
  168. this.myChart.resize()
  169. this.myChart.setOption(option, {
  170. notMerge: true
  171. })
  172. //图表大小自适应
  173. window.addEventListener('resize', () => {
  174. this.myChart.resize()
  175. })
  176. }
  177. initTable() {
  178. this.isShowTable = true
  179. }
  180. initChart() {
  181. this.isShowTable = false
  182. this.$nextTick(() => {
  183. this.initialChart()
  184. })
  185. }
  186. //下载
  187. downLoadInfo() {
  188. if (this.isShowTable) {
  189. this.exportTable()
  190. } else {
  191. this.exportChart()
  192. }
  193. }
  194. exportTable() {
  195. let wb = XLSX.utils.table_to_book(document.querySelector('#dataTable'), { raw: true })
  196. let wbout = XLSX.write(wb, {
  197. bookType: 'xlsx',
  198. bookSST: true,
  199. type: 'array'
  200. })
  201. try {
  202. FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), '数据表格.xlsx')
  203. } catch (e) {
  204. if (typeof console !== 'undefined') console.log(e, wbout)
  205. }
  206. return wbout
  207. }
  208. exportChart() {
  209. // 图表转换成canvas
  210. //@ts-ignore
  211. html2canvas(this.$refs.chart).then(function (canvas) {
  212. var img = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream')
  213. // 创建a标签,实现下载
  214. var creatIMg = document.createElement('a')
  215. creatIMg.download = `图表.png` // 设置下载的文件名,
  216. creatIMg.href = img // 下载url
  217. document.body.appendChild(creatIMg)
  218. creatIMg.click()
  219. creatIMg.remove() // 下载之后把创建的元素删除
  220. })
  221. }
  222. }
  223. </script>
  224. <style lang="scss" scoped>
  225. .chart-title {
  226. display: flex;
  227. justify-content: space-between;
  228. align-items: center;
  229. font-size: 16px;
  230. position: relative;
  231. margin-top: 10px;
  232. height: 20px;
  233. .name {
  234. font-family: Source Han Sans CN-Medium;
  235. font-style: normal;
  236. font-weight: 500;
  237. font-size: 14px;
  238. color: #2d74e7;
  239. white-space: nowrap;
  240. overflow: hidden;
  241. text-overflow: ellipsis;
  242. }
  243. .operation {
  244. // position: absolute;
  245. // right: 0;
  246. // z-index: 999;
  247. display: flex;
  248. align-items: center;
  249. @mixin font() {
  250. color: #333333;
  251. font-family: Source Han Sans CN;
  252. font-style: normal;
  253. font-weight: 400;
  254. font-size: 14px;
  255. }
  256. .el-button {
  257. padding: 2px;
  258. border: none;
  259. color: #333333;
  260. }
  261. >>> .el-radio {
  262. .el-radio__label {
  263. @include font();
  264. padding-left: 5px;
  265. }
  266. .el-radio__inner::after {
  267. height: 8px;
  268. width: 8px;
  269. background-color: #2083e8;
  270. }
  271. .el-radio__inner {
  272. border: 1px solid rgba(128, 175, 214, 1);
  273. background-color: transparent;
  274. }
  275. }
  276. .operation-btn {
  277. display: flex;
  278. align-items: center;
  279. cursor: pointer;
  280. margin-right: 30px;
  281. .icon {
  282. height: 14px;
  283. width: 14px;
  284. margin-right: 5px;
  285. }
  286. label {
  287. @include font();
  288. cursor: pointer;
  289. white-space: nowrap;
  290. }
  291. }
  292. }
  293. }
  294. .dataContainer {
  295. width: 100%;
  296. height: calc(100% - 30px);
  297. .IndexLineChart {
  298. width: 100%;
  299. height: 100%;
  300. }
  301. }
  302. </style>