소스 검색

考试培训数据统计

zjq 6 일 전
부모
커밋
f4b0435951

+ 53 - 0
src/api/examTrain/statistics.ts

@@ -0,0 +1,53 @@
+/*
+ * @Author: zjq
+ * @description 考试培训数据统计
+ */
+import request from '@/utils/request';
+
+/**
+ * @description 获取缺考人员列表
+ * @param {object} params
+ */
+export const getMissExamUsersData = (params?: object) => {
+    return request({
+        url: '/api/v1/UserExam/GetUnExamUsers',
+        method: 'post',
+        data: params,
+    });
+};
+
+/**
+ * @description 获取成绩统计分析列表
+ * @param {object} params
+ */
+export const getScoresAnalysisData = (params?: object) => {
+    return request({
+        url: '/api/v1/UserExam/GetUserExamResults',
+        method: 'post',
+        data: params,
+    });
+};
+
+/**
+ * @description 获取培训结果明细表数据
+ * @param {object} params
+ */
+export const getTrainResultAnalysisData = (params?: object) => {
+    return request({
+        url: '/api/v1/TrainRecord/AnalysisTrainResult',
+        method: 'post',
+        data: params,
+    });
+};
+
+/**
+ * @description 获取学习完成度数据
+ * @param {object} params
+ */
+export const getTrainCalcuteAnalysisData = (params?: object) => {
+    return request({
+        url: '/api/v1/TrainRecord/CalcuteAnalysisRate',
+        method: 'post',
+        data: params,
+    });
+};

+ 132 - 0
src/views/examTrain/exam/statistics/missExamUsers.vue

@@ -0,0 +1,132 @@
+<template>
+	<div class="snapshot-statistics-grid-handle-container layout-padding">
+		<div class="layout-padding-auto layout-padding-view pd20">
+			<vxe-grid v-bind="gridOptions" ref="gridRef">
+				<template #form>
+					<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline :disabled="gridOptions.loading">
+						<el-form-item prop="crTime">
+							<statistical-time v-model="state.queryParams.crTime" @change="handleQuery" ref="statisticalTimeRef" :disabled="state.loading" />
+						</el-form-item>
+						<el-form-item>
+							<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+							<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+								<SvgIcon name="ele-Refresh" class="mr5" />重置
+							</el-button>
+						</el-form-item>
+					</el-form>
+				</template>
+			</vxe-grid>
+		</div>
+	</div>
+</template>
+
+<script lang="tsx" setup name="examTrainExamStatisticsMissExamUsers">
+import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
+import { FormInstance } from 'element-plus';
+import { defaultDate } from '@/utils/constants';
+import { getMissExamUsersData } from '@/api/examTrain/statistics';
+import Other from '@/utils/other';
+
+// 引入组件
+const StatisticalTime = defineAsyncComponent(() => import('@/components/StatisticalTime/index.vue')); // 日期类型选择组件
+
+// 定义变量内容
+const state = reactive<any>({
+	loading: false,
+	queryParams: {
+		// 查询参数
+		crTime: defaultDate, // 时间默认今天开始到今天结束
+		startTime: null,
+		endTime: null,
+		IndustryId: null,
+	},
+});
+
+const requestParams = ref<EmptyObjectType>({});
+const gridOptions = reactive<any>({
+	loading: false,
+	border: true,
+	showOverflow: true,
+	columnConfig: {
+		resizable: true,
+	},
+	scrollY: {
+		enabled: true,
+		gt: 100,
+	},
+	toolbarConfig: {
+		zoom: true,
+		custom: true,
+		refresh: {
+			queryMethod: () => {
+				handleQuery();
+			},
+		},
+	},
+	customConfig: {
+		storage: true,
+	},
+	id: 'examTrainExamStatisticsMissExamUsers',
+	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true },
+	height: 'auto',
+	align: 'center',
+	columns: [
+		{
+			field: 'userName',
+			title: '缺考人员',
+			width: 200,
+			fixed: 'left',
+		},
+		{
+			field: 'orgName',
+			title: '部门名称',
+			fixed: 'left',
+			width: 300,
+		},
+        {
+			field: 'examName',
+			title: '考试题目',
+			fixed: 'left',
+			minWidth: 300,
+		},
+	],
+	data: [],
+});
+/** 搜索按钮操作 节流操作 */
+const handleQuery = () => {
+	state.queryParams.PageIndex = 1;
+	queryList();
+};
+// 获取参数列表
+const queryList = () => {
+	state.loading = true;
+	gridOptions.loading = true;
+	requestParams.value = Other.deepClone(state.queryParams);
+	requestParams.value.startTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0]; // 受理时间
+	requestParams.value.endTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(requestParams.value, 'crTime'); // 删除无用的参数
+	getMissExamUsersData(requestParams.value)
+		.then((res) => {
+			state.loading = false;
+			gridOptions.data = res.result.item ?? [];
+			gridOptions.loading = false;
+		})
+		.finally(() => {
+			state.loading = false;
+			gridOptions.loading = false;
+		});
+};
+// 重置表单
+const ruleFormRef = ref<any>(null); // 表单ref
+const statisticalTimeRef = ref<RefType>();
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	statisticalTimeRef.value.reset();
+	queryList();
+};
+// 页面加载时
+onMounted(() => {
+	queryList();
+});
+</script>

+ 165 - 0
src/views/examTrain/exam/statistics/scoresAnalysis.vue

@@ -0,0 +1,165 @@
+<template>
+	<div class="snapshot-statistics-grid-handle-container layout-padding">
+		<div class="layout-padding-auto layout-padding-view pd20">
+			<vxe-grid v-bind="gridOptions" ref="gridRef">
+				<template #form>
+					<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline :disabled="gridOptions.loading">
+						<el-form-item prop="crTime">
+							<statistical-time v-model="state.queryParams.crTime" @change="handleQuery" ref="statisticalTimeRef" :disabled="state.loading" />
+						</el-form-item>
+                        <el-form-item label="考试标题" prop="keyword">
+                            <el-input v-model="state.queryParams.keyword" placeholder="考试标题" clearable @change="handleQuery" :disabled="state.loading" class="keyword-input" />
+                        </el-form-item>
+                        <el-form-item label="考试分数>=" prop="minScore">
+                            <el-input-number v-model="state.queryParams.minScore" :min="0" class="w100" ></el-input-number>
+                        </el-form-item>
+                        <!-- <el-form-item label="考试分数<=" prop="maxScore">
+                            <el-input-number v-model="state.queryParams.maxScore" :min="0" class="w100" ></el-input-number>
+                        </el-form-item> -->
+						<el-form-item>
+							<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+							<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+								<SvgIcon name="ele-Refresh" class="mr5" />重置
+							</el-button>
+						</el-form-item>
+					</el-form>
+				</template>
+			</vxe-grid>
+		</div>
+	</div>
+</template>
+
+<script lang="tsx" setup name="examTrainExamStatisticsScoresAnalysis">
+import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
+import { FormInstance } from 'element-plus';
+import { defaultDate } from '@/utils/constants';
+import { getScoresAnalysisData } from '@/api/examTrain/statistics';
+import Other from '@/utils/other';
+
+// 引入组件
+const StatisticalTime = defineAsyncComponent(() => import('@/components/StatisticalTime/index.vue')); // 日期类型选择组件
+
+// 定义变量内容
+const state = reactive<any>({
+	loading: false,
+	queryParams: {
+		// 查询参数
+		crTime: defaultDate, // 时间默认今天开始到今天结束
+        keyword: '',
+        minScore: 0,
+        maxScore: null,
+		startTime: null,
+		endTime: null,
+		IndustryId: null,
+	},
+});
+
+const requestParams = ref<EmptyObjectType>({});
+const gridOptions = reactive<any>({
+	loading: false,
+	border: true,
+	showOverflow: true,
+	columnConfig: {
+		resizable: true,
+	},
+	scrollY: {
+		enabled: true,
+		gt: 100,
+	},
+	toolbarConfig: {
+		zoom: true,
+		custom: true,
+		refresh: {
+			queryMethod: () => {
+				handleQuery();
+			},
+		},
+	},
+	customConfig: {
+		storage: true,
+	},
+	id: 'examTrainExamStatisticsScoresAnalysis',
+	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true },
+	height: 'auto',
+	align: 'center',
+	columns: [
+		{
+			field: 'userName',
+			title: '参考人员',
+			width: 200,
+			fixed: 'left',
+		},
+		{
+			field: 'orgName',
+			title: '部门名称',
+			fixed: 'left',
+			width: 200,
+		},
+        {
+			field: 'examName',
+			title: '考试标题',
+			fixed: 'left',
+			minWidth: 200,
+		},
+        {
+			field: 'totalScore',
+			title: '考试总分',
+			fixed: 'left',
+            sortable: true,
+			width: 120,
+		},
+        {
+			field: 'cutoffScore',
+			title: '合格分数',
+			fixed: 'left',
+            sortable: true,
+			width: 120,
+		},
+        {
+			field: 'score',
+			title: '考试分数',
+			fixed: 'left',
+            sortable: true,
+			width: 120,
+		},
+	],
+	data: [],
+});
+/** 搜索按钮操作 节流操作 */
+const handleQuery = () => {
+	state.queryParams.PageIndex = 1;
+	queryList();
+};
+// 获取参数列表
+const queryList = () => {
+	state.loading = true;
+	gridOptions.loading = true;
+	requestParams.value = Other.deepClone(state.queryParams);
+	requestParams.value.startTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0]; // 受理时间
+	requestParams.value.endTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(requestParams.value, 'crTime'); // 删除无用的参数
+	getScoresAnalysisData(requestParams.value)
+		.then((res) => {
+			state.loading = false;
+			gridOptions.data = res.result.item ?? [];
+			gridOptions.loading = false;
+		})
+		.finally(() => {
+			state.loading = false;
+			gridOptions.loading = false;
+		});
+};
+// 重置表单
+const ruleFormRef = ref<any>(null); // 表单ref
+const statisticalTimeRef = ref<RefType>();
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	statisticalTimeRef.value.reset();
+	queryList();
+};
+// 页面加载时
+onMounted(() => {
+	queryList();
+});
+</script>

+ 180 - 0
src/views/examTrain/train/statistics/resultAnalysis.vue

@@ -0,0 +1,180 @@
+<template>
+	<div class="snapshot-statistics-hotspot-container layout-pd">
+		<el-card shadow="never">
+			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline :disabled="gridOptions.loading">
+				<el-form-item prop="crTime">
+					<statistical-time v-model="state.queryParams.crTime" @change="handleQuery" ref="statisticalTimeRef" :disabled="state.loading" />
+				</el-form-item>
+				<el-form-item label="培训标题" prop="keyword">
+                    <el-input v-model="state.queryParams.keyword" placeholder="培训标题" clearable @change="handleQuery" :disabled="state.loading" class="keyword-input" />
+                </el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+						<SvgIcon name="ele-Refresh" class="mr5" />重置
+					</el-button>
+				</el-form-item>
+			</el-form>
+			<el-row :gutter="20">
+                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
+					<div style="height: 70vh">
+						<vxe-grid v-bind="gridOptions" ref="gridRef"> </vxe-grid>
+					</div>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
+					<v-chart class="chart" :option="option" :loading="state.loading" autoresize />
+				</el-col>
+			</el-row>
+		</el-card>
+	</div>
+</template>
+<script setup lang="tsx" name="examTrainTrainStatisticsResultAnalysis">
+import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
+import { FormInstance } from 'element-plus';
+import { defaultDate } from '@/utils/constants';
+import Other from '@/utils/other';
+import { getTrainResultAnalysisData, getTrainCalcuteAnalysisData } from '@/api/examTrain/statistics';
+
+const StatisticalTime = defineAsyncComponent(() => import('@/components/StatisticalTime/index.vue')); // 日期类型选择组件
+// 定义变量内容
+const ruleFormRef = ref<RefType>(); // 表单ref
+const state = reactive<any>({
+	queryParams: {
+		// 查询条件
+		crTime: defaultDate, //
+		startTime: null,
+		endTime: null,
+        keyword: ''
+	},
+	tableData: [], //表单
+	loading: false, // 加载
+	total: 0, // 总数
+});
+/** 搜索按钮操作 */
+const handleQuery = () => {
+	queryList();
+};
+
+const requestParams = ref<EmptyObjectType>({});
+const gridOptions = reactive<any>({
+	loading: false,
+	border: true,
+	showOverflow: true,
+	columnConfig: {
+		resizable: true,
+	},
+	scrollY: {
+		enabled: true,
+		gt: 100,
+	},
+	toolbarConfig: {
+		custom: true,
+		refresh: {
+			queryMethod: () => {
+				handleQuery();
+			},
+		},
+	},
+	customConfig: {
+		storage: true,
+	},
+	id: 'examTrainTrainStatisticsResultAnalysis',
+	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true },
+	height: 'auto',
+	align: 'center',
+	columns: [
+		{ field: 'userName', title: '培训人员', width: 120 },
+        { field: 'trainName', title: '培训标题', minWidth: 200 },
+		{ field: 'isCompleteDes', title: '学习是否完成', width: 120},
+	],
+	data: [],
+});
+/** 获取列表 */
+const dataTable = ref([] as any []);
+const queryList = async () => {
+	state.loading = true;
+	gridOptions.loading = true;
+	requestParams.value = Other.deepClone(state.queryParams);
+    requestParams.value.startTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+    requestParams.value.endTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+    Reflect.deleteProperty(requestParams.value, 'crTime');
+    getTrainResultAnalysisData(requestParams.value)
+    .then((res) => {
+        gridOptions.data = res.result.item ?? [];
+    });
+    getTrainCalcuteAnalysisData(requestParams.value)
+    .then((res) => {
+        state.tableData = res.result ?? null;
+        const legendData = ['进行中', '是', '否']
+        dataTable.value = [
+            {name: '进行中', value: state.tableData.trainning},
+            {name: '是', value: state.tableData.complete},
+            {name: '否', value: state.tableData.unComplete},
+        ]
+        setOption(legendData, dataTable.value);
+    });
+    state.loading = false;
+    gridOptions.loading = false;
+};
+/** 重置按钮操作 */
+const statisticalTimeRef = ref<RefType>();
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	statisticalTimeRef.value.reset();
+	queryList();
+};
+const option = ref<EmptyObjectType>({});
+// 热点类型统计表
+const setOption = (legendData: string[], data: any) => {
+	option.value = {
+		title: {
+			text: '学习完成度占比',
+			left: 'center',
+		},
+		tooltip: {
+			formatter: '{b0}: {c0} ({d}%)',
+		},
+		legend: [
+			{
+				left: 'left',
+				top: '40',
+				orient: 'vertical',
+				data: legendData,
+			},
+		],
+		series: [
+			{
+				type: 'pie',
+				radius: ['0%', '60%'],
+				top: '10%',
+                itemStyle: {
+                    borderRadius: 10,
+                    borderColor: '#fff',
+                    borderWidth: 2
+                },
+				label: {
+					show: true,
+					overflow: 'none',
+					formatter: (params: any) => {
+						if (params.name !== '') {
+							return `${params.name}:${params.data.value}`;
+                            // (${params.percent}%)
+						}
+					},
+				},
+				data: data,
+			},
+		],
+	};
+};
+onMounted(() => {
+	queryList();
+});
+</script>
+<style lang="scss" scoped>
+.chart {
+	height: 70vh;
+	margin-top: 10px;
+}
+</style>

+ 4 - 0
src/views/examTrain/train/userTrain/study.vue

@@ -240,6 +240,10 @@ const getInfo = async () => {
     console.log(state.trainName);
     const res: any = await getTrainInfo(route.params.id);
     state.trainPracticeKnowladgeDtos = res.result.knowladgeDtos;
+    // 初始化知识点击
+    if (state.trainPracticeKnowladgeDtos.length > 0){
+        onClickKnowladge(state.trainPracticeKnowladgeDtos[0].id)
+    }
     // state.trainPracticeSourcewareDtos = res.result.trainPracticeSourcewareDtos;
     state.trainPracticeQuestionsDtos = res.result.questionDtos;
     state.loading = false;