This commit is contained in:
yaojian
2026-03-13 11:41:26 +08:00
parent ae72e88d78
commit c611c3e720
10 changed files with 416 additions and 79 deletions

View File

@@ -91,7 +91,6 @@ const form = reactive({
// 定义校验规则
const dataRules = ref({
classCode: [{ required: true, message: '班号不能为空', trigger: 'change' }],
stuNo: [{ required: true, message: '学生不能为空', trigger: 'change' }],
recordTime: [{ required: true, message: '记录时间不能为空', trigger: 'blur' }],
score: [{ required: true, message: '分数不能为空', trigger: 'blur' }],
note: [{ required: true, message: '检查记录不能为空', trigger: 'blur' }],

View File

@@ -159,31 +159,36 @@
/>
<!-- 学期统计对话框 -->
<el-dialog title="学期统计" v-model="rankDialogVisible" :close-on-click-modal="false" draggable width="800px">
<el-form :inline="true" :model="rankForm">
<el-dialog title="日常巡检学年学期统计" v-model="rankDialogVisible" :close-on-click-modal="false" draggable width="800px" destroy-on-close>
<el-form :inline="true" :model="rankForm" class="mb10">
<el-form-item label="学年">
<el-select v-model="rankForm.schoolYear" placeholder="请选择学年" clearable filterable style="width: 200px">
<el-select v-model="rankForm.schoolYear" placeholder="请选择学年" clearable filterable style="width: 180px">
<el-option v-for="item in schoolYearList" :key="item.year" :label="item.year" :value="item.year"> </el-option>
</el-select>
</el-form-item>
<el-form-item label="学期">
<el-input v-model="rankForm.schoolTerm" placeholder="请输入学期" clearable style="width: 200px" />
<el-select v-model="rankForm.schoolTerm" placeholder="请选择学期" clearable style="width: 180px">
<el-option v-for="item in schoolTermList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="学院">
<el-select v-model="rankForm.deptCode" placeholder="请选择学院" clearable filterable style="width: 180px">
<el-option v-for="item in deptList" :key="item.deptCode" :label="item.deptName" :value="item.deptCode" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getRankData">查询</el-button>
</el-form-item>
</el-form>
<el-table :data="rankData" v-loading="rankLoading" border style="margin-top: 20px">
<el-table-column type="index" label="序号" align="center" />
<el-table-column prop="deptName" label="学院" show-overflow-tooltip />
<el-table-column prop="classNo" label="班" show-overflow-tooltip />
<el-table-column prop="totalScore" label="总分数" show-overflow-tooltip />
<el-table-column prop="count" label="记录数" show-overflow-tooltip />
<el-table :data="rankData" v-loading="rankLoading" stripe max-height="400" :cell-style="{ padding: '8px 0', textAlign: 'center' }" :header-cell-style="{ background: '#f5f7fa', color: '#606266', fontWeight: 'bold', textAlign: 'center' }">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="deptName" label="学院" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="className" label="班级" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="totalScore" label="总分数" min-width="100" align="center" />
<el-table-column prop="recordCount" label="记录数" min-width="100" align="center" />
</el-table>
<template #footer>
<span class="dialog-footer">
<el-button @click="rankDialogVisible = false"> </el-button>
</span>
<template v-if="rankData.length === 0 && !rankLoading">
<el-empty description="暂无统计数据" :image-size="80" />
</template>
</el-dialog>
</div>
@@ -192,12 +197,13 @@
<script setup lang="ts" name="ClassCheckDaily">
import { ref, reactive, defineAsyncComponent, computed, onMounted } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObjs, exportData, getRank } from '/@/api/stuwork/classcheckdaily';
import { fetchList, delObjs, exportData, getRank, dailySummaryByYearTerm } from '/@/api/stuwork/classcheckdaily';
import { makeExportClassCheckDailyTask } from '/@/api/stuwork/file';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { getDeptList } from '/@/api/basic/basicclass';
import { getClassListByRole } from '/@/api/basic/basicclass';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getDicts } from '/@/api/admin/dict';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
import {
List,
@@ -230,6 +236,7 @@ const showSearch = ref(true);
const deptList = ref<any[]>([]);
const classList = ref<any[]>([]);
const schoolYearList = ref<any[]>([]);
const schoolTermList = ref<any[]>([]);
// 模板文件URL
const templateUrl = ref('/stuwork/classcheckdaily/importTemplate');
@@ -284,6 +291,7 @@ const rankData = ref<any[]>([]);
const rankForm = reactive({
schoolYear: '',
schoolTerm: '',
deptCode: '',
});
// 学院选择变化
@@ -350,6 +358,7 @@ const handleRank = () => {
rankDialogVisible.value = true;
rankForm.schoolYear = '';
rankForm.schoolTerm = '';
rankForm.deptCode = '';
rankData.value = [];
};
@@ -362,9 +371,10 @@ const getRankData = async () => {
try {
rankLoading.value = true;
const res = await getRank({
const res = await dailySummaryByYearTerm({
schoolYear: rankForm.schoolYear,
schoolTerm: rankForm.schoolTerm,
deptCode: rankForm.deptCode,
});
if (res.data) {
rankData.value = Array.isArray(res.data) ? res.data : [];
@@ -415,11 +425,29 @@ const getSchoolYearList = async () => {
}
};
// 获取学期字典
const getSchoolTermDict = async () => {
try {
const res = await getDicts('school_term');
if (res.data) {
schoolTermList.value = Array.isArray(res.data)
? res.data.map((item: any) => ({
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code,
}))
: [];
}
} catch (err) {
schoolTermList.value = [];
}
};
// 初始化
onMounted(() => {
getDeptListData();
getClassListData();
getSchoolYearList();
getSchoolTermDict();
});
</script>

View File

@@ -59,6 +59,7 @@
</span>
<div class="header-actions">
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog()"> 新增 </el-button>
<el-button icon="DataAnalysis" type="info" class="ml10" @click="handleOpenSummary"> 学期统计 </el-button>
<el-button icon="Upload" type="success" class="ml10" @click="handleImport"> 导入 </el-button>
<el-button icon="Download" type="warning" class="ml10" @click="handleExport"> 导出 </el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList">
@@ -160,19 +161,55 @@
:temp-url="templateUrl"
@refreshDataList="getDataList"
/>
<!-- 学期统计弹出框 -->
<el-dialog v-model="summaryVisible" title="日常行为学年学期统计" width="900px" destroy-on-close>
<el-form :model="summaryForm" :inline="true" class="mb10">
<el-form-item label="学年">
<el-select v-model="summaryForm.schoolYear" placeholder="请选择学年" clearable filterable style="width: 180px">
<el-option v-for="item in schoolYearList" :key="item.year" :label="item.year" :value="item.year" />
</el-select>
</el-form-item>
<el-form-item label="学期">
<el-select v-model="summaryForm.schoolTerm" placeholder="请选择学期" clearable style="width: 180px">
<el-option v-for="item in schoolTermList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="学院">
<el-select v-model="summaryForm.deptCode" placeholder="请选择学院" clearable filterable style="width: 180px">
<el-option v-for="item in deptList" :key="item.deptCode" :label="item.deptName" :value="item.deptCode" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuerySummary">查询</el-button>
</el-form-item>
</el-form>
<el-table :data="summaryData" v-loading="summaryLoading" stripe max-height="400" :cell-style="{ padding: '8px 0', textAlign: 'center' }" :header-cell-style="{ background: '#f5f7fa', color: '#606266', fontWeight: 'bold', textAlign: 'center' }">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="deptName" label="学院" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="className" label="班级" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="totalScore" label="总分" min-width="100" align="center" />
<el-table-column prop="recordCount" label="记录数" min-width="100" align="center" />
</el-table>
<template v-if="summaryData.length === 0 && !summaryLoading">
<el-empty description="暂无统计数据" :image-size="80" />
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="ClassHygieneDaily">
import { ref, reactive, defineAsyncComponent, computed, onMounted } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObjs } from '/@/api/stuwork/classhygienedaily';
import { fetchList, delObjs, dailySummaryByYearTerm } from '/@/api/stuwork/classhygienedaily';
import { downloadClassHygieneDailyTemplate, makeExportClassHygieneDailyTask } from '/@/api/stuwork/file';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { getDeptList } from '/@/api/basic/basicclass';
import { getClassListByRole } from '/@/api/basic/basicclass';
import { queryAllSchoolYear } from '/@/api/basic/basicyear';
import { getDicts } from '/@/api/admin/dict';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
import { List, OfficeBuilding, Grid, Calendar, Minus, Document, Setting, Menu, Search, FolderAdd, EditPen } from '@element-plus/icons-vue';
import { List, OfficeBuilding, Grid, Calendar, Minus, Document, Setting, Menu, Search, FolderAdd, EditPen, DataAnalysis } from '@element-plus/icons-vue';
import { useTableColumnControl } from '/@/hooks/tableColumn';
// 引入组件
@@ -187,9 +224,21 @@ const uploadExcelRef = ref();
const showSearch = ref(true);
const deptList = ref<any[]>([]);
const classList = ref<any[]>([]);
const schoolYearList = ref<any[]>([]);
const schoolTermList = ref<any[]>([]);
// 模板文件URL
const templateUrl = ref('/stuwork/classhygienedaily/importTemplate');
// 统计相关变量
const summaryVisible = ref(false);
const summaryLoading = ref(false);
const summaryData = ref<any[]>([]);
const summaryForm = reactive({
schoolYear: '',
schoolTerm: '',
deptCode: ''
});
// 表格列配置
const tableColumns = [
{ prop: 'deptName', label: '学院', icon: OfficeBuilding },
@@ -313,10 +362,72 @@ const getClassListData = async () => {
}
};
// 获取学年列表
const getSchoolYearListData = async () => {
try {
const res = await queryAllSchoolYear();
if (res.data) {
schoolYearList.value = Array.isArray(res.data) ? res.data : [];
}
} catch (err) {
schoolYearList.value = [];
}
};
// 获取学期字典
const getSchoolTermDict = async () => {
try {
const res = await getDicts('school_term');
if (res.data) {
schoolTermList.value = Array.isArray(res.data)
? res.data.map((item: any) => ({
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code,
}))
: [];
}
} catch (err) {
schoolTermList.value = [];
}
};
// 打开统计弹窗
const handleOpenSummary = () => {
summaryVisible.value = true;
summaryForm.schoolYear = '';
summaryForm.schoolTerm = '';
summaryForm.deptCode = '';
summaryData.value = [];
};
// 查询统计数据
const handleQuerySummary = async () => {
if (!summaryForm.schoolYear || !summaryForm.schoolTerm) {
useMessage().warning('请选择学年和学期');
return;
}
summaryLoading.value = true;
try {
const res = await dailySummaryByYearTerm({
schoolYear: summaryForm.schoolYear,
schoolTerm: summaryForm.schoolTerm,
deptCode: summaryForm.deptCode
});
summaryData.value = Array.isArray(res.data) ? res.data : [];
} catch (err: any) {
useMessage().error(err.msg || '获取统计数据失败');
summaryData.value = [];
} finally {
summaryLoading.value = false;
}
};
// 初始化
onMounted(() => {
getDeptListData();
getClassListData();
getSchoolYearListData();
getSchoolTermDict();
});
</script>

View File

@@ -38,6 +38,21 @@
<h3 class="content-title">总结报告</h3>
<div v-html="detailData.summary || '-'"></div>
</div>
<!-- 班级异动情况 -->
<div class="turnover-section">
<h3 class="content-title">班级异动情况</h3>
<el-table :data="turnoverData" v-loading="turnoverLoading" stripe max-height="300" :cell-style="{ padding: '8px 0', textAlign: 'center' }" :header-cell-style="{ background: '#f5f7fa', color: '#606266', fontWeight: 'bold', textAlign: 'center' }">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="studentName" label="学生姓名" min-width="100" align="center" show-overflow-tooltip />
<el-table-column prop="turnoverType" label="异动类型" min-width="100" align="center" show-overflow-tooltip />
<el-table-column prop="turnoverDate" label="异动日期" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="reason" label="异动原因" min-width="150" align="center" show-overflow-tooltip />
</el-table>
<template v-if="turnoverData.length === 0 && !turnoverLoading">
<el-empty description="暂无异动数据" :image-size="60" />
</template>
</div>
</div>
<template #footer>
<span class="dialog-footer">
@@ -50,6 +65,7 @@
<script setup lang="ts" name="ClassSummaryDetailDialog">
import { ref, onMounted } from 'vue';
import { getDetail } from '/@/api/stuwork/classsummary';
import { queryByClassCode } from '/@/api/stuwork/stuturnover';
import { getDicts } from '/@/api/admin/dict';
// 定义变量内容
@@ -58,6 +74,8 @@ const loading = ref(false);
const detailData = ref<any>(null);
const schoolTermList = ref<any[]>([]);
const statusList = ref<any[]>([]);
const turnoverData = ref<any[]>([]);
const turnoverLoading = ref(false);
// 格式化学期
const formatSchoolTerm = (value: string | number) => {
@@ -79,11 +97,16 @@ const formatStatus = (value: string) => {
const openDialog = async (id: string) => {
visible.value = true;
detailData.value = null;
turnoverData.value = [];
loading.value = true;
try {
const res = await getDetail(id);
if (res.data) {
detailData.value = res.data;
// 获取班级异动情况
if (res.data.classCode) {
fetchTurnoverData(res.data.classCode);
}
}
} catch (err) {
} finally {
@@ -91,6 +114,23 @@ const openDialog = async (id: string) => {
}
};
// 获取班级异动数据
const fetchTurnoverData = async (classCode: string) => {
turnoverLoading.value = true;
try {
const res = await queryByClassCode(classCode);
if (res.data) {
turnoverData.value = Array.isArray(res.data) ? res.data : [];
} else {
turnoverData.value = [];
}
} catch (err) {
turnoverData.value = [];
} finally {
turnoverLoading.value = false;
}
};
// 获取学期字典
const getSchoolTermDict = async () => {
try {
@@ -225,4 +265,8 @@ defineExpose({
color: #909399;
font-style: italic;
}
.turnover-section {
margin-top: 30px;
}
</style>