浏览代码

组长监控柱状图,任务设置按评卷员选择,评卷员列表大数据表格组件封装

刘洋 1 年之前
父节点
当前提交
a61bdd66b4

+ 2 - 1
package.json

@@ -36,7 +36,8 @@
     "splitpanes": "^3.1.5",
     "vue": "3.2.40",
     "vue-echarts": "6.2.3",
-    "vue-router": "4.1.5"
+    "vue-router": "4.1.5",
+    "vxe-table": "^4.5.21"
   },
   "devDependencies": {
     "@types/big.js": "^6.1.6",

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

@@ -142,6 +142,7 @@ export namespace System {
   type GetStudentImportStatus = BaseDefine<null, { importing: boolean; progress: number }>
   type imortAndExportList = BaseDefine<MultipleQuery<{ taskType?: string }>, MultipleResult<importOrExportItem>>
   type removeImportOrExport = BaseDefine<{ id: string }>
+  type AdminGetMarkers = BaseDefine<any, any>
   export interface ApiMap {
     importMarkingData: ImportMarkingData
     /** 创建评卷分配表 */
@@ -166,5 +167,6 @@ export namespace System {
     imortAndExportList: imortAndExportList
     /** 删除单条导入导出记录 */
     removeImportOrExport: removeImportOrExport
+    adminGetMarkers: AdminGetMarkers
   }
 }

+ 1 - 0
src/api/system.ts

@@ -50,6 +50,7 @@ const SystemApi: DefineApiModule<System.ApiMap> = {
   removeImportOrExport: '/api/operate/task/remove',
   /** 导入导出记录 */
   imortAndExportList: '/api/operate/task/page',
+  adminGetMarkers: '/api/user/marker/group/all',
   /** 任务设置 - 按评卷员设置 */
   markerSetCount: {
     url: '/api/user/marker/add/count',

+ 83 - 0
src/components/common/ChooseMarkers.vue

@@ -0,0 +1,83 @@
+<template>
+  <div class="choose-markers">
+    <el-button type="primary" :disabled="!subjectCode || !mainNumber" @click="modalVisible = true"
+      >选择评卷员{{ confirmResult?.length ? `(已选${confirmResult.length}人)` : '' }}</el-button
+    >
+    <base-dialog v-model="modalVisible" title="选择评卷员" :width="600" class="marker-dialog">
+      <vxe-table
+        :max-height="tableMaxHeight"
+        :column-config="{ resizable: true }"
+        :tree-config="{ childrenField: 'markers', rowField: 'id', expandAll: true }"
+        :data="tableData"
+        :checkbox-config="{ highlight: false }"
+        :scroll-y="{ enabled: true }"
+        @checkbox-change="selectChangeEvent"
+      >
+        <vxe-column type="checkbox" title="ID" width="280" tree-node></vxe-column>
+        <vxe-column field="showName" title="姓名"></vxe-column>
+      </vxe-table>
+      <template #footer>
+        <div class="flex justify-end">
+          <confirm-button
+            :disabled="!chooseResult.length"
+            @confirm="confirm"
+            @cancel="modalVisible = false"
+          ></confirm-button>
+        </div>
+      </template>
+    </base-dialog>
+  </div>
+</template>
+
+<script name="ChooseMarkers" lang="ts" setup>
+import { watch, ref, computed } from 'vue'
+import useFetch from '@/hooks/useFetch'
+import { ElButton } from 'element-plus'
+import BaseDialog from '../element/BaseDialog.vue'
+import { VxeTableEvents } from 'vxe-table'
+import ConfirmButton from '@/components/common/ConfirmButton.vue'
+import { cloneDeep } from 'lodash-es'
+
+const emits = defineEmits(['user-list'])
+const tableMaxHeight = window.innerHeight - 150 + 'px'
+const modalVisible = ref(false)
+const { fetch: fetchMarkers, result } = useFetch('adminGetMarkers')
+const tableData = computed(() => {
+  return (result.value || []).map((item: any) => {
+    item.showName = `第${item.markingGroupNumber}组`
+    !item.id && (item.id = '_' + item.markingGroupNumber)
+    item.markers = (item.markers || []).map((v: any) => {
+      v.showName = v.loginName + '-' + v.name
+      return v
+    })
+    return item
+  })
+})
+const props = defineProps<{
+  subjectCode: string | number | undefined
+  mainNumber: string | number | undefined
+}>()
+watch([() => props.subjectCode, () => props.mainNumber], (valArr) => {
+  if (valArr[0] && valArr[1]) {
+    fetchMarkers({ subjectCode: valArr[0], mainNumber: valArr[1] })
+  }
+})
+const chooseResult = ref<any>([])
+const confirmResult = ref<any>([])
+const selectChangeEvent: VxeTableEvents.CheckboxChange<any> = ({ $table }) => {
+  const records = $table.getCheckboxRecords()
+  console.info(`勾选${records.length}个树形节点`, records)
+  chooseResult.value = records.filter((item) => !!item.loginName)
+}
+const confirm = () => {
+  confirmResult.value = cloneDeep(chooseResult.value)
+  emits('user-list', [...confirmResult.value])
+  modalVisible.value = false
+}
+</script>
+
+<style lang="scss" scoped>
+.choose-markers {
+  max-height: 100vh;
+}
+</style>

+ 4 - 1
src/hooks/useDayListInGroup.ts

@@ -1,12 +1,15 @@
 import { ref, computed, watch } from 'vue'
 import useFetch from './useFetch'
+import useMainStore from '@/store/main'
 
 const useDayOptions = (dataModel: any) => {
+  const mainStore = useMainStore()
   const dayList = ref([])
   function fetchDayList() {
     if (dataModel.subject && dataModel.question) {
       useFetch('getDayListInGroup')
-        .fetch({ subjectCode: dataModel.subject, questionMainNumber: dataModel.question })
+        // .fetch({ subjectCode: dataModel.subject, questionMainNumber: dataModel.question })
+        .fetch({ examId: mainStore.myUserInfo?.examId })
         .then((res: any) => {
           dayList.value = res.map((item: any) => ({ label: item.value, value: item.key }))
         })

+ 1 - 1
src/hooks/useOptions.ts

@@ -75,7 +75,7 @@ const useOptions = (
       console.log('changeModelValue', key, v)
       // dataModel[key] = v
 
-      if (multGroup && key === 'group') {
+      if (multGroup && showAllLabel && key === 'group') {
         if (v.includes(undefined)) {
           if (dataModel[key]?.length === groupListWithAll.value.length) {
             dataModel[key] = v.filter((item: any) => !!item)

+ 9 - 4
src/main.ts

@@ -1,21 +1,26 @@
-import { createApp } from 'vue'
+import { createApp, App } from 'vue'
 import { createPinia } from 'pinia'
 import router from '@/router'
-import App from '@/App.vue'
+import AppCom from '@/App.vue'
 import useECharts from '@/plugins/echarts'
 import bootstrap from '@/bootstrap'
 import { setupDirectives } from '@/directives'
 import 'virtual:svg-icons-register'
 import { ElLoading, ElTooltip } from 'element-plus'
 import { DatePicker, RangePicker } from 'ant-design-vue'
+import VXETable from 'vxe-table'
+import 'vxe-table/lib/style.css'
 import 'dayjs/locale/zh-cn'
 import 'element-plus/theme-chalk/el-loading.css'
 import '@style/app.scss'
 import 'element-plus/theme-chalk/src/message.scss'
 import 'splitpanes/dist/splitpanes.css'
-const app = createApp(App)
+const app = createApp(AppCom)
 setupDirectives(app)
-app.use(createPinia()).use(router).use(ElLoading).use(ElTooltip).use(DatePicker).use(RangePicker)
+function useTable(app: App) {
+  app.use(VXETable)
+}
+app.use(createPinia()).use(router).use(ElLoading).use(ElTooltip).use(DatePicker).use(RangePicker).use(useTable)
 useECharts()
 
 app.mount('#app')

+ 7 - 5
src/modules/admin-data/task-setting/components/GroupSetting.vue

@@ -1,10 +1,10 @@
 <template>
-  <base-table border stripe size="small" height="100%" :columns="columns" :data="taskDetail"></base-table>
+  <base-table border stripe size="small" height="100%" :columns="columns" :data="tableData"></base-table>
 </template>
 
 <script setup lang="ts" name="GroupSetting">
 /** 任务设置 - 按小组设置 */
-import { watch } from 'vue'
+import { watch, computed } from 'vue'
 import useFetch from '@/hooks/useFetch'
 import BaseTable from '@/components/element/BaseTable.vue'
 
@@ -12,7 +12,7 @@ import type { EpTableColumn } from 'global-type'
 
 const props = defineProps<{
   mainNumber?: number | string
-  markingGroupNumbers?: number | string
+  markingGroupNumbers?: any
   subjectCode?: string
 }>()
 
@@ -23,7 +23,9 @@ const columns: EpTableColumn[] = [
   { label: '计划量', prop: 'markCount' },
   { label: '已完成量', prop: 'finishCount' },
 ]
-
+const tableData = computed(() => {
+  return !props.markingGroupNumbers?.length ? [] : taskDetail.value
+})
 watch(
   props,
   () => {
@@ -36,7 +38,7 @@ watch(
       getTaskDetail({ ...props })
     }
   },
-  { immediate: true }
+  { immediate: true, deep: true }
 )
 </script>
 

+ 18 - 4
src/modules/admin-data/task-setting/index.vue

@@ -12,19 +12,27 @@
         <template #form-item-un-mark>
           <span class="un-mark-count">{{ unMarkTasks?.unmarkCount ?? 0 }}</span>
         </template>
+        <template #form-item-chooseMarkers>
+          <choose-markers
+            :subject-code="taskSettingModel.subjectCode"
+            :main-number="taskSettingModel.mainNumber"
+            @user-list="onUserListChange"
+          ></choose-markers>
+        </template>
         <template #form-item-confirm>
           <el-button :loading="loading" type="primary" @click="onSubmit">{{
             isGroupSetting ? '确认追加' : '确定'
           }}</el-button>
         </template>
       </base-form>
-      <div class="flex-1 overflow-hidden m-t-base">
-        <component
+      <div v-if="isGroupSetting" class="flex-1 overflow-hidden m-t-base">
+        <!-- <component
           :is="TableComponent"
           v-bind="taskSettingModel"
           :key="refresh"
           @user-list="onUserListChange"
-        ></component>
+        ></component> -->
+        <group-setting v-bind="taskSettingModel" :key="refresh" @user-list="onUserListChange"></group-setting>
       </div>
     </div>
   </div>
@@ -41,7 +49,7 @@ import useVW from '@/hooks/useVW'
 import BaseForm from '@/components/element/BaseForm.vue'
 import GroupSetting from './components/GroupSetting.vue'
 import MarkerSetting from './components/MarkerSetting.vue'
-
+import ChooseMarkers from '@/components/common/ChooseMarkers.vue'
 import type { ExtractApiParams, ExtractMultipleApiResponse } from '@/api/api'
 import type { EpFormRules, EpFormItem } from 'global-type'
 
@@ -183,6 +191,12 @@ const items = computed<EpFormItem[]>(() => [
     slotName: 'un-mark',
     hidden: !isGroupSetting.value,
   }),
+  Span7({
+    rowKey: 'row-2',
+    label: '评卷员',
+    slotName: 'chooseMarkers',
+    hidden: isGroupSetting.value,
+  }),
   Span7({
     rowKey: 'row-3',
     label: '任务数设置',

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

@@ -27,12 +27,19 @@
           </template>
         </base-table>
       </div>
+
+      <div class="radius-base m-t-base p-l-base p-r-base p-t-mini fill-blank p-b-mini">
+        <div class="chart-wrap">
+          <vue-echarts :option="chartOptions" autoresize></vue-echarts>
+        </div>
+      </div>
     </div>
   </div>
 </template>
 
 <script setup lang="tsx" name="AnalysisGroupMonitoring">
 /** 小组监控 */
+import { computed } from 'vue'
 import { useRouter } from 'vue-router'
 import { ElButton } from 'element-plus'
 import BaseForm from '@/components/element/BaseForm.vue'
@@ -41,6 +48,7 @@ import useFetch from '@/hooks/useFetch'
 import useVW from '@/hooks/useVW'
 import useFormFilter from './hooks/useFormFilter'
 import { reactive } from 'vue'
+import VueEcharts from 'vue-echarts'
 import type { EpTableColumn } from 'global-type'
 import type { ExtractApiResponse } from '@/api/api'
 const jumpParams = reactive<any>({
@@ -134,6 +142,83 @@ function viewMonitoringDetail(
 }
 
 onOptionInit(onSearch)
+
+const chartOptions = computed(() => {
+  return {
+    grid: {
+      top: 50,
+      bottom: 15,
+      left: 30,
+      right: 30,
+      containLabel: true,
+    },
+    legend: {
+      top: 10,
+      itemWidth: 14,
+      data: ['已浏览', '已给分'],
+    },
+    tooltip: {
+      trigger: 'item',
+      triggerOn: 'mousemove',
+    },
+    xAxis: {
+      axisLine: { show: false },
+      axisTick: { show: false },
+      splitLine: { show: false },
+      // axisLabel: {
+      //   align: 'right',
+      // },
+      data: result.value?.map((item) => item.markingGroupLeader) || [],
+    },
+    yAxis: {
+      axisTick: { show: false },
+      type: 'value',
+    },
+
+    series: [
+      {
+        name: '已浏览',
+        type: 'bar',
+        itemStyle: {
+          color: '#0064FF',
+        },
+        data: result.value?.map((item) => item.totalCount) || [],
+        label: {
+          show: true,
+          color: '#444',
+          fontSize: 10,
+          position: 'top',
+          formatter({ value }) {
+            return value > 0 ? `${value}` : ''
+          },
+        },
+      },
+      {
+        name: '已给分',
+        type: 'bar',
+        itemStyle: {
+          color: '#3AD500',
+        },
+        data: result.value?.map((item) => item.totalReScoreCount) || [],
+        label: {
+          show: true,
+          color: '#444',
+          fontSize: 10,
+          position: 'top',
+          formatter({ value }) {
+            return value > 0 ? `${value}` : ''
+          },
+        },
+      },
+    ],
+  }
+})
 </script>
 
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.group-monitoring-view {
+  .chart-wrap {
+    height: 300px;
+  }
+}
+</style>