index.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <template>
  2. <div class="flex direction-column full training-monitoring-view">
  3. <div class="p-l-base p-r-base p-t-medium-base fill-blank filter-form">
  4. <base-form ref="formRef" size="small" :label-width="useVW(84)" :disabled="loading" :model="model" :items="items">
  5. <template #form-item-operation>
  6. <el-button type="primary" @click="onSearch">查询</el-button>
  7. </template>
  8. </base-form>
  9. </div>
  10. <div class="flex-1 p-base">
  11. <div class="radius-base p-base fill-blank">
  12. <div class="flex items m-b-base">
  13. <el-button size="small" :disabled="!hasSelected" type="primary" @click="onAssessPass(true)">
  14. 考核通过
  15. </el-button>
  16. <el-button size="small" :disabled="!hasSelected" type="primary" plain @click="onAssessPass(false)">
  17. 考核不通过
  18. </el-button>
  19. <!-- <el-button size="small" type="primary" custom-1 @click="viewPaper(false)">查看试卷</el-button> -->
  20. </div>
  21. <base-table
  22. :columns="columns"
  23. :data="trainingMonitor?.data"
  24. @selection-change="onSectionChange"
  25. @row-dblclick="onDbClick"
  26. >
  27. </base-table>
  28. </div>
  29. </div>
  30. </div>
  31. </template>
  32. <script setup lang="tsx" name="TrainingMonitoring">
  33. /** 培训监控 */
  34. import { computed } from 'vue'
  35. import { useRouter } from 'vue-router'
  36. import { ElButton, ElMessage } from 'element-plus'
  37. import { minus } from '@/utils/common'
  38. import BaseForm from '@/components/element/BaseForm.vue'
  39. import BaseTable from '@/components/element/BaseTable.vue'
  40. import useVW from '@/hooks/useVW'
  41. import useFetch from '@/hooks/useFetch'
  42. import useSection from '@/hooks/useSection'
  43. import useFormFilter from './hooks/useFormFilter'
  44. import type { ExtractApiResponse } from 'api-type'
  45. import type { EpTableColumn } from 'global-type'
  46. type TableDataType = ExtractArrayValue<ExtractApiResponse<'getTrainingMonitor'>['data']>
  47. const { push } = useRouter()
  48. const { diffShow, model, items, onOptionInit } = useFormFilter()
  49. /** 培训监控列表 */
  50. const { fetch: getTrainingMonitor, result: trainingMonitor, loading } = useFetch('getTrainingMonitor')
  51. /** 培训卷审核 */
  52. const { fetch: putSampleMonitorPass } = useFetch('putSampleMonitorPass')
  53. /** 强制考核卷审核 */
  54. const { fetch: putAssessMonitorPass } = useFetch('putAssessMonitorPass')
  55. const { hasSelected, selectedList, onSectionChange } = useSection<TableDataType>()
  56. const columns = computed<EpTableColumn<TableDataType>[]>(() => {
  57. const standardScores = trainingMonitor?.value?.data?.[0]?.scoreList
  58. const cols: EpTableColumn<TableDataType>[] =
  59. trainingMonitor?.value?.header?.map((h) => ({
  60. label: `${h}`,
  61. width: 52,
  62. formatter(row) {
  63. if (!row.markerId) {
  64. return `${row.scoreList[h - 1]}`
  65. }
  66. const score = row.scoreList[h - 1]
  67. const standardScore = standardScores[h - 1]
  68. return (
  69. <span style={{ color: minus(score, standardScore) ? '#f00' : 'inherit' }}>
  70. {diffShow.value ? minus(score, standardScore) : score}
  71. </span>
  72. )
  73. },
  74. })) || []
  75. return [
  76. {
  77. type: 'selection',
  78. slotName: 'xxx',
  79. selectable(row) {
  80. return !!row.markerId
  81. },
  82. },
  83. { label: '评卷员', prop: 'markerName' },
  84. { label: '状态', prop: 'status' },
  85. { label: '平均分', prop: 'avg' },
  86. { label: '标准差', prop: 'std' },
  87. { label: '相关系数', prop: 'xyRelate' },
  88. { label: '差异份数', prop: 'diffCount' },
  89. ...cols,
  90. ]
  91. })
  92. /** 刷新按钮 */
  93. function onSearch() {
  94. const { diffShow, ...params } = model || {}
  95. getTrainingMonitor(params)
  96. }
  97. /** 通过/不通过 */
  98. const onAssessPass = async (pass: boolean) => {
  99. if (!hasSelected.value) {
  100. return ElMessage.warning('未勾选考核人员')
  101. }
  102. const selectedData = selectedList.reduce((serialize, data) => {
  103. serialize[data.stage] ??= []
  104. serialize[data.stage].push(data)
  105. return serialize
  106. }, {} as Record<string, TableDataType[]>)
  107. const fetchList = Object.entries(selectedData).map(([stage, selected]) => {
  108. const forceGroupMarkerIds = selected.map((d) => d.forceGroupMarkerId)
  109. const markerIds = selected.map((d) => d.markerId)
  110. return stage === 'FORCE'
  111. ? putAssessMonitorPass({ forceGroupMarkerIds, pass })
  112. : putSampleMonitorPass({ markerIds, markStage: stage as SamplePaperType, pass })
  113. })
  114. await Promise.allSettled(fetchList)
  115. onSearch()
  116. }
  117. /** 双击跳转详情 */
  118. const onDbClick = (row: TableDataType) => {
  119. if (row.markerId) {
  120. push({
  121. name: 'TrainingDetail',
  122. query: {
  123. stage: row.stage,
  124. markerId: row.markerId,
  125. forceGroupMarkerId: row.forceGroupMarkerId,
  126. },
  127. })
  128. }
  129. }
  130. onOptionInit(onSearch)
  131. </script>
  132. <style scoped lang="scss">
  133. .training-monitoring {
  134. }
  135. </style>