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.

332 lines
7.7 KiB

2 years ago
  1. <template>
  2. <modal :name="`${label}-multiple-level-modal`" width="100%" height="auto" :scrollable="true" :clickToClose="true">
  3. <div class="tw-p-[40px] tw-h-full tw-overflow-auto">
  4. <div class="modal-header tw-flex tw-justify-end tw-items-center tw-mb-[40px] md:tw-mb-[40px]">
  5. <button class="close tw-transition tw-btn-md" @click="$modal.hide(`${label}-multiple-level-modal`)"></button>
  6. </div>
  7. <div class="modal-content">
  8. <div class="tw-p-[30px] tw-border-solid tw-border-neutrals-200 tw-border-[1px] tw-rounded-[16px]">
  9. <h4 class="t16 tw-font-normal tw-mb-[22px]">{{ $t(label) }}</h4>
  10. <a-input-search style="margin-bottom: 22px" :placeholder="$t(placeholder)" @change="onChange" />
  11. <a-tree v-model="checkedKeys" checkable :expanded-keys="expandedKeys" :auto-expand-parent="autoExpandParent"
  12. :tree-data="listData" @expand="onExpand" @select="onSelect">
  13. <template slot="title" slot-scope="{ title }">
  14. <span v-if="title.indexOf(searchValue) > -1">
  15. {{ title.substr(0, title.indexOf(searchValue)) }}
  16. <span style="color: #f50">{{ searchValue }}</span>
  17. {{
  18. title.substr(title.indexOf(searchValue) + searchValue.length)
  19. }}
  20. </span>
  21. <span v-else>{{ title }}</span>
  22. </template>
  23. </a-tree>
  24. </div>
  25. </div>
  26. </div>
  27. </modal>
  28. </template>
  29. <script>
  30. export default {
  31. props: {
  32. label: {
  33. type: String,
  34. },
  35. placeholder: {
  36. type: String,
  37. },
  38. list: {
  39. type: Array,
  40. },
  41. checked: {
  42. type: Array,
  43. },
  44. },
  45. data() {
  46. return {
  47. expandedKeys: [],
  48. checkedKeys: [],
  49. searchValue: "",
  50. autoExpandParent: true,
  51. listData: this.list,
  52. dataList: [],
  53. };
  54. },
  55. watch: {
  56. list: {
  57. handler: function () {
  58. this.listData = JSON.parse(JSON.stringify(this.list));
  59. this.generateList(this.listData);
  60. },
  61. },
  62. checked: {
  63. handler: function () {
  64. this.checkedKeys = this.checked;
  65. },
  66. },
  67. checkedKeys: {
  68. handler: function () {
  69. this.$emit("check", this.checkedKeys);
  70. // console.log("onCheck", this.checkedKeys);
  71. },
  72. },
  73. },
  74. methods: {
  75. onExpand(expandedKeys) {
  76. this.expandedKeys = expandedKeys;
  77. this.autoExpandParent = false;
  78. },
  79. onChange(e) {
  80. const value = e.target.value;
  81. if (value != "") {
  82. const expandedKeys = this.dataList
  83. .map((item) => {
  84. if (item.title.indexOf(value) > -1) {
  85. return this.getParentKey(item.key, this.listData);
  86. }
  87. return null;
  88. })
  89. .filter((item, i, self) => item && self.indexOf(item) === i);
  90. Object.assign(this, {
  91. expandedKeys,
  92. searchValue: value,
  93. autoExpandParent: true,
  94. });
  95. } else {
  96. const expandedKeys = this.dataList;
  97. Object.assign(this, {
  98. expandedKeys,
  99. searchValue: value,
  100. autoExpandParent: false,
  101. });
  102. }
  103. },
  104. onSelect(selectedKeys, info) {
  105. // console.log("onSelect", info);
  106. this.selectedKeys = selectedKeys;
  107. },
  108. generateList(data) {
  109. var vm = this;
  110. for (let i = 0; i < data.length; i++) {
  111. const node = data[i];
  112. const key = node.key;
  113. const title = node.title;
  114. vm.dataList.push({ key: key, title: title });
  115. if (node.children) {
  116. vm.generateList(node.children);
  117. }
  118. }
  119. },
  120. getParentKey(key, tree) {
  121. var vm = this;
  122. let parentKey;
  123. for (let i = 0; i < tree.length; i++) {
  124. const node = tree[i];
  125. if (node.children) {
  126. if (node.children.some((item) => item.key === key)) {
  127. parentKey = node.key;
  128. } else if (vm.getParentKey(key, node.children)) {
  129. parentKey = vm.getParentKey(key, node.children);
  130. }
  131. }
  132. }
  133. return parentKey;
  134. },
  135. },
  136. };
  137. </script>
  138. <style lang="scss" scoped>
  139. :deep() {
  140. .ant-input-search {
  141. &:hover {
  142. >.ant-input {
  143. border-color: #faae69;
  144. }
  145. }
  146. &:focus {
  147. >.ant-input {
  148. border-color: #f48800;
  149. }
  150. }
  151. >.ant-input {
  152. padding: 17px 12px;
  153. border-radius: 12px;
  154. }
  155. }
  156. .ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled) {
  157. border-color: #faae69;
  158. }
  159. .anticon-search.ant-input-search-icon {
  160. color: transparent;
  161. background-image: url("~/assets/svg/search.svg");
  162. background-position: center;
  163. background-repeat: no-repeat;
  164. background-size: 100%;
  165. width: 20px;
  166. height: 20px;
  167. }
  168. .ant-input {
  169. &:hover {
  170. border-color: #faae69;
  171. }
  172. &:focus {
  173. border-color: #f48800;
  174. box-shadow: 0 0 0 2px rgba(245, 135, 0, 0.2);
  175. }
  176. }
  177. .ant-tree-checkbox {
  178. .ant-tree-checkbox-inner {
  179. border: 1px solid #f48800;
  180. }
  181. &:hover {
  182. .ant-tree-checkbox-inner {
  183. border-color: #faae69;
  184. }
  185. }
  186. &:focus {
  187. .ant-tree-checkbox-inner {
  188. border-color: #f48800;
  189. }
  190. }
  191. }
  192. .ant-tree-checkbox-inner {
  193. width: 20px;
  194. height: 20px;
  195. border-radius: 4px;
  196. &:after {
  197. top: 50%;
  198. left: 27%;
  199. }
  200. }
  201. .ant-tree-checkbox-checked {
  202. &:after {
  203. border-color: transparent;
  204. }
  205. }
  206. .ant-tree-checkbox-checked .ant-tree-checkbox-inner {
  207. border-color: #f48800;
  208. background-color: #f48800;
  209. }
  210. .ant-tree-checkbox-indeterminate .ant-tree-checkbox-inner::after {
  211. top: 50%;
  212. left: 50%;
  213. width: 8px;
  214. height: 8px;
  215. background-color: #1890ff;
  216. border: 0;
  217. transform: translate(-50%, -50%) scale(1);
  218. opacity: 1;
  219. content: " ";
  220. }
  221. .ant-tree-checkbox-indeterminate .ant-tree-checkbox-inner::after {
  222. background-color: #f48800;
  223. }
  224. .ant-tree {
  225. padding: 0 !important;
  226. margin-bottom: 11px;
  227. }
  228. .ant-tree>li {}
  229. .ant-tree li {
  230. position: relative;
  231. padding: 11px 0;
  232. .ant-tree-node-content-wrapper {
  233. height: 100%;
  234. &.ant-tree-node-selected {
  235. background-color: transparent;
  236. }
  237. &:hover {
  238. background-color: transparent;
  239. }
  240. }
  241. .ant-tree-checkbox {
  242. display: inline-flex;
  243. align-items: center;
  244. margin-right: 20px;
  245. }
  246. span.ant-tree-switcher {
  247. position: absolute;
  248. top: 8px;
  249. right: 0;
  250. &:after {
  251. position: absolute;
  252. top: 0;
  253. right: 0;
  254. bottom: 0;
  255. left: 0;
  256. margin: auto;
  257. display: inline-block;
  258. content: "";
  259. width: 11px;
  260. height: 9px;
  261. background-image: url("~/assets/svg/down-arrow.svg");
  262. background-position: center;
  263. background-repeat: no-repeat;
  264. background-size: 100%;
  265. }
  266. i.ant-tree-switcher-icon {
  267. color: transparent;
  268. }
  269. &.ant-tree-switcher_open {
  270. &:after {
  271. transform: rotate(180deg);
  272. }
  273. }
  274. &.ant-tree-switcher-noop {
  275. &:after {
  276. background-image: none;
  277. }
  278. }
  279. }
  280. }
  281. .ant-tree-child-tree {
  282. padding-top: 11px;
  283. }
  284. span.ant-tree-title>span {
  285. display: block;
  286. max-width: 242px;
  287. white-space: initial;
  288. font-weight: 400;
  289. font-size: 14px;
  290. line-height: 18px;
  291. color: #232323;
  292. }
  293. }
  294. .close {
  295. background-image: url("~/assets/svg/close.svg");
  296. background-position: center;
  297. background-repeat: no-repeat;
  298. background-size: cover;
  299. width: 14px;
  300. height: 14px;
  301. }
  302. </style>