index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. <template>
  2. <u-popup class="jnpf-tree-select-popup" :maskCloseAble="maskCloseAble" mode="right" v-model="showPopup"
  3. :safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :z-index="uZIndex" width="100%">
  4. <view class="jnpf-tree-select-body">
  5. <view class="jnpf-tree-select-title">
  6. <text class="icon-ym icon-ym-report-icon-preview-pagePre u-font-40 backIcon" @tap="close"></text>
  7. <view class="title">选择用户</view>
  8. </view>
  9. <view class="jnpf-tree-select-search">
  10. <u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
  11. :show-action="false" @change="search(swiperCurrent)" bg-color="#f0f2f6" shape="square">
  12. </u-search>
  13. </view>
  14. <view class="jnpf-tree-selected">
  15. <view class="jnpf-tree-selected-head">
  16. <view>{{$t('component.jnpf.common.selected')}}</view>
  17. <view v-if="multiple" class="clear-btn" @click="cleanAll">
  18. {{$t('component.jnpf.common.clearAll')}}
  19. </view>
  20. </view>
  21. <view class="jnpf-tree-selected-box">
  22. <scroll-view scroll-y="true" style="max-height: 240rpx;">
  23. <view class="jnpf-tree-selected-list">
  24. <view class="u-selectTag" v-for="(list,index) in selectList" :key="index">
  25. <u-avatar class="avatar" :src="baseURL+list.headIcon" mode="circle"
  26. size="mini"></u-avatar>
  27. <view class="jnpf-tree-selected-content">
  28. <view class="name-box">
  29. <view class="name">{{list.fullName}}</view>
  30. <u-icon name="close" class="close" @click='delSelect(index)'></u-icon>
  31. </view>
  32. <view class="organize">{{list.organize}}</view>
  33. </view>
  34. </view>
  35. </view>
  36. </scroll-view>
  37. </view>
  38. </view>
  39. <view class="listTitle" v-if="selectType !== 'all'">全部数据</view>
  40. <view class="jnpf-user-content" v-if="selectType === 'all'">
  41. <!-- #ifdef MP-WEIXIN -->
  42. <u-tabs-swiper activeColor="#1890ff" ref="tabs" :list="tabsList" :current="current" @change="change"
  43. :is-scroll="false" :show-bar="false"></u-tabs-swiper>
  44. <!-- #endif -->
  45. <!-- #ifndef MP-WEIXIN -->
  46. <u-tabs-swiper activeColor="#1890ff" ref="tabs" :list="tabsList" :current="current" @change="change"
  47. :is-scroll="false"></u-tabs-swiper>
  48. <!-- #endif -->
  49. <swiper :current="swiperCurrent" @transition="transition" @animationfinish="animationfinish"
  50. class="swiper-box">
  51. <swiper-item>
  52. <scroll-view :scroll-y="true" class="scroll-view">
  53. <ly-tree ref="tree" :node-key="realProps.value" :expand-on-click-node="true"
  54. :tree-data="options0" check-on-click-node :show-checkbox="false"
  55. :default-expand-all="false" :highlight-current="true" @node-click="handleNodeClick"
  56. :props="realProps" :show-node-icon="true" :show-radio="false" :load="loadNode" lazy />
  57. </scroll-view>
  58. </swiper-item>
  59. <swiper-item>
  60. <scroll-view :scroll-y="true" class="scroll-view">
  61. <ly-tree ref="tree" :node-key="realProps.value" :expand-on-click-node="true"
  62. check-on-click-node :show-checkbox="false" :default-expand-all="false"
  63. :highlight-current="true" @node-click="handleNodeClick" :props="realProps"
  64. :show-node-icon="true" :show-radio="false" :tree-data="options" />
  65. </scroll-view>
  66. </swiper-item>
  67. <swiper-item>
  68. <scroll-view :scroll-y="true" class="scroll-view">
  69. <ly-tree ref="tree" :node-key="realProps.value" :expand-on-click-node="true"
  70. check-on-click-node :show-checkbox="false" :default-expand-all="false"
  71. :highlight-current="true" @node-click="handleNodeClick" :props="realProps"
  72. :show-node-icon="true" :show-radio="false" :tree-data="options" />
  73. </scroll-view>
  74. </swiper-item>
  75. </swiper>
  76. </view>
  77. <view v-else class="jnpf-tree-select-tree">
  78. <scroll-view class="scroll-view" :refresher-enabled="false" :refresher-threshold="100"
  79. :scroll-with-animation='true' :refresher-triggered="triggered" @scrolltolower="handleScrollToLower"
  80. :scroll-y="true">
  81. <view class="lists_box">
  82. <view class="list-cell-txt u-border-bottom" v-for="(list,index) in list" :key="index"
  83. @click="onSelect(list)">
  84. <u-avatar class="avatar" :src="baseURL+list.headIcon" mode="circle"
  85. size="default"></u-avatar>
  86. <view class="u-font-30 content">
  87. <view>{{list.fullName}}</view>
  88. <view class="organize">{{list.organize}}</view>
  89. </view>
  90. </view>
  91. <view v-if="list.length<1" class="nodata u-flex-col">
  92. <image :src="noDataIcon" mode="widthFix" class="noDataIcon"></image>
  93. {{$t('common.noData')}}
  94. </view>
  95. </view>
  96. </scroll-view>
  97. </view>
  98. <!-- 底部按钮 -->
  99. <view class="jnpf-tree-select-actions">
  100. <u-button class="buttom-btn" @click="close()">{{$t('common.cancelText')}}</u-button>
  101. <u-button class="buttom-btn" type="primary"
  102. @click.stop="handleConfirm">{{$t('common.okText')}}</u-button>
  103. </view>
  104. </view>
  105. </u-popup>
  106. </template>
  107. <script>
  108. /**
  109. * tree-select 树形选择器
  110. * @property {Boolean} v-model 布尔值变量,用于控制选择器的弹出与收起
  111. * @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
  112. * @property {String} cancel-color 取消按钮的颜色(默认#606266)
  113. * @property {String} confirm-color 确认按钮的颜色(默认#2979ff)
  114. * @property {String} confirm-text 确认按钮的文字
  115. * @property {String} cancel-text 取消按钮的文字
  116. * @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭Picker(默认true)
  117. * @property {String Number} z-index 弹出时的z-index值(默认10075)
  118. * @event {Function} confirm 点击确定按钮,返回当前选择的值
  119. */
  120. const defaultProps = {
  121. label: 'fullName',
  122. value: 'id',
  123. icon: 'icon',
  124. children: 'children'
  125. }
  126. import {
  127. getUserSelectorNew,
  128. getSubordinates,
  129. getOrganization,
  130. } from '@/api/common.js'
  131. import {
  132. getTaskUserList
  133. } from '@/api/workFlow/flowBefore'
  134. import resources from '@/libs/resources.js'
  135. import LyTree from '@/components/ly-tree/ly-tree.vue'
  136. export default {
  137. name: "comment-tree-select",
  138. components: {
  139. LyTree
  140. },
  141. props: {
  142. taskId: {
  143. type: String,
  144. default: ''
  145. },
  146. selectType: {
  147. type: String,
  148. default: 'all'
  149. },
  150. clearable: {
  151. type: Boolean,
  152. default: false
  153. },
  154. query: {
  155. type: Object,
  156. default: () => ({})
  157. },
  158. selectedData: {
  159. type: Array,
  160. default () {
  161. return [];
  162. }
  163. },
  164. // 是否显示边框
  165. border: {
  166. type: Boolean,
  167. default: true
  168. },
  169. // 通过双向绑定控制组件的弹出与收起
  170. modelValue: {
  171. type: Boolean,
  172. default: false
  173. },
  174. // "取消"按钮的颜色
  175. cancelColor: {
  176. type: String,
  177. default: '#606266'
  178. },
  179. // "确定"按钮的颜色
  180. confirmColor: {
  181. type: String,
  182. default: '#2979ff'
  183. },
  184. // 弹出的z-index值
  185. zIndex: {
  186. type: [String, Number],
  187. default: 999
  188. },
  189. safeAreaInsetBottom: {
  190. type: Boolean,
  191. default: false
  192. },
  193. // 是否允许通过点击遮罩关闭Picker
  194. maskCloseAble: {
  195. type: Boolean,
  196. default: true
  197. },
  198. props: {
  199. type: Object,
  200. default: () => ({
  201. label: 'fullName',
  202. value: 'id',
  203. icon: 'icon',
  204. children: 'children',
  205. isLeaf: 'isLeaf'
  206. })
  207. },
  208. //多选
  209. multiple: {
  210. type: Boolean,
  211. default: false
  212. },
  213. // 顶部标题
  214. title: {
  215. type: String,
  216. default: ''
  217. },
  218. // 取消按钮的文字
  219. cancelText: {
  220. type: String,
  221. default: '取消'
  222. },
  223. // 确认按钮的文字
  224. confirmText: {
  225. type: String,
  226. default: '确认'
  227. }
  228. },
  229. data() {
  230. return {
  231. noDataIcon: resources.message.nodata,
  232. triggered: false,
  233. moving: false,
  234. selectList: [],
  235. keyword: '',
  236. tabsList: [{
  237. name: '全部数据'
  238. },
  239. {
  240. name: '当前组织'
  241. },
  242. {
  243. name: '我的下属'
  244. }
  245. ],
  246. current: 0,
  247. swiperCurrent: 0,
  248. options: [],
  249. options0: [],
  250. list: [],
  251. pagination: {
  252. currentPage: 1,
  253. pageSize: 20
  254. },
  255. total: 0,
  256. height: 0,
  257. showPopup: false
  258. };
  259. },
  260. watch: {
  261. // 在select弹起的时候,重新初始化所有数据
  262. modelValue: {
  263. immediate: true,
  264. handler(val) {
  265. this.showPopup = val
  266. if (val) setTimeout(() => this.getInfoList(), 10);
  267. }
  268. },
  269. },
  270. computed: {
  271. baseURL() {
  272. return this.define.baseURL
  273. },
  274. uZIndex() {
  275. // 如果用户有传递z-index值,优先使用
  276. return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
  277. },
  278. realProps() {
  279. return {
  280. ...defaultProps,
  281. ...this.props
  282. }
  283. }
  284. },
  285. created() {
  286. this._freshing = false;
  287. setTimeout(() => {
  288. this.triggered = true;
  289. }, 1000)
  290. },
  291. methods: {
  292. handleScrollToLower() {
  293. this.getInfoList()
  294. },
  295. getInfoList() {
  296. this.pagination.keyword = this.keyword
  297. getTaskUserList(this.taskId, this.pagination).then(res => {
  298. const list = res.data.list;
  299. if (!list.length && this.pagination.currentPage != 1) return uni.showToast({
  300. title: '没有更多信息啦!',
  301. icon: 'none'
  302. });
  303. this.list = this.list.concat(list);
  304. this.pagination.currentPage++
  305. })
  306. },
  307. onSelect(list) {
  308. if (!this.multiple) this.selectList = []
  309. let flag = false;
  310. for (let i = 0; i < this.selectList.length; i++) {
  311. if (this.selectList[i].id === list.id) {
  312. flag = true;
  313. return
  314. }
  315. };
  316. !flag && this.selectList.push(list)
  317. },
  318. loadNode(node, resolve) {
  319. if (node.level === 0) {
  320. getUserSelectorNew(node.level).then(res => {
  321. resolve(res.data.list)
  322. })
  323. } else {
  324. getUserSelectorNew(node.data.id).then(res => {
  325. const data = res.data.list
  326. resolve(data)
  327. })
  328. }
  329. },
  330. change(index) {
  331. this.swiperCurrent = index;
  332. this.keyword = ''
  333. if (this.swiperCurrent !== 0) this.handOff(this.swiperCurrent)
  334. },
  335. handOff(swiperCurrent) {
  336. let method = swiperCurrent == 1 ? getOrganization : getSubordinates;
  337. method(this.keyword).then(res => {
  338. this.options = res.data
  339. })
  340. },
  341. search(index) {
  342. this.searchTimer && clearTimeout(this.searchTimer)
  343. this.searchTimer = setTimeout(() => {
  344. this.pagination = {
  345. currentPage: 1,
  346. pageSize: 20
  347. }
  348. if (this.selectType === 'all') {
  349. if (index !== 0) this.handOff(index)
  350. getUserSelectorNew(0, this.keyword).then(res => {
  351. this.options0 = res.data.list
  352. })
  353. } else {
  354. this.pagination.keyword = this.keyword
  355. getTaskUserList(this.taskId, this.pagination).then(res => {
  356. const list = res.data.list;
  357. this.list = list
  358. this.pagination = res.data.pagination
  359. this.total = this.pagination.total
  360. })
  361. }
  362. }, 300)
  363. },
  364. transition({
  365. detail: {
  366. dx
  367. }
  368. }) {
  369. this.$refs.tabs.setDx(dx);
  370. },
  371. animationfinish({
  372. detail: {
  373. current
  374. }
  375. }) {
  376. this.$refs.tabs.setFinishCurrent(current);
  377. this.swiperCurrent = current;
  378. this.current = current;
  379. if (this.swiperCurrent !== 0) this.handOff(this.swiperCurrent)
  380. },
  381. handleNodeClick(obj) {
  382. if (this.swiperCurrent === 0 && obj.data.type !== 'user') return
  383. if (!this.multiple) this.selectList = []
  384. var isExist = false;
  385. for (var i = 0; i < this.selectList.length; i++) {
  386. if (this.selectList[i].id == obj.data.id) {
  387. isExist = true;
  388. break;
  389. }
  390. };
  391. !isExist && this.selectList.push(obj.data);
  392. },
  393. delSelect(index) {
  394. this.selectList.splice(index, 1);
  395. },
  396. cleanAll() {
  397. this.selectList = [];
  398. },
  399. handleConfirm() {
  400. // #ifdef MP-WEIXIN
  401. if (this.moving) return;
  402. // #endif
  403. this.keyword = '';
  404. this.$emit('confirm', this.selectList);
  405. this.close();
  406. },
  407. // 标识滑动开始,只有微信小程序才有这样的事件
  408. pickstart() {
  409. // #ifdef MP-WEIXIN
  410. this.moving = true;
  411. // #endif
  412. },
  413. // 标识滑动结束
  414. pickend() {
  415. // #ifdef MP-WEIXIN
  416. this.moving = false;
  417. // #endif
  418. },
  419. filterNode(value, data) {
  420. if (!value) return true;
  421. return data[this.realProps.label].indexOf(value) !== -1;
  422. },
  423. close() {
  424. this.$emit('close');
  425. },
  426. resetData() {
  427. this.list = []
  428. this.pagination = {
  429. currentPage: 1,
  430. pageSize: 20
  431. }
  432. }
  433. }
  434. };
  435. </script>
  436. <style scoped lang="scss">
  437. .jnpf-user-content {
  438. flex: 1;
  439. display: flex;
  440. flex-direction: column;
  441. .swiper-box {
  442. flex: 1;
  443. }
  444. }
  445. .listTitle {
  446. padding: 10rpx 30rpx;
  447. font-size: 32rpx;
  448. }
  449. .scroll-view {
  450. height: 100%;
  451. }
  452. .lists_box {
  453. height: 100%;
  454. .nodata {
  455. height: 100%;
  456. margin: auto;
  457. align-items: center;
  458. justify-content: center;
  459. color: #909399;
  460. .noDataIcon {
  461. width: 300rpx;
  462. height: 210rpx;
  463. }
  464. }
  465. .list-cell-txt {
  466. display: flex;
  467. box-sizing: border-box;
  468. width: 100%;
  469. padding: 20rpx 32rpx;
  470. overflow: hidden;
  471. color: $u-content-color;
  472. font-size: 28rpx;
  473. line-height: 24px;
  474. background-color: #fff;
  475. .content {
  476. width: 85%;
  477. margin-left: 15rpx;
  478. .organize {
  479. white-space: nowrap;
  480. overflow: hidden; //超出的文本隐藏
  481. text-overflow: ellipsis
  482. }
  483. }
  484. .department {
  485. color: #9A9A9A;
  486. }
  487. }
  488. }
  489. </style>