studentManage.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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. <!-- input组件区域 -->
  6. <HeaderInput placeholder="请输入学生姓名或时间组名称" @changeInputValue="changeInputValue" />
  7. <!-- 学校年级班级区域 -->
  8. <view class="school" v-if="list.length">
  9. <view class="">{{ classInfo }}</view>
  10. <!-- 批量按钮区域 -->
  11. <view v-if="!showEdit" class="school_edit" @click="handleEdit">
  12. <img class="img" src="@/static/images/edit.png" />
  13. 批量
  14. </view>
  15. <!-- 全选按钮区域 -->
  16. <view v-else class="school_btn">
  17. <view class="cancel" @click="handleCancel">取消</view>
  18. <radio color="#0061FF" style="transform: scale(0.7)" :checked="allChecked" @click="handleAllCheck" />
  19. <view class="all">全选</view>
  20. </view>
  21. </view>
  22. <!-- 学生列表区域 -->
  23. <view class="list_box" v-if="list.length">
  24. <!-- 每一个学生区域 -->
  25. <view class="item_box" v-for="(item, index) in list" :key="index" @click="handleClickItem(item)">
  26. <view class="box_name">{{ item.name }}({{ item.cardNo }})</view>
  27. <view class="box_time">{{ item.timeGroup }}</view>
  28. <radio v-if="showEdit" color="#0061FF" style="transform: scale(0.7)" :checked="item.isChecked" />
  29. </view>
  30. </view>
  31. <!-- 关联时间组按钮区域 -->
  32. <view class="btn" v-if="showEdit">
  33. <view class="btn_box" @click="handleBind">
  34. <uni-icons color="#fff" type="link" size="28"></uni-icons>
  35. <text class="text">关联时间组</text>
  36. </view>
  37. </view>
  38. <!-- 没有数据时展示的页面 -->
  39. <NoData v-if="!list.length" style="margin-top: 140rpx" />
  40. <!-- 弹窗区域 -->
  41. <uni-popup ref="popupDom">
  42. <view class="pop_up">
  43. <!-- 头部标题区域 -->
  44. <view class="popup_top">{{ headerName }} - 关联时间组</view>
  45. <!-- 时间组区域 -->
  46. <view class="popup_body">
  47. <!-- 每一个时间组区域 -->
  48. <view class="time_item" v-for="item in timeGroups" :key="item.id" @click="handleClickItemPop(item)">
  49. <view class="item_left">
  50. <view class="top">{{ item.name }}</view>
  51. <view class="bottom">{{ item.remark }}</view>
  52. </view>
  53. <radio color="#0061FF" style="transform: scale(0.9)" :checked="item.isChecked" />
  54. </view>
  55. </view>
  56. </view>
  57. </uni-popup>
  58. </view>
  59. </template>
  60. <script setup>
  61. import { ref } from 'vue'
  62. import { onLoad } from '@dcloudio/uni-app'
  63. import HeaderInput from '@/components/headerInput.vue'
  64. import NoData from '@/components/noData.vue'
  65. import { myRequest } from '@/utils/api.js'
  66. import { decryptDes } from '@/utils/des.js'
  67. // 当前所处班级
  68. const classInfo = ref()
  69. // 搜索框绑定数据
  70. const keyWord = ref('')
  71. // 学生列表数据
  72. const list = ref([])
  73. // 缓存数据
  74. const copyList = ref([])
  75. // 是否显示全选radio
  76. const showEdit = ref(false)
  77. // 是否全选
  78. const allChecked = ref(false)
  79. // 弹窗DOM
  80. const popupDom = ref()
  81. // 时间组列表
  82. const timeGroups = ref([])
  83. // 弹窗标题
  84. const headerName = ref('')
  85. // 当前学生id
  86. const studentId = ref()
  87. // 滚动穿透控制
  88. const showPage = ref(false)
  89. onLoad(() => {
  90. getData()
  91. })
  92. // 获取学生列表数据
  93. const getData = async () => {
  94. const res = await myRequest({
  95. url: '/wanzai/api/smartUser/queryClassUser',
  96. data: {
  97. userId: uni.getStorageSync('userInfo').id,
  98. keyWord: keyWord.value
  99. }
  100. })
  101. // console.log(res)
  102. const result = JSON.parse(decryptDes(res.data))
  103. // console.log(result)
  104. list.value = result.userDetails
  105. list.value.forEach((ele) => {
  106. ele.isChecked = false
  107. })
  108. classInfo.value = result.name
  109. uni.setNavigationBarTitle({
  110. title: result.name
  111. })
  112. }
  113. // 点击批量按钮回调
  114. const handleEdit = () => {
  115. showEdit.value = true
  116. copyList.value = JSON.parse(JSON.stringify(list.value))
  117. }
  118. // 点击取消按钮回调
  119. const handleCancel = () => {
  120. showEdit.value = false
  121. allChecked.value = false
  122. list.value = copyList.value
  123. }
  124. // 点击全选按钮回调
  125. const handleAllCheck = () => {
  126. if (!allChecked.value) {
  127. list.value.forEach((ele) => {
  128. ele.isChecked = true
  129. })
  130. } else {
  131. list.value.forEach((ele) => {
  132. ele.isChecked = false
  133. })
  134. }
  135. allChecked.value = !allChecked.value
  136. }
  137. // 点击每一个学生时的回调
  138. const handleClickItem = (item) => {
  139. if (showEdit.value) {
  140. item.isChecked = !item.isChecked
  141. // 判断全选按钮的状态
  142. allChecked.value = list.value.every((ele) => ele.isChecked)
  143. } else {
  144. // 编辑单个学生
  145. showPage.value = true
  146. headerName.value = item.name
  147. studentId.value = item.id
  148. getTimeGroups()
  149. popupDom.value.open('center')
  150. }
  151. }
  152. // 获取时间组列表数据
  153. const getTimeGroups = async () => {
  154. const res = await myRequest({
  155. url: '/wanzai/api/smartUser/timeGroups'
  156. })
  157. // console.log(res)
  158. const result = JSON.parse(decryptDes(res.data))
  159. // console.log(result)
  160. timeGroups.value = result
  161. timeGroups.value.forEach((ele) => {
  162. ele.isChecked = false
  163. })
  164. }
  165. // 点击弹窗每一个时间组的回调
  166. const handleClickItemPop = (item) => {
  167. timeGroups.value.forEach((ele) => {
  168. ele.isChecked = false
  169. })
  170. item.isChecked = !item.isChecked
  171. uni.showModal({
  172. title: '提示',
  173. content: '确定修改时间组吗?',
  174. success: async (res) => {
  175. if (res.confirm) {
  176. handleConfirm(item.id)
  177. }
  178. }
  179. })
  180. }
  181. const handleConfirm = async (timeGroupId) => {
  182. const res = await myRequest({
  183. url: '/wanzai/api/smartUser/setUserTimeGroup',
  184. method: 'post',
  185. data: {
  186. ids: [studentId.value],
  187. timeGroupId
  188. }
  189. })
  190. // console.log(res)
  191. uni.showToast({
  192. title: res.message,
  193. icon: 'none',
  194. mask: true
  195. })
  196. if (res.code == 200) {
  197. setTimeout(() => {
  198. uni.reLaunch({
  199. url: '/pages/studentManage/studentManage'
  200. })
  201. }, 1500)
  202. }
  203. }
  204. // 点击关联时间组按钮回调
  205. const handleBind = () => {
  206. // 判断是否选择了学生
  207. const flag = list.value.find((ele) => ele.isChecked)
  208. if (!flag) {
  209. uni.showToast({
  210. title: '请至少选择一名学生',
  211. icon: 'none',
  212. mask: true
  213. })
  214. } else {
  215. let arr = []
  216. list.value.forEach((ele) => {
  217. if (ele.isChecked) {
  218. arr.push(ele.id)
  219. }
  220. })
  221. uni.navigateTo({
  222. url: `/pages/timeGroup/timeGroup?ids=${JSON.stringify(arr)}`
  223. })
  224. }
  225. }
  226. // 输入框组件自定义事件
  227. const changeInputValue = (value) => {
  228. keyWord.value = value
  229. getData()
  230. }
  231. </script>
  232. <style lang="scss" scoped>
  233. .container {
  234. display: flex;
  235. flex-direction: column;
  236. padding: 0 20rpx;
  237. min-height: 100vh;
  238. background-color: #f1f6fe;
  239. // 背景图片区域样式
  240. .img_bg {
  241. position: absolute;
  242. top: -70rpx;
  243. right: 0;
  244. width: 589rpx;
  245. height: 320rpx;
  246. pointer-events: none;
  247. }
  248. // 学校名称区域样式
  249. .school {
  250. display: flex;
  251. justify-content: space-between;
  252. align-items: center;
  253. margin-top: 38rpx;
  254. color: #808080;
  255. font-size: 28rpx;
  256. .school_edit {
  257. display: flex;
  258. align-items: center;
  259. margin-right: 30rpx;
  260. color: #0061ff;
  261. .img {
  262. margin-right: 10rpx;
  263. width: 30rpx;
  264. height: 30rpx;
  265. }
  266. }
  267. .school_btn {
  268. display: flex;
  269. align-items: center;
  270. .cancel {
  271. margin-right: 20rpx;
  272. color: #d43030;
  273. }
  274. .all {
  275. margin-left: -10rpx;
  276. }
  277. }
  278. }
  279. .list_box {
  280. padding: 0 30rpx 30rpx;
  281. margin-top: 22rpx;
  282. background-color: #fff;
  283. .item_box {
  284. display: flex;
  285. justify-content: space-between;
  286. align-items: center;
  287. height: 103rpx;
  288. font-size: 24rpx;
  289. border-bottom: 1rpx solid #e6e6e6;
  290. .box_name {
  291. }
  292. .box_time {
  293. }
  294. }
  295. }
  296. .btn {
  297. position: fixed;
  298. bottom: 0;
  299. padding: 0 30rpx 30rpx;
  300. background-color: #fff;
  301. .btn_box {
  302. display: flex;
  303. justify-content: center;
  304. align-items: center;
  305. margin-top: 28rpx;
  306. width: 650rpx;
  307. height: 100rpx;
  308. color: #fff;
  309. font-size: 32rpx;
  310. border-radius: 8rpx;
  311. background-color: #0061ff;
  312. .text {
  313. margin-left: 10rpx;
  314. }
  315. }
  316. }
  317. .pop_up {
  318. width: 710rpx;
  319. height: 855rpx;
  320. border-radius: 22rpx;
  321. background-color: #fff;
  322. .popup_top {
  323. height: 94rpx;
  324. line-height: 94rpx;
  325. text-align: center;
  326. font-size: 28rpx;
  327. border-bottom: 1rpx solid #e6e6e6;
  328. }
  329. .popup_body {
  330. height: 760rpx;
  331. overflow-y: auto;
  332. .time_item {
  333. display: flex;
  334. justify-content: space-between;
  335. align-items: center;
  336. padding: 0 40rpx;
  337. height: 130rpx;
  338. border-bottom: 1rpx solid #e6e6e6;
  339. .item_left {
  340. display: flex;
  341. flex-direction: column;
  342. justify-content: space-between;
  343. height: 80rpx;
  344. .top {
  345. font-size: 28rpx;
  346. }
  347. .bottom {
  348. font-size: 24rpx;
  349. color: #b3b3b3;
  350. }
  351. }
  352. }
  353. }
  354. }
  355. }
  356. </style>