@handaotech-design/bom 0.0.17 → 0.0.19

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.
Files changed (47) hide show
  1. package/dist/es/components/bom-tree/index.vue +2 -0
  2. package/dist/es/components/gray-input/index.vue +3 -0
  3. package/dist/lib/components/bom-tree/index.vue +2 -0
  4. package/dist/lib/components/gray-input/index.vue +3 -0
  5. package/package.json +2 -8
  6. package/build.config.ts +0 -27
  7. package/rollup.config.ts +0 -47
  8. package/src/all-components.ts +0 -12
  9. package/src/assets/icons/operation-selected.svg +0 -3
  10. package/src/assets/icons/operation.svg +0 -3
  11. package/src/assets/icons/process-path-selected.svg +0 -3
  12. package/src/assets/icons/process-path.svg +0 -3
  13. package/src/assets/icons/process-plan-selected.svg +0 -3
  14. package/src/assets/icons/process-plan.svg +0 -3
  15. package/src/assets/icons/remove-minus.svg +0 -4
  16. package/src/assets/icons/remove-plus.svg +0 -5
  17. package/src/assets/icons/search.svg +0 -4
  18. package/src/components/bom-tree/index.ts +0 -5
  19. package/src/components/bom-tree/index.vue +0 -377
  20. package/src/components/bom-workbench/index.ts +0 -5
  21. package/src/components/bom-workbench/index.vue +0 -97
  22. package/src/components/gray-input/index.ts +0 -5
  23. package/src/components/gray-input/index.vue +0 -40
  24. package/src/components/index.ts +0 -4
  25. package/src/components/left-right/index.ts +0 -5
  26. package/src/components/left-right/index.vue +0 -149
  27. package/src/defaults.ts +0 -3
  28. package/src/hooks/index.ts +0 -1
  29. package/src/hooks/use-ppboms.ts +0 -97
  30. package/src/index.ts +0 -9
  31. package/src/models/bom.ts +0 -43
  32. package/src/models/common.ts +0 -6
  33. package/src/models/index.ts +0 -2
  34. package/src/shared/keys.ts +0 -1
  35. package/src/shared/make-installer.ts +0 -21
  36. package/src/shims-vue.d.ts +0 -5
  37. package/src/tokens/index.ts +0 -0
  38. package/src/types/components.d.ts +0 -17
  39. package/src/utils/bom.ts +0 -33
  40. package/src/utils/config.ts +0 -11
  41. package/src/utils/index.ts +0 -4
  42. package/src/utils/rule-engine.ts +0 -83
  43. package/src/utils/template.ts +0 -13
  44. package/tsconfig.json +0 -33
  45. package/unocss.config.ts +0 -55
  46. package/vite-env.d.ts +0 -1
  47. package/vite.config.ts +0 -79
@@ -1,97 +0,0 @@
1
- <script lang="ts" setup>
2
- import { ref, watch } from 'vue'
3
- import * as _ from 'lodash-es'
4
- import type { BomNode, BomTreeConfig, Optional, WorkBenchLayoutConfig } from '../../models'
5
- import { convertBomDataToTree } from '../../utils'
6
- import HdLeftRight from '../left-right/index'
7
- import HdBomTree from '../bom-tree/index'
8
-
9
- const props = defineProps<Props>()
10
- const COMPONENT_NAME = 'HdBomWorkbench'
11
- defineOptions({
12
- name: COMPONENT_NAME,
13
- })
14
-
15
- interface Props {
16
- moduleKey: string
17
- bomData: Optional<BomNode[]>
18
- treeConfig: BomTreeConfig
19
- layoutConfig?: WorkBenchLayoutConfig
20
- }
21
- const bomDataForTree = ref<BomNode[]>()
22
- const selectedNode = ref<BomNode>()
23
-
24
- async function onSelected(data: BomNode) {
25
- selectedNode.value = data
26
- }
27
-
28
- watch(
29
- () => props.bomData,
30
- () => {
31
- if (_.isEmpty(props.bomData)) {
32
- selectedNode.value = undefined
33
- bomDataForTree.value = undefined
34
- }
35
- else {
36
- bomDataForTree.value = convertBomDataToTree(props.bomData!, props.treeConfig.nodeConfig.rule)
37
- }
38
- },
39
- { immediate: true },
40
- )
41
- </script>
42
-
43
- <template>
44
- <HdLeftRight
45
- v-if="bomDataForTree"
46
- :module-key="props.moduleKey"
47
- :max-left-width="props?.layoutConfig?.maxLeftWidth"
48
- >
49
- <template #left>
50
- <div class="left-content">
51
- <div class="bom-tree-container">
52
- <HdBomTree
53
- :tree-data="bomDataForTree"
54
- :config="props.treeConfig"
55
- @select="(data: BomNode) => onSelected(data)"
56
- >
57
- <template #right-click>
58
- <slot name="tree-right-click" :bom-node="selectedNode" />
59
- </template>
60
- </HdBomTree>
61
- </div>
62
- </div>
63
- </template>
64
- <template #right>
65
- <div class="m-20px">
66
- <slot name="content" :bom-node="selectedNode" />
67
- </div>
68
- </template>
69
- </HdLeftRight>
70
- </template>
71
-
72
- <style lang="scss" scoped>
73
- .v-h-center {
74
- width: 100%;
75
- height: 100%;
76
- display: flex;
77
- justify-content: center;
78
- align-items: center;
79
- transition: all 1s ease;
80
- }
81
- .left-content {
82
- display: flex;
83
- flex-direction: column;
84
- height: 100%;
85
- padding: 20px 0 16px 0;
86
-
87
- .bom-tree-container {
88
- flex-grow: 1;
89
- }
90
- }
91
- :deep(.spinning-wrapper) {
92
- height: 100%;
93
- .ant-spin-container {
94
- height: 100%;
95
- }
96
- }
97
- </style>
@@ -1,5 +0,0 @@
1
- import { withInstall } from '@handaotech-design/vue'
2
- import GaryInput from './index.vue'
3
- export * from './index.vue'
4
- export const HdGrayInput = withInstall(GaryInput)
5
- export default HdGrayInput
@@ -1,40 +0,0 @@
1
- <script setup lang="ts">
2
- const COMPONENT_NAME = 'HdBomGrayInput'
3
- defineOptions({
4
- name: COMPONENT_NAME,
5
- })
6
- </script>
7
-
8
- <template>
9
- <span class="inline-block gray-a-input-wrapper">
10
- <a-input
11
- v-bind="$attrs"
12
- >
13
- <template v-for="(key, index) in Object.keys($slots)" :key="index" #[key]>
14
- <slot :name="key" />
15
- </template>
16
- </a-input>
17
- </span>
18
- </template>
19
-
20
- <style lang="scss" scoped>
21
- .gray-a-input-wrapper {
22
- width: 100%;
23
- }
24
- :deep(.ant-input),
25
- :deep(.ant-input-affix-wrapper) {
26
- background-color: #F5F5F5;
27
- border-radius: 2px;
28
- padding: 6px 12px;
29
- font-size: 14px;
30
- border-color: transparent;
31
- &:hover {
32
- border-color: #1E3B9D;
33
- }
34
- &:focus, &.ant-input-affix-wrapper-focused {
35
- border-color: #1E3B9D;
36
- background-color: #fff;
37
- box-shadow: none;
38
- }
39
- }
40
- </style>
@@ -1,4 +0,0 @@
1
- export * from './bom-tree'
2
- export * from './bom-workbench'
3
- export * from './gray-input'
4
- export * from './left-right'
@@ -1,5 +0,0 @@
1
- import { withInstall } from '@handaotech-design/vue'
2
- import LeftRight from './index.vue'
3
- export * from './index.vue'
4
- export const HdLeftRight = withInstall(LeftRight)
5
- export default HdLeftRight
@@ -1,149 +0,0 @@
1
- <script lang="ts" setup>
2
- import { debounce, throttle } from 'lodash-es'
3
- import { onMounted, onUnmounted, ref } from 'vue'
4
-
5
- const props = defineProps({
6
- moduleKey: {
7
- type: String,
8
- required: true,
9
- },
10
- maxLeftWidth: {
11
- type: Number,
12
- required: false,
13
- },
14
- })
15
- const COMPONENT_NAME = 'HdLeftRight'
16
- defineOptions({
17
- name: COMPONENT_NAME,
18
- })
19
-
20
- // 默认宽度 & 本地存储
21
- const defaultLeftWidth = 300
22
- const savedWidth = localStorage.getItem(`${props.moduleKey}LeftPanelWidth`)
23
- const initialWidth = savedWidth ? parseInt(savedWidth) : defaultLeftWidth
24
-
25
- // 响应式宽度
26
- const leftWidth = ref(initialWidth)
27
- const isDragging = ref(false)
28
- let startX = 0
29
- let startWidth = 0
30
-
31
- // 节流更新UI(60fps)
32
- const throttledUpdate = throttle((width: number) => {
33
- leftWidth.value = width
34
- }, 16)
35
-
36
- // 防抖保存到本地存储(300ms延迟)
37
- const debouncedSave = debounce(
38
- (val: number) => {
39
- localStorage.setItem(`${props.moduleKey}LeftPanelWidth`, val.toString())
40
- },
41
- 300,
42
- { trailing: true }, // 确保最后一次触发
43
- )
44
-
45
- // 处理拖动
46
- const handleDrag = (e: MouseEvent) => {
47
- if (!isDragging.value) {
48
- return
49
- }
50
- const delta = e.clientX - startX
51
- const newWidth = Math.max(
52
- 200,
53
- Math.min(props.maxLeftWidth ?? 500, startWidth + delta),
54
- )
55
-
56
- throttledUpdate(newWidth) // 节流更新UI
57
- debouncedSave(newWidth) // 防抖保存
58
- }
59
-
60
- // 停止拖动
61
- const stopDrag = () => {
62
- isDragging.value = false
63
- document.removeEventListener('mousemove', handleDrag)
64
- document.removeEventListener('mouseup', stopDrag)
65
-
66
- debouncedSave.flush() // 立即执行未完成的保存
67
- }
68
-
69
- // 开始拖动
70
- const startDrag = (e: MouseEvent) => {
71
- isDragging.value = true
72
- startX = e.clientX
73
- startWidth = leftWidth.value
74
- document.addEventListener('mousemove', handleDrag)
75
- document.addEventListener('mouseup', stopDrag)
76
- }
77
-
78
- // 清理
79
- onUnmounted(() => {
80
- document.removeEventListener('mousemove', handleDrag)
81
- document.removeEventListener('mouseup', stopDrag)
82
- throttledUpdate.cancel()
83
- debouncedSave.cancel()
84
- })
85
-
86
- // 初始化
87
- onMounted(() => {
88
- leftWidth.value = initialWidth
89
- })
90
- </script>
91
-
92
- <template>
93
- <div class="wrapper">
94
- <div class="left" :style="{ width: `${leftWidth}px` }">
95
- <slot name="left" />
96
- </div>
97
- <div
98
- class="divider"
99
- :style="{ left: `${leftWidth}px` }"
100
- @mousedown="startDrag"
101
- >
102
- <div class="vertical-line" />
103
- </div>
104
- <div class="right">
105
- <slot name="right" />
106
- </div>
107
- </div>
108
- </template>
109
-
110
- <style scoped lang="scss">
111
- .wrapper {
112
- display: flex;
113
- position: relative;
114
- height: 100%;
115
-
116
- .left {
117
- height: 100%;
118
- overflow: hidden;
119
- }
120
-
121
- .divider {
122
- position: absolute;
123
- height: 100%;
124
- cursor: col-resize;
125
- z-index: 1;
126
- transition: background 0.2s;
127
-
128
- .vertical-line {
129
- width: 1px;
130
- height: 100%;
131
- background: #E9EBED;
132
- }
133
-
134
- &:hover {
135
- .vertical-line {
136
- background: #2e72d2;
137
- width: 2px;
138
- }
139
- }
140
- }
141
-
142
- .right {
143
- flex: 1;
144
- overflow-y: auto;
145
- overflow-x: hidden;
146
- padding: 0 16px;
147
- }
148
- }
149
- </style>
package/src/defaults.ts DELETED
@@ -1,3 +0,0 @@
1
- import { makeInstaller } from './shared/make-installer'
2
- import AllComponents from './all-components'
3
- export default makeInstaller([...AllComponents])
@@ -1 +0,0 @@
1
- export * from './use-ppboms'
@@ -1,97 +0,0 @@
1
- import { ref } from 'vue'
2
- import { convertBomDataToTree, getConfig } from '../utils'
3
- import { YesNo } from '../models'
4
-
5
- const ppbomPageConfigCode = 'PPBOM_PAGE'
6
-
7
- export enum QueryType {
8
- ALL = 'ALL',
9
- MODEL_ESN = 'MODEL_ESN',
10
- }
11
-
12
- interface UsePpbomsParams {
13
- host: string
14
- appId: string
15
- appSecret: string
16
- queryType?: QueryType
17
- options?: Record<string, any>
18
- }
19
-
20
- export const usePpboms = (params: UsePpbomsParams) => {
21
- const { host, appId, appSecret, queryType, options } = params
22
- const loading = ref<boolean>(false)
23
- const treeData = ref<any>()
24
- const treeConfig = ref<any>()
25
- const layoutConfig = ref<any>()
26
-
27
- const queryBoms = async () => {
28
- const body = {
29
- page: 1,
30
- pageSize: Number.MAX_SAFE_INTEGER,
31
- ...(options ?? {}),
32
- }
33
- const response = await fetch(`http://${host}/api/public/v2/ppboms/query/all`, {
34
- method: 'POST',
35
- headers: {
36
- 'Content-Type': 'application/json',
37
- 'X-CONSUMER-ID': appId,
38
- 'Authorization': `Bearer ${appSecret}`,
39
- },
40
- body: JSON.stringify(body),
41
- })
42
- return response.json()
43
- }
44
-
45
- const queryBomsByModelEsn = async () => {
46
- const body = {
47
- page: 1,
48
- pageSize: Number.MAX_SAFE_INTEGER,
49
- forceSettle: YesNo.YES,
50
- lookupOnly: YesNo.YES,
51
- ...(options ?? {}),
52
- }
53
- const response = await fetch(`http://${host}/api/public/v2/ppboms/query/by-model-esn`, {
54
- method: 'POST',
55
- headers: {
56
- 'Content-Type': 'application/json',
57
- 'X-CONSUMER-ID': appId,
58
- 'Authorization': `Bearer ${appSecret}`,
59
- },
60
- body: JSON.stringify(body),
61
- })
62
- return response.json()
63
- }
64
-
65
- const getData = async () => {
66
- switch (queryType) {
67
- case QueryType.MODEL_ESN:
68
- return await queryBomsByModelEsn()
69
- default:
70
- return await queryBoms()
71
- }
72
- }
73
-
74
- const getDataAndConfig = async () => {
75
- try {
76
- loading.value = true
77
- const dataResp = await getData()
78
- const configResp = await getConfig(host, ppbomPageConfigCode, appId, appSecret)
79
- loading.value = false
80
- const props = configResp.config.props
81
- treeData.value = convertBomDataToTree(dataResp.data.items, props.content.tree.nodeConfig.rule)
82
- treeConfig.value = props.content.tree
83
- layoutConfig.value = props.content.tree.layout
84
- }
85
- finally {
86
- loading.value = false
87
- }
88
- }
89
-
90
- return {
91
- treeData,
92
- layoutConfig,
93
- treeConfig,
94
- loading,
95
- getDataAndConfig,
96
- }
97
- }
package/src/index.ts DELETED
@@ -1,9 +0,0 @@
1
- import installer from './defaults'
2
- export * from './components'
3
- export * from './hooks'
4
- export * from './models'
5
- export * from './utils'
6
-
7
- export const install = installer.install
8
-
9
- export default installer
package/src/models/bom.ts DELETED
@@ -1,43 +0,0 @@
1
- import type { BaseRule } from '../utils'
2
- import type { YesNo } from './common'
3
-
4
- // eslint-disable-next-line no-template-curly-in-string
5
- export const defaultTitleTemplate = '${code}'
6
-
7
- export interface BomNodeTitleConfig {
8
- template: string
9
- }
10
-
11
- export interface WorkBenchLayoutConfig {
12
- maxLeftWidth: number
13
- }
14
-
15
- export interface BomTreeNodeConfig {
16
- title?: BomNodeTitleConfig
17
- selectable?: YesNo
18
- icon?: string
19
- }
20
-
21
- export interface BomLocalFilter {
22
- placeholder?: string
23
- }
24
-
25
- export interface BomTreeConfig {
26
- filter?: BomLocalFilter
27
- nodeConfig: {
28
- rule: BaseRule<BomTreeNodeConfig>
29
- }
30
- }
31
-
32
- export interface BomNode {
33
- id: string
34
- key: string
35
- code: string
36
- version: string
37
- name: string
38
- qty: number
39
- children?: BomNode[]
40
- businessType: string
41
- raw: Record<string, any>
42
- [key: string]: any
43
- }
@@ -1,6 +0,0 @@
1
- export enum YesNo {
2
- YES = 'YES',
3
- NO = 'NO',
4
- }
5
-
6
- export type Optional<T> = T | undefined | null
@@ -1,2 +0,0 @@
1
- export * from './common'
2
- export * from './bom'
@@ -1 +0,0 @@
1
- export const INSTALLED_KEY = Symbol('INSTALLED_KEY')
@@ -1,21 +0,0 @@
1
- import type { App, Plugin } from '@vue/runtime-core'
2
- import { INSTALLED_KEY } from './keys'
3
-
4
- export const makeInstaller = (components: Plugin[] = []) => {
5
- const install = (app: App) => {
6
- // @ts-expect-error mark app as having installer flag
7
- if (app[INSTALLED_KEY]) {
8
- return
9
- }
10
- // @ts-expect-error set installer flag on app instance
11
- app[INSTALLED_KEY] = true
12
-
13
- components.forEach(c => app.use(c))
14
-
15
- // if (options) provideGlobalConfig(options, app, true)
16
- }
17
-
18
- return {
19
- install,
20
- }
21
- }
@@ -1,5 +0,0 @@
1
- declare module '*.vue' {
2
- import type { DefineComponent } from 'vue';
3
- const component: DefineComponent<Record<string,unknown>, Record<string,unknown>, unknown>;
4
- export default component;
5
- }
File without changes
@@ -1,17 +0,0 @@
1
- // generated by unplugin-vue-components
2
- // We suggest you to commit this file into source control
3
- // Read more: https://github.com/vuejs/core/pull/3399
4
- import '@vue/runtime-core'
5
-
6
- export {}
7
-
8
- declare module '@vue/runtime-core' {
9
- export interface GlobalComponents {
10
- BomTree: typeof import('./../components/bom-tree/index.vue')['default']
11
- BomWorkbench: typeof import('./../components/bom-workbench/index.vue')['default']
12
- GrayInput: typeof import('./../components/gray-input/index.vue')['default']
13
- LeftRight: typeof import('./../components/left-right/index.vue')['default']
14
- RouterLink: typeof import('vue-router')['RouterLink']
15
- RouterView: typeof import('vue-router')['RouterView']
16
- }
17
- }
package/src/utils/bom.ts DELETED
@@ -1,33 +0,0 @@
1
- import * as _ from 'lodash-es'
2
- import type { BomNode, BomTreeNodeConfig } from '../models'
3
- import { YesNo, defaultTitleTemplate } from '../models'
4
- import type { BaseRule } from './rule-engine'
5
- import { RuleEngine } from './rule-engine'
6
- import { genText } from './template'
7
-
8
- const defaultTreeNodeConfig: BomTreeNodeConfig = {
9
- title: {
10
- template: defaultTitleTemplate,
11
- },
12
- }
13
-
14
- export const convertBomDataToTree = (treeData: BomNode[], nodeConfigRule: BaseRule<BomTreeNodeConfig>) => {
15
- const ruleEngine = new RuleEngine<BomTreeNodeConfig>(nodeConfigRule)
16
- const traverse = (nodes: BomNode[] = []) => {
17
- for (const node of nodes) {
18
- const nodeConfig = ruleEngine.matchOne({ bomNode: node }, defaultTreeNodeConfig)
19
- const titleTemplate = nodeConfig?.title?.template ?? defaultTitleTemplate
20
- Object.assign(node, {
21
- key: node.key,
22
- title: genText(node, titleTemplate),
23
- selectable: nodeConfig?.selectable === YesNo.YES,
24
- icon: nodeConfig?.icon,
25
- })
26
- if (!_.isEmpty(node.children)) {
27
- traverse(node.children)
28
- }
29
- }
30
- }
31
- traverse(treeData)
32
- return treeData
33
- }
@@ -1,11 +0,0 @@
1
- export const getConfig = async (host: string, code: string, appId: string, appSecret: string) => {
2
- const response = await fetch(`http://${host}/api/public/v2/business-configs/${code}`, {
3
- method: 'GET',
4
- headers: {
5
- 'Content-Type': 'application/json',
6
- 'X-CONSUMER-ID': appId,
7
- 'Authorization': `Bearer ${appSecret}`,
8
- },
9
- })
10
- return await response.json()
11
- }
@@ -1,4 +0,0 @@
1
- export * from './bom'
2
- export * from './rule-engine'
3
- export * from './template'
4
- export * from './config'
@@ -1,83 +0,0 @@
1
- import type { Optional } from '../models/common'
2
-
3
- export type RuleCondition = 'default' | 'always' | string | LogicExpression
4
-
5
- export interface LogicExpression {
6
- // 以后可扩展
7
- logic: any
8
- conditions: any[]
9
- }
10
-
11
- export interface BaseRule<T> {
12
- cases: BaseCase<T>[]
13
- }
14
-
15
- export interface BaseCase<T> {
16
- key?: string
17
- condition: RuleCondition
18
- result: T
19
- }
20
-
21
- export class RuleEngine<T> {
22
- private readonly rule: BaseRule<T>
23
-
24
- constructor(rule: BaseRule<T>) {
25
- this.rule = rule
26
- }
27
-
28
- matchOne(context: any, defaultResult?: T): Optional<T> | T {
29
- let defaultRule: BaseCase<T> | undefined
30
-
31
- for (const caseItem of this.rule.cases) {
32
- const cond = caseItem.condition
33
- if (cond === 'default') {
34
- defaultRule = caseItem
35
- continue
36
- }
37
- if (cond === 'always' || (typeof cond === 'string' && evaluate(cond, context))) {
38
- return caseItem.result
39
- }
40
- // LogicExpression 暂不支持
41
- }
42
-
43
- if (defaultRule) {
44
- return defaultRule.result
45
- }
46
- return defaultResult
47
- }
48
-
49
- matchMany(context: any, defaultResult?: T): T[] {
50
- const results: T[] = []
51
- let defaultRule: BaseCase<T> | undefined
52
-
53
- for (const caseItem of this.rule.cases) {
54
- const cond = caseItem.condition
55
- if (cond === 'default') {
56
- defaultRule = caseItem
57
- continue
58
- }
59
- if (cond === 'always' || (typeof cond === 'string' && evaluate(cond, context))) {
60
- results.push(caseItem.result)
61
- }
62
- // LogicExpression 暂不支持
63
- }
64
-
65
- if (results.length > 0) {
66
- return results
67
- }
68
- const fallback = defaultRule?.result ?? defaultResult
69
- return fallback ? [fallback] : []
70
- }
71
- }
72
-
73
- // TODO 安全的表达式求值器
74
- function evaluate(expr: string, context: any): boolean {
75
- try {
76
- // eslint-disable-next-line no-new-func
77
- const func = new Function('context', `with(context) { return ${expr}; }`)
78
- return Boolean(func(context))
79
- }
80
- catch {
81
- return false
82
- }
83
- }
@@ -1,13 +0,0 @@
1
- import * as _ from 'lodash-es'
2
-
3
- export function genText(data: Record<string, any>, templateStr: string, defaultText?: string) {
4
- const compiled = _.template(templateStr)
5
- let str: string
6
- try {
7
- str = compiled(data)
8
- }
9
- catch (e) { // 模板变量找不到,暂时处理
10
- str = defaultText ?? '--'
11
- }
12
- return str
13
- }