echarts总结

<template>
    <EWrap id='page-wrap' class="b-screen" :options="{width: 1920, height: 1080}">
        <!-- <RightMenu></RightMenu> -->
        <TopHeaderB></TopHeaderB>
        <div class="content">
            <div class="left">
                <section class="section-item">
                    <h5 class="title">电商数据&nbsp;&nbsp;<span class="subTitle">Sell Data</span></h5>
                    <div class="title-line">
                        <h6 class="s-title">
                            销售量
                        </h6>
                        <div class="unit">万元</div>
                    </div>
                    <counter :value='sellData'></counter>
                </section>
                <section class="section-item">
                    <div class="title-line">完成百分比</div>
                    <EProgress :chartData="progressData"></EProgress>
                </section>
                <section class="section-item">
                    <h5 class="title">热搜关键词&nbsp;&nbsp;<span class="subTitle">Top Search</span></h5>
                    <EWorlds class="worlds-block" :chartData="worldData" height="400px"></EWorlds>
                </section>
            </div>
            <div class="middle">
                <section class="section-item">
                    <h5 class="title">订单实时走势&nbsp;&nbsp;<span class="subTitle">Order curve</span></h5>
                    <e-bar-multiple :chartData="barData" width="800px" height="380px"></e-bar-multiple>
                </section>
                <section class="section-item section-flex">
                    <div class="flex-item flex-left">
                        <h5 class="title">销售区域Top&nbsp;&nbsp;</h5>
                        <EPointMul width="400px"></EPointMul>
                    </div>
                    <div class="flex-item flex-left">
                        <h5 class="title">购买终端&nbsp;&nbsp;</h5>
                        <ENightingale width="400px" :chartData="nightingaleChartData"></ENightingale>
                    </div>
                </section>
            </div>
            <div class="right">
                <section class="section-item">
                    <h5 class="title">统计数据&nbsp;&nbsp;<span class="subTitle">Statistics Data</span></h5>
                    <div class="block-wrap">
                        <EBlockData v-for="(item, index) in blockData" :key="index" :data="item"></EBlockData>
                    </div>
                </section>
                <section class="section-item">
                    <h5 class="title">大额订单Top&nbsp;&nbsp;<span class="subTitle">Super Orders</span></h5>
                    <ETable :data="tableData"></ETable>
                </section>
            </div>
        </div>
    </EWrap>
</template>

<script>
import * as echarts from 'echarts/core';

import EWrap from '../components/global/wrap.vue';
import TopHeaderB from '../components/topHeaderBaidu.vue';
import counter from '../components/global/counter.vue';
import EProgress from '../components/echarts/progress.vue';
import EWorlds from '../components/echarts/worldCloud.vue';
import EBlockData from '../components/simple/block_data.vue';
import ETable from '../components/simple/table.vue';
import EBarMultiple from '../components/echarts/bar_multile.vue';
import EPointMul from '../components/map/point-multuple.vue';
import ENightingale from '../components/echarts/nightingale.vue';

// import RightMenu from '../plugins/RightMenu/index.vue';
 
// import { parseTime } from '../utils/index';
export default {
    components: {
        EWrap,
        TopHeaderB,
        counter,
        EProgress,
        EWorlds,
        EBlockData,
        ETable,
        EBarMultiple,
        EPointMul,
        ENightingale,
        // RightMenu
    },
    setup() {
        const sellData = '1201077.9';
        const progressData = {
            val: 3000,
            total: 4000
        }
        const worldData = {
            data: [{ value: '7400', name: '韩衣都舍' },
            { value: '11638', name: '欧莱雅' },
            { value: '15000', name: '华为P20' },
            { value: '6055', name: '天生要强' },
            { value: '19655', name: 'iPhone X' },
            { value: '5065', name: '梅西' },
            { value: '5500', name: '良品铺子' },
            { value: '7630', name: 'MacBook Air ' },
            { value: '18341', name: 'Mac Pro' },
            { value: '11340', name: '小米手机' },
            { value: '11680', name: '玛莎拉蒂' },
            { value: '9900', name: '特斯拉' },]
        }
        const blockData = [
            {
                img: require('../assets/baidu/pic-4.png'),
                value: '42.3',
                info: '订单总数(万)'
            },
            {
                img: require('../assets/baidu/pic-4.png'),
                value: '42.3',
                info: '订单总数(万)'
            },
            {
                img: require('../assets/baidu/pic-4.png'),
                value: '42.3',
                info: '订单总数(万)'
            },
            {
                img: require('../assets/baidu/pic-4.png'),
                value: '42.3',
                info: '订单总数(万)'
            }
        ]

        const tableData = {
            header: ['时间','物品','数量','金额',],
            data: [
                ['05-05 07:05:58', '物品', 65, 987.654],
                ['05-05 07:06:58', '物品', 65, 987.654],
                ['05-05 07:07:58', '物品', 65, 987.654],
                ['05-05 07:08:58', '物品', 65, 987.654],
                ['05-05 07:09:58', '物品', 65, 987.654],
                ['05-05 07:10:58', '物品', 65, 987.654],
                ['05-05 07:11:58', '物品', 65, 987.654],
                ['05-05 07:12:58', '物品', 65, 987.654],
                ['05-05 07:13:58', '物品', 65, 987.654],
                ['05-05 07:14:58', '物品', 65, 987.654],
                ['05-05 07:15:58', '物品', 65, 987.654],
                ['05-05 07:16:58', '物品', 65, 987.654],
                ['05-05 07:17:58', '物品', 65, 987.654],
                ['05-05 07:18:58', '物品', 65, 987.654],
            ]
        }

        var xAxisData = [];
        var data1 = [];
        var data2 = [];
        for (var i = 0; i < 100; i++) {
            const timeStep = Date.now() - 2*60*60*1000 + 60*1000*i;
            data1.push([timeStep, parseInt(Math.abs((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5))]);
            data2.push([timeStep, parseInt(Math.abs((Math.cos(i / 5) * (i / 5 - 10) + i / 6) * 5))]);
        }

        const barData = {
            title: '',
            xData: xAxisData,
            series: [
                {
                    name: '新增订单数',
                    type: 'bar',
                    data: data1,
                    // color: '#24caff',
                    emphasis: {
                        focus: 'series'
                    },
                    itemStyle: {
                            color: new echarts.graphic.LinearGradient(
                                0, 0, 0, 1,
                                [              //柱图渐变色
                                    { offset: 0, color: 'lightblue' }, 
                                    { offset: 1, color: '#24caff' },
                                ]
                            ),
                        },
                    
                },
                {
                    name: '退单数',
                    type: 'bar',
                    data: data2,
                    color: '#9200ff',
                    emphasis: {
                        focus: 'series'
                    }
                }
            ],
        }

        const nightingaleColors = [
            [              //柱图渐变色
                'lightblue' , 
                '#24caff' ,
            ],
            [              //柱图渐变色
                '#9000ff' , 
                '#2e33d1' ,
            ],
            [              //柱图渐变色
                '#701d8d' , 
                '#2e33d1' ,
            ],
            [              //柱图渐变色
                '#4549d4' , 
                '#2e33d1' ,
            ]

        ]

        const nightingaleData = [
            { value: 354942, name: 'PC Web', },
        { value: 289594, name: 'IOS' , },
        { value: 152363, name: 'Android',},
        { value: 78291, name: 'Wap Web',}
        ]

        const nightingaleDatas = nightingaleData.map((item, index) => {
            const itemColors = nightingaleColors[index];
            item.label = {
                color: itemColors[1]
            }
            item.itemStyle = {
                    color: new echarts.graphic.LinearGradient(
                        0, 0, 0, 1,
                        [              //柱图渐变色
                            { offset: 0, color: itemColors[0] }, 
                            { offset: 1, color: itemColors[1] },
                        ]
                    ),
                
            }
            return item
        })

        const nightingaleChartData = {
            data: nightingaleDatas,
            name: '终端销售数据'
        }

        console.log(nightingaleChartData)

        return {
            sellData,
            progressData,
            worldData,
            blockData,
            tableData,
            barData,
            nightingaleChartData
        }
    }
}
</script>

<style lang='less'>
html, body, * {
    padding: 0;
    margin: 0;
    overflow: hidden;
}
.b-screen {
    overflow: hidden;
    background: url('../assets/baidu/background-2.png') -20px 0% / 100% 100%;
    display: flex;
    flex-direction: column;
    .content {
        flex: 1;
        display: flex;
        .left, .right {
            width: 478px;
            // background-color: red;
        }
        .left {
            margin-left: 43px;
        }
        .right {
            margin-right: 43px;
        }
        .middle { 
            flex: 1;
            margin: 0 43px;
            .section-item {
                width: 100%;
                // 
                &.section-flex {
                    display: flex;
                    align-items: center;
                    .flex-item {
                        flex: 1;
                    }
                }
            }

        }
        .right {
            .section-item {
                margin-bottom: 20px;
            }
            .table {
                margin-top: 15px;
            }
        }
        .section-item {
            color: rgb(154, 168, 212);
            margin-bottom: 36px;
            .title {
                font-weight: normal;
                font-size: 22px;
                height: 60px;
                line-height: 60px;
            }
            .subTitle{
                color: rgb(64, 77, 105);
            }
            .title-line{
                height: 36px;
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 6px;
                h6 {
                    font-size: 16px;
                }
                .unit {
                    color: rgb(115, 170, 229);
                    font-size: 18px;
                }
            }
        }
        
        .section-item {
            // 词云
            .worlds-block {
                margin-top: 30px;
                background: rgba(255, 255, 255, 0.05);
                border-radius: 4px;
            }
            // 统计数据
            .block-wrap {
                display: flex;
                flex-wrap: wrap;
                margin-top: 20px;
                .block-data {
                    flex: 1 1 50%;
                    margin: 12px 0;
                }
            }
        }
    }
}
</style>

          

<template>
    <div class='e-wrap' :ref='refName'>
        <!-- <template v-if="ready"> -->
            <slot></slot>
        <!-- </template> -->
    </div>
</template>
<script>
import { nextTick, onMounted, onUnmounted, ref } from 'vue';
import { debounce } from '../../utils';
export default {
    name: 'EWrap',
    props: {
        options: Object
    },
    emits: ['ready'],
    setup(props, context) {
        let $refName;
        let dom;
        const refName = (el) => {
            $refName = el;
            dom = el.cloneNode();
        };
        nextTick(() => {
            console.dir($refName);
        });

        const width = ref(0);
        const height = ref(0);
        const originalWidth = ref(0);
        const originalHeight = ref(0);
        const ready = ref(false);
        const clientWidth = ref(0);
        const clientHeight = ref(0);

        const initSize = () => {
            return new Promise((resolve) => {
                nextTick(() => {
                    // 获取大屏的真实尺寸
                    if (props.options && props.options.width && props.options.height) {
                        width.value = props.options.width
                        height.value = props.options.height
                    } else {
                        width.value = $refName.clientWidth
                        height.value = $refName.clientHeight
                    }
                    // 获取画布尺寸
                    if (!originalWidth.value || !originalHeight.value) {
                        originalWidth.value = window.screen.width
                        originalHeight.value = window.screen.height
                    }

                    clientWidth.value = document.body.clientWidth;
                    clientHeight.value = document.body.clientHeight;

                    console.log(width.value, height.value, originalWidth.value, originalHeight.value, document.body.offsetWidth, document.body.clientHeight)
                    resolve('');
                })
            })
        }

      const updateSize = () => {
        if (width.value && height.value) {
          $refName.style.width = `${width.value}px`
          $refName.style.height = `${height.value}px`
        } else {
          $refName.style.width = `${originalWidth.value}px`
          $refName.style.height = `${originalHeight.value}px`
        }
      }

      const updateScale = () => {
        // 获取真实的视口尺寸
          const currentWidth = document.body.clientWidth
          const currentHeight = document.body.clientHeight
          // 获取大屏最终的宽高
          const realWidth = width.value || originalWidth.value
          const realHeight = height.value || originalHeight.value
          // console.log(currentWidth, currentHeight)
          const widthScale = currentWidth / realWidth
          const heightScale = currentHeight / realHeight
          // console.log(widthScale, heightScale, realWidth, realHeight, currentWidth, currentHeight)
          
            // console.log(widthScale, heightScale, realWidth, realHeight, clientWidth.value, clientHeight.value, document.body.offsetWidth, document.body.clientHeight)
          $refName && ($refName.style.transform = `scale(${widthScale}, ${heightScale})`)
      }

      const onResize = async () => {
        await initSize()
        updateScale()
      }

      let observer;
      const initMutationObserver = () => {
        const MutationObserver = window.MutationObserver
        observer = new MutationObserver(onResize)
        observer.observe(dom, {
          attributes: true,
          attributeFilter: ['style'],
          attributeOldValue: true
        })
      }

      const removeMutationObserver = () => {
        if (observer) {
          observer.disconnect()
          observer.takeRecords()
          observer = null
        }
      }

      onMounted(async () => {
        ready.value = false
        await initSize()
        updateSize()
        updateScale()
        window.addEventListener('resize', debounce(onResize, 100, true))
        initMutationObserver()
        ready.value = true;
        context.emit('ready');
      })

      onUnmounted(() => {
        window.removeEventListener('resize', onResize)
        removeMutationObserver()
      })


        return {
            refName,
            ready,

        }
    }
};
</script>
<style lang='less'>
.e-wrap{
    position: absolute;
    z-index: 100;
    left: 0;
    top: 0;
    overflow: hidden;
    transform-origin: left top;
    z-index: 999;
}
</style>

  

/* eslint-disable */
/**
 * Created by PanJiaChen on 16/11/18.
 */


export const getDate = (time) => {
  let date
  if (typeof time === 'object') {
    date = new Date(time.toString())
  } else {
    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
      time = parseInt(time)
    }
    if ((typeof time === 'number') && (time.toString().length === 10)) {
      time = time * 1000
    }
    date = new Date(time)
  }
  return date
}

/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string}
 */
export function parseTime(time, cFormat) {
  if (arguments.length === 0) {
    return ''
  }
  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    date = new Date(time.toString())
  } else {
    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
      time = parseInt(time)
    }
    if ((typeof time === 'number') && (time.toString().length === 10)) {
      time = time * 1000
    }
    date = new Date(time)
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  const timeStr = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
    let value = formatObj[key]
    // Note: getDay() returns 0 on Sunday
    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
    if (result.length > 0 && value < 10) {
      value = '0' + value
    }
    return value || 0
  })
  return timeStr
}

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
  if (('' + time).length === 10) {
    time = time * 1000
  } else {
    time = +time
  }
  const d = new Date(time)
  const now = Date.now()

  const diff = (now - d.getTime()) / 1000

  if (diff < 30) {
    return '刚刚'
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + '分钟前'
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + '小时前'
  } else if (diff < 3600 * 24 * 2) {
    return '1天前'
  }
  if (option) {
    return parseTime(time, option)
  } else {
    return (
      d.getMonth() +
      1 +
      '月' +
      d.getDate() +
      '日' +
      d.getHours() +
      '时' +
      d.getMinutes() +
      '分'
    )
  }
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url) {
  url = url == null ? window.location.href : url
  const search = url.substring(url.lastIndexOf('?') + 1)
  const obj = {}
  const reg = /([^?&=]+)=([^?&=]*)/g
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1)
    let val = decodeURIComponent($2)
    val = String(val)
    obj[name] = val
    return rs
  })
  return obj
}

/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str) {
  // returns the byte length of an utf8 string
  let s = str.length
  for (let i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i)
    if (code > 0x7f && code <= 0x7ff) s++
    else if (code > 0x7ff && code <= 0xffff) s += 2
    if (code >= 0xDC00 && code <= 0xDFFF) i--
  }
  return s
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual) {
  const newArray = []
  for (let i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i])
    }
  }
  return newArray
}

/**
 * @param {Object} json
 * @returns {Array}
 */
export function param(json) {
  if (!json) return ''
  return cleanArray(
    Object.keys(json).map(key => {
      if (json[key] === undefined) return ''
      return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
    })
  ).join('&')
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = url.split('?')[1]
  if (!search) {
    return {}
  }
  return JSON.parse(
    '{"' +
      decodeURIComponent(search)
        .replace(/"/g, '\\"')
        .replace(/&/g, '","')
        .replace(/=/g, '":"')
        .replace(/\+/g, ' ') +
      '"}'
  )
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
  const div = document.createElement('div')
  div.innerHTML = val
  return div.textContent || div.innerText
}

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target, source) {
  if (typeof target !== 'object') {
    target = {}
  }
  if (Array.isArray(source)) {
    return source.slice()
  }
  Object.keys(source).forEach(property => {
    const sourceProperty = source[property]
    if (typeof sourceProperty === 'object') {
      target[property] = objectMerge(target[property], sourceProperty)
    } else {
      target[property] = sourceProperty
    }
  })
  return target
}

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element, className) {
  if (!element || !className) {
    return
  }
  let classString = element.className
  const nameIndex = classString.indexOf(className)
  if (nameIndex === -1) {
    classString += '' + className
  } else {
    classString =
      classString.substr(0, nameIndex) +
      classString.substr(nameIndex + className.length)
  }
  element.className = classString
}

/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type) {
  if (type === 'start') {
    return new Date().getTime() - 3600 * 1000 * 24 * 90
  } else {
    return new Date(new Date().toDateString())
  }
}

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args , context , timestamp, result

  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = ''
      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function(...args) {
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在,重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
  if (!source && typeof source !== 'object') {
    throw new Error('error arguments, deepClone')
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = deepClone(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr))
}

/**
 * @returns {string}
 */
export function createUniqueString() {
  const timestamp = +new Date() + ''
  const randomNum = parseInt(((1 + Math.random()) * 65536) + '') + ''
  return (+(randomNum + timestamp)).toString(32)
}

/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele, cls) {
  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
}

/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function addClass(ele, cls) {
  if (!hasClass(ele, cls)) ele.className += ' ' + cls
}

/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
    ele.className = ele.className.replace(reg, ' ')
  }
}
/*
 * @Author: your name
 * @Date: 2022-04-27 17:11:44
 * @LastEditTime: 2022-04-27 17:22:45
 * @LastEditors: Please set LastEditors
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: \youcai-pc\youcai-admin\src\utils\echarts.ts
 */
import { saveAs } from 'file-saver'
import { utils, write } from 'xlsx'
import html2canvas from 'html2canvas'
// 显示当前时间
export const timeFormate = (timeStamp) => {
    const year = new Date(timeStamp).getFullYear();
    const month =
      new Date(timeStamp).getMonth() + 1 < 10
        ? "0" + (new Date(timeStamp).getMonth() + 1)
        : new Date(timeStamp).getMonth() + 1;
    const date =
      new Date(timeStamp).getDate() < 10
        ? "0" + new Date(timeStamp).getDate()
        : new Date(timeStamp).getDate();
    const hh =
      new Date(timeStamp).getHours() < 10
        ? "0" + new Date(timeStamp).getHours()
        : new Date(timeStamp).getHours();
    const mm =
      new Date(timeStamp).getMinutes() < 10
        ? "0" + new Date(timeStamp).getMinutes()
        : new Date(timeStamp).getMinutes();
    const ss =
      new Date(timeStamp).getSeconds() < 10
        ? "0" + new Date(timeStamp).getSeconds()
        : new Date(timeStamp).getSeconds();
    const week = new Date(timeStamp).getDay();
    const weeks = ["日", "一", "二", "三", "四", "五", "六"];
    const getWeek = "星期" + weeks[week];
    return   year +
      "年" +
      month +
      "月" +
      date +
      "日" +
      " " +
      hh +
      ":" +
      mm +
      ":" +
      ss +
      getWeek;
}

export const parseTime = (time, cFormat = '{y}-{m}-{d} {h}:{i}:{s}') => {
 const format = cFormat
 let date
 if (typeof time === 'object') {
   date = new Date(time.toString())
 } else {
   if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
     time = parseInt(time)
   }
   if ((typeof time === 'number') && (time.toString().length === 10)) {
     time = time * 1000
   }
   date = new Date(time)
 }
 const formatObj = {
   y: date.getFullYear(),
   m: date.getMonth() + 1,
   d: date.getDate(),
   h: date.getHours(),
   i: date.getMinutes(),
   s: date.getSeconds(),
   a: date.getDay()
 }
 const timeStr = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
   let value = formatObj[key]
   // Note: getDay() returns 0 on Sunday
   if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
   if (result.length > 0 && value < 10) {
     value = '0' + value
   }
   return value || 0
 })
 return timeStr
}

// 下载图表图片
export const downImage = (chart, chartName = 'downChartImage') => {
  const url = chart.getDataURL({
    // 导出的格式,可选 png, jpg, svg
    // 注意:png, jpg 只有在 canvas 渲染器的时候可使用,svg 只有在使用 svg 渲染器的时候可用
    type: 'png',
    // 导出的图片分辨率比例,默认为 1。
    pixelRatio: 1,
    // 导出的图片背景色,默认使用 option 里的 backgroundColor
    backgroundColor: '#fff',
    // 忽略组件的列表,例如要忽略 toolbox 就是 ['toolbox']
    // excludeComponents?: Array.<string>
  })

  saveAs(url, chartName + '.png')

  // const a = document.createElement('a');
  // const event = new MouseEvent('click');
  // a.download = chartName;
  // a.href = url;
  // a.dispatchEvent(event);
}

// 导出数据为Excel
export const exportChart = (chart, chartName = 'exportChartData', type  = type) => {
  let $table = document.getElementById('chart-data-export')
  if (!$table) {
    $table = document.createElement('table');
    $table.setAttribute('id', 'chart-data-export')
  }
  console.log(chart._model, chart, 'ccc')
  if (!chart._model) {
    console.log('null')
    return
  }
  const series = chart._model.option.series;

  const len = series[0].data.length;

  // header
  let bodyInner = '<tr>' + '<td>X轴</td>'

  for(let i = 0; i < series.length; i++) {
    bodyInner += '<td>'+ series[i].name +'</td>';
  }

  bodyInner += '</tr>';

  // body

  for(let i = 0; i < len; i++) {
    let line = '<tr>'
    for(let j = 0; j < series.length; j++) {
      const start = j == 0 ? 0 : 1;
      for(let k = start; k < series[0].data[0].length; k++) {
        line += '<td>' + series[j].data[i][k] + '</td>'
      }
    }
    line += '</tr>'
    bodyInner += line;
  }

  const $tbody =  '<tbody>' + bodyInner + '</tbody>';
  
  $table.innerHTML = $tbody;

  document.body.append($table);

  const chart2Excel = utils.table_to_book($table);

  const chart2ExcelData = write(chart2Excel, {
    bookType: type,
    type: 'binary'
  })
  saveAs(
    new Blob([s2ab(chart2ExcelData)], {
      type: "application/octet-stream"
    }),
      chartName +  "." + type
    );
  
}

const s2ab = (s) => {
	var cuf;
	var i;
	if (typeof ArrayBuffer !== "undefined") {
	cuf = new ArrayBuffer(s.length);
	var view = new Uint8Array(cuf);
	for (i = 0; i !== s.length; i++) {
		view[i] = s.charCodeAt(i) & 0xff;
	}
	return cuf;
	} else {
	cuf = new Array(s.length);
	for (i = 0; i !== s.length; ++i) {
		cuf[i] = s.charCodeAt(i) & 'oxFF';
	}
	return cuf;
	}
}

// 截屏整个页面

export const exportPage = (id = 'page-wrap') => {
  const $page = document.getElementById(id)
  console.log('$page', $page)
  html2canvas($page, {useCORS:true}).then(function (canvas) {
    //获取年月日作为文件名
    var timers=new Date();
    var fullYear=timers.getFullYear();
    var month=timers.getMonth()+1;
    var date=timers.getDate();
    var randoms=Math.random()+'';
    //年月日加上随机数
    var numberFileName=fullYear+''+month+date+randoms.slice(3,10);
    var imgData=canvas.toDataURL();

    saveAs(imgData, numberFileName + '.png')
    // //保存图片
    // var saveFile = function(data, filename){
    //     var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
    //     save_link.href = data;
    //     save_link.download = filename;

    //     var event = document.createEvent('MouseEvents');
    //     event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    //     save_link.dispatchEvent(event);
    // };
    // //最终文件名+文件格式
    // var filename = numberFileName + '.png';
    // saveFile(imgData,filename);
    //document.body.appendChild(canvas);  把截的图显示在网页上
})
}

<!--
 * @Author: your name
 * @Date: 2022-04-27 17:13:30
 * @LastEditTime: 2022-04-27 17:46:10
 * @LastEditors: Please set LastEditors
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: \youcai-pc\youcai-admin\src\views\Statistic\components\topHeader.vue
-->
<template>
    <div class="header">
        <h3>电商大数据</h3>
        <span class="now-time">{{timeStr}}</span>
        <div class="head-bg"></div>
    </div>
</template>
<script>
import { onMounted, onUnmounted, ref } from 'vue';
import { parseTime } from '../utils/echarts';
export default {
    name: 'TopHeaderB',
    setup() {
        const timeStr = ref('');
        let timer = 0;

        const clear = () => {
            clearInterval(timer);
            timeStr.value = '';
        }

        const showTimes = () => {
            timeStr.value = parseTime(Date.now());
            
            timer = window.setInterval(() => {
                // clear();
                timeStr.value = parseTime(Date.now());
                // console.log(timeStr.value)
            }, 1000);
        }

        onMounted(() => {
            showTimes();
        })

        onUnmounted(() => {
            clear();
        })

        return {
            timeStr
        }
    }
};
</script>
<style lang='less'>
.header {
    width: 100%;
    height: 146px;
    position: relative;
    .logo{
        width: 120px;
        height: 120px;
    }
    h3 {
        height: 110px;
        line-height: 110px;
        font-family: "Microsoft Yahei", Arial, sans-serif;
        font-size: 36px;
        color: rgb(255, 255, 255);
        text-shadow: rgb(255 255 255) 0px 0px 15px;
        font-weight: bold;
        justify-content: center;
        text-align: center;
        margin: 0;
    }
    .now-time{
        position: absolute;
        right: 40px;
        top: 44px;
        font-size: 18px;
        color: #fff;
        display: flex;
        align-items: center;
        padding-bottom: 30px;
    }
    .head-bg {
        background: url('../assets/baidu/pic-2.png');
        width: 1625px;
        height: 146px;
        line-height: 146px;
        // background-image: url(/static/img-templet/pic-2.png);
        opacity: 1;
        margin-left: -812.5px;
        margin-top: -73px;
        transform: rotate(0deg);
        background-size: 100% 100%;
        background-repeat: no-repeat;
        background-position: center center;
        transform-origin: center;
        position: absolute;
        left: 50%;
        top: 50%;
        color: #ccc;
        font-size: 25px;
        text-align: center;
    }
}
</style>
<template>
  <div class="counter">
      <VueCountTo :class="['count-item', !isNaN(item) ? 'isNumber' : 'notNumber']" :startVal='0' v-for="(item, index) in value" :key="item + index" :endVal='getCount(item)'></VueCountTo>
  </div>
</template>

<script>
import VueCountTo from './CountTo/vue-countTo.vue';
export default {
    components: {
        VueCountTo
    },
    props: {
        value: {
            type: String,
            default: '0.0'
        }
    },
    setup() {
        const getCount = (item) => {
            return isNaN(item) ? item : +item;
        }

        return {
            getCount
        }
    }
}
</script>

<style lang='less'>
.counter {
    display: flex;
    justify-content: flex-end;
    .count-item {
        display: inline-block;
        text-align: center;
        margin: 0 3px;
        width: 52px;
        height: 80px;
        line-height: 80px;
        font-size: 62px;
        font-weight: bold;
        color: #fff;
        font-family: "Microsoft Yahei", Arial, sans-serif;
        border-radius: 2px;
        &.isNumber {
            background-color: rgb(15, 57, 107);
        }
        &.notNumber{
            width: 24px;
        }
    }
}
</style>
<!--
 * @Author: jeft
 * @Date: 2021-03-02 17:57:31
 * @LastEditTime: 2022-04-29 11:45:27
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \youcai-pc\youcai-admin\src\components\Echarts\line.vue
-->
<template>
  <div :id='className' :class="className" class="charts-progress" :style="{ height: height, width: width }" />
</template>
<script>
import { nextTick, onMounted, onUnmounted, watch } from "vue";
import * as echarts from 'echarts/core';
import {
    BarChart,
    CustomChart
} from 'echarts/charts';
import {
    TooltipComponent,
    TitleComponent,
    // 组件类型的定义后缀都为 ComponentOption
    GridComponent,

} from 'echarts/components';
import {
    SVGRenderer
} from 'echarts/renderers';
import { UseContextMenuChart } from 'jeft-echarts';

export default {
  name: "EProgress",
  props: {
    className: {
      type: String,
      default: "progress-chart",
    },
    width: {
      type: String,
      default: "100%",
    },
    height: {
      type: String,
      default: "60px",
    },
    chartData: {
      type: Object,
      required: true,
    },
    showTitle: {
      type: Boolean,
      default: true
    },
    barColor: {
      type: String,
      default: '#3888fa'
    }
  },
  setup(props) {
    let chart = null;
    
    // 注册必须的组件
    echarts.use(
        [ TooltipComponent, BarChart, CustomChart, TitleComponent, GridComponent, SVGRenderer ]
    );

    const setOptions = ({val, total}) => {
        console.log(val, total, 'iii')
      chart.setOption({
        grid: {
            left: 0,
            right: 0,
            top: 0,
            bottom: 0
          },
          xAxis: {
            type: 'value',
            show: false,
            max: total
          },
          yAxis: {
            type: 'category',
            show: false
          },
          series: [{
            name: '上月平台用户数',
            type: 'bar',
            // stack: '总量',
            data: [val],
            barWidth: 8,
            label: { //图形上的文本标签
                show: true,
                position: 'right',//标签的位置
                offset: [-20, -20],  //标签文字的偏移,此处表示向上偏移40
                formatter: () => {
                    const pre = parseInt((val / total) * 100) + '%';
                    return pre;
                },//标签内容格式器 {a}-系列名,{b}-数据名,{c}-数据值
                // color: 'rgba(0,0,0,.7)',//标签字体颜色
                fontSize: 16,  //标签字号
                color: '#fff'
            },
            showBackground: true,
              backgroundStyle: {
                borderRadius: 999,
                color: 'rgba(255, 255, 255, 0.25)'
              },
            // roundCap: false,
            // barBorderRadius:[10, 10, 0, 0],
            itemStyle: {
                  borderRadius: 999,
                    color: new echarts.graphic.LinearGradient(
                        0, 0, 1, 0,
                        [
                                               //柱图渐变色
                            { offset: 0, color: 'lightblue' },                   //柱图渐变色
                            { offset: 0.4, color: '#6dcde6' },
                            { offset: 0.8, color: '#337ab7' },
                            { offset: 1, color: 'blue' },
                        ]
                    ),
            }
          }, 
        //   {
        //     name: '今日平台用户数',
        //     type: 'bar',
        //     stack: '总量',
        //     xAxisIndex:1,
        //     data: [4000],
        //     itemStyle: {
        //       color: '#eee'
        //     }
        //   }, 
          {
            type: 'custom',
            stack: '总量',
            data: [3000],
            renderItem: (params, api) => {
              const value = api.value(0)
              const endPoint = api.coord([value, 0])

              return {
                type: 'group',
                position: endPoint,
                children: [
                    
                //     {
                //   type: 'path',
                //   shape: {
                //     d: 'M1024 255.996 511.971 767.909 0 255.996 1024 255.996z',
                //     x: -5,
                //     y: -20,
                //     width: 10,
                //     height: 10,
                //     layout: 'cover'
                //   },
                //   style: {
                //     fill: '#45c946'
                //   }
                // }, 
                {
                  type: 'path',
                  shape: {
                    d: 'M0 767.909l512.029-511.913L1024 767.909 0 767.909z',
                    x: -5,
                    y: 15,
                    width: 10,
                    height: 10,
                    layout: 'cover'
                  },
                  style: {
                    fill: '#fff'
                  }
                }]
              }
            }
          }]
      });
    };
    const initChart = () => {
        if (chart) {
          chart.dispose();
        }
        chart = echarts.init(document.getElementById(props.className));
        setOptions(props.chartData);
        UseContextMenuChart(chart, props.className, echarts)
    };

    watch(() => props.chartData, (newV) => {
        if (!chart) {
          return
        }
        setOptions(newV)
    }, { deep: true, immediate: false });
    
    onUnmounted(() => {
        if (!chart) {
            return
        }
        chart.dispose()
        chart = null
    });
    onMounted(() => {
        nextTick(() => {
            initChart();
        });
    })
    
    return {
      chart
    }
  }
};
</script>
<style lang='less'>
</style>
<!--
 * @Author: jeft
 * @Date: 2021-03-02 17:57:31
 * @LastEditTime: 2022-04-29 11:45:27
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \youcai-pc\youcai-admin\src\components\Echarts\line.vue
-->
<template>
  <div :id='className' :class="className" class="charts-worlds" :style="{ height: height, width: width }" />
</template>
<script>
import { nextTick, onMounted, onUnmounted, watch } from "vue";
import * as echarts from 'echarts/core';
import 'echarts-wordcloud';
import {
    TooltipComponent,
    GridComponent
} from 'echarts/components';
import {
    SVGRenderer
} from 'echarts/renderers';
import { UseContextMenuChart } from 'jeft-echarts';
// import rightMenu from '../global/context-menu.vue';
export default {
  name: "EWorlds",
  // components: {
  //   rightMenu
  // },
  props: {
    className: {
      type: String,
      default: "worlds-chart",
    },
    width: {
      type: String,
      default: "100%",
    },
    height: {
      type: String,
      default: "350px",
    },
    chartData: {
      type: Object,
      required: true,
    },
    showTitle: {
      type: Boolean,
      default: true
    },
    barColor: {
      type: String,
      default: '#3888fa'
    }
  },
  setup(props) {

    let chart = null;
    
    // 注册必须的组件
    echarts.use(
        [ TooltipComponent, GridComponent, SVGRenderer ]
    );

    const colors = ['#5b49c6', '#2d3c98', '#23c4f7', '#23c4f7', '#9000ff', '#701d8d', '#1685f8', '#4549d4', '#2e33d1', '#3f8bd8']

    const setOptions = ({data} ) => {
      chart.setOption({
        tooltip: {
          
        },
        series: [{
        type: 'wordCloud',

        // The shape of the "cloud" to draw. Can be any polar equation represented as a
        // callback function, or a keyword present. Available presents are circle (default),
        // cardioid (apple or heart shape curve, the most known polar equation), diamond (
        // alias of square), triangle-forward, triangle, (alias of triangle-upright, pentagon, and star.

        shape: 'pentagon',

        // Keep aspect ratio of maskImage or 1:1 for shapes
        // This option is supported from echarts-wordcloud@2.1.0
        keepAspect: false,

        // A silhouette image which the white area will be excluded from drawing texts.
        // The shape option will continue to apply as the shape of the cloud to grow.

        // maskImage: maskImage,

        // Folllowing left/top/width/height/right/bottom are used for positioning the word cloud
        // Default to be put in the center and has 75% x 80% size.

        left: '0',
        top: '0',
        width: '100%',
        height: '100%',
        right: null,
        bottom: null,

        // Text size range which the value in data will be mapped to.
        // Default to have minimum 12px and maximum 60px size.

        sizeRange: [12, 60],

        // Text rotation range and step in degree. Text will be rotated randomly in range [-90, 90] by rotationStep 45

        rotationRange: [0, 0],
        rotationStep: 0,

        // size of the grid in pixels for marking the availability of the canvas
        // the larger the grid size, the bigger the gap between words.

        gridSize: 20,

        // set to true to allow word being draw partly outside of the canvas.
        // Allow word bigger than the size of the canvas to be drawn
        drawOutOfBound: false,

        // If perform layout animation.
        // NOTE disable it will lead to UI blocking when there is lots of words.
        layoutAnimation: true,

        // Global text style
        textStyle: {
            fontFamily: 'sans-serif',
            fontWeight: 'bold',
            // Color can be a callback function or a color string
            color: function () {
                // Random color
                return colors[parseInt(Math.random()*10)];
            }
        },
        emphasis: {
            // focus: 'self',

            // textStyle: {
            //     textShadowBlur: 10,
            //     textShadowColor: '#333'
            // }
        },

        // Data is an array. Each array item must have name and value property.
        data
    }]
      });
    };
    const initChart = () => {
        if (chart) {
          chart.dispose();
        }
        chart = echarts.init(document.getElementById(props.className), 'macarons');
        setOptions(props.chartData);
        UseContextMenuChart(chart, props.className, echarts)
        // chart.on('contextmenu', function(params, ) {
        //   // 控制台打印数据的名称
        //   console.log(params);

        //   event.value = params.event;
        //   // event.value.prevent();
        //   visible.value = true;
        //   return false;
        // });
    };

    watch(() => props.chartData, (newV) => {
        if (!chart) {
          return
        }
        setOptions(newV)
    }, { deep: true, immediate: false });
    
    onUnmounted(() => {
        if (!chart) {
            return
        }
        chart.dispose()
        chart = null
    });
    onMounted(() => {
        nextTick(() => {
            initChart();
        });
    })
    
    return {
      chart

    }
  }
};
</script>
<style lang='less'>
</style>
<!--
 * @Author: jeft
 * @Date: 2021-03-02 17:57:31
 * @LastEditTime: 2022-04-29 11:45:27
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \youcai-pc\youcai-admin\src\components\Echarts\line.vue
-->
<template>
  <div :id='className' :class="className" class="charts-nightingale" :style="{ height: height, width: width }" />
</template>
<script>
import { nextTick, onMounted, onUnmounted, watch } from "vue";
import * as echarts from 'echarts/core';
import { ToolboxComponent, LegendComponent } from 'echarts/components';
import { PieChart } from 'echarts/charts';
import { LabelLayout } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
import { UseContextMenuChart } from 'jeft-echarts';

echarts.use([
  ToolboxComponent,
  LegendComponent,
  PieChart,
  CanvasRenderer,
  LabelLayout
]);

export default {
  name: "ENightingale",
  props: {
    className: {
      type: String,
      default: "nightingale-chart",
    },
    width: {
      type: String,
      default: "100%",
    },
    height: {
      type: String,
      default: "350px",
    },
    chartData: {
      type: Object,
      required: true,
    },
    showTitle: {
      type: Boolean,
      default: true
    },
    barColor: {
      type: String,
      default: '#3888fa'
    }
  },
  setup(props) {
    let chart = null;
    
    // 注册必须的组件
    echarts.use(
        [ ToolboxComponent,
  LegendComponent,
  PieChart,
  CanvasRenderer,
  LabelLayout ]
    );

    const setOptions = ({data, name} ) => {
      chart.setOption({
          tooltip: {
            trigger: 'item',
            confine: true,
            axisPointer: {            // 坐标轴指示器,坐标轴触发有效
                type: 'shadow',        // 默认为直线,可选为:'line' | 'shadow'
            },
            textStyle: {
                fontSize: 12,
                color: '#fff'
            },
            extraCssText: 'background:rgba(0, 0, 0, 0.4);color:#fff;border:none;',
            formatter: (params) => {
                let { name , percent, value } = params
                value = (+value).toLocaleString()
                return name + ': ' + percent + '% ' + '(' + value + ')';
            }
        },
        legend: {
            show: false,
    top: 'bottom',
    textStyle: {
        color: []
    }
  },
  label: { formatter: '{b}: {d}%', fontSize: 12},
  series: [
    {
      name,
      type: 'pie',
      radius: [35, 80],
      center: ['45%', '50%'],
    //   roseType: 'area',
      roseType: 'angle',
      data
    }
  ]
      });
    };
    const initChart = () => {
        if (chart) {
          chart.dispose();
        }
        chart = echarts.init(document.getElementById(props.className), 'macarons');
        setOptions(props.chartData);
        UseContextMenuChart(chart, props.className, echarts)
    };

    watch(() => props.chartData, (newV) => {
        if (!chart) {
          return
        }
        setOptions(newV)
    }, { deep: true, immediate: false });
    
    onUnmounted(() => {
        if (!chart) {
            return
        }
        chart.dispose()
        chart = null
    });
    onMounted(() => {
        nextTick(() => {
            initChart();
        });
    })
    
    return {
      chart
    }
  }
};
</script>
<style lang='less'>
</style>

  

<!--
 * @Author: jeft
 * @Date: 2021-03-02 17:57:31
 * @LastEditTime: 2022-04-29 11:45:27
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \youcai-pc\youcai-admin\src\components\Echarts\line.vue
-->
<template>
  <div :id='className' :class="className" class="charts-bar-multiple" :style="{ height: height, width: width }" />
</template>
<script>
import { nextTick, onMounted, onUnmounted, watch } from "vue";
import * as echarts from 'echarts';
import {
    BarChart
} from 'echarts/charts';
import {
    TooltipComponent,
    TitleComponent,
    LegendComponent,
    ToolboxComponent,
    // 组件类型的定义后缀都为 ComponentOption
    GridComponent
} from 'echarts/components';
import {
    CanvasRenderer
} from 'echarts/renderers';
// import { UseContextMenuChart } from '../../plugins/contextmenu/hook';
// import { UseContextMenuChart } from "@/plugins/contextmenu/hook";
// import { UseContextMenuChart } from '../../plugins/contextmenu/hook'
import { UseContextMenuChart } from 'jeft-echarts'
// import bus from '../../utils/bus';
export default {
  name: "EBarMultiple",
  props: {
    className: {
      type: String,
      default: "bar-multiple-chart",
    },
    width: {
      type: String,
      default: "100%",
    },
    height: {
      type: String,
      default: "350px",
    },
    chartData: {
      type: Object,
      required: true,
    },
    showTitle: {
      type: Boolean,
      default: true
    },
    barColor: {
      type: String,
      default: '#3888fa'
    }
  },
  setup(props) {
    let chart = null;
    
    // 注册必须的组件
    echarts.use(
        [ TooltipComponent, ToolboxComponent, LegendComponent, BarChart, TitleComponent, GridComponent, CanvasRenderer ]
    );

    const setOptions = ({ series, title }, ) => {
      chart.setOption({
        tooltip: {
          trigger: 'axis',
          confine: true,
          axisPointer: {            // 坐标轴指示器,坐标轴触发有效
            type: 'shadow',        // 默认为直线,可选为:'line' | 'shadow'
          },
          textStyle: {
            fontSize: 14,
            color: '#fff'
          },
          extraCssText: 'background:rgba(0, 0, 0, 0.5);color:#fff;border: none;'
        },
        // toolbox: {
        //   feature: {
        //     dataView: {
        //       show: true
        //     }
        //   }
        // },
        legend: {
            itemHeight: 12,
            data: series.map((item) => item.name),
            bottom: "0",
            //   top: "5%",
            left: "center",
            //   right: '10%',
            textStyle: {
                color: '#999',
                fontSize: 12
            }
        },
        xAxis: [
          {
              type: 'time',
            //   data: xData,
              splitNumber: 10,
              nameGap: 15,
            //   //开始时间
            //   min: Date.now() - 2*60*60*1000,
            //   //结束时间
            //   max: Date.now(),

              axisTick: {
                  alignWithLabel: true
              },
              axisLabel: {
                  fontSize: 12,
                  lineHeight: 20,
                  color: '#ccc'
              },
              splitLine: {
                  show: false
              },
          }
        ],
        title: {
          text: props.showTitle ? title : '',
          left: "center",
          textStyle: {
              lineHeight: 80,
              fontSize: 40,
              color: 'white',
          }
        },
        grid: {
          left: 20,
          right: 20,
          bottom: 30,
          top: 20,
          containLabel: true,
        },
        yAxis: [{
          type: 'value',
          axisTick: {
            show: true,
          },
          axisLine: {
            show: true,
            lineStyle: {
              color: '#ccc'
            }
          },
          splitLine: {
              show: false,
              lineStyle: {
                type: 'dashed',
                color: '#666'
              }
          },
          axisLabel: {
            fontSize: 12,
            color: '#ccc'
          }
        }],
        series
      });
    };

    
    const initChart = () => {
        if (chart) {
          chart.dispose();
        }
        chart = echarts.init(document.getElementById(props.className), 'macarons');
        setOptions(props.chartData);

        UseContextMenuChart(chart, props.className, echarts);
    };

    watch(() => props.chartData, (newV) => {
        if (!chart) {
          return
        }
        setOptions(newV)
    }, { deep: true, immediate: false });
    
    onUnmounted(() => {
        if (!chart) {
            return
        }
        chart.dispose()
        chart = null
    });
    onMounted(() => {
        nextTick(() => {
            initChart();
        });
    })
    
    return {
      chart
    }
  }
};
</script>
<style lang='less'>
</style>
<template>
  <div class="table">
      <div class="table-header table-line" :style="{height: itemHeight + 'px'}">
          <div class="table-cell" v-for="item in data.header" :key="item">{{item}}</div>
      </div>
      <div class="table-line" v-for="line in data.data" :key="line" :style="{height: itemHeight + 'px'}">
          <div class="table-cell" v-for="item in line" :key="item">{{item}}</div>
      </div>
  </div>
</template>

<script>
export default {
    name: 'ETable',
    props: {
        data: {
            type: Object,
            required: true // {header: [], data: []}
        },
        itemHeight: {
            type: Number,
            default: 36
        }
    }
}
</script>

<style lang='less'>
@import url('../../assets/css/common.less');
.table {
    color: #ddd;
    .borderH(currentColor);
    .borderV(currentColor);

    &::before {
        top: 0;
    }
    &::after{
        left: 0;
    }
    &-header {
        font-weight: bold;
        font-size: 14px
    }

    &-line {
        .borderH(currentColor);
        .borderV(currentColor);

        &::before {
            bottom: 0;
        }
        &::after{
            right: 0;
        }
        display: flex;
        align-items: center;
        justify-content: space-evenly;
        font-size: 12px;
        font-weight: 300;
        .item {
            flex: 1;
            text-align: center;
            
        }
    }
}
</style>
<!--
 * @Author: your name
 * @Date: 2022-04-27 16:39:55
 * @LastEditTime: 2022-04-27 16:58:08
 * @LastEditors: Please set LastEditors
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: \youcai-pc\youcai-admin\src\components\Echarts\components\block.vue
-->
<template>
    <div class='e-block' :style="{ color: color, background: background}">
        <div class="e-block-bottom"></div>
        <slot></slot>
    </div>
</template>
<script>
export default {
    name: 'EBlock',
    props: {
        color: {
            type: String,
            default: '#02a6b5'
        },
        background: {
            type: String,
            default: 'rgba(255,255,255,.04)'
        }
    },
    components: {

    },
};
</script>
<style lang='less'>
.e-block {
    position: relative;
    border: 0.05em solid rgba(25,186,139,.17);
    background: rgba(255,255,255,.04);
    &:before, &:after {
        position: absolute;
        width: 1em;
        height: 1em;
        content: "";
        border-top: 0.16em solid currentColor;
        top: 0;
    }
    &:before{
        border-left: 0.16em solid currentColor;
        left: 0;
    }
    &:after {
        border-right: 0.16em solid currentColor;
        right: 0;
    }
    &-bottom{
        position: absolute;
        bottom: 0;
        left: 0;
        width: 100%;
        &:before, &:after {
            position: absolute;
            width: 1em;
            height: 1em;
            content: "";
            border-bottom: 0.16em solid currentColor;
            bottom: 0;
        }
        &:before{
            border-left: 0.16em solid currentColor;
            left: 0;
        }
        &:after {
            border-right: 0.16em solid currentColor;
            right: 0;
        }
    }
}
</style>

​​​​​​​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值