import { computed, defineComponent, onBeforeUnmount, onMounted, reactive, ref } from 'vue' import styles from './index.module.less' import CircleProgress from './component/CircleProgress' import iconBackup from './image/icon-backup.png' import iconEnsemble from './image/icon-ensemble.png' import * as echarts from 'echarts' import { listenerMessage, postMessage, removeListenerMessage } from '@/helpers/native-message' type EChartsOption = echarts.EChartsOption interface ISubjectItem { /** 声部名称 */ subjectName: string /**达标率 */ practiceRate: number /** 达标人数 */ passNum: number /** 未达标人数 */ noPassNum: number /** 非会员 */ noMemberNum: number } const symbolData: any = { type: 'line', symbol: 'circle', symbolSize: 6, triggerLineEvent: true } export default defineComponent({ name: 'subject-echarts', setup() { const activeData = reactive({ index: -1, sum: { /**达标率 */ practiceRate: 0, /**达标人数 */ passNum: 0, /**未达标人数 */ noPassNum: 0, /**未会员 */ noMemberNum: 0 }, practiceThisWeeks: [] as ISubjectItem[], colors: [ { color: '#FF8057', borderColor: 'rgba(255,128,87,0.5)', text: '达标率', select: true, key: 'practiceRate' }, { color: '#2FC58D', borderColor: 'rgba(47,197,141,0.5)', text: '达标', select: true, key: 'passNum' }, { color: '#4A99FF', borderColor: 'rgba(74,153,255,0.5)', text: '未达标', select: true, key: 'noPassNum' }, { color: '#9884BA', borderColor: 'rgba(152,132,186,0.5)', text: '非会员', select: true, key: 'noMemberNum' } ] }) const subjects = computed(() => { return activeData.practiceThisWeeks.map((n) => n.subjectName) }) let myChart: echarts.ECharts const handleInit = (data: any) => { const { content } = data if (!content) return if (myChart) { myChart.dispose() } activeData.sum = content.sum || {} activeData.practiceThisWeeks = content.practiceThisWeeks || [] const chartDom = document.getElementById('subjectEcharts')! myChart = echarts.init(chartDom) const option: EChartsOption = { tooltip: { trigger: 'axis', showContent: false, axisPointer: { type: 'line', lineStyle: { width: 30, type: 'solid', opacity: 0.2 } } }, grid: { left: 8, top: 5, right: 5, bottom: 5, containLabel: true }, legend: { type: 'plain', align: 'auto', itemGap: 10, itemWidth: 6, itemStyle: { opacity: 0 }, lineStyle: { width: 0, opacity: 0 }, textStyle: { opacity: 0 } }, xAxis: { type: 'category', axisLine: { show: false }, axisLabel: { interval: 0, color: '#333', fontSize: 9 }, axisTick: { alignWithLabel: true, show: false }, // boundaryGap: false, data: subjects.value }, yAxis: [ { type: 'value', position: 'left', axisLine: { show: false, lineStyle: { color: '#999' } }, splitLine: { show: true, // 是否显示y轴分割线 lineStyle: { color: ['rgba(249, 234, 220, 1)'] // 分隔线颜色。 } }, min: 0, splitNumber: 5 }, { type: 'value', position: 'right', splitLine: { show: true, // 是否显示y轴分割线 lineStyle: { color: ['rgba(249, 234, 220, 1)'] // 分隔线颜色。 } }, axisLine: { show: false, lineStyle: { color: '#999' } }, interval: 20, min: 0, max: 100, splitNumber: 5, axisLabel: { formatter: function (value: number, index: number) { return value + '%' } } } ], series: ['practiceRate', 'passNum', 'noPassNum', 'noMemberNum'].map( (key: string, index: number) => { return { name: activeData.colors[index].text, color: activeData.colors[index].color, ...symbolData, yAxisIndex: index === 0 ? 1 : 0, data: activeData.practiceThisWeeks.map((n) => n[key]) } } ) } let maxNum = Math.max(...(option.series as any[]).map((n) => n.data).flat()) let minNum = Math.min(...(option.series as any[]).map((n) => n.data).flat()) maxNum = Math.ceil(maxNum / 9.5) * 10 minNum = Math.floor(minNum / 12) * 10 ;(option.yAxis as any[])[0].interval = Math.ceil(Math.ceil(maxNum) / 5) ;(option.yAxis as any[])[0].max = Math.ceil(Math.ceil(maxNum) / 5) * 5 option && myChart.setOption(option) myChart.on('highlight', function (params: any) { activeData.index = params.batch[0].dataIndex }) } const handleAction = (index: number) => { activeData.index = index myChart?.dispatchAction({ type: 'showTip', seriesIndex: 0, dataIndex: index }) } const changeLegend = (item: any) => { myChart?.dispatchAction({ type: item.select ? 'legendUnSelect' : 'legendSelect', // 图例名称 name: item.text }) item.select = !item.select } const handleMock = () => { // console.log('handleMock1232') const resulst = { sum: { noMemberNum: Math.floor(Math.random() * 1000), noPassNum: Math.floor(Math.random() * 1000), passNum: Math.floor(Math.random() * 1000), practiceRate: Math.ceil(Math.random() * 100) }, practiceThisWeeks: new Array(Math.ceil(Math.random() * 9)).fill(1).map((n, i) => { return { /** 声部名称 */ subjectName: '声部' + (i + 1), /**达标率 */ practiceRate: Math.ceil(Math.random() * 100), /** 达标人数 */ passNum: Math.floor(Math.random() * 1000), /** 未达标人数 */ noPassNum: Math.floor(Math.random() * 1000), /** 非会员 */ noMemberNum: Math.floor(Math.random() * 1000) } }) } console.log(resulst) handleInit({ content: resulst }) } onMounted(() => { // handleMock() listenerMessage('setAccomanyEcharts', handleInit) postMessage({ api: 'setAccomanyEcharts' }) }) onBeforeUnmount(() => { removeListenerMessage('setAccomanyEcharts', handleInit) }) const goto = () => { const url = location.origin + location.pathname + `#/exercise-record` console.log('🚀 ~ url:', url) postMessage({ api: 'openWebView', content: { url: url, orientation: 1 } }) } return () => (