|
|
@@ -0,0 +1,385 @@
|
|
|
+<!-- 竖形柱状图 -->
|
|
|
+<script lang="ts" setup>
|
|
|
+import * as echarts from 'echarts'
|
|
|
+import { useThemeStore } from '@/stores/modules/theme'
|
|
|
+import { onMounted, ref, reactive, watch, computed } from 'vue'
|
|
|
+import updateIcon from '../image/xiazai.png'
|
|
|
+import * as XLSX from 'xlsx'
|
|
|
+
|
|
|
+const themeStore = useThemeStore()
|
|
|
+const props = defineProps({
|
|
|
+ BarData: Object,
|
|
|
+ barHeight: Object,
|
|
|
+ isRevenue: Boolean,
|
|
|
+ RevenueStartDate: String,
|
|
|
+ RevenueEndDate: String
|
|
|
+})
|
|
|
+const bar_data = ref(props.BarData)
|
|
|
+const bar_ref = ref()
|
|
|
+watch(
|
|
|
+ () => bar_data.value,
|
|
|
+ (current) => {
|
|
|
+ bar_data.value = current
|
|
|
+ initOption.xAxis.data = barName.value
|
|
|
+ initOption.series = bar_series.value
|
|
|
+ initOption.legend.data = Name.value
|
|
|
+ initOption.toolbox.feature.saveAsImage.name = downloadName.value
|
|
|
+ initOption.toolbox.show = isShowTooltips.value
|
|
|
+ initOption.yAxis.max = Max.value
|
|
|
+ initOption.yAxis.interval = interval.value
|
|
|
+ initOption.title.text = bar_title.value
|
|
|
+ initChart()
|
|
|
+ },
|
|
|
+ {
|
|
|
+ deep: true,
|
|
|
+ once: true
|
|
|
+ }
|
|
|
+)
|
|
|
+// 最大值
|
|
|
+const Max = computed(() => {
|
|
|
+ return bar_data.value?.Max
|
|
|
+})
|
|
|
+// 刻度
|
|
|
+const interval = computed(() => {
|
|
|
+ return bar_data.value?.interval
|
|
|
+})
|
|
|
+// x轴值
|
|
|
+const barName = computed(() => {
|
|
|
+ return bar_data.value?.barList
|
|
|
+})
|
|
|
+// title
|
|
|
+const bar_title = computed(() => {
|
|
|
+ return bar_data.value?.bar_title
|
|
|
+})
|
|
|
+// series
|
|
|
+const bar_series = computed(() => {
|
|
|
+ return bar_data.value?.barSeries
|
|
|
+})
|
|
|
+// legend标题
|
|
|
+const Name = computed(() => {
|
|
|
+ if (bar_data.value?.barSeries) {
|
|
|
+ return bar_data.value?.barSeries.map((item: any) => {
|
|
|
+ return item.name
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+})
|
|
|
+const downloadName = computed(() => {
|
|
|
+ return bar_data.value?.download_name
|
|
|
+})
|
|
|
+const isShowTooltips = computed(() => {
|
|
|
+ return bar_data.value?.isShowTooltips
|
|
|
+})
|
|
|
+const exportData = ({ filename }: any) => {
|
|
|
+ $api
|
|
|
+ .RevenueDownload({
|
|
|
+ date_start: props.RevenueStartDate,
|
|
|
+ date_end: props.RevenueEndDate
|
|
|
+ })
|
|
|
+ .then((res: any) => {
|
|
|
+ if (res.code === 200) {
|
|
|
+ let header: any = []
|
|
|
+ let data: any = []
|
|
|
+ let sheetname: any = []
|
|
|
+ let filterA = res.data.r2_cloumn.map((el: any) => {
|
|
|
+ return el.dataIndex
|
|
|
+ })
|
|
|
+ let titleA = res.data.r2_cloumn.map((el: any) => {
|
|
|
+ return el.title
|
|
|
+ })
|
|
|
+ let filterB = res.data.r3_cloumn.map((el: any) => {
|
|
|
+ return el.dataIndex
|
|
|
+ })
|
|
|
+ let titleB = res.data.r3_cloumn.map((el: any) => {
|
|
|
+ return el.title
|
|
|
+ })
|
|
|
+ let result: any = [
|
|
|
+ {
|
|
|
+ tHeader: titleA,
|
|
|
+ filterVal: filterA,
|
|
|
+ tableDatas: res.data.r2,
|
|
|
+ sheetName: res.data.r2_title
|
|
|
+ },
|
|
|
+ {
|
|
|
+ tHeader: titleB,
|
|
|
+ filterVal: filterB,
|
|
|
+ tableDatas: res.data.r3,
|
|
|
+ sheetName: res.data.r3_title
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ let formatJson = (filterVal: any, jsonData: any) => {
|
|
|
+ return jsonData.map((v: any) => filterVal.map((j: any) => v[j]))
|
|
|
+ }
|
|
|
+ for (var i in result) {
|
|
|
+ header.push(result[i].tHeader)
|
|
|
+ sheetname.push(result[i].sheetName)
|
|
|
+ data.push(formatJson(result[i].filterVal, result[i].tableDatas))
|
|
|
+ }
|
|
|
+ // 将表头插入数据数组中
|
|
|
+ for (let i = 0; i < header.length; i++) {
|
|
|
+ data[i].unshift(header[i])
|
|
|
+ }
|
|
|
+ let ws_name = sheetname
|
|
|
+ // 创建工作簿对象
|
|
|
+ let wb = XLSX.utils.book_new()
|
|
|
+ let ws: any = []
|
|
|
+ // 创建每个工作表并设置列宽
|
|
|
+ for (let j = 0; j < header.length; j++) {
|
|
|
+ ws.push(XLSX.utils.aoa_to_sheet(data[j]))
|
|
|
+ let arr: any = []
|
|
|
+ header[j].forEach((val: any) => {
|
|
|
+ arr.push({
|
|
|
+ wpx: 120
|
|
|
+ })
|
|
|
+ })
|
|
|
+ ws[j]['!cols'] = arr
|
|
|
+ }
|
|
|
+ // 将工作表对象添加到工作簿中
|
|
|
+ for (let k = 0; k < header.length; k++) {
|
|
|
+ wb.SheetNames.push(ws_name[k])
|
|
|
+ wb.Sheets[ws_name[k]] = ws[k]
|
|
|
+ }
|
|
|
+ XLSX.writeFile(wb, filename + '.xlsx') // 导出文件
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .finally(() => {})
|
|
|
+}
|
|
|
+
|
|
|
+// 数额
|
|
|
+const initOption = reactive({
|
|
|
+ //标题
|
|
|
+ title: {
|
|
|
+ text: bar_title.value || 'Total:', //主标题
|
|
|
+ left: 19,
|
|
|
+ top: 9.5,
|
|
|
+ textStyle: {
|
|
|
+ color: '#2B2F36',
|
|
|
+ fontWeight: '700',
|
|
|
+ fontFamily: 'Lato-Light',
|
|
|
+ fontSize: '14px'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 间距
|
|
|
+ grid: {
|
|
|
+ top: '18%',
|
|
|
+ left: '1%',
|
|
|
+ right: '2%',
|
|
|
+ bottom: '5%',
|
|
|
+ containLabel: true // 距离包含坐标轴上的文字
|
|
|
+ },
|
|
|
+ // hover时的文字显示
|
|
|
+ tooltip: {
|
|
|
+ show: true,
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: {
|
|
|
+ type: 'shadow'
|
|
|
+ },
|
|
|
+ backgroundColor: '#2b2f36',
|
|
|
+ borderColor: '#2b2f36',
|
|
|
+ formatter: function (params: any) {
|
|
|
+ let str: any = ''
|
|
|
+ let allnum: any = 0
|
|
|
+ str += '<div style= ' + 'color:#FFF;font-family: Lato-Light>' + params[0].name + '</div>'
|
|
|
+ params.forEach((item: any) => {
|
|
|
+ allnum += item.value
|
|
|
+ allnum = Number(allnum.toFixed(2))
|
|
|
+ str +=
|
|
|
+ '<div style= ' +
|
|
|
+ 'color:#FFF>' +
|
|
|
+ item.marker +
|
|
|
+ item.seriesName +
|
|
|
+ ': ' +
|
|
|
+ item.value +
|
|
|
+ '</div>'
|
|
|
+ })
|
|
|
+ allnum = allnum.toFixed(2)
|
|
|
+ str += '<div style= ' + 'color:#FFF;font-family: Lato-Light>Total: ' + allnum + '</div>'
|
|
|
+ return str
|
|
|
+ },
|
|
|
+ textStyle: {
|
|
|
+ color: '#FFF',
|
|
|
+ fontWeight: 700,
|
|
|
+ fontFamily: 'Lato-Light',
|
|
|
+ fontSize: '14px'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ data: barName.value,
|
|
|
+ axisTick: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: '#eaebed'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ axisLabel: {
|
|
|
+ interval: 0,
|
|
|
+ fontFamily: 'Lato-Light',
|
|
|
+ color: '#B5B9BF'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ scale: true,
|
|
|
+ splitLine: {
|
|
|
+ show: true,
|
|
|
+ lineStyle: {
|
|
|
+ type: 'dashed',
|
|
|
+ color: '#eaebed'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ show: true,
|
|
|
+ lineStyle: {
|
|
|
+ color: '#eaebed'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ axisLabel: {
|
|
|
+ fontFamily: 'Lato-Light',
|
|
|
+ color: '#B5B9BF'
|
|
|
+ },
|
|
|
+ min: 0, // 最小值
|
|
|
+ max: Max.value, // 最大值
|
|
|
+ interval: interval.value // 刻度
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ data: Name.value,
|
|
|
+ top: '3%',
|
|
|
+ itemGap: 30,
|
|
|
+ left: '40%',
|
|
|
+ itemHeight: 8, //修改icon图形大小
|
|
|
+ itemWidth: 8, //修改icon图形大小
|
|
|
+ textStyle: {
|
|
|
+ fontSize: 12,
|
|
|
+ fontFamily: 'Lato-Light',
|
|
|
+ color: '#646A73'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ series: bar_series.value,
|
|
|
+ toolbox: {
|
|
|
+ iconStyle: {
|
|
|
+ borderColor: '#2B2F36'
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ iconStyle: {
|
|
|
+ borderColor: '#ff7500'
|
|
|
+ } // hover上去时的颜色
|
|
|
+ },
|
|
|
+ itemSize: 25,
|
|
|
+ show: isShowTooltips.value, // 显示工具箱
|
|
|
+ feature: {
|
|
|
+ saveAsImage: { show: false, name: downloadName.value },
|
|
|
+ myTool1: {
|
|
|
+ show: true,
|
|
|
+ title: 'update',
|
|
|
+ icon: 'image://' + updateIcon,
|
|
|
+ onclick: function () {
|
|
|
+ let filename = 'Revenue Spent Details ' + barName.value[0] + '-' + barName.value[1]
|
|
|
+ exportData({ filename: filename })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ showTitle: false
|
|
|
+ }
|
|
|
+})
|
|
|
+onMounted(() => {
|
|
|
+ initChart()
|
|
|
+ watch(
|
|
|
+ () => themeStore.theme,
|
|
|
+ (newVal) => {
|
|
|
+ if (newVal === 'dark') {
|
|
|
+ initOption.xAxis.axisLine.lineStyle.color = '#3F434A'
|
|
|
+ initOption.yAxis.axisLine.lineStyle.color = '#3F434A'
|
|
|
+ initOption.yAxis.splitLine.lineStyle.color = '#3F434A'
|
|
|
+ initChart()
|
|
|
+ } else {
|
|
|
+ initOption.xAxis.axisLine.lineStyle.color = '#eaebed'
|
|
|
+ initOption.yAxis.axisLine.lineStyle.color = '#eaebed'
|
|
|
+ initOption.yAxis.splitLine.lineStyle.color = '#eaebed'
|
|
|
+ initChart()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ immediate: true,
|
|
|
+ deep: true
|
|
|
+ }
|
|
|
+ )
|
|
|
+})
|
|
|
+
|
|
|
+const initChart = () => {
|
|
|
+ const bar_chart = echarts.init(bar_ref.value)
|
|
|
+ //图表响应式
|
|
|
+ window.addEventListener('resize', () => {
|
|
|
+ bar_chart.resize()
|
|
|
+ })
|
|
|
+ bar_chart.on('legendselectchanged', function (event: any) {
|
|
|
+ const selected = event.selected
|
|
|
+ let trueCount = 0
|
|
|
+ let trueObj: any = {}
|
|
|
+ let truearr: any = []
|
|
|
+ for (var key in selected) {
|
|
|
+ if (selected[key]) {
|
|
|
+ trueCount++
|
|
|
+ trueObj[key] = selected[key]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (trueCount == 1) {
|
|
|
+ initOption.series.forEach((item: any, index: any) => {
|
|
|
+ if (item.name == Object.keys(trueObj)) {
|
|
|
+ initOption.series[index].label.show = true
|
|
|
+ initOption.title.text = `Total: ${initOption.series[index].total}`
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ initOption.series.forEach((item: any, index: any) => {
|
|
|
+ initOption.series[index].label.show = false
|
|
|
+ initOption.title.text = `Total: `
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if (trueCount != 0) {
|
|
|
+ initOption.series.forEach((item: any) => {
|
|
|
+ if (Object.keys(trueObj).includes(item.name)) {
|
|
|
+ truearr.push(item)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ const max = Math.max.apply(
|
|
|
+ Math,
|
|
|
+ truearr.map((ele: any) => {
|
|
|
+ return ele.Max
|
|
|
+ })
|
|
|
+ )
|
|
|
+ const interval = Math.max.apply(
|
|
|
+ Math,
|
|
|
+ truearr.map((ele: any) => {
|
|
|
+ return ele.interval
|
|
|
+ })
|
|
|
+ )
|
|
|
+ initOption.yAxis.max = max
|
|
|
+ initOption.yAxis.interval = interval
|
|
|
+ }
|
|
|
+ bar_chart.setOption(initOption)
|
|
|
+ })
|
|
|
+ bar_chart.setOption(initOption)
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="com-container">
|
|
|
+ <div ref="bar_ref" id="bar_chart" :style="props.barHeight"></div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.com-container {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+#bar_chart {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+</style>
|