@cicctencent/low-code-editor 0.0.0-stage → 1.1.9-beta.5

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 (97) hide show
  1. package/README.md +2 -2
  2. package/api-extractor.json +36 -0
  3. package/dist/ActivityBar/index.vue.d.ts +29 -0
  4. package/dist/ComponentTree/components/List.vue.d.ts +29 -0
  5. package/dist/ComponentTree/index.vue.d.ts +32 -0
  6. package/dist/DataSource/index.vue.d.ts +34 -0
  7. package/dist/HeaderBar/components/BarTooltip.vue.d.ts +37 -0
  8. package/dist/HeaderBar/index.vue.d.ts +49 -0
  9. package/dist/NavTree/index.vue.d.ts +48 -0
  10. package/dist/SchemaConfig/index.vue.d.ts +36 -0
  11. package/dist/SidebarPane/index.vue.d.ts +38 -0
  12. package/dist/components/ComponentTreeFavorites/components/List.vue.d.ts +41 -0
  13. package/dist/components/ComponentTreeFavorites/components/Tips.vue.d.ts +16 -0
  14. package/dist/components/ComponentTreeFavorites/index.vue.d.ts +44 -0
  15. package/dist/components/ImageGuide/index.vue.d.ts +45 -0
  16. package/dist/components.d.ts +7 -0
  17. package/dist/composables/useComponentTree.d.ts +13 -0
  18. package/dist/config/ace.config.d.ts +3 -0
  19. package/dist/domain/EditorDomain.d.ts +89 -0
  20. package/dist/editor.d.ts +286 -0
  21. package/dist/editor.vue.d.ts +104 -0
  22. package/dist/formily/ActivityBar/index.d.ts +4 -0
  23. package/dist/formily/ComponentTree/index.d.ts +4 -0
  24. package/dist/formily/DataBinding/index.d.ts +4 -0
  25. package/dist/formily/DataBinding/index.vue.d.ts +26 -0
  26. package/dist/formily/DataSource/index.d.ts +4 -0
  27. package/dist/formily/MenuTable/PageList.vue.d.ts +28 -0
  28. package/dist/formily/MenuTable/index.d.ts +4 -0
  29. package/dist/formily/MenuTable/index.vue.d.ts +30 -0
  30. package/dist/formily/MenuTable/useMenuTable.d.ts +227 -0
  31. package/dist/formily/NavTree/index.d.ts +4 -0
  32. package/dist/formily/SidebarPane/index.d.ts +4 -0
  33. package/dist/formily/index.d.ts +2 -0
  34. package/dist/index.css +1167 -0
  35. package/dist/index.d.ts +250 -0
  36. package/dist/index.js +34171 -0
  37. package/dist/utils/base64.d.ts +4 -0
  38. package/dist/utils/index.d.ts +27 -0
  39. package/package.json +58 -4
  40. package/rollup.config.js +3 -0
  41. package/src/ActivityBar/index.vue +71 -0
  42. package/src/ComponentTree/components/List.vue +310 -0
  43. package/src/ComponentTree/index.vue +77 -0
  44. package/src/DataSource/index.vue +640 -0
  45. package/src/HeaderBar/components/BarDialog.vue +43 -0
  46. package/src/HeaderBar/components/BarTooltip.vue +33 -0
  47. package/src/HeaderBar/index.vue +513 -0
  48. package/src/NavTree/index.vue +345 -0
  49. package/src/SchemaConfig/index.vue +150 -0
  50. package/src/SidebarPane/index.vue +199 -0
  51. package/src/SynBarComponent/index.vue +31 -0
  52. package/src/assets/font/NotoSansSC.ttf +0 -0
  53. package/src/assets/img/header/edit.png +0 -0
  54. package/src/assets/img/header/link.png +0 -0
  55. package/src/assets/img/header/link.svg +9 -0
  56. package/src/assets/img/header/preview.png +0 -0
  57. package/src/assets/img/header/preview.svg +9 -0
  58. package/src/assets/img/header/redo.svg +1 -0
  59. package/src/assets/img/header/undo.svg +1 -0
  60. package/src/assets/img/tool/all-select.svg +9 -0
  61. package/src/assets/img/tool/all.svg +9 -0
  62. package/src/assets/img/tool/collect.svg +6 -0
  63. package/src/assets/img/tool/collection-select.svg +3 -0
  64. package/src/assets/img/tool/collection-tag.svg +5 -0
  65. package/src/assets/img/tool/info.svg +4 -0
  66. package/src/assets/img/tool/union.svg +4 -0
  67. package/src/components/ComponentTreeFavorites/components/List.vue +452 -0
  68. package/src/components/ComponentTreeFavorites/components/Tips.vue +108 -0
  69. package/src/components/ComponentTreeFavorites/index.vue +180 -0
  70. package/src/components/ImageGuide/index.vue +100 -0
  71. package/src/components.ts +23 -0
  72. package/src/composables/useComponentTree.ts +38 -0
  73. package/src/config/ace.config.ts +22 -0
  74. package/src/domain/EditorDomain.ts +265 -0
  75. package/src/editor.ts +645 -0
  76. package/src/editor.vue +380 -0
  77. package/src/formily/ActivityBar/index.ts +23 -0
  78. package/src/formily/ActivityBar/index.vue +121 -0
  79. package/src/formily/ComponentTree/index.ts +22 -0
  80. package/src/formily/DataBinding/index.ts +22 -0
  81. package/src/formily/DataBinding/index.vue +285 -0
  82. package/src/formily/DataSource/index.ts +22 -0
  83. package/src/formily/MenuTable/PageList.vue +132 -0
  84. package/src/formily/MenuTable/index.ts +19 -0
  85. package/src/formily/MenuTable/index.vue +218 -0
  86. package/src/formily/MenuTable/useMenuTable.ts +147 -0
  87. package/src/formily/NavTree/index.ts +20 -0
  88. package/src/formily/SidebarPane/index.ts +23 -0
  89. package/src/formily/SidebarPane/index.vue +174 -0
  90. package/src/formily/index.ts +12 -0
  91. package/src/index.ts +29 -0
  92. package/src/typings/vue-shim.d.ts +13 -0
  93. package/src/utils/base64.ts +5 -0
  94. package/src/utils/index.ts +57 -0
  95. package/test/case.ts +67 -0
  96. package/test/utils/index.test.ts +27 -0
  97. package/tsconfig.json +8 -0
@@ -0,0 +1,285 @@
1
+ <template>
2
+ <div class="data-binding">
3
+ <VueForm :schema="config" :model-value="formData" />
4
+ <div class="setter-actions" @click="onClickIcon">
5
+ <span class="title">
6
+ <b class="title-icon">
7
+ <svg
8
+ fill="currentColor"
9
+ preserveAspectRatio="xMidYMid meet"
10
+ width="20"
11
+ height="20"
12
+ viewBox="0 0 1024 1024"
13
+ data-spm-anchor-id="a2q5o.26736379.0.i29.1c952a4bJg2W1k"
14
+ >
15
+ <path
16
+ d="M596.32 263.392c18.048 6.56 27.328 26.496 20.8 44.512l-151.04 414.912a34.72 34.72 0 1 1-65.28-23.744l151.04-414.912a34.72 34.72 0 0 1 44.48-20.768zM220.64 192H273.6v55.488H233.024c-26.112 0-38.464 14.4-38.464 44.544v134.304c0 42.496-19.936 71.264-59.104 85.664 39.168 16.448 59.104 44.544 59.104 85.664v134.976c0 28.8 12.352 43.84 38.464 43.84H273.6V832H220.672c-30.24 0-53.6-10.272-70.08-29.44-15.136-17.856-22.72-42.496-22.72-72.64v-128.832c0-19.872-4.096-34.24-12.352-43.2-9.6-10.944-26.784-16.416-51.52-17.792v-56.192c24.736-1.376 41.92-7.52 51.52-17.824 8.256-9.6 12.384-24 12.384-43.168V294.784c0-30.848 7.552-55.488 22.688-73.312C167.04 201.6 190.4 192 220.672 192z m529.792 0h52.896c30.24 0 53.6 9.6 70.08 29.44 15.136 17.856 22.72 42.496 22.72 73.344v128.128c0 19.2 4.096 34.24 13.024 43.84 8.96 9.6 26.112 15.776 50.848 17.152v56.192c-24.736 1.376-41.92 6.848-51.52 17.824-8.256 8.896-12.384 23.296-12.384 43.168v128.8c0 30.176-7.552 54.816-22.688 72.64-16.48 19.2-39.84 29.472-70.08 29.472h-52.896v-55.488h40.544c25.408 0 38.464-15.104 38.464-43.84v-135.04c0-41.088 19.232-69.184 59.104-85.632-39.872-14.4-59.104-43.168-59.104-85.664V292.032c0-30.144-13.056-44.544-38.464-44.544H750.4V192z"
17
+ ></path>
18
+ </svg>
19
+ </b>
20
+ </span>
21
+ </div>
22
+ <el-dialog
23
+ v-model="dialogVisible"
24
+ title="变量绑定"
25
+ width="80%"
26
+ append-to-body
27
+ destroy-on-close
28
+ >
29
+ <div class="variable-dialog-content">
30
+ <div class="variable-selector">
31
+ <p class="variable-title">变量列表</p>
32
+ <div class="variable-selector-inner">
33
+ <ul class="variable-selector-category">
34
+ <li class="active">数据源</li>
35
+ </ul>
36
+ <div class="variable-selector-items-container">
37
+ <div class="selector-search-control">
38
+ <el-input
39
+ v-model="keyword"
40
+ @input="onInputChange"
41
+ placeholder="搜索"
42
+ :suffix-icon="Search"
43
+ />
44
+ </div>
45
+ <ul class="variable-selector-items">
46
+ <li
47
+ v-for="item in itemList"
48
+ :key="item.value"
49
+ @click="onItemClick(item)"
50
+ >
51
+ {{ item.label }}
52
+ </li>
53
+ </ul>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ <div class="variable-content">
58
+ <p class="variable-title">变量</p>
59
+ <div class="code-control">
60
+ <v-ace-editor
61
+ v-model:value="content"
62
+ :options="{ showPrintMargin: false }"
63
+ theme="chrome"
64
+ lang="typescript"
65
+ style="height: 320px"
66
+ />
67
+ </div>
68
+ </div>
69
+ </div>
70
+ <template #footer>
71
+ <span class="dialog-footer">
72
+ <el-button @click="onCancel">取消</el-button>
73
+ <el-button type="primary" @click="onConfirm"> 确定 </el-button>
74
+ </span>
75
+ </template>
76
+ </el-dialog>
77
+ </div>
78
+ </template>
79
+
80
+ <script lang="ts" setup>
81
+ // @ts-ignore
82
+ import { PropType, computed, reactive, ref, watch, defineProps, defineEmits } from 'vue';
83
+ import '../../config/ace.config';
84
+ import { VAceEditor } from 'vue3-ace-editor';
85
+ import { VueForm } from '@jt/formily';
86
+ import { Search } from '@jt/icons-vue';
87
+ import { DataSource } from '@jt/low-code-core';
88
+ const props = defineProps({
89
+ schema: Object,
90
+ modelValue: String,
91
+ sourceList: {
92
+ type: Array as PropType<DataSource[]>,
93
+ default: () => [],
94
+ },
95
+ });
96
+ const emits = defineEmits(['update:modelValue', 'getBindingValue']);
97
+
98
+ const dialogVisible = ref(false);
99
+ // 绑定的内容
100
+ const content = ref('');
101
+ // schema唯一表单项的key
102
+ const key = 'value';
103
+ // 表单数据
104
+ const formData = reactive<any>({});
105
+ // 搜索数据源名称关键字
106
+ const keyword = ref('');
107
+ // 展示的列表
108
+ const itemList = ref([]);
109
+ // 完整的列表
110
+ const stateList = computed(() => {
111
+ const defaultList = [
112
+ {
113
+ label: 'state.form',
114
+ value: '$form',
115
+ },
116
+ {
117
+ label: 'state.urlParams',
118
+ value: '$state.urlParams',
119
+ },
120
+ ];
121
+ if (Array.isArray(props.sourceList)) {
122
+ return [
123
+ ...defaultList,
124
+ ...props.sourceList.map(v => ({
125
+ label: `state.${v.name}`,
126
+ value: `$state.${v.name}`,
127
+ })),
128
+ ];
129
+ }
130
+ return defaultList;
131
+ });
132
+ // 表单schema配置
133
+ const config = computed(() => ({
134
+ [key]: {
135
+ ...props.schema,
136
+ },
137
+ }));
138
+ watch(
139
+ () => props.modelValue,
140
+ val => {
141
+ content.value = val;
142
+ },
143
+ { immediate: true }
144
+ );
145
+ watch(
146
+ stateList,
147
+ list => {
148
+ itemList.value = list;
149
+ },
150
+ { immediate: true, deep: true }
151
+ );
152
+ /* 点击图标触发的事件 */
153
+ const onClickIcon = () => {
154
+ dialogVisible.value = true;
155
+ };
156
+ /* 点击对话框确定按钮 */
157
+ const onConfirm = () => {
158
+ dialogVisible.value = false;
159
+ // 抛出事件更新值
160
+ emits('update:modelValue', content.value);
161
+ // 抛出事件 由模拟器返回真实数据
162
+ emits('getBindingValue', value => {
163
+ // FIXME: formData变化 展示数据不变化
164
+ formData[key] = value;
165
+ });
166
+ };
167
+ /* 选中state */
168
+ const onItemClick = item => {
169
+ content.value = item.value;
170
+ };
171
+ /* 点击对话框取消按钮 */
172
+ const onCancel = () => {
173
+ dialogVisible.value = false;
174
+ };
175
+ /* 关键字输入框输入值变化 */
176
+ const onInputChange = val => {
177
+ itemList.value = stateList.value.filter(v => v.label.includes(val));
178
+ };
179
+ </script>
180
+
181
+ <style lang="scss" scoped>
182
+ .data-binding {
183
+ position: relative;
184
+ .setter-actions {
185
+ position: absolute;
186
+ right: 0;
187
+ top: 0;
188
+ transform: none;
189
+ cursor: pointer;
190
+ display: flex;
191
+ align-items: center;
192
+ .title {
193
+ background: #006cff;
194
+ color: #fff !important;
195
+ border-radius: 3px;
196
+ .title-icon {
197
+ display: flex;
198
+ align-items: center;
199
+ }
200
+ }
201
+ .only-icon {
202
+ background: #fff;
203
+ color: #8f9bb3;
204
+ }
205
+ }
206
+ &:deep(.formily-element-plus-form-item-control-content-component) {
207
+ justify-content: flex-start;
208
+ }
209
+ }
210
+ .variable-dialog-content {
211
+ display: flex;
212
+ box-sizing: border-box;
213
+ .variable-selector {
214
+ width: 270px;
215
+ flex-shrink: 0;
216
+ flex-grow: 0;
217
+ .variable-selector-inner {
218
+ display: flex;
219
+ border: 1px solid rgba(31, 56, 88, 0.3);
220
+ border-radius: 3px;
221
+ height: calc(100% - 28px);
222
+ .variable-selector-category {
223
+ width: 110px;
224
+ flex-shrink: 0;
225
+ flex-grow: 0;
226
+ border-right: 1px solid rgba(31, 56, 88, 0.2);
227
+ li {
228
+ height: 28px;
229
+ line-height: 28px;
230
+ padding: 0 12px;
231
+ cursor: pointer;
232
+ position: relative;
233
+ overflow: hidden;
234
+ text-overflow: ellipsis;
235
+ white-space: nowrap;
236
+ }
237
+ .active {
238
+ background: rgba(31, 56, 88, 0.06);
239
+ }
240
+ }
241
+ .variable-selector-items-container {
242
+ width: 157px;
243
+ .selector-search-control {
244
+ margin: 10px;
245
+ height: 30px;
246
+ }
247
+ .variable-selector-items {
248
+ overflow-y: auto;
249
+ overflow-x: hidden;
250
+ height: 270px;
251
+ li {
252
+ height: 28px;
253
+ line-height: 28px;
254
+ padding: 0 12px;
255
+ cursor: pointer;
256
+ position: relative;
257
+ overflow: hidden;
258
+ text-overflow: ellipsis;
259
+ white-space: nowrap;
260
+ }
261
+ }
262
+ }
263
+ ul {
264
+ margin: 0;
265
+ padding: 0;
266
+ list-style-type: none;
267
+ li:hover {
268
+ background: rgba(31, 56, 88, 0.04);
269
+ }
270
+ }
271
+ }
272
+ }
273
+ .variable-content {
274
+ margin-left: 12px;
275
+ flex-grow: 1;
276
+ }
277
+ .variable-title {
278
+ font-weight: 700;
279
+ margin-bottom: 8px;
280
+ color: rgba(0, 0, 0, 0.8);
281
+ display: flex;
282
+ align-items: center;
283
+ }
284
+ }
285
+ </style>
@@ -0,0 +1,22 @@
1
+ import { connect, mapProps } from '@formily/vue';
2
+ import { transformComponent } from '@jt/formily';
3
+ import JtDataSource from '../../dataSource/index.vue';
4
+
5
+ export type JtDataSourceProps = typeof JtDataSource;
6
+
7
+ const TransformJtDataSource = transformComponent<JtDataSourceProps>(
8
+ JtDataSource,
9
+ {
10
+ change: 'update:modelValue',
11
+ }
12
+ );
13
+
14
+ export const ActivityBar = connect(
15
+ TransformJtDataSource,
16
+ mapProps({
17
+ value: 'modelValue',
18
+ readOnly: 'readonly',
19
+ })
20
+ );
21
+
22
+ export default ActivityBar;
@@ -0,0 +1,132 @@
1
+ <template>
2
+ <div class="page-list">
3
+ <div class="input" style="background-color: #f7f7f7">
4
+ <el-input
5
+ placeholder="搜索..."
6
+ :prefix-icon="Search"
7
+ v-model="searchValue"
8
+ clearable
9
+ />
10
+ </div>
11
+ <div class="title" style="background-color: #eeeeee">
12
+ {{ project.projectName }}(项目名称)
13
+ </div>
14
+ <ul class="name-list">
15
+ <template :key="page.id" v-for="page in pages">
16
+ <li class="page-item" @click="bindPage(page)">
17
+ {{ page.title }}
18
+ </li>
19
+ </template>
20
+ </ul>
21
+ <div v-if="modelValue" class="show-area" style="background-color: #f7f7f7">
22
+ <span>绑定页面:{{ pageName }}</span>
23
+ <span class="remove-icon" @click="unbindPage">
24
+ <el-icon><CircleClose /></el-icon>
25
+ <span style="padding-left: 5px">移除</span>
26
+ </span>
27
+ </div>
28
+ </div>
29
+ </template>
30
+
31
+ <script lang="ts" setup>
32
+ // @ts-nocheck
33
+ import {
34
+ computed,
35
+ ref,
36
+ watch,
37
+ withDefaults,
38
+ defineProps,
39
+ defineEmits,
40
+ } from 'vue';
41
+ import { Search, CircleClose } from '@jt/icons-vue';
42
+
43
+ const props = withDefaults(
44
+ defineProps<{
45
+ modelValue: number;
46
+ project: any;
47
+ }>(),
48
+ {
49
+ modelValue: 0,
50
+ }
51
+ );
52
+
53
+ const emits = defineEmits(['update:modelValue']);
54
+
55
+ // 输入的搜索关键字
56
+ const searchValue = ref('');
57
+
58
+ // 当前绑定的页面名
59
+ const pageName = ref('');
60
+
61
+ // 当前展示的页面列表(不包括关键字过滤掉的)
62
+ const pages = computed(() =>
63
+ props.project.pages
64
+ ? props.project.pages
65
+ .map(page => ({ title: page.title, id: page.id }))
66
+ .filter(p => p.title.includes(searchValue.value))
67
+ : []
68
+ );
69
+ watch(
70
+ () => props.modelValue,
71
+ id => {
72
+ pageName.value = pages.value.find(page => page.id === id)?.title ?? '';
73
+ },
74
+ { immediate: true }
75
+ );
76
+
77
+ /* 点击列表项绑定页面或者覆盖上一个绑定的页面 */
78
+ const bindPage = page => {
79
+ emits('update:modelValue', page.id);
80
+ pageName.value = page.title;
81
+ };
82
+
83
+ /* 点击移除图标解绑页面 */
84
+ const unbindPage = () => {
85
+ emits('update:modelValue', 0);
86
+ pageName.value = '';
87
+ };
88
+ </script>
89
+
90
+ <style lang="scss" scoped>
91
+ .page-list {
92
+ flex: 1;
93
+ margin-bottom: 18px;
94
+ border: 1px solid #6b7280;
95
+ border-radius: 5px;
96
+ overflow: hidden;
97
+ .input,
98
+ .title {
99
+ padding: 10px 15px 10px 15px;
100
+ }
101
+ .name-list {
102
+ list-style: none;
103
+ margin: 0;
104
+ padding: 0;
105
+ overflow: auto;
106
+ height: 150px;
107
+ li {
108
+ padding-left: 20px;
109
+ padding-right: 20px;
110
+ line-height: 30px;
111
+ cursor: pointer;
112
+ }
113
+ }
114
+ .show-area {
115
+ padding: 10px 15px 10px 15px;
116
+ display: flex;
117
+ justify-content: space-between;
118
+ .remove-icon {
119
+ display: flex;
120
+ justify-content: space-between;
121
+ align-items: center;
122
+ cursor: pointer;
123
+ }
124
+ }
125
+ }
126
+ .page-item {
127
+ transition: all 0.3s ease-in-out;
128
+ }
129
+ .page-item:hover {
130
+ background-color: #f5f7fa;
131
+ }
132
+ </style>
@@ -0,0 +1,19 @@
1
+ import { connect, mapProps } from '@formily/vue';
2
+ import { transformComponent } from '@jt/formily';
3
+ import JtMenuTable from './index.vue';
4
+
5
+ export type JtMenuTableProps = typeof JtMenuTable;
6
+
7
+ const TransformJtMenuTable = transformComponent<JtMenuTableProps>(JtMenuTable, {
8
+ change: 'update:modelValue',
9
+ });
10
+
11
+ export const MenuTable = connect(
12
+ TransformJtMenuTable,
13
+ mapProps({
14
+ value: 'modelValue',
15
+ readOnly: 'readonly',
16
+ })
17
+ );
18
+
19
+ export default MenuTable;
@@ -0,0 +1,218 @@
1
+ <template>
2
+ <el-table
3
+ :data="menuTree"
4
+ style="width: 100%"
5
+ row-key="name"
6
+ default-expand-all
7
+ >
8
+ <el-table-column prop="name" label="名称" width="180" />
9
+ <el-table-column label="图标" width="100">
10
+ <template #default="scope">
11
+ <div v-if="!scope.row.icon">无</div>
12
+ <div v-else>
13
+ <el-icon>
14
+ <component :is="ElIcons[scope.row.icon]" />
15
+ </el-icon>
16
+ </div>
17
+ </template>
18
+ </el-table-column>
19
+ <el-table-column label="导航类型" width="180">
20
+ <template #default="scope">
21
+ {{ scope.row.target === '_self' ? '本窗口打开' : '新窗口打开' }}
22
+ </template>
23
+ </el-table-column>
24
+ <el-table-column label="绑定界面" width="180" show-overflow-tooltip>
25
+ <template #default="scope">
26
+ <span v-if="scope.row.children.length">父级菜单</span>
27
+ <template v-else>
28
+ <span
29
+ v-if="scope.row.pageId && !scope.row.url"
30
+ class="binded-page"
31
+ :style="{ color: '#cc9c66' }"
32
+ >
33
+ <el-icon><Document /></el-icon>
34
+ <span>{{ pageNameMap[scope.row.pageId] }}</span>
35
+ </span>
36
+ <span v-else-if="scope.row.url" class="binded-page">
37
+ <el-icon><Link /></el-icon>
38
+ <el-link :href="scope.row.url" target="_blank">{{
39
+ scope.row.url
40
+ }}</el-link>
41
+ </span>
42
+ <span v-else :style="{ color: '#dd5547' }">未绑定</span>
43
+ </template>
44
+ </template>
45
+ </el-table-column>
46
+ <el-table-column label="操作" width="300" fixed="right">
47
+ <template #default="scope">
48
+ <el-button
49
+ size="small"
50
+ type="primary"
51
+ text
52
+ @click="addPeer(scope.$index, scope.row)"
53
+ >
54
+ 添加同级
55
+ </el-button>
56
+ <el-button
57
+ :disabled="scope.row.pageId || scope.row.url"
58
+ size="small"
59
+ type="primary"
60
+ text
61
+ @click="addSubordinate(scope.$index, scope.row)"
62
+ >
63
+ 添加下级
64
+ </el-button>
65
+ <el-button
66
+ size="small"
67
+ type="primary"
68
+ text
69
+ @click="handleEdit(scope.$index, scope.row)"
70
+ >
71
+ 编辑
72
+ </el-button>
73
+ <el-button
74
+ size="small"
75
+ type="danger"
76
+ text
77
+ @click="handleDelete(scope.$index, scope.row)"
78
+ >
79
+ 删除
80
+ </el-button>
81
+ </template>
82
+ </el-table-column>
83
+ </el-table>
84
+ <el-dialog
85
+ v-model="editModalOptions.visible"
86
+ :title="editModalOptions.title"
87
+ :width="editModalOptions.width"
88
+ append-to-body
89
+ >
90
+ <div class="menu-form">
91
+ <el-form :model="menuForm" ref="menuFormRef" label-width="100px">
92
+ <el-form-item
93
+ label="菜单名称:"
94
+ prop="name"
95
+ :rules="[{ required: true, message: '请填写菜单名称' }]"
96
+ >
97
+ <el-input
98
+ placeholder="请输入"
99
+ v-model="menuForm.name"
100
+ clearable
101
+ ></el-input>
102
+ </el-form-item>
103
+ <el-form-item label="菜单图标:" prop="icon">
104
+ <el-select v-model="menuForm.icon" placeholder="无">
105
+ <el-option
106
+ style="
107
+ display: flex;
108
+ justify-content: space-between;
109
+ align-items: center;
110
+ "
111
+ v-for="(item, key) in ElIcons"
112
+ :key="key"
113
+ :value="key"
114
+ >
115
+ <span>{{ key }}</span>
116
+ <el-icon><component :is="item" /></el-icon>
117
+ </el-option>
118
+ </el-select>
119
+ </el-form-item>
120
+ <el-form-item label="菜单内容:" prop="content">
121
+ <el-radio-group v-model="menuForm.content">
122
+ <el-radio label="pageId" value="pageId"> 项目中的页面 </el-radio>
123
+ <el-radio label="url" value="url">URL</el-radio>
124
+ </el-radio-group>
125
+ </el-form-item>
126
+ <el-form-item
127
+ v-if="menuForm.content === 'pageId'"
128
+ label-width="0px"
129
+ prop="pageId"
130
+ >
131
+ <PageList v-model="menuForm.pageId" :project="project" />
132
+ </el-form-item>
133
+ <template v-else>
134
+ <el-form-item label="打开方式:" prop="target">
135
+ <el-radio-group v-model="menuForm.target">
136
+ <el-radio label="_blank" value="_blank"> 新窗口打开 </el-radio>
137
+ <el-radio label="_self" value="_self"> 本窗口打开 </el-radio>
138
+ </el-radio-group>
139
+ </el-form-item>
140
+ <el-form-item
141
+ label="URL:"
142
+ prop="url"
143
+ :rules="[
144
+ {
145
+ type: 'url',
146
+ required: true,
147
+ message: '请输入URL',
148
+ },
149
+ ]"
150
+ >
151
+ <el-input
152
+ placeholder="请输入"
153
+ v-model="menuForm.url"
154
+ clearable
155
+ ></el-input>
156
+ </el-form-item>
157
+ </template>
158
+ </el-form>
159
+ </div>
160
+ <template #footer>
161
+ <span class="dialog-footer">
162
+ <el-button @click="cancel"> 取消 </el-button>
163
+ <el-button type="primary" @click="confirm"> 确认 </el-button>
164
+ </span>
165
+ </template>
166
+ </el-dialog>
167
+ </template>
168
+
169
+ <script lang="ts" setup>
170
+ // @ts-nocheck
171
+ import { defineProps, defineEmits } from 'vue';
172
+ import * as ElIcons from '@jt/icons-vue';
173
+ import PageList from './PageList.vue';
174
+ import useMenuTable from './useMenuTable';
175
+ const props = defineProps({
176
+ modelValue: {
177
+ type: Array,
178
+ default: () => [
179
+ {
180
+ name: '默认菜单',
181
+ icon: '',
182
+ pageId: 1,
183
+ children: [],
184
+ },
185
+ ],
186
+ },
187
+ project: Object,
188
+ });
189
+ const emits = defineEmits(['update:modelValue']);
190
+ const {
191
+ editModalOptions,
192
+ menuForm,
193
+ menuFormRef,
194
+ menuTree,
195
+ pageNameMap,
196
+ confirm,
197
+ cancel,
198
+ addPeer,
199
+ addSubordinate,
200
+ handleEdit,
201
+ handleDelete,
202
+ } = useMenuTable(props, emits);
203
+ </script>
204
+
205
+ <style lang="scss" scoped>
206
+ .binded-page {
207
+ display: 'flex';
208
+ align-items: 'center';
209
+ }
210
+ .menu-form {
211
+ margin-bottom: 17px;
212
+ padding-top: 44px;
213
+ padding-bottom: 26px;
214
+ border: 1px solid #e8e9eb;
215
+ border-left: none;
216
+ border-right: none;
217
+ }
218
+ </style>