浏览代码

紧急需求1-4开发

刘洋 2 年之前
父节点
当前提交
e47a811ac2

+ 2 - 0
src/api/api-types/statistics.d.ts

@@ -537,6 +537,7 @@ export namespace Statistics {
   type GetStatisticSubjectiveByMarker = BaseDefine<StatisticByMarker, StatisticResult>
 
   type GetProvinceProcess = BaseDefine<any, any>
+  type GetCompareList = BaseDefine<any, any>
 
   interface ApiMap {
     /** 质量统计-自查一致性分析 */
@@ -625,5 +626,6 @@ export namespace Statistics {
     /** 决策分析-监控统计-主观题分数分布(按评卷员) */
     getStatisticSubjectiveByMarker: GetStatisticSubjectiveByMarker
     getProvinceProcess: GetProvinceProcess
+    getCompareList: GetCompareList
   }
 }

+ 6 - 0
src/api/statistics.ts

@@ -159,6 +159,12 @@ const StatisticsApi: DefineApiModule<Statistics.ApiMap> = {
     download: true,
     timeout: 0,
   },
+  getCompareList: {
+    url: '/api/statistic/marker/compare/list',
+    headers: {
+      'Content-Type': 'application/json',
+    },
+  },
 }
 
 export default StatisticsApi

+ 1 - 1
src/modules/analysis/monitoring/index.vue

@@ -250,7 +250,7 @@ const getColumns = (
       label: '老师ID',
       align: 'center',
       prop: 'markerName',
-      formatter(row) {
+      formatter(row: any) {
         return row.markerId === 0 ? (
           '全体'
         ) : (

+ 0 - 8
src/modules/analysis/personnel-compare/hooks/useCompareFilter.ts

@@ -81,14 +81,6 @@ const useCompareFilter = () => {
         endPlaceholder: '结束时间',
       },
     }),
-    OneRowSpan3({
-      prop: 'expand',
-      label: '',
-      slotType: 'checkbox',
-      slot: {
-        options: [{ label: '历史对比' }],
-      },
-    }),
     OneRowSpan3({
       labelWidth: '20px',
       slotName: 'button-group',

+ 233 - 4
src/modules/analysis/personnel-compare/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="personnel-compare-view full">
+  <div class="personnel-compare-view">
     <div class="p-l-base p-r-base p-t-medium-base fill-blank filter-form" style="padding-bottom: 10px">
       <base-form size="small" :label-width="'88px'" :model="model" :items="items">
         <template #form-item-button-group>
@@ -7,17 +7,246 @@
         </template>
       </base-form>
     </div>
-    <div class="flex-1 p-small"></div>
+    <div v-loading="loading" class="p-small">
+      <el-radio-group v-model="dataType">
+        <el-radio-button v-for="type in dataTypeValues" :key="type" :label="type">
+          {{ dataTypeLabelMap[type] }}
+        </el-radio-button>
+      </el-radio-group>
+      <div class="m-t-small">
+        <base-table
+          v-if="dataType !== 'segmentScores'"
+          ref="tableRef1"
+          border
+          stripe
+          size="small"
+          :columns="columns"
+          :data="allTableData"
+          :height="'500px'"
+          highlight-current-row
+        >
+        </base-table>
+        <base-table
+          v-else
+          ref="tableRef2"
+          border
+          stripe
+          size="small"
+          :columns="columns2"
+          :data="allTableData"
+          :height="'500px'"
+          highlight-current-row
+        >
+        </base-table>
+      </div>
+      <div v-if="allTableData.length" class="m-t-small out-chart-box">
+        <div v-if="dataType !== 'segmentScores'" class="chart-box">
+          <vue-e-charts class="full" :option="lineChartOptions"></vue-e-charts>
+        </div>
+        <div v-else class="chart-box">
+          <vue-e-charts class="full" :option="multLineChartOptions"></vue-e-charts>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 <script setup lang="ts" name="PersonnelCompare">
+import { ref, reactive, computed, watch } from 'vue'
 import BaseForm from '@/components/element/BaseForm.vue'
-import { ElButton } from 'element-plus'
+import useFetch from '@/hooks/useFetch'
+import BaseTable from '@/components/element/BaseTable.vue'
+import { ElButton, ElRadioButton, ElRadioGroup } from 'element-plus'
 import useCompareFilter from './hooks/useCompareFilter'
+import VueECharts from 'vue-echarts'
+
+const dataType = ref('avg')
+const dataTypeValues = ['avg', 'std', 'segmentScores', 'markingCount', 'xyRelate']
+const dataTypeLabelMap = reactive<any>({
+  avg: '平均分',
+  std: '标准差',
+  segmentScores: '给分分布',
+  markingCount: '工作量',
+  xyRelate: '相关系数',
+})
+const multLineXdatas = ref([])
 const { model, fetchModel, items, onOptionInit } = useCompareFilter()
 
+const { fetch, result, loading } = useFetch('getCompareList')
+const averageDatas = computed(() => {
+  if (result.value) {
+    let data = result.value.groups.map((item: any) => {
+      return {
+        markingGroupNumber: item.markingGroupNumber,
+        avg: item.avg,
+        avgMarkingCount: item.avgMarkingCount,
+        std: item.std,
+        xyRelate: item.xyRelate,
+      }
+    })
+    return data
+  } else {
+    return []
+  }
+})
+const allTableData = computed(() => {
+  if (result.value) {
+    let arr = []
+    for (let i = 0; i < result.value.groups.length; i++) {
+      let g = result.value.groups[i]
+      arr.push(...g.markerCompares)
+    }
+    return arr
+  } else {
+    return []
+  }
+})
+watch(allTableData, () => {
+  if (!multLineXdatas.value.length) {
+    multLineXdatas.value = allTableData.value[0].segmentScores.map((item: any) => {
+      return item.scoreStart
+    })
+  }
+})
+const columns = computed(() => {
+  return [
+    { label: '账号', prop: 'loginName', align: 'center', minWidth: 120, fixed: 'left' },
+    { label: '姓名', prop: 'markerName', align: 'center', minWidth: 120, fixed: 'left' },
+    ...(result.value || { columns: [] }).columns.map((d: any) => {
+      return {
+        label: d,
+        align: 'center',
+        formatter(row: any) {
+          let find = row.dateItems.find((v: any) => v.date === d)
+          return find ? find[dataType.value] : ''
+        },
+        sortMethod: function (a: any, b: any) {
+          let aValue = a.dateItems.find((v: any) => v.date === d)[dataType.value] || 0
+          let bValue = b.dateItems.find((v: any) => v.date === d)[dataType.value] || 0
+          return aValue - bValue
+        },
+        minWidth: 100,
+      }
+    }),
+  ]
+})
+const columns2: any = computed(() => {
+  let initColumns = [
+    { label: '账号', prop: 'loginName', align: 'center', minWidth: 120, fixed: 'left' },
+    { label: '姓名', prop: 'markerName', align: 'center', minWidth: 120, fixed: 'left' },
+  ]
+  if (allTableData.value.length) {
+    let pushColumns = allTableData.value[0].segmentScores.map((item: any) => {
+      return {
+        label: item.scoreStart,
+        align: 'center',
+        formatter(row: any) {
+          return row.segmentScores.find((v: any) => v.scoreStart == item.scoreStart).rate
+        },
+        sortMethod: function (a: any, b: any) {
+          let aRate = a.segmentScores.find((v: any) => v.scoreStart === item.scoreStart)?.rate
+          let bRate = b.segmentScores.find((v: any) => v.scoreStart === item.scoreStart)?.rate
+          return aRate - bRate
+        },
+      }
+    })
+    initColumns.push(...pushColumns)
+  }
+  return initColumns
+})
+const lineChartOptions = computed(() => {
+  let xData = allTableData.value.map((item) => item.loginName)
+  return {
+    xAxis: {
+      axisLine: { show: false },
+      axisTick: { show: false },
+      splitLine: { show: false },
+      axisLabel: {
+        align: 'right',
+      },
+      data: xData,
+    },
+    yAxis: [
+      {
+        type: 'value',
+      },
+      {
+        type: 'value',
+        // axisLabel: {
+        //   formatter: `{value}%`,
+        // },
+        splitLine: { show: false },
+      },
+    ],
+    series: [
+      {
+        name: dataTypeLabelMap[dataType.value],
+        type: 'line',
+        barWidth: 20,
+        itemStyle: {
+          color: '#3AD500',
+        },
+        data: allTableData.value.map((item) => item[dataType.value]),
+        markLine: {
+          data: averageDatas.value.map((item: any) => {
+            return {
+              name: item.markingGroupNumber == 0 ? '总体平均分' : `小组${item.markingGroupNumber}平均分`,
+              yAxis: item[dataType.value === 'markingCount' ? 'avgMarkingCount' : dataType.value],
+            }
+          }),
+        },
+      },
+    ],
+  }
+})
+const multLineChartOptions = computed(() => {
+  return {
+    xAxis: {
+      axisLine: { show: false },
+      axisTick: { show: false },
+      splitLine: { show: false },
+      axisLabel: {
+        align: 'right',
+      },
+      data: multLineXdatas,
+    },
+    yAxis: [
+      {
+        type: 'value',
+      },
+      {
+        type: 'value',
+        splitLine: { show: false },
+      },
+    ],
+    series: allTableData.value.map((item: any) => {
+      return {
+        name: item.loginName,
+        type: 'line',
+        barWidth: 20,
+        // itemStyle: {
+        //   color: '#3AD500',
+        // },
+        data: item.segmentScores.map((v: any) => v.rate),
+      }
+    }),
+  }
+})
 const onSearch = () => {
   console.log('search')
+  fetch(fetchModel.value).then((res) => {
+    console.log('rrr', result.value)
+  })
 }
+onOptionInit(onSearch)
 </script>
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.personnel-compare-view {
+  background-color: #fff;
+  .out-chart-box {
+    height: 300px;
+  }
+  .chart-box {
+    height: 300px;
+  }
+}
+</style>

+ 11 - 2
src/plugins/echarts.ts

@@ -1,10 +1,19 @@
 import { use } from 'echarts/core'
 import { SVGRenderer, CanvasRenderer } from 'echarts/renderers'
 import { BarChart, LineChart } from 'echarts/charts'
-import { TitleComponent, GridComponent, LegendComponent } from 'echarts/components'
+import { TitleComponent, GridComponent, LegendComponent, MarkLineComponent } from 'echarts/components'
 
 const useECharts = () => {
-  return use([CanvasRenderer, SVGRenderer, BarChart, LineChart, TitleComponent, GridComponent, LegendComponent])
+  return use([
+    CanvasRenderer,
+    SVGRenderer,
+    BarChart,
+    LineChart,
+    TitleComponent,
+    GridComponent,
+    LegendComponent,
+    MarkLineComponent,
+  ])
 }
 
 export default useECharts