@james-zhang/elpis 1.0.0
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.
- package/.eslintignore +3 -0
- package/.eslintrc +55 -0
- package/.tmp-check.js +47 -0
- package/README.md +287 -0
- package/app/controller/base.js +37 -0
- package/app/controller/project.js +76 -0
- package/app/controller/view.js +17 -0
- package/app/extend/logger.js +36 -0
- package/app/middleware/api-params-verify.js +78 -0
- package/app/middleware/api-sign-verify.js +31 -0
- package/app/middleware/error-handler.js +36 -0
- package/app/middleware/project-handler.js +26 -0
- package/app/middleware.js +69 -0
- package/app/pages/asserts/custom.css +10 -0
- package/app/pages/boot.js +44 -0
- package/app/pages/common/curl.js +76 -0
- package/app/pages/common/utils.js +2 -0
- package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +19 -0
- package/app/pages/dashboard/complex-view/header-view/header-view.vue +131 -0
- package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +29 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/search-pannel/search-pannel.vue +36 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/table-pannel/table-pannel.vue +125 -0
- package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +19 -0
- package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +119 -0
- package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +131 -0
- package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +149 -0
- package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +126 -0
- package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +111 -0
- package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +28 -0
- package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +138 -0
- package/app/pages/dashboard/dashboard.vue +121 -0
- package/app/pages/dashboard/entry.dashboard.js +52 -0
- package/app/pages/dashboard/router.js +3 -0
- package/app/pages/dashboard/todo/todo.vue +10 -0
- package/app/pages/store/index.js +3 -0
- package/app/pages/store/menu.js +71 -0
- package/app/pages/store/project.js +15 -0
- package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
- package/app/pages/widgets/header-container/asserts/logo.png +0 -0
- package/app/pages/widgets/header-container/header-container.vue +118 -0
- package/app/pages/widgets/schema-form/complex-view/input/input.vue +165 -0
- package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +164 -0
- package/app/pages/widgets/schema-form/complex-view/select/select.vue +138 -0
- package/app/pages/widgets/schema-form/form-item-config.js +20 -0
- package/app/pages/widgets/schema-form/schema-form.vue +154 -0
- package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +49 -0
- package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +65 -0
- package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +44 -0
- package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +50 -0
- package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +134 -0
- package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
- package/app/pages/widgets/schema-table/schema-table.vue +277 -0
- package/app/pages/widgets/sider-container/sider-container.vue +42 -0
- package/app/public/static/logo.png +0 -0
- package/app/public/static/normalize.css +239 -0
- package/app/router/project.js +7 -0
- package/app/router/view.js +7 -0
- package/app/router-schema/project.js +34 -0
- package/app/service/base.js +10 -0
- package/app/service/project.js +43 -0
- package/app/view/entry.tpl +31 -0
- package/app/webpack/config/webpack.base.js +224 -0
- package/app/webpack/config/webpack.dev.js +53 -0
- package/app/webpack/config/webpack.prod.js +104 -0
- package/app/webpack/dev.js +54 -0
- package/app/webpack/libs/blank.js +1 -0
- package/app/webpack/prod.js +17 -0
- package/config/config.default.js +3 -0
- package/docs/dashboard-model.js +150 -0
- package/elpis-core/env.js +21 -0
- package/elpis-core/index.js +82 -0
- package/elpis-core/loader/config.js +58 -0
- package/elpis-core/loader/controller.js +55 -0
- package/elpis-core/loader/extend.js +42 -0
- package/elpis-core/loader/middleware.js +50 -0
- package/elpis-core/loader/router-schema.js +28 -0
- package/elpis-core/loader/router.js +42 -0
- package/elpis-core/loader/service.js +51 -0
- package/index.js +37 -0
- package/logs/application.log +50 -0
- package/logs/application.log.2026-06-13 +159 -0
- package/model/index.js +119 -0
- package/package.json +88 -0
- package/scripts/generate-cover.py +93 -0
- package/scripts/generate-diagrams.js +80 -0
- package/test/controller/project.test.js +218 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- 整行容器:标签 + 输入框左右布局 -->
|
|
3
|
+
<el-row
|
|
4
|
+
type="flex"
|
|
5
|
+
align="middle"
|
|
6
|
+
class="form-item"
|
|
7
|
+
>
|
|
8
|
+
<!-- 左侧标签区域 -->
|
|
9
|
+
<el-row
|
|
10
|
+
class="item-label"
|
|
11
|
+
justify="end"
|
|
12
|
+
>
|
|
13
|
+
<!-- 必填红色星号:schema里required为true才展示 -->
|
|
14
|
+
<el-row
|
|
15
|
+
v-if="schema.option?.required"
|
|
16
|
+
type="flex"
|
|
17
|
+
class="required"
|
|
18
|
+
>
|
|
19
|
+
*
|
|
20
|
+
</el-row>
|
|
21
|
+
<!-- 字段中文名称 -->
|
|
22
|
+
{{ schema.label }}
|
|
23
|
+
</el-row>
|
|
24
|
+
|
|
25
|
+
<!-- 右侧输入框区域 -->
|
|
26
|
+
<el-row class="item-value">
|
|
27
|
+
<el-input-number
|
|
28
|
+
v-bind="schema.option"
|
|
29
|
+
v-model="dtoValue"
|
|
30
|
+
:controls="false"
|
|
31
|
+
:placeholder="placeholder"
|
|
32
|
+
class="component"
|
|
33
|
+
:class="validTips?'valid-border':''"
|
|
34
|
+
@focus="onFocus"
|
|
35
|
+
@blur="onBlur"
|
|
36
|
+
/>
|
|
37
|
+
<div
|
|
38
|
+
v-if="validTips"
|
|
39
|
+
class="valid-tips"
|
|
40
|
+
>
|
|
41
|
+
{{ validTips }}
|
|
42
|
+
</div>
|
|
43
|
+
</el-row>
|
|
44
|
+
</el-row>
|
|
45
|
+
</template>
|
|
46
|
+
<script setup>
|
|
47
|
+
import { ref, toRefs, watch, inject, onMounted } from 'vue'
|
|
48
|
+
const ajv = inject('ajv')
|
|
49
|
+
|
|
50
|
+
// 接收父组件传入参数
|
|
51
|
+
const props = defineProps({
|
|
52
|
+
schemaKey: String, // 当前字段key(属性名,如productName)
|
|
53
|
+
schema: Object, // 当前字段完整schema配置
|
|
54
|
+
model: Object, // 当前字段的表单值
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// 解构props,toRefs保证响应式不丢失
|
|
58
|
+
const schemaKey = props.schemaKey
|
|
59
|
+
const { schema, model } = toRefs(props)
|
|
60
|
+
|
|
61
|
+
const name=ref('inputNumber')
|
|
62
|
+
const dtoValue=ref()
|
|
63
|
+
const placeholder=ref('')
|
|
64
|
+
const validTips=ref(null) // 校验错误信息
|
|
65
|
+
|
|
66
|
+
const initData=()=>{
|
|
67
|
+
dtoValue.value=model.value ?? schema.value.option?.default
|
|
68
|
+
validTips.value=null
|
|
69
|
+
|
|
70
|
+
const {
|
|
71
|
+
minimum,
|
|
72
|
+
maximum,
|
|
73
|
+
}=schema.value
|
|
74
|
+
|
|
75
|
+
const ruleList=[]
|
|
76
|
+
if(schema.value.option?.placeholder){
|
|
77
|
+
ruleList.push(schema.value.option.placeholder)
|
|
78
|
+
}
|
|
79
|
+
if(minimum !== undefined){
|
|
80
|
+
ruleList.push(`最小值应为 ${minimum}`)
|
|
81
|
+
}
|
|
82
|
+
if(maximum !== undefined){
|
|
83
|
+
ruleList.push(`最大值应为 ${maximum}`)
|
|
84
|
+
}
|
|
85
|
+
placeholder.value=ruleList.join('|')
|
|
86
|
+
}
|
|
87
|
+
onMounted(()=>{
|
|
88
|
+
initData()
|
|
89
|
+
})
|
|
90
|
+
watch([schema,model],()=>{
|
|
91
|
+
initData()
|
|
92
|
+
})
|
|
93
|
+
// 对外暴露:表单校验方法
|
|
94
|
+
const validate = () => {
|
|
95
|
+
// 清空上一轮校验错误提示
|
|
96
|
+
validTips.value = null;
|
|
97
|
+
// 解构取出schema里的type字段
|
|
98
|
+
const { type } = schema.value;
|
|
99
|
+
|
|
100
|
+
// 1、必填项校验
|
|
101
|
+
if (schema.value.option?.required && !dtoValue.value) {
|
|
102
|
+
validTips.value = '不能为空';
|
|
103
|
+
return false; // 校验失败,终止后续逻辑
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 2、输入有内容时,使用AJV库校验JSON Schema规则
|
|
107
|
+
if (dtoValue.value !== null && dtoValue.value !== undefined) {
|
|
108
|
+
// 编译当前字段的schema校验规则,生成校验函数
|
|
109
|
+
const validate = ajv.compile(schema.value);
|
|
110
|
+
// 执行校验:传入当前输入值
|
|
111
|
+
const valid = validate(dtoValue.value);
|
|
112
|
+
|
|
113
|
+
// 校验不通过 并且 存在错误详情
|
|
114
|
+
if (!valid && validate.errors && validate.errors[0]) {
|
|
115
|
+
// 取出第一条错误的关键字、参数
|
|
116
|
+
const { keyword, params } = validate.errors[0];
|
|
117
|
+
|
|
118
|
+
// 根据不同错误类型,自定义中文提示文案(把AJV默认英文提示转为中文)
|
|
119
|
+
if (keyword === 'type') {
|
|
120
|
+
validTips.value = `类型必须为 ${type}`;
|
|
121
|
+
} else if (keyword === 'minimum') {
|
|
122
|
+
validTips.value = `最小值应为 ${params.limit}`;
|
|
123
|
+
} else if (keyword === 'maximum') {
|
|
124
|
+
validTips.value = `最大值应为 ${params.limit}`;
|
|
125
|
+
} else {
|
|
126
|
+
// 其余未知错误兜底文案
|
|
127
|
+
console.log(validate.errors[0]);
|
|
128
|
+
validTips.value = '不符合要求';
|
|
129
|
+
}
|
|
130
|
+
return false; // 格式校验失败
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 所有校验全部通过
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
// 获得焦点时,清空校验错误提示
|
|
138
|
+
const onFocus = () => {
|
|
139
|
+
validTips.value = null;
|
|
140
|
+
}
|
|
141
|
+
// 失去焦点时,校验当前输入值
|
|
142
|
+
const onBlur = () => {
|
|
143
|
+
validate()
|
|
144
|
+
}
|
|
145
|
+
// 对外暴露:获取当前组件表单值
|
|
146
|
+
const getValue = () => {
|
|
147
|
+
return dtoValue.value !== undefined ? {
|
|
148
|
+
[schemaKey]:dtoValue.value
|
|
149
|
+
}:{}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 暴露方法给上层表单组件调用(全局表单提交校验、取值)
|
|
153
|
+
defineExpose({
|
|
154
|
+
name,
|
|
155
|
+
validate,
|
|
156
|
+
getValue
|
|
157
|
+
})
|
|
158
|
+
</script>
|
|
159
|
+
|
|
160
|
+
<style lang="less">
|
|
161
|
+
.el-input-number .el-input__inner {
|
|
162
|
+
text-align: left !important;
|
|
163
|
+
}
|
|
164
|
+
</style>
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- 整行容器:标签 + 输入框左右布局 -->
|
|
3
|
+
<el-row
|
|
4
|
+
type="flex"
|
|
5
|
+
align="middle"
|
|
6
|
+
class="form-item"
|
|
7
|
+
>
|
|
8
|
+
<!-- 左侧标签区域 -->
|
|
9
|
+
<el-row
|
|
10
|
+
class="item-label"
|
|
11
|
+
justify="end"
|
|
12
|
+
>
|
|
13
|
+
<!-- 必填红色星号:schema里required为true才展示 -->
|
|
14
|
+
<el-row
|
|
15
|
+
v-if="schema.option?.required"
|
|
16
|
+
type="flex"
|
|
17
|
+
class="required"
|
|
18
|
+
>
|
|
19
|
+
*
|
|
20
|
+
</el-row>
|
|
21
|
+
<!-- 字段中文名称 -->
|
|
22
|
+
{{ schema.label }}
|
|
23
|
+
</el-row>
|
|
24
|
+
|
|
25
|
+
<!-- 右侧输入框区域 -->
|
|
26
|
+
<el-row class="item-value">
|
|
27
|
+
<el-select
|
|
28
|
+
v-model="dtoValue"
|
|
29
|
+
v-bind="schema.option"
|
|
30
|
+
class="component"
|
|
31
|
+
:class="validTips?'valid-border':''"
|
|
32
|
+
@change="onChange"
|
|
33
|
+
>
|
|
34
|
+
<el-option
|
|
35
|
+
v-for="item in schema.option?.enumList"
|
|
36
|
+
:key="item.value"
|
|
37
|
+
:label="item.label"
|
|
38
|
+
:value="item.value"
|
|
39
|
+
/>
|
|
40
|
+
</el-select>
|
|
41
|
+
<div
|
|
42
|
+
v-if="validTips"
|
|
43
|
+
class="valid-tips"
|
|
44
|
+
>
|
|
45
|
+
{{ validTips }}
|
|
46
|
+
</div>
|
|
47
|
+
</el-row>
|
|
48
|
+
</el-row>
|
|
49
|
+
</template>
|
|
50
|
+
<script setup>
|
|
51
|
+
import { ref, toRefs, watch, inject, onMounted } from 'vue'
|
|
52
|
+
const ajv = inject('ajv')
|
|
53
|
+
|
|
54
|
+
// 接收父组件传入参数
|
|
55
|
+
const props = defineProps({
|
|
56
|
+
schemaKey: String, // 当前字段key(属性名,如productName)
|
|
57
|
+
schema: Object, // 当前字段完整schema配置
|
|
58
|
+
model: Object, // 当前字段的表单值
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// 解构props,toRefs保证响应式不丢失
|
|
62
|
+
const schemaKey = props.schemaKey
|
|
63
|
+
const { schema, model } = toRefs(props)
|
|
64
|
+
|
|
65
|
+
const name=ref('select')
|
|
66
|
+
const dtoValue=ref()
|
|
67
|
+
const validTips=ref(null) // 校验错误信息
|
|
68
|
+
|
|
69
|
+
const initData=()=>{
|
|
70
|
+
dtoValue.value=model.value ?? schema.value.option?.default
|
|
71
|
+
validTips.value=null
|
|
72
|
+
}
|
|
73
|
+
onMounted(()=>{
|
|
74
|
+
initData()
|
|
75
|
+
})
|
|
76
|
+
watch([schema,model],()=>{
|
|
77
|
+
initData()
|
|
78
|
+
})
|
|
79
|
+
// 对外暴露:表单校验方法
|
|
80
|
+
const validate = () => {
|
|
81
|
+
// 清空上一轮校验错误提示
|
|
82
|
+
validTips.value = null;
|
|
83
|
+
|
|
84
|
+
// 1、必填项校验
|
|
85
|
+
if (schema.value.option?.required && !dtoValue.value) {
|
|
86
|
+
validTips.value = '不能为空';
|
|
87
|
+
return false; // 校验失败,终止后续逻辑
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 2、输入有内容时,使用AJV库校验JSON Schema规则
|
|
91
|
+
if (dtoValue.value) {
|
|
92
|
+
let dtoEnum=[]
|
|
93
|
+
if(schema.value.option?.enumList){
|
|
94
|
+
dtoEnum=schema.value.option?.enumList.map(item=>item.value)
|
|
95
|
+
}
|
|
96
|
+
// 构造校验 schema:复用原字段 schema,并把 enum 替换为选项 value 列表
|
|
97
|
+
const validateSchema = { ...schema.value, enum: dtoEnum }
|
|
98
|
+
const validate=ajv.compile(validateSchema)
|
|
99
|
+
const valid=validate(dtoValue.value)
|
|
100
|
+
if(!valid && validate.errors && validate.errors[0]){
|
|
101
|
+
if(validate.errors[0].keyword==='enum'){
|
|
102
|
+
validTips.value='取值超出枚举范围'
|
|
103
|
+
}
|
|
104
|
+
else{
|
|
105
|
+
console.log(validate.errors[0])
|
|
106
|
+
}
|
|
107
|
+
return false; // 格式校验失败
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 所有校验全部通过
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 对外暴露:获取当前组件表单值
|
|
116
|
+
const getValue = () => {
|
|
117
|
+
return dtoValue.value !== undefined ? {
|
|
118
|
+
[schemaKey]:dtoValue.value
|
|
119
|
+
}:{}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const onChange=()=>{
|
|
123
|
+
validate()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 暴露方法给上层表单组件调用(全局表单提交校验、取值)
|
|
127
|
+
defineExpose({
|
|
128
|
+
name,
|
|
129
|
+
validate,
|
|
130
|
+
getValue
|
|
131
|
+
})
|
|
132
|
+
</script>
|
|
133
|
+
|
|
134
|
+
<style lang="less">
|
|
135
|
+
.form-item{
|
|
136
|
+
margin-bottom: 10px;
|
|
137
|
+
}
|
|
138
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import input from './complex-view/input/input.vue';
|
|
2
|
+
import inputNumber from './complex-view/input-number/input-number.vue';
|
|
3
|
+
import select from './complex-view/select/select.vue';
|
|
4
|
+
|
|
5
|
+
//业务扩展form-item配置
|
|
6
|
+
import BusinessFormItemConfig from '$businessSchemaFormItemConfig'
|
|
7
|
+
|
|
8
|
+
const FormItemConfig = {
|
|
9
|
+
input: {
|
|
10
|
+
component: input
|
|
11
|
+
},
|
|
12
|
+
inputNumber: {
|
|
13
|
+
component: inputNumber
|
|
14
|
+
},
|
|
15
|
+
select: {
|
|
16
|
+
component: select
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default {...FormItemConfig,...BusinessFormItemConfig};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-row
|
|
3
|
+
v-if="schema && schema.properties"
|
|
4
|
+
class="schema-form"
|
|
5
|
+
>
|
|
6
|
+
<!-- 外层循环所有表单字段 -->
|
|
7
|
+
<div
|
|
8
|
+
v-for="(itemSchema, key) in schema.properties"
|
|
9
|
+
v-show="itemSchema.option?.visible !== false"
|
|
10
|
+
:key="key"
|
|
11
|
+
class="form-item-wrapper"
|
|
12
|
+
>
|
|
13
|
+
<component
|
|
14
|
+
:is="FormItemConfig[itemSchema.option?.comType]?.component"
|
|
15
|
+
:ref="(el) => setFormComRef(el, key)"
|
|
16
|
+
:schema="itemSchema"
|
|
17
|
+
:schema-key="key"
|
|
18
|
+
:model="getFieldModel(key)"
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
21
|
+
</el-row>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script setup>
|
|
25
|
+
import {toRefs,provide,ref,unref,computed} from 'vue'
|
|
26
|
+
import FormItemConfig from './form-item-config.js'
|
|
27
|
+
|
|
28
|
+
const Ajv = require('ajv')
|
|
29
|
+
const ajv = new Ajv()
|
|
30
|
+
provide('ajv',ajv)
|
|
31
|
+
const formComList=ref({})
|
|
32
|
+
const setFormComRef=(el,key)=>{
|
|
33
|
+
if(el){
|
|
34
|
+
formComList.value[key]=el
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const props=defineProps({
|
|
39
|
+
/**
|
|
40
|
+
* schema:{
|
|
41
|
+
//板块数据结构
|
|
42
|
+
type:'object',
|
|
43
|
+
properties:{
|
|
44
|
+
key:{
|
|
45
|
+
...schema, //标准schema配置
|
|
46
|
+
type:'', //字段类型
|
|
47
|
+
label:'', //字段的中文名
|
|
48
|
+
option:{
|
|
49
|
+
...elComponentConfig,//标准el-component-column配置
|
|
50
|
+
comType:'',// 配置组件类型 input/select...
|
|
51
|
+
required:false, //表单项是否必填
|
|
52
|
+
visible:true, //是否在createForm中显示
|
|
53
|
+
disabled:false, //是否禁用createForm中的该字段
|
|
54
|
+
default:'', //默认值
|
|
55
|
+
|
|
56
|
+
//comType===select时,enumList为下拉选项列表
|
|
57
|
+
enumList:[], //下拉可选项
|
|
58
|
+
//comType===dynamicSelect时,enumList为动态下 拉选项列表
|
|
59
|
+
api:'' //动态下拉可选项
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
*/
|
|
64
|
+
schema:Object,
|
|
65
|
+
/**
|
|
66
|
+
* 表单数据
|
|
67
|
+
*/
|
|
68
|
+
model:Object
|
|
69
|
+
})
|
|
70
|
+
const {schema}=toRefs(props)
|
|
71
|
+
|
|
72
|
+
// 把 props.model 统一解包为普通对象,避免模板 prop 表达式里直接 model[key] 丢失响应追踪
|
|
73
|
+
const fieldModel = computed(() => unref(props.model) ?? {})
|
|
74
|
+
const getFieldModel = (key) => fieldModel.value[key]
|
|
75
|
+
|
|
76
|
+
//表单校验
|
|
77
|
+
const validate=()=>{
|
|
78
|
+
return Object.values(formComList.value).every(component=>component && typeof component.validate==='function' && component.validate())
|
|
79
|
+
}
|
|
80
|
+
//获取表单值
|
|
81
|
+
const getValue=()=>{
|
|
82
|
+
return Object.values(formComList.value).reduce((dtoObj,component)=>{
|
|
83
|
+
if(!component || typeof component.getValue!=='function'){
|
|
84
|
+
return dtoObj
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
...dtoObj,
|
|
88
|
+
...component.getValue()
|
|
89
|
+
}
|
|
90
|
+
},{})
|
|
91
|
+
}
|
|
92
|
+
defineExpose({
|
|
93
|
+
validate,
|
|
94
|
+
getValue
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
</script>
|
|
99
|
+
|
|
100
|
+
<style lang="less">
|
|
101
|
+
.schema-form{
|
|
102
|
+
.form-item {
|
|
103
|
+
margin-bottom: 20px;
|
|
104
|
+
min-width: 500px;
|
|
105
|
+
|
|
106
|
+
// 左侧表单标签区域
|
|
107
|
+
.item-label {
|
|
108
|
+
margin-right: 15px;
|
|
109
|
+
min-width: 70px;
|
|
110
|
+
text-align: right;
|
|
111
|
+
font-size: 14px;
|
|
112
|
+
color: #333333;
|
|
113
|
+
word-break: break-all;
|
|
114
|
+
|
|
115
|
+
// 必填红色星号 *
|
|
116
|
+
.required {
|
|
117
|
+
position: relative;
|
|
118
|
+
top: 2px;
|
|
119
|
+
padding-left: 4px;
|
|
120
|
+
color: #f56c6c;
|
|
121
|
+
font-size: 20px;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 右侧输入组件区域
|
|
126
|
+
.item-value {
|
|
127
|
+
.component {
|
|
128
|
+
width: 320px;
|
|
129
|
+
}
|
|
130
|
+
// 校验激活时的边框样式
|
|
131
|
+
.valid-border {
|
|
132
|
+
.el-input__wrapper {
|
|
133
|
+
border: 1px solid #F93F3F;
|
|
134
|
+
box-shadow: 0 0 0;
|
|
135
|
+
}
|
|
136
|
+
.el-select__wrapper {
|
|
137
|
+
border: 1px solid #F93F3F;
|
|
138
|
+
box-shadow: 0 0 0;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 校验错误提示文字
|
|
144
|
+
.valid-tips {
|
|
145
|
+
margin-left: 10px;
|
|
146
|
+
height: 36px;
|
|
147
|
+
line-height: 36px;
|
|
148
|
+
overflow: hidden;
|
|
149
|
+
font-size: 12px;
|
|
150
|
+
color: #F93F3F;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
</style>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { onMounted } from 'vue';
|
|
2
|
+
<template>
|
|
3
|
+
<el-date-picker
|
|
4
|
+
v-model="dtoValue"
|
|
5
|
+
v-bind="schema.option"
|
|
6
|
+
type="daterange"
|
|
7
|
+
:start-placeholder="schema.label + ' 开始日期'"
|
|
8
|
+
:end-placeholder="schema.label + ' 结束日期'"
|
|
9
|
+
class="date-range"
|
|
10
|
+
>
|
|
11
|
+
</el-date-picker>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
import {ref,onMounted} from 'vue'
|
|
16
|
+
import moment from 'moment'
|
|
17
|
+
|
|
18
|
+
const {schemaKey,schema}=defineProps({
|
|
19
|
+
schemaKey:String,
|
|
20
|
+
schema:Object,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const emit=defineEmits(['load'])
|
|
24
|
+
|
|
25
|
+
const dtoValue=ref([])
|
|
26
|
+
const getValue=()=>{
|
|
27
|
+
return dtoValue.value.length===2?
|
|
28
|
+
{[`${schemaKey}_start`]:moment(dtoValue.value[0]).format('YYYY-MM-DD'),
|
|
29
|
+
[`${schemaKey}_end`]:moment(dtoValue.value[1]).format('YYYY-MM-DD')}
|
|
30
|
+
:{}
|
|
31
|
+
}
|
|
32
|
+
const reset=()=>{
|
|
33
|
+
dtoValue.value=[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
onMounted(()=>{
|
|
37
|
+
reset()
|
|
38
|
+
emit('load')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
defineExpose({
|
|
42
|
+
getValue,
|
|
43
|
+
reset,
|
|
44
|
+
})
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
|
|
49
|
+
</style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-select
|
|
3
|
+
v-model="dtoValue"
|
|
4
|
+
v-bind="schema.option"
|
|
5
|
+
class="dynamic-select"
|
|
6
|
+
>
|
|
7
|
+
<el-option
|
|
8
|
+
v-for="item in enumList"
|
|
9
|
+
:key="item.value"
|
|
10
|
+
:label="item.label"
|
|
11
|
+
:value="item.value"
|
|
12
|
+
/>
|
|
13
|
+
</el-select>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup>
|
|
17
|
+
import {ref,onMounted} from 'vue'
|
|
18
|
+
import $curl from '$elpisCommon/curl.js'
|
|
19
|
+
|
|
20
|
+
const {schemaKey,schema}=defineProps({
|
|
21
|
+
schemaKey:String,
|
|
22
|
+
schema:Object,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const emit=defineEmits(['load'])
|
|
26
|
+
|
|
27
|
+
const dtoValue=ref()
|
|
28
|
+
const getValue=()=>{
|
|
29
|
+
return dtoValue.value!==undefined && dtoValue.value!==''?
|
|
30
|
+
{[schemaKey]:dtoValue.value}:
|
|
31
|
+
{}
|
|
32
|
+
}
|
|
33
|
+
const reset=()=>{
|
|
34
|
+
dtoValue.value=schema?.option?.default ?? enumList.value?.[0]?.value
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const enumList=ref([])
|
|
38
|
+
const fetchEnumList=async()=>{
|
|
39
|
+
const res=await $curl({
|
|
40
|
+
method:'get',
|
|
41
|
+
url:schema?.option?.api,
|
|
42
|
+
data:{}
|
|
43
|
+
})
|
|
44
|
+
if(res?.data?.length>0){
|
|
45
|
+
enumList.value.push(...res?.data)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
onMounted(()=>{
|
|
52
|
+
fetchEnumList()
|
|
53
|
+
reset()
|
|
54
|
+
emit('load')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
defineExpose({
|
|
58
|
+
getValue,
|
|
59
|
+
reset,
|
|
60
|
+
})
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<style>
|
|
64
|
+
|
|
65
|
+
</style>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { onMounted } from 'vue';
|
|
2
|
+
<template>
|
|
3
|
+
<el-input
|
|
4
|
+
v-model="dtoValue"
|
|
5
|
+
v-bind="schema.option"
|
|
6
|
+
class="input"
|
|
7
|
+
>
|
|
8
|
+
</el-input>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup>
|
|
12
|
+
import {ref,onMounted} from 'vue'
|
|
13
|
+
|
|
14
|
+
const {schemaKey,schema}=defineProps({
|
|
15
|
+
schemaKey:String,
|
|
16
|
+
schema:Object,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const emit=defineEmits(['load'])
|
|
20
|
+
|
|
21
|
+
const dtoValue=ref()
|
|
22
|
+
const getValue=()=>{
|
|
23
|
+
return dtoValue.value!==undefined && dtoValue.value!==''?
|
|
24
|
+
{[schemaKey]:dtoValue.value}:
|
|
25
|
+
{}
|
|
26
|
+
}
|
|
27
|
+
const reset=()=>{
|
|
28
|
+
dtoValue.value=schema?.option?.default||''
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
onMounted(()=>{
|
|
32
|
+
reset()
|
|
33
|
+
emit('load')
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
defineExpose({
|
|
37
|
+
getValue,
|
|
38
|
+
reset,
|
|
39
|
+
})
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<style>
|
|
43
|
+
|
|
44
|
+
</style>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { onMounted } from 'vue';
|
|
2
|
+
<template>
|
|
3
|
+
<el-select
|
|
4
|
+
v-model="dtoValue"
|
|
5
|
+
v-bind="schema.option"
|
|
6
|
+
class="select"
|
|
7
|
+
>
|
|
8
|
+
<el-option
|
|
9
|
+
v-for="item in schema.option?.enumList"
|
|
10
|
+
:key="item.value"
|
|
11
|
+
:label="item.label"
|
|
12
|
+
:value="item.value"
|
|
13
|
+
/>
|
|
14
|
+
</el-select>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup>
|
|
18
|
+
import {ref,onMounted} from 'vue'
|
|
19
|
+
|
|
20
|
+
const {schemaKey,schema}=defineProps({
|
|
21
|
+
schemaKey:String,
|
|
22
|
+
schema:Object,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const emit=defineEmits(['load'])
|
|
26
|
+
|
|
27
|
+
const dtoValue=ref()
|
|
28
|
+
const getValue=()=>{
|
|
29
|
+
return dtoValue.value!==undefined && dtoValue.value!==''?
|
|
30
|
+
{[schemaKey]:dtoValue.value}:
|
|
31
|
+
{}
|
|
32
|
+
}
|
|
33
|
+
const reset=()=>{
|
|
34
|
+
dtoValue.value=schema?.option?.default ?? schema?.option?.enumList?.[0]?.value
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
onMounted(()=>{
|
|
38
|
+
reset()
|
|
39
|
+
emit('load')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
defineExpose({
|
|
43
|
+
getValue,
|
|
44
|
+
reset,
|
|
45
|
+
})
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<style>
|
|
49
|
+
|
|
50
|
+
</style>
|