You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

290 line
7.4 KiB

  1. <template>
  2. <view class="tree-item">
  3. <!-- 全局根元素时隐藏 -->
  4. <view v-if="root.id !== '0'" @click="selfClick" class="tree-item-self">
  5. <!-- 已确认子列表为空则显示横杠图标;加载中则显示 loading 图标;否则显示展开/收起图标 -->
  6. <l-icon v-if="isEmpty" type="move" class="tree-item-icon" />
  7. <l-icon
  8. v-else-if="root.type !== 'user' && !isLoading"
  9. :type="isOpen ? 'unfold' : 'right'"
  10. class="tree-item-icon"
  11. />
  12. <view v-else-if="root.type !== 'user' && isLoading" class="loading-fix cu-load loading tree-item-icon"></view>
  13. <!-- 是职员,则显示头像 -->
  14. <image
  15. v-else
  16. class="tree-item-avatar"
  17. :src="avatar"
  18. :style="{ borderRadius: roundAvatar ? '50%' : '3px' }"
  19. mode="aspectFill"
  20. ></image>
  21. <!-- 名称 -->
  22. <!-- <text class="tree-item-title">{{ name }}</text> -->
  23. <text class="tree-item-title">{{ name + (mobile ? '(' +mobile + ')' : "") }}</text>
  24. <!-- 非用户,显示后置标题 -->
  25. <l-tag v-if="root.type !== 'user' || staffTag" :line="tagColor" size="sm" class="margin-left-sm">
  26. {{ tagName }}
  27. </l-tag>
  28. <uni-view v-if="root.type === 'user' && mobile" class="margin-left-sm sm line-gray cu-tag" style="z-index: 1;" @tap="copy(mobile)">复制</uni-view>
  29. <!-- 开启按钮显示且级别对应,则显示按钮 -->
  30. <view v-if="button && root.type === level" class="tree-item-action">
  31. <l-button v-if="!selectIds.includes(root.id)" @click="itemClick(root)" line="green" size="sm">选择</l-button>
  32. <l-button v-else @click="itemClick(root)" line="blue" size="sm">取消选择</l-button>
  33. </view>
  34. </view>
  35. <!-- 子节点列表;非用户节点且已加载完毕时显示 -->
  36. <view
  37. v-if="root.type !== 'user' && isLoadOk"
  38. v-show="isOpen"
  39. :style="{ paddingLeft: root.id === '0' ? '0' : '25rpx' }"
  40. class="tree-item-children"
  41. >
  42. <l-organize-tree
  43. v-for="child of children"
  44. @userClick="$emit('userClick', $event)"
  45. @buttonClick="$emit('buttonClick', $event)"
  46. :key="child.id"
  47. :open="root.id === '0'"
  48. :root="child"
  49. :button="button"
  50. :level="level"
  51. :value="value"
  52. />
  53. </view>
  54. </view>
  55. </template>
  56. <script>
  57. import uniCopy from "@/common/js/uni-copy.js"
  58. export default {
  59. name: 'l-organize-tree',
  60. props: {
  61. root: { default: () => ({ type: 'company', id: '0' }) },
  62. level: { default: 'user' },
  63. button: {},
  64. open: { default: true },
  65. value:{},
  66. },
  67. data() {
  68. return {
  69. isOpen: this.open,
  70. isLoading: false,
  71. isLoadOk: false,
  72. isEmpty: false,
  73. children: [],
  74. selectIds:[]
  75. }
  76. },
  77. async created() {
  78. await this.init()
  79. },
  80. methods: {
  81. // 组件被创建
  82. async init() {
  83. if(this.value){
  84. this.selectIds = this.value.split(",")
  85. }
  86. // 如果自己是根节点,则创建时直接加载子节点
  87. if (this.open) {
  88. await this.loadChildren()
  89. }
  90. },
  91. // 自身被点击,如果不是用户节点则收起/展开 (如果没有加载子节点则还需加载),否则触发点击用户的事件
  92. selfClick() {
  93. if (this.isLoading) {
  94. return
  95. }
  96. if (this.root.type === 'user') {
  97. this.$emit('userClick', this.root)
  98. return
  99. }
  100. if (this.isLoadOk) {
  101. this.isOpen = !this.isOpen
  102. return
  103. }
  104. this.loadChildren()
  105. },
  106. itemClick(root){
  107. if(this.selectIds.indexOf(root.id) !== -1){
  108. this.selectIds.splice(this.selectIds.indexOf(root.id),1)
  109. }else{
  110. this.selectIds.push(root.id)
  111. }
  112. this.$emit('buttonClick', root)
  113. },
  114. // 加载子节点
  115. async loadChildren() {
  116. this.isLoading = true
  117. let children = []
  118. // 只有公司/根节点能加载子公司
  119. if (this.root.type === 'company') {
  120. children = children.concat(
  121. Object.entries(this.GET_GLOBAL('company'))
  122. .filter(([id, item]) => item.parentId === this.root.id)
  123. .map(([id, item]) => ({ ...item, id, type: 'company' }))
  124. )
  125. }
  126. // 加载子部门
  127. if (this.level === 'department' || this.level === 'user') {
  128. console.log(this.level,'level')
  129. if(this.root.type == 'company'){
  130. children = children.concat(
  131. Object.entries(this.GET_GLOBAL('department'))
  132. .filter(([id, item]) => item.companyId === this.root.id && (Number(item.parentId) == -1||Number(item.parentId) == 0))
  133. .map(([id, item]) => ({ ...item, id, type: 'department' }))
  134. )
  135. }
  136. else{
  137. children = children.concat(
  138. Object.entries(this.GET_GLOBAL('department'))
  139. .filter(([id, item]) => item.companyId === this.root.companyId && (item.parentId == this.root.id ))
  140. .map(([id, item]) => ({ ...item, id, type: 'department' }))
  141. )
  142. }
  143. }
  144. // 加载子职员
  145. if (this.level === 'user') {
  146. children = children.concat(
  147. Object.entries(this.GET_GLOBAL('user'))
  148. .filter(
  149. ([id, item]) =>
  150. this.root.id ===
  151. (item.departmentId && Number(item.departmentId) !== 0 ? item.departmentId : item.companyId)
  152. )
  153. .map(([id, item]) => ({ ...item, id, type: 'user' }))
  154. )
  155. }
  156. this.children = children
  157. this.isLoadOk = true
  158. this.isOpen = true
  159. this.isLoading = false
  160. },
  161. copy(mobile){
  162. uniCopy({
  163. content:mobile,
  164. success:(res)=>{
  165. uni.showToast({
  166. title: "复制手机号成功~",
  167. icon: 'none',
  168. duration:3000,
  169. })
  170. },
  171. error:(e)=>{
  172. uni.showToast({
  173. title: e,
  174. icon: 'none',
  175. duration:3000,
  176. })
  177. }
  178. })
  179. }
  180. },
  181. computed: {
  182. // 获取用户头像
  183. avatar() {
  184. if (!Number.isNaN(this.root.img)) {
  185. return Number(this.root.img) === 1 ? '/static/img-avatar/chat-boy.jpg' : '/static/img-avatar/chat-girl.jpg'
  186. }
  187. return this.root.img
  188. },
  189. // 是否在职员一级显示标签
  190. staffTag() {
  191. return this.CONFIG('pageConfig.contact.staffTag')
  192. },
  193. // 获取树形列表每一项后面 tag 的显示
  194. tagName() {
  195. return { user: '职员', department: '部门', company: '公司' }[this.root.type]
  196. },
  197. // 获取 tag 的颜色
  198. tagColor() {
  199. return { company: 'red', department: 'blue', user: 'green' }[this.root.type]
  200. },
  201. // 节点名称
  202. name() {
  203. if (this.root.name) {
  204. return this.root.name
  205. }
  206. const rootItem = this.GET_GLOBAL(this.root.type)[this.root.id]
  207. return rootItem ? rootItem.name : '(根节点)'
  208. },
  209. mobile() {
  210. if (this.root.mobile) {
  211. return this.root.mobile
  212. }
  213. const rootItem = this.GET_GLOBAL(this.root.type)[this.root.id]
  214. return rootItem ? rootItem.mobile: '(根节点)'
  215. },
  216. // 头像圆形/方形显示参数
  217. roundAvatar() {
  218. return this.CONFIG('pageConfig.roundAvatar')
  219. }
  220. }
  221. }
  222. </script>
  223. <style lang="less" scoped>
  224. :host {
  225. display: block;
  226. }
  227. .tree-item {
  228. background-color: #fff;
  229. .tree-item-self {
  230. display: flex;
  231. min-height: 65rpx;
  232. align-items: center;
  233. .tree-item-icon {
  234. margin: 0 30rpx;
  235. line-height: 1em;
  236. }
  237. .tree-item-avatar {
  238. width: 60rpx;
  239. height: 60rpx;
  240. margin-top: 8rpx;
  241. margin-bottom: 8rpx;
  242. margin-left: 30rpx;
  243. margin-right: 16rpx;
  244. }
  245. .tree-item-action {
  246. position: absolute;
  247. right: 30rpx;
  248. }
  249. }
  250. }
  251. </style>