Forráskód Böngészése

v1.1.0需求开发

刘洋 1 éve
szülő
commit
5dbd75f9fb

+ 1 - 1
electron/main/main.ts

@@ -102,7 +102,7 @@ async function createWindow() {
     center: true,
     center: true,
     icon: path.join(__dirname, './icons/icon.ico'),
     icon: path.join(__dirname, './icons/icon.ico'),
     resizable: false,
     resizable: false,
-    fullscreen: app.isPackaged ? true : true,
+    fullscreen: app.isPackaged ? true : false,
     fullscreenable: true,
     fullscreenable: true,
     alwaysOnTop: false,
     alwaysOnTop: false,
     useContentSize: true,
     useContentSize: true,

BIN
src/assets/images/app_close.png


BIN
src/assets/images/app_close2.png


BIN
src/assets/images/app_minimize.png


BIN
src/assets/images/app_minimize2.png


+ 4 - 4
src/components/common/secNumberStatus.vue

@@ -21,11 +21,11 @@ const props = defineProps<{ secretNumber: any; checked: boolean; corrected: bool
   .status,
   .status,
   .status2 {
   .status2 {
     display: inline-block;
     display: inline-block;
-    width: 8px;
-    height: 8px;
-    border-radius: 4px;
+    width: 10px;
+    height: 10px;
+    border-radius: 5px;
     background-color: transparent;
     background-color: transparent;
-    margin-right: 3px;
+    margin-right: 8px;
     &.corrected {
     &.corrected {
       background-color: #f53f3f;
       background-color: #f53f3f;
       cursor: pointer;
       cursor: pointer;

+ 12 - 2
src/hooks/useTable.ts

@@ -4,6 +4,7 @@ import useFetch from '@/hooks/useFetch'
 import useSection from '@/hooks/useSection'
 import useSection from '@/hooks/useSection'
 import bus from '@/utils/bus'
 import bus from '@/utils/bus'
 import { ElMessage } from 'element-plus'
 import { ElMessage } from 'element-plus'
+import useMainStore from '@/store/main'
 import type { Ref } from 'vue'
 import type { Ref } from 'vue'
 import type {
 import type {
   ApiKeys,
   ApiKeys,
@@ -43,7 +44,7 @@ export type ResponseType<T extends ApiKeys> = ExtractApiResponse<T>
 //   pageNumber: 1,
 //   pageNumber: 1,
 //   pageSize: 10,
 //   pageSize: 10,
 // }
 // }
-
+const mainStore = useMainStore()
 const DEFAULT_PAGINATION: Partial<PaginationProps> = {
 const DEFAULT_PAGINATION: Partial<PaginationProps> = {
   layout: 'prev,pager,next',
   layout: 'prev,pager,next',
 }
 }
@@ -141,10 +142,19 @@ const useTable = <
     return currentPage.value * baseParams.pageSize + 1 > total.value
     return currentPage.value * baseParams.pageSize + 1 > total.value
   })
   })
   bus.on('toNextTablePage', () => {
   bus.on('toNextTablePage', () => {
+    // if (isLastPage.value) {
+    //   ElMessage.warning('当前页已是最后一页')
+    // } else {
+    currentPage.value = Number(currentPage.value) + 1
+    // }
+  })
+
+  bus.on('atBottomRowFromUseTableCheck', () => {
+    //被useTableCheck告知到了最后一行
     if (isLastPage.value) {
     if (isLastPage.value) {
       ElMessage.warning('当前页已是最后一页')
       ElMessage.warning('当前页已是最后一页')
     } else {
     } else {
-      currentPage.value = Number(currentPage.value) + 1
+      mainStore.setRowNextBottomDialogStatus(true)
     }
     }
   })
   })
 
 

+ 35 - 5
src/hooks/useTableCheck.ts

@@ -5,6 +5,8 @@ import type { InstanceTable } from 'global-type'
 import type { MultipleResult } from '@/api/api'
 import type { MultipleResult } from '@/api/api'
 import { throttle } from 'lodash-es'
 import { throttle } from 'lodash-es'
 import useMainStore from '@/store/main'
 import useMainStore from '@/store/main'
+import bus from '@/utils/bus'
+import { ElMessage } from 'element-plus'
 type ArrayObjectType = Array<Record<string, any>>
 type ArrayObjectType = Array<Record<string, any>>
 
 
 type MultipleResultType<T = Record<string, any>> = MultipleResult<T>
 type MultipleResultType<T = Record<string, any>> = MultipleResult<T>
@@ -29,7 +31,22 @@ const useTableCheck = <T extends TableDataType<InputDataType>>(data: T, auto = t
   const elTableRef = computed(() => {
   const elTableRef = computed(() => {
     return tableRef?.value?.tableRef
     return tableRef?.value?.tableRef
   })
   })
-
+  const totalCount = ref<any>(null)
+  const pageSize = ref<any>(null)
+  const pageNumber = ref<any>(null)
+
+  const initPaginationParams = () => {
+    const _data: any = unref(data)
+    if (isMultipleData(_data)) {
+      totalCount.value = _data.totalCount
+      pageSize.value = _data.pageSize
+      pageNumber.value = _data.pageNumber
+    }
+  }
+  initPaginationParams()
+  watch(data, () => {
+    initPaginationParams()
+  })
   const tableData = computed(() => {
   const tableData = computed(() => {
     const d = unref(data)
     const d = unref(data)
     // let result: RowType<T>[] = []
     // let result: RowType<T>[] = []
@@ -91,8 +108,21 @@ const useTableCheck = <T extends TableDataType<InputDataType>>(data: T, auto = t
     console.log('current.value?.index:', current.value?.index)
     console.log('current.value?.index:', current.value?.index)
     console.log('tableData.value.length:', tableData.value.length)
     console.log('tableData.value.length:', tableData.value.length)
     if (current.value?.index == tableData.value.length - 1) {
     if (current.value?.index == tableData.value.length - 1) {
-      //说明高亮正处于最后一行了,需要提示用户是否需要翻到下一页
-      mainStore.setRowNextBottomDialogStatus(true)
+      //说明高亮正处于最后一行了,需要提示用户是否需要翻到下一页。
+      if (totalCount.value !== null && pageSize.value !== null) {
+        // 说明页面只使用了useTableCheck,而未使用useTable。
+        //注意:这里只处理只使用了useTableCheck而未使用useTable的情况。另外一种情况在useTable里处理。避免重复
+        //只使用了useTableCheck,而未使用useTable的情况,基本上是pageSize传了99999这种情况,所以一页就是全部的数据,最后一行就是到底了
+        if (pageNumber.value * pageSize.value + 1 > totalCount.value) {
+          ElMessage.warning('当前页已是最后一页')
+        } else {
+          //该情况应该不可能出现,因为只使用了useTableCheck而未使用useTable的情况,是只有一页的,即pageSize传的999999之类
+          // mainStore.setRowNextBottomDialogStatus(true)
+        }
+      } else {
+        //在useTable里才能拿到分页相关信息,所以要对useTable进行通信,告诉它到了最后一行了,是否需要弹框诱导到下一页
+        bus.emit('atBottomRowFromUseTableCheck')
+      }
       return
       return
     }
     }
     const index = (current.value?.index || 0) + 1
     const index = (current.value?.index || 0) + 1
@@ -114,7 +144,7 @@ const useTableCheck = <T extends TableDataType<InputDataType>>(data: T, auto = t
       }
       }
     }
     }
     // elTableRef?.value?.scrollTo(0, (current.value?.index || 0) * 36)
     // elTableRef?.value?.scrollTo(0, (current.value?.index || 0) * 36)
-  }, 500)
+  }, 300)
   const prevRow = throttle(() => {
   const prevRow = throttle(() => {
     console.log('current.value?.index:', current.value?.index)
     console.log('current.value?.index:', current.value?.index)
     if (current.value?.index > 0) {
     if (current.value?.index > 0) {
@@ -136,7 +166,7 @@ const useTableCheck = <T extends TableDataType<InputDataType>>(data: T, auto = t
         }
         }
       }
       }
     }
     }
-  }, 500)
+  }, 300)
   const arrowDownToNextRow = (e: any) => {
   const arrowDownToNextRow = (e: any) => {
     // if (e.target.tagName === 'INPUT' || (e.target.className || '').includes('contenteditable-ele')) {
     // if (e.target.tagName === 'INPUT' || (e.target.className || '').includes('contenteditable-ele')) {
     //   return false
     //   return false

+ 28 - 2
src/layout/bootstrap/index.vue

@@ -5,8 +5,14 @@
         <span>CET</span>
         <span>CET</span>
         <span> 电子阅卷</span>
         <span> 电子阅卷</span>
       </div>
       </div>
-      <div class="grid fill-light-gray pointer close-icon" @click="closeApp">
-        <el-icon><close /></el-icon>
+      <div class="flex items-center">
+        <!-- <el-icon><close /></el-icon> -->
+        <div class="icon-box" @click="maximize">
+          <img src="../../assets/images/app_minimize.png" />
+        </div>
+        <div class="icon-box m-l-base" @click="closeApp">
+          <img src="../../assets/images/app_close.png" />
+        </div>
       </div>
       </div>
     </div>
     </div>
     <div class="flex-1 bootstrap-content">
     <div class="flex-1 bootstrap-content">
@@ -19,6 +25,10 @@
 import { ElIcon } from 'element-plus'
 import { ElIcon } from 'element-plus'
 import { Close } from '@element-plus/icons-vue'
 import { Close } from '@element-plus/icons-vue'
 import { closeApp } from '@/utils/shared'
 import { closeApp } from '@/utils/shared'
+const maximize = () => {
+  let electronAPI = (window as any).electronAPI
+  electronAPI && electronAPI.windowMin()
+}
 </script>
 </script>
 
 
 <style scoped lang="scss">
 <style scoped lang="scss">
@@ -28,6 +38,22 @@ import { closeApp } from '@/utils/shared'
     font-size: $MainLayoutHeaderLogoFontSize;
     font-size: $MainLayoutHeaderLogoFontSize;
     color: $MainLayoutHeaderLogoFontColor;
     color: $MainLayoutHeaderLogoFontColor;
   }
   }
+  .icon-box {
+    width: 40px;
+    height: 40px;
+    border-radius: 6px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: pointer;
+    img {
+      width: 22px;
+      height: 22px;
+    }
+    &:hover {
+      background-color: #eee;
+    }
+  }
   .close-icon {
   .close-icon {
     width: 32px;
     width: 32px;
     height: 32px;
     height: 32px;

+ 35 - 4
src/layout/main/index.vue

@@ -1,7 +1,7 @@
 <template>
 <template>
   <div class="flex main-layout">
   <div class="flex main-layout">
     <div class="flex direction-column main-layout-left" :class="{ 'is-collapse': mainLayoutStore.collapse }">
     <div class="flex direction-column main-layout-left" :class="{ 'is-collapse': mainLayoutStore.collapse }">
-      <div class="drag flex items-center justify-center dou-yu main-layout-left-logo" @click="maximize">
+      <div class="drag flex items-center justify-center dou-yu main-layout-left-logo" @dblClick="reloadPage">
         <span v-if="mainLayoutStore.collapse">CET</span>
         <span v-if="mainLayoutStore.collapse">CET</span>
         <img v-else src="../../assets/images/logo.png" />
         <img v-else src="../../assets/images/logo.png" />
         <!-- <span v-show="!mainLayoutStore.collapse"> 电子阅卷</span> -->
         <!-- <span v-show="!mainLayoutStore.collapse"> 电子阅卷</span> -->
@@ -11,6 +11,14 @@
       </div>
       </div>
     </div>
     </div>
     <div class="flex flex-1 direction-column scroll-auto main-layout-right">
     <div class="flex flex-1 direction-column scroll-auto main-layout-right">
+      <div class="frame-header p-base flex items-center justify-end">
+        <div class="icon-box" @click="maximize">
+          <img src="../../assets/images/app_minimize2.png" />
+        </div>
+        <div class="icon-box m-l-base" @click="closeApp">
+          <img src="../../assets/images/app_close2.png" />
+        </div>
+      </div>
       <main-header :reply-user-id="replyUserId" :message-visible="messageVisible" :in-layout="true"></main-header>
       <main-header :reply-user-id="replyUserId" :message-visible="messageVisible" :in-layout="true"></main-header>
       <div class="flex-1 scroll-auto main-layout-right-content">
       <div class="flex-1 scroll-auto main-layout-right-content">
         <!-- <RouterView></RouterView> -->
         <!-- <RouterView></RouterView> -->
@@ -31,11 +39,13 @@ import MainHeader from './MainHeader.vue'
 import useMainLayoutStore from '@/store/layout'
 import useMainLayoutStore from '@/store/layout'
 import useMainStore from '@/store/main'
 import useMainStore from '@/store/main'
 import { useRoute } from 'vue-router'
 import { useRoute } from 'vue-router'
-const route = useRoute()
+import { closeApp } from '@/utils/shared'
 const maximize = () => {
 const maximize = () => {
   let electronAPI = (window as any).electronAPI
   let electronAPI = (window as any).electronAPI
   electronAPI && electronAPI.windowMin()
   electronAPI && electronAPI.windowMin()
 }
 }
+const route = useRoute()
+
 const reloadPage = () => {
 const reloadPage = () => {
   ;(window as any).location.reload()
   ;(window as any).location.reload()
 }
 }
@@ -69,17 +79,38 @@ provide('reload', reload)
 .main-layout {
 .main-layout {
   width: 100%;
   width: 100%;
   height: 100%;
   height: 100%;
+  .frame-header {
+    height: 70px;
+    background-color: #333;
+    .icon-box {
+      width: 40px;
+      height: 40px;
+      border-radius: 6px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      cursor: pointer;
+      img {
+        width: 22px;
+        height: 22px;
+      }
+      &:hover {
+        background-color: #666;
+      }
+    }
+  }
   .main-layout-left {
   .main-layout-left {
     width: $LayoutLeftMenuWidth;
     width: $LayoutLeftMenuWidth;
     // background-color: $LayoutLeftMenuBg;
     // background-color: $LayoutLeftMenuBg;
     background-color: #333;
     background-color: #333;
     transition: $LayoutLeftMenuTransition;
     transition: $LayoutLeftMenuTransition;
-    border-right: $OnePixelLine;
+    // border-right: $OnePixelLine;
     &.is-collapse {
     &.is-collapse {
       width: $LayoutLeftMenuCollapseWidth;
       width: $LayoutLeftMenuCollapseWidth;
     }
     }
     .main-layout-left-logo {
     .main-layout-left-logo {
-      min-height: $MainLayoutHeaderHeight;
+      // min-height: $MainLayoutHeaderHeight;
+      min-height: 70px;
       margin: 0 $BaseGapSpace;
       margin: 0 $BaseGapSpace;
       // border-bottom: $OnePixelLine;
       // border-bottom: $OnePixelLine;
       border-bottom: 1px solid #eee;
       border-bottom: 1px solid #eee;

+ 2 - 1
src/modules/analysis/personnel-statistics/components/RightKeyMenu.vue

@@ -3,6 +3,7 @@
   <div ref="rkm" class="right-key-menu">
   <div ref="rkm" class="right-key-menu">
     <div class="rightKeyMenuItem" @click="emits('onSetWorkload', unref(curRow))">设置工作量</div>
     <div class="rightKeyMenuItem" @click="emits('onSetWorkload', unref(curRow))">设置工作量</div>
     <div class="rightKeyMenuItem" @click="emits('onSendMessage', unref(curRow))">发送消息</div>
     <div class="rightKeyMenuItem" @click="emits('onSendMessage', unref(curRow))">发送消息</div>
+    <div class="rightKeyMenuItem" @click="emits('onShowScoreLines', curRow)">分数分布曲线</div>
     <div
     <div
       v-if="curRow.markingStatus === '正评'"
       v-if="curRow.markingStatus === '正评'"
       class="rightKeyMenuItem"
       class="rightKeyMenuItem"
@@ -15,7 +16,7 @@
 <script setup lang="ts" name="RightKeyMenu">
 <script setup lang="ts" name="RightKeyMenu">
 import { ref, onUnmounted, unref } from 'vue'
 import { ref, onUnmounted, unref } from 'vue'
 let rkm = ref()
 let rkm = ref()
-const emits = defineEmits(['rightClick', 'onSetWorkload', 'onSendMessage', 'forceAssessment'])
+const emits = defineEmits(['rightClick', 'onSetWorkload', 'onSendMessage', 'forceAssessment', 'onShowScoreLines'])
 const fun = () => {
 const fun = () => {
   emits('rightClick')
   emits('rightClick')
 }
 }

+ 24 - 23
src/modules/analysis/personnel-statistics/components/StatisticsGroup.vue

@@ -56,7 +56,7 @@ const columns = computed(() => {
     {
     {
       label: '#',
       label: '#',
       type: 'index',
       type: 'index',
-      width: 50,
+      width: 40,
       align: 'center',
       align: 'center',
       fixed: 'left',
       fixed: 'left',
       index(index: number) {
       index(index: number) {
@@ -75,20 +75,20 @@ const columns = computed(() => {
     {
     {
       label: '评卷员',
       label: '评卷员',
       prop: 'markerName',
       prop: 'markerName',
-      minWidth: 84,
+      minWidth: 100,
       fixed: 'left',
       fixed: 'left',
       slotName: 'marker',
       slotName: 'marker',
       formatter(row: any) {
       formatter(row: any) {
         return row.markingGroupNumber === 0 ? '全体' : `第${row.markingGroupNumber}组`
         return row.markingGroupNumber === 0 ? '全体' : `第${row.markingGroupNumber}组`
       },
       },
     },
     },
-    { align: 'center', label: '评卷份数', prop: 'markingPaperCount', minWidth: 100 },
-    { align: 'center', label: '平均分', prop: 'avg', minWidth: 82 },
+    { align: 'center', label: '份数', prop: 'markingPaperCount', minWidth: 84 },
+    { align: 'center', label: '平均分', prop: 'avg', minWidth: 66 },
     {
     {
       align: 'center',
       align: 'center',
       label: '相关系数',
       label: '相关系数',
       prop: 'xyRelate',
       prop: 'xyRelate',
-      minWidth: 96,
+      minWidth: 80,
       formatter(row: any) {
       formatter(row: any) {
         let compareTarget = tableData.value.find((item: any) => item.markingGroupNumber == 0)
         let compareTarget = tableData.value.find((item: any) => item.markingGroupNumber == 0)
         if (compareTarget) {
         if (compareTarget) {
@@ -98,38 +98,39 @@ const columns = computed(() => {
         }
         }
       },
       },
     },
     },
-    { align: 'center', label: '标准差', prop: 'std', minWidth: 82 },
-    { align: 'center', label: '综合系数', prop: 'integration', minWidth: 96 },
+    { align: 'center', label: '标准差', prop: 'std', minWidth: 66 },
+    { align: 'center', label: '综合系数', prop: 'integration', minWidth: 80 },
 
 
     // { align: 'center', label: '评卷份数', prop: 'markingPaperCount', width: 92 },
     // { align: 'center', label: '评卷份数', prop: 'markingPaperCount', width: 92 },
-    { align: 'center', label: '当日可阅', prop: 'markDayCount', minWidth: 96 },
-    { align: 'center', label: '剩余可阅', prop: 'todoMarkDayCount', minWidth: 96 },
-    { align: 'center', label: '客观题0分量', prop: 'objectiveZero', minWidth: 120 },
-    { align: 'center', label: '客观平均分', prop: 'objectiveAvg', minWidth: 110 },
-    { align: 'center', label: '客观标准差', prop: 'objectiveStd', minWidth: 110 },
+    { align: 'center', label: '当日可阅', prop: 'markDayCount', minWidth: 80 },
+    { align: 'center', label: '剩余可阅', prop: 'todoMarkDayCount', minWidth: 80 },
+    { align: 'center', label: '速度', prop: 'markingRate', minWidth: 56 },
+    { align: 'center', label: '客观题0分量', prop: 'objectiveZero', minWidth: 104 },
+    { align: 'center', label: '客观平均分', prop: 'objectiveAvg', minWidth: 94 },
+    { align: 'center', label: '客观标准差', prop: 'objectiveStd', minWidth: 94 },
     {
     {
       align: 'center',
       align: 'center',
       label: '重评/待确认',
       label: '重评/待确认',
       prop: 'reMarkUnConfirmCount',
       prop: 'reMarkUnConfirmCount',
-      minWidth: 120,
+      minWidth: 104,
       formatter(row: any) {
       formatter(row: any) {
         return `${row.reMarkCount}/${row.reMarkUnConfirmCount}`
         return `${row.reMarkCount}/${row.reMarkUnConfirmCount}`
       },
       },
     },
     },
-    { align: 'center', label: '抽查量', prop: 'checkCount', minWidth: 90 },
-    { align: 'center', label: '抽查改正量', prop: 'checkCorrectCount', minWidth: 110 },
+    { align: 'center', label: '抽查量', prop: 'checkCount', minWidth: 74 },
+    { align: 'center', label: '抽查改正量', prop: 'checkCorrectCount', minWidth: 94 },
     // { align: 'center', label: '相关系数', prop: 'xyRelate', width: 90 },
     // { align: 'center', label: '相关系数', prop: 'xyRelate', width: 90 },
     // { align: 'center', label: '平均分', prop: 'avg', width: 80 },
     // { align: 'center', label: '平均分', prop: 'avg', width: 80 },
     // { align: 'center', label: '标准差', prop: 'std', width: 80 },
     // { align: 'center', label: '标准差', prop: 'std', width: 80 },
-    { align: 'center', label: '近5分钟最高分', prop: 'scoreTop', minWidth: 130 },
-    { align: 'center', label: '近5分钟最低分', prop: 'scoreLow', minWidth: 130 },
-    { align: 'center', label: '近5分钟客主比', prop: 'objSubRate', minWidth: 130 },
-    { align: 'center', label: '平均客主比', prop: 'objSubAvgRate', minWidth: 110 },
+    { align: 'center', label: '近5分钟最高分', prop: 'scoreTop', minWidth: 114 },
+    { align: 'center', label: '近5分钟最低分', prop: 'scoreLow', minWidth: 114 },
+    { align: 'center', label: '近5分钟客主比', prop: 'objSubRate', minWidth: 114 },
+    { align: 'center', label: '平均客主比', prop: 'objSubAvgRate', minWidth: 94 },
     {
     {
       align: 'center',
       align: 'center',
       label: '在线',
       label: '在线',
       prop: 'online',
       prop: 'online',
-      minWidth: 72,
+      minWidth: 56,
       formatter(row: any) {
       formatter(row: any) {
         if (row.markingGroupNumber === 0) {
         if (row.markingGroupNumber === 0) {
           return (
           return (
@@ -156,9 +157,9 @@ const columns = computed(() => {
       align: 'center',
       align: 'center',
       label: '状态',
       label: '状态',
       prop: 'markingStatus',
       prop: 'markingStatus',
-      minWidth: 100,
+      minWidth: 84,
     },
     },
-    { align: 'center', label: '速度', prop: 'markingRate', minWidth: 72 },
+
     // { align: 'center', label: '综合系数', prop: 'integration', width: 90 },
     // { align: 'center', label: '综合系数', prop: 'integration', width: 90 },
   ]
   ]
     .map((col: any) => {
     .map((col: any) => {
@@ -303,7 +304,7 @@ const getXAxisData = <K extends keyof ExtractArrayValue<StatisticObjectiveByGrou
 }
 }
 const tableHeight = computed(() => {
 const tableHeight = computed(() => {
   // return !!current.value ? 'calc(100vh - 520px)' : 'calc(100vh - 219px)'
   // return !!current.value ? 'calc(100vh - 520px)' : 'calc(100vh - 219px)'
-  return 'calc(100vh - 250px)'
+  return 'calc(100vh - 318px)'
 })
 })
 const clearCheck = () => {
 const clearCheck = () => {
   ;(elTableRef as any).value!.setCurrentRow(undefined)
   ;(elTableRef as any).value!.setCurrentRow(undefined)

+ 67 - 31
src/modules/analysis/personnel-statistics/components/StatisticsPersonnel.vue

@@ -37,16 +37,28 @@
             </el-menu-item>
             </el-menu-item>
           </el-menu>
           </el-menu>
         </el-popover> -->
         </el-popover> -->
-        <span v-if="row.markerId">{{ row.markerName }}</span>
+        <span v-if="row.markerId">
+          <span
+            :style="{
+              backgroundColor: row.online ? '#00B42A' : '#ddd',
+              display: 'inline-block',
+              width: '10px',
+              height: '10px',
+              marginRight: '3px',
+              borderRadius: '2px',
+            }"
+          ></span>
+          {{ row.markerName }}</span
+        >
         <span v-else-if="row.markingGroupNumber == 0">全体</span>
         <span v-else-if="row.markingGroupNumber == 0">全体</span>
         <span v-else>全组</span>
         <span v-else>全组</span>
       </template>
       </template>
     </base-table>
     </base-table>
   </div>
   </div>
-  <!-- <div
-    v-if="!!current && !!current?.markerId"
+  <div
+    v-if="!!current && !!current?.markerId && showCharts"
     v-loading="loading1 || loading2"
     v-loading="loading1 || loading2"
-    class="flex justify-between m-t-base charts-box"
+    class="flex justify-between charts-box"
   >
   >
     <el-button type="primary" plain size="small" class="close-panel" @click="clearCheck">关闭</el-button>
     <el-button type="primary" plain size="small" class="close-panel" @click="clearCheck">关闭</el-button>
 
 
@@ -56,7 +68,7 @@
     <div class="flex-1 p-base radius-base fill-blank chart-box">
     <div class="flex-1 p-base radius-base fill-blank chart-box">
       <vue-e-charts class="full" :option="markerObjectiveChartsOption"></vue-e-charts>
       <vue-e-charts class="full" :option="markerObjectiveChartsOption"></vue-e-charts>
     </div>
     </div>
-  </div> -->
+  </div>
   <set-workload v-model="setWorkloadVisible" :data="setWorkloadData" />
   <set-workload v-model="setWorkloadVisible" :data="setWorkloadData" />
   <right-key-menu
   <right-key-menu
     v-show="visable"
     v-show="visable"
@@ -65,6 +77,7 @@
     @on-set-workload="onSetWorkload"
     @on-set-workload="onSetWorkload"
     @on-send-message="onSendMessage"
     @on-send-message="onSendMessage"
     @force-assessment="forceAssessment"
     @force-assessment="forceAssessment"
+    @on-show-score-lines="onShowScoreLines"
   ></right-key-menu>
   ></right-key-menu>
 </template>
 </template>
 
 
@@ -90,6 +103,7 @@ const isChief = computed(() => {
   const arr = ['CHIEF', 'SECTION_LEADER', 'EXPERT']
   const arr = ['CHIEF', 'SECTION_LEADER', 'EXPERT']
   return arr.indexOf(mainStore.myUserInfo?.role || '') > -1
   return arr.indexOf(mainStore.myUserInfo?.role || '') > -1
 })
 })
+const showCharts = ref(false)
 const rightKeyMenu = ref(null)
 const rightKeyMenu = ref(null)
 const rightClick = () => {
 const rightClick = () => {
   visable.value = false
   visable.value = false
@@ -117,7 +131,7 @@ const columns = computed(() => {
     {
     {
       label: '#',
       label: '#',
       type: 'index',
       type: 'index',
-      width: 50,
+      width: 40,
       align: 'center',
       align: 'center',
       fixed: 'left',
       fixed: 'left',
       index(index: number) {
       index(index: number) {
@@ -133,15 +147,15 @@ const columns = computed(() => {
         return row.markingGroupNumber === 0 ? '全部' : `第${row.markingGroupNumber}组`
         return row.markingGroupNumber === 0 ? '全部' : `第${row.markingGroupNumber}组`
       },
       },
     },
     },
-    { label: '评卷员', prop: 'markerName', minWidth: 84, slotName: 'marker', fixed: 'left' },
+    { label: '评卷员', prop: 'markerName', minWidth: 100, slotName: 'marker', fixed: 'left' },
 
 
-    { align: 'center', label: '评卷份数', prop: 'markingPaperCount', minWidth: 96 },
-    { align: 'center', label: '平均分', prop: 'avg', minWidth: 80 },
+    { align: 'center', label: '份数', prop: 'markingPaperCount', minWidth: 80 },
+    { align: 'center', label: '平均分', prop: 'avg', minWidth: 64 },
     {
     {
       align: 'center',
       align: 'center',
       label: '相关系数',
       label: '相关系数',
       prop: 'xyRelate',
       prop: 'xyRelate',
-      minWidth: 96,
+      minWidth: 80,
       formatter(row: any) {
       formatter(row: any) {
         let r = unref(props.result) || []
         let r = unref(props.result) || []
         const { markingGroupNumber } = row
         const { markingGroupNumber } = row
@@ -160,38 +174,39 @@ const columns = computed(() => {
         }
         }
       },
       },
     },
     },
-    { align: 'center', label: '标准差', prop: 'std', minWidth: 80 },
-    { align: 'center', label: '综合系数', prop: 'integration', minWidth: 96 },
+    { align: 'center', label: '标准差', prop: 'std', minWidth: 64 },
+    { align: 'center', label: '综合系数', prop: 'integration', minWidth: 80 },
 
 
     // { align: 'center', label: '评卷份数', prop: 'markingPaperCount', width: 92 },
     // { align: 'center', label: '评卷份数', prop: 'markingPaperCount', width: 92 },
-    { align: 'center', label: '当日可阅', prop: 'markDayCount', minWidth: 96 },
-    { align: 'center', label: '剩余可阅', prop: 'todoMarkDayCount', minWidth: 96 },
-    { align: 'center', label: '客观题0分量', prop: 'objectiveZero', minWidth: 120 },
-    { align: 'center', label: '客观平均分', prop: 'objectiveAvg', minWidth: 110 },
-    { align: 'center', label: '客观标准差', prop: 'objectiveStd', minWidth: 110 },
+    { align: 'center', label: '当日可阅', prop: 'markDayCount', minWidth: 80 },
+    { align: 'center', label: '剩余可阅', prop: 'todoMarkDayCount', minWidth: 80 },
+    { align: 'center', label: '速度', prop: 'markingRate', minWidth: 56 },
+    { align: 'center', label: '客观题0分量', prop: 'objectiveZero', minWidth: 104 },
+    { align: 'center', label: '客观平均分', prop: 'objectiveAvg', minWidth: 94 },
+    { align: 'center', label: '客观标准差', prop: 'objectiveStd', minWidth: 94 },
     {
     {
       align: 'center',
       align: 'center',
       label: '重评/待确认',
       label: '重评/待确认',
       prop: 'reMarkUnConfirmCount',
       prop: 'reMarkUnConfirmCount',
-      minWidth: 120,
+      minWidth: 104,
       formatter(row: any) {
       formatter(row: any) {
         return `${row.reMarkCount}/${row.reMarkUnConfirmCount}`
         return `${row.reMarkCount}/${row.reMarkUnConfirmCount}`
       },
       },
     },
     },
-    { align: 'center', label: '抽查量', prop: 'checkCount', minWidth: 90 },
-    { align: 'center', label: '抽查改正量', prop: 'checkCorrectCount', minWidth: 110 },
+    { align: 'center', label: '抽查量', prop: 'checkCount', minWidth: 74 },
+    { align: 'center', label: '抽查改正量', prop: 'checkCorrectCount', minWidth: 94 },
     // { align: 'center', label: '相关系数', prop: 'xyRelate', width: 90 },
     // { align: 'center', label: '相关系数', prop: 'xyRelate', width: 90 },
     // { align: 'center', label: '平均分', prop: 'avg', width: 80 },
     // { align: 'center', label: '平均分', prop: 'avg', width: 80 },
     // { align: 'center', label: '标准差', prop: 'std', width: 80 },
     // { align: 'center', label: '标准差', prop: 'std', width: 80 },
-    { align: 'center', label: '近5分钟最高分', prop: 'scoreTop', minWidth: 130 },
-    { align: 'center', label: '近5分钟最低分', prop: 'scoreLow', minWidth: 130 },
-    { align: 'center', label: '近5分钟客主比', prop: 'objSubRate', minWidth: 130 },
-    { align: 'center', label: '平均客主比', prop: 'objSubAvgRate', minWidth: 110 },
+    { align: 'center', label: '近5分钟最高分', prop: 'scoreTop', minWidth: 114 },
+    { align: 'center', label: '近5分钟最低分', prop: 'scoreLow', minWidth: 114 },
+    { align: 'center', label: '近5分钟客主比', prop: 'objSubRate', minWidth: 114 },
+    { align: 'center', label: '平均客主比', prop: 'objSubAvgRate', minWidth: 96 },
     {
     {
       align: 'center',
       align: 'center',
       label: '在线',
       label: '在线',
       prop: 'online',
       prop: 'online',
-      minWidth: 72,
+      minWidth: 56,
       formatter(row: any) {
       formatter(row: any) {
         if (row.markingGroupNumber === 0) {
         if (row.markingGroupNumber === 0) {
           let total = (unref(props.result) || [])
           let total = (unref(props.result) || [])
@@ -218,8 +233,8 @@ const columns = computed(() => {
         }
         }
       },
       },
     },
     },
-    { align: 'center', label: '状态', prop: 'markingStatus', minWidth: 100 },
-    { align: 'center', label: '速度', prop: 'markingRate', minWidth: 72 },
+    { align: 'center', label: '状态', prop: 'markingStatus', minWidth: 84 },
+
     // { align: 'center', label: '综合系数', prop: 'integration', width: 90 },
     // { align: 'center', label: '综合系数', prop: 'integration', width: 90 },
   ]
   ]
     .map((col: any) => {
     .map((col: any) => {
@@ -239,7 +254,6 @@ const rowContextmenu = (row: any, column: any, event: any) => {
   }, 50)
   }, 50)
   event.preventDefault()
   event.preventDefault()
   nextTick(() => {
   nextTick(() => {
-    // alert(1)
     ;(rightKeyMenu.value as any).onload(row, column, event)
     ;(rightKeyMenu.value as any).onload(row, column, event)
   })
   })
 }
 }
@@ -274,6 +288,10 @@ function onSendMessage(data: ExtractArrayValue<ExtractApiResponse<'getStatistics
   setReplyUserId?.(data.markerId)
   setReplyUserId?.(data.markerId)
   setMessageVisible?.(true)
   setMessageVisible?.(true)
 }
 }
+function onShowScoreLines(row: any) {
+  showCharts.value = true
+  ;(elTableRef as any).value!.setCurrentRow(row)
+}
 function forceAssessment(data: ExtractArrayValue<ExtractApiResponse<'getStatisticsByGroup'>>) {
 function forceAssessment(data: ExtractArrayValue<ExtractApiResponse<'getStatisticsByGroup'>>) {
   push({
   push({
     name: 'MarkingAssess',
     name: 'MarkingAssess',
@@ -417,6 +435,13 @@ const getXAxisData = <K extends keyof ExtractArrayValue<StatisticObjectiveByMark
 
 
 const markerSubjectiveChartsOption = computed<EChartsOption>(() => {
 const markerSubjectiveChartsOption = computed<EChartsOption>(() => {
   return {
   return {
+    grid: {
+      top: 34,
+      bottom: 0,
+      left: 15,
+      right: 15,
+      containLabel: true,
+    },
     legend: {
     legend: {
       right: 0,
       right: 0,
       itemWidth: 14,
       itemWidth: 14,
@@ -474,6 +499,13 @@ const markerSubjectiveChartsOption = computed<EChartsOption>(() => {
 
 
 const markerObjectiveChartsOption = computed<EChartsOption>(() => {
 const markerObjectiveChartsOption = computed<EChartsOption>(() => {
   return {
   return {
+    grid: {
+      top: 34,
+      bottom: 0,
+      left: 15,
+      right: 15,
+      containLabel: true,
+    },
     legend: {
     legend: {
       right: 0,
       right: 0,
       itemWidth: 14,
       itemWidth: 14,
@@ -529,11 +561,14 @@ const markerObjectiveChartsOption = computed<EChartsOption>(() => {
   }
   }
 })
 })
 const tableHeight = computed(() => {
 const tableHeight = computed(() => {
-  // return !!current.value && !!current.value?.markerId ? 'calc(100vh - 520px)' : 'calc(100vh - 219px)'
-  return 'calc(100vh - 250px)'
+  return !!current.value && !!current.value?.markerId && showCharts.value
+    ? 'calc(100vh - 482px)'
+    : 'calc(100vh - 318px)'
+  // return 'calc(100vh - 250px)'
 })
 })
 const clearCheck = () => {
 const clearCheck = () => {
   ;(elTableRef as any).value!.setCurrentRow(undefined)
   ;(elTableRef as any).value!.setCurrentRow(undefined)
+  showCharts.value = false
 }
 }
 </script>
 </script>
 
 
@@ -563,10 +598,11 @@ const clearCheck = () => {
   }
   }
 }
 }
 .chart-box {
 .chart-box {
-  height: 293px;
+  height: 160px;
 }
 }
 .charts-box {
 .charts-box {
   position: relative;
   position: relative;
+  margin-top: 5px;
   .close-panel {
   .close-panel {
     position: absolute;
     position: absolute;
     top: 50%;
     top: 50%;

+ 30 - 7
src/modules/analysis/personnel-statistics/index.vue

@@ -160,20 +160,31 @@ const data = computed<ExtractApiResponse<'getStatisticsByGroup'>>(() => {
       }
       }
     })
     })
     .filter((v: any) => !!v)
     .filter((v: any) => !!v)
-  // alert(model.markingGroupNumber)
   const totalIndex = groupList.findIndex((v) => v.markingGroupNumber === 0)
   const totalIndex = groupList.findIndex((v) => v.markingGroupNumber === 0)
+  // let expandData = groupList
+  //   .filter((v) => v.markingGroupNumber !== 0)
+  //   .reduce((total, cur) => {
+  //     total.push(...(cur.markerDetails || []))
+  //     return total
+  //   }, [] as ExtractApiResponse<'getStatisticsByGroup'>)
+  //   .sort((a: any, b: any) => a.markerId - b.markerId)
+  //   .concat(totalIndex >= 0 ? groupList[totalIndex] : [])
+  // let topGroupRow = groupList.find((v) => v.markingGroupNumber == model.markingGroupNumber)
+  // if (model.markingGroupNumber && topGroupRow) {
+  //   expandData.unshift({ ...topGroupRow, isGroupTotalRow: true })
+  // }
+
   let expandData = groupList
   let expandData = groupList
     .filter((v) => v.markingGroupNumber !== 0)
     .filter((v) => v.markingGroupNumber !== 0)
     .reduce((total, cur) => {
     .reduce((total, cur) => {
-      total.push(...(cur.markerDetails || []))
+      total.push({ ...cur, isGroupTotalRow: true })
+      let details = cur.markerDetails || []
+      details.sort((a: any, b: any) => a.markerId - b.markerId)
+      total.push(...details)
       return total
       return total
     }, [] as ExtractApiResponse<'getStatisticsByGroup'>)
     }, [] as ExtractApiResponse<'getStatisticsByGroup'>)
-    .sort((a: any, b: any) => a.markerId - b.markerId)
     .concat(totalIndex >= 0 ? groupList[totalIndex] : [])
     .concat(totalIndex >= 0 ? groupList[totalIndex] : [])
-  let topGroupRow = groupList.find((v) => v.markingGroupNumber == model.markingGroupNumber)
-  if (model.markingGroupNumber && topGroupRow) {
-    expandData.unshift({ ...topGroupRow, isGroupTotalRow: true })
-  }
+
   return fetchModel.value.expand
   return fetchModel.value.expand
     ? expandData
     ? expandData
     : groupList.sort((a: any, b: any) => (a.markingGroupNumber as number) - (b.markingGroupNumber as number))
     : groupList.sort((a: any, b: any) => (a.markingGroupNumber as number) - (b.markingGroupNumber as number))
@@ -211,6 +222,18 @@ function onExport() {
   .filter-form {
   .filter-form {
     border-bottom: $OnePixelLine;
     border-bottom: $OnePixelLine;
   }
   }
+  :deep(.el-table__header .el-table__cell > .cell) {
+    padding: 0;
+    .caret-wrapper {
+      width: 16px;
+      .sort-caret {
+        left: 4px;
+      }
+    }
+  }
+  :deep(.el-table__body .el-table__cell > .cell) {
+    padding: 0 5px;
+  }
   :deep(.setting-box) {
   :deep(.setting-box) {
     width: 100%;
     width: 100%;
     display: flex;
     display: flex;

+ 1 - 1
src/modules/monitor/training-monitoring/index.vue

@@ -78,7 +78,7 @@ import type { EpTableColumn } from 'global-type'
 type TableDataType = ExtractArrayValue<ExtractApiResponse<'getTrainingMonitor'>['data']>
 type TableDataType = ExtractArrayValue<ExtractApiResponse<'getTrainingMonitor'>['data']>
 const tableMaxHeight = ref(400)
 const tableMaxHeight = ref(400)
 onBeforeMount(() => {
 onBeforeMount(() => {
-  tableMaxHeight.value = window.innerHeight - 240
+  tableMaxHeight.value = window.innerHeight - 310
 })
 })
 const { push } = useRouter()
 const { push } = useRouter()