Skip to content

Commit 57424d5

Browse files
Create ModelApiConfigurator.vue
1 parent ee3030a commit 57424d5

1 file changed

Lines changed: 397 additions & 0 deletions

File tree

Lines changed: 397 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,397 @@
1+
<template>
2+
<tiny-popover
3+
placement="bottom-start"
4+
trigger="manual"
5+
v-model="isShow"
6+
:visible-arrow="false"
7+
:popper-class="['option-popper', 'fixed-left']"
8+
:offset="isSecond ? 652 : 0"
9+
width="860"
10+
>
11+
<div class="model-function-wrap">
12+
<div class="model-title">
13+
<span>选择模型方法</span>
14+
<div class="right">
15+
<tiny-button @click="closePopover">取消</tiny-button>
16+
<tiny-button type="primary" @click="setModelFunction"
17+
>确定</tiny-button
18+
>
19+
<tiny-icon-close
20+
class="tiny-svg-size"
21+
@click="closePopover"
22+
></tiny-icon-close>
23+
</div>
24+
</div>
25+
<div class="model-set-wrap">
26+
<div class="model-wrap">
27+
<div class="model-groups">
28+
<model-select
29+
:model-page-size="5"
30+
@model-select="getModel"
31+
:meta="meta"
32+
:isShow="isShow"
33+
></model-select>
34+
</div>
35+
<div class="model-parameters">
36+
<tiny-grid
37+
:data="modelFunctions || []"
38+
:loading="gridLoading"
39+
min-height="116"
40+
max-height="330"
41+
@radio-change="selectModelFunction"
42+
>
43+
<tiny-grid-column type="radio" width="40"></tiny-grid-column>
44+
<tiny-grid-column
45+
field="apiName"
46+
title="方法名称"
47+
show-overflow
48+
></tiny-grid-column>
49+
<tiny-grid-column
50+
field="apiDescription"
51+
title="方法描述"
52+
show-overflow
53+
></tiny-grid-column>
54+
</tiny-grid>
55+
</div>
56+
</div>
57+
<div class="model-param-wrap" v-if="selectedFunction">
58+
<tiny-collapse v-model="activeNames">
59+
<tiny-collapse-item title="入参配置" name="request">
60+
<params-bind-grid
61+
ref="gridRequest"
62+
:data="selectedFunction?.fields?.request || []"
63+
:model-fields="selectedModel?.params || []"
64+
:type="'request'"
65+
></params-bind-grid>
66+
</tiny-collapse-item>
67+
<tiny-collapse-item title="出参配置" name="response">
68+
<params-bind-grid
69+
ref="gridResponse"
70+
:data="selectedFunction?.fields?.response || []"
71+
:model-fields="selectedModel?.params || []"
72+
:type="'response'"
73+
></params-bind-grid>
74+
</tiny-collapse-item>
75+
</tiny-collapse>
76+
</div>
77+
</div>
78+
</div>
79+
</tiny-popover>
80+
<tiny-button @click="openPopover">{{
81+
buttonText
82+
}}</tiny-button>
83+
</template>
84+
<script setup>
85+
import { ref, defineProps, defineEmits } from "vue";
86+
import {
87+
Button as TinyButton,
88+
Popover as TinyPopover,
89+
Collapse as TinyCollapse,
90+
CollapseItem as TinyCollapseItem,
91+
Grid as TinyGrid,
92+
GridColumn as TinyGridColumn,
93+
} from "@opentiny/vue";
94+
import { iconClose } from "@opentiny/vue-icon";
95+
import { HttpService, useCanvas } from "@opentiny/tiny-engine";
96+
import ModelSelect from "../common/ModelSelect.vue";
97+
import ParamsBindGrid from "./ParamsBindGrid.vue";
98+
import { transformNode } from "../common/utils";
99+
100+
const props = defineProps({
101+
meta: {
102+
type: Object,
103+
default: () => ({}),
104+
},
105+
buttonText: {
106+
type: String,
107+
default: "绑定模型方法",
108+
},
109+
// 协议类型
110+
renderType: {
111+
type: String,
112+
default: "JSExpression",
113+
},
114+
isFunction: {
115+
type: Boolean,
116+
default: true,
117+
},
118+
// 是否是二级面板
119+
isSecond: {
120+
type: Boolean,
121+
default: false,
122+
},
123+
// 是否引入model的url等
124+
isShowModelDetail: {
125+
type: Boolean,
126+
default: true,
127+
},
128+
});
129+
const emit = defineEmits(["update:modelValue"]);
130+
const { getPageSchema } = useCanvas();
131+
const pageSchema = getPageSchema();
132+
const TinyIconClose = iconClose();
133+
const isShow = ref(false);
134+
const gridLoading = ref(false);
135+
const modelValue = ref(props.meta.widget.props.modelValue);
136+
const activeNames = ref(["request", "response"]);
137+
138+
const gridRequest = ref();
139+
const gridResponse = ref();
140+
141+
const selectedModel = ref();
142+
const modelFunctions = ref([]);
143+
const selectedFunction = ref();
144+
145+
const openPopover = () => {
146+
isShow.value = true;
147+
};
148+
149+
const closePopover = () => {
150+
isShow.value = false;
151+
};
152+
153+
const getModelFunctions = () => {
154+
HttpService.apis
155+
.get(
156+
`http://10.159.227.31:9090/baseUiEngine/basic/xdm/module/queryDataApiServLog?applicationId=${selectedModel.value.appId}&modelType=${selectedModel.value.modelData.modelType}&entityNameEn=${selectedModel.value.modelData.nameEn}&version=${selectedModel.value.modelData.modelVersion}`
157+
)
158+
.then((res) => {
159+
if (res) {
160+
modelFunctions.value = res.map((category) => category?.children || []);
161+
modelFunctions.value = modelFunctions.value.flatMap((item) => item);
162+
}
163+
gridLoading.value = false;
164+
})
165+
.catch(() => (gridLoading.value = false));
166+
};
167+
168+
const getFunctionsField = () => {
169+
let params = {};
170+
if (selectedFunction.value.masterId) {
171+
params = {
172+
id: selectedFunction.value.id,
173+
apiId: selectedFunction.value.apiId,
174+
masterId: selectedFunction.value.masterId,
175+
};
176+
} else {
177+
params = {
178+
apiNameEn: selectedFunction.value.apiNameEn,
179+
requestMode: selectedFunction.value.requestMode,
180+
type: selectedFunction.value.type,
181+
uri: selectedFunction.value.uri,
182+
};
183+
}
184+
HttpService.apis
185+
.post(
186+
`http://10.159.227.31:9090/baseUiEngine/basic/xdm/module/queryApiInfoById?modelType=${selectedModel.value.modelData.modelType}&applicationId=${selectedModel.value.appId}&version=${selectedModel.value.modelData.modelVersion}`,
187+
params
188+
)
189+
.then((res) => {
190+
if (res) {
191+
selectedFunction.value.url = res.requestUrl;
192+
selectedFunction.value.method = res.requestMethod;
193+
selectedFunction.value.fields = {
194+
request: JSON.parse(res.requestParameters).map((item) =>
195+
transformNode(item)
196+
),
197+
response: JSON.parse(res.responseParameters).map((item) =>
198+
transformNode(item)
199+
),
200+
};
201+
}
202+
});
203+
};
204+
205+
const getModel = (data) => {
206+
gridLoading.value = true;
207+
selectedModel.value = data;
208+
getModelFunctions();
209+
};
210+
211+
const modelDataToSchema = (modelData, resultValue) => {
212+
modelData.forEach((item) => {
213+
if (item.bindValue) {
214+
resultValue[item.prop] = item.bindValue;
215+
return;
216+
}
217+
if (item.children) {
218+
resultValue[item.prop] = {};
219+
modelDataToSchema(item.children, resultValue[item.prop]);
220+
}
221+
});
222+
};
223+
224+
const setModelFunction = async () => {
225+
if (!selectedModel.value || !selectedFunction.value) {
226+
return;
227+
}
228+
const requsetFormValid = await gridRequest.value.validateForm();
229+
const responseFormValid = await gridResponse.value.validateForm();
230+
if (!("modelApis" in pageSchema)) {
231+
pageSchema.modelApis = {};
232+
}
233+
if (requsetFormValid && responseFormValid) {
234+
const requestBindResult = gridRequest.value.getData();
235+
const responseBindResult = gridResponse.value.getData();
236+
const apiKeys = Object.keys(pageSchema.modelApis);
237+
const apiIndex =
238+
apiKeys.filter((key) => /^api\d+$/.test(key)).length > 0
239+
? Math.max(
240+
...apiKeys
241+
.filter((str) => /^api\d+$/.test(str))
242+
.map((str) => parseInt(str.replace(/^api/, ""), 10))
243+
) + 1
244+
: 1;
245+
const methodKeys = Object.keys(pageSchema.methods);
246+
const methodIndex =
247+
methodKeys.filter((key) => /^onModelApiMethod\d+$/.test(key)).length > 0
248+
? Math.max(
249+
...methodKeys
250+
.filter((str) => /^onModelApiMethod\d+$/.test(str))
251+
.map((str) => parseInt(str.replace(/^onModelApiMethod/, ""), 10))
252+
) + 1
253+
: 1;
254+
let methodName = `onModelApiMethod${methodIndex}`;
255+
let apiName = `api${apiIndex}`;
256+
// 如果是重新绑定
257+
if (modelValue.value) {
258+
methodName = modelValue?.methodName || '';
259+
apiName = modelValue.apiName
260+
}
261+
// 处理映射关系
262+
let updateValue = {
263+
type: props.renderType,
264+
value: `this.modelApis.${apiName}`,
265+
apiName: apiName,
266+
};
267+
// 生成方法
268+
if (props.isFunction) {
269+
pageSchema.methods[
270+
`${methodName}`
271+
] = {
272+
type: 'JSFunction',
273+
value: `function ${methodName}() {\n this.modelApis.${apiName}();\n}`
274+
};
275+
updateValue = {
276+
type: props.renderType,
277+
value: `this.${methodName}`,
278+
methodName: `${methodName}`,
279+
apiName: apiName,
280+
};
281+
}
282+
const result = {
283+
config: {
284+
modelApplicationId: selectedModel.value.appId,
285+
modelNameEn: selectedModel.value.modelData.nameEn,
286+
modelVersion: selectedModel.value.modelData.modelVersion,
287+
},
288+
name: selectedFunction.value.name,
289+
request: {},
290+
response: {},
291+
};
292+
if (props.isShowModelDetail) {
293+
result.method = selectedFunction.value.method;
294+
result.url = selectedFunction.value.url;
295+
result.headers = selectedFunction.value.headers || {};
296+
}
297+
modelDataToSchema(requestBindResult, result.request);
298+
modelDataToSchema(responseBindResult, result.response);
299+
pageSchema.modelApis[`${apiName}`] = result;
300+
useCanvas().canvasApi.value.updateRect();
301+
emit("update:modelValue", updateValue);
302+
closePopover();
303+
}
304+
};
305+
306+
const selectModelFunction = (data) => {
307+
selectedFunction.value = data.row;
308+
getFunctionsField();
309+
};
310+
</script>
311+
312+
<style lang="less" scoped>
313+
.model-function-wrap {
314+
overflow-y: scroll;
315+
height: 100%;
316+
.model-title {
317+
display: flex;
318+
justify-content: space-between;
319+
align-items: center;
320+
margin: 8px 0 20px 0;
321+
.right {
322+
svg {
323+
margin-left: 10px;
324+
}
325+
}
326+
span {
327+
font-weight: 600;
328+
}
329+
330+
.tiny-svg {
331+
cursor: pointer;
332+
}
333+
}
334+
.model-set-wrap {
335+
.model-wrap {
336+
display: flex;
337+
min-height: 140px;
338+
max-height: 355px;
339+
border: 1px solid #e6e6e6;
340+
border-radius: 4px;
341+
.model-groups {
342+
width: 410px;
343+
padding: 12px;
344+
border-right: 1px solid #e6e6e6;
345+
:deep(.tiny-tree) {
346+
.tiny-tree-node__content .tiny-tree-node__content-left {
347+
padding: 0;
348+
.tiny-tree-node__label {
349+
color: #191919;
350+
}
351+
}
352+
.tiny-tree-node__children .tiny-tree-node__content {
353+
padding: 0;
354+
.tiny-tree-node__content-left .tiny-tree-node__label {
355+
color: #595959;
356+
}
357+
}
358+
}
359+
.search {
360+
margin-bottom: 12px;
361+
}
362+
}
363+
.model-parameters {
364+
width: 412px;
365+
padding: 12px;
366+
overflow-y: scroll;
367+
&::-webkit-scrollbar {
368+
display: none;
369+
}
370+
div {
371+
border-bottom: 1px solid #f5f5f5;
372+
}
373+
span {
374+
padding-left: 12px;
375+
display: inline-block;
376+
width: 180px;
377+
}
378+
.title {
379+
height: 24px;
380+
background-color: #f5f5f5;
381+
display: flex;
382+
align-items: center;
383+
span:first-child {
384+
border-right: 1px solid #dbdbdb;
385+
}
386+
}
387+
.list-items {
388+
height: 30px;
389+
line-height: 30px;
390+
display: flex;
391+
align-items: center;
392+
}
393+
}
394+
}
395+
}
396+
}
397+
</style>

0 commit comments

Comments
 (0)