Skip to content

Commit 5609a2e

Browse files
committed
Merge branch 'feat/model' of https://github.com/betterdancing/tiny-engine into feat/model
2 parents 5d833bf + 48b5f6f commit 5609a2e

6 files changed

Lines changed: 5737 additions & 0 deletions

File tree

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
<template>
2+
<div>
3+
<div
4+
class="placeholder-layer"
5+
v-if="!formModel || !formModel?.id"
6+
>
7+
请选择表单模型
8+
</div>
9+
<tiny-form
10+
v-else
11+
ref="formRef"
12+
label-width="120"
13+
label-position="left"
14+
:model="modelData"
15+
v-bind="$attrs"
16+
>
17+
<tiny-row>
18+
<tiny-col
19+
:span="colNumber"
20+
v-for="(item, index) in formModel.parameters"
21+
:key="index"
22+
>
23+
<tiny-form-item :prop="item.prop">
24+
<template #label>
25+
<div
26+
class="custom-label"
27+
v-auto-tip
28+
>
29+
{{ item.label }}
30+
</div>
31+
</template>
32+
<div v-if="item?.isModel && item.defaultValue !== null">
33+
<tiny-form
34+
label-width="100"
35+
label-position="left"
36+
:model="modelData[item.prop]"
37+
>
38+
<tiny-row>
39+
<tiny-col
40+
:span="insideColNumber"
41+
v-for="(insideItem, insideIndex) in item.defaultValue"
42+
:key="insideIndex"
43+
>
44+
<tiny-form-item :prop="insideItem.prop">
45+
<template #label>
46+
<div
47+
class="custom-label"
48+
v-auto-tip
49+
>
50+
{{ insideItem.label }}
51+
</div>
52+
</template>
53+
<component
54+
:is="componentsMap[insideItem.component]"
55+
v-model="modelData[item.prop][insideItem.prop]"
56+
:disabled="viewOnly"
57+
v-bind="insideItem"
58+
></component>
59+
</tiny-form-item>
60+
</tiny-col>
61+
</tiny-row>
62+
</tiny-form>
63+
</div>
64+
<component
65+
v-else
66+
:is="componentsMap[item.component]"
67+
v-model="modelData[item.prop]"
68+
:disabled="viewOnly"
69+
v-bind="item"
70+
></component>
71+
</tiny-form-item>
72+
</tiny-col>
73+
</tiny-row>
74+
</tiny-form>
75+
</div>
76+
</template>
77+
<script setup>
78+
import { ref, defineProps, defineEmits, defineExpose, computed, watch, reactive } from 'vue';
79+
import {
80+
Form as TinyForm,
81+
FormItem as TinyFormItem,
82+
Input as TinyInput,
83+
Select as TinySelect,
84+
Checkbox as TinyCheckbox,
85+
Radio as TinyRadio,
86+
DatePicker as TinyDatePicker,
87+
Numeric as TinyNumeric,
88+
Row as TinyRow,
89+
Col as TinyCol,
90+
} from '@opentiny/vue';
91+
import axios from 'axios';
92+
93+
const props = defineProps({
94+
style: {
95+
type: String,
96+
},
97+
className: {
98+
type: String,
99+
},
100+
layout: {
101+
type: Number,
102+
default: 2,
103+
},
104+
viewOnly: {
105+
type: Boolean,
106+
default: false,
107+
},
108+
modelValue: {
109+
type: Object,
110+
},
111+
serviceModel: {
112+
type: Object,
113+
},
114+
modelApis: {
115+
type: Array,
116+
default: () => [],
117+
},
118+
});
119+
120+
const modelData = ref({});
121+
122+
const emit = defineEmits(['update:modelValue']);
123+
124+
const formRef = ref(null);
125+
126+
const colNumber = computed(() => 12 / props.layout);
127+
128+
const insideColNumber = computed(() => (props.layout === 1 ? 6 : 12));
129+
130+
const formModel = computed(() => props.serviceModel);
131+
132+
const componentsMap = reactive({
133+
TinyInput,
134+
TinySelect,
135+
TinyCheckbox,
136+
TinyRadio,
137+
TinyDatePicker,
138+
TinyNumeric,
139+
});
140+
141+
const insertApi = (data = modelData.value) => {
142+
const apiInfo = props.modelApis.find(api => api.nameEn === 'insertApi');
143+
if (!apiInfo) {
144+
return undefined;
145+
}
146+
return axios[apiInfo.method](apiInfo.url, data)
147+
.then(res => {
148+
if (res.status === 200) {
149+
return res.data;
150+
} else {
151+
throw new Error('request fail');
152+
}
153+
})
154+
.catch(err => {
155+
throw new Error(err);
156+
});
157+
};
158+
159+
const updateApi = (data = modelData.value) => {
160+
const apiInfo = props.modelApis.find(api => api.nameEn === 'updateApi');
161+
if (!apiInfo) {
162+
return undefined;
163+
}
164+
return axios[apiInfo.method](apiInfo.url, data)
165+
.then(res => {
166+
if (res.status === 200) {
167+
return res.data;
168+
} else {
169+
throw new Error('request fail');
170+
}
171+
})
172+
.catch(err => {
173+
throw new Error(err);
174+
});
175+
};
176+
177+
const queryApi = ({ currentPage, pageSize, data } = {}) => {
178+
const apiInfo = props.modelApis.find(api => api.nameEn === 'queryApi');
179+
if (!apiInfo) {
180+
return undefined;
181+
}
182+
return axios[apiInfo.method](`${apiInfo.url}?currentPage=${currentPage || 1}&pageSize=${pageSize || 10}`, {
183+
params: data || modelData.value,
184+
})
185+
.then(res => {
186+
if (res.status === 200) {
187+
return res.data;
188+
}
189+
throw new Error('request fail');
190+
})
191+
.catch(err => {
192+
throw new Error(err);
193+
});
194+
};
195+
196+
const deleteApi = (evidence = { id: modelData.value?.id }) => {
197+
const apiInfo = props.modelApis.find(api => api.nameEn === 'deleteApi');
198+
if (!apiInfo) {
199+
return undefined;
200+
}
201+
return axios[apiInfo.method](apiInfo.url, { params: evidence })
202+
.then(res => {
203+
if (res.status === 200) {
204+
return res.data;
205+
} else {
206+
throw new Error('request fail');
207+
}
208+
})
209+
.catch(err => {
210+
throw new Error(err);
211+
});
212+
};
213+
214+
const initFormData = () => {
215+
modelData.value = Object.fromEntries(
216+
(formModel.value.parameters || []).map(item => {
217+
return [
218+
item.prop,
219+
item?.isModel
220+
? Object.fromEntries(item.defaultValue.map(insideItem => [insideItem.prop, insideItem.defaultValue || null]))
221+
: item.defaultValue || null,
222+
];
223+
})
224+
);
225+
}
226+
227+
watch(
228+
() => props.modelValue,
229+
value => {
230+
if (value) {
231+
modelData.value = props.modelValue;
232+
} else {
233+
initFormData()
234+
}
235+
},
236+
{ deep: true, immediate: true }
237+
);
238+
239+
const exposedData = {
240+
formData: () => modelData.value,
241+
formRef,
242+
insertApi,
243+
updateApi,
244+
queryApi,
245+
deleteApi,
246+
};
247+
248+
defineExpose({
249+
...exposedData,
250+
});
251+
</script>
252+
<style lang="less" scoped>
253+
.placeholder-layer {
254+
height: 40px;
255+
background-color: #f5f5f5;
256+
width: 100%;
257+
text-align: center;
258+
line-height: 40px;
259+
}
260+
</style>

0 commit comments

Comments
 (0)