学生信息页面完善

This commit is contained in:
yaojian
2026-03-10 18:32:48 +08:00
parent 33b228da9a
commit 15d9ca27eb
75 changed files with 301 additions and 42 deletions

View File

@@ -530,15 +530,13 @@ export const importCertificate = (formData: FormData) => {
};
/**
* 证书导出
* @param data
* TODO: 接口文档中未找到此接口,请提供正确的接口地址
* 创建证书导出异步任务
* @param data 查询参数
*/
export const exportCertificate = (data: any) => {
export const makeExportSkillLevelTask = (data?: any) => {
return request({
url: '/basic/basicstudent/exportCertificate', // TODO: 接口文档中未找到此接口
url: '/ems/file/makeExportSkillLevelTask',
method: 'post',
data: data,
responseType: 'blob',
});
};

View File

@@ -0,0 +1,274 @@
<template>
<el-dialog title="学生证件照打印" v-model="visible" :close-on-click-modal="false" draggable fullscreen>
<div class="print-container" ref="printRef">
<div class="print-actions" v-if="!isPrinting">
<el-button type="primary" icon="Printer" @click="handlePrint">打印</el-button>
<el-button @click="visible = false">关闭</el-button>
</div>
<div v-loading="loading" class="print-content">
<div class="print-page" v-for="(page, pageIndex) in printPages" :key="pageIndex">
<div class="card-wrapper" v-for="(item, cardIndex) in page" :key="cardIndex" :style="getBackgroundStyle(item)">
<!-- 头像区域 -->
<div class="photo-area">
<img :src="item.photo || defaultAvatar" class="student-photo" />
</div>
<!-- 二维码和学生信息区域 -->
<div class="info-area">
<div class="qrcode-wrapper">
<img :src="item.ava || item.qrCode" class="qrcode-img" />
</div>
<div class="student-info">
<ul>
<li>姓名{{ item.realName || '-' }}</li>
<li>班级{{ item.className || '-' }}</li>
<li>系部{{ item.deptName || '-' }}</li>
<li>学号{{ item.stuNo || '-' }}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</template>
<script setup lang="ts" name="StudentIdCardPrint">
import { ref, computed } from 'vue';
import { preBatchPrint, prePrint } from '/@/api/basic/basicstudent';
import { useMessage } from '/@/hooks/message';
// 默认头像
const defaultAvatar = '/img/avatar-default.png';
// 定义变量
const visible = ref(false);
const loading = ref(false);
const isPrinting = ref(false);
const printRef = ref();
const studentList = ref<any[]>([]);
// 计算打印页面每页4个学生
const printPages = computed(() => {
const pages: any[][] = [];
const students = studentList.value;
const totalPages = Math.ceil(students.length / 4);
for (let i = 0; i < totalPages; i++) {
const pageStudents = students.slice(i * 4, (i + 1) * 4);
pages.push(pageStudents);
}
return pages;
});
// 获取背景样式
const getBackgroundStyle = (item: any) => {
if (item.roomNo) {
return "background-image: url('/img/bg/zss.jpeg');";
}
return "background-image: url('/img/bg/userphotobg.jpg');";
};
// 打开弹窗 - 批量打印传入选中的学生完整JSON数据
const openDialog = async (selectedRows: any[]) => {
if (!selectedRows || selectedRows.length === 0) {
useMessage().warning('请先选择要打印的学生');
return;
}
visible.value = true;
loading.value = true;
try {
// 调用后端接口,传入选中的学生完整数据
const res = await preBatchPrint(selectedRows);
if (res.data && Array.isArray(res.data)) {
studentList.value = res.data;
} else {
// 如果后端没有返回数据,直接使用前端数据
studentList.value = selectedRows;
}
} catch (err: any) {
// 如果接口报错,直接使用前端数据
studentList.value = selectedRows;
console.warn('获取打印数据失败,使用前端数据', err);
} finally {
loading.value = false;
}
};
// 打开弹窗 - 单个学生打印
const openSingleDialog = async (row: any) => {
if (!row.stuNo) {
useMessage().warning('学号不存在');
return;
}
visible.value = true;
loading.value = true;
try {
const res = await prePrint(row.stuNo);
if (res.data) {
studentList.value = [res.data];
} else {
studentList.value = [row];
}
} catch (err: any) {
studentList.value = [row];
console.warn('获取打印数据失败,使用前端数据', err);
} finally {
loading.value = false;
}
};
// 执行打印
const handlePrint = () => {
isPrinting.value = true;
setTimeout(() => {
window.print();
isPrinting.value = false;
}, 100);
};
// 暴露方法
defineExpose({
openDialog,
openSingleDialog,
});
</script>
<style lang="scss" scoped>
.print-container {
height: 100%;
overflow: auto;
}
.print-actions {
position: fixed;
top: 80px;
right: 80px;
z-index: 100;
background: #fff;
padding: 10px 20px;
border-radius: 4px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.print-content {
padding: 20px;
}
.print-page {
width: 29.7cm;
height: 19.2cm;
margin: 0 auto 20px;
page-break-after: always;
&:last-child {
page-break-after: auto;
}
}
.card-wrapper {
width: 7cm;
height: 10cm;
border: 1px #0508b8 solid;
margin-left: 5cm;
margin-top: 0.3cm;
margin-bottom: 0.3cm;
float: left;
background-repeat: no-repeat;
background-size: 100% auto;
background-position: center;
}
.photo-area {
width: 2.5cm;
margin: 0 auto;
height: 5.8cm;
display: flex;
align-items: center;
justify-content: center;
}
.student-photo {
width: 2.5cm;
height: 3cm;
object-fit: cover;
margin-top: 2cm;
}
.info-area {
width: 6.5cm;
margin: 0 auto;
display: flex;
align-items: flex-start;
}
.qrcode-wrapper {
width: 2.5cm;
flex-shrink: 0;
}
.qrcode-img {
width: 2.5cm;
height: 2.5cm;
object-fit: contain;
}
.student-info {
width: 4cm;
flex-shrink: 0;
ul {
margin: 0;
padding: 0;
list-style: none;
li {
line-height: 23px;
font-size: 14px;
}
}
}
@media print {
.print-actions {
display: none !important;
}
:deep(.el-dialog__header),
:deep(.el-dialog__footer) {
display: none !important;
}
:deep(.el-dialog) {
margin: 0 !important;
max-width: 100% !important;
width: 100% !important;
}
:deep(.el-dialog__body) {
padding: 0 !important;
}
.print-content {
padding: 0;
}
.print-page {
margin: 0;
}
body {
-webkit-print-color-adjust: exact;
-moz-print-color-adjust: exact;
-ms-print-color-adjust: exact;
print-color-adjust: exact;
}
}
</style>

View File

@@ -226,6 +226,9 @@
<!-- 简单信息维护对话框 -->
<SimpleEditDialog ref="simpleEditDialogRef" @refresh="getDataList(false)" />
<!-- 学生证件照打印 -->
<PrintDialog ref="printDialogRef" />
<!-- 段段清证书导入对话框 -->
<el-dialog title="段段清证书导入" v-model="importCertificateDialogVisible" :close-on-click-modal="false" draggable width="500px">
<el-upload
@@ -335,7 +338,7 @@ import {
preBatchPrint,
importCertificate,
exportStuInfoCard,
exportCertificate,
makeExportSkillLevelTask,
resetPassWord,
editIsleader,
updateInout,
@@ -355,12 +358,14 @@ import { makeExportClassRoomHygieneMonthlyTask } from '/@/api/stuwork/file';
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
const DetailDialog = defineAsyncComponent(() => import('./components/StudentDetail.vue'));
const SimpleEditDialog = defineAsyncComponent(() => import('./components/SimpleEdit.vue'));
const PrintDialog = defineAsyncComponent(() => import('./components/StudentIdCardPrint.vue'));
// 定义变量内容
const route = useRoute();
const formDialogRef = ref();
const detailDialogRef = ref();
const simpleEditDialogRef = ref();
const printDialogRef = ref();
const searchFormRef = ref();
const uploadRef = ref();
const columnControlRef = ref();
@@ -731,8 +736,12 @@ const handleExportAvatar = async () => {
};
// 批量打印
const handleBatchPrint = async () => {
useMessage().warning('功能开发中');
const handleBatchPrint = () => {
if (selectedRows.value.length === 0) {
useMessage().warning('请先选择要打印的学生');
return;
}
printDialogRef.value?.openDialog(selectedRows.value);
};
// 段段清证书导入
@@ -808,7 +817,15 @@ const handleExportStudentCard = async () => {
// 证书导出
const handleExportCertificate = async () => {
useMessage().warning('功能开发中');
try {
await makeExportSkillLevelTask({
deptCode: searchForm.deptCode,
classCode: searchForm.classCode,
});
useMessage().success('导出任务已创建,请在文件管理中下载');
} catch (err: any) {
useMessage().error(err.msg || '创建导出任务失败');
}
};
// 简单信息维护
@@ -822,38 +839,8 @@ const handleViewDetail = (row: any) => {
};
// 打印证件照
const handlePrintPhoto = async (row: any) => {
if (!row.stuNo) {
useMessage().warning('学号不存在');
return;
}
try {
const res = await prePrint(row.stuNo);
if (res.data) {
// 打开新窗口进行打印
const printWindow = window.open('', '_blank');
if (printWindow) {
printWindow.document.write(`
<html>
<head><title>学生证件照打印</title></head>
<body>
<h2 style="text-align:center;">学生证打印</h2>
<div style="text-align:center;">
<p><strong>姓名:</strong>${res.data.realName || row.realName || '-'}</p>
<p><strong>学号:</strong>${res.data.stuNo || row.stuNo || '-'}</p>
<p><strong>班级:</strong>${res.data.className || row.className || '-'}</p>
<p><strong>身份证号:</strong>${res.data.idCard || row.idCard || '-'}</p>
</div>
<script>window.onload = function() { window.print(); }<\/script>
</body>
</html>
`);
printWindow.document.close();
}
}
} catch (err: any) {
useMessage().error(err.msg || '获取打印信息失败');
}
const handlePrintPhoto = (row: any) => {
printDialogRef.value?.openSingleDialog(row);
};
// 重置密码