|
|
@@ -0,0 +1,771 @@
|
|
|
+<template>
|
|
|
+ <view class="page_select_object">
|
|
|
+ <view class="select_header">
|
|
|
+ <uni-icons type="back" size="24" color="#333333" @click="goBack"></uni-icons>
|
|
|
+ <text class="header_title">选择通知对象</text>
|
|
|
+ <text class="header_placeholder"></text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="tabs_container">
|
|
|
+ <view v-for="tab in tabs" :key="tab.key" class="tab_item" :class="{ active: activeTab === tab.key, disabled: editMode }"
|
|
|
+ @click="!editMode && handleTabChange(tab.key)">
|
|
|
+ <text class="tab_text">{{ tab.label }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="search_container">
|
|
|
+ <view class="search_box">
|
|
|
+ <image src="/static/image/icon/search.png" class="search_icon" mode="aspectFit"></image>
|
|
|
+ <input type="text" class="search_input" v-model="searchKeyword" @input="searchTree(searchKeyword)" placeholder="请输入关键字搜索" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <scroll-view scroll-y class="content_list">
|
|
|
+ <TreeNode :tree-data="treeData" :expanded-ids="expandedIds" @toggle-expand="toggleExpand"
|
|
|
+ @toggle-select="toggleSelect" />
|
|
|
+ </scroll-view>
|
|
|
+
|
|
|
+ <view class="select_footer">
|
|
|
+ <view class="confirm_btn" @click="handleConfirm">
|
|
|
+ <text class="btn_text">确定(已选{{ selectedCount }}人)</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed, onMounted } from 'vue';
|
|
|
+import uniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue';
|
|
|
+import TreeNode from '@/components/tree-node.vue';
|
|
|
+import overview from '@/reqApi/overview.js';
|
|
|
+
|
|
|
+const activeTab = ref('department');
|
|
|
+const searchKeyword = ref('');
|
|
|
+const schoolYearId = ref('');
|
|
|
+const editMode = ref(false);
|
|
|
+const noticeType = ref(0);
|
|
|
+const selectedUserIds = ref([]);
|
|
|
+
|
|
|
+const tabs = [
|
|
|
+ { key: 'department', label: '按部门' },
|
|
|
+ { key: 'subject', label: '按学科' },
|
|
|
+ { key: 'grade', label: '按年级' },
|
|
|
+ { key: 'permission', label: '按权限' },
|
|
|
+ { key: 'student', label: '按学生' }
|
|
|
+];
|
|
|
+
|
|
|
+const treeData = ref([]);
|
|
|
+const fullTreeData = ref([]);
|
|
|
+const expandedIds = ref([]);
|
|
|
+
|
|
|
+// 按 teacherId 去重用户列表
|
|
|
+const deduplicateUsers = (users) => {
|
|
|
+ if (!users || !Array.isArray(users)) return [];
|
|
|
+ const seen = new Set();
|
|
|
+ return users.filter(user => {
|
|
|
+ if (user.teacherId && seen.has(user.teacherId)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (user.teacherId) {
|
|
|
+ seen.add(user.teacherId);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 转换按部门接口数据为树形结构
|
|
|
+const transformDepartmentData = (data) => {
|
|
|
+ if (!data || !Array.isArray(data)) return [];
|
|
|
+
|
|
|
+ return data.map(dept => {
|
|
|
+ const groups = (dept.groupVOS || []).map(group => ({
|
|
|
+ id: group.groupId,
|
|
|
+ name: group.groupName,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false,
|
|
|
+ children: deduplicateUsers(group.groupUserVOS || []).map(user => ({
|
|
|
+ id: user.userId,
|
|
|
+ name: `${user.teacherName} (${user.userAccount})`,
|
|
|
+ userId: user.userId,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false
|
|
|
+ }))
|
|
|
+ }));
|
|
|
+
|
|
|
+ return {
|
|
|
+ id: dept.id,
|
|
|
+ name: dept.name,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false,
|
|
|
+ children: groups
|
|
|
+ };
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 根据 userId 同步所有相同用户的选中状态
|
|
|
+const syncTeacherSelection = (userId, checked) => {
|
|
|
+ const syncNode = (nodes) => {
|
|
|
+ nodes.forEach(node => {
|
|
|
+ if (node.userId && node.userId === userId) {
|
|
|
+ node.checked = checked;
|
|
|
+ node.halfChecked = false;
|
|
|
+ }
|
|
|
+ if (node.children && node.children.length > 0) {
|
|
|
+ syncNode(node.children);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+ syncNode(treeData.value);
|
|
|
+};
|
|
|
+
|
|
|
+// 转换按学科的数据为树形结构
|
|
|
+const transformSubjectData = (data) => {
|
|
|
+ if (!data || !Array.isArray(data)) return [];
|
|
|
+
|
|
|
+ return data.map(subject => {
|
|
|
+ const grades = (subject.gradePersonVos || []).map(grade => ({
|
|
|
+ id: grade.schoolYearGradeId || grade.gradeCode,
|
|
|
+ name: grade.gradeName,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false,
|
|
|
+ children: deduplicateUsers(grade.personVoList || []).map(user => ({
|
|
|
+ id: user.userId,
|
|
|
+ name: `${user.teacherName} (${user.userAccount})`,
|
|
|
+ userId: user.userId,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false
|
|
|
+ }))
|
|
|
+ }));
|
|
|
+
|
|
|
+ return {
|
|
|
+ id: subject.subjectCode,
|
|
|
+ name: subject.subjectName,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false,
|
|
|
+ children: grades
|
|
|
+ };
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 转换按年级的数据为树形结构
|
|
|
+const transformGradeData = (data) => {
|
|
|
+ if (!data || !Array.isArray(data)) return [];
|
|
|
+
|
|
|
+ return data.map(grade => {
|
|
|
+ const classTypes = (grade.classTypePersonVoList || []).map(classType => {
|
|
|
+ const classes = (classType.classInfoPersonVoList || []).map(cls => ({
|
|
|
+ id: cls.classCode,
|
|
|
+ name: cls.className,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false,
|
|
|
+ children: deduplicateUsers(cls.personVoList || []).map(user => ({
|
|
|
+ id: user.userId,
|
|
|
+ name: `${user.teacherName} (${user.userAccount})`,
|
|
|
+ userId: user.userId,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false
|
|
|
+ }))
|
|
|
+ }));
|
|
|
+
|
|
|
+ return {
|
|
|
+ id: classType.classType,
|
|
|
+ name: classType.classTypeName,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false,
|
|
|
+ children: classes
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ id: grade.schoolYearGradeId || grade.gradeCode,
|
|
|
+ name: grade.gradeName,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false,
|
|
|
+ children: classTypes
|
|
|
+ };
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 转换按权限的数据为树形结构
|
|
|
+const transformPersonalData = (data) => {
|
|
|
+ if (!data || !Array.isArray(data)) return [];
|
|
|
+
|
|
|
+ return data.map(item => {
|
|
|
+ return {
|
|
|
+ id: item.roleId,
|
|
|
+ name: item.roleName,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false,
|
|
|
+ children: deduplicateUsers(item.personVoList || []).map(user => ({
|
|
|
+ id: user.userId,
|
|
|
+ name: `${user.teacherName} (${user.userAccount})`,
|
|
|
+ userId: user.userId,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false
|
|
|
+ }))
|
|
|
+ };
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 转换按学生的数据为树形结构
|
|
|
+const transformStudentData = (data) => {
|
|
|
+ if (!data || !Array.isArray(data)) return [];
|
|
|
+
|
|
|
+ return data.map(grade => {
|
|
|
+ const classes = (grade.clsVOS || []).map(cls => ({
|
|
|
+ id: cls.classId,
|
|
|
+ name: cls.className,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false,
|
|
|
+ children: (cls.studentTblVOS || []).map(student => ({
|
|
|
+ id: student.userId,
|
|
|
+ name: `${student.studentName} (${student.studentCode})`,
|
|
|
+ userId: student.userId,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false
|
|
|
+ }))
|
|
|
+ }));
|
|
|
+
|
|
|
+ return {
|
|
|
+ id: grade.schoolYearGradeId || grade.gradeCode,
|
|
|
+ name: grade.gradeName,
|
|
|
+ checked: false,
|
|
|
+ halfChecked: false,
|
|
|
+ children: classes
|
|
|
+ };
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 获取学年
|
|
|
+const getSchoolYear = async () => {
|
|
|
+ try {
|
|
|
+ const res = await overview.findSchoolYear();
|
|
|
+ if (res.data && res.data.length > 0) {
|
|
|
+ schoolYearId.value = res.data[0].id;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取学年失败:', error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 获取按部门数据
|
|
|
+const loadDepartmentData = async () => {
|
|
|
+ if (!schoolYearId.value) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await overview.find_depart_contain_user({ schoolYearId: schoolYearId.value });
|
|
|
+ fullTreeData.value = transformDepartmentData(res.data);
|
|
|
+ treeData.value = fullTreeData.value;
|
|
|
+ expandedIds.value = [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取部门数据失败:', error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 获取按学科/年级/权限数据
|
|
|
+const loadPersonalData = async (type) => {
|
|
|
+ if (!schoolYearId.value) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await overview.find_collect_personal_info({ schoolYearId: schoolYearId.value });
|
|
|
+
|
|
|
+ let data = [];
|
|
|
+ let transformFn = transformPersonalData;
|
|
|
+
|
|
|
+ if (type === 'subject') {
|
|
|
+ data = res.data.subjectPersonVoList || [];
|
|
|
+ transformFn = transformSubjectData;
|
|
|
+ } else if (type === 'grade') {
|
|
|
+ data = res.data.collectGradePersonVos || [];
|
|
|
+ transformFn = transformGradeData;
|
|
|
+ } else if (type === 'permission') {
|
|
|
+ data = res.data.collectPermissionPersonVos || [];
|
|
|
+ }
|
|
|
+
|
|
|
+ fullTreeData.value = transformFn(data);
|
|
|
+ treeData.value = fullTreeData.value;
|
|
|
+ expandedIds.value = [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`获取${type}数据失败:`, error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 获取按学生数据
|
|
|
+const loadStudentData = async () => {
|
|
|
+ if (!schoolYearId.value) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await overview.query_notice_student({ id: 0, schoolYearId: schoolYearId.value });
|
|
|
+ fullTreeData.value = transformStudentData(res.data || []);
|
|
|
+ treeData.value = fullTreeData.value;
|
|
|
+ expandedIds.value = [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取学生数据失败:', error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 切换标签
|
|
|
+const handleTabChange = async (key) => {
|
|
|
+ activeTab.value = key;
|
|
|
+
|
|
|
+ if (key === 'department') {
|
|
|
+ await loadDepartmentData();
|
|
|
+ } else if (key === 'subject' || key === 'grade' || key === 'permission') {
|
|
|
+ await loadPersonalData(key);
|
|
|
+ } else if (key === 'student') {
|
|
|
+ await loadStudentData();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const getDescendantIds = (nodes, parentId) => {
|
|
|
+ const ids = [];
|
|
|
+ const findDescendants = (items, targetId) => {
|
|
|
+ items.forEach(item => {
|
|
|
+ if (item.id === targetId && item.children && item.children.length > 0) {
|
|
|
+ const collectIds = (children) => {
|
|
|
+ children.forEach(child => {
|
|
|
+ ids.push(child.id);
|
|
|
+ if (child.children && child.children.length > 0) {
|
|
|
+ collectIds(child.children);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+ collectIds(item.children);
|
|
|
+ }
|
|
|
+ if (item.children && item.children.length > 0) {
|
|
|
+ findDescendants(item.children, targetId);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+ findDescendants(nodes, parentId);
|
|
|
+ return ids;
|
|
|
+};
|
|
|
+
|
|
|
+const searchTree = (keyword) => {
|
|
|
+ if (!keyword.trim()) {
|
|
|
+ treeData.value = fullTreeData.value;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const filterNodes = (nodes) => {
|
|
|
+ const filtered = [];
|
|
|
+ nodes.forEach(node => {
|
|
|
+ const hasMatch = node.name && node.name.includes(keyword);
|
|
|
+ let childrenFiltered = [];
|
|
|
+
|
|
|
+ if (node.children && node.children.length > 0) {
|
|
|
+ childrenFiltered = filterNodes(node.children);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hasMatch || childrenFiltered.length > 0) {
|
|
|
+ filtered.push({
|
|
|
+ ...node,
|
|
|
+ children: childrenFiltered
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return filtered;
|
|
|
+ };
|
|
|
+
|
|
|
+ treeData.value = filterNodes(fullTreeData.value);
|
|
|
+};
|
|
|
+
|
|
|
+const toggleExpand = ({ itemId, siblingIds, isExpanded }) => {
|
|
|
+ if (isExpanded) {
|
|
|
+ expandedIds.value = expandedIds.value.filter(id => id !== itemId);
|
|
|
+ } else {
|
|
|
+ const descendantIds = getDescendantIds(treeData.value, itemId);
|
|
|
+ expandedIds.value = expandedIds.value.filter(id => {
|
|
|
+ if (siblingIds.includes(id)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (descendantIds.includes(id)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+ expandedIds.value = [...expandedIds.value, itemId];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 向下级联:更新所有子节点的选中状态
|
|
|
+const toggleChildren = (children, checked) => {
|
|
|
+ children.forEach(child => {
|
|
|
+ child.checked = checked;
|
|
|
+ child.halfChecked = false;
|
|
|
+ if (child.children && child.children.length > 0) {
|
|
|
+ toggleChildren(child.children, checked);
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 向上级联:更新父节点的选中状态
|
|
|
+const updateParentStatus = () => {
|
|
|
+ const updateNode = (nodes) => {
|
|
|
+ nodes.forEach(node => {
|
|
|
+ if (node.children && node.children.length > 0) {
|
|
|
+ updateNode(node.children);
|
|
|
+
|
|
|
+ // 检查子节点的选中状态
|
|
|
+ const childrenChecked = node.children.filter(c => c.checked);
|
|
|
+ const childrenHalfChecked = node.children.filter(c => c.halfChecked);
|
|
|
+
|
|
|
+ if (childrenChecked.length === node.children.length) {
|
|
|
+ // 所有子节点都选中,父节点也选中
|
|
|
+ node.checked = true;
|
|
|
+ node.halfChecked = false;
|
|
|
+ } else if (childrenChecked.length > 0 || childrenHalfChecked.length > 0) {
|
|
|
+ // 部分子节点选中,父节点半选
|
|
|
+ node.checked = false;
|
|
|
+ node.halfChecked = true;
|
|
|
+ } else {
|
|
|
+ // 没有子节点选中
|
|
|
+ node.checked = false;
|
|
|
+ node.halfChecked = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+ updateNode(treeData.value);
|
|
|
+};
|
|
|
+
|
|
|
+const toggleSelect = (item) => {
|
|
|
+ item.checked = !item.checked;
|
|
|
+ item.halfChecked = false;
|
|
|
+
|
|
|
+ // 如果是叶子节点(用户),同步所有相同 userId 的节点
|
|
|
+ if (!item.children || item.children.length === 0) {
|
|
|
+ if (item.userId) {
|
|
|
+ syncTeacherSelection(item.userId, item.checked);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 向下级联
|
|
|
+ toggleChildren(item.children, item.checked);
|
|
|
+
|
|
|
+ // 获取所有叶子节点的 userId 并同步到其他分组
|
|
|
+ const getUserIds = (nodes) => {
|
|
|
+ const ids = [];
|
|
|
+ nodes.forEach(node => {
|
|
|
+ if (node.userId) {
|
|
|
+ ids.push(node.userId);
|
|
|
+ } else if (node.children && node.children.length > 0) {
|
|
|
+ ids.push(...getUserIds(node.children));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return ids;
|
|
|
+ };
|
|
|
+
|
|
|
+ const userIds = getUserIds(item.children);
|
|
|
+ userIds.forEach(id => {
|
|
|
+ syncTeacherSelection(id, item.checked);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 向上级联
|
|
|
+ updateParentStatus();
|
|
|
+};
|
|
|
+
|
|
|
+const selectedCount = computed(() => {
|
|
|
+ const selectedUserIds = new Set();
|
|
|
+ const collectChecked = (items) => {
|
|
|
+ items.forEach(item => {
|
|
|
+ if (item.children) {
|
|
|
+ collectChecked(item.children);
|
|
|
+ } else if (item.checked && item.userId) {
|
|
|
+ selectedUserIds.add(item.userId);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+ collectChecked(treeData.value);
|
|
|
+ return selectedUserIds.size;
|
|
|
+});
|
|
|
+
|
|
|
+const goBack = () => {
|
|
|
+ uni.navigateBack();
|
|
|
+};
|
|
|
+
|
|
|
+const collectSelectedUsers = () => {
|
|
|
+ const selectedUsers = [];
|
|
|
+ const collect = (nodes) => {
|
|
|
+ nodes.forEach(node => {
|
|
|
+ if (node.children && node.children.length > 0) {
|
|
|
+ collect(node.children);
|
|
|
+ } else if (node.checked && node.userId) {
|
|
|
+ selectedUsers.push({
|
|
|
+ id: node.id,
|
|
|
+ name: node.name,
|
|
|
+ userId: node.userId
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+ collect(treeData.value);
|
|
|
+ return selectedUsers;
|
|
|
+};
|
|
|
+
|
|
|
+const handleConfirm = () => {
|
|
|
+ const data = {
|
|
|
+ tab: tabs.find(t => t.key === activeTab.value).label,
|
|
|
+ count: selectedCount.value,
|
|
|
+ users: collectSelectedUsers()
|
|
|
+ };
|
|
|
+
|
|
|
+ uni.setStorageSync('selectObjectResult', JSON.stringify(data));
|
|
|
+ uni.navigateBack();
|
|
|
+};
|
|
|
+
|
|
|
+const setSelectedUsers = (users) => {
|
|
|
+ if (!users || !Array.isArray(users)) return;
|
|
|
+
|
|
|
+ const selectedTeacherIds = new Set(users.map(u => u.teacherId));
|
|
|
+
|
|
|
+ const setNode = (nodes) => {
|
|
|
+ nodes.forEach(node => {
|
|
|
+ if (node.children && node.children.length > 0) {
|
|
|
+ setNode(node.children);
|
|
|
+ } else if (node.teacherId && selectedTeacherIds.has(node.teacherId)) {
|
|
|
+ node.checked = true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ setNode(treeData.value);
|
|
|
+ updateParentStatus();
|
|
|
+};
|
|
|
+
|
|
|
+const setSelectedUsersById = (userIds) => {
|
|
|
+ if (!userIds || !Array.isArray(userIds)) return;
|
|
|
+
|
|
|
+ const selectedIds = new Set(userIds);
|
|
|
+
|
|
|
+ const setNode = (nodes) => {
|
|
|
+ nodes.forEach(node => {
|
|
|
+ if (node.children && node.children.length > 0) {
|
|
|
+ setNode(node.children);
|
|
|
+ } else if (node.id && selectedIds.has(node.id)) {
|
|
|
+ node.checked = true;
|
|
|
+ if (node.teacherId) {
|
|
|
+ syncTeacherSelection(node.teacherId, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ setNode(treeData.value);
|
|
|
+ updateParentStatus();
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ const pages = getCurrentPages();
|
|
|
+ if (pages.length === 1) {
|
|
|
+ uni.redirectTo({ url: '/pages/notice/publish/index' });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const lastSelection = uni.getStorageSync('selectObjectLastSelection');
|
|
|
+ if (lastSelection) {
|
|
|
+ try {
|
|
|
+ const data = JSON.parse(lastSelection);
|
|
|
+
|
|
|
+ if (data.isEdit) {
|
|
|
+ editMode.value = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.noticeType) {
|
|
|
+ noticeType.value = data.noticeType;
|
|
|
+ const typeMap = {
|
|
|
+ 1: 'department',
|
|
|
+ 2: 'subject',
|
|
|
+ 3: 'grade',
|
|
|
+ 4: 'permission',
|
|
|
+ 5: 'student'
|
|
|
+ };
|
|
|
+ const tabKey = typeMap[data.noticeType];
|
|
|
+ if (tabKey) {
|
|
|
+ activeTab.value = tabKey;
|
|
|
+ }
|
|
|
+ } else if (data.tab) {
|
|
|
+ const tab = tabs.find(t => t.label === data.tab);
|
|
|
+ if (tab) {
|
|
|
+ activeTab.value = tab.key;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.users) {
|
|
|
+ selectedUserIds.value = data.users.map(u => u.id);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('解析上次选择失败:', e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ await getSchoolYear();
|
|
|
+
|
|
|
+ if (activeTab.value === 'department') {
|
|
|
+ await loadDepartmentData();
|
|
|
+ } else if (activeTab.value === 'subject' || activeTab.value === 'grade' || activeTab.value === 'permission') {
|
|
|
+ await loadPersonalData(activeTab.value);
|
|
|
+ } else if (activeTab.value === 'student') {
|
|
|
+ await loadStudentData();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (selectedUserIds.value.length > 0) {
|
|
|
+ setSelectedUsersById(selectedUserIds.value);
|
|
|
+ } else if (lastSelection) {
|
|
|
+ try {
|
|
|
+ const data = JSON.parse(lastSelection);
|
|
|
+ if (data.users) {
|
|
|
+ setSelectedUsers(data.users);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('设置选中状态失败:', e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.page_select_object {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ min-height: 100vh;
|
|
|
+}
|
|
|
+
|
|
|
+.select_header {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ z-index: 100;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ height: 96rpx;
|
|
|
+ padding: 0 24rpx;
|
|
|
+ background-color: #FFFFFF;
|
|
|
+ border-bottom: 2rpx solid #F3F3F3;
|
|
|
+
|
|
|
+ .header_title {
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 32rpx;
|
|
|
+ color: #333333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .header_placeholder {
|
|
|
+ width: 48rpx;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.tabs_container {
|
|
|
+ position: fixed;
|
|
|
+ top: 96rpx;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ z-index: 99;
|
|
|
+ display: flex;
|
|
|
+ padding: 24rpx;
|
|
|
+ background-color: #FFFFFF;
|
|
|
+ justify-content: space-between;
|
|
|
+
|
|
|
+ .tab_item {
|
|
|
+ flex-shrink: 0;
|
|
|
+ width: 122rpx;
|
|
|
+ height: 72rpx;
|
|
|
+ background: #FFFFFF;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ border: 2rpx solid #DCDFE6;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ background: #2E64FA;
|
|
|
+ border-color: #2E64FA;
|
|
|
+
|
|
|
+ .tab_text {
|
|
|
+ color: #FFFFFF;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .tab_text {
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333333;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.disabled {
|
|
|
+ pointer-events: none;
|
|
|
+ opacity: 0.5;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.search_container {
|
|
|
+ position: fixed;
|
|
|
+ top: 192rpx;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ z-index: 98;
|
|
|
+ padding: 32rpx 0rpx;
|
|
|
+ margin: 0 24rpx;
|
|
|
+ background-color: #FFFFFF;
|
|
|
+ border-bottom: 2rpx solid #F3F3F3;
|
|
|
+
|
|
|
+ .search_box {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 0rpx 24rpx;
|
|
|
+ height: 72rpx;
|
|
|
+ line-height: 72rpx;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ border: 2rpx solid #DCDFE6;
|
|
|
+
|
|
|
+ .search_icon {
|
|
|
+ width: 32rpx;
|
|
|
+ height: 32rpx;
|
|
|
+ margin-right: 8rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .search_input {
|
|
|
+ flex: 1;
|
|
|
+ height: 72rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333333;
|
|
|
+ padding-right:24rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.content_list {
|
|
|
+ flex: 1;
|
|
|
+ padding: 330rpx 0 150rpx 0;
|
|
|
+}
|
|
|
+
|
|
|
+.select_footer {
|
|
|
+ position: fixed;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ padding: 24rpx;
|
|
|
+ padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
|
|
|
+ background-color: #FFFFFF;
|
|
|
+ border-top: 2rpx solid #F3F3F3;
|
|
|
+
|
|
|
+ .confirm_btn {
|
|
|
+ width: 100%;
|
|
|
+ height: 90rpx;
|
|
|
+ background: #2E64FA;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 90rpx;
|
|
|
+
|
|
|
+ .btn_text {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #FFFFFF;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|