index.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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" style="padding-bottom: 10px">
  4. <base-form
  5. ref="formRef"
  6. size="small"
  7. :label-width="useVW(100)"
  8. :disabled="loading"
  9. :model="model"
  10. :rules="rules"
  11. :items="items"
  12. >
  13. <template #form-item-operation>
  14. <el-button type="primary" @click="onSearch">查询</el-button>
  15. </template>
  16. </base-form>
  17. </div>
  18. <div class="flex-1 p-base">
  19. <div class="radius-base p-base fill-blank">
  20. <div class="flex items m-b-base">
  21. <el-button
  22. size="small"
  23. :disabled="!hasSelected"
  24. :loading="putSampleIng || putAssessIng"
  25. type="primary"
  26. @click="onAssessPass(true)"
  27. >
  28. 考核通过
  29. </el-button>
  30. <el-button
  31. size="small"
  32. :disabled="!hasSelected"
  33. :loading="putSampleIng || putAssessIng"
  34. type="primary"
  35. plain
  36. @click="onAssessPass(false)"
  37. >
  38. 考核不通过
  39. </el-button>
  40. <!-- <el-button size="small" type="primary" custom-1 @click="viewPaper(false)">查看试卷</el-button> -->
  41. </div>
  42. <base-table
  43. :max-height="tableMaxHeight"
  44. border
  45. stripe
  46. size="small"
  47. :columns="columns"
  48. :data="trainingMonitor?.data"
  49. @selection-change="onSectionChange"
  50. @row-dblclick="onDbClick"
  51. >
  52. </base-table>
  53. </div>
  54. </div>
  55. </div>
  56. </template>
  57. <script setup lang="tsx" name="TrainingMonitoring">
  58. /** 培训监控 */
  59. import { computed, onBeforeUnmount, onBeforeMount, ref } from 'vue'
  60. import { useRouter } from 'vue-router'
  61. import { ElButton, ElMessage } from 'element-plus'
  62. import { minus, isDefine } from '@/utils/common'
  63. import BaseForm from '@/components/element/BaseForm.vue'
  64. import BaseTable from '@/components/element/BaseTable.vue'
  65. import useVW from '@/hooks/useVW'
  66. import useFetch from '@/hooks/useFetch'
  67. import useSection from '@/hooks/useSection'
  68. import useFormFilter from './hooks/useFormFilter'
  69. import type { ExtractApiResponse } from '@/api/api'
  70. import type { EpTableColumn } from 'global-type'
  71. type TableDataType = ExtractArrayValue<ExtractApiResponse<'getTrainingMonitor'>['data']>
  72. const tableMaxHeight = ref(300)
  73. onBeforeMount(() => {
  74. tableMaxHeight.value = window.innerHeight - 300
  75. })
  76. const { push } = useRouter()
  77. const { diffShow, model, items, rules, formRef, elFormRef, onOptionInit } = useFormFilter()
  78. /** 培训监控列表 */
  79. const { fetch: getTrainingMonitor, result: trainingMonitor, loading } = useFetch('getTrainingMonitor')
  80. /** 培训卷审核 */
  81. const { fetch: putSampleMonitorPass, loading: putSampleIng } = useFetch('putSampleMonitorPass')
  82. /** 强制考核卷审核 */
  83. const { fetch: putAssessMonitorPass, loading: putAssessIng } = useFetch('putAssessMonitorPass')
  84. const { hasSelected, selectedList, onSectionChange } = useSection<TableDataType>()
  85. const columns = computed<EpTableColumn<TableDataType>[]>(() => {
  86. const standardScores = trainingMonitor?.value?.data?.[0]?.scoreList
  87. const cols: EpTableColumn<TableDataType>[] =
  88. trainingMonitor?.value?.header?.map((h, i) => ({
  89. label: `${h}`,
  90. formatter(row) {
  91. if (!row.markerId) {
  92. return `${row.scoreList[i]}`
  93. }
  94. const score = row.scoreList[i]
  95. const standardScore = standardScores[i]
  96. const diff = isDefine(score) ? minus(score, standardScore) : ''
  97. return <span style={{ color: diff ? '#f00' : 'inherit' }}>{diffShow.value ? diff : score}</span>
  98. },
  99. })) || []
  100. return [
  101. {
  102. type: 'selection',
  103. selectable(row) {
  104. return !!row.markerId
  105. },
  106. fixed: 'left',
  107. },
  108. { label: '评卷员', prop: 'markerName', width: 100, fixed: 'left' },
  109. { label: '状态', prop: 'status', width: 100, fixed: 'left' },
  110. { label: '平均分', prop: 'avg', width: 80 },
  111. { label: '标准差', prop: 'std', width: 80 },
  112. { label: '相关系数', prop: 'xyRelate', width: 80 },
  113. { label: '差异份数', prop: 'diffCount', width: 80 },
  114. ...cols,
  115. ]
  116. })
  117. let currentDataType: TableDataType['stage'] = 'SAMPLE_A'
  118. /** 刷新按钮 */
  119. async function onSearch() {
  120. try {
  121. const valid = await elFormRef?.value?.validate()
  122. if (valid) {
  123. const { diffShow, ...params } = model || {}
  124. const dataType = model.markStage
  125. getTrainingMonitor(params).then(() => {
  126. currentDataType = dataType
  127. })
  128. }
  129. } catch (error) {
  130. console.error(error)
  131. }
  132. }
  133. /** 通过/不通过 */
  134. const onAssessPass = async (pass: boolean) => {
  135. if (!hasSelected.value) {
  136. return ElMessage.warning('未勾选考核人员')
  137. }
  138. if (currentDataType === 'FORCE') {
  139. const forceGroupMarkerIds: number[] = selectedList.map((d) => d.forceGroupMarkerId)
  140. await putAssessMonitorPass({ forceGroupMarkerIds, pass })
  141. } else {
  142. const markerIds = selectedList.map((d) => d.markerId)
  143. await putSampleMonitorPass({ markerIds, markStage: currentDataType, pass })
  144. }
  145. onSearch()
  146. }
  147. /** 双击跳转详情 */
  148. const onDbClick = (row: TableDataType) => {
  149. if (row.markerId) {
  150. push({
  151. name: 'TrainingDetail',
  152. query: {
  153. // stage: row.stage,
  154. stage: row.queryStage,
  155. markerId: row.markerId,
  156. forceGroupMarkerId: row.forceGroupMarkerId,
  157. },
  158. })
  159. }
  160. }
  161. onOptionInit(onSearch)
  162. let timer: any = setInterval(() => {
  163. onSearch()
  164. }, 30000)
  165. onBeforeUnmount(() => {
  166. clearInterval(timer)
  167. timer = null
  168. })
  169. </script>
  170. <style scoped lang="scss">
  171. .training-monitoring-view {
  172. :deep(.el-form-item--small) {
  173. margin-bottom: 10px;
  174. }
  175. }
  176. </style>