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.
 
 
 
 
 
 

242 lines
6.2 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. <!-- 非用户,显示后置标题 -->
  24. <l-tag v-if="root.type !== 'user' || staffTag" :line="tagColor" size="sm" class="margin-left-sm">
  25. {{ tagName }}
  26. </l-tag>
  27. <!-- 开启按钮显示且级别对应,则显示按钮 -->
  28. <view v-if="button && root.type === level" class="tree-item-action">
  29. <l-button @click="$emit('buttonClick', root)" line="green" size="sm">选择</l-button>
  30. </view>
  31. </view>
  32. <!-- 子节点列表;非用户节点且已加载完毕时显示 -->
  33. <view
  34. v-if="root.type !== 'user' && isLoadOk"
  35. v-show="isOpen"
  36. :style="{ paddingLeft: root.id === '0' ? '0' : '25rpx' }"
  37. class="tree-item-children"
  38. >
  39. <l-organize-tree
  40. v-for="child of children"
  41. @userClick="$emit('userClick', $event)"
  42. @buttonClick="$emit('buttonClick', $event)"
  43. :key="child.id"
  44. :open="root.id === '0'"
  45. :root="child"
  46. :button="button"
  47. :level="level"
  48. />
  49. </view>
  50. </view>
  51. </template>
  52. <script>
  53. export default {
  54. name: 'l-organize-tree',
  55. props: {
  56. root: { default: () => ({ type: 'company', id: '0' }) },
  57. level: { default: 'user' },
  58. button: {},
  59. open: { default: true }
  60. },
  61. data() {
  62. return {
  63. isOpen: this.open,
  64. isLoading: false,
  65. isLoadOk: false,
  66. isEmpty: false,
  67. children: []
  68. }
  69. },
  70. async created() {
  71. await this.init()
  72. },
  73. methods: {
  74. // 组件被创建
  75. async init() {
  76. // 如果自己是根节点,则创建时直接加载子节点
  77. if (this.open) {
  78. await this.loadChildren()
  79. }
  80. },
  81. // 自身被点击,如果不是用户节点则收起/展开 (如果没有加载子节点则还需加载),否则触发点击用户的事件
  82. selfClick() {
  83. if (this.isLoading) {
  84. return
  85. }
  86. if (this.root.type === 'user') {
  87. this.$emit('userClick', this.root)
  88. return
  89. }
  90. if (this.isLoadOk) {
  91. this.isOpen = !this.isOpen
  92. return
  93. }
  94. this.loadChildren()
  95. },
  96. // 加载子节点
  97. async loadChildren() {
  98. this.isLoading = true
  99. let children = []
  100. // 只有公司/根节点能加载子公司
  101. if (this.root.type === 'company') {
  102. children = children.concat(
  103. Object.entries(this.GET_GLOBAL('company'))
  104. .filter(([id, item]) => item.parentId === this.root.id)
  105. .map(([id, item]) => ({ ...item, id, type: 'company' }))
  106. )
  107. }
  108. // 加载子部门
  109. if (this.level === 'department' || this.level === 'user') {
  110. console.log(this.level,'level')
  111. if(this.root.type == 'company'){
  112. children = children.concat(
  113. Object.entries(this.GET_GLOBAL('department'))
  114. .filter(([id, item]) => item.companyId === this.root.id && (Number(item.parentId) == -1||Number(item.parentId) == 0))
  115. .map(([id, item]) => ({ ...item, id, type: 'department' }))
  116. )
  117. }
  118. else{
  119. children = children.concat(
  120. Object.entries(this.GET_GLOBAL('department'))
  121. .filter(([id, item]) => item.companyId === this.root.companyId && (item.parentId == this.root.id ))
  122. .map(([id, item]) => ({ ...item, id, type: 'department' }))
  123. )
  124. }
  125. }
  126. // 加载子职员
  127. if (this.level === 'user') {
  128. children = children.concat(
  129. Object.entries(this.GET_GLOBAL('user'))
  130. .filter(
  131. ([id, item]) =>
  132. this.root.id ===
  133. (item.departmentId && Number(item.departmentId) !== 0 ? item.departmentId : item.companyId)
  134. )
  135. .map(([id, item]) => ({ ...item, id, type: 'user' }))
  136. )
  137. }
  138. this.children = children
  139. this.isLoadOk = true
  140. this.isOpen = true
  141. this.isLoading = false
  142. }
  143. },
  144. computed: {
  145. // 获取用户头像
  146. avatar() {
  147. if (!Number.isNaN(this.root.img)) {
  148. return Number(this.root.img) === 1 ? '/static/img-avatar/chat-boy.jpg' : '/static/img-avatar/chat-girl.jpg'
  149. }
  150. return this.root.img
  151. },
  152. // 是否在职员一级显示标签
  153. staffTag() {
  154. return this.CONFIG('pageConfig.contact.staffTag')
  155. },
  156. // 获取树形列表每一项后面 tag 的显示
  157. tagName() {
  158. return { user: '职员', department: '部门', company: '公司' }[this.root.type]
  159. },
  160. // 获取 tag 的颜色
  161. tagColor() {
  162. return { company: 'red', department: 'blue', user: 'green' }[this.root.type]
  163. },
  164. // 节点名称
  165. name() {
  166. if (this.root.name) {
  167. return this.root.name
  168. }
  169. const rootItem = this.GET_GLOBAL(this.root.type)[this.root.id]
  170. return rootItem ? rootItem.name : '(根节点)'
  171. },
  172. // 头像圆形/方形显示参数
  173. roundAvatar() {
  174. return this.CONFIG('pageConfig.roundAvatar')
  175. }
  176. }
  177. }
  178. </script>
  179. <style lang="less" scoped>
  180. :host {
  181. display: block;
  182. }
  183. .tree-item {
  184. background-color: #fff;
  185. .tree-item-self {
  186. display: flex;
  187. min-height: 65rpx;
  188. align-items: center;
  189. .tree-item-icon {
  190. margin: 0 30rpx;
  191. line-height: 1em;
  192. }
  193. .tree-item-avatar {
  194. width: 60rpx;
  195. height: 60rpx;
  196. margin-top: 8rpx;
  197. margin-bottom: 8rpx;
  198. margin-left: 30rpx;
  199. margin-right: 16rpx;
  200. }
  201. .tree-item-action {
  202. position: absolute;
  203. right: 30rpx;
  204. }
  205. }
  206. }
  207. </style>