|
@@ -8,37 +8,89 @@
|
|
</base-form>
|
|
</base-form>
|
|
</div>
|
|
</div>
|
|
<div class="flex-1 p-base">
|
|
<div class="flex-1 p-base">
|
|
- <base-table :columns="columns" :data="trainingMonitor?.data"></base-table>
|
|
|
|
|
|
+ <div class="radius-base p-base fill-blank">
|
|
|
|
+ <div v-show="hasSelected" class="flex items m-b-base">
|
|
|
|
+ <el-button size="small" type="primary" @click="onAssessPass(true)">考核通过</el-button>
|
|
|
|
+ <el-button size="small" type="primary" plain="" @click="onAssessPass(false)">考核不通过</el-button>
|
|
|
|
+ <!-- <el-button size="small" type="primary" custom-1 @click="viewPaper(false)">查看试卷</el-button> -->
|
|
|
|
+ </div>
|
|
|
|
+ <base-table
|
|
|
|
+ :columns="columns"
|
|
|
|
+ :data="trainingMonitor?.data"
|
|
|
|
+ @selection-change="onSectionChange"
|
|
|
|
+ @row-dblclick="onDbClick"
|
|
|
|
+ >
|
|
|
|
+ </base-table>
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
-<script setup lang="ts" name="TrainingMonitoring">
|
|
|
|
|
|
+<script setup lang="tsx" name="TrainingMonitoring">
|
|
/** 培训监控 */
|
|
/** 培训监控 */
|
|
import { computed } from 'vue'
|
|
import { computed } from 'vue'
|
|
-import { ElButton } from 'element-plus'
|
|
|
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
|
+import { ElButton, ElMessage } from 'element-plus'
|
|
|
|
+import { minus } from '@/utils/common'
|
|
import BaseForm from '@/components/element/BaseForm.vue'
|
|
import BaseForm from '@/components/element/BaseForm.vue'
|
|
import BaseTable from '@/components/element/BaseTable.vue'
|
|
import BaseTable from '@/components/element/BaseTable.vue'
|
|
import useVW from '@/hooks/useVW'
|
|
import useVW from '@/hooks/useVW'
|
|
import useFetch from '@/hooks/useFetch'
|
|
import useFetch from '@/hooks/useFetch'
|
|
|
|
+import useSection from '@/hooks/useSection'
|
|
import useFormFilter from './hooks/useFormFilter'
|
|
import useFormFilter from './hooks/useFormFilter'
|
|
|
|
|
|
import type { ExtractApiResponse } from 'api-type'
|
|
import type { ExtractApiResponse } from 'api-type'
|
|
import type { EpTableColumn } from 'global-type'
|
|
import type { EpTableColumn } from 'global-type'
|
|
|
|
|
|
-const { model, items, onOptionInit } = useFormFilter()
|
|
|
|
|
|
+type TableDataType = ExtractArrayValue<ExtractApiResponse<'getTrainingMonitor'>['data']>
|
|
|
|
|
|
|
|
+const { push } = useRouter()
|
|
|
|
+
|
|
|
|
+const { diffShow, model, items, onOptionInit } = useFormFilter()
|
|
|
|
+
|
|
|
|
+/** 培训监控列表 */
|
|
const { fetch: getTrainingMonitor, result: trainingMonitor, loading } = useFetch('getTrainingMonitor')
|
|
const { fetch: getTrainingMonitor, result: trainingMonitor, loading } = useFetch('getTrainingMonitor')
|
|
|
|
+/** 培训卷审核 */
|
|
|
|
+const { fetch: putSampleMonitorPass } = useFetch('putSampleMonitorPass')
|
|
|
|
+/** 强制考核卷审核 */
|
|
|
|
+const { fetch: putAssessMonitorPass } = useFetch('putAssessMonitorPass')
|
|
|
|
|
|
-const columns = computed<EpTableColumn<ExtractApiResponse<'getTrainingMonitor'>>[]>(() => {
|
|
|
|
|
|
+const { hasSelected, selectedList, onSectionChange } = useSection<TableDataType>()
|
|
|
|
+
|
|
|
|
+const columns = computed<EpTableColumn<TableDataType>[]>(() => {
|
|
|
|
+ const standardScores = trainingMonitor?.value?.data?.[0]?.scoreList
|
|
|
|
+ const cols: EpTableColumn<TableDataType>[] =
|
|
|
|
+ trainingMonitor?.value?.header?.map((h) => ({
|
|
|
|
+ label: `${h}`,
|
|
|
|
+ width: 52,
|
|
|
|
+ formatter(row) {
|
|
|
|
+ if (!row.markerId) {
|
|
|
|
+ return `${row.scoreList[h - 1]}`
|
|
|
|
+ }
|
|
|
|
+ const score = row.scoreList[h - 1]
|
|
|
|
+ const standardScore = standardScores[h - 1]
|
|
|
|
+ return (
|
|
|
|
+ <span style={{ color: minus(score, standardScore) ? '#f00' : 'inherit' }}>
|
|
|
|
+ {diffShow.value ? minus(score, standardScore) : score}
|
|
|
|
+ </span>
|
|
|
|
+ )
|
|
|
|
+ },
|
|
|
|
+ })) || []
|
|
return [
|
|
return [
|
|
- { type: 'index' },
|
|
|
|
|
|
+ {
|
|
|
|
+ type: 'selection',
|
|
|
|
+ slotName: 'xxx',
|
|
|
|
+ selectable(row) {
|
|
|
|
+ return !!row.markerId
|
|
|
|
+ },
|
|
|
|
+ },
|
|
{ label: '评卷员', prop: 'markerName' },
|
|
{ label: '评卷员', prop: 'markerName' },
|
|
{ label: '状态', prop: 'status' },
|
|
{ label: '状态', prop: 'status' },
|
|
{ label: '平均分', prop: 'avg' },
|
|
{ label: '平均分', prop: 'avg' },
|
|
{ label: '标准差', prop: 'std' },
|
|
{ label: '标准差', prop: 'std' },
|
|
{ label: '相关系数', prop: 'xyRelate' },
|
|
{ label: '相关系数', prop: 'xyRelate' },
|
|
{ label: '差异份数', prop: 'diffCount' },
|
|
{ label: '差异份数', prop: 'diffCount' },
|
|
|
|
+ ...cols,
|
|
]
|
|
]
|
|
})
|
|
})
|
|
|
|
|
|
@@ -48,6 +100,42 @@ function onSearch() {
|
|
getTrainingMonitor(params)
|
|
getTrainingMonitor(params)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** 通过/不通过 */
|
|
|
|
+const onAssessPass = async (pass: boolean) => {
|
|
|
|
+ if (!hasSelected.value) {
|
|
|
|
+ return ElMessage.warning('未勾选考核人员')
|
|
|
|
+ }
|
|
|
|
+ const selectedData = selectedList.reduce((serialize, data) => {
|
|
|
|
+ serialize[data.stage] ??= []
|
|
|
|
+ serialize[data.stage].push(data)
|
|
|
|
+ return serialize
|
|
|
|
+ }, {} as Record<string, TableDataType[]>)
|
|
|
|
+
|
|
|
|
+ const fetchList = Object.entries(selectedData).map(([stage, selected]) => {
|
|
|
|
+ const forceGroupMarkerIds = selected.map((d) => d.forceGroupMarkerId)
|
|
|
|
+ const markerIds = selected.map((d) => d.markerId)
|
|
|
|
+ return stage === 'FORCE'
|
|
|
|
+ ? putAssessMonitorPass({ forceGroupMarkerIds, pass })
|
|
|
|
+ : putSampleMonitorPass({ markerIds, markStage: stage as SamplePaperType, pass })
|
|
|
|
+ })
|
|
|
|
+ await Promise.allSettled(fetchList)
|
|
|
|
+ onSearch()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/** 双击跳转详情 */
|
|
|
|
+const onDbClick = (row: TableDataType) => {
|
|
|
|
+ if (row.markerId) {
|
|
|
|
+ push({
|
|
|
|
+ name: 'TrainingDetail',
|
|
|
|
+ query: {
|
|
|
|
+ stage: row.stage,
|
|
|
|
+ markerId: row.markerId,
|
|
|
|
+ forceGroupMarkerId: row.forceGroupMarkerId,
|
|
|
|
+ },
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
onOptionInit(onSearch)
|
|
onOptionInit(onSearch)
|
|
</script>
|
|
</script>
|
|
|
|
|