Skip to content

Commit eeb9c83

Browse files
committed
feat: ✨新增数据接口管理
1 parent c543fe8 commit eeb9c83

File tree

13 files changed

+667
-278
lines changed

13 files changed

+667
-278
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# 基于 Vite2.x + Vue3.x + TypeScript H5 低代码平台
22

3+
### 后续可能会。。。搭建 PC 端后台管理系统低代码平台
4+
35
[![license](https://img.shields.io/github/license/buqiyuan/vite-vue3-lowcode.svg)](LICENSE)
46

57
**中文** | [English](./README.EN.md)
@@ -34,7 +36,7 @@ git clone --single-branch https://gitee.com/buqiyuan/vite-vue3-lowcode.git
3436
- [x] 动态添加页面
3537
- [x] 拖拽式生成组件
3638
- [ ] service worker + indexeddb 实现无服务端的前端交互
37-
- [ ] 数据源管理
39+
- [ ] 数据源管理(支持导入 swagger JSON 生成数据模型及接口)
3840
- [ ] 提供预置函数
3941
- [ ] 更多组件的封装
4042
- [ ] 其他...

components.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ declare module 'vue' {
1515
ElTabPane: typeof import('element-plus/es/el-tab-pane')['default']
1616
ElTabs: typeof import('element-plus/es/el-tabs')['default']
1717
ElDialog: typeof import('element-plus/es/el-dialog')['default']
18-
ElCollapseItem: typeof import('element-plus/es/el-collapse-item')['default']
19-
ElCollapse: typeof import('element-plus/es/el-collapse')['default']
2018
ElTag: typeof import('element-plus/es/el-tag')['default']
2119
ElDropdownItem: typeof import('element-plus/es/el-dropdown-item')['default']
2220
ElDropdownMenu: typeof import('element-plus/es/el-dropdown-menu')['default']
@@ -25,6 +23,9 @@ declare module 'vue' {
2523
ElInput: typeof import('element-plus/es/el-input')['default']
2624
ElFormItem: typeof import('element-plus/es/el-form-item')['default']
2725
ElForm: typeof import('element-plus/es/el-form')['default']
26+
ElCollapseItem: typeof import('element-plus/es/el-collapse-item')['default']
27+
ElCollapse: typeof import('element-plus/es/el-collapse')['default']
28+
ElPopconfirm: typeof import('element-plus/es/el-popconfirm')['default']
2829
}
2930
}
3031

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"axios": "^0.21.1",
2828
"dayjs": "^1.10.5",
2929
"dexie": "^3.0.3",
30-
"element-plus": "1.0.2-beta.53",
30+
"element-plus": "1.0.2-beta.52",
3131
"lodash": "^4.17.21",
3232
"monaco-editor": "^0.25.2",
3333
"normalize.css": "^8.0.1",
@@ -62,7 +62,7 @@
6262
"gh-pages": "^3.2.3",
6363
"husky": "^6.0.0",
6464
"lint-staged": "^11.0.0",
65-
"prettier": "^2.3.1",
65+
"prettier": "^2.3.2",
6666
"pretty-quick": "^3.1.1",
6767
"sass": "1.35.1",
6868
"stylelint": "^13.13.1",
@@ -72,7 +72,7 @@
7272
"typescript": "^4.3.4",
7373
"vite": "2.3.8",
7474
"vite-plugin-components": "^0.11.2",
75-
"vite-plugin-style-import": "^1.0.0",
75+
"vite-plugin-style-import": "^1.0.1",
7676
"vite-plugin-windicss": "^1.1.1",
7777
"vue-eslint-parser": "^7.6.0",
7878
"vue-tsc": "^0.2.0",

src/enums/httpEnum.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* @description: 请求结果集
3+
*/
4+
export enum ResultEnum {
5+
SUCCESS = 0,
6+
ERROR = -1,
7+
TIMEOUT = 10042,
8+
TYPE = 'success'
9+
}
10+
11+
/**
12+
* @description: 请求方法
13+
*/
14+
export enum RequestEnum {
15+
GET = 'GET',
16+
POST = 'POST',
17+
PATCH = 'PATCH',
18+
PUT = 'PUT',
19+
DELETE = 'DELETE'
20+
}
21+
22+
/**
23+
* @description: 常用的contentTyp类型
24+
*/
25+
export enum ContentTypeEnum {
26+
// json
27+
JSON = 'application/json;charset=UTF-8',
28+
// json
29+
TEXT = 'text/plain;charset=UTF-8',
30+
// form-data 一般配合qs
31+
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
32+
// form-data 上传
33+
FORM_DATA = 'multipart/form-data;charset=UTF-8'
34+
}
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
<!--
2+
* @Author: 卜启缘
3+
* @Date: 2021-06-24 18:36:03
4+
* @LastEditTime: 2021-06-26 21:34:53
5+
* @LastEditors: 卜启缘
6+
* @Description: 接口请求
7+
* @FilePath: \vite-vue3-lowcode\src\visual-editor\components\left-aside\components\data-source\data-fetch.vue
8+
-->
9+
<template>
10+
<div class="!mb-10px">
11+
<el-button type="primary" size="small" @click="showModelMoal">添加</el-button>
12+
<el-button type="warning" size="small" @click="showImportSwaggerJsonModal"
13+
>导入swagger</el-button
14+
>
15+
</div>
16+
<el-collapse v-model="state.activeNames">
17+
<template v-for="item in apis" :key="item.key">
18+
<el-collapse-item :title="item.name" :name="item.key">
19+
<template #title>
20+
<div class="model-item-title">
21+
<span>{{ item.name }}</span>
22+
<div class="model-actions">
23+
<i class="el-icon-edit" @click="editApiItem(item)"></i>
24+
<el-popconfirm
25+
confirm-button-text="确定"
26+
cancel-button-text="取消"
27+
icon="el-icon-info"
28+
icon-color="red"
29+
title="确定要删除该接口吗?"
30+
@confirm="deleteFetchApi(item.key)"
31+
>
32+
<template #reference>
33+
<i class="el-icon-delete"></i>
34+
</template>
35+
</el-popconfirm>
36+
</div>
37+
</div>
38+
</template>
39+
<div class="low-model-item">
40+
<pre class="code">{{ JSON.stringify(item, null, 2) }}</pre>
41+
</div>
42+
</el-collapse-item>
43+
</template>
44+
</el-collapse>
45+
</template>
46+
47+
<script setup lang="tsx">
48+
import { reactive, computed } from 'vue'
49+
import {
50+
ElForm,
51+
ElFormItem,
52+
ElInput,
53+
ElSelect,
54+
ElOption,
55+
ElButton,
56+
ElMessage,
57+
ElCascader
58+
} from 'element-plus'
59+
import { useVisualData, fieldTypes } from '@/visual-editor/hooks/useVisualData'
60+
import type { FetchApiItem, VisualEditorModel } from '@/visual-editor/visual-editor.utils'
61+
import { useModal } from '@/visual-editor/hooks/useModal'
62+
import { cloneDeep } from 'lodash'
63+
import { generateUUID } from '@/visual-editor/utils/'
64+
import { RequestEnum, ContentTypeEnum } from '@/enums/httpEnum'
65+
66+
interface IState {
67+
activeNames: string[]
68+
ruleFormRef: any
69+
ruleForm: FetchApiItem
70+
}
71+
72+
const { jsonData, incrementFetchApi, updateFetchApi, deleteFetchApi } = useVisualData()
73+
74+
/**
75+
* @description 接口集合
76+
*/
77+
const apis = computed(() => cloneDeep(jsonData.actions.fetch.apis))
78+
79+
/**
80+
* @description 模型集合
81+
*/
82+
const models = computed(() => cloneDeep(jsonData.models))
83+
84+
/**
85+
* @description 是否处于编辑状态
86+
*/
87+
const isEdit = computed(() => apis.value.some((item) => item.key == state.ruleForm.key))
88+
89+
/**
90+
* @description 创建空的数据接口对象
91+
*/
92+
const createEmptyApiItem = (): FetchApiItem => ({
93+
key: generateUUID(),
94+
name: '',
95+
options: {
96+
url: '', // 请求的url
97+
method: RequestEnum.GET, // 请求的方法
98+
contentType: 'JSON' // 请求的内容类型
99+
},
100+
data: {
101+
bind: '', // 请求绑定对应的某个实体
102+
recv: '' // 响应的结果绑定到某个实体上
103+
}
104+
})
105+
106+
const state = reactive<IState>({
107+
activeNames: [],
108+
ruleFormRef: null,
109+
ruleForm: createEmptyApiItem()
110+
})
111+
112+
const rules = {
113+
name: [{ required: true, message: '请输入接口名称', trigger: 'change' }],
114+
'options.url': [{ required: true, message: '请输入接口名称', trigger: 'change' }],
115+
'options.contentType': [{ required: true, message: '请选择内容类型', trigger: 'change' }]
116+
}
117+
118+
const handleBindChange = (e: VisualEditorModel[]) => {
119+
console.log(e, 'kkk')
120+
}
121+
122+
/**
123+
* @description 显示添加接口弹窗
124+
*/
125+
const showModelMoal = () => {
126+
useModal({
127+
title: `${isEdit.value ? '编辑' : '新增'}接口`,
128+
props: {
129+
width: 600
130+
},
131+
content: () => (
132+
<ElForm
133+
model={state.ruleForm}
134+
ref={(el) => el && (state.ruleFormRef = el)}
135+
label-width="100px"
136+
size={'mini'}
137+
rules={rules}
138+
class="demo-ruleForm"
139+
>
140+
<ElFormItem label="名称" prop="name">
141+
<ElInput v-model={state.ruleForm.name} placeholder={'请输入接口名称'}></ElInput>
142+
</ElFormItem>
143+
<ElFormItem label="接口" prop={'options.url'}>
144+
<ElInput v-model={state.ruleForm.options.url} placeholder={'请输入接口地址'}>
145+
{{
146+
prepend: () => (
147+
<ElSelect v-model={state.ruleForm.options.method} class={'w-90px'}>
148+
{Object.keys(RequestEnum).map((key) => (
149+
<ElOption key={key} label={key} value={key}></ElOption>
150+
))}
151+
</ElSelect>
152+
)
153+
}}
154+
</ElInput>
155+
</ElFormItem>
156+
<ElFormItem label="内容类型" prop={'options.contentType'}>
157+
<ElSelect v-model={state.ruleForm.options.contentType}>
158+
{Object.keys(ContentTypeEnum).map((key) => (
159+
<ElOption key={key} label={key} value={key}></ElOption>
160+
))}
161+
</ElSelect>
162+
</ElFormItem>
163+
<ElFormItem label="请求数据" prop={'data.bind'}>
164+
<ElCascader
165+
clearable={true}
166+
props={{
167+
checkStrictly: true,
168+
children: 'entitys',
169+
label: 'name',
170+
value: 'key',
171+
expandTrigger: 'hover'
172+
}}
173+
placeholder="请选择绑定的请求数据"
174+
onChange={handleBindChange}
175+
v-model={state.ruleForm.data.bind}
176+
options={models.value}
177+
></ElCascader>
178+
</ElFormItem>
179+
</ElForm>
180+
),
181+
onConfirm: () => {
182+
return new Promise((resolve, reject) => {
183+
state.ruleFormRef.validate((valid) => {
184+
if (valid) {
185+
if (isEdit.value) {
186+
updateFetchApi(cloneDeep(state.ruleForm))
187+
} else {
188+
incrementFetchApi(cloneDeep(state.ruleForm))
189+
}
190+
ElMessage.success(`${isEdit.value ? '修改' : '新增'}接口成功!`)
191+
state.ruleForm = createEmptyApiItem()
192+
resolve('submit!')
193+
} else {
194+
reject()
195+
console.log('error submit!!')
196+
return false
197+
}
198+
})
199+
})
200+
},
201+
onCancel: () => (state.ruleForm = createEmptyApiItem())
202+
})
203+
}
204+
205+
/**
206+
* @description 编辑模型
207+
*/
208+
const editApiItem = (apiItem: FetchApiItem) => {
209+
console.log(apiItem)
210+
state.ruleForm = cloneDeep(apiItem)
211+
showModelMoal()
212+
}
213+
214+
/**
215+
* @description 显示导入swagger JSON模态框
216+
*/
217+
const showImportSwaggerJsonModal = () => {
218+
ElMessage.info('敬请期待!')
219+
}
220+
</script>
221+
222+
<style lang="scss" scoped>
223+
.code {
224+
padding: 4px 10px;
225+
font-size: 12px;
226+
line-height: 1.4;
227+
}
228+
229+
.model-item-title {
230+
flex: 1;
231+
display: flex;
232+
align-items: center;
233+
justify-content: space-between;
234+
235+
.model-actions {
236+
i {
237+
padding: 6px;
238+
margin: 0 2px;
239+
font-weight: bold;
240+
cursor: pointer;
241+
border-radius: 2px;
242+
opacity: 0.7;
243+
transition: all 0.1s;
244+
245+
&:hover {
246+
background-color: #f1f1f1;
247+
opacity: 1;
248+
}
249+
250+
&.el-icon-delete {
251+
color: #f44336;
252+
}
253+
254+
&.el-icon-edit {
255+
color: #2196f3;
256+
}
257+
}
258+
}
259+
}
260+
</style>

0 commit comments

Comments
 (0)