w-web-api 1.0.52 → 1.0.53
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.
- package/_gh-pages-deploy/.nojekyll +0 -0
- package/_gh-pages-deploy/WWebApi.html +898 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/_gh-pages-deploy/index.html +84 -0
- package/_gh-pages-deploy/scripts/collapse.js +39 -0
- package/_gh-pages-deploy/scripts/commonNav.js +28 -0
- package/_gh-pages-deploy/scripts/linenumber.js +25 -0
- package/_gh-pages-deploy/scripts/nav.js +12 -0
- package/_gh-pages-deploy/scripts/polyfill.js +4 -0
- package/_gh-pages-deploy/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/_gh-pages-deploy/scripts/prettify/lang-css.js +2 -0
- package/_gh-pages-deploy/scripts/prettify/prettify.js +28 -0
- package/_gh-pages-deploy/scripts/search.js +99 -0
- package/{docs/WWebApi.mjs.html → _gh-pages-deploy/server_WWebApi.mjs.html} +96 -39
- package/_gh-pages-deploy/src_components_Common_CheckYesNo.vue.html +187 -0
- package/_gh-pages-deploy/styles/jsdoc.css +776 -0
- package/_gh-pages-deploy/styles/prettify.css +80 -0
- package/dist/css/app.fe69497a.css +1 -0
- package/dist/index.tmp +4 -2
- package/dist/js/app-legacy.15819aa7.js +1 -0
- package/dist/js/app.15819aa7.js +1 -0
- package/dist/js/chunk-vendors-legacy.c1a32dd1.js +15 -0
- package/dist/js/chunk-vendors.c1a32dd1.js +15 -0
- package/dist/w-web-api.umd.js +2 -2
- package/dist/w-web-api.umd.js.map +1 -1
- package/docs/WWebApi.html +2 -2
- package/docs/index.html +1 -1
- package/docs/server_WWebApi.mjs.html +1012 -0
- package/docs/src_components_Common_CheckYesNo.vue.html +187 -0
- package/g.getSettings.mjs +3 -0
- package/package.json +15 -11
- package/public/index.html +9 -2
- package/server/WWebApi.mjs +93 -36
- package/server/procApis.mjs +62 -0
- package/server/procLang.mjs +386 -0
- package/server/procProxy.mjs +120 -0
- package/server/srLog.mjs +30 -0
- package/server/staLogs/staEvent.mjs +129 -0
- package/server/staLogs/test_staEvent.mjs +132 -0
- package/settings.json +14 -0
- package/src/App.vue +11 -7
- package/src/assets/scalar-ui.css +113 -0
- package/src/components/Common/CheckYes.vue +102 -0
- package/src/components/Common/CheckYesNo.vue +115 -0
- package/src/components/Common/LoadingWinBar.vue +114 -0
- package/src/components/Layout.vue +8 -7
- package/src/components/LayoutContent.vue +308 -333
- package/src/components/LayoutContentEdit.vue +577 -0
- package/src/components/LayoutContentStats.vue +485 -0
- package/src/components/LayoutContentTest.vue +799 -0
- package/src/components/MdPanel.vue +80 -58
- package/src/main.js +8 -0
- package/src/plugins/mUI.mjs +19 -4
- package/src/schema/tables/apis.mjs +30 -0
- package/srv.mjs +47 -19
- package/tableTags.json +1 -1
- package/.github/workflows/ci-test.yml +0 -24
- package/.vscode/launch.json +0 -18
- package/db/wapis/apis/data.mdb +0 -0
- package/db/wapis/apis/lock.mdb +0 -0
- package/dist/css/app.b5cf2ef5.css +0 -1
- package/dist/js/app-legacy.927b5679.js +0 -1
- package/dist/js/app.927b5679.js +0 -1
- package/dist/js/chunk-vendors-legacy.ffb0c6c5.js +0 -13
- package/dist/js/chunk-vendors.ffb0c6c5.js +0 -13
- package/tableTags-web-api.json +0 -1
- package/test/all.test.mjs +0 -10
|
@@ -5,8 +5,28 @@
|
|
|
5
5
|
@domresize="resize"
|
|
6
6
|
:changeApis="changeApis"
|
|
7
7
|
>
|
|
8
|
+
<div style="display:flex; height:100%; width:100%;">
|
|
9
|
+
|
|
10
|
+
<!-- 左側垂直主選單(仿 w-web-sso):切換 API 工作區 / 統計資訊 -->
|
|
11
|
+
<div :style="`width:${widthMainMenu}px; flex-shrink:0; height:100%; box-sizing:border-box; background:var(--bg-2); border-right:1px solid var(--border); display:flex; flex-direction:column; padding:8px 0; gap:4px;`">
|
|
12
|
+
<button
|
|
13
|
+
v-for="m in mainMenus"
|
|
14
|
+
:key="m.id"
|
|
15
|
+
class="w-mm-btn"
|
|
16
|
+
:class="{on: section===m.id}"
|
|
17
|
+
@click="onClickMainMenu(m)"
|
|
18
|
+
>
|
|
19
|
+
<svg viewBox="0 0 24 24" width="22" height="22" style="display:block; margin:0 auto;"><path :d="m.icon" fill="currentColor"></path></svg>
|
|
20
|
+
<div class="w-mm-label">{{$t(m.textKey)}}</div>
|
|
21
|
+
</button>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<!-- 工作區 -->
|
|
25
|
+
<div style="flex:1; min-width:0; height:100%; position:relative;">
|
|
26
|
+
|
|
27
|
+
<template v-if="section==='api'">
|
|
8
28
|
|
|
9
|
-
|
|
29
|
+
<template v-if="syncState">
|
|
10
30
|
|
|
11
31
|
<WDrawer
|
|
12
32
|
:style="`height:${panelHeight}px; width:100%;`"
|
|
@@ -23,25 +43,44 @@
|
|
|
23
43
|
>
|
|
24
44
|
|
|
25
45
|
<template v-slot:drawer="props">
|
|
26
|
-
<div :style="`height:${props.height}px; background
|
|
46
|
+
<div :style="`height:${props.height}px; background:var(--bg-2); border-right:1px solid var(--border); position:relative;`">
|
|
47
|
+
|
|
48
|
+
<!-- 搜尋 + 新增API -->
|
|
49
|
+
<div :style="`height:${heightDrawerHeader}px; box-sizing:border-box; padding:8px 40px 8px 8px; border-bottom:1px solid var(--border); display:flex; gap:6px; align-items:center;`">
|
|
50
|
+
<input
|
|
51
|
+
v-model="search"
|
|
52
|
+
type="text"
|
|
53
|
+
:placeholder="$t('searchApiPlaceholder')"
|
|
54
|
+
style="flex:1; min-width:0; padding:5px 8px; border:1px solid var(--border); border-radius:var(--radius); font-size:0.85rem; outline:none; box-sizing:border-box; transition:border-color .15s, box-shadow .15s;"
|
|
55
|
+
@focus="$event.target.style.borderColor='var(--accent)'; $event.target.style.boxShadow='var(--focus)'"
|
|
56
|
+
@blur="$event.target.style.borderColor='var(--border)'; $event.target.style.boxShadow='none'"
|
|
57
|
+
/>
|
|
58
|
+
<button
|
|
59
|
+
@click="onClickAddApi"
|
|
60
|
+
class="w-btn-primary"
|
|
61
|
+
style="flex-shrink:0; white-space:nowrap;"
|
|
62
|
+
>+ {{$t('addApi')}}</button>
|
|
63
|
+
</div>
|
|
27
64
|
|
|
28
65
|
<template v-if="apisTree.length>0">
|
|
29
66
|
<WTree
|
|
30
|
-
:style="`height:${props.height}px;`"
|
|
31
|
-
:viewHeightMax="props.height"
|
|
67
|
+
:style="`height:${props.height-heightDrawerHeader}px;`"
|
|
68
|
+
:viewHeightMax="props.height-heightDrawerHeader"
|
|
32
69
|
:data="apisTree"
|
|
33
70
|
:iconHeight="lineHeightTree"
|
|
34
71
|
:defItemHeight="lineHeightTree"
|
|
35
72
|
:activable="true"
|
|
36
73
|
:itemActive="apiActive"
|
|
37
74
|
:funActive="funActive"
|
|
38
|
-
:itemTextColorActive="'
|
|
39
|
-
:itemBackgroundColorActive ="'rgba(
|
|
75
|
+
:itemTextColorActive="'var(--c-1)'"
|
|
76
|
+
:itemBackgroundColorActive ="'linear-gradient(to right, #0099ff 3px, rgba(0,153,255,0.08) 3px)'"
|
|
77
|
+
:indent="0.25"
|
|
78
|
+
:iconSize="12"
|
|
40
79
|
>
|
|
41
80
|
<template v-slot:item="props">
|
|
42
81
|
|
|
43
82
|
<div
|
|
44
|
-
:style="`display:flex; align-items:center; min-height:${lineHeightTree}px;`"
|
|
83
|
+
:style="`display:flex; align-items:center; min-height:${lineHeightTree}px; color:var(--c-3); font-size:11px; font-weight:600; letter-spacing:.05em; text-transform:uppercase;`"
|
|
45
84
|
v-if="props.data.type!=='node'"
|
|
46
85
|
>
|
|
47
86
|
{{props.data.key}}
|
|
@@ -49,12 +88,12 @@
|
|
|
49
88
|
|
|
50
89
|
<div
|
|
51
90
|
:style="`display:flex; align-items:center; min-height:${lineHeightTree}px; cursor:pointer;`"
|
|
52
|
-
@click="ckItem(getItemByKey(props.data.text))"
|
|
91
|
+
@click="ckItem(getItemByKey(props.data.text), props.data)"
|
|
53
92
|
v-else
|
|
54
93
|
>
|
|
55
94
|
|
|
56
95
|
<div style="padding-right:5px;">
|
|
57
|
-
<div
|
|
96
|
+
<div class="w-mb" :class="getMethodByKey(props.data.text).toLowerCase()">
|
|
58
97
|
{{getMethodByKey(props.data.text)}}
|
|
59
98
|
</div>
|
|
60
99
|
</div>
|
|
@@ -81,7 +120,7 @@
|
|
|
81
120
|
>
|
|
82
121
|
<WButtonCircle
|
|
83
122
|
:paddingStyle="{v:3,h:3}"
|
|
84
|
-
:icon="
|
|
123
|
+
:icon="mdiArrowLeft"
|
|
85
124
|
:iconSize="16"
|
|
86
125
|
:backgroundColor="'#fff'"
|
|
87
126
|
:backgroundColorHover="'#eee'"
|
|
@@ -101,283 +140,100 @@
|
|
|
101
140
|
<template v-slot:content="props">
|
|
102
141
|
<div :style="`height:${props.height}px; width:${props.width}px; position:relative;`">
|
|
103
142
|
|
|
104
|
-
<!--
|
|
105
|
-
<template>
|
|
143
|
+
<!-- 模式切換(文件/編輯/測試) + 內容 -->
|
|
144
|
+
<template v-if="apiSelect || newMode">
|
|
145
|
+
|
|
146
|
+
<div :style="`height:${heightModeBar}px; box-sizing:border-box; padding:8px 12px; border-bottom:1px solid var(--border); background:var(--bg-1); display:flex; align-items:center;`">
|
|
147
|
+
<div class="w-seg">
|
|
148
|
+
<button class="w-seg-btn" :class="{on: mode==='docs'}" @click="onChangeMode({id:'docs'})">{{$t('tabDocs')}}</button>
|
|
149
|
+
<button class="w-seg-btn" :class="{on: mode==='edit'}" @click="onChangeMode({id:'edit'})">{{$t('tabEdit')}}</button>
|
|
150
|
+
<button class="w-seg-btn" :class="{on: mode==='test'}" @click="onChangeMode({id:'test'})">{{$t('tabTest')}}</button>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
106
153
|
|
|
107
154
|
<div
|
|
108
|
-
:style="`height:${props.height}px; overflow-y:auto;`"
|
|
109
|
-
v-if="apiSelect"
|
|
155
|
+
:style="`height:${props.height-heightModeBar}px; overflow-y:auto; background:var(--bg-1);`"
|
|
156
|
+
v-if="mode==='docs' && apiSelect"
|
|
110
157
|
>
|
|
111
|
-
<div style="padding:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
<div style="font-size:0.8rem;">
|
|
128
|
-
{{$ui.gv(apiSelect,'url')}}
|
|
129
|
-
</div>
|
|
130
|
-
|
|
131
|
-
</div>
|
|
132
|
-
|
|
158
|
+
<div style="padding:30px 36px;">
|
|
159
|
+
|
|
160
|
+
<!-- op header -->
|
|
161
|
+
<div><span class="w-mb" :class="getMethod(apiSelect).toLowerCase()">{{getMethod(apiSelect)}}</span></div>
|
|
162
|
+
<div class="op-title">{{$ui.gv(apiSelect,'name')}}</div>
|
|
163
|
+
<div class="op-path"><span class="w-mb" :class="getMethod(apiSelect).toLowerCase()">{{getMethod(apiSelect)}}</span><span class="w-mono">{{$ui.gv(apiSelect,'url')}}</span></div>
|
|
164
|
+
<div class="op-desc">{{$ui.gv(apiSelect,'description')}}</div>
|
|
165
|
+
|
|
166
|
+
<!-- metadata pills -->
|
|
167
|
+
<div class="pills">
|
|
168
|
+
<span class="pill" v-if="$ui.gv(apiSelect,'version')"><b>{{$ui.gv(apiSelect,'version')}}</b></span>
|
|
169
|
+
<span class="pill" v-if="$ui.gv(apiSelect,'levels')">{{$t('levels')}} <b>{{$ui.gv(apiSelect,'levels')}}</b></span>
|
|
170
|
+
<span class="pill" v-if="keywordsList.length">{{$t('keywords')}}<span class="kw-chip" v-for="kw in keywordsList" :key="'kw-'+kw">{{kw}}</span></span>
|
|
171
|
+
<span class="pill ok" v-if="$ui.gv(apiSelect,'state')">{{$ui.gv(apiSelect,'state')}}</span>
|
|
172
|
+
<span class="pill" v-if="$ui.gv(apiSelect,'creator')">{{$t('creator')}} <b>{{$ui.gv(apiSelect,'creator')}}</b></span>
|
|
173
|
+
<span class="pill" v-if="$ui.gv(apiSelect,'dataSource')">{{$t('dataSource')}} <b>{{$ui.gv(apiSelect,'dataSource')}}</b></span>
|
|
133
174
|
</div>
|
|
134
175
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
{{$ui.gv(apiSelect,'description')}}
|
|
143
|
-
</div>
|
|
144
|
-
|
|
145
|
-
</div>
|
|
146
|
-
|
|
147
|
-
<div style="padding:10px;">
|
|
148
|
-
|
|
149
|
-
<div class="bk" style="">
|
|
150
|
-
|
|
151
|
-
<div class="bk-title" style="">
|
|
152
|
-
{{$t('tokens')}}
|
|
153
|
-
</div>
|
|
154
|
-
|
|
155
|
-
<div class="bk-item" style="">
|
|
156
|
-
{{$ui.gv(apiSelect,'tokens')}}
|
|
157
|
-
</div>
|
|
158
|
-
|
|
159
|
-
</div>
|
|
160
|
-
|
|
161
|
-
<div class="bk" style="">
|
|
162
|
-
|
|
163
|
-
<div class="bk-title" style="">
|
|
164
|
-
{{$t('version')}}
|
|
165
|
-
</div>
|
|
166
|
-
|
|
167
|
-
<div class="bk-item" style="">
|
|
168
|
-
{{$ui.gv(apiSelect,'version')}}
|
|
169
|
-
</div>
|
|
170
|
-
|
|
171
|
-
</div>
|
|
172
|
-
|
|
173
|
-
<div class="bk" style="">
|
|
174
|
-
|
|
175
|
-
<div class="bk-title" style="">
|
|
176
|
-
{{$t('levels')}}
|
|
177
|
-
</div>
|
|
178
|
-
|
|
179
|
-
<div class="bk-item" style="">
|
|
180
|
-
{{$ui.gv(apiSelect,'')}}
|
|
181
|
-
</div>
|
|
182
|
-
|
|
183
|
-
</div>
|
|
184
|
-
|
|
185
|
-
<div class="bk" style="">
|
|
186
|
-
|
|
187
|
-
<div class="bk-title" style="">
|
|
188
|
-
{{$t('keywords')}}
|
|
189
|
-
</div>
|
|
190
|
-
|
|
191
|
-
<div class="bk-item" style="">
|
|
192
|
-
{{$ui.gv(apiSelect,'')}}
|
|
193
|
-
</div>
|
|
194
|
-
|
|
195
|
-
</div>
|
|
196
|
-
|
|
197
|
-
<div class="bk" style="">
|
|
198
|
-
|
|
199
|
-
<div class="bk-title" style="">
|
|
200
|
-
{{$t('state')}}
|
|
201
|
-
</div>
|
|
202
|
-
|
|
203
|
-
<div class="bk-item" style="">
|
|
204
|
-
{{$ui.gv(apiSelect,'')}}
|
|
205
|
-
</div>
|
|
206
|
-
|
|
207
|
-
</div>
|
|
208
|
-
|
|
209
|
-
<div class="bk" style="">
|
|
210
|
-
|
|
211
|
-
<div class="bk-title" style="">
|
|
212
|
-
{{$t('timeCreate')}}
|
|
213
|
-
</div>
|
|
214
|
-
|
|
215
|
-
<div class="bk-item" style="">
|
|
216
|
-
{{$ui.gv(apiSelect,'timeCreate',getDay)}}
|
|
217
|
-
</div>
|
|
218
|
-
|
|
219
|
-
</div>
|
|
220
|
-
|
|
221
|
-
<div class="bk" style="">
|
|
222
|
-
|
|
223
|
-
<div class="bk-title" style="">
|
|
224
|
-
{{$t('timeUpdate')}}
|
|
225
|
-
</div>
|
|
226
|
-
|
|
227
|
-
<div class="bk-item" style="">
|
|
228
|
-
{{$ui.gv(apiSelect,'timeUpdate',getDay)}}
|
|
229
|
-
</div>
|
|
230
|
-
|
|
231
|
-
</div>
|
|
232
|
-
|
|
233
|
-
<div class="bk" style="">
|
|
234
|
-
|
|
235
|
-
<div class="bk-title" style="">
|
|
236
|
-
{{$t('creator')}}
|
|
237
|
-
</div>
|
|
238
|
-
|
|
239
|
-
<div class="bk-item" style="">
|
|
240
|
-
{{$ui.gv(apiSelect,'creator')}}
|
|
241
|
-
</div>
|
|
242
|
-
|
|
243
|
-
</div>
|
|
244
|
-
|
|
245
|
-
<div class="bk" style="">
|
|
246
|
-
|
|
247
|
-
<div class="bk-title" style="">
|
|
248
|
-
{{$t('dataSource')}}
|
|
249
|
-
</div>
|
|
250
|
-
|
|
251
|
-
<div class="bk-item" style="">
|
|
252
|
-
{{$ui.gv(apiSelect,'dataSource')}}
|
|
253
|
-
</div>
|
|
254
|
-
|
|
255
|
-
</div>
|
|
256
|
-
|
|
257
|
-
<div class="bk" style="">
|
|
258
|
-
|
|
259
|
-
<div class="bk-title" style="">
|
|
260
|
-
{{$t('isActive')}}
|
|
176
|
+
<!-- two-column split -->
|
|
177
|
+
<div class="split">
|
|
178
|
+
<!-- 左欄:參數說明 -->
|
|
179
|
+
<div>
|
|
180
|
+
<div class="dsec">
|
|
181
|
+
<div class="dsec-h">{{$t('docInput')}}</div>
|
|
182
|
+
<div class="doc-md"><MdPanel :md="$ui.gv(apiSelect,'mdInputParams')"></MdPanel></div>
|
|
261
183
|
</div>
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
184
|
+
<div class="dsec">
|
|
185
|
+
<div class="dsec-h">{{$t('docOutputFields')}}</div>
|
|
186
|
+
<div class="doc-md"><MdPanel :md="$ui.gv(apiSelect,'mdOutputParams')"></MdPanel></div>
|
|
265
187
|
</div>
|
|
266
|
-
|
|
267
|
-
</div>
|
|
268
|
-
|
|
269
|
-
</div>
|
|
270
|
-
|
|
271
|
-
<div style="padding:10px;">
|
|
272
|
-
|
|
273
|
-
<div class="bk-title" style="">
|
|
274
|
-
{{$t('mdInputParams')}}
|
|
275
|
-
</div>
|
|
276
|
-
|
|
277
|
-
<div class="bk-item" style="padding:10px;">
|
|
278
|
-
<MdPanel
|
|
279
|
-
:md="$ui.gv(apiSelect,'mdInputParams')"
|
|
280
|
-
></MdPanel>
|
|
281
|
-
</div>
|
|
282
|
-
|
|
283
|
-
</div>
|
|
284
|
-
|
|
285
|
-
<div style="padding:10px;">
|
|
286
|
-
|
|
287
|
-
<div class="bk-title" style="">
|
|
288
|
-
{{$t('inputExample')}}
|
|
289
|
-
</div>
|
|
290
|
-
|
|
291
|
-
<div class="bk-item" style="padding:10px;">
|
|
292
|
-
{{$ui.gv(apiSelect,'inputExample')}}
|
|
293
|
-
</div>
|
|
294
|
-
|
|
295
|
-
</div>
|
|
296
|
-
|
|
297
|
-
<div style="padding:10px;">
|
|
298
|
-
|
|
299
|
-
<div class="bk-title" style="">
|
|
300
|
-
{{$t('mdOutputParams')}}
|
|
301
188
|
</div>
|
|
302
|
-
|
|
303
|
-
<div class="
|
|
304
|
-
<
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
</div>
|
|
308
|
-
|
|
309
|
-
</div>
|
|
310
|
-
|
|
311
|
-
<div style="padding:10px;">
|
|
312
|
-
|
|
313
|
-
<div class="bk-title" style="">
|
|
314
|
-
{{$t('outputExample')}}
|
|
315
|
-
</div>
|
|
316
|
-
|
|
317
|
-
<div style="padding-top:3px;">
|
|
318
|
-
|
|
319
|
-
<div style="padding-left:10px; margin-bottom:-1px;">
|
|
320
|
-
<!-- 因上下皆有border, 故需負margin-bottom來吃掉重複border -->
|
|
321
|
-
<WGroupChipRadio
|
|
322
|
-
:items="optputMenuItems"
|
|
323
|
-
:value="optputMenuItemSelect"
|
|
324
|
-
@input="changeOptputMenuItemSelect"
|
|
325
|
-
:group="true"
|
|
326
|
-
:group-border-radius-style="{top:true}"
|
|
327
|
-
:group-shift="7"
|
|
328
|
-
:border-radius="20"
|
|
329
|
-
:border-color="'#ddd'"
|
|
330
|
-
:border-color-hover="'#dadada'"
|
|
331
|
-
:border-color-active="'orange lighten-2'"
|
|
332
|
-
:margin-style="{}"
|
|
333
|
-
></WGroupChipRadio>
|
|
189
|
+
<!-- 右欄:code rail -->
|
|
190
|
+
<div class="rail">
|
|
191
|
+
<div class="card">
|
|
192
|
+
<div class="card-h"><span class="lab">{{$t('docRequest')}}</span><span class="w-muted" style="margin-left:auto; font-size:11.5px;">cURL</span></div>
|
|
193
|
+
<pre class="code">{{curlOf(apiSelect)}}</pre>
|
|
334
194
|
</div>
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
<div
|
|
339
|
-
style="padding:10px 15px;"
|
|
340
|
-
v-if="optputMenuItemSelectId==='tree'"
|
|
341
|
-
>
|
|
342
|
-
<WJsonView
|
|
343
|
-
style="width:100%;"
|
|
344
|
-
:viewHeightMax="null"
|
|
345
|
-
:data="getOutputJsonObj(apiSelect)"
|
|
346
|
-
></WJsonView>
|
|
347
|
-
</div>
|
|
348
|
-
|
|
349
|
-
<div
|
|
350
|
-
style="padding:15px; color:#555; font-size:0.85rem;"
|
|
351
|
-
v-if="optputMenuItemSelectId==='raw'
|
|
352
|
-
">
|
|
353
|
-
<pre style="margin:0px; padding:0px;">{{getOutputJson(apiSelect)}}</pre>
|
|
354
|
-
</div>
|
|
355
|
-
|
|
195
|
+
<div class="card">
|
|
196
|
+
<div class="card-h"><span class="lab">{{$t('resTitle')}}</span><span class="st">200 OK</span></div>
|
|
197
|
+
<pre class="code" v-html="jsonHighlight($ui.gv(apiSelect,'outputExample'))"></pre>
|
|
356
198
|
</div>
|
|
357
|
-
|
|
358
199
|
</div>
|
|
359
|
-
|
|
360
200
|
</div>
|
|
361
201
|
|
|
362
202
|
</div>
|
|
363
203
|
</div>
|
|
364
204
|
|
|
365
|
-
<
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
205
|
+
<LayoutContentEdit
|
|
206
|
+
v-else-if="mode==='edit'"
|
|
207
|
+
:item="editItem"
|
|
208
|
+
:height="props.height-heightModeBar"
|
|
209
|
+
:isNew="newMode"
|
|
210
|
+
@saved="onEditSaved"
|
|
211
|
+
@deleted="onEditDeleted"
|
|
212
|
+
@cancel="onEditCancel"
|
|
213
|
+
></LayoutContentEdit>
|
|
214
|
+
|
|
215
|
+
<LayoutContentTest
|
|
216
|
+
v-else-if="mode==='test' && apiSelect"
|
|
217
|
+
:item="apiSelect"
|
|
218
|
+
:height="props.height-heightModeBar"
|
|
219
|
+
></LayoutContentTest>
|
|
371
220
|
|
|
372
221
|
</template>
|
|
373
222
|
|
|
223
|
+
<div
|
|
224
|
+
style="padding:20px; font-size:0.9rem;"
|
|
225
|
+
v-else
|
|
226
|
+
>
|
|
227
|
+
{{$t('noSelectApi')}}
|
|
228
|
+
</div>
|
|
229
|
+
|
|
374
230
|
<div
|
|
375
231
|
:style="`position:absolute; top:1px; left:4px;`"
|
|
376
232
|
v-if="!drawer"
|
|
377
233
|
>
|
|
378
234
|
<WButtonCircle
|
|
379
235
|
:paddingStyle="{v:3,h:3}"
|
|
380
|
-
:icon="
|
|
236
|
+
:icon="mdiArrowRight"
|
|
381
237
|
:iconSize="16"
|
|
382
238
|
:backgroundColor="'#fff'"
|
|
383
239
|
:backgroundColorHover="'#eee'"
|
|
@@ -406,6 +262,16 @@
|
|
|
406
262
|
</div>
|
|
407
263
|
</template>
|
|
408
264
|
|
|
265
|
+
</template>
|
|
266
|
+
|
|
267
|
+
<LayoutContentStats
|
|
268
|
+
v-else-if="section==='stats'"
|
|
269
|
+
:height="panelHeight"
|
|
270
|
+
></LayoutContentStats>
|
|
271
|
+
|
|
272
|
+
</div>
|
|
273
|
+
|
|
274
|
+
</div>
|
|
409
275
|
</div>
|
|
410
276
|
</template>
|
|
411
277
|
|
|
@@ -416,28 +282,31 @@ import each from 'lodash-es/each.js'
|
|
|
416
282
|
import size from 'lodash-es/size.js'
|
|
417
283
|
import trim from 'lodash-es/trim.js'
|
|
418
284
|
import find from 'lodash-es/find.js'
|
|
285
|
+
import filter from 'lodash-es/filter.js'
|
|
419
286
|
import cloneDeep from 'lodash-es/cloneDeep.js'
|
|
420
287
|
import isobj from 'wsemi/src/isobj.mjs'
|
|
421
288
|
import iseobj from 'wsemi/src/iseobj.mjs'
|
|
422
|
-
import j2o from 'wsemi/src/j2o.mjs'
|
|
423
289
|
import timemsTZ2day from 'wsemi/src/timemsTZ2day.mjs'
|
|
424
290
|
import convertToTree from 'wsemi/src/convertToTree.mjs'
|
|
291
|
+
import { mdiArrowLeft, mdiArrowRight, mdiCloudBraces, mdiChartBar } from '@mdi/js'
|
|
425
292
|
import WButtonCircle from 'w-component-vue/src/components/WButtonCircle.vue'
|
|
426
|
-
import WGroupChipRadio from 'w-component-vue/src/components/WGroupChipRadio.vue'
|
|
427
293
|
import WDrawer from 'w-component-vue/src/components/WDrawer.vue'
|
|
428
294
|
import WTree from 'w-component-vue/src/components/WTree.vue'
|
|
429
|
-
import WJsonView from 'w-component-vue/src/components/WJsonView.vue'
|
|
430
295
|
import MdPanel from './MdPanel.vue'
|
|
296
|
+
import LayoutContentEdit from './LayoutContentEdit.vue'
|
|
297
|
+
import LayoutContentTest from './LayoutContentTest.vue'
|
|
298
|
+
import LayoutContentStats from './LayoutContentStats.vue'
|
|
431
299
|
|
|
432
300
|
|
|
433
301
|
export default {
|
|
434
302
|
components: {
|
|
435
303
|
WButtonCircle,
|
|
436
|
-
WGroupChipRadio,
|
|
437
304
|
WDrawer,
|
|
438
305
|
WTree,
|
|
439
|
-
WJsonView,
|
|
440
306
|
MdPanel,
|
|
307
|
+
LayoutContentEdit,
|
|
308
|
+
LayoutContentTest,
|
|
309
|
+
LayoutContentStats,
|
|
441
310
|
},
|
|
442
311
|
props: {
|
|
443
312
|
},
|
|
@@ -447,6 +316,14 @@ export default {
|
|
|
447
316
|
panelWidth: 0,
|
|
448
317
|
panelHeight: 0,
|
|
449
318
|
|
|
319
|
+
//左側垂直主選單
|
|
320
|
+
section: 'api', //'api' | 'stats'
|
|
321
|
+
widthMainMenu: 76,
|
|
322
|
+
mainMenus: [
|
|
323
|
+
{ id: 'api', textKey: 'mmApi', icon: mdiCloudBraces },
|
|
324
|
+
{ id: 'stats', textKey: 'mmStaInfor', icon: mdiChartBar },
|
|
325
|
+
],
|
|
326
|
+
|
|
450
327
|
drawer: true,
|
|
451
328
|
drawerWidth: 320,
|
|
452
329
|
drawerWidthMin: 200,
|
|
@@ -457,16 +334,24 @@ export default {
|
|
|
457
334
|
apisTree: [],
|
|
458
335
|
kpApisTree: {},
|
|
459
336
|
apiActive: null,
|
|
337
|
+
mdiArrowLeft,
|
|
338
|
+
mdiArrowRight,
|
|
460
339
|
apiSelect: null,
|
|
461
340
|
|
|
462
341
|
kpColorMethod: {
|
|
463
|
-
GET: '#
|
|
464
|
-
POST: '#
|
|
465
|
-
PUT: '#
|
|
466
|
-
DEL: '#
|
|
342
|
+
GET: '#0082d0',
|
|
343
|
+
POST: '#069061',
|
|
344
|
+
PUT: '#ff5800',
|
|
345
|
+
DEL: '#ef0006',
|
|
467
346
|
},
|
|
468
347
|
|
|
469
|
-
|
|
348
|
+
//API 管理:模式切換 / 新增 / 搜尋
|
|
349
|
+
mode: 'docs', //'docs' | 'edit' | 'test'
|
|
350
|
+
newMode: false,
|
|
351
|
+
blankApi: {},
|
|
352
|
+
search: '',
|
|
353
|
+
heightModeBar: 46,
|
|
354
|
+
heightDrawerHeader: 48,
|
|
470
355
|
|
|
471
356
|
}
|
|
472
357
|
},
|
|
@@ -484,32 +369,25 @@ export default {
|
|
|
484
369
|
let vo = this
|
|
485
370
|
//trigger
|
|
486
371
|
let apis = vo.apis
|
|
372
|
+
let search = vo.search //讓搜尋變更也觸發tree重建
|
|
373
|
+
void search
|
|
487
374
|
vo.genTree(apis)
|
|
488
375
|
return ''
|
|
489
376
|
},
|
|
490
377
|
|
|
491
|
-
|
|
378
|
+
editItem: function() {
|
|
492
379
|
let vo = this
|
|
493
|
-
|
|
494
|
-
{
|
|
495
|
-
id: 'tree',
|
|
496
|
-
text: vo.$t('outputMenuTree'),
|
|
497
|
-
icon: 'mdi-vanity-light',
|
|
498
|
-
},
|
|
499
|
-
{
|
|
500
|
-
id: 'raw',
|
|
501
|
-
text: vo.$t('outputMenuRaw'),
|
|
502
|
-
icon: 'mdi-lan',
|
|
503
|
-
},
|
|
504
|
-
]
|
|
505
|
-
return ms
|
|
380
|
+
return vo.newMode ? vo.blankApi : vo.apiSelect
|
|
506
381
|
},
|
|
507
382
|
|
|
508
|
-
|
|
383
|
+
//關鍵字以分號切開成陣列(trim + 去空),供 pills 區逐一以 chip 呈現
|
|
384
|
+
keywordsList: function() {
|
|
509
385
|
let vo = this
|
|
510
|
-
let
|
|
511
|
-
|
|
512
|
-
|
|
386
|
+
let s = get(vo.apiSelect, 'keywords', '')
|
|
387
|
+
if (!s) {
|
|
388
|
+
return []
|
|
389
|
+
}
|
|
390
|
+
return String(s).split(';').map((x) => x.trim()).filter((x) => x !== '')
|
|
513
391
|
},
|
|
514
392
|
|
|
515
393
|
},
|
|
@@ -530,14 +408,17 @@ export default {
|
|
|
530
408
|
genTree: function () {
|
|
531
409
|
let vo = this
|
|
532
410
|
|
|
411
|
+
//保留目前選取的API id, 重建後盡量維持選取(避免儲存/同步後選取跳回第一筆)
|
|
412
|
+
let prevId = get(vo.apiSelect, 'id', '')
|
|
413
|
+
|
|
533
414
|
//default
|
|
534
415
|
vo.apiActive = null
|
|
535
|
-
vo.apiSelect = null
|
|
536
416
|
vo.apisTree = []
|
|
537
417
|
vo.kpApisTree = {}
|
|
538
418
|
|
|
539
419
|
//check
|
|
540
420
|
if (size(vo.apis) === 0) {
|
|
421
|
+
vo.apiSelect = null
|
|
541
422
|
return
|
|
542
423
|
}
|
|
543
424
|
|
|
@@ -545,6 +426,15 @@ export default {
|
|
|
545
426
|
let apis = cloneDeep(vo.apis)
|
|
546
427
|
// console.log('apis', cloneDeep(apis))
|
|
547
428
|
|
|
429
|
+
//搜尋過濾(name/keywords/url/levels/method)
|
|
430
|
+
let sterm = trim(vo.search).toLowerCase()
|
|
431
|
+
if (sterm !== '') {
|
|
432
|
+
apis = filter(apis, (v) => {
|
|
433
|
+
let hay = `${get(v, 'name', '')} ${get(v, 'keywords', '')} ${get(v, 'url', '')} ${get(v, 'levels', '')} ${get(v, 'method', '')}`.toLowerCase()
|
|
434
|
+
return hay.indexOf(sterm) >= 0
|
|
435
|
+
})
|
|
436
|
+
}
|
|
437
|
+
|
|
548
438
|
//tr
|
|
549
439
|
let tr = {}
|
|
550
440
|
let kpTree = {}
|
|
@@ -570,8 +460,14 @@ export default {
|
|
|
570
460
|
let tree = convertToTree(tr, { bindRoot: '全部' })
|
|
571
461
|
// console.log('tree', cloneDeep(tree))
|
|
572
462
|
|
|
573
|
-
//apiSelect,
|
|
574
|
-
let apiSelect =
|
|
463
|
+
//apiSelect: 優先保留原選取(仍存在時), 否則取第一筆
|
|
464
|
+
let apiSelect = null
|
|
465
|
+
if (prevId !== '') {
|
|
466
|
+
apiSelect = find(apis, { id: prevId }) || null
|
|
467
|
+
}
|
|
468
|
+
if (!iseobj(apiSelect)) {
|
|
469
|
+
apiSelect = get(apis, 0, null)
|
|
470
|
+
}
|
|
575
471
|
// console.log('apiSelect', cloneDeep(apiSelect))
|
|
576
472
|
|
|
577
473
|
//save
|
|
@@ -596,6 +492,16 @@ export default {
|
|
|
596
492
|
return method
|
|
597
493
|
},
|
|
598
494
|
|
|
495
|
+
curlOf: function(item) {
|
|
496
|
+
let vo = this
|
|
497
|
+
let method = vo.getMethod(item) || 'GET'
|
|
498
|
+
let url = get(item, 'inputExample', '')
|
|
499
|
+
if (!url) {
|
|
500
|
+
url = get(item, 'url', '')
|
|
501
|
+
}
|
|
502
|
+
return 'curl -X ' + method + ' "' + url + '"'
|
|
503
|
+
},
|
|
504
|
+
|
|
599
505
|
getMethodByKey: function(key) {
|
|
600
506
|
let vo = this
|
|
601
507
|
let item = vo.getItemByKey(key)
|
|
@@ -621,44 +527,102 @@ export default {
|
|
|
621
527
|
return timemsTZ2day(t)
|
|
622
528
|
},
|
|
623
529
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
//
|
|
633
|
-
|
|
634
|
-
//
|
|
635
|
-
|
|
636
|
-
return
|
|
530
|
+
jsonHighlight: function(str) {
|
|
531
|
+
let s = (str === null || str === undefined) ? '' : String(str)
|
|
532
|
+
// escape HTML
|
|
533
|
+
s = s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
534
|
+
// key: "xxx":
|
|
535
|
+
s = s.replace(/("(?:[^"\\]|\\.)*")(\s*:)/g, '<span class="k">$1</span>$2')
|
|
536
|
+
// string value
|
|
537
|
+
s = s.replace(/:(\s*)("(?:[^"\\]|\\.)*")/g, ':$1<span class="s">$2</span>')
|
|
538
|
+
// number
|
|
539
|
+
s = s.replace(/([:\[,\s])(-?\d+\.?\d*)/g, '$1<span class="n">$2</span>')
|
|
540
|
+
// bool/null
|
|
541
|
+
s = s.replace(/\b(true|false|null)\b/g, '<span class="b">$1</span>')
|
|
542
|
+
return s
|
|
637
543
|
},
|
|
638
544
|
|
|
639
545
|
funActive: function(msg) {
|
|
640
546
|
let vo = this
|
|
641
|
-
let b = !Array.isArray(msg.item.children) //children非陣列代表沒有所屬節點
|
|
547
|
+
let b = !Array.isArray(msg.item.children) //children非陣列代表沒有所屬節點(葉節點)
|
|
642
548
|
if (b) {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
549
|
+
//渲染時用穩定的 api id(=節點 text) 對應目前選取項, 把 apiActive 刷新成該葉節點「當前」的 id;
|
|
550
|
+
//避免存檔後 tree 重建、convertToTree 重新產生節點 id, 使 apiActive 變舊而高亮(含左側 accent bar)失效
|
|
551
|
+
let itemText = get(msg, 'item.text', '')
|
|
552
|
+
let itemId = get(msg, 'item.id', '')
|
|
553
|
+
if (iseobj(vo.apiSelect) && itemText === vo.apiSelect.id) {
|
|
554
|
+
if (get(vo.apiActive, 'id') !== itemId) {
|
|
555
|
+
vo.apiActive = { id: itemId }
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
else if (!iseobj(vo.apiActive)) { //無選取時初始化第一個葉節點為 active
|
|
559
|
+
vo.apiActive = { id: itemId }
|
|
647
560
|
}
|
|
648
561
|
}
|
|
649
562
|
return b
|
|
650
563
|
},
|
|
651
564
|
|
|
652
|
-
|
|
653
|
-
// console.log('
|
|
565
|
+
ckItem: function(item, node) {
|
|
566
|
+
// console.log('ckItem', item)
|
|
567
|
+
let vo = this
|
|
568
|
+
vo.apiSelect = cloneDeep(item)
|
|
569
|
+
if (iseobj(node)) { //點擊即更新 active 節點 id, 使高亮(含左側 bar)立即移到所點項目
|
|
570
|
+
vo.apiActive = { id: node.id }
|
|
571
|
+
}
|
|
572
|
+
vo.newMode = false //點選既有API即離開新增狀態
|
|
573
|
+
},
|
|
574
|
+
|
|
575
|
+
onChangeMode: function(msg) {
|
|
654
576
|
let vo = this
|
|
655
|
-
vo.
|
|
577
|
+
vo.mode = msg.id
|
|
578
|
+
//切到非編輯模式時取消新增狀態
|
|
579
|
+
if (vo.newMode && msg.id !== 'edit') {
|
|
580
|
+
vo.newMode = false
|
|
581
|
+
}
|
|
656
582
|
},
|
|
657
583
|
|
|
658
|
-
|
|
659
|
-
// console.log('ckItem', item)
|
|
584
|
+
onClickMainMenu: function(m) {
|
|
660
585
|
let vo = this
|
|
661
|
-
vo.
|
|
586
|
+
vo.section = m.id
|
|
587
|
+
},
|
|
588
|
+
|
|
589
|
+
onClickAddApi: function() {
|
|
590
|
+
let vo = this
|
|
591
|
+
//種子空白API(預設值, 送出時後端funNew會配id/時間)
|
|
592
|
+
vo.blankApi = {
|
|
593
|
+
name: '',
|
|
594
|
+
description: '',
|
|
595
|
+
url: '',
|
|
596
|
+
method: 'get',
|
|
597
|
+
version: 'v1',
|
|
598
|
+
group: '',
|
|
599
|
+
levels: '',
|
|
600
|
+
keywords: '',
|
|
601
|
+
state: 'ok',
|
|
602
|
+
authType: 'none',
|
|
603
|
+
contentType: 'application/json',
|
|
604
|
+
}
|
|
605
|
+
vo.newMode = true
|
|
606
|
+
vo.mode = 'edit'
|
|
607
|
+
},
|
|
608
|
+
|
|
609
|
+
onEditSaved: function() {
|
|
610
|
+
let vo = this
|
|
611
|
+
vo.newMode = false
|
|
612
|
+
vo.mode = 'docs'
|
|
613
|
+
},
|
|
614
|
+
|
|
615
|
+
onEditDeleted: function() {
|
|
616
|
+
let vo = this
|
|
617
|
+
vo.newMode = false
|
|
618
|
+
vo.apiSelect = null
|
|
619
|
+
vo.mode = 'docs'
|
|
620
|
+
},
|
|
621
|
+
|
|
622
|
+
onEditCancel: function() {
|
|
623
|
+
let vo = this
|
|
624
|
+
vo.newMode = false
|
|
625
|
+
vo.mode = 'docs'
|
|
662
626
|
},
|
|
663
627
|
|
|
664
628
|
}
|
|
@@ -666,23 +630,34 @@ export default {
|
|
|
666
630
|
</script>
|
|
667
631
|
|
|
668
632
|
<style scoped>
|
|
669
|
-
.
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
padding:
|
|
673
|
-
|
|
633
|
+
.w-mm-btn {
|
|
634
|
+
width: 100%;
|
|
635
|
+
box-sizing: border-box;
|
|
636
|
+
padding: 10px 4px;
|
|
637
|
+
border: none;
|
|
638
|
+
border-left: 3px solid transparent;
|
|
639
|
+
background: transparent;
|
|
640
|
+
color: var(--c-2);
|
|
641
|
+
cursor: pointer;
|
|
642
|
+
display: flex;
|
|
643
|
+
flex-direction: column;
|
|
644
|
+
align-items: center;
|
|
645
|
+
gap: 4px;
|
|
646
|
+
transition: background .15s, color .15s, border-color .15s;
|
|
647
|
+
}
|
|
648
|
+
.w-mm-btn:hover {
|
|
649
|
+
background: rgba(0, 153, 255, 0.06);
|
|
650
|
+
color: var(--c-1);
|
|
674
651
|
}
|
|
675
|
-
.
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
652
|
+
.w-mm-btn.on {
|
|
653
|
+
color: var(--accent);
|
|
654
|
+
border-left-color: var(--accent);
|
|
655
|
+
background: rgba(0, 153, 255, 0.08);
|
|
679
656
|
}
|
|
680
|
-
.
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
border:1px solid #ddd;
|
|
686
|
-
background:#fff;
|
|
657
|
+
.w-mm-label {
|
|
658
|
+
font-size: 11px;
|
|
659
|
+
line-height: 1.2;
|
|
660
|
+
text-align: center;
|
|
661
|
+
word-break: break-word;
|
|
687
662
|
}
|
|
688
663
|
</style>
|