Tree.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <template>
  2. <u-popup class="jnpf-tree-select-popup" width="100%" v-model="showPopup" length="auto" mode="right" :popup="false"
  3. :safeAreaInsetBottom="safeAreaInsetBottom" :maskCloseAble="maskCloseAble" :z-index="uZIndex" @close="close">
  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 backIcon" @tap="close"></text>
  7. <view class="title">级联选择</view>
  8. </view>
  9. <view class="jnpf-tree-select-search" v-if="filterable">
  10. <u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="filterText" height="72"
  11. :show-action="false" 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="setCheckAll">
  18. {{$t('component.jnpf.common.clearAll')}}
  19. </view>
  20. </view>
  21. <view class="jnpf-tree-selected-box">
  22. <scroll-view scroll-y="true" class="select-list">
  23. <u-tag closeable @close="delSelect(index)" v-for="(list,index) in selectListText" :key="index"
  24. :text="list" class="u-selectTag" />
  25. </scroll-view>
  26. </view>
  27. </view>
  28. <view class="jnpf-tree-select-tree">
  29. <scroll-view :scroll-y="true" style="height: 100%">
  30. <ly-tree ref="tree" :tree-data="options" check-on-click-node default-expand-all
  31. :node-key="realProps.value" highlight-current :props="realProps" @node-click="handleNodeClick"
  32. :filter-node-method="filterNode" />
  33. </scroll-view>
  34. </view>
  35. <!-- 底部按钮 -->
  36. <view class="jnpf-tree-select-actions">
  37. <u-button class="buttom-btn" @click="close()">{{$t('common.cancelText')}}</u-button>
  38. <u-button class="buttom-btn" type="primary"
  39. @click.stop="handleConfirm">{{$t('common.okText')}}</u-button>
  40. </view>
  41. </view>
  42. </u-popup>
  43. </template>
  44. <script>
  45. /**
  46. * tree-select 树形选择器
  47. * @property {Boolean} v-model 布尔值变量,用于控制选择器的弹出与收起
  48. * @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
  49. * @property {String} cancel-color 取消按钮的颜色(默认#606266)
  50. * @property {String} confirm-color 确认按钮的颜色(默认#2979ff)
  51. * @property {String} confirm-text 确认按钮的文字
  52. * @property {String} cancel-text 取消按钮的文字
  53. * @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭Picker(默认true)
  54. * @property {String Number} z-index 弹出时的z-index值(默认10075)
  55. * @event {Function} confirm 点击确定按钮,返回当前选择的值
  56. */
  57. const defaultProps = {
  58. label: 'fullName',
  59. value: 'id',
  60. icon: 'icon',
  61. children: 'children'
  62. }
  63. import {
  64. getProvinceSelector
  65. } from '@/api/common.js'
  66. let _self;
  67. export default {
  68. name: "tree-select",
  69. props: {
  70. selectList: {
  71. type: Array,
  72. default () {
  73. return [];
  74. }
  75. },
  76. selectedId: {
  77. type: Array,
  78. default () {
  79. return [];
  80. }
  81. },
  82. selectData: {
  83. type: Array,
  84. default () {
  85. return [];
  86. }
  87. },
  88. options: {
  89. type: Array,
  90. default: () => []
  91. },
  92. // 是否显示边框
  93. border: {
  94. type: Boolean,
  95. default: true
  96. },
  97. filterable: {
  98. type: Boolean,
  99. default: false
  100. },
  101. showAllLevels: {
  102. type: Boolean,
  103. default: true
  104. },
  105. clearable: {
  106. type: Boolean,
  107. default: false
  108. },
  109. // 通过双向绑定控制组件的弹出与收起
  110. modelValue: {
  111. type: Boolean,
  112. default: false
  113. },
  114. // "取消"按钮的颜色
  115. cancelColor: {
  116. type: String,
  117. default: '#606266'
  118. },
  119. // "确定"按钮的颜色
  120. confirmColor: {
  121. type: String,
  122. default: '#2979ff'
  123. },
  124. // 弹出的z-index值
  125. zIndex: {
  126. type: [String, Number],
  127. default: 0
  128. },
  129. safeAreaInsetBottom: {
  130. type: Boolean,
  131. default: false
  132. },
  133. // 是否允许通过点击遮罩关闭Picker
  134. maskCloseAble: {
  135. type: Boolean,
  136. default: true
  137. },
  138. props: {
  139. type: Object,
  140. default: () => ({
  141. label: 'fullName',
  142. value: 'id',
  143. icon: 'icon',
  144. children: 'children',
  145. isLeaf: 'isLeaf'
  146. })
  147. },
  148. multiple: {
  149. type: Boolean,
  150. default: false
  151. },
  152. // 顶部标题
  153. title: {
  154. type: String,
  155. default: ''
  156. },
  157. // 取消按钮的文字
  158. cancelText: {
  159. type: String,
  160. default: '取消'
  161. },
  162. // 确认按钮的文字
  163. confirmText: {
  164. type: String,
  165. default: '确认'
  166. },
  167. level: {
  168. type: Number,
  169. default: 0
  170. }
  171. },
  172. data() {
  173. return {
  174. moving: false,
  175. selectListText: [],
  176. selectListId: [],
  177. selectListData: [],
  178. newListId: [],
  179. filterText: '',
  180. showPopup: false
  181. };
  182. },
  183. watch: {
  184. // 在select弹起的时候,重新初始化所有数据
  185. modelValue: {
  186. immediate: true,
  187. handler(val) {
  188. this.showPopup = val
  189. if (val) setTimeout(() => this.init(), 10);
  190. }
  191. },
  192. filterText(val) {
  193. this.$refs.tree.filter(val);
  194. }
  195. },
  196. created() {
  197. _self = this
  198. this.init()
  199. },
  200. computed: {
  201. uZIndex() {
  202. // 如果用户有传递z-index值,优先使用
  203. return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
  204. },
  205. realProps() {
  206. return {
  207. ...defaultProps,
  208. ...this.props
  209. }
  210. }
  211. },
  212. methods: {
  213. init() {
  214. this.selectListText = this.$u.deepClone(this.selectList)
  215. this.selectListId = this.$u.deepClone(this.selectedId)
  216. this.selectListData = this.$u.deepClone(this.selectData)
  217. },
  218. filterNode(value, options) {
  219. if (!value) return true;
  220. return options[this.props.label].indexOf(value) !== -1;
  221. },
  222. handleNodeClick(obj) {
  223. if (!obj.parentId && !obj.isLeaf) return
  224. let allPath = this.$refs.tree.getNodePath(obj)
  225. let list = []
  226. let listId = []
  227. let currentNode = obj.data
  228. if (!this.multiple) {
  229. this.selectListText = [];
  230. this.selectListId = [];
  231. this.selectListData = [];
  232. }
  233. let txt = ''
  234. let ids = ''
  235. for (let i = 0; i < allPath.length; i++) {
  236. listId.push(allPath[i][this.props.value])
  237. ids += (i ? ',' : '') + allPath[i][this.props.value]
  238. txt += (i ? '/' : '') + allPath[i][this.props.label]
  239. }
  240. if (this.showAllLevels) {
  241. this.selectListText.push(txt)
  242. } else {
  243. this.selectListText.push(currentNode[this.props.label])
  244. }
  245. this.selectListText = [...new Set(this.selectListText)]
  246. var isExist = false;
  247. for (var i = 0; i < this.selectListId.length; i++) {
  248. if (this.selectListId[i].join(',') === ids) {
  249. isExist = true;
  250. break;
  251. }
  252. };
  253. !isExist && this.selectListId.push(listId);
  254. this.selectListData = allPath
  255. },
  256. delSelect(index) {
  257. this.selectListText.splice(index, 1);
  258. this.selectListId.splice(index, 1);
  259. this.selectListData.splice(index, 1);
  260. },
  261. setCheckAll() {
  262. this.selectListText = [];
  263. this.selectListId = [];
  264. this.selectListData = [];
  265. this.$refs.tree.setCheckAll(false);
  266. },
  267. handleConfirm() {
  268. this.$emit('confirm', this.selectListText, this.selectListId, this.selectListData);
  269. this.close();
  270. },
  271. close() {
  272. this.$emit('close', false);
  273. }
  274. }
  275. };
  276. </script>