@neatui/nuxt 0.1.0 → 1.0.0

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 (84) hide show
  1. package/BUILD.md +128 -0
  2. package/README.md +98 -1
  3. package/SSR_COMPATIBILITY.md +201 -0
  4. package/USAGE.md +260 -0
  5. package/nuxt.config.example.ts +37 -0
  6. package/package.json +29 -11
  7. package/src/components/basic/IDraggable.vue +87 -65
  8. package/src/components/basic/IFollowView.vue +32 -23
  9. package/src/components/basic/IRouterView.vue +38 -23
  10. package/src/components/basic/IScrollView.vue +11 -7
  11. package/src/components/basic/Icon.vue +17 -17
  12. package/src/components/basic/LayerView/Layer.vue +33 -106
  13. package/src/components/basic/follow.ts +133 -0
  14. package/src/components/display/Calendar.vue +14 -14
  15. package/src/components/display/CalendarReg.vue +14 -14
  16. package/src/components/display/Image.vue +8 -8
  17. package/src/components/display/PhotoEditor.vue +36 -36
  18. package/src/components/display/PhotoViewer.vue +8 -8
  19. package/src/components/display/Tree.vue +6 -6
  20. package/src/components/display/TreeView.vue +4 -4
  21. package/src/components/display/index.ts +2 -2
  22. package/src/components/form/Cascader.vue +19 -19
  23. package/src/components/form/Checkbox.vue +64 -0
  24. package/src/components/form/DatePicker.vue +6 -7
  25. package/src/components/form/DateRangePicker@v3.vue +4 -4
  26. package/src/components/form/DateRangeView@v3.vue +18 -19
  27. package/src/components/form/DateView.vue +14 -14
  28. package/src/components/form/DateView@v2.vue +14 -14
  29. package/src/components/form/DateView@v3.vue +331 -318
  30. package/src/components/form/ImgUpload.vue +7 -7
  31. package/src/components/form/Input@v3.vue +11 -11
  32. package/src/components/form/MoreSelect@v3.vue +87 -17
  33. package/src/components/form/MoreSelectList.vue +8 -8
  34. package/src/components/form/MoreSelectPanel@v3.vue +3 -3
  35. package/src/components/form/MoreSelectPicker.vue +7 -7
  36. package/src/components/form/MoreSelectTags.vue +8 -8
  37. package/src/components/form/PageMoreSelect.vue +14 -14
  38. package/src/components/form/PageSelect.vue +16 -16
  39. package/src/components/form/SearchMoreSelect.vue +12 -12
  40. package/src/components/form/SearchSelect@v3.vue +3 -3
  41. package/src/components/form/Select@v3.vue +229 -23
  42. package/src/components/form/SelectList.vue +8 -8
  43. package/src/components/form/SelectPicker.vue +6 -6
  44. package/src/components/form/SelectTags.vue +7 -7
  45. package/src/components/form/SelectTree/SelectTree@v1.vue +5 -5
  46. package/src/components/form/Switch.vue +38 -103
  47. package/src/components/form/TextArea.vue +18 -18
  48. package/src/components/form/Textarea@v2.vue +275 -0
  49. package/src/components/form/TimeView.vue +14 -14
  50. package/src/components/form/Upload.vue +806 -297
  51. package/src/components/form/date.ts +321 -0
  52. package/src/components/form/index.ts +7 -5
  53. package/src/components/form/number.ts +3 -0
  54. package/src/components/form/type.ts +224 -0
  55. package/src/components/icon/OrderIcon.vue +113 -0
  56. package/src/components/loader/FormLoader/FormLoader@v2.vue +193 -195
  57. package/src/components/loader/FormLoader/FormLoader@v3.vue.backup +372 -291
  58. package/src/components/loader/FormLoader/FormRender@v3.vue.backup +4 -0
  59. package/src/components/loader/FormLoader/NodeLoader.vue +85 -0
  60. package/src/components/loader/FormLoader@v1/FormLoader.vue +1 -1
  61. package/src/components/loader/FormLoader@v1/FormRender.vue +49 -24
  62. package/src/components/loader/LayerLoader/LayerLoader.vue +318 -0
  63. package/src/components/loader/LayerLoader/index.ts +2 -0
  64. package/src/components/loader/LayerLoader/style.scss +77 -0
  65. package/src/components/loader/LimitLoader/LimitLoader@v3.vue +39 -28
  66. package/src/components/loader/MoveLoader/MoveLoader.vue +628 -0
  67. package/src/components/loader/MoveLoader/index.ts +2 -0
  68. package/src/components/loader/MoveLoader/style.scss +77 -0
  69. package/src/components/loader/TableLoader/TableLoader.vue +227 -195
  70. package/src/components/loader/TableLoader/TableRender.vue +141 -0
  71. package/src/components/loader/TableLoader/index.ts +47 -0
  72. package/src/components/loader/index.ts +3 -2
  73. package/src/components/tools/Pagination@a.vue +17 -18
  74. package/src/components/tools/Pagination@b.vue +16 -16
  75. package/src/index.ts +2 -1
  76. package/src/module.ts +169 -0
  77. package/src/runtime/types.d.ts +36 -0
  78. package/src/store/{myui.ts → frame.ts} +4 -4
  79. package/src/utils/theme.ts +14 -0
  80. package/tsconfig.json +1 -1
  81. package/src/components/loader/FormLoader/index.ts +0 -2
  82. package/src/components/loader/LimitLoader/LimitLoader.vue.backup +0 -131
  83. package/src/components/loader/LimitLoader/LimitLoader@v2.vue.backup +0 -174
  84. package/src/components/loader/TableLoader/TableColView.vue +0 -115
@@ -0,0 +1,4 @@
1
+ <template>
2
+ <div></div>
3
+ </template>
4
+ <script setup lang="ts"></script>
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <template v-for="(item, index) in $nodes" :key="item.paths">
3
+ <div class="fekit-node-loader" :data-level="level" :data-index="index" :data-paths="item.paths" v-bind="item.attrs" v-on="item.$events" v-html="item.value"></div>
4
+ <NodeLoader v-if="item.child" :nodes="item.child" :level="$level" :index="index" :paths="item.paths" />
5
+ </template>
6
+ </template>
7
+ <script setup lang="ts">
8
+ import { computed } from 'vue';
9
+ import NodeLoader from './NodeLoader.vue';
10
+
11
+ interface NodeProps {
12
+ label?: string | ((data: any) => string);
13
+ field?: string | ((data: any) => string);
14
+ model?: string | ((data: any) => string);
15
+ attrs?: Record<string, any> | ((data: any) => Record<string, any>);
16
+ clear?: boolean | ((data: any) => boolean);
17
+ media?: string | ((data: any) => string);
18
+ value?: any | ((data: any) => any);
19
+ event?: Record<string, any> | ((data: any) => Record<string, any>);
20
+ child?: NodeProps[];
21
+ }
22
+
23
+ interface Props {
24
+ nodes: NodeProps[];
25
+ level?: number;
26
+ index?: number;
27
+ paths?: string;
28
+ }
29
+ const props = withDefaults(defineProps<Props>(), {
30
+ nodes: () => [],
31
+ level: 0,
32
+ index: 0,
33
+ paths: '',
34
+ });
35
+
36
+ const $nodes = computed(() => {
37
+ return props.nodes.map((item, index) => {
38
+ const paths = props.paths ? `${props.paths}-${index}` : `${index}`;
39
+ const context = { node: item, level: props.level, index, paths } as const;
40
+
41
+ let attrs: any = item.attrs;
42
+ if (typeof attrs === 'function') {
43
+ try {
44
+ attrs = attrs(context);
45
+ } catch {
46
+ /* noop */
47
+ }
48
+ }
49
+
50
+ let value: any = (item as any).value;
51
+ if (typeof value === 'function') {
52
+ try {
53
+ value = value(context);
54
+ } catch {
55
+ /* noop */
56
+ }
57
+ }
58
+
59
+ let ev: any = (item as any).event;
60
+ if (typeof ev === 'function') {
61
+ try {
62
+ ev = ev(context);
63
+ } catch {
64
+ ev = undefined;
65
+ }
66
+ }
67
+
68
+ const $events: Record<string, any> = {};
69
+ if (ev && typeof ev === 'object') {
70
+ for (const key in ev) {
71
+ const fn = ev[key];
72
+ if (typeof fn === 'function') {
73
+ $events[key] = (...args: any[]) => fn(context, ...args);
74
+ }
75
+ }
76
+ }
77
+
78
+ return { ...item, index, paths, attrs, value, $events } as any;
79
+ });
80
+ });
81
+
82
+ const $level = computed(() => {
83
+ return props.level + 1;
84
+ });
85
+ </script>
@@ -170,7 +170,7 @@
170
170
  <div v-for="(item, idx) in node.other.suffix" v-html="item.value" v-bind="item.attrs" :key="idx"></div>
171
171
  </div>
172
172
  </div>
173
- <div v-if="$slots.submit" class="full-x" ui-flex="row lm">
173
+ <div v-if="$slots.submit" class="w-full" ui-flex="row lm">
174
174
  <div class="flex-fixed" :style="labelcss(node)">&nbsp;</div>
175
175
  <div class="flex-block"><slot name="submit"></slot></div>
176
176
  </div>
@@ -2,12 +2,19 @@
2
2
  <div class="flex-block pr">
3
3
  <template v-if="mode === 'view'">
4
4
  <slot :name="`${node.field}-value`" :data="data" :node="node" :bind.sync="bind">
5
- <div class="nt-ss"><div v-html="value" style="padding-top: 2px;"></div></div>
5
+ <div class="nt-ss"><div v-html="value" style="padding-top: 2px"></div></div>
6
6
  </slot>
7
7
  </template>
8
8
  <template v-else>
9
- <el-input v-if="node.model[0] === 'Input'" v-model="value" class="full-w" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted" />
10
- <el-input v-if="node.model[0] === 'TextArea'" v-model="value" class="full-w" v-bind="{ ...(node.model[1] || {}, { type: 'textarea', rows: 3 }) }" @input="setInteracted" @blur="setInteracted" />
9
+ <el-input v-if="node.model[0] === 'Input'" v-model="value" class="w-full" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted" />
10
+ <el-input
11
+ v-if="node.model[0] === 'Textarea'"
12
+ v-model="value"
13
+ class="w-full"
14
+ v-bind="{ ...(node.model[1] || {}, { type: 'textarea', rows: 3 }) }"
15
+ @input="setInteracted"
16
+ @blur="setInteracted"
17
+ />
11
18
  <el-select v-else-if="node.model[0] === 'Select'" v-model="value" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted">
12
19
  <el-option v-for="item in node.enums" :key="item.value" :label="item.label" :value="item.value"> </el-option>
13
20
  </el-select>
@@ -19,17 +26,35 @@
19
26
  </el-checkbox-group>
20
27
  <el-checkbox v-else-if="node.model[0] === 'Checkbox'" v-model="value" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted"> </el-checkbox>
21
28
  <el-switch v-else-if="node.model[0] === 'Switch'" v-model="value" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted"> </el-switch>
22
- <el-time-select v-else-if="node.model[0] === 'TimeSelect'" v-model="value" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted"> </el-time-select>
23
- <el-time-picker v-else-if="node.model[0] === 'TimePicker'" v-model="value" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted"> </el-time-picker>
24
- <el-date-picker v-else-if="node.model[0] === 'DatePicker'" v-model="value" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted"> </el-date-picker>
25
- <el-date-picker v-else-if="node.model[0] === 'DateTimePicker'" v-model="value" type="datetime" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted"> </el-date-picker>
26
- <el-cascader v-else-if="node.model[0] === 'Cascader'" v-model="value" :options="node.enums" v-bind="{ ...node.model[1] }" @input="setInteracted" @blur="setInteracted"></el-cascader>
29
+ <el-time-select v-else-if="node.model[0] === 'TimeSelect'" v-model="value" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted">
30
+ </el-time-select>
31
+ <el-time-picker v-else-if="node.model[0] === 'TimePicker'" v-model="value" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted">
32
+ </el-time-picker>
33
+ <el-date-picker v-else-if="node.model[0] === 'DatePicker'" v-model="value" v-bind="{ ...(node.model[1] || {}) }" @input="setInteracted" @blur="setInteracted">
34
+ </el-date-picker>
35
+ <el-date-picker
36
+ v-else-if="node.model[0] === 'DateTimePicker'"
37
+ v-model="value"
38
+ type="datetime"
39
+ v-bind="{ ...(node.model[1] || {}) }"
40
+ @input="setInteracted"
41
+ @blur="setInteracted"
42
+ >
43
+ </el-date-picker>
44
+ <el-cascader
45
+ v-else-if="node.model[0] === 'Cascader'"
46
+ v-model="value"
47
+ :options="node.enums"
48
+ v-bind="{ ...node.model[1] }"
49
+ @input="setInteracted"
50
+ @blur="setInteracted"
51
+ ></el-cascader>
27
52
  <gallery-value v-else-if="node.model[0] === 'SelectImg'" :form="data" :node="node" v-bind="{ ...node.model[1] }"></gallery-value>
28
53
  <!-- 自定义组件插槽 -->
29
54
  <slot v-else-if="node.model[0]" :name="node.model[0]" :data="data" :node="node" :bind.sync="bind"></slot>
30
55
  <!-- 自定义字段插槽 -->
31
56
  <slot v-else :name="`${node.field}-value`" :data="data" :node="node" :bind.sync="bind">
32
- <div class="nt-ss"><div v-html="value" style="padding-top: 2px;"></div></div>
57
+ <div class="nt-ss"><div v-html="value" style="padding-top: 2px"></div></div>
33
58
  </slot>
34
59
  <p v-show="error.verify === 'no'" class="form-loader-verify" :data-verify-type="error.co">{{ error.tips }}</p>
35
60
  </template>
@@ -44,28 +69,28 @@
44
69
  props: {
45
70
  mode: {
46
71
  type: String,
47
- default: 'edit'
72
+ default: 'edit',
48
73
  },
49
74
  node: {
50
75
  type: Object,
51
- default: () => ({})
76
+ default: () => ({}),
52
77
  },
53
78
  data: {
54
79
  type: Object,
55
- default: () => ({})
80
+ default: () => ({}),
56
81
  },
57
82
  interacted: {
58
83
  type: Boolean,
59
- default: false
60
- }
84
+ default: false,
85
+ },
61
86
  },
62
87
  data() {
63
88
  return {
64
89
  _interacted: false,
65
90
  bind: {
66
- value: null
91
+ value: null,
67
92
  },
68
- error: {}
93
+ error: {},
69
94
  };
70
95
  },
71
96
  created() {},
@@ -99,8 +124,8 @@
99
124
  this.$set(this.data, this.node.field, value);
100
125
  }
101
126
  this.validate();
102
- }
103
- }
127
+ },
128
+ },
104
129
  },
105
130
  methods: {
106
131
  async validate() {
@@ -166,7 +191,7 @@
166
191
  this.validate();
167
192
  }, 50);
168
193
  }
169
- }
194
+ },
170
195
  },
171
196
  watch: {
172
197
  bind: {
@@ -183,22 +208,22 @@
183
208
  this.$set(this.data, this.node.field, value);
184
209
  this.$set(this.bind, 'value', value);
185
210
  },
186
- deep: true
211
+ deep: true,
187
212
  },
188
213
  interacted: {
189
214
  handler(val) {
190
215
  this._interacted = val;
191
216
  this.validate();
192
217
  },
193
- deep: true
218
+ deep: true,
194
219
  },
195
220
  value: {
196
221
  handler() {
197
222
  this.validate();
198
223
  },
199
- deep: true
200
- }
201
- }
224
+ deep: true,
225
+ },
226
+ },
202
227
  };
203
228
  </script>
204
229
  <style>
@@ -0,0 +1,318 @@
1
+ <template>
2
+ <div id="layer-loader-root" :path="path" :class="`${!path ? '' : 'pr nl-ms'}`" :ui-lines="path ? line : null">
3
+ <template v-for="(item, idx) in data" :key="idx">
4
+ <div
5
+ ui-flex="row xm"
6
+ class="fekit-layer-loader-item ux-hover nx-ss r-ss pr z1"
7
+ :data-move="item._move"
8
+ :class="`${store.active === paths(idx) ? (store.error ? 'bg-risk+o-ss co-risk' : 'bg-main+o-ss co-main fekit-layer-node-active') : ''}${item?.attrs?.hide ? ' o-mm' : ''}`"
9
+ @mousedown="fMoveSta($event, data, idx, paths(idx))"
10
+ @mousemove="fMoveIng($event, item, paths(idx), false, item.child?.length && !item.__folding)"
11
+ @mouseout="fMoveOut($event, paths(idx))"
12
+ @mouseup="fMoveEnd($event, data, item, idx, paths(idx))"
13
+ >
14
+ <div class="hover:co-main" :ui-arrow="`${item.child ? '1' : '0'}`" :ui-folding="item.__folding" @click="item.__folding = item.child && !item.__folding"></div>
15
+ <div :id="`LID${path.replace(/\./g, '')}-${idx}`" :path="paths(idx)" ui-flex="row lt" class="flex-block ny-ss" @click="store.active = paths(idx)">
16
+ <slot name="prefix" :item="item" :path="paths(idx)">
17
+ <i :class="`ml-ss mr-xs o-ms icon icon-model-${!path ? 'label' : item.model || (item.child ? 'area' : 'null')}`"></i>
18
+ </slot>
19
+ <slot name="item" :item="item" :path="paths(idx)">
20
+ <span class="ux-none" ui-omit="1">
21
+ {{ (item.model === 'text' || (!item.model && !item.child) ? item.value : null) || item.label || word(label(item.model)) || '‐‐' }}{{ item.__folding ? ' ⋯' : '' }}
22
+ </span>
23
+ </slot>
24
+ <slot name="suffix" :item="item" :path="paths(idx)"></slot>
25
+ </div>
26
+ <slot name="tools" :data="data" :item="item" :path="paths(idx)">
27
+ <div ui-flex="row rm" class="layer-loader-tool parent-hover:show fs-xs" :data-model="item.model">
28
+ <div ui-tips="@a co:well ux:hover">
29
+ <button ui-btn="@a none s :square">
30
+ <i class="icon icon-add"></i>
31
+ </button>
32
+ <div ui-tips-box="bl">
33
+ <div class="n-sm nowrap fs-ss">
34
+ <ul class="nx-sm-sub ny-ss-sub">
35
+ <li class="r-sm ux-hover" @click="fAddArea(item, data, path, idx)">用容器包裹</li>
36
+ <li class="b-solid bk-line bb-xs n-no my-ss" v-if="isBoxNode(item.model)"></li>
37
+ <li class="r-sm ux-hover" v-if="isBoxNode(item.model)" @click="fAddNode(item, data, path, idx)">添加到内部</li>
38
+ <li class="b-solid bk-line bb-xs n-no my-ss"></li>
39
+ <li class="r-sm ux-hover" @click="fAddNode(item, data, path, idx, 'prev')">添加到前面</li>
40
+ <li class="r-sm ux-hover" @click="fAddNode(item, data, path, idx, 'next')">添加到后面</li>
41
+ <li class="b-solid bk-line bb-xs n-no my-ss"></li>
42
+ <li class="r-sm ux-hover" @click="fAddNode(item, data, path, idx, 'prev', 1)">复制到前面</li>
43
+ <li class="r-sm ux-hover" @click="fAddNode(item, data, path, idx, 'next', 1)">复制到后面</li>
44
+ </ul>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ <button ui-btn="@a none s :square" @click="fDelNode(item, data, idx)"><i class="icon icon-delete"></i></button>
49
+ </div>
50
+ <button ui-btn="@a none s :square" class="layer-loader-tool fs-xs" :class="item?.attrs?.hide ? '' : 'parent-hover:show'" @click="fhideNode(item)">
51
+ <i class="icon" :class="item?.attrs?.hide ? 'icon-hide' : 'icon-view'"></i>
52
+ </button>
53
+ </slot>
54
+ </div>
55
+ <LayerLoader v-if="item.child && !item.__folding" :data="item.child" :path="paths(idx)" :class="`${item?.attrs?.hide ? ' o-mm' : ''}`">
56
+ <template #prefix="{ item = {}, path = '' }: any = {}"><slot name="prefix" :item="item" :path="path"></slot></template>
57
+ <template #item="{ item = {}, path = '' }: any = {}"><slot name="item" :item="item" :path="path"></slot></template>
58
+ <template #suffix="{ item = {}, path = '' }: any = {}"><slot name="suffix" :item="item" :path="path"></slot></template>
59
+ <template #tools="{ item = {}, path = '' }: any = {}"><slot name="tools" :item="item" :path="path"></slot></template>
60
+ </LayerLoader>
61
+ <div
62
+ v-if="item.child?.length && !item.__folding"
63
+ ui-flex="row lm"
64
+ class="pr z1"
65
+ style="height: 0.5em"
66
+ :data-label="(item.model === 'text' || (!item.model && !item.child) ? item.value : null) || item.label || item.model || '‐‐'"
67
+ :data-move="item._move"
68
+ @mousemove="fMoveIng($event, item, paths(idx), true)"
69
+ @mouseout="fMoveOut($event, paths(idx))"
70
+ @mouseup="fMoveEnd($event, data, item, idx, paths(idx))"
71
+ ></div>
72
+ </template>
73
+ </div>
74
+ </template>
75
+ <script setup lang="ts">
76
+ import { nextTick, reactive, ref, watch, onMounted } from 'vue';
77
+ import LayerLoader from './LayerLoader.vue';
78
+ import { useBasicStore, useWorksStore, storeToRefs } from '@/stores';
79
+ import { deepcopy } from '@fekit/utils';
80
+ import scrollto from '@fekit/scrollto';
81
+
82
+ // 事件定义
83
+ const store: any = useWorksStore();
84
+ const base: any = useBasicStore();
85
+ const { word } = base;
86
+
87
+ // 类型定义
88
+ interface Props {
89
+ data?: Array<any>;
90
+ path?: string;
91
+ line?: boolean;
92
+ }
93
+ // 外部入参
94
+ const props: any = withDefaults(defineProps<Props>(), {
95
+ data: () => [],
96
+ path: '',
97
+ line: true,
98
+ });
99
+
100
+ // 内部状态
101
+ const state: any = reactive({});
102
+ const tools: any = ref(null);
103
+
104
+ const ph = ref(0);
105
+ onMounted(() => {
106
+ const side = document.getElementById('side-layerloader');
107
+ ph.value = side?.clientHeight || 0;
108
+ });
109
+
110
+ // 计算路径
111
+ const paths = (idx: number) => {
112
+ return props.path ? `${props.path}-${idx}` : `${idx}`;
113
+ };
114
+
115
+ function unfoldActivePath(data: any, activePath: any) {
116
+ if (!activePath) return;
117
+ const indices = activePath.split('-').map(Number);
118
+ let cur = data;
119
+ for (let i = 0; i < indices.length; i++) {
120
+ const idx = indices[i];
121
+ if (!cur || !cur[idx]) break;
122
+ cur[idx].__folding = false;
123
+ cur = cur[idx].child;
124
+ }
125
+ }
126
+
127
+ if (!props.path) {
128
+ watch(
129
+ () => store.active,
130
+ (newActive) => {
131
+ unfoldActivePath(props.data, newActive);
132
+
133
+ nextTick(() => {
134
+ const el = document.getElementById(`LID${newActive.replace(/\./g, '')}`);
135
+ if (el && !store.isMouseInLayer) {
136
+ scrollto({
137
+ el: '#side-layerloader',
138
+ to: {
139
+ y: el,
140
+ },
141
+ offset: {
142
+ y: -(ph.value / 2.5),
143
+ },
144
+ time: 600,
145
+ });
146
+ }
147
+ });
148
+ },
149
+ );
150
+ }
151
+
152
+ // 查找枚举
153
+ const label = (item: any) => {
154
+ return base.enums?.sys_models?.find((e: any) => e.value === item)?.label || item;
155
+ };
156
+
157
+ // 是容器节点
158
+ const isBoxNode = (model: string) => {
159
+ return !['data', 'text', 'icon', 'code', 'draw'].includes(model);
160
+ };
161
+
162
+ // 添加节点
163
+ const fAddNode = async (item: any = {}, _data: any = [], _path: any = '', _idx: number = 0, pos: any = null, copy: any = 0) => {
164
+ if (pos) {
165
+ if (pos === 'prev') {
166
+ // 加到前面
167
+ _data.splice(
168
+ _idx,
169
+ 0,
170
+ copy
171
+ ? deepcopy(item)
172
+ : {
173
+ label: '',
174
+ model: '',
175
+ value: '',
176
+ attrs: {},
177
+ },
178
+ );
179
+ store.active = `${_path}-${_idx}`;
180
+ } else if (pos === 'next') {
181
+ // 加到后面
182
+ _data.splice(
183
+ _idx + 1,
184
+ 0,
185
+ copy
186
+ ? deepcopy(item)
187
+ : {
188
+ label: '',
189
+ model: '',
190
+ value: '',
191
+ attrs: {},
192
+ },
193
+ );
194
+ store.active = `${_path}-${_idx + 1}`;
195
+ }
196
+ } else {
197
+ if (!item.child) {
198
+ item.child = [];
199
+ }
200
+ await item.child.push({
201
+ label: '',
202
+ model: '',
203
+ value: '',
204
+ attrs: {},
205
+ });
206
+ store.active = `${_path}-${_idx}-${item.child.length - 1}`;
207
+ }
208
+ };
209
+
210
+ // 包裹容器
211
+ const fAddArea = (item: any = {}, data: any = [], path: any = '', idx: number = 0, pos: any = null, copy: any = 0) => {
212
+ // 1. 构造新的 area 节点
213
+ const areaNode = {
214
+ model: 'area',
215
+ attrs: {},
216
+ child: [item],
217
+ param: {},
218
+ };
219
+ // 2. 替换 data 中的当前节点
220
+ data.splice(idx, 1, areaNode);
221
+ // 3. 设置 active 到新节点
222
+ store.active = path ? `${path}-${idx}` : `${idx}`;
223
+ };
224
+
225
+ // 删除节点
226
+ const fDelNode = (_item: any = {}, data: any = [], idx: number = 0) => {
227
+ if (data.length > 0) {
228
+ data.splice(idx, 1);
229
+ }
230
+ };
231
+ const fhideNode = (_item: any = {}) => {
232
+ _item.attrs.hide = _item.attrs.hide ? 0 : 1;
233
+ };
234
+
235
+ // 是否同祖
236
+ function inform(from: string, data: string) {
237
+ const _form = from.split('.');
238
+ const _data = data.split('.');
239
+ return _form.every((part, index) => part === _data[index]);
240
+ }
241
+
242
+ // 按住
243
+ const fMoveSta = (ev: any, data: any, idx: number, paths: any) => {
244
+ if (paths.length > 1) {
245
+ store.layer.moveing = true;
246
+ store.layer.from = { data, idx, dom: ev?.currentTarget, y: ev.clientY, paths };
247
+ }
248
+ };
249
+ const fMoveIng = (ev: any, item: any, paths: any, isend: boolean = false, ischildandnofold: boolean = false) => {
250
+ if (!store.layer.moveing || paths.length <= 1) return;
251
+ const dom = ev?.currentTarget;
252
+ if (!dom || dom === store.layer.from.dom) return;
253
+ const rect = dom.getBoundingClientRect();
254
+ const thirdHeight = rect.height / 3 || 1;
255
+ const offsetY = ev?.layerY ?? ev?.offsetY ?? 0;
256
+ let mode = 'prev';
257
+ if (offsetY > thirdHeight * 2 || isend) {
258
+ mode = ischildandnofold ? 'inset' : 'next';
259
+ } else if (offsetY > thirdHeight && offsetY < thirdHeight * 2) {
260
+ if (isBoxNode(item.model)) {
261
+ mode = 'inset';
262
+ }
263
+ }
264
+ store.layer.correct = mode;
265
+ dom.setAttribute('data-ins', mode);
266
+ };
267
+ // 移出
268
+ const fMoveOut = (ev: any, paths: any) => {
269
+ if (store.layer.moveing && paths.length > 1) {
270
+ ev?.currentTarget?.removeAttribute('data-ins');
271
+ }
272
+ };
273
+ // 松开
274
+ const fMoveEnd = (ev: any, data: any, item: any, idx: number, paths: any) => {
275
+ console.log(207, data, item);
276
+ if (store.layer.moveing && paths.length > 1 && !inform(store.layer.from.paths, paths)) {
277
+ const from = store.layer.from;
278
+ if (from.data && from.dom !== ev?.currentTarget) {
279
+ const isAdjacent =
280
+ (store.layer.correct === 'prev' && from.dom?.nextElementSibling === ev?.currentTarget) ||
281
+ (store.layer.correct === 'next' && from.dom?.previousElementSibling === ev?.currentTarget) ||
282
+ (store.layer.correct === 'inset' && (from.dom?.contains(ev?.currentTarget) || ev?.currentTarget?.contains(from.dom)));
283
+
284
+ if (!isAdjacent) {
285
+ const [node] = from.data.splice(from.idx, 1);
286
+ let newPath = paths;
287
+
288
+ // Adjust target index if it's after the removed item in the same array
289
+ let targetIdx = idx;
290
+ if (from.data === data && from.idx < idx) {
291
+ targetIdx -= 1;
292
+ }
293
+
294
+ if (store.layer.correct === 'prev') {
295
+ data.splice(targetIdx, 0, node);
296
+ newPath = props.path ? `${props.path}-${targetIdx}` : `${targetIdx}`;
297
+ } else if (store.layer.correct === 'next') {
298
+ const insertIndex = targetIdx + 1;
299
+ data.splice(insertIndex, 0, node);
300
+ newPath = props.path ? `${props.path}-${insertIndex}` : `${insertIndex}`;
301
+ } else if (store.layer.correct === 'inset') {
302
+ if (!item.child) item.child = [];
303
+ const targetIndex = item.child.length;
304
+ item.child.push(node);
305
+ newPath = paths + '-' + targetIndex;
306
+ }
307
+
308
+ requestAnimationFrame(() => {
309
+ store.active = newPath;
310
+ });
311
+ }
312
+ }
313
+ }
314
+
315
+ ev?.currentTarget?.removeAttribute('data-ins');
316
+ store.layer.moveing = false;
317
+ };
318
+ </script>
@@ -0,0 +1,2 @@
1
+ import LayerLoader from './LayerLoader.vue';
2
+ export default LayerLoader;
@@ -0,0 +1,77 @@
1
+ .fekit-layer-loader-item {
2
+ user-select: none;
3
+ line-height: 1.2;
4
+ }
5
+
6
+ // 箭头
7
+ [ui-arrow] {
8
+ position: relative;
9
+ width: 1em;
10
+ height: 1em;
11
+ left: 0.1em;
12
+
13
+ // &[ui-arrow~='0'] {
14
+ // &::before {
15
+ // position: absolute;
16
+ // display: inline-block;
17
+ // content: '';
18
+ // width: 0.5em;
19
+ // height: 0.5em;
20
+ // border: 1px solid currentColor;
21
+ // top: 0.25em;
22
+ // left: 0.3em;
23
+ // border-radius: 50%;
24
+ // }
25
+ // }
26
+ &[ui-arrow~='0'] {
27
+ height: 1px;
28
+ border-bottom: 1px dotted var(--co-case);
29
+ position: relative;
30
+ left: -5px;
31
+ }
32
+
33
+ &[ui-arrow~='1'] {
34
+ &::before {
35
+ position: absolute;
36
+ display: inline-block;
37
+ content: '';
38
+ width: 0;
39
+ height: 0;
40
+ border-width: 0.35em 0 0.35em 0.35em;
41
+ border-style: solid;
42
+ border-color: transparent;
43
+ border-left-color: transparent;
44
+ border-left-color: currentColor;
45
+ top: 0.2em;
46
+ left: 0.35em;
47
+ transform: rotate(90deg);
48
+ border-radius: 25%;
49
+ }
50
+ }
51
+
52
+ &[ui-folding~='true']::before {
53
+ transform: rotate(0deg);
54
+ }
55
+ }
56
+
57
+ // 线条
58
+ [ui-lines] {
59
+ position: relative;
60
+ &::before {
61
+ position: absolute;
62
+ content: '';
63
+ display: block;
64
+ width: 5px;
65
+ height: 100%;
66
+ left: 0.85em;
67
+
68
+ border-left: 1px dotted var(--co-case);
69
+ border-bottom: 1px dotted var(--co-case);
70
+ }
71
+ }
72
+
73
+ .fekit-layer-node-active {
74
+ .layer-loader-tool {
75
+ opacity: 1;
76
+ }
77
+ }