@wanglindoc/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.
Files changed (88) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +52 -0
  3. package/.idea/codeStyles/Project.xml +14 -0
  4. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  5. package/.idea/elpis.iml +12 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  7. package/.idea/modules.xml +8 -0
  8. package/.idea/prettier.xml +7 -0
  9. package/.idea/vcs.xml +6 -0
  10. package/README.md +232 -0
  11. package/app/controller/base.js +42 -0
  12. package/app/controller/project.js +76 -0
  13. package/app/controller/view.js +19 -0
  14. package/app/extend/logger.js +42 -0
  15. package/app/middleware/api-params-verify.js +81 -0
  16. package/app/middleware/api-sign-verify.js +45 -0
  17. package/app/middleware/error-handler.js +41 -0
  18. package/app/middleware/project-handler.js +30 -0
  19. package/app/middleware.js +42 -0
  20. package/app/pages/assets/custom.css +14 -0
  21. package/app/pages/boot.js +51 -0
  22. package/app/pages/common/curl.js +91 -0
  23. package/app/pages/common/utils.js +7 -0
  24. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +18 -0
  25. package/app/pages/dashboard/complex-view/header-view/header-view.vue +154 -0
  26. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +46 -0
  27. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +40 -0
  28. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +127 -0
  29. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +22 -0
  30. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +95 -0
  31. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +104 -0
  32. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +129 -0
  33. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +137 -0
  34. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +102 -0
  35. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu.vue +21 -0
  36. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +141 -0
  37. package/app/pages/dashboard/dashboard.vue +96 -0
  38. package/app/pages/dashboard/entry.dashboard.js +53 -0
  39. package/app/pages/dashboard/todo/todo.vue +6 -0
  40. package/app/pages/store/index.js +5 -0
  41. package/app/pages/store/menu.js +73 -0
  42. package/app/pages/store/project.js +15 -0
  43. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  44. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  45. package/app/pages/widgets/header-container/header-container.vue +106 -0
  46. package/app/pages/widgets/schema-form/complex-view/input/input.vue +137 -0
  47. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +135 -0
  48. package/app/pages/widgets/schema-form/complex-view/select/select.vue +119 -0
  49. package/app/pages/widgets/schema-form/form-item-config.js +20 -0
  50. package/app/pages/widgets/schema-form/schema-form.vue +145 -0
  51. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +52 -0
  52. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +65 -0
  53. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +42 -0
  54. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +49 -0
  55. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +129 -0
  56. package/app/pages/widgets/schema-search-bar/search-item-config.js +24 -0
  57. package/app/pages/widgets/schema-table/schema-table.vue +212 -0
  58. package/app/pages/widgets/sider-container/sider-container.vue +26 -0
  59. package/app/public/output/entry.page1.tpl +55 -0
  60. package/app/public/output/entry.page2.tpl +11 -0
  61. package/app/public/static/favicon.ico +0 -0
  62. package/app/public/static/normalize.css +267 -0
  63. package/app/router/project.js +14 -0
  64. package/app/router/view.js +9 -0
  65. package/app/router-schema/project.js +32 -0
  66. package/app/service/base.js +15 -0
  67. package/app/service/project.js +48 -0
  68. package/app/view/entry.tpl +22 -0
  69. package/app/webpack/build-dev.js +64 -0
  70. package/app/webpack/build-prod.js +29 -0
  71. package/app/webpack/config/webpack.base.js +352 -0
  72. package/app/webpack/config/webpack.dev.js +59 -0
  73. package/app/webpack/config/webpack.prod.js +145 -0
  74. package/app/webpack/libs/blank.js +1 -0
  75. package/config/config.default.js +4 -0
  76. package/elpis-core/env.js +20 -0
  77. package/elpis-core/index.js +106 -0
  78. package/elpis-core/loader/config.js +62 -0
  79. package/elpis-core/loader/controller.js +79 -0
  80. package/elpis-core/loader/extend.js +67 -0
  81. package/elpis-core/loader/middleware.js +77 -0
  82. package/elpis-core/loader/router-schema.js +57 -0
  83. package/elpis-core/loader/router.js +57 -0
  84. package/elpis-core/loader/service.js +76 -0
  85. package/index.js +39 -0
  86. package/model/index.js +128 -0
  87. package/package.json +90 -0
  88. package/test/controller/project.test.js +243 -0
@@ -0,0 +1,135 @@
1
+ <template>
2
+ <el-row type="flex" align="middle" class="form-item">
3
+ <el-row class="item-label" justify="end">
4
+ <el-row
5
+ v-if="schema && schema.option?.required"
6
+ type="flex"
7
+ class="required"
8
+ >
9
+ *
10
+ </el-row>
11
+ {{ schema.label }}
12
+ </el-row>
13
+
14
+ <el-row class="item-value">
15
+ <el-input-number
16
+ v-model="dtoValue"
17
+ v-bind="schema.option"
18
+ :controls="false"
19
+ :placeholder="placeholder"
20
+ class="component"
21
+ :class="validTips ? 'valid-border' : ''"
22
+ @focus="onFocus"
23
+ @blur="onBlur"
24
+ ></el-input-number>
25
+ </el-row>
26
+
27
+ <!-- 错误信息 -->
28
+ <el-row v-if="validTips" class="valid-tips">
29
+ {{ validTips }}
30
+ </el-row>
31
+ </el-row>
32
+ </template>
33
+
34
+ <script setup>
35
+ import { ref, toRefs, watch, inject, onMounted } from "vue";
36
+ const ajv = inject("ajv");
37
+
38
+ const props = defineProps({
39
+ schemaKey: String,
40
+ schema: Object,
41
+ model: Number,
42
+ });
43
+
44
+ const { schema, schemaKey } = props;
45
+ const { model } = toRefs(props);
46
+
47
+ const name = ref("inputNumber");
48
+ const dtoValue = ref();
49
+ const validTips = ref(null);
50
+ const placeholder = ref("");
51
+ const initData = () => {
52
+ dtoValue.value = model.value ?? schema.option?.default;
53
+ validTips.value = null;
54
+
55
+ const { minimum, maximum } = schema;
56
+ const ruleList = [];
57
+ if (schema.option?.placeholder) {
58
+ ruleList.push(schema.option.placeholder);
59
+ }
60
+
61
+ if (minimum) {
62
+ ruleList.push(`最小值:${minimum}`);
63
+ }
64
+
65
+ if (maximum) {
66
+ ruleList.push(`最大值:${maximum}`);
67
+ }
68
+
69
+ placeholder.value = ruleList.join["|"];
70
+ };
71
+
72
+ onMounted(() => {
73
+ initData();
74
+ });
75
+
76
+ watch(
77
+ [model, schema],
78
+ () => {
79
+ initData();
80
+ },
81
+ { deep: true },
82
+ );
83
+
84
+ const validate = () => {
85
+ validTips.value = null;
86
+ const { type } = schema;
87
+
88
+ if (schema.option?.required && !dtoValue.value) {
89
+ validTips.value = "不能为空";
90
+ return false;
91
+ }
92
+
93
+ if (dtoValue.value) {
94
+ const validate = ajv.compile(schema);
95
+ const valid = validate(dtoValue.value);
96
+
97
+ if (!valid && validate.errors && validate.errors[0]) {
98
+ const { keyword, params } = validate.errors[0];
99
+ if (keyword === "type") {
100
+ validTips.value = `类型必须为 ${type}`;
101
+ } else if (keyword === "minimum") {
102
+ validTips.value = `最小值应为 ${params.limit}`;
103
+ } else if (keyword === "maximum") {
104
+ validTips.value = `最大值应为 ${params.limit}`;
105
+ } else {
106
+ console.log(validate.errors[0]);
107
+ validTips.value = "不符合要求";
108
+ }
109
+ return false;
110
+ }
111
+ }
112
+
113
+ return true;
114
+ };
115
+
116
+ const getValue = () => {
117
+ return dtoValue.value !== undefined ? { [schemaKey]: dtoValue.value } : {};
118
+ };
119
+
120
+ const onFocus = () => (validTips.value = null);
121
+
122
+ const onBlur = () => validate();
123
+
124
+ defineExpose({
125
+ name,
126
+ validate,
127
+ getValue,
128
+ });
129
+ </script>
130
+
131
+ <style scoped lang="less">
132
+ :deep(.el-input-number .el-input__inner) {
133
+ text-align: left;
134
+ }
135
+ </style>
@@ -0,0 +1,119 @@
1
+ <template>
2
+ <el-row type="flex" align="middle" class="form-item">
3
+ <el-row class="item-label" justify="end">
4
+ <el-row
5
+ v-if="schema && schema.option?.required"
6
+ type="flex"
7
+ class="required"
8
+ >
9
+ *
10
+ </el-row>
11
+ {{ schema.label }}
12
+ </el-row>
13
+
14
+ <el-row class="item-value">
15
+ <el-select
16
+ v-model="dtoValue"
17
+ v-bind="schema.option"
18
+ class="component"
19
+ :class="validTips ? 'valid-border' : ''"
20
+ @change="onChange"
21
+ >
22
+ <el-option
23
+ v-for="item in schema.option?.enumList"
24
+ :key="item.value"
25
+ :label="item.label"
26
+ :value="item.value"
27
+ >
28
+ </el-option>
29
+ </el-select>
30
+ </el-row>
31
+
32
+ <!-- 错误信息 -->
33
+ <el-row v-if="validTips" class="valid-tips">
34
+ {{ validTips }}
35
+ </el-row>
36
+ </el-row>
37
+ </template>
38
+
39
+ <script setup>
40
+ import { ref, toRefs, watch, inject, onMounted } from "vue";
41
+ const ajv = inject("ajv");
42
+
43
+ const props = defineProps({
44
+ schemaKey: String,
45
+ schema: Object,
46
+ model: Object,
47
+ });
48
+
49
+ const { schema, schemaKey } = props;
50
+ const { model } = toRefs(props);
51
+
52
+ const name = ref("select");
53
+ const dtoValue = ref("");
54
+ const validTips = ref("");
55
+ const initData = () => {
56
+ dtoValue.value = model.value ?? schema.option?.default;
57
+ validTips.value = null;
58
+ };
59
+
60
+ onMounted(() => {
61
+ initData();
62
+ });
63
+
64
+ watch(
65
+ [model, schema],
66
+ () => {
67
+ initData();
68
+ },
69
+ { deep: true },
70
+ );
71
+
72
+ const validate = () => {
73
+ validTips.value = null;
74
+
75
+ if (schema.option?.required && !dtoValue.value) {
76
+ validTips.value = "不能为空";
77
+ return false;
78
+ }
79
+
80
+ if (dtoValue.value) {
81
+ let dtoEnum = [];
82
+ if (schema.option?.enumList) {
83
+ dtoEnum = schema.option?.enumList.map((item) => item.value);
84
+ }
85
+
86
+ const validate = ajv.compile({
87
+ schema,
88
+ ...{ enum: dtoEnum },
89
+ });
90
+
91
+ const valid = validate(dtoValue.value);
92
+ if (!valid && validate.errors && validate.errors[0]) {
93
+ if (validate.errors[0].keyword === "enum") {
94
+ validTips.value = "取值超出枚举范围";
95
+ } else {
96
+ console.log(validate.errors[0]);
97
+ validTips.value = "不符合要求";
98
+ }
99
+ return false;
100
+ }
101
+ }
102
+
103
+ return true;
104
+ };
105
+
106
+ const getValue = () => {
107
+ return dtoValue.value !== undefined ? { [schemaKey]: dtoValue.value } : {};
108
+ };
109
+
110
+ const onChange = () => validate();
111
+
112
+ defineExpose({
113
+ name,
114
+ validate,
115
+ getValue,
116
+ });
117
+ </script>
118
+
119
+ <style scoped lang="less"></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 "$businessFormItemConfig";
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,145 @@
1
+ <template>
2
+ <el-row v-if="schema && schema.properties" class="schema-form">
3
+ <template v-for="(itemSchema, key) in schema.properties">
4
+ <component
5
+ ref="formComList"
6
+ v-show="itemSchema.option.visible !== false"
7
+ :is="formItemConfig[itemSchema.option?.comType]?.component"
8
+ :schemaKey="key"
9
+ :schema="itemSchema"
10
+ :model="model ? model[key] : undefined"
11
+ ></component>
12
+ </template>
13
+ </el-row>
14
+ </template>
15
+
16
+ <script setup>
17
+ // 1、接收什么属性
18
+ // 2、返回什么事件
19
+ // 3、暴露什么方法
20
+
21
+ import { provide, ref, toRefs } from "vue";
22
+ import formItemConfig from "./form-item-config";
23
+ const Ajv = require("ajv");
24
+ const ajv = new Ajv();
25
+
26
+ provide("ajv", ajv);
27
+
28
+ const props = defineProps({
29
+ /**
30
+ * schema 配置,结构如下:
31
+ * {
32
+ * type:'object',
33
+ * properties: {
34
+ * key: {
35
+ * ...schema, // 标准 schema 配置
36
+ * type: "", // 字段类型
37
+ * label: "", // 字段中文名
38
+ * option: {
39
+ * ...eleComponentConfig, // 标准 el-component 配置
40
+ * comType: "", // 控件类型 input/select/input-number
41
+ * required: false, // 表单项是否必填,默认 false
42
+ * visible: true, // 是否展示(true/false)默认 true
43
+ * disabled: false, // 是否禁用(true/false)默认 false
44
+ * default: '', // 默认值
45
+ *
46
+ * // comType === 'select' 时生效
47
+ * enumList: []
48
+ * }
49
+ * }
50
+ * }
51
+ * }
52
+ */
53
+ schema: Object,
54
+
55
+ /**
56
+ * 表单数据
57
+ */
58
+ model: Object,
59
+ });
60
+
61
+ const { schema } = toRefs(props);
62
+
63
+ const formComList = ref([]);
64
+
65
+ /**
66
+ * 表单校验方法
67
+ */
68
+ const validate = () => {
69
+ return formComList.value.every((component) => component.validate());
70
+ };
71
+
72
+ /**
73
+ * 获取表单值
74
+ */
75
+ const getValue = () => {
76
+ // let dtoObj = {};
77
+
78
+ // formComList.value.forEach((component) => {
79
+ // dtoObj = {
80
+ // ...dtoObj,
81
+ // ...component.getValue(),
82
+ // };
83
+ // });
84
+
85
+ // return dtoObj;
86
+
87
+ return formComList.value.reduce((pre, cur) => {
88
+ return {
89
+ ...pre,
90
+ ...cur.getValue(),
91
+ };
92
+ }, {});
93
+ };
94
+
95
+ defineExpose({
96
+ validate,
97
+ getValue,
98
+ });
99
+ </script>
100
+
101
+ <style lang="less">
102
+ .schema-form {
103
+ .form-item {
104
+ margin-bottom: 20px;
105
+ min-width: 500px;
106
+
107
+ .item-label {
108
+ margin-right: 15px;
109
+ min-width: 70px;
110
+ text-align: right;
111
+ font-size: 14px;
112
+ word-break: break-all;
113
+
114
+ .required {
115
+ top: 2px;
116
+ padding-left: 4px;
117
+ color: tomato;
118
+ font-size: 20px;
119
+ }
120
+ }
121
+
122
+ .item-value {
123
+ .component {
124
+ width: 320px;
125
+ }
126
+
127
+ .valid-border {
128
+ .el-input__wrapper {
129
+ border: 1px solid tomato;
130
+ box-shadow: 0 0 0 0;
131
+ }
132
+ }
133
+ }
134
+
135
+ .valid-tips {
136
+ margin-left: 10px;
137
+ height: 36px;
138
+ line-height: 36px;
139
+ overflow: hidden;
140
+ font-size: 12px;
141
+ color: tomato;
142
+ }
143
+ }
144
+ }
145
+ </style>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <el-date-picker
3
+ v-model="dtoValue"
4
+ v-bind="schema.option"
5
+ type="daterange"
6
+ range-separator="至"
7
+ :start-placeholder="schema.label + '(开始)'"
8
+ :end-placeholder="schema.label + '(结束)'"
9
+ class="date-range"
10
+ ></el-date-picker>
11
+ </template>
12
+
13
+ <script setup>
14
+ import { ref, onMounted } from "vue";
15
+ import moment from "moment";
16
+
17
+ const { schema, schemaKey } = defineProps({
18
+ schemaKey: String,
19
+ schema: Object,
20
+ });
21
+
22
+ const emits = defineEmits(["loaded"]);
23
+
24
+ // 为什么初始值是 undefined 而不是空字符串
25
+ // 因为 undefined 会在搜索的时候被过滤掉,如果存在 router-schema 必填校验,则接口会报错,但空字串会被认为传递的就是空串
26
+ const dtoValue = ref([]);
27
+
28
+ const getValue = () => {
29
+ return dtoValue.value?.length === 2
30
+ ? {
31
+ [`${schemaKey}_start`]: moment(dtoValue.value[0]).format("YYYY-MM-DD"),
32
+ [`${schemaKey}_end`]: moment(dtoValue.value[1]).format("YYYY-MM-DD"),
33
+ }
34
+ : {};
35
+ };
36
+
37
+ const reset = () => {
38
+ dtoValue.value = [];
39
+ };
40
+
41
+ onMounted(() => {
42
+ reset();
43
+ emits("loaded");
44
+ });
45
+
46
+ defineExpose({
47
+ getValue,
48
+ reset,
49
+ });
50
+ </script>
51
+
52
+ <style scoped lang="less"></style>
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <el-select v-model="dtoValue" v-bind="schema.option" class="dynamic-select">
3
+ <el-option
4
+ v-for="item in enumList"
5
+ :key="item.value"
6
+ :label="item.label"
7
+ :value="item.value"
8
+ ></el-option>
9
+ </el-select>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { ref, onMounted } from "vue";
14
+ import $curl from "$elpisCommon/curl.js";
15
+
16
+ const { schema, schemaKey } = defineProps({
17
+ schemaKey: String,
18
+ schema: Object,
19
+ });
20
+
21
+ const emits = defineEmits(["loaded"]);
22
+
23
+ // 为什么初始值是 undefined 而不是空字符串
24
+ // 因为 undefined 会在搜索的时候被过滤掉,如果存在 router-schema 必填校验,则接口会报错,但空字串会被认为传递的就是空串
25
+ const dtoValue = ref();
26
+
27
+ const getValue = () => {
28
+ return dtoValue.value !== undefined
29
+ ? {
30
+ [schemaKey]: dtoValue.value,
31
+ }
32
+ : {};
33
+ };
34
+
35
+ const reset = () => {
36
+ dtoValue.value = schema?.option?.default ?? enumList.value[0]?.value;
37
+ };
38
+
39
+ const enumList = ref([]);
40
+
41
+ const fetchEnumList = async () => {
42
+ const res = await $curl({
43
+ method: "get",
44
+ url: schema?.option?.api,
45
+ data: {},
46
+ });
47
+
48
+ if (res?.data?.length > 0) {
49
+ enumList.value.push(...res?.data);
50
+ }
51
+ };
52
+
53
+ onMounted(async () => {
54
+ await fetchEnumList();
55
+ reset();
56
+ emits("loaded");
57
+ });
58
+
59
+ defineExpose({
60
+ getValue,
61
+ reset,
62
+ });
63
+ </script>
64
+
65
+ <style scoped lang="less"></style>
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <el-input v-model="dtoValue" v-bind="schema.option" class="input"></el-input>
3
+ </template>
4
+
5
+ <script setup>
6
+ import { ref, onMounted } from "vue";
7
+
8
+ const { schema, schemaKey } = defineProps({
9
+ schemaKey: String,
10
+ schema: Object,
11
+ });
12
+
13
+ const emits = defineEmits(["loaded"]);
14
+
15
+ // 为什么初始值是 undefined 而不是空字符串
16
+ // 因为 undefined 会在搜索的时候被过滤掉,如果存在 router-schema 必填校验,则接口会报错,但空字串会被认为传递的就是空串
17
+ const dtoValue = ref();
18
+
19
+ const getValue = () => {
20
+ return dtoValue.value !== undefined
21
+ ? {
22
+ [schemaKey]: dtoValue.value,
23
+ }
24
+ : {};
25
+ };
26
+
27
+ const reset = () => {
28
+ dtoValue.value = schema?.option?.default;
29
+ };
30
+
31
+ onMounted(() => {
32
+ reset();
33
+ emits("loaded");
34
+ });
35
+
36
+ defineExpose({
37
+ getValue,
38
+ reset,
39
+ });
40
+ </script>
41
+
42
+ <style scoped lang="less"></style>
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <el-select v-model="dtoValue" v-bind="schema.option" class="select">
3
+ <el-option
4
+ v-for="item in schema.option?.enumList"
5
+ :key="item.value"
6
+ :label="item.label"
7
+ :value="item.value"
8
+ ></el-option>
9
+ </el-select>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { ref, onMounted } from "vue";
14
+
15
+ const { schema, schemaKey } = defineProps({
16
+ schemaKey: String,
17
+ schema: Object,
18
+ });
19
+
20
+ const emits = defineEmits(["loaded"]);
21
+
22
+ // 为什么初始值是 undefined 而不是空字符串
23
+ // 因为 undefined 会在搜索的时候被过滤掉,如果存在 router-schema 必填校验,则接口会报错,但空字串会被认为传递的就是空串
24
+ const dtoValue = ref();
25
+
26
+ const getValue = () => {
27
+ return dtoValue.value !== undefined
28
+ ? {
29
+ [schemaKey]: dtoValue.value,
30
+ }
31
+ : {};
32
+ };
33
+
34
+ const reset = () => {
35
+ dtoValue.value = schema?.option?.default ?? schema.option?.enumList[0]?.value;
36
+ };
37
+
38
+ onMounted(() => {
39
+ reset();
40
+ emits("loaded");
41
+ });
42
+
43
+ defineExpose({
44
+ getValue,
45
+ reset,
46
+ });
47
+ </script>
48
+
49
+ <style scoped lang="less"></style>