@handaotech-design/bom 0.0.48 → 0.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +0,0 @@
1
- import { Dropdown, Input, Tree } from "ant-design-vue";
2
- import { MoreOutlined } from "@ant-design/icons-vue";
3
- import { withInstall } from "../../utils/install.js";
4
- import BomTree from "./index.vue";
5
- export * from "./index.vue";
6
- const antdComponents = Object.fromEntries(
7
- [Input, Tree, Dropdown, MoreOutlined].map((comp) => [comp.name, comp])
8
- );
9
- export const HdBomTree = withInstall(BomTree, antdComponents);
10
- export default HdBomTree;
@@ -1,420 +0,0 @@
1
- <script lang="ts" setup>
2
- import { nextTick, onBeforeUnmount, onMounted, ref, toRefs, watch } from 'vue'
3
- import type { TreeProps } from 'ant-design-vue'
4
- import { Dropdown, Tree } from 'ant-design-vue'
5
- import { watchDebounced } from '@vueuse/shared'
6
- import * as _ from 'lodash-es'
7
- import type { DataNode } from 'ant-design-vue/es/vc-tree-select/interface'
8
- import type { EventDataNode } from 'ant-design-vue/es/tree'
9
- import { MoreOutlined } from '@ant-design/icons-vue'
10
- import HdGrayInput from '../gray-input'
11
- import type { BomNode, BomTreeConfig } from '../../models'
12
-
13
- const props = withDefaults(defineProps<Props>(), {
14
- maintainable: false,
15
- })
16
- const emit = defineEmits(['select'])
17
- const COMPONENT_NAME = 'HdBomTreeView'
18
- defineOptions({
19
- name: COMPONENT_NAME,
20
- components: { ATree: Tree, ADropdown: Dropdown },
21
- })
22
-
23
- type TreeNodeWithMeta = DataNode & {
24
- parentKeys: string[]
25
- }
26
-
27
- interface Props {
28
- treeData: TreeProps['treeData']
29
- config: BomTreeConfig
30
- maintainable?: boolean
31
- shouldSelect?: (node: DataNode) => Promise<boolean>
32
- keyNodeMap: Map<string, BomNode>
33
- firstSelectableKey?: string
34
- }
35
-
36
- const expandedKeys = ref<(string | number)[]>([])
37
- const searchValue = ref<string>('')
38
- const autoExpandParent = ref<boolean>(true)
39
- const { treeData: _treeData } = toRefs(props)
40
- const filteredTreeData = ref<TreeProps['treeData']>([])
41
- const treeContainerHeight = ref<number>(0)
42
- const treeContainerId = 'treeContainer'
43
- let keyToNodeMap = new Map<string, TreeNodeWithMeta>()
44
- const selectedKeys = ref<string[]>([])
45
- const isPreservingTreeState = ref<boolean>(false)
46
- const initTreeState = () => {
47
- searchValue.value = ''
48
- selectedKeys.value = []
49
- expandedKeys.value = []
50
- }
51
-
52
- const onExpand = (keys: Key[]) => {
53
- expandedKeys.value = keys
54
- autoExpandParent.value = false
55
- }
56
-
57
- const updateTreeContainerHeight = () => {
58
- const treeContainer = document.getElementById(treeContainerId)
59
- if (treeContainer) {
60
- treeContainerHeight.value = treeContainer.clientHeight
61
- }
62
- }
63
-
64
- const buildKeyToNodeMap = (treeData: TreeProps['treeData']) => {
65
- const keyMap = new Map<string, TreeNodeWithMeta>()
66
- const traverse = (nodes: TreeProps['treeData'] = [], parentKeys: string[] = []) => {
67
- for (const node of nodes) {
68
- if (parentKeys) {
69
- keyMap.set(node.key as string, {
70
- ...node,
71
- parentKeys: parentKeys || [],
72
- } as any)
73
- }
74
- if (!_.isEmpty(node.children)) {
75
- traverse(node.children, [...parentKeys, node.key as string])
76
- }
77
- }
78
- }
79
- traverse(treeData)
80
- return keyMap
81
- }
82
-
83
- const filterTreeData = (data: TreeProps['treeData'], filteredKeys: string[]) => {
84
- const getNodes = (result: any, node: any) => {
85
- if (_.includes(filteredKeys, node.key)) {
86
- result.push({ ...node })
87
- return result
88
- }
89
- if (Array.isArray(node.children)) {
90
- const children = node.children.reduce(getNodes, [])
91
- if (!_.isEmpty(children)) {
92
- result.push({ ...node, children })
93
- }
94
- }
95
- return result
96
- }
97
- return (data || []).reduce(getNodes, [])
98
- }
99
-
100
- // 获取直接父节点的 key
101
- const getParentKeys = (key: string): string[] | undefined => {
102
- const treeNode = keyToNodeMap.get(key)
103
- return treeNode?.parentKeys || []
104
- }
105
-
106
- const selectFirstSelectableNode = (preserveExpanded = false) => {
107
- const firstNode: any = _.find(Array.from(keyToNodeMap.values()), node => (node as any)?.selectable)
108
- if (!firstNode) {
109
- return
110
- }
111
-
112
- nextTick(() => {
113
- const parentKeys = getParentKeys(firstNode.key as string) as string[]
114
- expandedKeys.value = preserveExpanded
115
- ? Array.from(new Set([...expandedKeys.value, ...parentKeys])) // 取并集
116
- : parentKeys
117
- selectedKeys.value = [firstNode.key]
118
- })
119
- }
120
-
121
- type Key = string | number
122
- const onSelected = async (keys: Key[], { node }: { node: EventDataNode }) => {
123
- if (_.isFunction(props.shouldSelect) && node?.dataRef && !(await props.shouldSelect(node.dataRef))) {
124
- return
125
- }
126
- const key = node?.dataRef?.key
127
- if (key) {
128
- selectedKeys.value = [key as string]
129
- }
130
- else {
131
- selectedKeys.value = []
132
- }
133
- }
134
-
135
- onMounted(async () => {
136
- window.addEventListener('resize', updateTreeContainerHeight)
137
- await nextTick(() => {
138
- updateTreeContainerHeight()
139
- })
140
- })
141
-
142
- onBeforeUnmount(() => {
143
- window.removeEventListener('resize', updateTreeContainerHeight)
144
- })
145
-
146
- watch(
147
- () => _treeData.value,
148
- async () => {
149
- filteredTreeData.value = _treeData.value
150
- keyToNodeMap = buildKeyToNodeMap(_treeData.value ?? [])
151
- initTreeState()
152
- // if (!isPreservingTreeState.value) {
153
- // selectFirstSelectableNode(true)
154
- // }
155
- },
156
- {
157
- immediate: true,
158
- },
159
- )
160
-
161
- watchDebounced(
162
- searchValue, (value: string) => {
163
- let expanded: any[]
164
- if (_.isEmpty(value)) {
165
- expanded = getParentKeys(selectedKeys.value[0]) || []
166
- filteredTreeData.value = _treeData.value
167
- }
168
- else {
169
- const filteredNodes: TreeProps['treeData'] = []
170
- expanded = (Array.from(keyToNodeMap.values()))
171
- .map((item: any) => {
172
- if (hasSearchMatch(item.title)) {
173
- filteredNodes.push(item)
174
- return getParentKeys(item.key)
175
- }
176
- return null
177
- })
178
- .filter((item, i, self) => item && self.indexOf(item) === i)
179
- const filteredKeys = filteredNodes.map(item => item.key)
180
- filteredTreeData.value = _.isEmpty(filteredKeys) ? [] : filterTreeData(_treeData.value, filteredKeys as unknown as string[])
181
- }
182
- expandedKeys.value = expanded
183
- nextTick(() => {
184
- expandedKeys.value = _.uniq(expanded.flat(1)) as any as string[]
185
- })
186
- }, { debounce: 500 })
187
-
188
- watch(
189
- () => selectedKeys.value,
190
- () => {
191
- if (selectedKeys.value && selectedKeys.value.length) {
192
- return emit('select', keyToNodeMap.get(selectedKeys.value[0]))
193
- }
194
- },
195
- )
196
-
197
- function getIconClass(icon: string, isSelected: boolean) {
198
- return isSelected ? `i-icon-${icon}-selected` : `i-icon-${icon}`
199
- }
200
-
201
- function getTitlePart(title: string, partType: 'before' | 'after') {
202
- const _searchValue = searchValue.value || ''
203
- const index = title.indexOf(_searchValue)
204
-
205
- return {
206
- before: title.substring(0, index),
207
- after: title.substring(index + _searchValue.length),
208
- }[partType]
209
- }
210
-
211
- function hasSearchMatch(title: string) {
212
- return searchValue.value && title.includes(searchValue.value)
213
- }
214
-
215
- async function updateTreeWithPreservedState(updateDataFn: () => Promise<void>) {
216
- const prevSelected = selectedKeys.value?.[0]
217
- const prevExpanded = [...expandedKeys.value]
218
- isPreservingTreeState.value = true
219
- await updateDataFn()
220
- await nextTick(() => {
221
- expandedKeys.value = prevExpanded.filter(key => keyToNodeMap.has(key as string))
222
-
223
- if (prevSelected && keyToNodeMap.has(prevSelected)) {
224
- selectedKeys.value = [prevSelected]
225
- }
226
- else {
227
- selectFirstSelectableNode(true)
228
- }
229
- isPreservingTreeState.value = false
230
- })
231
- }
232
-
233
- function getDepth(key: string): number {
234
- const parentKeys = getParentKeys(key)
235
- if (_.isEmpty(parentKeys)) {
236
- return -1
237
- }
238
- return parentKeys!.length + 1
239
- }
240
-
241
- defineExpose({
242
- updateTreeWithPreservedState,
243
- getParentKeys,
244
- getDepth,
245
- })
246
- </script>
247
-
248
- <template>
249
- <div class="flex flex-col h-100%">
250
- <div class="search-box">
251
- <HdGrayInput
252
- v-model:value="searchValue"
253
- :placeholder="props.config?.filter?.placeholder || '输入关键词进行筛选(如名称/编号)'"
254
- class="search-input"
255
- >
256
- <template #prefix>
257
- <div class="i-icon-search w-16px h-16px" />
258
- </template>
259
- </HdGrayInput>
260
- </div>
261
- <div :id="treeContainerId" class="flex-grow tree-wrapper mt-12px overflow-y-hidden">
262
- <div v-if="!_.isEmpty(filteredTreeData)">
263
- <a-tree
264
- :height="treeContainerHeight"
265
- :expanded-keys="expandedKeys"
266
- :auto-expand-parent="autoExpandParent"
267
- :tree-data="filteredTreeData"
268
- :block-node="true"
269
- :default-selected-keys="[props.firstSelectableKey]"
270
- @expand="onExpand"
271
- @select="onSelected"
272
- >
273
- <template #title="{ title, dataRef }">
274
- <div :class="`tree-node-tittle flex items-center ${dataRef.selectable ? 'selectable' : 'not-selectable'}`">
275
- <div
276
- v-if="!!dataRef.icon"
277
- class="icon w-20px h-20px mr-4px min-w-20px"
278
- :class="[getIconClass(dataRef.icon, selectedKeys.includes(dataRef.key))]"
279
- />
280
- <div v-if="hasSearchMatch(title)" class="tree-node-text">
281
- <span>{{ getTitlePart(title, 'before') }}</span>
282
- <span class="highlight" style="background-color: #FFD499">{{ searchValue }}</span>
283
- <span>{{ getTitlePart(title, 'after') }}</span>
284
- </div>
285
- <div v-else class="tree-node-text">
286
- {{ title }}
287
- </div>
288
- <div v-if="props.maintainable" class="click-menu-wrapper">
289
- <a-dropdown
290
- :trigger="['hover', 'click']"
291
- :destroy-popup-on-hide="true"
292
- >
293
- <MoreOutlined class="menu-trigger" @click.stop />
294
- <template #overlay>
295
- <slot name="node-menu" :tree-node="dataRef" />
296
- </template>
297
- </a-dropdown>
298
- </div>
299
- </div>
300
- </template>
301
- <template #switcherIcon="{ dataRef }">
302
- <div
303
- v-if="expandedKeys.includes(dataRef.key)" class="i-icon-remove-minus icon w-16px h-16px"
304
- style="font-size: 20px;"
305
- />
306
- <div v-else class="i-icon-remove-plus icon w-16px h-16px" />
307
- </template>
308
- </a-tree>
309
- </div>
310
- <div v-show="_.isEmpty(filteredTreeData)" class="w-100% h-100% flex justify-center items-center">
311
- <span>暂无数据</span>
312
- </div>
313
- </div>
314
- </div>
315
- </template>
316
-
317
- <style scoped>
318
- .tree-wrapper {
319
- background-color: #fff;
320
- min-height: 0;
321
- }
322
-
323
- .search-box {
324
- padding: 0 16px;
325
- }
326
-
327
- :deep(.ant-tree-list) .ant-tree-treenode-motion {
328
- width: 100%;
329
- }
330
- :deep(.ant-tree-list) .ant-tree-treenode {
331
- width: 100%;
332
- align-items: center;
333
- color: #2C2C2C;
334
- font-size: 16px;
335
- display: flex;
336
- justify-content: center;
337
- padding: 4px 0 4px 12px;
338
- }
339
- :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-indent-unit {
340
- width: 10px;
341
- }
342
- :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-switcher {
343
- width: 16px;
344
- height: 16px;
345
- padding: 0;
346
- margin: 0 10px 0 0;
347
- align-self: center;
348
- line-height: 16px;
349
- }
350
- :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper {
351
- transition: none;
352
- white-space: nowrap;
353
- text-overflow: ellipsis;
354
- margin-bottom: 0;
355
- display: inline-flex;
356
- overflow: visible !important;
357
- flex: 1;
358
- min-width: 0;
359
- }
360
- :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper:hover {
361
- background-color: #E9EBED;
362
- }
363
- :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper .ant-tree-title {
364
- text-overflow: ellipsis;
365
- white-space: nowrap;
366
- flex: 1;
367
- min-width: 0;
368
- position: relative;
369
- }
370
- :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper .ant-tree-title .tree-node-tittle.selectable {
371
- cursor: pointer;
372
- }
373
- :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper .ant-tree-title .tree-node-tittle.not-selectable {
374
- cursor: auto;
375
- }
376
- :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper .ant-tree-title .tree-node-tittle .click-menu-wrapper {
377
- display: none;
378
- margin-left: auto;
379
- margin-right: 4px;
380
- }
381
- :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper .ant-tree-title .tree-node-tittle:hover .click-menu-wrapper {
382
- display: block;
383
- }
384
- :deep(.ant-tree-list) .ant-tree-treenode:hover {
385
- background-color: #E9EBED;
386
- }
387
- :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper {
388
- user-select: auto;
389
- }
390
- :deep(.ant-tree-list) .ant-tree-treenode.ant-tree-treenode-selected {
391
- background-color: #EDF4FF;
392
- border-radius: 4px;
393
- color: #1E3B9D;
394
- font-weight: 700;
395
- }
396
- :deep(.ant-tree-list) .ant-tree-treenode.ant-tree-treenode-selected .ant-tree-switcher, :deep(.ant-tree-list) .ant-tree-treenode.ant-tree-treenode-selected .ant-tree-node-content-wrapper {
397
- background-color: #EDF4FF;
398
- }
399
- :deep(.ant-tree-list) .ant-tree-node-content-wrapper {
400
- align-items: center;
401
- padding: 0;
402
- }
403
- :deep(.ant-tree-list) .ant-tree-node-content-wrapper {
404
- display: flex;
405
- margin-bottom: -4px;
406
- }
407
- :deep(.ant-tree-list) .ant-tree-node-content-wrapper .ant-tree-title {
408
- flex-grow: 1;
409
- display: block;
410
- }
411
-
412
- .tree-node-text {
413
- display: inline-block;
414
- max-width: 100%;
415
- overflow: hidden;
416
- text-overflow: ellipsis;
417
- white-space: nowrap;
418
- vertical-align: middle;
419
- }
420
- </style>
@@ -1,3 +0,0 @@
1
- export * from './index.vue';
2
- export declare const HdBomTree: any;
3
- export default HdBomTree;
@@ -1,29 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- var _exportNames = {
7
- HdBomTree: true
8
- };
9
- module.exports = exports.HdBomTree = void 0;
10
- var _antDesignVue = require("ant-design-vue");
11
- var _iconsVue = require("@ant-design/icons-vue");
12
- var _install = require("../../utils/install");
13
- var _index = _interopRequireWildcard(require("./index.vue"));
14
- Object.keys(_index).forEach(function (key) {
15
- if (key === "default" || key === "__esModule") return;
16
- if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
17
- if (key in exports && exports[key] === _index[key]) return;
18
- Object.defineProperty(exports, key, {
19
- enumerable: true,
20
- get: function () {
21
- return _index[key];
22
- }
23
- });
24
- });
25
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
26
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
27
- const antdComponents = Object.fromEntries([_antDesignVue.Input, _antDesignVue.Tree, _antDesignVue.Dropdown, _iconsVue.MoreOutlined].map(comp => [comp.name, comp]));
28
- const HdBomTree = exports.HdBomTree = (0, _install.withInstall)(_index.default, antdComponents);
29
- module.exports = HdBomTree;