1
This commit is contained in:
@@ -78,3 +78,16 @@ export function getRank(query?: Object) {
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日常巡检学年学期统计
|
||||
* @param {Object} [query] - 查询参数(schoolYear, schoolTerm, deptCode)
|
||||
* @returns {Promise} 请求的 Promise 对象。
|
||||
*/
|
||||
export function dailySummaryByYearTerm(query?: Object) {
|
||||
return request({
|
||||
url: '/stuwork/classcheckdaily/dailySummaryByYearTerm',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -64,3 +64,16 @@ export function putObj(obj?: Object) {
|
||||
data: obj,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日常行为学年学期统计
|
||||
* @param {Object} [query] - 查询参数(schoolYear, schoolTerm, deptCode)
|
||||
* @returns {Promise} 请求的 Promise 对象。
|
||||
*/
|
||||
export function dailySummaryByYearTerm(query?: Object) {
|
||||
return request({
|
||||
url: '/stuwork/classhygienedaily/dailySummaryByYearTerm',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -84,3 +84,15 @@ export const exportData = (query?: any) => {
|
||||
responseType: 'blob',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据班号查询班级异动情况
|
||||
* @param classCode 班号
|
||||
*/
|
||||
export const queryByClassCode = (classCode: string) => {
|
||||
return request({
|
||||
url: '/stuwork/stuturnover/queryByClassCode',
|
||||
method: 'get',
|
||||
params: { classCode },
|
||||
});
|
||||
};
|
||||
|
||||
@@ -24,8 +24,46 @@
|
||||
<el-descriptions-item label="门禁规则" :span="3">{{ detailData.ruleName || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 详细信息 - 使用 tabs 展示六个接口的数据 -->
|
||||
<!-- 详细信息 - 使用 tabs 展示 -->
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<!-- 学生概况 -->
|
||||
<el-tab-pane label="学生概况" name="studentOverview">
|
||||
<div v-loading="studentOverviewLoading">
|
||||
<el-descriptions :column="4" border>
|
||||
<el-descriptions-item label="教室安排">
|
||||
<span>{{ classroomInfo || '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="班主任姓名">
|
||||
<span>{{ studentOverviewData?.classMasterName || detailData?.teacherRealName || '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="在校人数(注册)">
|
||||
<el-tag type="primary" size="small">{{ studentOverviewData?.stuNum || 0 }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="在校人数(借读)">
|
||||
<el-tag type="warning" size="small">{{ studentOverviewData?.borrowingStuNum || 0 }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="男(在校)">
|
||||
<el-tag type="success" size="small">{{ studentOverviewData?.manStuNum || 0 }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="女(在校)">
|
||||
<el-tag type="danger" size="small">{{ studentOverviewData?.girlStuNum || 0 }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="借读">
|
||||
<el-tag type="info" size="small">{{ studentOverviewData?.borrowingStuNum || 0 }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="住宿人数">
|
||||
<el-tag type="primary" size="small">{{ dormOverviewData?.stuNum || 0 }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="住宿(男)">
|
||||
<el-tag type="success" size="small">{{ dormOverviewData?.manStuNum || 0 }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="住宿(女)">
|
||||
<el-tag type="danger" size="small">{{ dormOverviewData?.girlStuNum || 0 }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="班级荣誉" name="honor">
|
||||
<el-table :data="honorList" border style="width: 100%" v-loading="honorLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
@@ -59,21 +97,6 @@
|
||||
<div v-if="classroomList.length === 0 && !classroomLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="学生数量" name="studentNum">
|
||||
<el-table :data="studentNumList" border style="width: 100%" v-loading="studentNumLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" show-overflow-tooltip />
|
||||
<el-table-column prop="realName" label="姓名" show-overflow-tooltip />
|
||||
<el-table-column prop="sex" label="性别" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.sex === '1' ? '男' : scope.row.sex === '0' ? '女' : '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" label="电话" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="studentNumList.length === 0 && !studentNumLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="宿舍学生" name="dormStudent">
|
||||
<el-table :data="dormStudentList" border style="width: 100%" v-loading="dormStudentLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
@@ -85,16 +108,30 @@
|
||||
<div v-if="dormStudentList.length === 0 && !dormStudentLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="惩罚记录" name="punish">
|
||||
<el-table :data="punishList" border style="width: 100%" v-loading="punishLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" show-overflow-tooltip />
|
||||
<el-table-column prop="realName" label="姓名" show-overflow-tooltip />
|
||||
<el-table-column prop="punishType" label="惩罚类型" show-overflow-tooltip />
|
||||
<el-table-column prop="punishReason" label="惩罚原因" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="惩罚时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="punishList.length === 0 && !punishLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
<!-- 处罚处分 -->
|
||||
<el-tab-pane label="处罚处分" name="punish">
|
||||
<div v-loading="punishLoading">
|
||||
<el-descriptions :column="3" border>
|
||||
<el-descriptions-item label="警告">
|
||||
<el-tag type="warning" size="small">{{ punishOverviewData?.warningNum || 0 }}人</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="严重警告">
|
||||
<el-tag type="danger" size="small">{{ punishOverviewData?.seriousWarningNum || 0 }}人</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="记过">
|
||||
<el-tag type="danger" size="small" effect="plain">{{ punishOverviewData?.recordDemeritNum || 0 }}人</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="留校察看">
|
||||
<el-tag type="danger" size="small">{{ punishOverviewData?.detentionNum || 0 }}人</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="责令退学">
|
||||
<el-tag type="danger" size="small" effect="plain">{{ punishOverviewData?.dropOutNum || 0 }}人</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="开除学籍">
|
||||
<el-tag type="danger" size="small">{{ punishOverviewData?.expelSchoolNum || 0 }}人</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="顶岗计划" name="practicePlan">
|
||||
@@ -119,6 +156,24 @@
|
||||
</el-table>
|
||||
<div v-if="practicePlanList.length === 0 && !practicePlanLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="班级异动" name="turnover">
|
||||
<el-table :data="turnoverList" border style="width: 100%" v-loading="turnoverLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="realName" label="学生姓名" width="120" />
|
||||
<el-table-column prop="stuNo" label="学号" width="120" />
|
||||
<el-table-column prop="oldClassNo" label="原班级" width="120" />
|
||||
<el-table-column prop="newClassNo" label="现班级" width="120" />
|
||||
<el-table-column prop="turnoverType" label="异动类型" width="100">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="turnover_type" :value="scope.row.turnoverType"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="turnoverDate" label="异动日期" width="120" />
|
||||
<el-table-column prop="remarks" label="异动原因" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="turnoverList.length === 0 && !turnoverLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<template #footer>
|
||||
@@ -130,7 +185,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="BasicClassDetail">
|
||||
import { ref } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import { queryClassHonorByClassCode } from '/@/api/stuwork/classhonor';
|
||||
import { queryDataByClassCode } from '/@/api/stuwork/classpublicity';
|
||||
import { getClassRoomByClassCode } from '/@/api/stuwork/teachclassroomassign';
|
||||
@@ -138,60 +193,120 @@ import { queryStuNumByClassCode } from '/@/api/basic/basicstudent';
|
||||
import { fearchStuNumByClassCode } from '/@/api/stuwork/dormroomstudent';
|
||||
import { queryPunlishNumByClass } from '/@/api/stuwork/stupunlish';
|
||||
import { fetchList as fetchPracticePlanList } from '/@/api/basic/basicpracticeclassplan';
|
||||
import { queryByClassCode } from '/@/api/stuwork/stuturnover';
|
||||
import { useDict } from "/@/hooks/dict";
|
||||
|
||||
// 定义变量内容
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const detailData = ref<any>(null);
|
||||
const activeTab = ref('honor');
|
||||
const activeTab = ref('studentOverview');
|
||||
|
||||
// 六个接口的数据
|
||||
// 各接口的数据
|
||||
const honorList = ref<any[]>([]);
|
||||
const honorLoading = ref(false);
|
||||
const publicityList = ref<any[]>([]);
|
||||
const publicityLoading = ref(false);
|
||||
const classroomList = ref<any[]>([]);
|
||||
const classroomLoading = ref(false);
|
||||
const studentNumList = ref<any[]>([]);
|
||||
const studentNumLoading = ref(false);
|
||||
const dormStudentList = ref<any[]>([]);
|
||||
const dormStudentLoading = ref(false);
|
||||
const punishList = ref<any[]>([]);
|
||||
|
||||
// 学生概况数据
|
||||
const studentOverviewData = ref<any>(null);
|
||||
const dormOverviewData = ref<any>(null);
|
||||
const studentOverviewLoading = ref(false);
|
||||
|
||||
// 处罚处分数据
|
||||
const punishOverviewData = ref<any>(null);
|
||||
const punishLoading = ref(false);
|
||||
|
||||
// 顶岗计划数据
|
||||
const practicePlanList = ref<any[]>([]);
|
||||
const practicePlanLoading = ref(false);
|
||||
|
||||
// 班级异动数据
|
||||
const turnoverList = ref<any[]>([]);
|
||||
const turnoverLoading = ref(false);
|
||||
|
||||
const { turnover_type } = useDict('turnover_type');
|
||||
|
||||
// 教室安排信息(拼接显示)
|
||||
const classroomInfo = computed(() => {
|
||||
if (classroomList.value && classroomList.value.length > 0) {
|
||||
return classroomList.value.map((item: any) => {
|
||||
const parts = [];
|
||||
if (item.buildingNo) parts.push(item.buildingNo);
|
||||
if (item.roomNo) parts.push(item.roomNo);
|
||||
if (item.roomName) parts.push(item.roomName);
|
||||
return parts.join('-');
|
||||
}).join('、');
|
||||
}
|
||||
return '-';
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = async (rowData: any) => {
|
||||
visible.value = true;
|
||||
detailData.value = rowData || null;
|
||||
activeTab.value = 'studentOverview';
|
||||
|
||||
// 如果有班级代码,加载六个接口的数据
|
||||
// 如果有班级代码,加载所有接口的数据
|
||||
if (rowData?.classCode) {
|
||||
await loadAllData(rowData.classCode);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载所有六个接口的数据
|
||||
// 加载所有接口的数据
|
||||
const loadAllData = async (classCode: string) => {
|
||||
loading.value = true;
|
||||
|
||||
// 并行加载所有接口数据
|
||||
await Promise.all([
|
||||
loadStudentOverviewData(classCode),
|
||||
loadDormOverviewData(classCode),
|
||||
loadClassroomData(classCode),
|
||||
loadHonorData(classCode),
|
||||
loadPublicityData(classCode),
|
||||
loadClassroomData(classCode),
|
||||
loadStudentNumData(classCode),
|
||||
loadDormStudentData(classCode),
|
||||
loadPunishData(classCode),
|
||||
loadPracticePlanData(classCode),
|
||||
loadTurnoverData(classCode),
|
||||
]);
|
||||
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
// 加载学生概况数据
|
||||
const loadStudentOverviewData = async (classCode: string) => {
|
||||
studentOverviewLoading.value = true;
|
||||
try {
|
||||
const res = await queryStuNumByClassCode({ classCode });
|
||||
if (res.data) {
|
||||
// 返回的是对象,直接赋值
|
||||
studentOverviewData.value = res.data;
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取学生概况失败', err);
|
||||
studentOverviewData.value = null;
|
||||
} finally {
|
||||
studentOverviewLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载住宿概况数据
|
||||
const loadDormOverviewData = async (classCode: string) => {
|
||||
try {
|
||||
const res = await fearchStuNumByClassCode(classCode);
|
||||
if (res.data) {
|
||||
dormOverviewData.value = res.data;
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取住宿概况失败', err);
|
||||
dormOverviewData.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载班级荣誉数据
|
||||
const loadHonorData = async (classCode: string) => {
|
||||
honorLoading.value = true;
|
||||
@@ -240,22 +355,6 @@ const loadClassroomData = async (classCode: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 加载学生数量数据
|
||||
const loadStudentNumData = async (classCode: string) => {
|
||||
studentNumLoading.value = true;
|
||||
try {
|
||||
const res = await queryStuNumByClassCode({ classCode });
|
||||
if (res.data) {
|
||||
studentNumList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取学生数量失败', err);
|
||||
studentNumList.value = [];
|
||||
} finally {
|
||||
studentNumLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载宿舍学生数据
|
||||
const loadDormStudentData = async (classCode: string) => {
|
||||
dormStudentLoading.value = true;
|
||||
@@ -272,17 +371,18 @@ const loadDormStudentData = async (classCode: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 加载惩罚记录数据
|
||||
// 加载处罚处分数据
|
||||
const loadPunishData = async (classCode: string) => {
|
||||
punishLoading.value = true;
|
||||
try {
|
||||
const res = await queryPunlishNumByClass(classCode);
|
||||
if (res.data) {
|
||||
punishList.value = Array.isArray(res.data) ? res.data : [];
|
||||
// 返回的是对象,包含各处罚类型的人数
|
||||
punishOverviewData.value = res.data;
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取惩罚记录失败', err);
|
||||
punishList.value = [];
|
||||
console.error('获取处罚处分失败', err);
|
||||
punishOverviewData.value = null;
|
||||
} finally {
|
||||
punishLoading.value = false;
|
||||
}
|
||||
@@ -308,6 +408,24 @@ const loadPracticePlanData = async (classCode: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 加载班级异动数据
|
||||
const loadTurnoverData = async (classCode: string) => {
|
||||
turnoverLoading.value = true;
|
||||
try {
|
||||
const res = await queryByClassCode(classCode);
|
||||
if (res.data) {
|
||||
turnoverList.value = Array.isArray(res.data) ? res.data : [];
|
||||
} else {
|
||||
turnoverList.value = [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取班级异动失败', err);
|
||||
turnoverList.value = [];
|
||||
} finally {
|
||||
turnoverLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取顶岗计划状态标签
|
||||
const getPracticeStatusLabel = (status: string) => {
|
||||
const statusMap: Record<string, string> = {
|
||||
@@ -340,4 +458,4 @@ defineExpose({
|
||||
.mb20 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@@ -202,7 +202,7 @@
|
||||
<el-divider content-position="left">家庭基本信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="户口详细地址" prop="householdAddress" :rules="formRules.householdAddress">
|
||||
<el-form-item label="户口详细地址" prop="householdAddress" :rules="formRules.homeHouseholdAddress">
|
||||
<el-input v-model="homeInfo.householdAddress" placeholder="请输入户口详细地址" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -734,7 +734,7 @@ const formRules = {
|
||||
// 教育经历必填
|
||||
education: [{ required: true, message: '请选择入学前文化程度', trigger: 'change' }],
|
||||
// 家庭信息必填
|
||||
householdAddress: [{ required: true, message: '请输入户口详细地址', trigger: 'blur' }],
|
||||
homeHouseholdAddress: [{ required: true, message: '请输入户口详细地址', trigger: 'blur' }],
|
||||
householdProperties: [{ required: true, message: '请选择户口性质', trigger: 'change' }],
|
||||
isTemp: [{ required: true, message: '请选择是否租住', trigger: 'change' }],
|
||||
liveAddress: [{ required: true, message: '请输入居住详细地址', trigger: 'blur' }],
|
||||
|
||||
@@ -37,7 +37,6 @@ const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
},
|
||||
};
|
||||
},
|
||||
createdIsNeed: false,
|
||||
});
|
||||
const visible = ref(false);
|
||||
|
||||
|
||||
@@ -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' }],
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user