studentManage.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. <template>
  2. <view class="container" :style="[showEdit ? 'padding-bottom:180rpx' : '', showPage ? 'overflow:hidden' : 'overflow:visible']">
  3. <!-- 背景图片区域 -->
  4. <img class="img_bg" src="../../static/images/center-bg.png" />
  5. <!-- 输入框和设置按钮区域 -->
  6. <view class="header">
  7. <view class="header_input">
  8. <uni-icons type="search" size="28" color="#808080" @click="changeInputValue"></uni-icons>
  9. <input v-model="keyWord" class="input" type="text" placeholder="请输入学生姓名" />
  10. </view>
  11. <view class="header_set" @click="handleClickSet">
  12. <uni-icons type="gear" size="28" color="#383838"></uni-icons>
  13. </view>
  14. </view>
  15. <!-- 功能按钮区域 -->
  16. <view class="school" v-if="list.length">
  17. <!-- 邀请家长按钮区域 -->
  18. <view v-if="!showEdit" class="invite" @click="handleInvitation">
  19. <uni-icons type="personadd" size="22" color="#0061FF"></uni-icons>
  20. &nbsp;邀请家长
  21. </view>
  22. <!-- 批量修改按钮区域 -->
  23. <view v-if="!showEdit" class="school_edit" @click="handleEdit('修改')">
  24. <img class="img" src="@/static/images/edit2.png" />
  25. 批量修改
  26. </view>
  27. <!-- 添加按钮区域 -->
  28. <view v-if="!showEdit" class="add" @click="handleAdd">
  29. <uni-icons type="plus" size="22" color="#0061FF"></uni-icons>
  30. &nbsp;添加
  31. </view>
  32. <!-- 删除按钮区域 -->
  33. <view v-if="!showEdit" class="delete" @click="handleDelete('删除')">
  34. <uni-icons type="trash" size="22" color="#D43030"></uni-icons>
  35. 批量删除
  36. </view>
  37. <!-- 全选按钮区域 -->
  38. <view v-if="showEdit" class="school_btn">
  39. <view class="cancel" @click="handleCancel">取消</view>
  40. <radio color="#0061FF" style="transform: scale(0.7)" :checked="allChecked" @click="handleAllCheck" />
  41. <view class="all">全选</view>
  42. </view>
  43. </view>
  44. <!-- 学生列表区域 -->
  45. <view class="list_box" v-if="list.length">
  46. <uni-swipe-action>
  47. <view v-for="(item, index) in list" :key="index">
  48. <uni-swipe-action-item :right-options="options" @click="onClickItem(item)">
  49. <!-- 每一个学生区域 -->
  50. <view class="item_box" @click="handleClickItem(item)">
  51. <view class="box_info">
  52. <image class="info_img" src="/static/images/header.png" mode="aspectFill"></image>
  53. <view class="info_msg">
  54. <view class="msg_name">
  55. {{ item.name }}
  56. </view>
  57. <view class="msg_no">
  58. {{ item.cardNo }}
  59. </view>
  60. </view>
  61. </view>
  62. <view class="box_time">{{ item.timeGroup }}</view>
  63. <radio v-if="showEdit" color="#0061FF" style="transform: scale(0.7)" :checked="item.isChecked" />
  64. </view>
  65. </uni-swipe-action-item>
  66. <view style="height: 20rpx"></view>
  67. </view>
  68. </uni-swipe-action>
  69. </view>
  70. <!-- 关联时间组按钮区域 -->
  71. <view class="btn" v-if="showEdit && currentType == '修改'">
  72. <view class="btn_box" @click="handleBind">
  73. <uni-icons color="#fff" type="link" size="28"></uni-icons>
  74. <text class="text">关联时间组</text>
  75. </view>
  76. </view>
  77. <!-- 批量删除区域 -->
  78. <view class="btn" v-if="showEdit && currentType == '删除'">
  79. <view class="btn_box delete" @click="handleDeleteBatch">
  80. <uni-icons color="#fff" type="trash" size="28"></uni-icons>
  81. <text class="text">批量删除</text>
  82. </view>
  83. </view>
  84. <!-- 没有数据时展示的页面 -->
  85. <NoData v-if="!list.length" style="margin-top: 140rpx" />
  86. <!-- 弹窗区域 -->
  87. <uni-popup ref="popupDom">
  88. <view class="pop_up">
  89. <!-- 头部标题区域 -->
  90. <view class="popup_top">{{ headerName }} - 关联时间组</view>
  91. <!-- 时间组区域 -->
  92. <view class="popup_body">
  93. <!-- 每一个时间组区域 -->
  94. <view class="time_item" v-for="item in timeGroups" :key="item.id" @click="handleClickItemPop(item)">
  95. <view class="item_left">
  96. <view class="top">{{ item.name }}</view>
  97. <view class="bottom">{{ item.remark }}</view>
  98. </view>
  99. <radio color="#0061FF" style="transform: scale(0.9)" :checked="item.isChecked" />
  100. </view>
  101. </view>
  102. </view>
  103. </uni-popup>
  104. </view>
  105. </template>
  106. <script setup>
  107. import { ref } from 'vue'
  108. import { onLoad } from '@dcloudio/uni-app'
  109. import HeaderInput from '@/components/headerInput.vue'
  110. import NoData from '@/components/noData.vue'
  111. import { myRequest } from '@/utils/api.js'
  112. import { decryptDes } from '@/utils/des.js'
  113. // 当前所处班级
  114. const classInfo = ref()
  115. // 搜索框绑定数据
  116. const keyWord = ref('')
  117. // 学生列表数据
  118. const list = ref([])
  119. // 缓存数据
  120. const copyList = ref([])
  121. // 是否显示全选radio
  122. const showEdit = ref(false)
  123. // 是否全选
  124. const allChecked = ref(false)
  125. // 弹窗DOM
  126. const popupDom = ref()
  127. // 时间组列表
  128. const timeGroups = ref([])
  129. // 弹窗标题
  130. const headerName = ref('')
  131. // 当前学生id
  132. const studentId = ref()
  133. // 滚动穿透控制
  134. const showPage = ref(false)
  135. const options = [
  136. {
  137. text: '删除',
  138. style: {
  139. backgroundColor: '#D43030'
  140. }
  141. }
  142. ]
  143. const currentType = ref('')
  144. onLoad(() => {
  145. getData()
  146. })
  147. // 获取学生列表数据
  148. const getData = async () => {
  149. const res = await myRequest({
  150. url: '/wanzai/api/smartUser/queryClassUser',
  151. data: {
  152. userId: uni.getStorageSync('userInfo').id,
  153. keyWord: keyWord.value
  154. }
  155. })
  156. // console.log(res)
  157. const result = JSON.parse(decryptDes(res.data))
  158. // console.log(result)
  159. list.value = result.userDetails
  160. list.value.forEach((ele) => {
  161. ele.isChecked = false
  162. })
  163. classInfo.value = result.name
  164. uni.setNavigationBarTitle({
  165. title: result.name
  166. })
  167. }
  168. // 点击邀请家长按钮回调
  169. const handleInvitation = () => {
  170. uni.navigateTo({
  171. url: '/pages/invitation/invitation'
  172. })
  173. }
  174. // 点击批量按钮回调
  175. const handleEdit = (type) => {
  176. currentType.value = type
  177. showEdit.value = true
  178. copyList.value = JSON.parse(JSON.stringify(list.value))
  179. }
  180. // 点击添加按钮回调
  181. const handleAdd = () => {
  182. uni.navigateTo({
  183. url: '/pages/addStudent/addStudent'
  184. })
  185. }
  186. // 批量删除按钮回调
  187. const handleDelete = (type) => {
  188. currentType.value = type
  189. showEdit.value = true
  190. copyList.value = JSON.parse(JSON.stringify(list.value))
  191. }
  192. // 点击取消按钮回调
  193. const handleCancel = () => {
  194. currentType.value = ''
  195. showEdit.value = false
  196. allChecked.value = false
  197. list.value = copyList.value
  198. }
  199. // 点击全选按钮回调
  200. const handleAllCheck = () => {
  201. if (!allChecked.value) {
  202. list.value.forEach((ele) => {
  203. ele.isChecked = true
  204. })
  205. } else {
  206. list.value.forEach((ele) => {
  207. ele.isChecked = false
  208. })
  209. }
  210. allChecked.value = !allChecked.value
  211. }
  212. // 点击每一项删除回调
  213. const onClickItem = (item) => {
  214. uni.showModal({
  215. title: '提示',
  216. content: `确定把${item.name}移除吗?`,
  217. success: (res) => {
  218. if (res.confirm) {
  219. handleDeleteReq([item.id])
  220. }
  221. }
  222. })
  223. }
  224. // 删除请求
  225. const handleDeleteReq = async (ids) => {
  226. const res = await myRequest({
  227. url: '/wanzai/api/smartUser/appRemoveClass',
  228. method: 'post',
  229. data: {
  230. ids: ids
  231. }
  232. })
  233. // console.log(res)
  234. if (res.code == 200) {
  235. uni.showToast({
  236. title: res.message,
  237. icon: 'success'
  238. })
  239. setTimeout(() => {
  240. currentType.value = ''
  241. showEdit.value = false
  242. allChecked.value = false
  243. getData()
  244. }, 1500)
  245. }
  246. }
  247. // 点击每一个学生时的回调
  248. const handleClickItem = (item) => {
  249. if (showEdit.value) {
  250. item.isChecked = !item.isChecked
  251. // 判断全选按钮的状态
  252. allChecked.value = list.value.every((ele) => ele.isChecked)
  253. } else {
  254. // 编辑单个学生
  255. showPage.value = true
  256. headerName.value = item.name
  257. studentId.value = item.id
  258. getTimeGroups()
  259. popupDom.value.open('center')
  260. }
  261. }
  262. // 获取时间组列表数据
  263. const getTimeGroups = async () => {
  264. const res = await myRequest({
  265. url: '/wanzai/api/smartUser/timeGroups'
  266. })
  267. // console.log(res)
  268. const result = JSON.parse(decryptDes(res.data))
  269. // console.log(result)
  270. timeGroups.value = result
  271. timeGroups.value.forEach((ele) => {
  272. ele.isChecked = false
  273. })
  274. }
  275. // 点击弹窗每一个时间组的回调
  276. const handleClickItemPop = (item) => {
  277. timeGroups.value.forEach((ele) => {
  278. ele.isChecked = false
  279. })
  280. item.isChecked = !item.isChecked
  281. uni.showModal({
  282. title: '提示',
  283. content: '确定修改时间组吗?',
  284. success: async (res) => {
  285. if (res.confirm) {
  286. handleConfirm(item.id)
  287. }
  288. }
  289. })
  290. }
  291. const handleConfirm = async (timeGroupId) => {
  292. const res = await myRequest({
  293. url: '/wanzai/api/smartUser/setUserTimeGroup',
  294. method: 'post',
  295. data: {
  296. ids: [studentId.value],
  297. timeGroupId
  298. }
  299. })
  300. // console.log(res)
  301. uni.showToast({
  302. title: res.message,
  303. icon: 'none',
  304. mask: true
  305. })
  306. if (res.code == 200) {
  307. setTimeout(() => {
  308. uni.reLaunch({
  309. url: '/pages/studentManage/studentManage'
  310. })
  311. }, 1500)
  312. }
  313. }
  314. // 点击关联时间组按钮回调
  315. const handleBind = () => {
  316. // 判断是否选择了学生
  317. const flag = list.value.find((ele) => ele.isChecked)
  318. if (!flag) {
  319. uni.showToast({
  320. title: '请至少选择一名学生',
  321. icon: 'none',
  322. mask: true
  323. })
  324. } else {
  325. let arr = []
  326. list.value.forEach((ele) => {
  327. if (ele.isChecked) {
  328. arr.push(ele.id)
  329. }
  330. })
  331. uni.navigateTo({
  332. url: `/pages/timeGroup/timeGroup?ids=${JSON.stringify(arr)}`
  333. })
  334. }
  335. }
  336. // 批量删除按钮回调
  337. const handleDeleteBatch = () => {
  338. // 判断是否选择了学生
  339. const flag = list.value.find((ele) => ele.isChecked)
  340. if (!flag) {
  341. uni.showToast({
  342. title: '请至少选择一名学生',
  343. icon: 'none',
  344. mask: true
  345. })
  346. } else {
  347. uni.showModal({
  348. title: '提示',
  349. content: '确定批量移除吗?',
  350. success: (res) => {
  351. if (res.confirm) {
  352. let arr = []
  353. list.value.forEach((ele) => {
  354. if (ele.isChecked) {
  355. arr.push(ele.id)
  356. }
  357. })
  358. handleDeleteReq(arr)
  359. }
  360. }
  361. })
  362. }
  363. }
  364. // 输入框组件自定义事件
  365. const changeInputValue = () => {
  366. getData()
  367. }
  368. // 设置图标点击回调
  369. const handleClickSet = () => {
  370. uni.navigateTo({
  371. url: '/pages/set/set'
  372. })
  373. }
  374. </script>
  375. <style lang="scss" scoped>
  376. .container {
  377. display: flex;
  378. flex-direction: column;
  379. padding: 0 20rpx;
  380. min-height: 100vh;
  381. background-color: #f1f6fe;
  382. // 背景图片区域样式
  383. .img_bg {
  384. position: absolute;
  385. top: -70rpx;
  386. right: 0;
  387. width: 589rpx;
  388. height: 320rpx;
  389. pointer-events: none;
  390. }
  391. .header {
  392. display: flex;
  393. justify-content: space-between;
  394. align-items: center;
  395. padding-top: 30rpx;
  396. .header_input {
  397. display: flex;
  398. align-items: center;
  399. box-sizing: border-box;
  400. padding-left: 40rpx;
  401. width: 589rpx;
  402. height: 100rpx;
  403. font-size: 28rpx;
  404. border-radius: 13rpx;
  405. border: 2rpx solid #cccccc;
  406. background-color: #fff;
  407. .input {
  408. padding: 0 20rpx;
  409. width: 425rpx;
  410. }
  411. }
  412. .header_set {
  413. display: flex;
  414. justify-content: center;
  415. align-items: center;
  416. width: 100rpx;
  417. height: 100rpx;
  418. border-radius: 13rpx;
  419. border: 2rpx solid #cccccc;
  420. background-color: #fff;
  421. }
  422. }
  423. // 学校名称区域样式
  424. .school {
  425. display: flex;
  426. // justify-content: space-between;
  427. align-items: center;
  428. margin-top: 38rpx;
  429. color: #808080;
  430. font-size: 28rpx;
  431. .invite {
  432. display: flex;
  433. align-items: center;
  434. margin-right: 30rpx;
  435. color: #0061ff;
  436. }
  437. .school_edit {
  438. display: flex;
  439. align-items: center;
  440. margin-right: 80rpx;
  441. color: #00baad;
  442. .img {
  443. width: 45rpx;
  444. height: 45rpx;
  445. }
  446. }
  447. .add {
  448. display: flex;
  449. align-items: center;
  450. color: #0061ff;
  451. }
  452. .delete {
  453. display: flex;
  454. align-items: center;
  455. margin-left: auto;
  456. color: #d43030;
  457. }
  458. .school_btn {
  459. display: flex;
  460. align-items: center;
  461. .cancel {
  462. margin-right: 20rpx;
  463. color: #d43030;
  464. }
  465. .all {
  466. margin-left: -10rpx;
  467. }
  468. }
  469. }
  470. .list_box {
  471. padding-bottom: 30rpx;
  472. margin-top: 22rpx;
  473. background-color: #f1f6fe;
  474. .item_box {
  475. display: flex;
  476. justify-content: space-between;
  477. align-items: center;
  478. padding: 0 20rpx;
  479. height: 167rpx;
  480. font-size: 28rpx;
  481. border-radius: 8rpx;
  482. background-color: #fff;
  483. .box_info {
  484. display: flex;
  485. .info_img {
  486. width: 100rpx;
  487. height: 100rpx;
  488. border-radius: 50%;
  489. }
  490. .info_msg {
  491. display: flex;
  492. flex-direction: column;
  493. justify-content: space-between;
  494. margin-left: 28rpx;
  495. .msg_name {
  496. font-size: 32rpx;
  497. }
  498. .msg_no {
  499. color: #808080;
  500. }
  501. }
  502. }
  503. .box_time {
  504. }
  505. }
  506. }
  507. .btn {
  508. position: fixed;
  509. bottom: 0;
  510. padding: 0 30rpx 30rpx;
  511. background-color: #fff;
  512. .btn_box {
  513. display: flex;
  514. justify-content: center;
  515. align-items: center;
  516. margin-top: 28rpx;
  517. width: 650rpx;
  518. height: 100rpx;
  519. color: #fff;
  520. font-size: 32rpx;
  521. border-radius: 8rpx;
  522. background-color: #0061ff;
  523. .text {
  524. margin-left: 10rpx;
  525. }
  526. }
  527. .delete {
  528. background-color: #d43030;
  529. }
  530. }
  531. .pop_up {
  532. width: 710rpx;
  533. height: 855rpx;
  534. border-radius: 22rpx;
  535. background-color: #fff;
  536. .popup_top {
  537. height: 94rpx;
  538. line-height: 94rpx;
  539. text-align: center;
  540. font-size: 28rpx;
  541. border-bottom: 1rpx solid #e6e6e6;
  542. }
  543. .popup_body {
  544. height: 760rpx;
  545. overflow-y: auto;
  546. .time_item {
  547. display: flex;
  548. justify-content: space-between;
  549. align-items: center;
  550. padding: 0 40rpx;
  551. height: 130rpx;
  552. border-bottom: 1rpx solid #e6e6e6;
  553. .item_left {
  554. display: flex;
  555. flex-direction: column;
  556. justify-content: space-between;
  557. height: 80rpx;
  558. .top {
  559. font-size: 28rpx;
  560. }
  561. .bottom {
  562. font-size: 24rpx;
  563. color: #b3b3b3;
  564. }
  565. }
  566. }
  567. }
  568. }
  569. }
  570. </style>