audit-model-tree.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <template>
  2. <a-card
  3. :class="[
  4. $style.treewrap,
  5. $style.ywlxtree,
  6. { [$style.collapse]: false, [$style.single]: false },
  7. ]"
  8. >
  9. <a-form-model>
  10. <a-form-model-item :label="null" prop="orgValue">
  11. <a-select
  12. v-model="allTreeDataKeys"
  13. show-search
  14. :filter-option="filterOption"
  15. @change="onSelectName"
  16. >
  17. <a-select-option v-for="item in allTreeData" :key="item.id" :value="item.id">
  18. {{ item.categoryName }}
  19. </a-select-option>
  20. </a-select>
  21. </a-form-model-item>
  22. </a-form-model>
  23. <slot></slot>
  24. <a-empty v-if="empty" />
  25. <a-tree
  26. v-else
  27. ref="tree"
  28. :key="key"
  29. v-model="checkedKeys"
  30. :tree-data="treeData"
  31. :show-line="true"
  32. :replace-fields="replaceFields"
  33. :expanded-keys="expandedKeys"
  34. :default-selected-keys="defaultSelectedKeys"
  35. @select="treeSelect"
  36. @expand="onExpand"
  37. >
  38. </a-tree>
  39. <!-- 设置 -->
  40. </a-card>
  41. </template>
  42. <script>
  43. import components from './_import-components/audit-model-tree-import'
  44. import { generateTree, getTreeIds } from '@product/iam/audit/dataMarket/util'
  45. import auditModelService from './audit-model-service'
  46. export default {
  47. name: 'AuditModelTree',
  48. metaInfo: {
  49. title: 'AuditModelTree',
  50. },
  51. // 树结构数据
  52. components,
  53. data() {
  54. return {
  55. key: 0,
  56. allTreeDataKeys: null,
  57. // 分类加载状态
  58. replaceFields: {
  59. title: 'categoryName',
  60. key: 'id',
  61. children: 'children',
  62. },
  63. empty: true,
  64. expandedKeys: ['0'],
  65. // 原始数据列表
  66. // 树结构
  67. // 搜索数据结构
  68. searchInput: '',
  69. treeData: [],
  70. allTreeData: [],
  71. checkedKeys: [],
  72. defaultSelectedKeys: [],
  73. }
  74. },
  75. created() {
  76. this.initMineTreeData()
  77. },
  78. methods: {
  79. initMineTreeData() {
  80. // 获取分类数据信息
  81. auditModelService.getAuditModelTreeAll().then((res) => {
  82. // 存储搜索所需的数据
  83. this.allTreeData = res.data
  84. // 组装数据
  85. const nodeData = [
  86. {
  87. id: '0',
  88. categoryName: '全部分类',
  89. isLeaf: false,
  90. isroot: true,
  91. children: [],
  92. },
  93. ]
  94. if (res.data.length) {
  95. nodeData[0].children = res.data
  96. }
  97. // 根据props下的isEnd越大层级越深 0为最上级节点
  98. // props下的parentId代表父节点id
  99. // 根据上述数据生成多层嵌套的树形结构,该树形结构有多个根节点
  100. const generateTree = (data) => {
  101. const tree = []
  102. const temp = {}
  103. for (let i = 0; i < data.length; i++) {
  104. temp[data[i].id] = data[i]
  105. }
  106. for (let i = 0; i < data.length; i++) {
  107. if (temp[data[i].parentId] && data[i].id !== data[i].parentId) {
  108. if (!temp[data[i].parentId].children) {
  109. temp[data[i].parentId].children = []
  110. }
  111. temp[data[i].parentId].children.push(data[i])
  112. } else {
  113. tree.push(data[i])
  114. }
  115. }
  116. return tree
  117. }
  118. nodeData[0].children = generateTree(res.data)
  119. this.treeData = [...nodeData]
  120. this.key += 1
  121. this.empty = false
  122. this.spinning = false
  123. })
  124. },
  125. //
  126. refreshNode() {
  127. this.initMineTreeData()
  128. this.key += 1
  129. },
  130. // 点击选中
  131. // 点击取消
  132. treeSelect(selectedKeys, info) {
  133. if (selectedKeys.length === 0) {
  134. this.allTreeDataKeys = null
  135. }
  136. this.$emit('treeSelect', selectedKeys, info)
  137. },
  138. onExpand(expandedKeys) {
  139. this.expandedKeys = expandedKeys
  140. },
  141. filterOption(input, option) {
  142. return option.componentOptions.children[0].text.indexOf(input) >= 0
  143. },
  144. // 搜索数据
  145. onSelectName(val) {
  146. this.defaultSelectedKeys = [val]
  147. this.key++
  148. const onInfo = this.allTreeData.find((item) => item.id === val)
  149. // 根据当前节点id寻找所有上级节点id
  150. let parentId = onInfo.parentId
  151. while (parentId !== '0') {
  152. this.expandedKeys.push(parentId)
  153. const parentInfo = this.allTreeData.find((item) => item.id === parentId)
  154. parentId = parentInfo?.parentId || '0'
  155. }
  156. const onSelected = []
  157. onSelected.push({
  158. data: {
  159. props: {
  160. id: onInfo.id,
  161. text: onInfo.text,
  162. edit: true,
  163. props: {
  164. ...onInfo.props,
  165. },
  166. },
  167. },
  168. })
  169. // }
  170. this.$emit('treeSelect', [val], {
  171. selectedNodes: onSelected,
  172. node: {
  173. dataRef: {
  174. id: onInfo.id,
  175. text: onInfo.text,
  176. props: {
  177. isroot: false,
  178. },
  179. },
  180. },
  181. })
  182. },
  183. },
  184. }
  185. </script>
  186. <style module lang="scss">
  187. @use '@/common/design' as *;
  188. .spin {
  189. width: 100%;
  190. line-height: 30;
  191. }
  192. .ywlxtree {
  193. :global(.ant-tree-title) {
  194. display: inline-block;
  195. width: 100%;
  196. overflow: hidden;
  197. text-overflow: ellipsis;
  198. white-space: nowrap;
  199. }
  200. :global(.ant-input-search) {
  201. margin: 8px 0;
  202. overflow: hidden;
  203. }
  204. .active {
  205. color: $primary-color;
  206. }
  207. :global(.ant-select) {
  208. width: 100%;
  209. overflow: hidden;
  210. }
  211. }
  212. .treewrap {
  213. position: relative;
  214. display: flex;
  215. flex-direction: column;
  216. width: 20%;
  217. min-height: 100%;
  218. margin-right: $padding-lg;
  219. transition: width 0.2s;
  220. .fold {
  221. position: absolute;
  222. top: calc(50% - 30px);
  223. right: -15px;
  224. z-index: 2;
  225. width: 15px;
  226. height: 75px;
  227. padding: 0;
  228. border-radius: 0 10px 10px 0;
  229. }
  230. :global(.ant-tree) {
  231. overflow: hidden;
  232. text-overflow: ellipsis;
  233. white-space: nowrap;
  234. }
  235. :global(.ant-card-body) {
  236. background: $white;
  237. }
  238. }
  239. .collapse {
  240. width: 0;
  241. :global(.ant-card-body) {
  242. background: transparent;
  243. :global(.ant-empty) {
  244. display: none;
  245. }
  246. }
  247. }
  248. // 单选样式
  249. .single {
  250. :global .ant-tree-checkbox {
  251. .ant-tree-checkbox-inner {
  252. border-radius: 100px;
  253. &::after {
  254. position: absolute;
  255. top: 3px;
  256. left: 3px;
  257. display: table;
  258. width: 8px;
  259. height: 8px;
  260. content: ' ';
  261. background-color: $primary-color;
  262. border: 0;
  263. border-radius: 8px;
  264. opacity: 0;
  265. transition: all 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
  266. transform: scale(0);
  267. }
  268. }
  269. &.ant-tree-checkbox-checked {
  270. &::after {
  271. position: absolute;
  272. top: 16.67%;
  273. left: 0;
  274. width: 100%;
  275. height: 66.67%;
  276. content: '';
  277. border: 1px solid #1890ff;
  278. border-radius: 50%;
  279. animation: antRadioEffect 0.36s ease-in-out;
  280. animation-fill-mode: both;
  281. }
  282. .ant-tree-checkbox-inner {
  283. background-color: $white;
  284. &::after {
  285. opacity: 1;
  286. transition: all 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
  287. transform: scale(1);
  288. }
  289. }
  290. }
  291. }
  292. }
  293. </style>