Skip to content

Commit 9385bd5

Browse files
committed
feat(template-center)
1 parent 69e6bea commit 9385bd5

18 files changed

Lines changed: 1802 additions & 3 deletions

File tree

packages/register/src/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,6 @@ export const META_APP = {
8484
Canvas: 'engine.canvas',
8585
Tutorial: 'engine.plugins.tutorial',
8686
// 首页菜单
87-
AppCenter: 'engine.home.application-center',
88-
TemplateCenter: 'engine.home.template-center'
87+
AppCenter: 'engine.workspace.application-center',
88+
TemplateCenter: 'engine.workspace.template-center'
8989
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Copyright (c) 2023 - present TinyEngine Authors.
3+
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
4+
*
5+
* Use of this source code is governed by an MIT-style license.
6+
*
7+
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8+
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9+
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10+
*
11+
*/
12+
13+
import entry from './src/Main.vue'
14+
import metaData from './meta'
15+
import './src/styles/vars.less'
16+
17+
export default {
18+
...metaData,
19+
entry
20+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
id: 'engine.workspace.application-center',
3+
title: '应用中心',
4+
type: 'workspace',
5+
icon: 'workspace-icon-application-center'
6+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"name": "@opentiny/tiny-engine-workspace-application-center",
3+
"version": "2.8.0",
4+
"publishConfig": {
5+
"access": "public"
6+
},
7+
"scripts": {
8+
"build": "vite build"
9+
},
10+
"type": "module",
11+
"main": "dist/index.js",
12+
"module": "dist/index.js",
13+
"files": [
14+
"dist"
15+
],
16+
"repository": {
17+
"type": "git",
18+
"url": "https://github.com/opentiny/tiny-engine",
19+
"directory": "packages/workspace/application-center"
20+
},
21+
"bugs": {
22+
"url": "https://github.com/opentiny/tiny-engine/issues"
23+
},
24+
"author": "OpenTiny Team",
25+
"license": "MIT",
26+
"homepage": "https://opentiny.design/tiny-engine",
27+
"dependencies": {
28+
"@opentiny/tiny-engine-common": "workspace:*",
29+
"@opentiny/tiny-engine-meta-register": "workspace:*",
30+
"vue-clipboard3": "^2.0.0"
31+
},
32+
"devDependencies": {
33+
"@opentiny/tiny-engine-vite-plugin-meta-comments": "workspace:*",
34+
"@vitejs/plugin-vue": "^5.1.2",
35+
"@vitejs/plugin-vue-jsx": "^4.0.1",
36+
"vite": "^5.4.2"
37+
},
38+
"peerDependencies": {
39+
"@opentiny/vue": "^3.20.0",
40+
"@opentiny/vue-icon": "^3.20.0",
41+
"vue": "^3.4.15"
42+
}
43+
}
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
<template>
2+
<tiny-dialog-box
3+
:visible="visible"
4+
title="新建应用"
5+
width="400px"
6+
append-to-body
7+
destroy-on-close
8+
@update:visible="setVisible"
9+
>
10+
<tiny-form
11+
ref="editAppInfoRef"
12+
label-position="left"
13+
label-width="84px"
14+
label-align
15+
:model="formState"
16+
:rules="validRules"
17+
validate-type="text"
18+
>
19+
<tiny-form-item label="应用名称" prop="name">
20+
<tiny-input v-model="formState.name" placeholder="请输入"></tiny-input>
21+
</tiny-form-item>
22+
<tiny-form-item label="应用描述" prop="description">
23+
<tiny-input v-model="formState.description" type="textarea" placeholder="请输入此次发布的修改点"></tiny-input>
24+
</tiny-form-item>
25+
<tiny-form-item label="场景" prop="sceneId">
26+
<tiny-select
27+
v-model="formState.sceneId"
28+
placeholder="请选择"
29+
:options="tagsList.scene"
30+
:disabled="template?.sceneId"
31+
value-field="id"
32+
text-field="name"
33+
></tiny-select>
34+
</tiny-form-item>
35+
<tiny-form-item label="行业" prop="industryId">
36+
<tiny-select
37+
v-model="formState.industryId"
38+
placeholder="请选择"
39+
:options="tagsList.industry"
40+
:disabled="template?.industryId"
41+
value-field="id"
42+
text-field="name"
43+
></tiny-select>
44+
</tiny-form-item>
45+
<tiny-form-item label="缩略图">
46+
<div class="form-item-icon-wrapper">
47+
<svg-icon :name="formState.assetsUrl" class="form-item-icon" @click="handleOpen"></svg-icon>
48+
<transition name="dropdown">
49+
<div v-if="isOpen" class="dropdown-menu">
50+
<!-- 菜单项 -->
51+
<div class="icon-list">
52+
<template v-for="iconIndex in 15" :key="iconIndex">
53+
<svg-icon
54+
:name="'template-cover-' + iconIndex"
55+
class="icon"
56+
@click="handleSelectIcon('template-cover-' + iconIndex)"
57+
></svg-icon>
58+
</template>
59+
</div>
60+
</div>
61+
</transition>
62+
</div>
63+
</tiny-form-item>
64+
</tiny-form>
65+
<template #footer>
66+
<tiny-button type="primary" @click="confirm"> 确定 </tiny-button>
67+
<tiny-button @click="setVisible(false)">取消</tiny-button>
68+
</template>
69+
</tiny-dialog-box>
70+
</template>
71+
72+
<script lang="ts">
73+
import { ref, reactive, onMounted } from 'vue'
74+
import {
75+
Input as TinyInput,
76+
Button as TinyButton,
77+
DialogBox as TinyDialogBox,
78+
Form as TinyForm,
79+
FormItem as TinyFormItem,
80+
Select as TinySelect,
81+
Notify
82+
} from '@opentiny/vue'
83+
import { fetchBusinessCategoryByGroup } from './js/http'
84+
85+
export default {
86+
components: {
87+
TinyInput,
88+
TinyButton,
89+
TinyDialogBox,
90+
TinyForm,
91+
TinyFormItem,
92+
TinySelect
93+
},
94+
props: {
95+
visible: {
96+
type: Boolean,
97+
default: false
98+
},
99+
template: {
100+
type: Object,
101+
default: () => ({})
102+
},
103+
openByTemplate: {
104+
type: Boolean,
105+
default: false
106+
}
107+
},
108+
emits: ['confirm'],
109+
setup(props, { emit }) {
110+
const editAppInfoRef = ref()
111+
112+
const formState = reactive({
113+
name: props.template.name || '',
114+
description: props.template.description || '',
115+
sceneId: props.template.sceneId || null,
116+
industryId: props.template.industryId || null,
117+
assetsUrl: props.template.assetsUrl || 'template-cover-1'
118+
})
119+
120+
const isOpen = ref(false)
121+
122+
const tagsList = reactive({
123+
scene: [],
124+
industry: []
125+
})
126+
127+
const validRules = {
128+
name: [
129+
{ required: true, message: '应用名称必填', trigger: 'blur' },
130+
{ max: 50, message: '长度不大于50', trigger: 'change' },
131+
{
132+
trigger: 'blur',
133+
validator: (rule: any, value: string, callback: any) => {
134+
if (!/^[\w\-_]+$/.test(value)) {
135+
callback(new Error('应用名称只能包括英文、数字、中划线和下划线'))
136+
} else {
137+
callback()
138+
}
139+
}
140+
}
141+
],
142+
description: [
143+
{ max: 200, message: '长度不大于200', trigger: 'change' },
144+
{
145+
trigger: 'blur',
146+
validator: (rule: any, value: string, callback: any) => {
147+
if (!/^[\w\-_\u4e00-\u9fa5]*$/.test(value)) {
148+
callback(new Error('描述只能包括中文、英文、数字、中划线和下划线'))
149+
} else {
150+
callback()
151+
}
152+
}
153+
}
154+
],
155+
sceneId: [{ required: true, message: '场景必选', trigger: 'change' }],
156+
industryId: [{ required: true, message: '行业必选', trigger: 'change' }]
157+
}
158+
159+
const setVisible = (visible: boolean) => emit('update:visible', visible)
160+
161+
const getTagsList = async () => {
162+
Promise.all([fetchBusinessCategoryByGroup('场景'), fetchBusinessCategoryByGroup('行业')])
163+
.then((res) => {
164+
tagsList.scene = res[0] || []
165+
tagsList.industry = res[1] || []
166+
})
167+
.catch((error) => {
168+
Notify({
169+
type: 'error',
170+
message: error,
171+
position: 'top-right',
172+
duration: 5000
173+
})
174+
})
175+
}
176+
177+
const handleOpen = () => {
178+
isOpen.value = true
179+
}
180+
181+
const handleSelectIcon = (icon: string) => {
182+
formState.assetsUrl = icon
183+
isOpen.value = false
184+
}
185+
186+
const confirm = () => {
187+
editAppInfoRef.value.validate((valid: boolean) => {
188+
if (valid) {
189+
emit(
190+
'confirm',
191+
props.template?.id
192+
? {
193+
id: props.template.id,
194+
...formState
195+
}
196+
: formState
197+
)
198+
199+
setVisible(false)
200+
}
201+
})
202+
}
203+
204+
onMounted(() => {
205+
getTagsList()
206+
})
207+
208+
return {
209+
isOpen,
210+
editAppInfoRef,
211+
formState,
212+
validRules,
213+
tagsList,
214+
setVisible,
215+
handleOpen,
216+
handleSelectIcon,
217+
confirm
218+
}
219+
}
220+
}
221+
</script>
222+
223+
<style lang="less" scoped>
224+
.form-item-icon-wrapper {
225+
position: relative;
226+
.form-item-icon {
227+
font-size: 40px;
228+
cursor: pointer;
229+
}
230+
.dropdown-menu {
231+
position: absolute;
232+
bottom: 100%;
233+
left: 0;
234+
padding: 16px;
235+
margin-bottom: 5px;
236+
width: 216px;
237+
border-radius: 4px;
238+
z-index: 1000;
239+
overflow: hidden;
240+
background: var(--te-template-common-bg-color);
241+
box-shadow: 0 4px 16px 0 var(--te-base-box-shadow-rgba-3);
242+
243+
.icon-list {
244+
display: flex;
245+
flex-wrap: wrap;
246+
gap: 8px;
247+
margin: 4px 0;
248+
.icon {
249+
font-size: 32px;
250+
cursor: pointer;
251+
}
252+
}
253+
}
254+
}
255+
</style>

0 commit comments

Comments
 (0)