selectObject.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. <template>
  2. <view class="page_select_object">
  3. <CommonHeader title="选择通知对象" @back="goBack"></CommonHeader>
  4. <view class="tabs_container" :style="{ top: tabsTop + 'rpx' }">
  5. <view v-for="tab in tabs" :key="tab.key" class="tab_item" :class="{ active: activeTab === tab.key, disabled: editMode }"
  6. @click="!editMode && handleTabChange(tab.key)">
  7. <text class="tab_text">{{ tab.label }}</text>
  8. </view>
  9. </view>
  10. <SearchBar v-model="searchKeyword" @search="searchTree" :border="true" :isFixed="true" :top="searchBarTop + 'rpx'" :zIndex="100"></SearchBar>
  11. <scroll-view scroll-y class="content_list" :style="{ paddingTop: contentPaddingTop + 'rpx' }">
  12. <TreeNode :tree-data="treeData" :expanded-ids="expandedIds" @toggle-expand="toggleExpand"
  13. @toggle-select="toggleSelect" />
  14. </scroll-view>
  15. <view class="select_footer">
  16. <view class="confirm_btn" @click="handleConfirm">
  17. <text class="btn_text">确定(已选{{ selectedCount }}人)</text>
  18. </view>
  19. </view>
  20. </view>
  21. </template>
  22. <script setup>
  23. import { ref, computed, onMounted } from 'vue';
  24. import TreeNode from '@/components/tree-node.vue';
  25. import SearchBar from '@/components/search-bar.vue';
  26. import CommonHeader from '@/components/common-header.vue';
  27. import overview from '@/reqApi/overview.js';
  28. import { useSafeArea } from '@/common/safeArea';
  29. const { statusBarHeight, initSafeArea } = useSafeArea();
  30. const HEADER_CONTENT_HEIGHT = 130;
  31. const TABS_HEIGHT = 120;
  32. const SEARCHBAR_HEIGHT = 84;
  33. const SPACING = 16;
  34. const tabsTop = computed(() => statusBarHeight.value + HEADER_CONTENT_HEIGHT);
  35. const searchBarTop = computed(() => statusBarHeight.value + HEADER_CONTENT_HEIGHT + TABS_HEIGHT);
  36. const contentPaddingTop = computed(() => statusBarHeight.value + HEADER_CONTENT_HEIGHT + TABS_HEIGHT + SEARCHBAR_HEIGHT + SPACING);
  37. const activeTab = ref('department');
  38. const searchKeyword = ref('');
  39. const schoolYearId = ref('');
  40. const editMode = ref(false);
  41. const noticeType = ref(0);
  42. const selectedUserIds = ref([]);
  43. const tabs = [
  44. { key: 'department', label: '按部门' },
  45. { key: 'subject', label: '按学科' },
  46. { key: 'grade', label: '按年级' },
  47. { key: 'permission', label: '按权限' },
  48. { key: 'student', label: '按学生' }
  49. ];
  50. const treeData = ref([]);
  51. const fullTreeData = ref([]);
  52. const expandedIds = ref([]);
  53. // 按 teacherId 去重用户列表
  54. const deduplicateUsers = (users) => {
  55. if (!users || !Array.isArray(users)) return [];
  56. const seen = new Set();
  57. return users.filter(user => {
  58. const userId = user.userId;
  59. if (userId && seen.has(userId)) {
  60. return false;
  61. }
  62. if (userId) {
  63. seen.add(userId);
  64. }
  65. return true;
  66. });
  67. };
  68. // 转换按部门接口数据为树形结构
  69. const transformDepartmentData = (data) => {
  70. if (!data || !Array.isArray(data)) return [];
  71. return data.map(dept => {
  72. const groups = (dept.groupVOS || []).map(group => ({
  73. id: `${dept.id}_${group.groupId}`,
  74. name: group.groupName,
  75. checked: false,
  76. halfChecked: false,
  77. children: deduplicateUsers(group.groupUserVOS || []).map(user => ({
  78. id: user.userId,
  79. name: user.teacherName,
  80. userId: user.userId,
  81. userAccount: user.userAccount,
  82. checked: false,
  83. halfChecked: false
  84. }))
  85. }));
  86. return {
  87. id: dept.id,
  88. name: dept.name,
  89. checked: false,
  90. halfChecked: false,
  91. children: groups
  92. };
  93. });
  94. };
  95. // 根据 userId 同步所有相同用户的选中状态
  96. const syncTeacherSelection = (userId, checked) => {
  97. const syncNode = (nodes) => {
  98. nodes.forEach(node => {
  99. if (node.userId && node.userId === userId) {
  100. node.checked = checked;
  101. node.halfChecked = false;
  102. }
  103. if (node.children && node.children.length > 0) {
  104. syncNode(node.children);
  105. }
  106. });
  107. };
  108. syncNode(treeData.value);
  109. };
  110. // 转换按学科的数据为树形结构
  111. const transformSubjectData = (data) => {
  112. if (!data || !Array.isArray(data)) return [];
  113. return data.map(subject => {
  114. const grades = (subject.gradePersonVos || []).map(grade => ({
  115. id: `${subject.subjectCode}_${grade.schoolYearGradeId || grade.gradeCode}`,
  116. name: grade.gradeName,
  117. checked: false,
  118. halfChecked: false,
  119. children: deduplicateUsers(grade.personVoList || []).map(user => ({
  120. id: user.userId,
  121. name: user.teacherName,
  122. userId: user.userId,
  123. userAccount: user.userAccount,
  124. checked: false,
  125. halfChecked: false
  126. }))
  127. }));
  128. return {
  129. id: `subject_${subject.subjectCode}`,
  130. name: subject.subjectName,
  131. checked: false,
  132. halfChecked: false,
  133. children: grades
  134. };
  135. });
  136. };
  137. // 转换按年级的数据为树形结构
  138. const transformGradeData = (data) => {
  139. if (!data || !Array.isArray(data)) return [];
  140. return data.map(grade => {
  141. const classTypes = (grade.classTypePersonVoList || []).map(classType => {
  142. const classes = (classType.classInfoPersonVoList || []).map(cls => ({
  143. id: `${classType.classType}_${cls.classCode}`,
  144. name: cls.className,
  145. checked: false,
  146. halfChecked: false,
  147. children: deduplicateUsers(cls.personVoList || []).map(user => ({
  148. id: user.userId,
  149. name: user.teacherName,
  150. userId: user.userId,
  151. userAccount: user.userAccount,
  152. checked: false,
  153. halfChecked: false
  154. }))
  155. }));
  156. return {
  157. id: `${grade.schoolYearGradeId || grade.gradeCode}_${classType.classType}`,
  158. name: classType.classTypeName,
  159. checked: false,
  160. halfChecked: false,
  161. children: classes
  162. };
  163. });
  164. return {
  165. id: grade.schoolYearGradeId || grade.gradeCode,
  166. name: grade.gradeName,
  167. checked: false,
  168. halfChecked: false,
  169. children: classTypes
  170. };
  171. });
  172. };
  173. // 转换按权限的数据为树形结构
  174. const transformPersonalData = (data) => {
  175. if (!data || !Array.isArray(data)) return [];
  176. return data.map(item => {
  177. return {
  178. id: item.roleId,
  179. name: item.roleName,
  180. checked: false,
  181. halfChecked: false,
  182. children: deduplicateUsers(item.personVoList || []).map(user => ({
  183. id: user.userId,
  184. name: user.teacherName,
  185. userId: user.userId,
  186. userAccount: user.userAccount,
  187. checked: false,
  188. halfChecked: false
  189. }))
  190. };
  191. });
  192. };
  193. // 转换按学生的数据为树形结构
  194. const transformStudentData = (data) => {
  195. if (!data || !Array.isArray(data)) return [];
  196. return data.map(grade => {
  197. const classes = (grade.clsVOS || []).map(cls => ({
  198. id: `${grade.schoolYearGradeId || grade.gradeCode}_${cls.classId}`,
  199. name: cls.className,
  200. checked: false,
  201. halfChecked: false,
  202. children: deduplicateUsers(cls.studentTblVOS || []).map(student => ({
  203. id: student.userId,
  204. name: student.studentName,
  205. userId: student.userId,
  206. userAccount: student.studentCode,
  207. checked: false,
  208. halfChecked: false
  209. }))
  210. }));
  211. return {
  212. id: `student_${grade.schoolYearGradeId || grade.gradeCode}`,
  213. name: grade.gradeName,
  214. checked: false,
  215. halfChecked: false,
  216. children: classes
  217. };
  218. });
  219. };
  220. // 获取学年
  221. const getSchoolYear = async () => {
  222. try {
  223. const res = await overview.findSchoolYear();
  224. if (res.data && res.data.length > 0) {
  225. schoolYearId.value = res.data[0].id;
  226. }
  227. } catch (error) {
  228. console.error('获取学年失败:', error);
  229. }
  230. };
  231. // 获取按部门数据
  232. const loadDepartmentData = async () => {
  233. if (!schoolYearId.value) return;
  234. try {
  235. const res = await overview.find_depart_contain_user({ schoolYearId: schoolYearId.value });
  236. fullTreeData.value = transformDepartmentData(res.data);
  237. treeData.value = fullTreeData.value;
  238. expandedIds.value = [];
  239. } catch (error) {
  240. console.error('获取部门数据失败:', error);
  241. }
  242. };
  243. // 获取按学科/年级/权限数据
  244. const loadPersonalData = async (type) => {
  245. if (!schoolYearId.value) return;
  246. try {
  247. const res = await overview.find_collect_personal_info({ schoolYearId: schoolYearId.value });
  248. let data = [];
  249. let transformFn = transformPersonalData;
  250. if (type === 'subject') {
  251. data = res.data.subjectPersonVoList || [];
  252. transformFn = transformSubjectData;
  253. } else if (type === 'grade') {
  254. data = res.data.collectGradePersonVos || [];
  255. transformFn = transformGradeData;
  256. } else if (type === 'permission') {
  257. data = res.data.collectPermissionPersonVos || [];
  258. }
  259. fullTreeData.value = transformFn(data);
  260. treeData.value = fullTreeData.value;
  261. expandedIds.value = [];
  262. } catch (error) {
  263. console.error(`获取${type}数据失败:`, error);
  264. }
  265. };
  266. // 获取按学生数据
  267. const loadStudentData = async () => {
  268. if (!schoolYearId.value) return;
  269. try {
  270. const res = await overview.query_notice_student({ id: 0, schoolYearId: schoolYearId.value });
  271. fullTreeData.value = transformStudentData(res.data || []);
  272. treeData.value = fullTreeData.value;
  273. expandedIds.value = [];
  274. } catch (error) {
  275. console.error('获取学生数据失败:', error);
  276. }
  277. };
  278. // 切换标签
  279. const handleTabChange = async (key) => {
  280. activeTab.value = key;
  281. if (key === 'department') {
  282. await loadDepartmentData();
  283. } else if (key === 'subject' || key === 'grade' || key === 'permission') {
  284. await loadPersonalData(key);
  285. } else if (key === 'student') {
  286. await loadStudentData();
  287. }
  288. };
  289. const getDescendantIds = (nodes, parentId) => {
  290. const ids = [];
  291. const findDescendants = (items, targetId) => {
  292. items.forEach(item => {
  293. if (item.id === targetId && item.children && item.children.length > 0) {
  294. const collectIds = (children) => {
  295. children.forEach(child => {
  296. ids.push(child.id);
  297. if (child.children && child.children.length > 0) {
  298. collectIds(child.children);
  299. }
  300. });
  301. };
  302. collectIds(item.children);
  303. }
  304. if (item.children && item.children.length > 0) {
  305. findDescendants(item.children, targetId);
  306. }
  307. });
  308. };
  309. findDescendants(nodes, parentId);
  310. return ids;
  311. };
  312. const searchTree = (keyword) => {
  313. if (!keyword.trim()) {
  314. treeData.value = fullTreeData.value;
  315. return;
  316. }
  317. const filterNodes = (nodes) => {
  318. const filtered = [];
  319. nodes.forEach(node => {
  320. const hasMatch = node.name && node.name.includes(keyword);
  321. let childrenFiltered = [];
  322. if (node.children && node.children.length > 0) {
  323. childrenFiltered = filterNodes(node.children);
  324. }
  325. if (hasMatch || childrenFiltered.length > 0) {
  326. filtered.push({
  327. ...node,
  328. children: childrenFiltered
  329. });
  330. }
  331. });
  332. return filtered;
  333. };
  334. treeData.value = filterNodes(fullTreeData.value);
  335. };
  336. const toggleExpand = ({ itemId, siblingIds, isExpanded }) => {
  337. if (isExpanded) {
  338. expandedIds.value = expandedIds.value.filter(id => id !== itemId);
  339. } else {
  340. expandedIds.value = expandedIds.value.filter(id => {
  341. if (siblingIds.includes(id)) {
  342. return false;
  343. }
  344. return true;
  345. });
  346. expandedIds.value = [...expandedIds.value, itemId];
  347. }
  348. };
  349. // 向下级联:更新所有子节点的选中状态
  350. const toggleChildren = (children, checked) => {
  351. children.forEach(child => {
  352. child.checked = checked;
  353. child.halfChecked = false;
  354. if (child.children && child.children.length > 0) {
  355. toggleChildren(child.children, checked);
  356. }
  357. });
  358. };
  359. // 向上级联:更新父节点的选中状态
  360. const updateParentStatus = () => {
  361. const updateNode = (nodes) => {
  362. nodes.forEach(node => {
  363. if (node.children && node.children.length > 0) {
  364. updateNode(node.children);
  365. // 检查子节点的选中状态
  366. const childrenChecked = node.children.filter(c => c.checked);
  367. const childrenHalfChecked = node.children.filter(c => c.halfChecked);
  368. if (childrenChecked.length === node.children.length) {
  369. // 所有子节点都选中,父节点也选中
  370. node.checked = true;
  371. node.halfChecked = false;
  372. } else if (childrenChecked.length > 0 || childrenHalfChecked.length > 0) {
  373. // 部分子节点选中,父节点半选
  374. node.checked = false;
  375. node.halfChecked = true;
  376. } else {
  377. // 没有子节点选中
  378. node.checked = false;
  379. node.halfChecked = false;
  380. }
  381. }
  382. });
  383. };
  384. updateNode(treeData.value);
  385. };
  386. const toggleSelect = (item) => {
  387. item.checked = !item.checked;
  388. item.halfChecked = false;
  389. // 如果是叶子节点(用户),同步所有相同 userId 的节点
  390. if (!item.children || item.children.length === 0) {
  391. if (item.userId) {
  392. syncTeacherSelection(item.userId, item.checked);
  393. }
  394. } else {
  395. // 向下级联
  396. toggleChildren(item.children, item.checked);
  397. // 获取所有叶子节点的 userId 并同步到其他分组
  398. const getUserIds = (nodes) => {
  399. const ids = [];
  400. nodes.forEach(node => {
  401. if (node.userId) {
  402. ids.push(node.userId);
  403. } else if (node.children && node.children.length > 0) {
  404. ids.push(...getUserIds(node.children));
  405. }
  406. });
  407. return ids;
  408. };
  409. const userIds = getUserIds(item.children);
  410. userIds.forEach(id => {
  411. syncTeacherSelection(id, item.checked);
  412. });
  413. }
  414. // 向上级联
  415. updateParentStatus();
  416. };
  417. const selectedCount = computed(() => {
  418. const selectedUserIds = new Set();
  419. const collectChecked = (items) => {
  420. items.forEach(item => {
  421. if (item.children) {
  422. collectChecked(item.children);
  423. } else if (item.checked && item.userId) {
  424. selectedUserIds.add(item.userId);
  425. }
  426. });
  427. };
  428. collectChecked(treeData.value);
  429. return selectedUserIds.size;
  430. });
  431. const goBack = () => {
  432. uni.navigateBack();
  433. };
  434. const collectSelectedUsers = () => {
  435. const selectedUsers = [];
  436. const seen = new Set();
  437. const currentTab = activeTab.value;
  438. const collect = (nodes, parentInfo = {}) => {
  439. nodes.forEach(node => {
  440. if (node.children && node.children.length > 0) {
  441. const newParentInfo = { ...parentInfo };
  442. if (node.name && !node.userId) {
  443. if (currentTab === 'department') {
  444. // 按部门: 第一级是部门名称,第二级是分组名称
  445. if (!newParentInfo.departmentName) {
  446. newParentInfo.departmentName = node.name;
  447. } else if (!newParentInfo.groupName) {
  448. newParentInfo.groupName = node.name;
  449. }
  450. } else if (currentTab === 'subject') {
  451. // 按学科: 第一级是科目,第二级是年级
  452. if (!newParentInfo.subjectName) {
  453. newParentInfo.subjectName = node.name;
  454. } else if (!newParentInfo.gradeName) {
  455. newParentInfo.gradeName = node.name;
  456. }
  457. } else if (currentTab === 'grade') {
  458. // 按年级: 第一级是年级,第二级是班级类型,第三级是班级
  459. if (!newParentInfo.gradeName) {
  460. newParentInfo.gradeName = node.name;
  461. } else if (!newParentInfo.classTypeName) {
  462. newParentInfo.classTypeName = node.name;
  463. } else if (!newParentInfo.className) {
  464. newParentInfo.className = node.name;
  465. }
  466. } else if (currentTab === 'permission') {
  467. // 按权限: 第一级是角色
  468. if (!newParentInfo.roleName) {
  469. newParentInfo.roleName = node.name;
  470. }
  471. } else if (currentTab === 'student') {
  472. // 按学生: 第一级是年级,第二级是班级类型,第三级是班级
  473. if (!newParentInfo.gradeName) {
  474. newParentInfo.gradeName = node.name;
  475. } else if (!newParentInfo.classTypeName) {
  476. newParentInfo.classTypeName = node.name;
  477. } else if (!newParentInfo.className) {
  478. newParentInfo.className = node.name;
  479. }
  480. }
  481. }
  482. collect(node.children, newParentInfo);
  483. } else if (node.checked && node.userId && !seen.has(node.userId)) {
  484. seen.add(node.userId);
  485. selectedUsers.push({
  486. id: node.id,
  487. name: node.name,
  488. userId: node.userId,
  489. thirdCode: node.userAccount || '',
  490. departmentName: parentInfo.departmentName || '',
  491. groupName: parentInfo.groupName || '',
  492. subjectName: parentInfo.subjectName || '',
  493. gradeName: parentInfo.gradeName || '',
  494. classTypeName: parentInfo.classTypeName || '',
  495. className: parentInfo.className || '',
  496. roleName: parentInfo.roleName || ''
  497. });
  498. }
  499. });
  500. };
  501. collect(treeData.value);
  502. return selectedUsers;
  503. };
  504. const handleConfirm = () => {
  505. const data = {
  506. tab: tabs.find(t => t.key === activeTab.value).label,
  507. count: selectedCount.value,
  508. users: collectSelectedUsers()
  509. };
  510. uni.setStorageSync('selectObjectResult', JSON.stringify(data));
  511. uni.navigateBack();
  512. };
  513. const setSelectedUsers = (users) => {
  514. if (!users || !Array.isArray(users)) return;
  515. const selectedTeacherIds = new Set(users.map(u => u.teacherId));
  516. const setNode = (nodes) => {
  517. nodes.forEach(node => {
  518. if (node.children && node.children.length > 0) {
  519. setNode(node.children);
  520. } else if (node.teacherId && selectedTeacherIds.has(node.teacherId)) {
  521. node.checked = true;
  522. }
  523. });
  524. };
  525. setNode(treeData.value);
  526. updateParentStatus();
  527. };
  528. const setSelectedUsersById = (userIds) => {
  529. if (!userIds || !Array.isArray(userIds)) return;
  530. const selectedIds = new Set(userIds);
  531. const setNode = (nodes) => {
  532. nodes.forEach(node => {
  533. if (node.children && node.children.length > 0) {
  534. setNode(node.children);
  535. } else if (node.id && selectedIds.has(node.id)) {
  536. node.checked = true;
  537. if (node.teacherId) {
  538. syncTeacherSelection(node.teacherId, true);
  539. }
  540. }
  541. });
  542. };
  543. setNode(treeData.value);
  544. updateParentStatus();
  545. };
  546. onMounted(async () => {
  547. initSafeArea();
  548. const pages = getCurrentPages();
  549. if (pages.length === 1) {
  550. uni.redirectTo({ url: '/pages/notice/publish/index' });
  551. return;
  552. }
  553. const lastSelection = uni.getStorageSync('selectObjectLastSelection');
  554. if (lastSelection) {
  555. try {
  556. const data = JSON.parse(lastSelection);
  557. if (data.isEdit) {
  558. editMode.value = true;
  559. }
  560. if (data.noticeType) {
  561. noticeType.value = data.noticeType;
  562. const typeMap = {
  563. 1: 'department',
  564. 2: 'subject',
  565. 3: 'grade',
  566. 4: 'permission',
  567. 5: 'student'
  568. };
  569. const tabKey = typeMap[data.noticeType];
  570. if (tabKey) {
  571. activeTab.value = tabKey;
  572. }
  573. } else if (data.tab) {
  574. const tab = tabs.find(t => t.label === data.tab);
  575. if (tab) {
  576. activeTab.value = tab.key;
  577. }
  578. }
  579. if (data.users) {
  580. selectedUserIds.value = data.users.map(u => u.userId || u.id);
  581. }
  582. } catch (e) {
  583. console.error('解析上次选择失败:', e);
  584. }
  585. }
  586. await getSchoolYear();
  587. if (activeTab.value === 'department') {
  588. await loadDepartmentData();
  589. } else if (activeTab.value === 'subject' || activeTab.value === 'grade' || activeTab.value === 'permission') {
  590. await loadPersonalData(activeTab.value);
  591. } else if (activeTab.value === 'student') {
  592. await loadStudentData();
  593. }
  594. if (selectedUserIds.value.length > 0) {
  595. setSelectedUsersById(selectedUserIds.value);
  596. } else if (lastSelection) {
  597. try {
  598. const data = JSON.parse(lastSelection);
  599. if (data.users) {
  600. setSelectedUsers(data.users);
  601. }
  602. } catch (e) {
  603. console.error('设置选中状态失败:', e);
  604. }
  605. }
  606. });
  607. </script>
  608. <style lang="scss" scoped>
  609. .page_select_object {
  610. display: flex;
  611. flex-direction: column;
  612. min-height: 100vh;
  613. }
  614. .tabs_container {
  615. position: fixed;
  616. left: 0;
  617. right: 0;
  618. z-index: 99;
  619. display: flex;
  620. padding: 24rpx ;
  621. background-color: #FFFFFF;
  622. justify-content: space-between;
  623. .tab_item {
  624. flex-shrink: 0;
  625. width: 122rpx;
  626. height: 72rpx;
  627. background: #FFFFFF;
  628. border-radius: 8rpx;
  629. border: 2rpx solid #DCDFE6;
  630. display: flex;
  631. align-items: center;
  632. justify-content: center;
  633. &.active {
  634. background: #2E64FA;
  635. border-color: #2E64FA;
  636. .tab_text {
  637. color: #FFFFFF;
  638. }
  639. }
  640. .tab_text {
  641. font-weight: 400;
  642. font-size: 28rpx;
  643. color: #333333;
  644. }
  645. &.disabled {
  646. pointer-events: none;
  647. opacity: 0.5;
  648. }
  649. }
  650. }
  651. .content_list {
  652. flex: 1;
  653. padding-bottom: 150rpx;
  654. }
  655. .select_footer {
  656. position: fixed;
  657. bottom: 0;
  658. left: 0;
  659. right: 0;
  660. padding: 24rpx;
  661. background-color: #FFFFFF;
  662. border-top: 2rpx solid #F3F3F3;
  663. .confirm_btn {
  664. width: 100%;
  665. height: 90rpx;
  666. background: #2E64FA;
  667. border-radius: 8rpx;
  668. text-align: center;
  669. line-height: 90rpx;
  670. .btn_text {
  671. font-size: 32rpx;
  672. font-weight: 500;
  673. color: #FFFFFF;
  674. }
  675. }
  676. }
  677. </style>