|
@@ -1,10 +1,6 @@
|
|
|
<template>
|
|
<template>
|
|
|
<view class="page_select_object">
|
|
<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>
|
|
|
|
|
|
|
+ <CommonHeader title="选择通知对象" @back="goBack"></CommonHeader>
|
|
|
|
|
|
|
|
<view class="tabs_container">
|
|
<view class="tabs_container">
|
|
|
<view v-for="tab in tabs" :key="tab.key" class="tab_item" :class="{ active: activeTab === tab.key, disabled: editMode }"
|
|
<view v-for="tab in tabs" :key="tab.key" class="tab_item" :class="{ active: activeTab === tab.key, disabled: editMode }"
|
|
@@ -13,12 +9,7 @@
|
|
|
</view>
|
|
</view>
|
|
|
</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>
|
|
|
|
|
|
|
+ <SearchBar v-model="searchKeyword" @search="searchTree" :border="true" :isFixed="true" :top="212" :zIndex="100"></SearchBar>
|
|
|
|
|
|
|
|
<scroll-view scroll-y class="content_list">
|
|
<scroll-view scroll-y class="content_list">
|
|
|
<TreeNode :tree-data="treeData" :expanded-ids="expandedIds" @toggle-expand="toggleExpand"
|
|
<TreeNode :tree-data="treeData" :expanded-ids="expandedIds" @toggle-expand="toggleExpand"
|
|
@@ -37,6 +28,8 @@
|
|
|
import { ref, computed, onMounted } from 'vue';
|
|
import { ref, computed, onMounted } from 'vue';
|
|
|
import uniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue';
|
|
import uniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue';
|
|
|
import TreeNode from '@/components/tree-node.vue';
|
|
import TreeNode from '@/components/tree-node.vue';
|
|
|
|
|
+import SearchBar from '@/components/search-bar.vue';
|
|
|
|
|
+import CommonHeader from '@/components/common-header.vue';
|
|
|
import overview from '@/reqApi/overview.js';
|
|
import overview from '@/reqApi/overview.js';
|
|
|
|
|
|
|
|
const activeTab = ref('department');
|
|
const activeTab = ref('department');
|
|
@@ -63,11 +56,12 @@ const deduplicateUsers = (users) => {
|
|
|
if (!users || !Array.isArray(users)) return [];
|
|
if (!users || !Array.isArray(users)) return [];
|
|
|
const seen = new Set();
|
|
const seen = new Set();
|
|
|
return users.filter(user => {
|
|
return users.filter(user => {
|
|
|
- if (user.teacherId && seen.has(user.teacherId)) {
|
|
|
|
|
|
|
+ const userId = user.userId;
|
|
|
|
|
+ if (userId && seen.has(userId)) {
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
- if (user.teacherId) {
|
|
|
|
|
- seen.add(user.teacherId);
|
|
|
|
|
|
|
+ if (userId) {
|
|
|
|
|
+ seen.add(userId);
|
|
|
}
|
|
}
|
|
|
return true;
|
|
return true;
|
|
|
});
|
|
});
|
|
@@ -79,14 +73,15 @@ const transformDepartmentData = (data) => {
|
|
|
|
|
|
|
|
return data.map(dept => {
|
|
return data.map(dept => {
|
|
|
const groups = (dept.groupVOS || []).map(group => ({
|
|
const groups = (dept.groupVOS || []).map(group => ({
|
|
|
- id: group.groupId,
|
|
|
|
|
|
|
+ id: `${dept.id}_${group.groupId}`,
|
|
|
name: group.groupName,
|
|
name: group.groupName,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false,
|
|
halfChecked: false,
|
|
|
children: deduplicateUsers(group.groupUserVOS || []).map(user => ({
|
|
children: deduplicateUsers(group.groupUserVOS || []).map(user => ({
|
|
|
id: user.userId,
|
|
id: user.userId,
|
|
|
- name: `${user.teacherName} (${user.userAccount})`,
|
|
|
|
|
|
|
+ name: user.teacherName,
|
|
|
userId: user.userId,
|
|
userId: user.userId,
|
|
|
|
|
+ userAccount: user.userAccount,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false
|
|
halfChecked: false
|
|
|
}))
|
|
}))
|
|
@@ -124,21 +119,22 @@ const transformSubjectData = (data) => {
|
|
|
|
|
|
|
|
return data.map(subject => {
|
|
return data.map(subject => {
|
|
|
const grades = (subject.gradePersonVos || []).map(grade => ({
|
|
const grades = (subject.gradePersonVos || []).map(grade => ({
|
|
|
- id: grade.schoolYearGradeId || grade.gradeCode,
|
|
|
|
|
|
|
+ id: `${subject.subjectCode}_${grade.schoolYearGradeId || grade.gradeCode}`,
|
|
|
name: grade.gradeName,
|
|
name: grade.gradeName,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false,
|
|
halfChecked: false,
|
|
|
children: deduplicateUsers(grade.personVoList || []).map(user => ({
|
|
children: deduplicateUsers(grade.personVoList || []).map(user => ({
|
|
|
id: user.userId,
|
|
id: user.userId,
|
|
|
- name: `${user.teacherName} (${user.userAccount})`,
|
|
|
|
|
|
|
+ name: user.teacherName,
|
|
|
userId: user.userId,
|
|
userId: user.userId,
|
|
|
|
|
+ userAccount: user.userAccount,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false
|
|
halfChecked: false
|
|
|
}))
|
|
}))
|
|
|
}));
|
|
}));
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
- id: subject.subjectCode,
|
|
|
|
|
|
|
+ id: `subject_${subject.subjectCode}`,
|
|
|
name: subject.subjectName,
|
|
name: subject.subjectName,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false,
|
|
halfChecked: false,
|
|
@@ -154,21 +150,22 @@ const transformGradeData = (data) => {
|
|
|
return data.map(grade => {
|
|
return data.map(grade => {
|
|
|
const classTypes = (grade.classTypePersonVoList || []).map(classType => {
|
|
const classTypes = (grade.classTypePersonVoList || []).map(classType => {
|
|
|
const classes = (classType.classInfoPersonVoList || []).map(cls => ({
|
|
const classes = (classType.classInfoPersonVoList || []).map(cls => ({
|
|
|
- id: cls.classCode,
|
|
|
|
|
|
|
+ id: `${classType.classType}_${cls.classCode}`,
|
|
|
name: cls.className,
|
|
name: cls.className,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false,
|
|
halfChecked: false,
|
|
|
children: deduplicateUsers(cls.personVoList || []).map(user => ({
|
|
children: deduplicateUsers(cls.personVoList || []).map(user => ({
|
|
|
id: user.userId,
|
|
id: user.userId,
|
|
|
- name: `${user.teacherName} (${user.userAccount})`,
|
|
|
|
|
|
|
+ name: user.teacherName,
|
|
|
userId: user.userId,
|
|
userId: user.userId,
|
|
|
|
|
+ userAccount: user.userAccount,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false
|
|
halfChecked: false
|
|
|
}))
|
|
}))
|
|
|
}));
|
|
}));
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
- id: classType.classType,
|
|
|
|
|
|
|
+ id: `${grade.schoolYearGradeId || grade.gradeCode}_${classType.classType}`,
|
|
|
name: classType.classTypeName,
|
|
name: classType.classTypeName,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false,
|
|
halfChecked: false,
|
|
@@ -198,8 +195,9 @@ const transformPersonalData = (data) => {
|
|
|
halfChecked: false,
|
|
halfChecked: false,
|
|
|
children: deduplicateUsers(item.personVoList || []).map(user => ({
|
|
children: deduplicateUsers(item.personVoList || []).map(user => ({
|
|
|
id: user.userId,
|
|
id: user.userId,
|
|
|
- name: `${user.teacherName} (${user.userAccount})`,
|
|
|
|
|
|
|
+ name: user.teacherName,
|
|
|
userId: user.userId,
|
|
userId: user.userId,
|
|
|
|
|
+ userAccount: user.userAccount,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false
|
|
halfChecked: false
|
|
|
}))
|
|
}))
|
|
@@ -213,21 +211,22 @@ const transformStudentData = (data) => {
|
|
|
|
|
|
|
|
return data.map(grade => {
|
|
return data.map(grade => {
|
|
|
const classes = (grade.clsVOS || []).map(cls => ({
|
|
const classes = (grade.clsVOS || []).map(cls => ({
|
|
|
- id: cls.classId,
|
|
|
|
|
|
|
+ id: `${grade.schoolYearGradeId || grade.gradeCode}_${cls.classId}`,
|
|
|
name: cls.className,
|
|
name: cls.className,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false,
|
|
halfChecked: false,
|
|
|
- children: (cls.studentTblVOS || []).map(student => ({
|
|
|
|
|
|
|
+ children: deduplicateUsers(cls.studentTblVOS || []).map(student => ({
|
|
|
id: student.userId,
|
|
id: student.userId,
|
|
|
- name: `${student.studentName} (${student.studentCode})`,
|
|
|
|
|
|
|
+ name: student.studentName,
|
|
|
userId: student.userId,
|
|
userId: student.userId,
|
|
|
|
|
+ userAccount: student.studentCode,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false
|
|
halfChecked: false
|
|
|
}))
|
|
}))
|
|
|
}));
|
|
}));
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
- id: grade.schoolYearGradeId || grade.gradeCode,
|
|
|
|
|
|
|
+ id: `student_${grade.schoolYearGradeId || grade.gradeCode}`,
|
|
|
name: grade.gradeName,
|
|
name: grade.gradeName,
|
|
|
checked: false,
|
|
checked: false,
|
|
|
halfChecked: false,
|
|
halfChecked: false,
|
|
@@ -374,14 +373,10 @@ const toggleExpand = ({ itemId, siblingIds, isExpanded }) => {
|
|
|
if (isExpanded) {
|
|
if (isExpanded) {
|
|
|
expandedIds.value = expandedIds.value.filter(id => id !== itemId);
|
|
expandedIds.value = expandedIds.value.filter(id => id !== itemId);
|
|
|
} else {
|
|
} else {
|
|
|
- const descendantIds = getDescendantIds(treeData.value, itemId);
|
|
|
|
|
expandedIds.value = expandedIds.value.filter(id => {
|
|
expandedIds.value = expandedIds.value.filter(id => {
|
|
|
if (siblingIds.includes(id)) {
|
|
if (siblingIds.includes(id)) {
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
- if (descendantIds.includes(id)) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
return true;
|
|
return true;
|
|
|
});
|
|
});
|
|
|
expandedIds.value = [...expandedIds.value, itemId];
|
|
expandedIds.value = [...expandedIds.value, itemId];
|
|
@@ -486,15 +481,51 @@ const goBack = () => {
|
|
|
|
|
|
|
|
const collectSelectedUsers = () => {
|
|
const collectSelectedUsers = () => {
|
|
|
const selectedUsers = [];
|
|
const selectedUsers = [];
|
|
|
- const collect = (nodes) => {
|
|
|
|
|
|
|
+ const seen = new Set();
|
|
|
|
|
+ const collect = (nodes, parentInfo = {}) => {
|
|
|
nodes.forEach(node => {
|
|
nodes.forEach(node => {
|
|
|
if (node.children && node.children.length > 0) {
|
|
if (node.children && node.children.length > 0) {
|
|
|
- collect(node.children);
|
|
|
|
|
- } else if (node.checked && node.userId) {
|
|
|
|
|
|
|
+ const newParentInfo = { ...parentInfo };
|
|
|
|
|
+ if (node.name && !node.userId) {
|
|
|
|
|
+ if (!newParentInfo.departmentName && !newParentInfo.subjectName && !newParentInfo.gradeName && !newParentInfo.roleName) {
|
|
|
|
|
+ if (activeTab.value === 1) {
|
|
|
|
|
+ newParentInfo.departmentName = node.name;
|
|
|
|
|
+ } else if (activeTab.value === 2) {
|
|
|
|
|
+ newParentInfo.subjectName = node.name;
|
|
|
|
|
+ } else if (activeTab.value === 3) {
|
|
|
|
|
+ newParentInfo.gradeName = node.name;
|
|
|
|
|
+ } else if (activeTab.value === 4) {
|
|
|
|
|
+ newParentInfo.roleName = node.name;
|
|
|
|
|
+ } else if (activeTab.value === 5) {
|
|
|
|
|
+ newParentInfo.gradeName = node.name;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (!newParentInfo.groupName && !newParentInfo.classTypeName && !newParentInfo.className) {
|
|
|
|
|
+ if (activeTab.value === 1) {
|
|
|
|
|
+ newParentInfo.groupName = node.name;
|
|
|
|
|
+ } else if (activeTab.value === 3) {
|
|
|
|
|
+ newParentInfo.classTypeName = node.name;
|
|
|
|
|
+ } else if (activeTab.value === 5) {
|
|
|
|
|
+ newParentInfo.className = node.name;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (!newParentInfo.className && activeTab.value === 3) {
|
|
|
|
|
+ newParentInfo.className = node.name;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ collect(node.children, newParentInfo);
|
|
|
|
|
+ } else if (node.checked && node.userId && !seen.has(node.userId)) {
|
|
|
|
|
+ seen.add(node.userId);
|
|
|
selectedUsers.push({
|
|
selectedUsers.push({
|
|
|
id: node.id,
|
|
id: node.id,
|
|
|
name: node.name,
|
|
name: node.name,
|
|
|
- userId: node.userId
|
|
|
|
|
|
|
+ userId: node.userId,
|
|
|
|
|
+ thirdCode: node.userAccount,
|
|
|
|
|
+ departmentName: parentInfo.departmentName || '',
|
|
|
|
|
+ groupName: parentInfo.groupName || '',
|
|
|
|
|
+ subjectName: parentInfo.subjectName || '',
|
|
|
|
|
+ gradeName: parentInfo.gradeName || '',
|
|
|
|
|
+ classTypeName: parentInfo.classTypeName || '',
|
|
|
|
|
+ className: parentInfo.className || '',
|
|
|
|
|
+ roleName: parentInfo.roleName || ''
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
@@ -592,7 +623,7 @@ onMounted(async () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (data.users) {
|
|
if (data.users) {
|
|
|
- selectedUserIds.value = data.users.map(u => u.id);
|
|
|
|
|
|
|
+ selectedUserIds.value = data.users.map(u => u.userId || u.id);
|
|
|
}
|
|
}
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
console.error('解析上次选择失败:', e);
|
|
console.error('解析上次选择失败:', e);
|
|
@@ -631,31 +662,6 @@ onMounted(async () => {
|
|
|
min-height: 100vh;
|
|
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 {
|
|
.tabs_container {
|
|
|
position: fixed;
|
|
position: fixed;
|
|
|
top: 96rpx;
|
|
top: 96rpx;
|
|
@@ -663,7 +669,7 @@ onMounted(async () => {
|
|
|
right: 0;
|
|
right: 0;
|
|
|
z-index: 99;
|
|
z-index: 99;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
- padding: 24rpx;
|
|
|
|
|
|
|
+ padding: 24rpx ;
|
|
|
background-color: #FFFFFF;
|
|
background-color: #FFFFFF;
|
|
|
justify-content: space-between;
|
|
justify-content: space-between;
|
|
|
|
|
|
|
@@ -700,44 +706,6 @@ onMounted(async () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.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 {
|
|
.content_list {
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
padding: 330rpx 0 150rpx 0;
|
|
padding: 330rpx 0 150rpx 0;
|