@dmqweb/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 (81) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc +59 -0
  3. package/.vscode/settings.json +15 -0
  4. package/README.md +198 -0
  5. package/app/controller/base.js +41 -0
  6. package/app/controller/project.js +98 -0
  7. package/app/controller/view.js +24 -0
  8. package/app/extend/logger.js +43 -0
  9. package/app/middleware/api-params-verify.js +89 -0
  10. package/app/middleware/api-sign-verify.js +47 -0
  11. package/app/middleware/error-handler.js +41 -0
  12. package/app/middleware/project-handler.js +27 -0
  13. package/app/middleware.js +40 -0
  14. package/app/pages/asserts/custom.css +12 -0
  15. package/app/pages/boot.js +59 -0
  16. package/app/pages/common/curl.js +88 -0
  17. package/app/pages/common/util.js +3 -0
  18. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +40 -0
  19. package/app/pages/dashboard/complex-view/header-view/header-view.vue +141 -0
  20. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +43 -0
  21. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +39 -0
  22. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +146 -0
  23. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +24 -0
  24. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +118 -0
  25. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +177 -0
  26. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +157 -0
  27. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +150 -0
  28. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +113 -0
  29. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +35 -0
  30. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +134 -0
  31. package/app/pages/dashboard/dashboard.vue +127 -0
  32. package/app/pages/dashboard/entry.dashboard.js +46 -0
  33. package/app/pages/store/index.js +5 -0
  34. package/app/pages/store/menu.js +61 -0
  35. package/app/pages/store/project.js +13 -0
  36. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  37. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  38. package/app/pages/widgets/header-container/header-container.vue +144 -0
  39. package/app/pages/widgets/schema-form/complex-view/input/input.vue +165 -0
  40. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +166 -0
  41. package/app/pages/widgets/schema-form/complex-view/select/select.vue +144 -0
  42. package/app/pages/widgets/schema-form/form-item.config.js +24 -0
  43. package/app/pages/widgets/schema-form/schema-form.vue +144 -0
  44. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +57 -0
  45. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +77 -0
  46. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +51 -0
  47. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +58 -0
  48. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +138 -0
  49. package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
  50. package/app/pages/widgets/schema-table/schema-table.vue +254 -0
  51. package/app/pages/widgets/sider-container/sider-container.vue +32 -0
  52. package/app/router/business.js +15 -0
  53. package/app/router/project.js +10 -0
  54. package/app/router/view.js +11 -0
  55. package/app/router-schema/business.js +82 -0
  56. package/app/router-schema/project.js +40 -0
  57. package/app/service/base.js +13 -0
  58. package/app/service/project.js +55 -0
  59. package/app/view/entry.tpl +27 -0
  60. package/app/webpack/config/blank.js +3 -0
  61. package/app/webpack/config/webpack.base.js +269 -0
  62. package/app/webpack/config/webpack.dev.js +61 -0
  63. package/app/webpack/config/webpack.prod.js +149 -0
  64. package/app/webpack/dev.js +58 -0
  65. package/app/webpack/prod.js +21 -0
  66. package/config/config.default.js +3 -0
  67. package/elpis-core/env.js +22 -0
  68. package/elpis-core/index.js +99 -0
  69. package/elpis-core/loader/config.js +51 -0
  70. package/elpis-core/loader/controller.js +75 -0
  71. package/elpis-core/loader/extend.js +54 -0
  72. package/elpis-core/loader/middleware.js +69 -0
  73. package/elpis-core/loader/router-schema.js +50 -0
  74. package/elpis-core/loader/router.js +52 -0
  75. package/elpis-core/loader/service.js +74 -0
  76. package/index.js +29 -0
  77. package/jsconfig.json +16 -0
  78. package/logs/applocation.log +3 -0
  79. package/model/index.js +119 -0
  80. package/package.json +93 -0
  81. package/test/controller/project.test.js +216 -0
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <el-sub-menu :index="menuItem.key">
3
+ <template #title>
4
+ {{ menuItem.name }}
5
+ </template>
6
+ <div
7
+ v-for="item in menuItem.subMenu"
8
+ :key="item.key"
9
+ >
10
+ <sub-menu
11
+ v-if="item.subMenu && item.subMenu.length > 0"
12
+ :menu-item="item"
13
+ />
14
+ <el-menu-item
15
+ v-else
16
+ :index="item.key"
17
+ >
18
+ {{ item.name }}
19
+ </el-menu-item>
20
+ </div>
21
+ </el-sub-menu>
22
+ </template>
23
+
24
+ <script setup>
25
+ const { menuItem } = defineProps({
26
+ menuItem: {
27
+ type: Object,
28
+ required: true
29
+ }
30
+ })
31
+ </script>
32
+
33
+ <style lang="less" scoped>
34
+
35
+ </style>
@@ -0,0 +1,134 @@
1
+ <template>
2
+ <sider-container>
3
+ <!-- 侧边栏 -->
4
+ <template #menu-content>
5
+ <el-menu
6
+ :default-active="activeKey"
7
+ :ellipsis="false"
8
+ @select="onMenuSelect"
9
+ >
10
+ <template v-for="item in menuList">
11
+ <!-- group -->
12
+ <sub-menu
13
+ v-if="item.subMenu && item.subMenu.length > 0"
14
+ :menu-item="item"
15
+ >
16
+ <!-- -->
17
+ </sub-menu>
18
+ <!-- module -->
19
+ <el-menu-item
20
+ v-else
21
+ :key="item.key"
22
+ :index="item.key"
23
+ >
24
+ {{ item.name }}
25
+ </el-menu-item>
26
+ </template>
27
+ </el-menu>
28
+ </template>
29
+ <!-- 主内容 -->
30
+ <template #main-content>
31
+ <router-view />
32
+ </template>
33
+ </sider-container>
34
+ </template>
35
+
36
+ <script setup>
37
+ import { ref, watch, onMounted } from 'vue';
38
+ import { useRouter, useRoute } from 'vue-router';
39
+ import { useMenuStore } from '$elpisStore/menu.js'
40
+ import siderContainer from '$elpisWidgets/sider-container/sider-container.vue';
41
+ import subMenu from './complex-view/sub-menu/sub-menu.vue';
42
+
43
+ const router = useRouter();
44
+ const route = useRoute();
45
+ const menuStore = useMenuStore();
46
+
47
+
48
+ const menuList = ref([])
49
+ const setMenuList = function() {
50
+ const menuItem = menuStore.findMenuItem({
51
+ key: 'key',
52
+ value: route.query.key
53
+ })
54
+ if (menuItem && menuItem.siderConfig && menuItem.siderConfig.menu) {
55
+ menuList.value = menuItem.siderConfig.menu
56
+ }
57
+ }
58
+
59
+ const activeKey = ref('');
60
+ // 设置 activeKey
61
+ const setActiveKey = function() {
62
+ let siderMenuItem = menuStore.findMenuItem({
63
+ key: 'key',
64
+ value: route.query.sider_key
65
+ })
66
+ // 首次加载时,没有 sider_key ,用户没有选择侧边栏菜单,则默认选择第一个菜单
67
+ if (!siderMenuItem) {
68
+ const hMenuList = menuStore.findMenuItem({
69
+ key: 'key',
70
+ value: route.query.key
71
+ })
72
+ if (hMenuList && hMenuList.siderConfig && hMenuList.siderConfig.menu) {
73
+ const siderMenuList = hMenuList.siderConfig.menu
74
+ siderMenuItem = menuStore.findFirstMenuItem(siderMenuList) // 递归查找第一个菜单
75
+ if (siderMenuItem) {
76
+ handleMenuSelect(siderMenuItem.key)
77
+ }
78
+ }
79
+ }
80
+ activeKey.value = siderMenuItem?.key
81
+ }
82
+
83
+ // 监听路由变化,设置 activeKey
84
+ watch( [
85
+ () => route.query.key,
86
+ () => menuStore.getMenuList
87
+ ], () => {
88
+ setActiveKey()
89
+ setMenuList()
90
+ },{ deep: true })
91
+
92
+ // 当页面加载完成并且该组件被挂载到DOM上时
93
+ onMounted(() => {
94
+ setActiveKey()
95
+ setMenuList()
96
+ })
97
+ const onMenuSelect = function(menuKey) {
98
+ handleMenuSelect(menuKey)
99
+ }
100
+
101
+ // 菜单选择处理
102
+ const handleMenuSelect = function(menuKey) {
103
+ const siderMenuItem = menuStore.findMenuItem({
104
+ key: 'key',
105
+ value: menuKey
106
+ })
107
+ if (!siderMenuItem) {
108
+ return
109
+ }
110
+ const { key, moduleType, customConfig } = siderMenuItem
111
+
112
+ if (key === route.query.sider_key) {
113
+ return
114
+ }
115
+ const pathMap = {
116
+ schema: '/schema',
117
+ iframe: '/iframe',
118
+ custom: customConfig?.path
119
+ }
120
+ router.push({
121
+ path: `/view/dashboard/sider${pathMap[moduleType]}`,
122
+ query: {
123
+ key: route.query.key,
124
+ sider_key: key,
125
+ proj_key: route.query.proj_key
126
+ }
127
+ })
128
+ }
129
+
130
+ </script>
131
+
132
+ <style lang="scss" scoped>
133
+
134
+ </style>
@@ -0,0 +1,127 @@
1
+ <template>
2
+ <el-config-provider :locale="zhCn">
3
+ <header-view
4
+ :proj-name="projName"
5
+ @menu-select="onMenuSelect"
6
+ >
7
+ <!-- 主内容区域插槽插入 -->
8
+ <template #main-content>
9
+ <router-view />
10
+ </template>
11
+ </header-view>
12
+ </el-config-provider>
13
+ </template>
14
+
15
+ <script setup>
16
+ import zhCn from 'element-plus/es/locale/lang/zh-cn'
17
+ import HeaderView from './complex-view/header-view/header-view.vue'
18
+ import { ref, onMounted } from 'vue'
19
+ import { useProjectStore } from '$elpisStore/project.js'
20
+ import { useMenuStore } from '$elpisStore/menu.js'
21
+ import $curl from '$elpisCommon/curl.js'
22
+ import { useRouter, useRoute } from 'vue-router'
23
+
24
+ const projectStore = useProjectStore()
25
+ const menuStore = useMenuStore()
26
+ const projName = ref('')
27
+ const route = useRoute()
28
+ const router = useRouter()
29
+ const isLoading = ref(true)
30
+
31
+ onMounted( async () => {
32
+ try {
33
+ await getProjectList()
34
+ const configLoaded = await getProjectConfig()
35
+
36
+ if (configLoaded) {
37
+ // 等待一小段时间确保菜单数据完全设置
38
+ setTimeout(() => {
39
+ isLoading.value = false
40
+ }, 200)
41
+ } else {
42
+ console.error('项目配置加载失败')
43
+ isLoading.value = false
44
+ }
45
+ } catch (error) {
46
+ console.error('初始化失败:', error)
47
+ isLoading.value = false
48
+ }
49
+ })
50
+
51
+ // 请求 /api/project/list 并缓存到 project-store
52
+ async function getProjectList() {
53
+ const res = await $curl({
54
+ method: 'get',
55
+ url: '/api/project/list',
56
+ params: {
57
+ // todo 动态获取
58
+ proj_key: route.query.proj_key,
59
+ }
60
+ });
61
+ if (!res || !res.data || !res.success) {
62
+ return
63
+ }
64
+
65
+ projectStore.setProjectList(res.data)
66
+ }
67
+ // 请求 /api/project 并缓存到 menu-store
68
+ async function getProjectConfig() {
69
+ try {
70
+ const res = await $curl({
71
+ method: 'get',
72
+ url: '/api/project',
73
+ params: {
74
+ proj_key: route.query.proj_key,
75
+ },
76
+ });
77
+
78
+ if (!res || !res.data || !res.success) {
79
+ return false; // 返回失败状态
80
+ }
81
+
82
+ const { name, menu} = res.data
83
+ projName.value = name
84
+ menuStore.setMenuList(menu)
85
+
86
+ return true; // 返回成功状态
87
+ } catch (error) {
88
+ console.error('获取项目配置失败:', error)
89
+ return false; // 返回失败状态
90
+ }
91
+ }
92
+
93
+ // 点击菜单回调方法
94
+ const onMenuSelect = function(menuItem) {
95
+ const { moduleType, key, customConfig} = menuItem
96
+
97
+ if (key === route.query.key) {
98
+ return
99
+ }
100
+ // 菜单项的 moduleType 映射到对应的路由
101
+ const pathMap = {
102
+ sider: '/sider',
103
+ schema: '/schema',
104
+ iframe: '/iframe',
105
+ custom: customConfig?.path
106
+ }
107
+ router.push({
108
+ path: `/view/dashboard${pathMap[moduleType]}`,
109
+ query: {
110
+ key,
111
+ proj_key: route.query.proj_key
112
+ }
113
+ })
114
+ }
115
+
116
+ </script>
117
+
118
+ <style scoped lang="less">
119
+ .global-loading {
120
+ width: 100vw;
121
+ height: 100vh;
122
+ position: relative;
123
+ }
124
+ :depp(el-main) {
125
+ padding: 0%;
126
+ }
127
+ </style>
@@ -0,0 +1,46 @@
1
+ import boot from '$elpisPage/boot.js'
2
+ import dashboard from './dashboard.vue'
3
+ import businessDashboardRouterConfig from "$businessDashboardRouterConfig";
4
+
5
+ const routes = []
6
+
7
+ // 头部菜单路由
8
+ routes.push({
9
+ path: '/view/dashboard/iframe',
10
+ component: () => import('./complex-view/iframe-view/iframe-view.vue')
11
+ })
12
+ routes.push({
13
+ path: '/view/dashboard/schema',
14
+ component: () => import('./complex-view/schema-view/schema-view.vue')
15
+ })
16
+
17
+ const siderRouters = [
18
+ {
19
+ path: 'schema',
20
+ component: () => import('./complex-view/schema-view/schema-view.vue')
21
+ },
22
+ {
23
+ path: 'iframe',
24
+ component: () => import('./complex-view/iframe-view/iframe-view.vue')
25
+ },
26
+ ];
27
+
28
+ // 侧边栏路由
29
+ routes.push({
30
+ path: '/view/dashboard/sider',
31
+ component: () => import('./complex-view/sider-view/sider-view.vue'),
32
+ children: siderRouters
33
+ })
34
+
35
+ // 业务扩展路由
36
+ if(typeof businessDashboardRouterConfig === "function"){
37
+ businessDashboardRouterConfig({ routes , siderRouters })
38
+ }
39
+
40
+ // 侧边栏路由兜底
41
+ routes.push({
42
+ path: '/view/dashboard/sider/:chapters+',
43
+ component: () => import('./complex-view/sider-view/sider-view.vue')
44
+ })
45
+ // 启动页面
46
+ boot(dashboard, { routes } )
@@ -0,0 +1,5 @@
1
+ import { createPinia } from "pinia";
2
+
3
+ const pinia = createPinia();
4
+
5
+ export default pinia;
@@ -0,0 +1,61 @@
1
+ import { defineStore } from 'pinia'
2
+ import { ref } from 'vue'
3
+
4
+ export const useMenuStore = defineStore('menu', () => {
5
+ // 菜单列表
6
+ const menuList = ref([]);
7
+
8
+ // 设置菜单列表配置
9
+ const setMenuList = (list) => {
10
+ menuList.value = list;
11
+ }
12
+
13
+ /**
14
+ * 找出菜单目录
15
+ * @param key 搜索字段
16
+ * @param value 搜索值
17
+ * @param mlist 要搜索的菜单列表
18
+ */
19
+ const findMenuItem = function({ key, value }, mlist = menuList.value) {
20
+ // 遍历要搜索的菜单列表
21
+ for (let i = 0; i < mlist.length; i++) {
22
+ // 获取当前菜单项
23
+ const menuItem = mlist[i];
24
+ // 如果菜单项不存在,继续下一个
25
+ if (!menuItem) continue;
26
+ // 获取菜单项的菜单枚举值和模块枚举值
27
+ const { menuType, moduleType } = menuItem;
28
+ // 如果菜单项的 key 对应的值等于搜索值,返回该菜单项
29
+ if (menuItem[key] === value) {
30
+ return menuItem;
31
+ }
32
+ // 如果菜单项是分组类型,并且有子菜单,递归查找子菜单
33
+ if (menuType === 'group' && menuItem.subMenu) {
34
+ const mItem = findMenuItem({ key, value }, menuItem.subMenu);
35
+ if (mItem) return mItem;
36
+ }
37
+ // 如果菜单项模块类型是侧边栏类型,并且有侧边栏配置,并且有侧边栏配置和侧边栏菜单,递归查找侧边栏菜单
38
+ if (moduleType === 'sider' && menuItem.siderConfig && menuItem.siderConfig.menu) {
39
+ const mItem = findMenuItem({ key, value }, menuItem.siderConfig.menu);
40
+ if (mItem) return mItem;
41
+ }
42
+ }
43
+ }
44
+
45
+
46
+ /**
47
+ * 找出第一个菜单项
48
+ * @param mlist 要搜索的菜单列表
49
+ */
50
+ const findFirstMenuItem = function(mlist = menuList.value) {
51
+ if (!mlist || !mlist[0]) return ;
52
+ let firstMenuItem = mlist[0];
53
+ if (firstMenuItem.subMenu && firstMenuItem.subMenu.length > 0) {
54
+ firstMenuItem = findFirstMenuItem(firstMenuItem.subMenu);
55
+ }
56
+ return firstMenuItem;
57
+ }
58
+
59
+
60
+ return { menuList, setMenuList, findMenuItem, findFirstMenuItem }
61
+ })
@@ -0,0 +1,13 @@
1
+ import { defineStore } from 'pinia'
2
+ import { ref } from 'vue'
3
+
4
+ export const useProjectStore = defineStore('project', () => {
5
+ const projectList = ref([])
6
+
7
+ // 设置项目列表
8
+ const setProjectList = (list) => {
9
+ projectList.value = list;
10
+ }
11
+
12
+ return { projectList, setProjectList }
13
+ })
@@ -0,0 +1,144 @@
1
+ <template>
2
+ <!-- 布局模板 -->
3
+ <el-container class="header-container">
4
+ <!-- 头部 -->
5
+ <el-header class="header">
6
+ <el-row
7
+ type="flex"
8
+ align="middle"
9
+ class="header-row"
10
+ >
11
+ <!-- 左上方 title -->
12
+ <el-row
13
+ type="flex"
14
+ align="middle"
15
+ class="title-panel"
16
+ >
17
+ <img
18
+ src="./asserts/logo.png"
19
+ class="logo"
20
+ >
21
+ <el-row class="text">
22
+ {{ title }}
23
+ </el-row>
24
+ </el-row>
25
+
26
+ <!-- 插槽: 中间菜单区域 -->
27
+ <slot name="menu-content" />
28
+ <!-- 右上方 设置区域 -->
29
+ <el-row
30
+ type="flex"
31
+ align="middle"
32
+ justify="end"
33
+ class="setting-panel"
34
+ >
35
+ <!-- 插槽: 设置区域 -->
36
+ <slot name="setting-content" />
37
+ <img
38
+ src="./asserts/avatar.png"
39
+ class="avatar"
40
+ >
41
+ <el-dropdown @command="handleUserCommand">
42
+ <span class="username">
43
+ {{ userName }} <i class="el-icon-arrow-down el-icon--right" />
44
+ </span>
45
+ <template #dropdown>
46
+ <el-dropdown-item command="logout">
47
+ 退出登录
48
+ </el-dropdown-item>
49
+ </template>
50
+ </el-dropdown>
51
+ </el-row>
52
+ </el-row>
53
+ </el-header>
54
+
55
+ <!-- 主要区域 -->
56
+ <el-main class="main-container">
57
+ <!-- 插槽: 外部扩展区域 -->
58
+ <slot name="main-content" />
59
+ </el-main>
60
+ </el-container>
61
+ </template>
62
+ <script setup>
63
+ import { ref } from 'vue'
64
+
65
+ defineProps({
66
+ title: {
67
+ type: String,
68
+ default: ''
69
+ }
70
+ })
71
+
72
+ const userName = ref('小吴')
73
+ const handleUserCommand = function(event) {
74
+ console.log(event)
75
+ }
76
+ </script>
77
+
78
+ <style lang="less">
79
+ // 外层容器
80
+ .header-container {
81
+ height: 100%;
82
+ min-width: 1000px;
83
+ overflow: hidden;
84
+
85
+ // 顶栏容器
86
+ .header {
87
+ max-height: 120px;
88
+ border-bottom: 1px solid #e8e8e8;
89
+ // background-color: #e8e8e8;
90
+ // 左上方title
91
+ .header-row {
92
+ height: 60px;
93
+ padding: 0 20px;
94
+
95
+ .title-panel {
96
+ width: 180px;
97
+ min-width: 180px;
98
+
99
+ .logo {
100
+ margin-right: 10px;
101
+ width: 25px;
102
+ height: 25px;
103
+ border-radius: 50%;
104
+ }
105
+
106
+ .text {
107
+ font-size: 15px;
108
+ font-weight: 500;
109
+ }
110
+ }
111
+ }
112
+
113
+ // 右上方 设置区域
114
+ .setting-panel {
115
+ margin-left: auto;
116
+ width: 180px;
117
+ min-width: 180px;
118
+
119
+ .avatar {
120
+ margin-right: 10px;
121
+ width: 25px;
122
+ height: 25px;
123
+ border-radius: 50%;
124
+ }
125
+
126
+ .username {
127
+ font-size: 15px;
128
+ font-weight: 500;
129
+ cursor: pointer;
130
+ height: 60px;
131
+ line-height: 60px;
132
+ outline: none;
133
+ }
134
+ }
135
+ }
136
+
137
+ // 主要区域容器
138
+ // .main-container{}
139
+ }
140
+
141
+ :deep(.el-header) {
142
+ padding: 0;
143
+ }
144
+ </style>