Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

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