diff --git a/src/api/base/server.ts b/src/api/base/server.ts
index dc618aa..c8cda98 100644
--- a/src/api/base/server.ts
+++ b/src/api/base/server.ts
@@ -1,82 +1,89 @@
// 参数接口
// 响应接口
-import {get, post} from "@/utils/request";
+import { get, post } from "@/utils/request";
/**
* 获取服务器时间
*/
export const xqgwFindAllApi = async () => {
- return await get("/api/xqgw/findAll");
+ return await get("/api/xqgw/findAll");
};
export const xqxjFindAllApi = async () => {
- return await get("/api/xqxj/findAll");
+ return await get("/api/xqxj/findAll");
};
export const findAllNjBjTreeApi = async () => {
- return await get("/api/nj/findAllNjBjTree");
+ return await get("/api/nj/findAllNjBjTree");
};
export const kmFindAllApi = async () => {
- return await get("/api/km/findAll");
+ return await get("/api/km/findAll");
};
export const findAllXxXqNjTree = async () => {
- return await get("/api/nj/findAllXxXqNjTree");
+ return await get("/api/nj/findAllXxXqNjTree");
};
export const findAllNjBjTree = async () => {
- return await get("/api/nj/findAllNjBjTree");
+ return await get("/api/nj/findAllNjBjTree");
};
export const jsConfirmJsDataApi = async (params: any) => {
- return await post("/api/js/confirmJsData", params);
+ return await post("/api/js/confirmJsData", params);
};
export const jsdFindPageTaskApi = async (params: any) => {
- return await get("/api/jsd/findPageTask", params);
+ return await get("/api/jsd/findPageTask", params);
};
export const rwflFindRwlxsByRwId = async (params: any) => {
- return await get("/api/rwlx/findRwlxsByRwId", params);
-}
+ return await get("/api/rwlx/findRwlxsByRwId", params);
+};
export const rwzxSaveApi = async (params: any) => {
- return await post("/api/rwzx/save", params);
+ return await post("/api/rwzx/save", params);
};
export const rwzxExecutedInfoByRwIdAndJsApi = async (params: any) => {
- return await get("/api/rwzx/executedInfoByRwIdAndJs", params);
+ return await get("/api/rwzx/executedInfoByRwIdAndJs", params);
};
-
export const rwFindInfoByRwId = async (params: any) => {
- return await get("/api/rw/findInfoByRwId", params);
-}
+ return await get("/api/rw/findInfoByRwId", params);
+};
export const fractionRuleApi = async () => {
- return await get(
- "/api/fractionRule/findAllByItemId?itemId=CDFDED2A704F46E2A4D7E8816968BD23"
- );
+ return await get(
+ "/api/fractionRule/findAllByItemId?itemId=CDFDED2A704F46E2A4D7E8816968BD23"
+ );
};
export const fractionRuleApi1 = async () => {
- return await get(
- "/api/fractionRule/findAllByItemId?itemId=B96A0FA22C414F71A3E1CDCA7E206B10"
- );
+ return await get(
+ "/api/fractionRule/findAllByItemId?itemId=B96A0FA22C414F71A3E1CDCA7E206B10"
+ );
};
// 查询教师信息
export const jsdfindJsByPhoneApi = async (params: any) => {
- return await get("/api/js/findJsByPhone", params);
+ return await get("/api/js/findJsByPhone", params);
};
// 选课列表
export const jsdXkListApi = async (params: any) => {
- return await get("/mobile/js/xk/list", params);
+ return await get("/mobile/js/xk/list", params);
};
// 选课列表
export const jsdXkkcSaveApi = async (params: any) => {
- return await post("/api/xkkc/save", params);
+ return await post("/api/xkkc/save", params);
};
// 选课学生列表
export const jsdXkXsListApi = async (params: any) => {
- return await get("/mobile/js/xkxs/list", params);
+ return await get("/mobile/js/xkxs/list", params);
+};
+export const mobilejlstudentListApi = async (params: any) => {
+ return await get("/mobile/jl/studentList", params);
+};
+
+export const mobilejllistApi = async (params: any) => {
+ const res = await get("/mobile/jl/list", params);
+ return res.result;
};
// 提交点名信息
export const jsdXkdmListApi = async (params: any) => {
- return await post("/mobile/js/xkdm/add", params);
+ return await post("/mobile/js/xkdm/add", params);
};
diff --git a/src/config.ts b/src/config.ts
index 7b4929d..bf5bbad 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -1,4 +1,5 @@
-const ip: string = "192.168.239.1:8897";
+// const ip: string = "192.168.239.1:8897";
+const ip: string = "yufangzc.com";
// const ip: string = "yufangzc.com";
const fwqip: string = "yufangzc.com";
//打包服务器接口代理标识
diff --git a/src/pages/view/hr/teacherProfile/PositionInfo.vue b/src/pages/view/hr/teacherProfile/PositionInfo.vue
index 549095a..ac7e5cb 100644
--- a/src/pages/view/hr/teacherProfile/PositionInfo.vue
+++ b/src/pages/view/hr/teacherProfile/PositionInfo.vue
@@ -226,29 +226,6 @@ if (getFile.rgqkList && getFile.rgqkList.length > 0) {
});
}
-// 手动触发计算所有项目的任岗年限
-const calculateAllPositionYears = () => {
- education.xl.forEach((item: any, index: number) => {
- if (item.value.gwrzkstime) {
- const years = calculatePositionYears(
- item.value.gwrzkstime,
- item.value.gwrzjstime
- );
- item.value.gwrznx = years;
- console.log(`表单项${index}计算结果:`, {
- gwrzkstime: item.value.gwrzkstime,
- gwrzjstime: item.value.gwrzjstime,
- gwrznx: years,
- 是否为0: years === "0",
- });
- } else {
- // 没有开始时间时,清空任岗年限
- item.value.gwrznx = "";
- }
- });
- forceUpdateKey.value++;
-};
-
function addEducation() {
education.xl.push({ value: {} });
// 强制重新渲染
diff --git a/src/pages/view/notice/index.vue b/src/pages/view/notice/index.vue
index 2547b7b..0a1c254 100644
--- a/src/pages/view/notice/index.vue
+++ b/src/pages/view/notice/index.vue
@@ -1,38 +1,55 @@
-
-
-
-
-
-
-
-
-
- 暂无数据
+
+
@@ -215,11 +206,8 @@ const formatTime = (timeStr: string) => {
}
}
-// FAB 按钮样式
+// FAB 按钮样式 - 由 DragButton 组件处理定位
.fab-button {
- position: fixed;
- right: 20px;
- bottom: 40px; // 根据需要调整距离底部的距离
width: 50px;
height: 50px;
background-color: #4477ee;
@@ -228,12 +216,7 @@ const formatTime = (timeStr: string) => {
justify-content: center;
align-items: center;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
- z-index: 10;
}
-.empty-list {
- text-align: center;
- color: #999;
- margin-top: 40px;
-}
+/* 空列表样式已由 BasicListLayout 组件处理,移除此样式 */
diff --git a/src/pages/view/notice/publish.vue b/src/pages/view/notice/publish.vue
index 355fe57..c385a54 100644
--- a/src/pages/view/notice/publish.vue
+++ b/src/pages/view/notice/publish.vue
@@ -15,7 +15,7 @@
@@ -80,45 +80,35 @@
- 添加图文/视频/文件/公众号/小程序等
+ 添加图文/视频/文件
-
-
+
{{ name }}
-
+
+
@@ -165,17 +155,64 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ name }}
+
+
+
+
@@ -183,6 +220,10 @@
import { ref, reactive, computed } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import CustomUpload from "/src/components/BasicUpload/CustomUpload.vue";
+import BasicTree from "@/components/BasicTree/Tree.vue";
+import { attachmentUpload } from "@/api/system/upload";
+import { imagUrl } from "@/utils";
+import { findAllNjBjTree, mobilejlstudentListApi } from "@/api/base/server";
interface Attachment {
name: string;
@@ -200,6 +241,8 @@ interface FormData {
targetClass: string;
targetNames: string[];
targetStudentIds: string[];
+ targetNjIds: string[]; // 年级ID数组
+ targetBjIds: string[]; // 班级ID数组
signatureRequired: boolean;
startTime: string;
endTime: string;
@@ -215,6 +258,8 @@ const formData = reactive({
targetClass: "",
targetNames: [],
targetStudentIds: [],
+ targetNjIds: [],
+ targetBjIds: [],
signatureRequired: false,
startTime: "",
endTime: "",
@@ -225,38 +270,40 @@ const signatureStatusText = computed(() => {
return formData.signatureRequired ? "启用" : "不启用";
});
-const classList = ref([
- { id: "g1c1", name: "一年级1班" },
- { id: "g1c2", name: "一年级2班" },
- { id: "g1c3", name: "一年级3班" },
- { id: "g1c4", name: "一年级4班" },
- { id: "g1c5", name: "一年级5班" },
- { id: "g2c1", name: "二年级1班" },
- { id: "g2c2", name: "二年级2班" },
- { id: "g2c3", name: "二年级3班" },
- { id: "g3c1", name: "三年级1班" },
- { id: "g3c2", name: "三年级2班" },
- { id: "g3c3", name: "三年级3班" },
- { id: "g3c4", name: "三年级4班" },
- { id: "g4c1", name: "四年级1班" },
- { id: "g4c2", name: "四年级2班" },
- { id: "g5c1", name: "五年级1班" },
- { id: "g5c2", name: "五年级2班" },
- { id: "g5c3", name: "五年级3班" },
- { id: "g6c1", name: "六年级1班" },
- { id: "g6c2", name: "六年级2班" },
-]);
+// 树形数据
+const treeData = ref([]);
+const treeRef = ref();
-const combinedClassRange = computed(() => {
- return classList.value.map((cls) => cls.name);
+// 学生显示相关
+const maxDisplayCount = 24; // 最多显示24个学生(4行×6列)
+const showStudentModal = ref(false);
+
+// 计算显示的学生名单(最多显示前24个)
+const displayNames = computed(() => {
+ return formData.targetNames.slice(0, maxDisplayCount);
});
-const selectedClassIndex = computed(() => {
- const index = classList.value.findIndex(
- (cls) => cls.name === formData.targetClass
- );
- return index >= 0 ? index : 0;
-});
+// 加载树形数据
+const loadTreeData = async () => {
+ try {
+ const res = await findAllNjBjTree();
+ if (res.resultCode === 1 && res.result) {
+ // 转换数据格式以适配 BasicTree 组件
+ treeData.value = res.result.map((item: any) => ({
+ key: item.key,
+ title: item.title,
+ children: item.children || [],
+ }));
+ console.log("树形数据加载成功:", treeData.value);
+ }
+ } catch (error) {
+ console.error("加载树形数据失败:", error);
+ uni.showToast({ title: "加载班级数据失败", icon: "error" });
+ }
+};
+
+// 在组件挂载时加载数据
+loadTreeData();
const fetchStudentsByClass = async (className: string): Promise => {
console.log(`模拟获取班级 [${className}] 的学生列表...`);
@@ -281,40 +328,42 @@ const fetchStudentsByClass = async (className: string): Promise => {
return mockStudents;
};
-onLoad((options) => {
- if (options && options.id) {
- noticeId.value = options.id;
- uni.setNavigationBarTitle({ title: "编辑通知" });
- formData.title = "关于五一放假的通知 (编辑)";
- formData.content = "根据校历安排,现将2024年五一劳动节放假安排通知如下...";
- formData.targetClass = "二年级1班";
- formData.targetNames = ["张三", "李四"];
- formData.targetStudentIds = ["s201-mock", "s202-mock"];
- formData.signatureRequired = true;
- formData.startTime = "2024-04-30 18:00:00";
- formData.endTime = "2024-05-05 23:59:59";
- if (formData.targetClass && noticeId.value) {
- fetchStudentsByClass(formData.targetClass).then((students) => {
- formData.targetNames = students;
- });
- }
- } else {
- uni.setNavigationBarTitle({ title: "发布通知" });
- }
-});
+onLoad((options) => {});
-const handleCoverSelected = (e: any) => {
- console.log("选择封面 (CustomUpload):", e);
+const handleCoverSelected = async (e: any) => {
if (e.tempFilePaths && e.tempFilePaths.length > 0) {
- formData.coverImage = e.tempFilePaths[0];
- console.log("封面临时路径:", formData.coverImage);
+ const tempFilePath = e.tempFilePaths[0];
+
+ try {
+ uni.showLoading({ title: "上传中..." });
+
+ // 直接使用 tempFilePath 作为 Blob 传给接口
+ const uploadResult: any = await attachmentUpload(tempFilePath as any);
+
+ if (
+ uploadResult.resultCode === 1 &&
+ uploadResult.result &&
+ uploadResult.result.length > 0
+ ) {
+ // 保存原始的 filePath(用于提交到服务器)
+ const originalPath = uploadResult.result[0].filePath;
+ formData.coverImage = originalPath;
+ uni.showToast({ title: "封面上传成功", icon: "success" });
+ } else {
+ throw new Error("上传响应格式异常");
+ }
+ } catch (error) {
+ uni.showToast({ title: "封面上传失败", icon: "error" });
+ formData.coverImage = null;
+ } finally {
+ uni.hideLoading();
+ }
} else {
console.error("无法从选择事件中获取封面路径:", e);
}
};
const handleCoverClosed = (field: string) => {
- console.log(`删除封面 (CustomUpload): field=${field}`);
if (field === "coverImage") {
formData.coverImage = null;
}
@@ -324,47 +373,74 @@ const addAttachment = () => {
uni.chooseFile({
count: 5,
type: "all",
- success: (res) => {
+ success: async (res) => {
const tempFiles = res.tempFiles;
if (Array.isArray(tempFiles) && tempFiles.length > 0) {
- tempFiles.forEach((file: any) => {
- let fileType = "file";
- const fileName = file.name || "";
- const fileExtension = fileName.split(".").pop()?.toLowerCase();
+ uni.showLoading({ title: "上传中..." });
- if (
- ["png", "jpg", "jpeg", "gif", "bmp", "webp"].includes(
- fileExtension || ""
- )
- ) {
- fileType = "image";
- } else if (
- ["mp4", "mov", "avi", "wmv", "flv"].includes(fileExtension || "")
- ) {
- fileType = "video";
- } else if (
- ["mp3", "wav", "aac", "ogg"].includes(fileExtension || "")
- ) {
- fileType = "audio";
+ try {
+ for (const file of tempFiles) {
+ const fileInfo = file as any; // 强制类型转换避免类型检查错误
+ let fileType = "file";
+ const fileName = fileInfo.name || "";
+ const fileExtension = fileName.split(".").pop()?.toLowerCase();
+
+ if (
+ ["png", "jpg", "jpeg", "gif", "bmp", "webp"].includes(
+ fileExtension || ""
+ )
+ ) {
+ fileType = "image";
+ } else if (
+ ["mp4", "mov", "avi", "wmv", "flv"].includes(fileExtension || "")
+ ) {
+ fileType = "video";
+ } else if (
+ ["mp3", "wav", "aac", "ogg"].includes(fileExtension || "")
+ ) {
+ fileType = "audio";
+ }
+
+ if (
+ fileInfo.type &&
+ typeof fileInfo.type === "string" &&
+ (fileInfo.type.startsWith("image/") ||
+ fileInfo.type.startsWith("video/") ||
+ fileInfo.type.startsWith("audio/"))
+ ) {
+ fileType = fileInfo.type.split("/")[0];
+ }
+
+ // 直接使用文件路径作为 Blob 传给接口
+ const uploadResult: any = await attachmentUpload(
+ fileInfo.path as any
+ );
+
+ if (
+ uploadResult.resultCode === 1 &&
+ uploadResult.result &&
+ uploadResult.result.length > 0
+ ) {
+ // 保存原始的 filePath(用于提交到服务器)
+ const originalPath = uploadResult.result[0].filePath;
+ formData.attachments.push({
+ name: fileName,
+ type: fileType,
+ url: originalPath, // 保存原始路径
+ size: fileInfo.size,
+ });
+ } else {
+ uni.showToast({ title: `${fileName} 上传失败`, icon: "error" });
+ }
}
- if (
- file.type &&
- typeof file.type === "string" &&
- (file.type.startsWith("image/") ||
- file.type.startsWith("video/") ||
- file.type.startsWith("audio/"))
- ) {
- fileType = file.type.split("/")[0];
- }
-
- formData.attachments.push({
- name: fileName,
- type: fileType,
- url: file.path,
- size: file.size,
- });
- });
+ uni.showToast({ title: "附件上传完成", icon: "success" });
+ } catch (error) {
+ console.error("附件上传失败:", error);
+ uni.showToast({ title: "附件上传失败", icon: "error" });
+ } finally {
+ uni.hideLoading();
+ }
} else {
console.log("未选择任何文件或返回结果异常,或 tempFiles 不是数组");
}
@@ -391,38 +467,124 @@ const getAttachmentIcon = (type: string): string => {
const previewAttachment = (attachment: Attachment) => {
console.log("预览附件:", attachment);
- uni.showToast({ title: `预览 ${attachment.name} 功能待实现`, icon: "none" });
+ // 如果是图片类型,可以预览
+ if (attachment.type === "image") {
+ const fullUrl = imagUrl(attachment.url);
+ uni.previewImage({
+ urls: [fullUrl],
+ current: fullUrl,
+ });
+ } else {
+ uni.showToast({
+ title: `预览 ${attachment.name} 功能待实现`,
+ icon: "none",
+ });
+ }
};
-const onClassPickerChange = async (e: any) => {
- const index = e.detail.value;
- const selectedClass = classList.value[index];
- if (selectedClass && selectedClass.name !== formData.targetClass) {
- formData.targetClass = selectedClass.name;
+// 显示班级选择树
+const showClassTree = () => {
+ if (treeRef.value) {
+ treeRef.value._show();
+ }
+};
+
+// 树形选择确认
+const onTreeConfirm = async (selectedItems: any[]) => {
+ console.log("选择的班级:", selectedItems);
+ if (selectedItems.length > 0) {
+ // 处理多选情况
+ const classNames = selectedItems.map((item) => item.title);
+ formData.targetClass = classNames.join(", ");
formData.targetNames = [];
formData.targetStudentIds = [];
+ formData.targetNjIds = [];
+ formData.targetBjIds = [];
+
try {
- const students = await fetchStudentsByClass(formData.targetClass);
- formData.targetNames = students;
+ uni.showLoading({ title: "获取学生列表中..." });
+
+ // 提取年级ID和班级ID
+ const njIds: string[] = [];
+ const bjIds: string[] = [];
+
+ selectedItems.forEach((item) => {
+ // 如果选择的是班级(有parents表示是班级)
+ if (item.parents && item.parents.length > 0) {
+ const njId = item.parents[0].key; // 年级ID:parents[0].key
+ const bjId = item.key; // 班级ID:item.key
+ njIds.push(njId);
+ bjIds.push(bjId);
+ console.log(
+ `选择班级: ${item.title}, 年级ID: ${njId}, 班级ID: ${bjId}`
+ );
+ }
+ });
+
+ if (njIds.length > 0 && bjIds.length > 0) {
+ // 对年级ID去重
+ const uniqueNjIds = [...new Set(njIds)];
+
+ // 保存选择的年级ID和班级ID到formData中
+ formData.targetNjIds = uniqueNjIds;
+ formData.targetBjIds = bjIds;
+
+ // 调用接口获取学生列表
+ const params = {
+ njId: uniqueNjIds.join(","),
+ bjId: bjIds.join(","),
+ };
+
+ const response = await mobilejlstudentListApi(params);
+
+ if (response && response.resultCode === 1 && response.result) {
+ // 提取学生姓名,尝试多个可能的字段名
+ const studentNames = response.result.map(
+ (student: any) =>
+ student.xsxm ||
+ student.name ||
+ student.studentName ||
+ student.xm ||
+ "未知姓名"
+ );
+ formData.targetNames = studentNames;
+ formData.targetStudentIds = response.result.map(
+ (student: any) =>
+ student.id || student.xsId || student.studentId || ""
+ );
+ } else {
+ throw new Error("获取学生列表失败");
+ }
+ }
+
+ uni.hideLoading();
+ uni.showToast({
+ title: `已选择 ${selectedItems.length} 个班级`,
+ icon: "success",
+ });
} catch (error) {
console.error("获取学生列表失败:", error);
- uni.showToast({ title: "获取学生列表失败", icon: "none" });
+ uni.hideLoading();
+ uni.showToast({ title: "获取学生列表失败", icon: "error" });
+ // 如果接口失败,使用模拟数据
+ formData.targetNames = await fetchStudentsByClass(formData.targetClass);
}
}
};
-const handleModifyNames = () => {
- const selectedClassObj = classList.value.find(
- (cls) => cls.name === formData.targetClass
- );
- if (!selectedClassObj) {
- uni.showToast({ title: "请先选择班级", icon: "none" });
- return;
- }
- const classId = selectedClassObj.id;
- uni.navigateTo({
- url: `/pages/view/notice/selectStudents?classId=${classId}`,
- });
+// 树形选择取消
+const onTreeCancel = () => {
+ console.log("取消选择班级");
+};
+
+// 显示全部学生
+const showAllStudents = () => {
+ showStudentModal.value = true;
+};
+
+// 关闭学生弹窗
+const closeStudentModal = () => {
+ showStudentModal.value = false;
};
const handleSignatureChange = (e: any) => {
@@ -464,13 +626,25 @@ const previewNotice = () => {
const publishNotice = () => {
if (!validateForm()) return;
- console.log("发布通知", formData);
- uni.showLoading({ title: "发布中..." });
- setTimeout(() => {
- uni.hideLoading();
- uni.showToast({ title: "发布成功 (模拟)", icon: "success" });
- uni.navigateBack();
- }, 1000);
+
+ // 准备发布数据,包含年级ID和班级ID
+ const publishData = {
+ ...formData,
+ njIds: formData.targetNjIds.join(","), // 年级ID字符串
+ bjIds: formData.targetBjIds.join(","), // 班级ID字符串
+ };
+
+ console.log("发布通知数据:", publishData);
+ console.log("年级ID:", publishData.njIds);
+ console.log("班级ID:", publishData.bjIds);
+
+ // TODO: 调用发布接口
+ // uni.showLoading({ title: "发布中..." });
+ // setTimeout(() => {
+ // uni.hideLoading();
+ // uni.showToast({ title: "发布成功 (模拟)", icon: "success" });
+ // uni.navigateBack();
+ // }, 1000);
};
@@ -496,10 +670,10 @@ const publishNotice = () => {
}
.form-container {
- padding: 12px;
+ padding: 12px;
box-sizing: border-box;
/* Add padding-bottom if content gets hidden by bottom bar */
- /* padding-bottom: 70px; */
+ /* padding-bottom: 70px; */
}
.info-card {
@@ -734,8 +908,7 @@ const publishNotice = () => {
position: relative;
min-height: 30px;
- .name-tag,
- .modify-btn {
+ .name-tag {
font-size: 13px;
padding: 5px 0;
border-radius: 4px;
@@ -746,29 +919,10 @@ const publishNotice = () => {
flex-basis: calc((100% - 50px) / 6);
height: 28px;
line-height: 18px;
- }
-
- .name-tag {
background-color: #f4f4f5;
color: #909399;
}
- .modify-btn {
- background-color: #ecf5ff;
- color: #409eff;
- border: 1px solid #d9ecff;
- padding: 0;
- margin-left: 0;
- margin-top: 0;
- margin-bottom: 0;
- &::after {
- border: none;
- }
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
.loading-spinner {
position: absolute;
top: 5px;
@@ -778,6 +932,26 @@ const publishNotice = () => {
}
}
+.more-btn-container {
+ width: 100%;
+}
+
+.more-btn-full {
+ width: 100%;
+ height: 35px;
+ background-color: #fff2e8;
+ color: #e6a23c;
+ border: 1px solid #f5dab1;
+ border-radius: 4px;
+ font-size: 14px;
+ &::after {
+ border: none;
+ }
+ &:active {
+ background-color: #ffecd1;
+ }
+}
+
.list-item-card {
padding: 0;
.uni-datetime-picker,
@@ -841,7 +1015,7 @@ const publishNotice = () => {
display: flex;
justify-content: space-around;
align-items: center;
- padding: 12px 15px;
+ padding: 12px 15px;
background-color: #ffffff;
border-top: 1px solid #e5e5e5;
@@ -887,7 +1061,76 @@ const publishNotice = () => {
}
.target-class text.placeholder {
- color: #909399;
+ color: #909399;
}
+/* 学生名单弹窗样式 */
+.student-modal-mask {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 9999;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.student-modal {
+ width: 90%;
+ max-height: 80%;
+ background-color: #ffffff;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+.student-modal-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 15px 20px;
+ border-bottom: 1px solid #f0f0f0;
+ background-color: #fafafa;
+}
+
+.modal-title {
+ font-size: 16px;
+ font-weight: 500;
+ color: #303133;
+}
+
+.student-count {
+ font-size: 14px;
+ color: #909399;
+}
+
+.close-icon {
+ cursor: pointer;
+ padding: 5px;
+}
+
+.student-modal-content {
+ max-height: 400px;
+ padding: 20px;
+}
+
+.all-student-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px 10px;
+}
+
+.student-tag {
+ font-size: 13px;
+ padding: 6px 12px;
+ border-radius: 4px;
+ text-align: center;
+ background-color: #f4f4f5;
+ color: #909399;
+ min-width: 60px;
+ box-sizing: border-box;
+}