@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,95 @@
1
+ <template>
2
+ <el-drawer
3
+ v-model="isShow"
4
+ direction="rtl"
5
+ :destory-on-close="true"
6
+ :size="550"
7
+ >
8
+ <template #header>
9
+ <h3>{{ title }}</h3>
10
+ </template>
11
+
12
+ <template #default>
13
+ <schema-form
14
+ ref="schemaFormRef"
15
+ v-loading="loading"
16
+ :schema="components[name]?.schema"
17
+ ></schema-form>
18
+ </template>
19
+
20
+ <template #footer>
21
+ <el-button type="primary" @click="save">
22
+ {{ saveBtnText }}
23
+ </el-button>
24
+ </template>
25
+ </el-drawer>
26
+ </template>
27
+
28
+ <script setup>
29
+ import { ref, inject } from "vue";
30
+ import SchemaForm from "$elpisWidgets/schema-form/schema-form.vue";
31
+ import $curl from "$elpisCommon/curl.js";
32
+ import { ElNotification } from "element-plus";
33
+
34
+ const { api, components } = inject("schemaViewData");
35
+ const emits = defineEmits(["command"]);
36
+
37
+ const name = ref("createForm");
38
+ const isShow = ref(false);
39
+ const title = ref("");
40
+ const saveBtnText = ref("");
41
+ const loading = ref(false);
42
+ const schemaFormRef = ref(null);
43
+
44
+ const show = (rowData) => {
45
+ const { config } = components.value[name.value];
46
+ title.value = config.title;
47
+ saveBtnText.value = config.saveBtnText;
48
+
49
+ isShow.value = true;
50
+ };
51
+
52
+ const save = async () => {
53
+ if (loading.value) {
54
+ return;
55
+ }
56
+
57
+ // 校验表单
58
+ if (!schemaFormRef.value?.validate()) {
59
+ return;
60
+ }
61
+
62
+ loading.value = true;
63
+
64
+ const res = await $curl({
65
+ method: "post",
66
+ url: api.value,
67
+ data: {
68
+ ...schemaFormRef.value.getValue(),
69
+ },
70
+ });
71
+
72
+ loading.value = false;
73
+
74
+ if (!res || !res.success) {
75
+ return;
76
+ }
77
+
78
+ ElNotification({
79
+ title: "创建成功",
80
+ message: "创建成功",
81
+ type: "success",
82
+ });
83
+
84
+ isShow.value = false;
85
+
86
+ emits("command", { event: "loadTableData" });
87
+ };
88
+
89
+ defineExpose({
90
+ name,
91
+ show,
92
+ });
93
+ </script>
94
+
95
+ <style lang="less" scoped></style>
@@ -0,0 +1,104 @@
1
+ <template>
2
+ <el-drawer
3
+ v-model="isShow"
4
+ direction="rtl"
5
+ :destory-on-close="true"
6
+ :size="550"
7
+ >
8
+ <template #header>
9
+ <h3>{{ title }}</h3>
10
+ </template>
11
+
12
+ <template #default>
13
+ <el-card v-loading="loading" shadow="always" class="detail-panel">
14
+ <el-row
15
+ v-for="(item, key) in components[name]?.schema?.properties"
16
+ :key="key"
17
+ type="flex"
18
+ align="middle"
19
+ class="row-item"
20
+ >
21
+ <el-row class="item-label">{{ item.label }}:</el-row>
22
+ <el-row class="item-value">{{ dtoModel[key] }}</el-row>
23
+ </el-row>
24
+ </el-card>
25
+ </template>
26
+ </el-drawer>
27
+ </template>
28
+
29
+ <script setup>
30
+ import { ref, inject } from "vue";
31
+ import $curl from "$elpisCommon/curl.js";
32
+
33
+ const { api, components } = inject("schemaViewData");
34
+
35
+ const name = ref("detailPanel");
36
+
37
+ const isShow = ref(false);
38
+ const title = ref("");
39
+ const mainKey = ref("");
40
+ const mainValue = ref();
41
+ const loading = ref(false);
42
+ const dtoModel = ref({});
43
+
44
+ const show = (rowData) => {
45
+ const { config } = components.value[name.value];
46
+ title.value = config.title;
47
+ mainKey.value = config.mainKey;
48
+ mainValue.value = rowData[config.mainKey];
49
+
50
+ isShow.value = true;
51
+
52
+ fetchFormData();
53
+ };
54
+
55
+ const fetchFormData = async () => {
56
+ if (loading.value) {
57
+ return;
58
+ }
59
+
60
+ loading.value = true;
61
+
62
+ const res = await $curl({
63
+ method: "get",
64
+ url: api.value,
65
+ query: {
66
+ [mainKey.value]: mainValue.value,
67
+ },
68
+ });
69
+
70
+ loading.value = false;
71
+
72
+ if (!res || !res.success || !res.data) {
73
+ return;
74
+ }
75
+
76
+ dtoModel.value = res.data;
77
+ };
78
+
79
+ defineExpose({
80
+ name,
81
+ show,
82
+ });
83
+ </script>
84
+
85
+ <style scoped lang="less">
86
+ .detail-panel {
87
+ padding: 20px;
88
+
89
+ .row-item {
90
+ height: 40px;
91
+ line-height: 40px;
92
+ font-size: 20px;
93
+
94
+ .item-label {
95
+ margin-right: 20px;
96
+ width: 120px;
97
+ }
98
+
99
+ .item-value {
100
+ color: #999999;
101
+ }
102
+ }
103
+ }
104
+ </style>
@@ -0,0 +1,129 @@
1
+ <template>
2
+ <el-drawer
3
+ v-model="isShow"
4
+ direction="rtl"
5
+ :destory-on-close="true"
6
+ :size="550"
7
+ >
8
+ <template #header>
9
+ <h3>{{ title }}</h3>
10
+ </template>
11
+
12
+ <template #default>
13
+ <schema-form
14
+ ref="schemaFormRef"
15
+ v-loading="loading"
16
+ :schema="components[name]?.schema"
17
+ :model="dtoModel"
18
+ ></schema-form>
19
+ </template>
20
+
21
+ <template #footer>
22
+ <el-button type="primary" @click="save">
23
+ {{ saveBtnText }}
24
+ </el-button>
25
+ </template>
26
+ </el-drawer>
27
+ </template>
28
+
29
+ <script setup>
30
+ import { ref, inject } from "vue";
31
+ import SchemaForm from "$elpisWidgets/schema-form/schema-form.vue";
32
+ import $curl from "$elpisCommon/curl.js";
33
+ import { ElNotification } from "element-plus";
34
+
35
+ const { api, components } = inject("schemaViewData");
36
+ const emits = defineEmits(["command"]);
37
+
38
+ const name = ref("editForm");
39
+
40
+ const isShow = ref(false);
41
+ const title = ref("");
42
+ const saveBtnText = ref("");
43
+ const mainKey = ref("");
44
+ const mainValue = ref();
45
+ const loading = ref(false);
46
+ const dtoModel = ref({});
47
+ const schemaFormRef = ref(null);
48
+
49
+ const show = (rowData) => {
50
+ const { config } = components.value[name.value];
51
+ title.value = config.title;
52
+ saveBtnText.value = config.saveBtnText;
53
+ mainKey.value = config.mainKey;
54
+ mainValue.value = rowData[config.mainKey];
55
+
56
+ isShow.value = true;
57
+
58
+ fetchFormData();
59
+ };
60
+
61
+ const fetchFormData = async () => {
62
+ if (loading.value) {
63
+ return;
64
+ }
65
+
66
+ loading.value = true;
67
+
68
+ const res = await $curl({
69
+ method: "get",
70
+ url: api.value,
71
+ query: {
72
+ [mainKey.value]: mainValue.value,
73
+ },
74
+ });
75
+
76
+ loading.value = false;
77
+
78
+ if (!res || !res.success || !res.data) {
79
+ return;
80
+ }
81
+
82
+ dtoModel.value = res.data;
83
+ };
84
+
85
+ const save = () => {
86
+ if (loading.value) {
87
+ return;
88
+ }
89
+
90
+ if (!schemaFormRef.value.validate()) {
91
+ return;
92
+ }
93
+ loading.value = true;
94
+
95
+ const res = $curl({
96
+ method: "put",
97
+ url: api.value,
98
+ data: {
99
+ [mainKey.value]: mainValue.value,
100
+ ...schemaFormRef.value.getValue(),
101
+ },
102
+ });
103
+
104
+ loading.value = false;
105
+
106
+ if (!res || !res.success) {
107
+ return;
108
+ }
109
+
110
+ ElNotification({
111
+ title: "修改成功",
112
+ message: "修改成功",
113
+ type: "success",
114
+ });
115
+
116
+ isShow.value = false;
117
+
118
+ emits("command", {
119
+ event: "loadTableData",
120
+ });
121
+ };
122
+
123
+ defineExpose({
124
+ name,
125
+ show,
126
+ });
127
+ </script>
128
+
129
+ <style scoped lang="less"></style>
@@ -0,0 +1,137 @@
1
+ import { ref, watch, onMounted, nextTick } from "vue";
2
+ import { useRoute } from "vue-router";
3
+ import { useMenuStore } from "$elpisStore/menu.js";
4
+
5
+ export const useSchema = function () {
6
+ const route = useRoute();
7
+ const menuStore = useMenuStore();
8
+
9
+ const api = ref("");
10
+ const tableSchema = ref({});
11
+ const tableConfig = ref();
12
+ const searchSchema = ref({});
13
+ const searchConfig = ref();
14
+
15
+ const components = ref({});
16
+
17
+ /**
18
+ * 构造 schemaConfig 相关配置,输送给 schemaView 解释
19
+ */
20
+ const buildData = function () {
21
+ const { key, sider_key: siderKey } = route.query;
22
+
23
+ const mItem = menuStore.findMenuItem({
24
+ key: "key",
25
+ value: siderKey ?? key,
26
+ });
27
+
28
+ if (mItem && mItem.schemaConfig) {
29
+ const { schemaConfig } = mItem;
30
+
31
+ const configSchema = JSON.parse(JSON.stringify(schemaConfig.schema));
32
+
33
+ api.value = schemaConfig.api ?? "";
34
+ tableSchema.value = {};
35
+ tableConfig.value = undefined;
36
+ searchSchema.value = {};
37
+ searchConfig.value = undefined;
38
+
39
+ components.value = {};
40
+
41
+ nextTick(() => {
42
+ // 构造 tableSchema 和 tableConfig
43
+ tableSchema.value = buildDtoSchema(configSchema, "table");
44
+ tableConfig.value = schemaConfig.tableConfig;
45
+
46
+ // 构造 searchSchema 和 searchConfig
47
+ const dtoSearchSchema = buildDtoSchema(configSchema, "search");
48
+ for (const key in dtoSearchSchema.properties) {
49
+ if (route.query[key] !== undefined) {
50
+ dtoSearchSchema.properties[key].option.default = route.query[key];
51
+ }
52
+ }
53
+ searchSchema.value = dtoSearchSchema;
54
+ searchConfig.value = schemaConfig.searchConfig;
55
+
56
+ // 构造 components { componentKey: { schema, config } }
57
+ const { componentConfig } = schemaConfig;
58
+
59
+ if (componentConfig && Object.keys(componentConfig.length > 0)) {
60
+ const dtoComponents = {};
61
+ for (const comName in componentConfig) {
62
+ dtoComponents[comName] = {
63
+ schema: buildDtoSchema(configSchema, comName),
64
+ config: componentConfig[comName],
65
+ };
66
+ }
67
+
68
+ components.value = dtoComponents;
69
+ }
70
+ });
71
+ }
72
+ };
73
+
74
+ /**
75
+ * 通用构建 schema 方法
76
+ * @returns
77
+ */
78
+ const buildDtoSchema = (_schema, comName) => {
79
+ if (!_schema?.properties) {
80
+ return {};
81
+ }
82
+
83
+ const dtoSchema = {
84
+ type: "object",
85
+ properties: {},
86
+ };
87
+
88
+ for (let key in _schema.properties) {
89
+ const props = _schema.properties[key];
90
+
91
+ if (props[`${comName}Option`]) {
92
+ let dtoProps = {};
93
+
94
+ for (let pKey in props) {
95
+ if (pKey.indexOf("Option" < 0)) {
96
+ dtoProps[pKey] = props[pKey];
97
+ }
98
+ }
99
+
100
+ dtoProps = Object.assign({}, dtoProps, {
101
+ option: props[`${comName}Option`],
102
+ });
103
+
104
+ // 处理 required 字段
105
+ const { required } = _schema;
106
+ if (required && required.find((pk) => pk === key)) {
107
+ dtoProps.option.required = true;
108
+ }
109
+
110
+ dtoSchema.properties[key] = dtoProps;
111
+ }
112
+ }
113
+
114
+ return dtoSchema;
115
+ };
116
+
117
+ watch(
118
+ [
119
+ () => route.query.key,
120
+ () => route.query.sider_key,
121
+ () => menuStore.menuList,
122
+ ],
123
+ () => buildData(),
124
+ { deep: true },
125
+ );
126
+
127
+ onMounted(() => buildData());
128
+
129
+ return {
130
+ api,
131
+ tableSchema,
132
+ tableConfig,
133
+ searchSchema,
134
+ searchConfig,
135
+ components,
136
+ };
137
+ };
@@ -0,0 +1,102 @@
1
+ <template>
2
+ <el-row class="schema-view">
3
+ <search-panel
4
+ v-if="
5
+ searchSchema?.properties &&
6
+ Object.keys(searchSchema.properties).length > 0
7
+ "
8
+ @search="onSearch"
9
+ ></search-panel>
10
+
11
+ <table-panel ref="tablePanelRef" @operate="onTableOperate"></table-panel>
12
+
13
+ <component
14
+ v-for="(item, key) in components"
15
+ :key="key"
16
+ :is="ComponentsConfig[key]?.component"
17
+ ref="comListRef"
18
+ @command="onComponentCommand"
19
+ ></component>
20
+ </el-row>
21
+ </template>
22
+
23
+ <script setup>
24
+ import { provide, ref } from "vue";
25
+ import SearchPanel from "./complex-view/search-panel/search-panel.vue";
26
+ import TablePanel from "./complex-view/table-panel/table-panel.vue";
27
+ import { useSchema } from "./hook/schema.js";
28
+ import ComponentsConfig from "./components/component-config.js";
29
+
30
+ const {
31
+ api,
32
+ tableSchema,
33
+ tableConfig,
34
+ searchSchema,
35
+ searchConfig,
36
+ components,
37
+ } = useSchema();
38
+
39
+ const apiParams = ref({});
40
+ provide("schemaViewData", {
41
+ api,
42
+ apiParams,
43
+ tableSchema,
44
+ tableConfig,
45
+ searchSchema,
46
+ searchConfig,
47
+ components,
48
+ });
49
+
50
+ const comListRef = ref([]);
51
+ const tablePanelRef = ref(null);
52
+
53
+ const onSearch = (searchValueObj) => {
54
+ apiParams.value = searchValueObj;
55
+ };
56
+
57
+ const EventHandlerMap = {
58
+ showComponent: showComponent,
59
+ };
60
+
61
+ const onTableOperate = ({ btnConfig, rowData }) => {
62
+ const { eventKey } = btnConfig;
63
+ if (EventHandlerMap[eventKey]) {
64
+ EventHandlerMap[eventKey]({ btnConfig, rowData });
65
+ }
66
+ };
67
+
68
+ // showComponent 展示动态组件
69
+ function showComponent({ btnConfig, rowData }) {
70
+ const { comName } = btnConfig.eventOption;
71
+ if (!comName) {
72
+ return;
73
+ }
74
+
75
+ const comRef = comListRef.value.find((item) => item.name === comName);
76
+
77
+ if (!comRef || typeof comRef.show !== "function") {
78
+ return;
79
+ }
80
+
81
+ comRef.show(rowData);
82
+ }
83
+
84
+ /**
85
+ * 响应组件事件
86
+ */
87
+ const onComponentCommand = (data) => {
88
+ const { event } = data;
89
+ if (event === "loadTableData") {
90
+ tablePanelRef.value.loadTableData();
91
+ }
92
+ };
93
+ </script>
94
+
95
+ <style scoped lang="less">
96
+ .schema-view {
97
+ display: flex;
98
+ flex-direction: column;
99
+ width: 100%;
100
+ height: 100%;
101
+ }
102
+ </style>
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <el-sub-menu :index="menuItem.key">
3
+ <template #title>{{ menuItem.name }}</template>
4
+
5
+ <div v-for="item in menuItem.subMenu" :key="item.key">
6
+ <sub-menu
7
+ v-if="item.subMenu && item.subMenu.length > 0"
8
+ :menu-item="item"
9
+ >
10
+ </sub-menu>
11
+
12
+ <el-menu-item v-else :index="item.key">{{ item.name }}</el-menu-item>
13
+ </div>
14
+ </el-sub-menu>
15
+ </template>
16
+
17
+ <script setup>
18
+ const { menuItem } = defineProps(["menuItem"]);
19
+ </script>
20
+
21
+ <style scoped lang="less"></style>