group.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. <template>
  2. <view class="container">
  3. <view class="placeholder"></view>
  4. <!-- 头部搜索栏区域 -->
  5. <view class="search">
  6. <uni-search-bar bgColor="#fff" placeholder="请输入搜索内容" cancelButton="none" v-model="searchValue" @clear="clear" @input="getGroupData"></uni-search-bar>
  7. </view>
  8. <!-- 新增考勤组区域 -->
  9. <view class="add">
  10. <view v-if="flag == 1" class="icon" @click="handleAdd"><img src="../../static/imgs/add.png" /></view>
  11. <view v-if="flag == 1" class="title" @click="handleAdd">新增考勤组</view>
  12. <view v-if="flag == 2" class="icon" @click="handleRelevancy"><img src="../../static/imgs/add.png" /></view>
  13. <view v-if="flag == 2" class="title" @click="handleRelevancy">关联考勤组</view>
  14. </view>
  15. <!--考勤组列表区域 -->
  16. <view class="group">
  17. <uni-swipe-action>
  18. <!-- 每一个考勤组区域 -->
  19. <uni-swipe-action-item :auto-close="true" :right-options="options" @click="onClick(item.id)" v-for="item in list" :key="item.id">
  20. <view class="group_item">
  21. <uni-collapse :ref="item.id + 'collapse'">
  22. <uni-collapse-item open>
  23. <!-- 自定义标题区域 -->
  24. <template v-slot:title>
  25. <view class="collapse_title">
  26. <checkbox class="collapse_check" :disabled="checkStatus" color="#0082FC" :checked="item.checked" @click.stop="handleChange(item)" />
  27. <view class="collapse_info">{{ item.name }}</view>
  28. </view>
  29. </template>
  30. <!-- 折叠内容区域 -->
  31. <view class="content">
  32. <view class="num">随机人数:{{ item.peopleCount }}人</view>
  33. <!-- 树状结构区域 -->
  34. <view class="tree"><dropDown :node="item.textArr" @nodechange="nodechange(item.id + 'collapse')"></dropDown></view>
  35. </view>
  36. </uni-collapse-item>
  37. </uni-collapse>
  38. </view>
  39. </uni-swipe-action-item>
  40. </uni-swipe-action>
  41. </view>
  42. <!-- 新增考勤组弹窗区域 -->
  43. <uni-popup ref="popup" :is-mask-click="false">
  44. <view class="popup_box">
  45. <view class="header">新增考勤组</view>
  46. <view class="body">
  47. <view class="name"><input type="text" placeholder="请输入考勤组名称" v-model="group_name" /></view>
  48. <view class="scope" @click="handleChoose">
  49. <view class="notes" v-if="!group_scope">请选择考勤组范围</view>
  50. <view class="notes2" v-else>{{ group_scope }}</view>
  51. <view class="icon"><img src="./imgs/bottom.png" /></view>
  52. </view>
  53. <view class="num">
  54. <view class="count">
  55. <view class="icon"><img src="./imgs/people.png" /></view>
  56. <view class="info">{{ group_total }}人</view>
  57. </view>
  58. <view class="input"><input type="number" placeholder="请输入打卡人数" v-model="group_num" /></view>
  59. </view>
  60. </view>
  61. <view class="foot">
  62. <view class="left" @click="handleCancel">取消</view>
  63. <view class="right" @click="handleSave">保存</view>
  64. </view>
  65. </view>
  66. </uni-popup>
  67. <!-- 选择考勤组范围区域 -->
  68. <tki-tree ref="tkitree" multiple :range="range" rangeKey="name" confirmColor="#3396FB" @confirm="treeConfirm" @cancel="treeCancel" />
  69. </view>
  70. </template>
  71. <script>
  72. import tkiTree from '../../components/tki-tree/tki-tree.vue'
  73. export default {
  74. components: {
  75. tkiTree
  76. },
  77. data() {
  78. return {
  79. // 新增考勤组名称
  80. group_name: '',
  81. // 新增考勤组范围
  82. group_scope: '',
  83. // 新增考勤组需要打卡人数
  84. group_num: null,
  85. // 新增考勤组总人数
  86. group_total: 0,
  87. // 新增考勤组ID数组
  88. userOrgList: [],
  89. // 判断是新增考勤组还是关联考勤组标识
  90. flag: null,
  91. // 考勤组勾选框禁用标识
  92. checkStatus: false,
  93. // 搜索框绑定的值
  94. searchValue: '',
  95. // 左滑选项配置
  96. options: [
  97. {
  98. text: '删除',
  99. style: {
  100. backgroundColor: '#D43030'
  101. }
  102. }
  103. ],
  104. // 考勤组列表数据
  105. list: [],
  106. // 考勤组范围数组
  107. range: []
  108. }
  109. },
  110. onLoad(options) {
  111. this.flag = options.flag
  112. if (this.flag == 1) {
  113. this.checkStatus = true
  114. }
  115. this.getGroupData()
  116. },
  117. methods: {
  118. // 获取考勤组列表数据
  119. async getGroupData() {
  120. let res = await this.$myRequest_clockIn({
  121. url: '/attendance/api/settings/group/list',
  122. data: {
  123. name: this.searchValue,
  124. size: 999
  125. }
  126. })
  127. // console.log(res);
  128. if (res.code == 200) {
  129. res.data.list.forEach(ele => {
  130. ele.checked = false
  131. ele.textArr = []
  132. ele.names.forEach(element => {
  133. ele.textArr.push({
  134. name: element
  135. })
  136. })
  137. })
  138. this.list = res.data.list
  139. }
  140. },
  141. // 考勤组选择框确定回调事件
  142. treeConfirm(e) {
  143. // console.log(e)
  144. let count = 0
  145. let temList = []
  146. let userOrgList = []
  147. e.forEach(ele => {
  148. temList.push(ele.name)
  149. userOrgList.push({
  150. orgId: ele.id,
  151. type: 2
  152. })
  153. count += ele.number
  154. })
  155. this.group_scope = temList.join(',')
  156. this.group_total = count
  157. this.userOrgList = userOrgList
  158. },
  159. // 考勤组选择框取消回调事件
  160. treeCancel(e) {
  161. // this.$refs.tkitree._hide()
  162. },
  163. // 点击选择考勤组选择框回调
  164. async handleChoose() {
  165. this.range = []
  166. let res = await this.$myRequest_clockIn({
  167. url: '/attendance/api/settings/org/tree'
  168. })
  169. // console.log(res);
  170. if (res.code == 200) {
  171. this.range = res.data
  172. this.$refs.tkitree._show()
  173. }
  174. },
  175. handleChange(item) {
  176. // console.log(item);
  177. item.checked = !item.checked
  178. },
  179. // 点击弹窗保存按钮回调
  180. async handleSave() {
  181. if (!this.group_name) {
  182. uni.showToast({
  183. title: '请输入考勤组名称',
  184. icon: 'none'
  185. })
  186. return
  187. }
  188. if (!this.group_scope) {
  189. uni.showToast({
  190. title: '请选择考勤组范围',
  191. icon: 'none'
  192. })
  193. return
  194. }
  195. if (this.group_total == 0) {
  196. uni.showToast({
  197. title: '该考勤组范围中人数为0,请重新选择',
  198. icon: 'none'
  199. })
  200. return
  201. }
  202. if (!this.group_num) {
  203. uni.showToast({
  204. title: '请输入打卡人数',
  205. icon: 'none'
  206. })
  207. return
  208. }
  209. if (this.group_num - 0 > this.group_total - 0) {
  210. uni.showToast({
  211. title: '打卡人数不能超过总人数',
  212. icon: 'none'
  213. })
  214. return
  215. }
  216. let res = await this.$myRequest_clockIn({
  217. url: '/attendance/api/settings/group/add',
  218. method: 'post',
  219. header: {
  220. 'content-type': 'application/json'
  221. },
  222. data: {
  223. name: this.group_name,
  224. peopleCount: this.group_num,
  225. peopleTotal: this.group_total,
  226. userOrgList: this.userOrgList
  227. }
  228. })
  229. // console.log(res);
  230. if (res.code == 200) {
  231. this.$refs.popup.close()
  232. uni.showToast({
  233. title: '添加成功',
  234. icon: 'none'
  235. })
  236. setTimeout(() => {
  237. this.getGroupData()
  238. }, 1500)
  239. } else {
  240. uni.showToast({
  241. title: res.message,
  242. icon: 'none'
  243. })
  244. }
  245. },
  246. // 点击弹窗取消按钮回调
  247. handleCancel() {
  248. this.$refs.popup.close()
  249. },
  250. // 点击新增考勤组按钮回调
  251. handleAdd() {
  252. this.group_name = ''
  253. this.group_num = null
  254. this.group_total = 0
  255. this.group_scope = ''
  256. this.userOrgList = []
  257. this.$nextTick(() => {
  258. this.$refs.popup.open()
  259. })
  260. },
  261. // 点击关联考勤组按钮回调
  262. handleRelevancy() {
  263. let temList = []
  264. this.list.forEach(ele => {
  265. if (ele.checked == true) {
  266. temList.push({
  267. name: ele.name,
  268. id: ele.id
  269. })
  270. }
  271. })
  272. if (temList.length == 0) {
  273. uni.showToast({
  274. title: '请先勾选考勤组',
  275. icon: 'none'
  276. })
  277. } else {
  278. uni.$emit('updateRuleGroup', temList)
  279. uni.navigateBack({
  280. delta: 1
  281. })
  282. }
  283. },
  284. // 点击树状节点回调
  285. nodechange(ref) {
  286. // console.log(ref);
  287. this.$nextTick(() => {
  288. setTimeout(() => {
  289. this.$refs[ref][0].resize()
  290. }, 200)
  291. })
  292. },
  293. // 点击右侧删除按钮回调
  294. onClick(id) {
  295. // console.log(id);
  296. uni.showModal({
  297. title: '提示',
  298. content: '确定删除该考勤组吗?',
  299. success: async res => {
  300. if (res.confirm) {
  301. let res = await this.$myRequest_clockIn({
  302. url: '/attendance/api/settings/group/delete',
  303. method: 'delete',
  304. data: {
  305. ids: [id]
  306. }
  307. })
  308. // console.log(res);
  309. if (res.code == 200 && res.data) {
  310. uni.showToast({
  311. title: '删除成功',
  312. icon: 'success'
  313. })
  314. setTimeout(() => {
  315. this.getGroupData()
  316. }, 1500)
  317. } else {
  318. uni.showToast({
  319. title: res.message,
  320. icon: 'none',
  321. duration: 3000
  322. })
  323. }
  324. } else if (res.cancel) {
  325. }
  326. }
  327. })
  328. },
  329. // 清除搜索框内容时的回调
  330. clear() {
  331. this.searchValue = ''
  332. this.getGroupData()
  333. }
  334. }
  335. }
  336. </script>
  337. <style lang="scss" scoped>
  338. .container {
  339. min-width: 100vw;
  340. min-height: 100vh;
  341. background-color: #f2f2f2;
  342. .placeholder {
  343. height: 20rpx;
  344. }
  345. .search {
  346. box-sizing: border-box;
  347. padding: 0 30rpx;
  348. width: 750rpx;
  349. height: 90rpx;
  350. border-radius: 170rpx;
  351. background-color: #fff;
  352. }
  353. .add {
  354. margin-top: 20rpx;
  355. display: flex;
  356. align-items: center;
  357. width: 750rpx;
  358. height: 110rpx;
  359. background-color: #fff;
  360. .icon {
  361. margin: 0 20rpx 0 30rpx;
  362. width: 36rpx;
  363. height: 36rpx;
  364. img {
  365. width: 100%;
  366. height: 100%;
  367. }
  368. }
  369. .title {
  370. font-size: 30rpx;
  371. color: #0082fc;
  372. }
  373. }
  374. .group {
  375. margin-top: 20rpx;
  376. background-color: #f2f2f2;
  377. .group_item {
  378. margin-bottom: 20rpx;
  379. width: 750rpx;
  380. background-color: #fff;
  381. .collapse_title {
  382. display: flex;
  383. align-items: center;
  384. height: 79rpx;
  385. .collapse_check {
  386. margin-left: 30rpx;
  387. }
  388. .collapse_info {
  389. margin-left: 10rpx;
  390. font-size: 28rpx;
  391. font-weight: 600;
  392. }
  393. }
  394. .content {
  395. padding-bottom: 50rpx;
  396. .num {
  397. margin-left: 30rpx;
  398. height: 50rpx;
  399. font-size: 24rpx;
  400. color: #808080;
  401. }
  402. .tree {
  403. }
  404. }
  405. }
  406. }
  407. .popup_box {
  408. width: 630rpx;
  409. height: 610rpx;
  410. border-radius: 33rpx;
  411. background-color: #fff;
  412. .header {
  413. width: 630rpx;
  414. height: 97rpx;
  415. line-height: 97rpx;
  416. text-align: center;
  417. font-size: 32rpx;
  418. font-weight: 500;
  419. border-bottom: 1rpx solid #e6e6e6;
  420. }
  421. .body {
  422. display: flex;
  423. flex-direction: column;
  424. align-items: center;
  425. width: 630rpx;
  426. height: 414rpx;
  427. border-bottom: 1rpx solid #e6e6e6;
  428. .name {
  429. margin-top: 42rpx;
  430. width: 570rpx;
  431. height: 80rpx;
  432. border-radius: 10rpx;
  433. border: 1rpx solid #ccc;
  434. input {
  435. padding: 0 24rpx;
  436. width: 90%;
  437. height: 100%;
  438. font-size: 28rpx;
  439. }
  440. }
  441. .scope {
  442. display: flex;
  443. align-items: center;
  444. margin-top: 32rpx;
  445. width: 570rpx;
  446. height: 80rpx;
  447. border-radius: 10rpx;
  448. border: 1rpx solid #ccc;
  449. .notes {
  450. padding-left: 24rpx;
  451. flex: 5;
  452. font-size: 28rpx;
  453. color: #808080;
  454. }
  455. .notes2 {
  456. padding-left: 24rpx;
  457. flex: 5;
  458. font-size: 28rpx;
  459. overflow: hidden;
  460. white-space: nowrap;
  461. text-overflow: ellipsis;
  462. }
  463. .icon {
  464. flex: 1;
  465. display: flex;
  466. justify-content: center;
  467. align-items: center;
  468. img {
  469. width: 25rpx;
  470. height: 20rpx;
  471. }
  472. }
  473. }
  474. .num {
  475. display: flex;
  476. align-items: center;
  477. margin-top: 32rpx;
  478. width: 570rpx;
  479. height: 80rpx;
  480. border-radius: 10rpx;
  481. border: 1rpx solid #ccc;
  482. .count {
  483. flex: 2;
  484. display: flex;
  485. align-items: center;
  486. height: 50rpx;
  487. border-right: 1rpx solid #a6a6a6;
  488. .icon {
  489. flex: 1;
  490. display: flex;
  491. justify-content: center;
  492. align-items: center;
  493. img {
  494. width: 30rpx;
  495. height: 30rpx;
  496. }
  497. }
  498. .info {
  499. flex: 2;
  500. font-size: 28rpx;
  501. }
  502. }
  503. .input {
  504. flex: 4;
  505. input {
  506. padding: 0 45rpx;
  507. width: 80%;
  508. font-size: 28rpx;
  509. }
  510. }
  511. }
  512. }
  513. .foot {
  514. display: flex;
  515. justify-content: space-evenly;
  516. width: 630rpx;
  517. height: 99rpx;
  518. line-height: 99rpx;
  519. font-size: 28rpx;
  520. .left {
  521. flex: 1;
  522. text-align: center;
  523. border-right: 1rpx solid #ccc;
  524. }
  525. .right {
  526. flex: 1;
  527. text-align: center;
  528. color: #2a82e4;
  529. }
  530. }
  531. }
  532. }
  533. // 解决输入框不居中问题
  534. ::v-deep .uni-searchbar {
  535. padding: 10rpx;
  536. }
  537. // 解决左滑区域突出问题
  538. ::v-deep .uni-swipe_button-group {
  539. margin-bottom: 20rpx;
  540. }
  541. // 清除树状组件下边框
  542. ::v-deep .uni-collapse-item__wrap-content.uni-collapse-item--border {
  543. border-bottom: none;
  544. }
  545. </style>