@yukihong/schema-admin-x 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 (80) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc +55 -0
  3. package/README.md +208 -0
  4. package/app/controller/base.js +39 -0
  5. package/app/controller/project.js +80 -0
  6. package/app/controller/view.js +20 -0
  7. package/app/extend/logger.js +39 -0
  8. package/app/middleware/api-params-verify.js +79 -0
  9. package/app/middleware/api-sign-verify.js +34 -0
  10. package/app/middleware/error-handler.js +34 -0
  11. package/app/middleware/project-handler.js +27 -0
  12. package/app/middleware.js +40 -0
  13. package/app/pages/asserts/custom.css +13 -0
  14. package/app/pages/boot.js +53 -0
  15. package/app/pages/common/curl.js +91 -0
  16. package/app/pages/common/utils.js +3 -0
  17. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +21 -0
  18. package/app/pages/dashboard/complex-view/header-view/header-view.vue +127 -0
  19. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +44 -0
  20. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +41 -0
  21. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +131 -0
  22. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +23 -0
  23. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +100 -0
  24. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +106 -0
  25. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +131 -0
  26. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +126 -0
  27. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +102 -0
  28. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +26 -0
  29. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +128 -0
  30. package/app/pages/dashboard/dashboard.vue +99 -0
  31. package/app/pages/dashboard/entry.dashboard.js +44 -0
  32. package/app/pages/store/index.js +4 -0
  33. package/app/pages/store/menu.js +61 -0
  34. package/app/pages/store/project.js +17 -0
  35. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  36. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  37. package/app/pages/widgets/header-container/header-container.vue +109 -0
  38. package/app/pages/widgets/schema-form/complex-view/input/input.vue +146 -0
  39. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +140 -0
  40. package/app/pages/widgets/schema-form/complex-view/select/select.vue +121 -0
  41. package/app/pages/widgets/schema-form/form-item-config.js +23 -0
  42. package/app/pages/widgets/schema-form/schema-form.vue +131 -0
  43. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +50 -0
  44. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +65 -0
  45. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +44 -0
  46. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +51 -0
  47. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +127 -0
  48. package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
  49. package/app/pages/widgets/schema-table/schema-table.vue +248 -0
  50. package/app/pages/widgets/sider-container/sider-container.vue +28 -0
  51. package/app/public/static/logo.png +0 -0
  52. package/app/public/static/normalize.css +239 -0
  53. package/app/router/project.js +7 -0
  54. package/app/router/view.js +10 -0
  55. package/app/router-schema/project.js +30 -0
  56. package/app/service/base.js +13 -0
  57. package/app/service/project.js +50 -0
  58. package/app/view/entry.tpl +25 -0
  59. package/app/webpack/config/webpack.base.js +213 -0
  60. package/app/webpack/config/webpack.dev.js +61 -0
  61. package/app/webpack/config/webpack.prod.js +124 -0
  62. package/app/webpack/dev.js +63 -0
  63. package/app/webpack/libs/blank.js +1 -0
  64. package/app/webpack/prod.js +19 -0
  65. package/config/config.beta.js +3 -0
  66. package/config/config.default.js +3 -0
  67. package/config/config.prod.js +3 -0
  68. package/elpis-core/env.js +20 -0
  69. package/elpis-core/index.js +99 -0
  70. package/elpis-core/loader/config.js +52 -0
  71. package/elpis-core/loader/controller.js +75 -0
  72. package/elpis-core/loader/extend.js +55 -0
  73. package/elpis-core/loader/middleware.js +64 -0
  74. package/elpis-core/loader/router-schema.js +47 -0
  75. package/elpis-core/loader/router.js +59 -0
  76. package/elpis-core/loader/service.js +75 -0
  77. package/index.js +40 -0
  78. package/model/index.js +102 -0
  79. package/package.json +93 -0
  80. package/test/controller/project.test.js +217 -0
@@ -0,0 +1,248 @@
1
+ <template>
2
+ <div class="schema-table">
3
+ <el-table
4
+ v-if="schema && schema.properties"
5
+ v-loading="loading"
6
+ :data="tableData"
7
+ class="table"
8
+ >
9
+ <template v-for="(schemaItem,key) in schema.properties">
10
+ <el-table-column
11
+ v-if="schemaItem.option.visible !== false"
12
+ :key="key"
13
+ :prop="key"
14
+ :label="schemaItem.label"
15
+ v-bind="schemaItem.option"
16
+ ></el-table-column>
17
+ </template>
18
+ <el-table-column
19
+ v-if="buttons?.length > 0"
20
+ label="操作"
21
+ fixed="right"
22
+ :width="operationWidth"
23
+ >
24
+ <template #default="scope">
25
+ <el-button
26
+ v-for="item in buttons"
27
+ link
28
+ v-bind="item"
29
+ @click="operationHandler({btnConfig: item, rowData: scope.row})"
30
+ >{{item.label}}</el-button>
31
+ </template>
32
+ </el-table-column>
33
+ </el-table>
34
+ <el-row justify="end" class="pagination">
35
+ <el-pagination
36
+ :current-page="currentPage"
37
+ :page-size="pageSize"
38
+ :page-sizes="[10,20,50,100,200]"
39
+ :total="total"
40
+ layout="total, sizes, prev, pager, next, jumper"
41
+ @size-change="onPageSizeChange"
42
+ @current-change="onCurrentPageChange"
43
+ />
44
+ </el-row>
45
+ </div>
46
+ </template>
47
+
48
+ <script setup>
49
+ import {
50
+ ref,
51
+ toRefs,
52
+ computed,
53
+ watch,
54
+ nextTick,
55
+ onMounted
56
+ } from 'vue';
57
+ import $curl from '$elpisCommon/curl.js';
58
+
59
+ const props = defineProps({
60
+
61
+ /**
62
+ * schema 配置,结构如下:
63
+ {
64
+ type: 'object',
65
+ properties: {
66
+ key: {
67
+ ...schema, // 标准 schema 配置
68
+ type: '', // 字段类型
69
+ label: '', // 字段的中文名
70
+ // 字段在 table 中的相关配置
71
+ option: {
72
+ ...elTableColumnConfig, // 标准的 el-table-column 配置
73
+ visible: true, // 默认为 true (false 或 不配置时,表示不在表单中显示)
74
+ }
75
+ },
76
+ ...
77
+ }
78
+ }
79
+ */
80
+ schema: Object,
81
+
82
+ /**
83
+ * 表格数据源 api
84
+ */
85
+ api: String,
86
+
87
+ /**
88
+ * api 请求参数,请求 API 时携带
89
+ */
90
+ apiParams: Object,
91
+
92
+ /**
93
+ * buttons 操作按钮相关配置,结构如下
94
+ [{
95
+ label: '', // 按钮中文名
96
+ eventKey: '', // 按钮事件名
97
+ eventOption: {}, // 按钮事件具体配置
98
+ ...elButtonConfig // 标准 el-button 配置
99
+ }, ...]
100
+ */
101
+ buttons: Array
102
+ });
103
+
104
+ const { schema, api, apiParams, buttons } = toRefs(props);
105
+
106
+ const emit = defineEmits(['operate']);
107
+
108
+ // 计算操作栏宽度
109
+ const operationWidth = computed(() => {
110
+ return buttons?.value?.length > 0 ? buttons.value.reduce((pre,cur) => {
111
+ return pre + cur.label.length * 18;
112
+ }, 50) : 50;
113
+ })
114
+
115
+ const loading = ref(false);
116
+ const tableData = ref([]);
117
+ const currentPage = ref(1);
118
+ const pageSize = ref(50);
119
+ const total = ref(0);
120
+
121
+ onMounted(() => {
122
+ initData();
123
+ });
124
+
125
+ watch(
126
+ [schema, api, apiParams],
127
+ () => {
128
+ initData();
129
+ },
130
+ { deep: true},
131
+ );
132
+
133
+ const initData = () => {
134
+ currentPage.value = 1;
135
+ pageSize.value = 50;
136
+ nextTick(async() => {
137
+ await loadTableData();
138
+ });
139
+ }
140
+
141
+ // 节流,合并触发,最大限度解决重复请求的问题
142
+ let timerId = null;
143
+ const loadTableData = async () => {
144
+ clearTimeout(timerId);
145
+ timerId = setTimeout(async () => {
146
+ await fetchTableData();
147
+ timerId = null; // 理定时器引用,避免内存泄漏和逻辑异常
148
+ }, 100)
149
+ }
150
+
151
+ const fetchTableData = async () => {
152
+ if(!api.value) { return; }
153
+
154
+ showLoading();
155
+
156
+ // 请求 table 数据
157
+ const res = await $curl({
158
+ url: `${api.value}/list`,
159
+ method: 'get',
160
+ query: {
161
+ ...apiParams.value,
162
+ page: currentPage.value,
163
+ size: pageSize.value
164
+ }
165
+ });
166
+
167
+ hideLoading();
168
+
169
+ if(!res || !res.success || !Array.isArray(res.data)) {
170
+ tableData.value = [];
171
+ total.value = 0;
172
+ return;
173
+ }
174
+
175
+ tableData.value = buildTableData(res.data);
176
+ total.value = res.metadata.total;
177
+ }
178
+
179
+ /**
180
+ * 对后端返回的数据进行渲染前的预处理
181
+ * @param {object} listData 列表数据
182
+ */
183
+ const buildTableData = (listData) => {
184
+ if(!schema.value?.properties) {
185
+ return listData;
186
+ }
187
+
188
+ return listData.map(rowData => {
189
+ for(const dKey in rowData) {
190
+ const schemaItem = schema.value.properties[dKey];
191
+
192
+ // 处理 toFixed
193
+ if(schemaItem?.option?.toFixed) {
194
+ rowData[dKey] = rowData[dKey].toFixed && rowData[dKey].toFixed(schemaItem.option.toFixed);
195
+ }
196
+ }
197
+ return rowData;
198
+ })
199
+ }
200
+
201
+ const showLoading = () => {
202
+ loading.value = true;
203
+ }
204
+
205
+ const hideLoading = () => {
206
+ loading.value = false;
207
+ }
208
+
209
+ const operationHandler = ({ btnConfig, rowData }) => {
210
+ emit('operate', { btnConfig, rowData })
211
+ }
212
+
213
+ const onPageSizeChange = async (value) => {
214
+ pageSize.value = value;
215
+ await loadTableData();
216
+ }
217
+
218
+ const onCurrentPageChange = async (value) => {
219
+ currentPage.value = value;
220
+ await loadTableData();
221
+ }
222
+
223
+ defineExpose({
224
+ initData,
225
+ loadTableData,
226
+ showLoading,
227
+ hideLoading
228
+ })
229
+
230
+ </script>
231
+
232
+ <style lang="less" scoped>
233
+ .schema-table {
234
+ flex: 1;
235
+ display: flex;
236
+ flex-direction: column;
237
+ overflow: auto;
238
+
239
+ .table {
240
+ flex: 1;
241
+ }
242
+
243
+ .pagination {
244
+ margin: 10px 0;
245
+ text-align: right;
246
+ }
247
+ }
248
+ </style>
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <el-container class="sider-container">
3
+ <el-aside width="200px" class="aside">
4
+ <slot name="menu-content"></slot>
5
+ </el-aside>
6
+ <el-main class="main">
7
+ <slot name="main-content"></slot>
8
+ </el-main>
9
+ </el-container>
10
+ </template>
11
+
12
+ <script setup>
13
+ </script>
14
+
15
+ <style lang="less" scoped>
16
+ .sider-container {
17
+ height: 100%;
18
+ }
19
+ .aside {
20
+ border-right: 1px solid #e8e8e8;
21
+ }
22
+ .main {
23
+ overflow: scroll;
24
+ }
25
+ :deep(.el-menu) {
26
+ border-right: 0;
27
+ }
28
+ </style>
Binary file
@@ -0,0 +1,239 @@
1
+ /*! normalize.css v3.0.2 | MIT License | git.io/normalize */
2
+
3
+ /**
4
+ * 1. Set default font family to sans-serif.
5
+ * 2. Prevent iOS text size adjust after orientation change, without disabling
6
+ * user zoom.
7
+ */
8
+ html,body,span,div,p,a,table,tbody,td,h1,h2,h3,img,form,font,strong,b,i,dl,dt,dd,ol,ul,li,dl,dd,dt,iframe,label,blockquote,input,button
9
+ {
10
+ padding: 0;
11
+ margin: 0;
12
+ list-style: none;
13
+ }
14
+
15
+ html {
16
+ font-family: "Open Sans","Helvetica Neue","Microsoft Yahei",sans-serif;/* 1 */
17
+ -ms-text-size-adjust: 100%; /* 2 */
18
+ -webkit-text-size-adjust: 100%; /* 2 */
19
+ }
20
+
21
+ /**
22
+ * Remove default margin.
23
+ */
24
+
25
+ body {
26
+ margin: 0;
27
+ }
28
+
29
+ /* Links
30
+ ========================================================================== */
31
+
32
+ /**
33
+ * Remove the gray background color from active links in IE 10.
34
+ */
35
+
36
+ a {
37
+ background-color: transparent;
38
+ text-decoration: none;
39
+ }
40
+
41
+ /**
42
+ * Improve readability when focused and also mouse hovered in all browsers.
43
+ */
44
+
45
+ a:active,
46
+ a:hover {
47
+ outline: 0;
48
+ }
49
+
50
+ /* Text-level semantics
51
+ ========================================================================== */
52
+
53
+ /**
54
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
55
+ */
56
+
57
+ b,
58
+ strong {
59
+ font-weight: bold;
60
+ }
61
+
62
+ /* Embedded content
63
+ ========================================================================== */
64
+
65
+ /**
66
+ * Remove border when inside `a` element in IE 8/9/10.
67
+ */
68
+
69
+ img {
70
+ border: 0;
71
+ }
72
+
73
+
74
+ /* Grouping content
75
+ ========================================================================== */
76
+
77
+ /**
78
+ * Address margin not present in IE 8/9 and Safari.
79
+ */
80
+
81
+ figure {
82
+ margin: 1em 40px;
83
+ }
84
+
85
+
86
+ /* Forms
87
+ ========================================================================== */
88
+
89
+ /**
90
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
91
+ * styling of `select`, unless a `border` property is set.
92
+ */
93
+
94
+ /**
95
+ * 1. Correct color not being inherited.
96
+ a * Known issue: affects color of disabled elements.
97
+ * 2. Correct font properties not being inherited.
98
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
99
+ */
100
+
101
+ button,
102
+ input,
103
+ optgroup,
104
+ select,
105
+ textarea {
106
+ color: inherit; /* 1 */
107
+ font: inherit; /* 2 */
108
+ margin: 0; /* 3 */
109
+ }
110
+
111
+ /**
112
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
113
+ */
114
+
115
+ button {
116
+ overflow: visible;
117
+ }
118
+
119
+ /**
120
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
121
+ * All other form control elements do not inherit `text-transform` values.
122
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
123
+ * Correct `select` style inheritance in Firefox.
124
+ */
125
+
126
+ button,
127
+ select {
128
+ text-transform: none;
129
+ }
130
+
131
+ /**
132
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
133
+ * and `video` controls.
134
+ * 2. Correct inability to style clickable `input` types in iOS.
135
+ * 3. Improve usability and consistency of cursor style between image-type
136
+ * `input` and others.
137
+ */
138
+
139
+ button,
140
+ html input[type="button"], /* 1 */
141
+ input[type="reset"],
142
+ input[type="submit"] {
143
+ -webkit-appearance: button; /* 2 */
144
+ cursor: pointer; /* 3 */
145
+ }
146
+
147
+ /**
148
+ * Re-set default cursor for disabled elements.
149
+ */
150
+
151
+ button[disabled],
152
+ html input[disabled] {
153
+ cursor: default;
154
+ }
155
+
156
+ /**
157
+ * Remove inner padding and border in Firefox 4+.
158
+ */
159
+
160
+ button::-moz-focus-inner,
161
+ input::-moz-focus-inner {
162
+ border: 0;
163
+ padding: 0;
164
+ }
165
+
166
+ /**
167
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
168
+ * the UA stylesheet.
169
+ */
170
+
171
+ input {
172
+ line-height: normal;
173
+ }
174
+
175
+ /**
176
+ * It's recommended that you don't attempt to style these elements.
177
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
178
+ *
179
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
180
+ * 2. Remove excess padding in IE 8/9/10.
181
+ */
182
+
183
+ input[type="checkbox"],
184
+ input[type="radio"] {
185
+ box-sizing: border-box; /* 1 */
186
+ padding: 0; /* 2 */
187
+ }
188
+
189
+ /**
190
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
191
+ * `font-size` values of the `input`, it causes the cursor style of the
192
+ * decrement button to change from `default` to `text`.
193
+ */
194
+
195
+ input[type="number"]::-webkit-inner-spin-button,
196
+ input[type="number"]::-webkit-outer-spin-button {
197
+ height: auto;
198
+ }
199
+
200
+ /**
201
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
202
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
203
+ * (include `-moz` to future-proof).
204
+ */
205
+
206
+ input[type="search"] {
207
+ -webkit-appearance: textfield; /* 1 */
208
+ -moz-box-sizing: content-box;
209
+ -webkit-box-sizing: content-box; /* 2 */
210
+ box-sizing: content-box;
211
+ }
212
+
213
+ /**
214
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
215
+ * Safari (but not Chrome) clips the cancel button when the search input has
216
+ * padding (and `textfield` appearance).
217
+ */
218
+
219
+ input[type="search"]::-webkit-search-cancel-button,
220
+ input[type="search"]::-webkit-search-decoration {
221
+ -webkit-appearance: none;
222
+ }
223
+
224
+ /* Tables
225
+ ========================================================================== */
226
+
227
+ /**
228
+ * Remove most spacing between table cells.
229
+ */
230
+
231
+ table {
232
+ border-collapse: collapse;
233
+ border-spacing: 0;
234
+ }
235
+
236
+ td,
237
+ th {
238
+ padding: 0;
239
+ }
@@ -0,0 +1,7 @@
1
+ module.exports = (app,router) => {
2
+ // controll loader 处理后 可用 app.controller.view 获取内容
3
+ const { project: projectController } = app.controller;
4
+ router.get('/api/project', projectController.get.bind(projectController));
5
+ router.get('/api/project/list', projectController.getList.bind(projectController));
6
+ router.get('/api/project/model_list', projectController.getModelList.bind(projectController));
7
+ }
@@ -0,0 +1,10 @@
1
+ module.exports = (app,router) => {
2
+ // controll loader 处理后 可用 app.controller.view 获取内容
3
+ const { view: viewController } = app.controller;
4
+
5
+ // 用户输入 http://ip:port/view/page1 就能渲染出对应的页面
6
+ // Koa Router 动态路由参数,:page 匹配到 page1 并将其挂载到 ctx.params.page 上
7
+ router.get('/view/:page', viewController.renderPage.bind(viewController));
8
+ // 用户输入 http://ip:port/view/xx/xx/xx/* 就能渲染出对应的页面
9
+ router.get('/view/:page/*', viewController.renderPage.bind(viewController));
10
+ }
@@ -0,0 +1,30 @@
1
+ module.exports = {
2
+ '/api/project': {
3
+ get: {
4
+ query: {
5
+ type: 'object',
6
+ projecties: {
7
+ proj_key: {
8
+ type: 'string'
9
+ }
10
+ },
11
+ required: ['proj_key']
12
+ }
13
+ }
14
+ },
15
+ '/api/project/list': {
16
+ get: {
17
+ query: {
18
+ type: 'object',
19
+ properties: {
20
+ proj_key: {
21
+ type: 'string'
22
+ }
23
+ }
24
+ }
25
+ }
26
+ },
27
+ '/api/project/model_list': {
28
+ get: {}
29
+ }
30
+ }
@@ -0,0 +1,13 @@
1
+ const superagent = require('superagent');
2
+
3
+ module.exports = (app) => class BaseService {
4
+ /**
5
+ * service 基类
6
+ * 统一收拢 service 相关的公共方法
7
+ */
8
+ constructor() {
9
+ this.app = app;
10
+ this.config = app.config;
11
+ this.curl = superagent;
12
+ }
13
+ }
@@ -0,0 +1,50 @@
1
+ module.exports = (app) => {
2
+ const BaseService = require('./base.js')(app);
3
+ const modelList = require('../../model/index.js')(app);
4
+
5
+ return class ProjectService extends BaseService {
6
+
7
+ /**
8
+ * 根据 projKey 获取项目配置
9
+ */
10
+ get(projKey) {
11
+ let projConfig;
12
+
13
+ modelList.forEach(modelItem => {
14
+ if(modelItem.project[projKey]) {
15
+ projConfig = modelItem.project[projKey];
16
+ }
17
+ })
18
+
19
+ return projConfig;
20
+ }
21
+
22
+ /**
23
+ * 获取统一模型下的项目列表(如果无 projKey,取全量)
24
+ */
25
+ getList({projKey}) {
26
+ return modelList.reduce((preList, modelItem) => {
27
+ const { project } = modelItem;
28
+
29
+ // 如果有传 projKey 则只取当前同模型下的项目,不传的情况下则取全量
30
+ if(projKey && !project[projKey]) {
31
+ return preList;
32
+ }
33
+
34
+ for( const pKey in project) {
35
+ preList.push(project[pKey]);
36
+ }
37
+
38
+ return preList;
39
+ }, []);
40
+
41
+ }
42
+
43
+ /**
44
+ * 获取所有模型与项目的结构化数据
45
+ */
46
+ async getModelList() {
47
+ return modelList;
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html class="dark">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>{{ name }}</title>
6
+ <link rel="stylesheet" href="/static/normalize.css" />
7
+ <link rel="icon" href="/static/logo.png" type="image/x-icon" />
8
+ </head>
9
+ <body style="color:blue;">
10
+ <div id="root"></div>
11
+ <input id="projKey" value="{{ projKey }}" style="display: none;"/>
12
+ <input id="env" value="{{ env }}" style="display: none;"/>
13
+ <input id="options" value="{{ options }}" style="display: none;"/>
14
+ </body>
15
+ <script type="text/javascript">
16
+ try {
17
+ window.projKey = document.getElementById('projKey').value;
18
+ window.env = document.getElementById('env').value;
19
+ const options = document.getElementById('options').value;
20
+ window.options = JSON.parse(options)
21
+ } catch (e) {
22
+ console.log(e)
23
+ }
24
+ </script>
25
+ </html>