@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,77 @@
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'
19
+
20
+ const { schema, schemaKey} = defineProps({
21
+ schema: {
22
+ type: Object,
23
+ default: () => ({})
24
+ },
25
+ schemaKey: {
26
+ type: String,
27
+ default: ''
28
+ }
29
+ })
30
+
31
+ const emit = defineEmits(['loaded'])
32
+
33
+ const dtoValue = ref()
34
+
35
+ const getValue = () => {
36
+ return dtoValue.value !== undefined ? {
37
+ [schemaKey]: dtoValue.value
38
+ } : {}
39
+ }
40
+
41
+
42
+
43
+ const enumList = ref([])
44
+ const fetchEnumList = async () => {
45
+ try{
46
+ const res = await $curl({
47
+ method: 'get',
48
+ url: schema.option?.api,
49
+ params: {}
50
+ })
51
+ if(res?.data?.length > 0){
52
+ enumList.value.push(...res?.data)
53
+ }
54
+
55
+ }catch(e) {
56
+ console.log(e)
57
+ }
58
+ }
59
+ const reset = () => {
60
+ dtoValue.value = schema?.option?.default ?? enumList?.value[0]?.value;
61
+ return
62
+ }
63
+ onMounted(async () => {
64
+ await fetchEnumList()
65
+ reset()
66
+ emit('loaded')
67
+ })
68
+
69
+ defineExpose({
70
+ getValue,
71
+ reset
72
+ })
73
+ </script>
74
+
75
+ <style lang="less" scoped>
76
+
77
+ </style>
@@ -0,0 +1,51 @@
1
+ <template>
2
+ <el-input
3
+ v-model="dtoValue"
4
+ v-bind="schema.option"
5
+ class="input"
6
+ />
7
+ </template>
8
+
9
+ <script setup>
10
+ import { ref, onMounted} from 'vue'
11
+
12
+ const { schema, schemaKey} = defineProps({
13
+ schema: {
14
+ type: Object,
15
+ default: () => ({})
16
+ },
17
+ schemaKey: {
18
+ type: String,
19
+ default: ''
20
+ }
21
+ })
22
+
23
+ const emit = defineEmits(['loaded'])
24
+
25
+ const dtoValue = ref()
26
+
27
+ const getValue = () => {
28
+ return dtoValue.value !== undefined ? {
29
+ [schemaKey]: dtoValue.value
30
+ } : {}
31
+ }
32
+
33
+ const reset = () => {
34
+ dtoValue.value = schema?.option?.default;
35
+ return
36
+ }
37
+
38
+ onMounted(() => {
39
+ reset()
40
+ emit('loaded')
41
+ })
42
+
43
+ defineExpose({
44
+ getValue,
45
+ reset
46
+ })
47
+ </script>
48
+
49
+ <style lang="less" scoped>
50
+
51
+ </style>
@@ -0,0 +1,58 @@
1
+ <template>
2
+ <el-select
3
+ v-model="dtoValue"
4
+ v-bind="schema.option"
5
+ class="select"
6
+ >
7
+ <el-option
8
+ v-for="item in schema.option?.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
+
19
+ const { schema, schemaKey} = defineProps({
20
+ schema: {
21
+ type: Object,
22
+ default: () => ({})
23
+ },
24
+ schemaKey: {
25
+ type: String,
26
+ default: ''
27
+ }
28
+ })
29
+
30
+ const emit = defineEmits(['loaded'])
31
+
32
+ const dtoValue = ref()
33
+
34
+ const getValue = () => {
35
+ return dtoValue.value !== undefined ? {
36
+ [schemaKey]: dtoValue.value
37
+ } : {}
38
+ }
39
+
40
+ const reset = () => {
41
+ dtoValue.value = schema?.option?.default ?? schema.option?.enumList?.[0]?.value ?? '';
42
+ return
43
+ }
44
+
45
+ onMounted(() => {
46
+ reset()
47
+ emit('loaded')
48
+ })
49
+
50
+ defineExpose({
51
+ getValue,
52
+ reset
53
+ })
54
+ </script>
55
+
56
+ <style lang="less" scoped>
57
+
58
+ </style>
@@ -0,0 +1,138 @@
1
+ <template>
2
+ <el-form
3
+ v-if="schema && schema.properties"
4
+ class="schema-search-bar"
5
+ :inline="true"
6
+ >
7
+ <!-- 动态组件 -->
8
+ <el-form-item
9
+ v-for="(schemaItem, key) in schema.properties"
10
+ :key="key"
11
+ :label="schemaItem.label"
12
+ >
13
+ <!-- 展示子组件 -->
14
+ <component
15
+ :is="SearchItemConfig[schemaItem.option?.comType]?.component"
16
+ :ref="searchComList"
17
+ :schema-key="key"
18
+ :schema="schemaItem"
19
+ @loaded="handleChildLoaded"
20
+ />
21
+ </el-form-item>
22
+ <!-- 操作区域 -->
23
+ <el-form-item>
24
+ <el-button
25
+ plain
26
+ type="primary"
27
+ class="search-btn"
28
+ @click="search"
29
+ >
30
+ 搜索
31
+ </el-button>
32
+ <el-button
33
+ plain
34
+ class="reset-btn"
35
+ @click="reset"
36
+ >
37
+ 重置
38
+ </el-button>
39
+ </el-form-item>
40
+ </el-form>
41
+ </template>
42
+
43
+ <script setup>
44
+ import { ref, toRefs} from 'vue'
45
+ import SearchItemConfig from './search-item-config'
46
+
47
+ const props = defineProps({
48
+ /**
49
+ * schema 配置, 结构如下
50
+ * {
51
+ * type: 'object',
52
+ properties: {
53
+ key: {
54
+ ...schema, // 标准 schema 配置
55
+ type: '', // 字段类型
56
+ label: '', // 字段名称
57
+ option: {
58
+ ...elComponentConfig, // 标准 el-component-column 配置
59
+ comType: '', // 配置组件类型 input/select....
60
+ default: '', // 默认值
61
+ }
62
+ }
63
+ }
64
+ }
65
+ */
66
+ schema: {
67
+ type: Object,
68
+ default: () => ({})
69
+ }
70
+ })
71
+ const { schema } = toRefs(props)
72
+
73
+ const emit = defineEmits([ 'load', 'search', 'reset' ])
74
+
75
+ const searchComList = ref([])
76
+
77
+ // 获取动态组件实例里的数据
78
+ const getValue = () => {
79
+ let dtoObj = {}
80
+ searchComList.value.forEach(component => {
81
+ dtoObj = {
82
+ ...dtoObj,
83
+ ...component.getValue( )
84
+ }
85
+ })
86
+ return dtoObj
87
+ }
88
+
89
+ let childComLoadedCount = 0
90
+ const handleChildLoaded = () => {
91
+ childComLoadedCount++
92
+ if (childComLoadedCount >= Object.keys(schema?.value?.properties).length) {
93
+ emit('load',getValue())
94
+ }
95
+ }
96
+
97
+ const search = () => {
98
+ emit('search', getValue())
99
+ }
100
+ const reset = () => {
101
+ searchComList.value.forEach(component => {
102
+ component.reset()
103
+ })
104
+ emit('reset')
105
+ }
106
+
107
+ defineExpose({
108
+ reset,
109
+ getValue
110
+ })
111
+ </script>
112
+
113
+ <style lang="less">
114
+ .schema-search-bar{
115
+ min-width: 500px;
116
+
117
+ // 库存
118
+ .input{
119
+ width: 100px;
120
+ }
121
+ // 商品名称
122
+ .dynamic-select{
123
+ width: 250px;
124
+ }
125
+ // 价格
126
+ .select{
127
+ width: 150px;
128
+ }
129
+ // 搜索按钮
130
+ .search-btn{
131
+ width: 100px;
132
+ }
133
+ // 重置按钮
134
+ .reset-btn{
135
+ width: 100px;
136
+ }
137
+ }
138
+ </style>
@@ -0,0 +1,27 @@
1
+ import input from './complex-view/input/input.vue'
2
+ import select from './complex-view/select/select.vue';
3
+ import dynamicSelect from './complex-view/dynamic-select/dynamic-select.vue';
4
+ import dateRange from './complex-view/date-range/date-range.vue';
5
+
6
+ // 自定义业务搜索项组件
7
+ import BusinessSearchItemConfig from "$businessSearchItemConfig"
8
+
9
+ const SearchItemConfig = {
10
+ input: {
11
+ component: input
12
+ },
13
+ select: {
14
+ component: select
15
+ },
16
+ dynamicSelect: {
17
+ component: dynamicSelect
18
+ },
19
+ dateRange: {
20
+ component: dateRange
21
+ }
22
+ }
23
+
24
+ export default {
25
+ ...SearchItemConfig,
26
+ ...BusinessSearchItemConfig
27
+ };
@@ -0,0 +1,254 @@
1
+ <template>
2
+ <div class="search-panel">
3
+ <!-- 表格 -->
4
+ <el-table
5
+ v-if="schema && schema.properties"
6
+ v-loading="loading"
7
+ class="table"
8
+ :data="tableData"
9
+ >
10
+ <template v-for="(schemaItem, key) in schema.properties">
11
+ <el-table-column
12
+ v-if="schemaItem?.option?.visible !== false"
13
+ :key="key"
14
+ :prop="key"
15
+ :label="schemaItem.label"
16
+ v-bind="schemaItem?.option"
17
+ />
18
+ </template>
19
+ <!-- 行为按钮组 -->
20
+ <el-table-column
21
+ v-if="buttons?.length > 0"
22
+ fixed="right"
23
+ label="操作"
24
+ :width="operationWidth"
25
+ >
26
+ <template #default="scope">
27
+ <el-button
28
+ v-for="item in buttons"
29
+ link
30
+ v-bind="item"
31
+ @click="operationHandler({ btnConfig: item, rowData: scope.row })"
32
+ >
33
+ {{ item.label }}
34
+ </el-button>
35
+ </template>
36
+ </el-table-column>
37
+ </el-table>
38
+ <!-- 分页 -->
39
+ <el-row
40
+ justify="end"
41
+ class="pagination"
42
+ >
43
+ <el-pagination
44
+ :current-page="currentPage"
45
+ :page-size="pageSize"
46
+ :total="total"
47
+ :page-sizes="[10, 20, 50, 100]"
48
+ layout="total, sizes, prev, pager, next, jumper"
49
+ @size-change="onPageSizeChange"
50
+ @current-change="onCurrentPageChange"
51
+ />
52
+ </el-row>
53
+ </div>
54
+ </template>
55
+
56
+ <script setup>
57
+ import { ref, toRefs, onMounted, computed, watch, nextTick,} from 'vue'
58
+ import $curl from '$elpisCommon/curl'
59
+
60
+ const props = defineProps({
61
+ /**
62
+ * schema 配置, 结构如下
63
+ * {
64
+ * type: 'object',
65
+ properties: {
66
+ key: {
67
+ ...schema, // 标准 schema 配置
68
+ type: '', // 字段类型
69
+ label: '', // 字段名称
70
+ option: {
71
+ ...elTableColumnConfig, // 标准 el-table-column 配置
72
+ visible: true // 是否在 表单 中显示
73
+ }
74
+ },
75
+ ...}
76
+ * }
77
+ */
78
+ schema: {
79
+ type: Object,
80
+ default: () => ({}) // 为Object类型设置默认值
81
+ },
82
+
83
+ /**
84
+ * 表格数据源 api
85
+ */
86
+ api: {
87
+ type: String,
88
+ default: '' // 为String类型设置默认值
89
+ },
90
+ /**
91
+ * 表格数据源 api 参数
92
+ */
93
+ apiParams: {
94
+ type: Object,
95
+ default: () => ({})
96
+ },
97
+ /**
98
+ * buttons 按钮配置, 结构如下
99
+ * [{
100
+ * label: '', // 按钮名称
101
+ eventKey: '', // 按钮事件名
102
+ eventOptions: {}, // 按钮配置
103
+ ...elButton, // 标准 el-button 配置
104
+ * }, ...]
105
+ */
106
+ buttons: {
107
+ type: Array,
108
+ default: () => [] // 为Array类型设置默认值
109
+ }
110
+ })
111
+
112
+ const { schema, buttons, api, apiParams } = toRefs(props);
113
+
114
+ const emit = defineEmits(['operate']);
115
+
116
+ // 计算按钮宽度
117
+ const operationWidth = computed( () => {
118
+ return buttons?.value?.length > 0 ? buttons?.value.reduce(( pre, cur) => {
119
+ return pre + cur.label.length * 18
120
+ }, 50) : 50
121
+ })
122
+
123
+ // 表格数据
124
+ const loading = ref(false); // 表格加载状态
125
+ const tableData = ref([]); // 表格数据
126
+ const currentPage = ref(1); // 当前页码
127
+ const pageSize = ref(50); // 每页条数
128
+ const total = ref(0); // 数据总数
129
+
130
+ onMounted(() => {
131
+ initData();
132
+ });
133
+
134
+ watch([api, schema, apiParams], () => {
135
+ initData();
136
+ }, { deep: true})
137
+
138
+ // 初始化数据
139
+ const initData = () => {
140
+ currentPage.value = 1;
141
+ pageSize.value = 50;
142
+ nextTick( async () => {
143
+ await loadTableData();
144
+ });
145
+ }
146
+
147
+ // 防抖加载表格数据
148
+ let timer = null;
149
+ const loadTableData = () => {
150
+ clearTimeout(timer);
151
+ timer = setTimeout(() => {
152
+ fetchTableData();
153
+ timer = null;
154
+ }, 300);
155
+ }
156
+
157
+ // 获取表格数据
158
+ const fetchTableData = async () => {
159
+ if (!api.value) return;
160
+
161
+ showLoading();
162
+
163
+ // 获取数据
164
+ const res = await $curl({
165
+ method: 'get',
166
+ url: `${api.value}/list`,
167
+ params: {
168
+ ...apiParams.value,
169
+ page: currentPage.value,
170
+ pageSize: pageSize.value
171
+ }
172
+ })
173
+
174
+ hideLoading();
175
+
176
+ if (!res || !Array.isArray(res.data) || !res.success) {
177
+ tableData.value = [];
178
+ total.value = 0;
179
+ return;
180
+ }
181
+ tableData.value = buildTableData(res.data);
182
+ total.value = res.metadata.total;
183
+ }
184
+
185
+ /**
186
+ * 处理后端返回的数据,根据 schema 配置进行数据预处理
187
+ * @param listData 列表数据
188
+ */
189
+ const buildTableData = (listData) => {
190
+ if (!schema?.value.properties) return listData;
191
+
192
+ return listData.map(rowData => {
193
+ for (const dKey in rowData) {
194
+ const schemaItem = schema.value.properties[dKey];
195
+
196
+ // 处理toFixed
197
+ if (schemaItem?.option?.toFixed) {
198
+ rowData[dKey] = rowData[dKey].toFixed(schemaItem.option.toFixed);
199
+ }
200
+ }
201
+ return rowData;
202
+ })
203
+ }
204
+
205
+ const showLoading = () => {
206
+ loading.value = true;
207
+ }
208
+
209
+ const hideLoading = () => {
210
+ loading.value = false;
211
+ }
212
+
213
+ // 按钮点击处理
214
+ const operationHandler = ( { btnConfig, rowData }) => {
215
+ emit('operate', { btnConfig, rowData });
216
+ }
217
+
218
+ // 处理每页显示条目数
219
+ const onPageSizeChange = async (value) => {
220
+ pageSize.value = value
221
+ await loadTableData();
222
+ }
223
+
224
+ // 处理当前页码的改变
225
+ const onCurrentPageChange = async (value) => {
226
+ currentPage.value = value
227
+ await loadTableData();
228
+ }
229
+
230
+ defineExpose({
231
+ initData,
232
+ loadTableData,
233
+ hideLoading,
234
+ showLoading
235
+ })
236
+ </script>
237
+
238
+ <style lang="less" scoped>
239
+ .search-panel {
240
+ flex: 1;
241
+ display: flex;
242
+ flex-direction: column;
243
+ overflow: auto;
244
+
245
+ .table{
246
+ flex: 1;
247
+ }
248
+ .pagination{
249
+ margin: 10px 0;
250
+ text-align: right;
251
+ }
252
+ }
253
+
254
+ </style>
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <el-container class="sider-container">
3
+ <!-- 侧边栏模板 -->
4
+ <el-aside
5
+ width="200px"
6
+ class="aside"
7
+ >
8
+ <slot name="menu-content" />
9
+ </el-aside>
10
+ <!-- 主内容模板 -->
11
+ <el-main class="main">
12
+ <slot name="main-content" />
13
+ </el-main>
14
+ </el-container>
15
+ </template>
16
+
17
+ <script setup>
18
+
19
+ </script>
20
+
21
+ <style lang="less" scoped>
22
+ .sider-container {
23
+ height: 100%;
24
+
25
+ .aside{
26
+ border-right: 1px solid #eee;
27
+ }
28
+ .main{
29
+ overflow: auto;
30
+ }
31
+ }
32
+ </style>
@@ -0,0 +1,15 @@
1
+ module.exports = (app,router) => {
2
+ const { business: businessController} = app.controller;
3
+
4
+ router.post('/api/proj/product',businessController.create.bind(businessController));
5
+
6
+ router.get('/api/proj/product',businessController.get.bind(businessController));
7
+
8
+ router.put('/api/proj/product',businessController.update.bind(businessController));
9
+
10
+ router.delete('/api/proj/product',businessController.remove.bind(businessController));
11
+
12
+ router.get('/api/proj/product/list',businessController.getProductList.bind(businessController));
13
+
14
+ router.get('/api/proj/product_enum/list',businessController.getProductEnumList.bind(businessController));
15
+ }
@@ -0,0 +1,10 @@
1
+ module.exports = (app,router) => {
2
+ const { project: projectController} = app.controller;
3
+
4
+ // 获取项目配置接口
5
+ router.get('/api/project',projectController.get.bind(projectController))
6
+ // 获取项目列表接口
7
+ router.get('/api/project/list',projectController.getProjectList.bind(projectController))
8
+ // 获取项目列表关键数据接口
9
+ router.get('/api/project/model_list',projectController.getModelList.bind(projectController))
10
+ }
@@ -0,0 +1,11 @@
1
+ // 导出一个函数,接收 app(Koa 应用实例)和 router(路由实例)两个参数
2
+ module.exports = (app,router) => {
3
+ // 从 app.controller 中获取 view 控制器实例,并重命名为 viewController
4
+ // 这里的 view 对应 app/controller/view.js 文件
5
+ const { view: viewController} = app.controller;
6
+ // 定义一个 GET 路由,用于处理 GET 请求
7
+ // viewController.renderPage.bind(viewController) 是路由处理函数
8
+ // 使用 bind 确保 renderPage 方法内部的 this 指向正确的 viewController 实例
9
+ router.get('/view/:page',viewController.renderPage.bind(viewController));
10
+ router.get('/view/:page/*',viewController.renderPage.bind(viewController));
11
+ }