liushengqiang 2 年 前
コミット
eb60ad24e3
2 ファイル変更240 行追加131 行削除
  1. 11 2
      src/views/subject-echarts/index.module.less
  2. 229 129
      src/views/subject-echarts/index.tsx

+ 11 - 2
src/views/subject-echarts/index.module.less

@@ -1,13 +1,22 @@
 .subjectEcharts {
-    padding: 12px;
+    padding: 12px 12px 30px 12px;
 }
 
 .container {
+    position: relative;
     padding: 14px 12px;
     border-radius: 10px;
     background-color: #fff;
     margin-bottom: 12px;
 }
+.emtry{
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translateX(-50%);
+    font-size: 14px;
+    color: #AAAAAA;
+}
 
 .head {
     display: flex;
@@ -105,7 +114,7 @@
     display: flex;
     align-items: center;
     padding: 10px 15px 10px 27px;
-
+    border: 1px solid transparent;
     &:not(:last-child) {
         border-bottom: 1px dashed #EAEAEA;
     }

+ 229 - 129
src/views/subject-echarts/index.tsx

@@ -1,77 +1,186 @@
-import { defineComponent, onMounted, ref } from 'vue'
+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 { postMessage } from '@/helpers/native-message'
+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,
+  stack: 'Total'
+}
 export default defineComponent({
   name: 'subject-echarts',
   setup() {
-    const colors = [
-      {
-        color: '#FF8057',
-        borderColor: 'rgba(255,128,87,0.5)',
-        text: '达标率'
-      },
-      {
-        color: '#2FC58D',
-        borderColor: 'rgba(47,197,141,0.5)',
-        text: '达标'
+    const activeData = reactive({
+      index: -1,
+      sum: {
+        /**达标率 */
+        practiceRate: 0,
+        /**达标人数 */
+        passNum: 0,
+        /**未达标人数 */
+        noPassNum: 0,
+        /**未会员 */
+        noMemberNum: 0
       },
-      {
-        color: '#4A99FF',
-        borderColor: 'rgba(74,153,255,0.5)',
-        text: '未达标'
-      },
-      {
-        color: '#9884BA',
-        borderColor: 'rgba(152,132,186,0.5)',
-        text: '非会员'
+      practiceThisWeeks: [] as ISubjectItem[],
+      colors: [
+        {
+          color: '#FF8057',
+          borderColor: 'rgba(255,128,87,0.5)',
+          text: '达标率',
+          select: true
+        },
+        {
+          color: '#2FC58D',
+          borderColor: 'rgba(47,197,141,0.5)',
+          text: '达标',
+          select: true
+        },
+        {
+          color: '#4A99FF',
+          borderColor: 'rgba(74,153,255,0.5)',
+          text: '未达标',
+          select: true
+        },
+        {
+          color: '#9884BA',
+          borderColor: 'rgba(152,132,186,0.5)',
+          text: '非会员',
+          select: true
+        }
+      ]
+    })
+    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.clear()
       }
-    ]
-    const myChart = ref<echarts.ECharts>()
-    const handleInit = () => {
-      var chartDom = document.getElementById('subjectEcharts')!
-      myChart.value = echarts.init(chartDom, undefined, {
-        renderer: 'svg'
-      })
-      var option: EChartsOption
-
-      option = {
+      activeData.sum = content.sum || {}
+      activeData.practiceThisWeeks =
+        content.practiceThisWeeks
+        // .concat(
+        //   ...[
+        //     {
+        //       memberNum: 1,
+        //       noMemberNum: 10,
+        //       noPassNum: 12,
+        //       passNum: 30,
+        //       practiceRate: 20,
+        //       subjectName: '单簧管',
+        //       trainingNum: 0
+        //     },
+        //     {
+        //       memberNum: 1,
+        //       noMemberNum: 20,
+        //       noPassNum: 31,
+        //       passNum: 10,
+        //       practiceRate: 30,
+        //       subjectName: '萨克斯',
+        //       trainingNum: 0
+        //     },
+        //     {
+        //       memberNum: 1,
+        //       noMemberNum: 10,
+        //       noPassNum: 16,
+        //       passNum: 40,
+        //       practiceRate: 20,
+        //       subjectName: '小号',
+        //       trainingNum: 0
+        //     },
+        //     {
+        //       memberNum: 1,
+        //       noMemberNum: 10,
+        //       noPassNum: 16,
+        //       passNum: 40,
+        //       practiceRate: 20,
+        //       subjectName: '小号',
+        //       trainingNum: 0
+        //     }
+        //   ]
+        // ) 
+        || []
+      const chartDom = document.getElementById('subjectEcharts')!
+      myChart = echarts.init(chartDom)
+      const option: EChartsOption = {
         tooltip: {
           trigger: 'axis',
-        },
-        dataset: {
-          source: [['Email']]
+          axisPointer: {
+            type: 'line',
+            lineStyle: {
+              width: 40,
+              opacity: 0.5,
+            }
+          }
         },
         grid: {
-          left: '3%',
-          right: '3%',
-          bottom: '3%',
+          left: 5,
+          top: 5,
+          right: 5,
+          bottom: 5,
           containLabel: true
         },
+        legend: {
+          type: 'scroll',
+          right: 12,
+          itemGap: 0,
+          itemWidth: 2,
+          itemStyle: {
+            opacity: 0
+          },
+          lineStyle: {
+            width: 0,
+            opacity: 0
+          },
+          textStyle: {
+            opacity: 0
+          }
+        },
         xAxis: {
           type: 'category',
+          axisLabel: {
+            interval: 0,
+            color: '#333',
+            fontSize: 9
+          },
+          axisTick: {
+            show: false
+          },
           boundaryGap: false,
-          data: ['长笛', '单簧管', '萨克斯', '小号', '圆号', '上低音号', '打击乐'],
-          axisPointer:{
-            type: 'shadow'
-          }
+          data: subjects.value
         },
         yAxis: [
           {
             type: 'value',
             position: 'left',
-            alignTicks: true,
             axisLine: {
               show: true,
               lineStyle: {
-                color: colors[2].color
+                color: '#999'
               }
             },
             axisLabel: {
@@ -81,11 +190,10 @@ export default defineComponent({
           {
             type: 'value',
             position: 'right',
-            alignTicks: true,
             axisLine: {
               show: true,
               lineStyle: {
-                color: colors[0].color
+                color: '#999'
               }
             },
             axisLabel: {
@@ -93,89 +201,87 @@ export default defineComponent({
             }
           }
         ],
-        series: [
-          {
-            name: '达标率',
-            type: 'line',
-            data: [120, 132, 101, 134, 90, 230, 210]
-          },
-          {
-            name: '达标',
-            type: 'line',
-            data: [150, 232, 201, 154, 190, 330, 410]
-          },
-          {
-            name: '未达标',
-            type: 'line',
-            data: [320, 332, 301, 334, 390, 330, 320]
-          },
-          {
-            name: '非会员',
-            type: 'line',
-            yAxisIndex: 1,
-            data: [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2]
+        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])
+            }
           }
-        ]
+        )
       }
 
-      option && myChart.value.setOption(option)
-      console.log('🚀 ~ myChart:', myChart.value)
+      option && myChart.setOption(option)
+      myChart.on('highlight', function (params: any) {
+        activeData.index = params.batch[0].dataIndex
+      })
+      // console.log('🚀 ~ myChart:', myChart)
     }
-    const getThisWeek = async () => {
-      postMessage(
-        {
-          api: 'setAccomanyEcharts'
-        },
-        (evt) => {
-          console.log(evt?.content)
-        }
-      )
+    const handleAction = (index: number) => {
+      activeData.index = index
+      myChart?.dispatchAction({
+        type: 'showTip',
+        seriesIndex: 0,
+        dataIndex: index
+      })
     }
-    const action = () => {
-      // myChart.value?.dispatchAction({
-      //   type: 'showTip',
-      //   name: '单簧管'
-      // })
-      myChart.value?.dispatchAction({
-          type:'downplay',
-          seriesIndex:[0,1],//两个图标同时展示
-          dataIndex:0
-    })
+    const changeLegend = (item: any) => {
+      myChart?.dispatchAction({
+        type: item.select ? 'legendUnSelect' : 'legendSelect',
+        // 图例名称
+        name: item.text
+      })
+      item.select = !item.select
     }
     onMounted(() => {
-      getThisWeek()
-      handleInit()
+      handleInit({ content: { practiceThisWeeks: [], sum: {} } })
+      listenerMessage('setAccomanyEcharts', handleInit)
+      postMessage({
+        api: 'setAccomanyEcharts'
+      })
+    })
+    onBeforeUnmount(() => {
+      removeListenerMessage('setAccomanyEcharts', handleInit)
     })
     return () => (
       <div class={styles.subjectEcharts}>
         <div class={[styles.container, styles.ensemble]}>
           <div class={styles.head}>
-            <div class={styles.headLeft}>
+            <div class={styles.headLeft} onClick={() => handleInit({ content: { practiceThisWeeks: [], sum: {} } })}>
               <img class={styles.icon} src={iconEnsemble} />
               <div>总体情况</div>
             </div>
           </div>
 
           <div class={styles.content}>
-            <CircleProgress value={80} size={80} color="#FF8057" strokeWidth={6} duration={3000} />
+            <CircleProgress
+              value={activeData.sum.practiceRate}
+              size={80}
+              color="#FF8057"
+              strokeWidth={6}
+              duration={3000}
+            />
             <div class={styles.items}>
               <div class={styles.item}>
                 <div class={styles.itemNum}>
                   <span class={styles.rect}></span>
-                  <span style={{ color: '#FF8057' }}>348</span>
+                  <span style={{ color: '#FF8057' }}>{activeData.sum.passNum}</span>
                 </div>
                 <div class={styles.itemTitle}>达标人数</div>
               </div>
               <div class={[styles.item, styles.line]}>
                 <div class={styles.itemNum}>
                   <span class={styles.rect} style={{ background: '#FFE7DF' }}></span>
-                  <span>348</span>
+                  <span>{activeData.sum.noPassNum}</span>
                 </div>
                 <div class={styles.itemTitle}>未达标人数</div>
               </div>
               <div class={styles.item}>
                 <div class={styles.itemNum}>
-                  <span>348</span>
+                  <span>{activeData.sum.noMemberNum}</span>
                 </div>
                 <div class={styles.itemTitle}>非会员人数</div>
               </div>
@@ -190,13 +296,14 @@ export default defineComponent({
               <div>声部情况</div>
             </div>
             <div class={styles.headRight}>
-              {colors.map((c) => (
+              {activeData.colors.map((c) => (
                 <div
-                  style={{ color: c.color, borderColor: c.borderColor }}
-                  onClick={() => {
-                    console.log(myChart.value)
-                    action()
-                  }}
+                  style={
+                    c.select
+                      ? { color: '#fff', borderColor: c.color, backgroundColor: c.color }
+                      : { color: c.color, borderColor: c.borderColor }
+                  }
+                  onClick={() => changeLegend(c)}
                 >
                   {c.text}
                 </div>
@@ -205,41 +312,34 @@ export default defineComponent({
           </div>
 
           <div id="subjectEcharts" class={styles.echartsMain}></div>
+          {!activeData.practiceThisWeeks.length && <div class={styles.emtry}>暂无联系记录</div>}
         </div>
 
         <div class={[styles.container, styles.subjectWrap]}>
-          {new Array(8).fill(1).map((item: any, index: number) => (
-            <div class={[styles.listItem, index == 3 ? styles.listItemActive : '']}>
+          {activeData.practiceThisWeeks.map((item, index: number) => (
+            <div
+              class={[styles.listItem, index === activeData.index ? styles.listItemActive : '']}
+              onClick={() => handleAction(index)}
+            >
               <div class={styles.dot}></div>
               <div class={styles.itemLeft}>
-                <div class={styles.subjectName}>长笛</div>
+                <div class={styles.subjectName}>{item.subjectName}</div>
                 <div class={styles.subjectType}>声部</div>
               </div>
               <div class={styles.listitems}>
-                <div class={styles.item}>
-                  <div class={styles.itemNum}>
-                    <span style={{ color: colors[0].color }}>348</span>
-                  </div>
-                  <div class={styles.itemTitle}>达标率</div>
-                </div>
-                <div class={styles.item}>
-                  <div class={styles.itemNum}>
-                    <span style={{ color: colors[1].color }}>348</span>
-                  </div>
-                  <div class={styles.itemTitle}>达标人数</div>
-                </div>
-                <div class={styles.item}>
-                  <div class={styles.itemNum}>
-                    <span style={{ color: colors[2].color }}>348</span>
-                  </div>
-                  <div class={styles.itemTitle}>未达标人数</div>
-                </div>
-                <div class={styles.item}>
-                  <div class={styles.itemNum}>
-                    <span style={{ color: colors[3].color }}>348</span>
-                  </div>
-                  <div class={styles.itemTitle}>非会员人数</div>
-                </div>
+                {activeData.colors.map((c, index: number) => {
+                  return (
+                    <div class={styles.item}>
+                      <div class={styles.itemNum}>
+                        <span style={{ color: c.color }}>{item.practiceRate}</span>
+                      </div>
+                      <div class={styles.itemTitle}>
+                        {c.text}
+                        {index === 0 ? '' : '人数'}
+                      </div>
+                    </div>
+                  )
+                })}
               </div>
             </div>
           ))}