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
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :style="`height:${height}px; box-sizing:border-box; overflow-y:auto; padding:20px;`">
|
|
3
|
+
|
|
4
|
+
<!-- 區塊一:基本資訊 -->
|
|
5
|
+
<div style="margin-bottom:20px;">
|
|
6
|
+
|
|
7
|
+
<div class="bk-title-sec">
|
|
8
|
+
{{$t('secBasic')}}
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<div class="bk-row">
|
|
12
|
+
<div class="bk-col-label bk-title">{{$t('name')}}<span style="color:var(--danger); margin-left:2px;">*</span></div>
|
|
13
|
+
<div class="bk-col-field">
|
|
14
|
+
<input class="bk-input" v-model="form.name" type="text" />
|
|
15
|
+
<div class="bk-err" v-if="errName">{{errName}}</div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="bk-row">
|
|
20
|
+
<div class="bk-col-label bk-title">{{$t('description')}}</div>
|
|
21
|
+
<div class="bk-col-field">
|
|
22
|
+
<textarea class="bk-textarea" v-model="form.description" rows="3"></textarea>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div class="bk-row">
|
|
27
|
+
<div class="bk-col-label bk-title">{{$t('apiUrl')}}<span style="color:var(--danger); margin-left:2px;">*</span></div>
|
|
28
|
+
<div class="bk-col-field">
|
|
29
|
+
<input class="bk-input" v-model="form.url" type="text" />
|
|
30
|
+
<div class="bk-err" v-if="errUrl">{{errUrl}}</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div class="bk-row">
|
|
35
|
+
<div class="bk-col-label bk-title">{{$t('fieldMethod')}}</div>
|
|
36
|
+
<div class="bk-col-field">
|
|
37
|
+
<WTextSelect
|
|
38
|
+
style="width:160px;"
|
|
39
|
+
:items="methodItems"
|
|
40
|
+
:value="form.method"
|
|
41
|
+
@input="onChangeMethod"
|
|
42
|
+
>
|
|
43
|
+
<template v-slot:select="props">
|
|
44
|
+
{{getMethodText(props.item)}}
|
|
45
|
+
</template>
|
|
46
|
+
<template v-slot:item="props">
|
|
47
|
+
{{getMethodText(props.item)}}
|
|
48
|
+
</template>
|
|
49
|
+
</WTextSelect>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div class="bk-row">
|
|
54
|
+
<div class="bk-col-label bk-title">{{$t('version')}}</div>
|
|
55
|
+
<div class="bk-col-field">
|
|
56
|
+
<input class="bk-input" v-model="form.version" type="text" />
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div class="bk-row">
|
|
61
|
+
<div class="bk-col-label bk-title">{{$t('fieldGroup')}}</div>
|
|
62
|
+
<div class="bk-col-field">
|
|
63
|
+
<input class="bk-input" v-model="form.group" type="text" />
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="bk-row">
|
|
68
|
+
<div class="bk-col-label bk-title">{{$t('levels')}}</div>
|
|
69
|
+
<div class="bk-col-field">
|
|
70
|
+
<input class="bk-input" v-model="form.levels" type="text" />
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div class="bk-row">
|
|
75
|
+
<div class="bk-col-label bk-title">{{$t('keywords')}}</div>
|
|
76
|
+
<div class="bk-col-field">
|
|
77
|
+
<input class="bk-input" v-model="form.keywords" type="text" />
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div class="bk-row">
|
|
82
|
+
<div class="bk-col-label bk-title">{{$t('state')}}</div>
|
|
83
|
+
<div class="bk-col-field">
|
|
84
|
+
<input class="bk-input" v-model="form.state" type="text" />
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<div class="bk-row">
|
|
89
|
+
<div class="bk-col-label bk-title">{{$t('fieldOrder')}}</div>
|
|
90
|
+
<div class="bk-col-field">
|
|
91
|
+
<input class="bk-input" v-model.number="form.order" type="number" />
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div class="bk-row">
|
|
96
|
+
<div class="bk-col-label bk-title">{{$t('tokens')}}</div>
|
|
97
|
+
<div class="bk-col-field">
|
|
98
|
+
<textarea class="bk-textarea" v-model="form.tokens" rows="3"></textarea>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<!-- 區塊二:文件 -->
|
|
105
|
+
<div style="margin-bottom:20px;">
|
|
106
|
+
|
|
107
|
+
<div class="bk-title-sec">
|
|
108
|
+
{{$t('secDocs')}}
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="bk-row">
|
|
112
|
+
<div class="bk-col-label bk-title">{{$t('mdInputParams')}}</div>
|
|
113
|
+
<div class="bk-col-field">
|
|
114
|
+
<textarea class="bk-textarea" v-model="form.mdInputParams" rows="6"></textarea>
|
|
115
|
+
<div class="bk-preview bk-item" v-if="form.mdInputParams">
|
|
116
|
+
<MdPanel :md="form.mdInputParams"></MdPanel>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div class="bk-row">
|
|
122
|
+
<div class="bk-col-label bk-title">{{$t('inputExample')}}</div>
|
|
123
|
+
<div class="bk-col-field">
|
|
124
|
+
<textarea class="bk-textarea" v-model="form.inputExample" rows="4"></textarea>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<div class="bk-row">
|
|
129
|
+
<div class="bk-col-label bk-title">{{$t('mdOutputParams')}}</div>
|
|
130
|
+
<div class="bk-col-field">
|
|
131
|
+
<textarea class="bk-textarea" v-model="form.mdOutputParams" rows="6"></textarea>
|
|
132
|
+
<div class="bk-preview bk-item" v-if="form.mdOutputParams">
|
|
133
|
+
<MdPanel :md="form.mdOutputParams"></MdPanel>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<div class="bk-row">
|
|
139
|
+
<div class="bk-col-label bk-title">{{$t('outputExample')}}</div>
|
|
140
|
+
<div class="bk-col-field">
|
|
141
|
+
<textarea class="bk-textarea" v-model="form.outputExample" rows="6"></textarea>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<!-- 區塊三:測試設定 -->
|
|
148
|
+
<div style="margin-bottom:20px;">
|
|
149
|
+
|
|
150
|
+
<div class="bk-title-sec">
|
|
151
|
+
{{$t('secTest')}}
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<div class="bk-row">
|
|
155
|
+
<div class="bk-col-label bk-title">{{$t('fieldTestBaseUrl')}}</div>
|
|
156
|
+
<div class="bk-hint">{{$t('hintTestBaseUrl')}}</div>
|
|
157
|
+
<div class="bk-col-field">
|
|
158
|
+
<input class="bk-input" v-model="form.testBaseUrl" type="text" />
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
<div class="bk-row">
|
|
163
|
+
<div class="bk-col-label bk-title">{{$t('fieldAuthType')}}</div>
|
|
164
|
+
<div class="bk-hint">{{$t('hintAuthType')}}</div>
|
|
165
|
+
<div class="bk-col-field">
|
|
166
|
+
<WTextSelect
|
|
167
|
+
style="width:200px;"
|
|
168
|
+
:items="authTypeItems"
|
|
169
|
+
:value="form.authType"
|
|
170
|
+
@input="onChangeAuthType"
|
|
171
|
+
>
|
|
172
|
+
<template v-slot:select="props">
|
|
173
|
+
{{getAuthTypeText(props.item)}}
|
|
174
|
+
</template>
|
|
175
|
+
<template v-slot:item="props">
|
|
176
|
+
{{getAuthTypeText(props.item)}}
|
|
177
|
+
</template>
|
|
178
|
+
</WTextSelect>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
|
|
182
|
+
<div class="bk-row">
|
|
183
|
+
<div class="bk-col-label bk-title">{{$t('fieldAuthConfigJson')}}</div>
|
|
184
|
+
<div class="bk-hint">{{$t('hintAuthConfigJson')}}</div>
|
|
185
|
+
<div class="bk-col-field">
|
|
186
|
+
<textarea class="bk-textarea" v-model="form.authConfigJson" rows="4"></textarea>
|
|
187
|
+
<div class="bk-err" v-if="errJson && errJsonField==='authConfigJson'">{{errJson}}</div>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
<div class="bk-row">
|
|
192
|
+
<div class="bk-col-label bk-title">{{$t('fieldDefaultHeadersJson')}}</div>
|
|
193
|
+
<div class="bk-hint">{{$t('hintDefaultHeadersJson')}}</div>
|
|
194
|
+
<div class="bk-col-field">
|
|
195
|
+
<textarea class="bk-textarea" v-model="form.defaultHeadersJson" rows="4"></textarea>
|
|
196
|
+
<div class="bk-err" v-if="errJson && errJsonField==='defaultHeadersJson'">{{errJson}}</div>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<div class="bk-row">
|
|
201
|
+
<div class="bk-col-label bk-title">{{$t('fieldDefaultQueryJson')}}</div>
|
|
202
|
+
<div class="bk-hint">{{$t('hintDefaultQueryJson')}}</div>
|
|
203
|
+
<div class="bk-col-field">
|
|
204
|
+
<textarea class="bk-textarea" v-model="form.defaultQueryJson" rows="4"></textarea>
|
|
205
|
+
<div class="bk-err" v-if="errJson && errJsonField==='defaultQueryJson'">{{errJson}}</div>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<div class="bk-row">
|
|
210
|
+
<div class="bk-col-label bk-title">{{$t('fieldDefaultBodyJson')}}</div>
|
|
211
|
+
<div class="bk-hint">{{$t('hintDefaultBodyJson')}}</div>
|
|
212
|
+
<div class="bk-col-field">
|
|
213
|
+
<textarea class="bk-textarea" v-model="form.defaultBodyJson" rows="4"></textarea>
|
|
214
|
+
<div class="bk-err" v-if="errJson && errJsonField==='defaultBodyJson'">{{errJson}}</div>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<div class="bk-row">
|
|
219
|
+
<div class="bk-col-label bk-title">{{$t('fieldContentType')}}</div>
|
|
220
|
+
<div class="bk-hint">{{$t('hintContentType')}}</div>
|
|
221
|
+
<div class="bk-col-field">
|
|
222
|
+
<input class="bk-input" v-model="form.contentType" type="text" />
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
</div>
|
|
227
|
+
|
|
228
|
+
<!-- 全域儲存錯誤 -->
|
|
229
|
+
<div class="bk-err" v-if="errSave" style="margin-bottom:10px;">{{errSave}}</div>
|
|
230
|
+
|
|
231
|
+
<!-- 底部按鈕列 -->
|
|
232
|
+
<div style="display:flex; gap:8px; padding-bottom:20px;">
|
|
233
|
+
|
|
234
|
+
<button class="btn-save" @click="onClickSave">
|
|
235
|
+
{{$t('save')}}
|
|
236
|
+
</button>
|
|
237
|
+
|
|
238
|
+
<button class="btn-delete" @click="onClickDelete" v-if="!isNew">
|
|
239
|
+
{{$t('delete')}}
|
|
240
|
+
</button>
|
|
241
|
+
|
|
242
|
+
<button class="btn-cancel" @click="onClickCancel">
|
|
243
|
+
{{$t('cancel')}}
|
|
244
|
+
</button>
|
|
245
|
+
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
</div>
|
|
249
|
+
</template>
|
|
250
|
+
|
|
251
|
+
<script>
|
|
252
|
+
import cloneDeep from 'lodash-es/cloneDeep.js'
|
|
253
|
+
import isestr from 'wsemi/src/isestr.mjs'
|
|
254
|
+
import WTextSelect from 'w-component-vue/src/components/WTextSelect.vue'
|
|
255
|
+
import MdPanel from './MdPanel.vue'
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
export default {
|
|
259
|
+
components: {
|
|
260
|
+
WTextSelect,
|
|
261
|
+
MdPanel,
|
|
262
|
+
},
|
|
263
|
+
props: {
|
|
264
|
+
item: {
|
|
265
|
+
type: Object,
|
|
266
|
+
default: function() { return {} },
|
|
267
|
+
},
|
|
268
|
+
height: {
|
|
269
|
+
type: Number,
|
|
270
|
+
default: 0,
|
|
271
|
+
},
|
|
272
|
+
isNew: {
|
|
273
|
+
type: Boolean,
|
|
274
|
+
default: false,
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
data: function() {
|
|
278
|
+
return {
|
|
279
|
+
|
|
280
|
+
form: {},
|
|
281
|
+
|
|
282
|
+
errName: '',
|
|
283
|
+
errUrl: '',
|
|
284
|
+
errJson: '',
|
|
285
|
+
errJsonField: '',
|
|
286
|
+
errSave: '',
|
|
287
|
+
|
|
288
|
+
methodItems: ['get', 'post', 'put', 'del'],
|
|
289
|
+
authTypeItems: ['none', 'bearer', 'apikey', 'basic'],
|
|
290
|
+
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
mounted: function() {
|
|
294
|
+
let vo = this
|
|
295
|
+
vo.form = cloneDeep(vo.item)
|
|
296
|
+
},
|
|
297
|
+
watch: {
|
|
298
|
+
item: {
|
|
299
|
+
deep: true,
|
|
300
|
+
immediate: true,
|
|
301
|
+
handler: function(val) {
|
|
302
|
+
let vo = this
|
|
303
|
+
vo.form = cloneDeep(val)
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
methods: {
|
|
308
|
+
|
|
309
|
+
getMethodText: function(item) {
|
|
310
|
+
// let vo = this
|
|
311
|
+
if (!isestr(item)) {
|
|
312
|
+
return ''
|
|
313
|
+
}
|
|
314
|
+
return item.toUpperCase()
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
getAuthTypeText: function(item) {
|
|
318
|
+
let vo = this
|
|
319
|
+
let kp = {
|
|
320
|
+
none: vo.$t('authNone'),
|
|
321
|
+
bearer: vo.$t('authBearer'),
|
|
322
|
+
apikey: vo.$t('authApikey'),
|
|
323
|
+
basic: vo.$t('authBasic'),
|
|
324
|
+
}
|
|
325
|
+
if (!isestr(item)) {
|
|
326
|
+
return ''
|
|
327
|
+
}
|
|
328
|
+
return kp[item] || item
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
onChangeMethod: function(val) {
|
|
332
|
+
let vo = this
|
|
333
|
+
vo.form.method = val
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
onChangeAuthType: function(val) {
|
|
337
|
+
let vo = this
|
|
338
|
+
vo.form.authType = val
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
onClickSave: function() {
|
|
342
|
+
let vo = this
|
|
343
|
+
vo.submitSave()
|
|
344
|
+
.catch(function(err) { console.log('catch', err); vo.$alert(vo.$t('anUnexpectedErrorOccurred'), 'error') })
|
|
345
|
+
.finally(function() { vo.$ui.updateLoading(false) })
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
submitSave: function() {
|
|
349
|
+
let vo = this
|
|
350
|
+
let core = async function() {
|
|
351
|
+
|
|
352
|
+
// 1) 清空舊 inline 錯誤
|
|
353
|
+
vo.errName = ''
|
|
354
|
+
vo.errUrl = ''
|
|
355
|
+
vo.errJson = ''
|
|
356
|
+
vo.errJsonField = ''
|
|
357
|
+
vo.errSave = ''
|
|
358
|
+
|
|
359
|
+
// 2) 同步檢測,開 loading 之前
|
|
360
|
+
if (!isestr(vo.form.name)) {
|
|
361
|
+
vo.errName = vo.$t('valRequired')
|
|
362
|
+
return
|
|
363
|
+
}
|
|
364
|
+
if (!isestr(vo.form.url)) {
|
|
365
|
+
vo.errUrl = vo.$t('valRequired')
|
|
366
|
+
return
|
|
367
|
+
}
|
|
368
|
+
let jsonFields = ['authConfigJson', 'defaultHeadersJson', 'defaultQueryJson', 'defaultBodyJson']
|
|
369
|
+
for (let i = 0; i < jsonFields.length; i++) {
|
|
370
|
+
let fk = jsonFields[i]
|
|
371
|
+
let fv = vo.form[fk]
|
|
372
|
+
if (isestr(fv)) {
|
|
373
|
+
let jsonOk = true
|
|
374
|
+
try { JSON.parse(fv) } catch (e) { jsonOk = false }
|
|
375
|
+
if (!jsonOk) {
|
|
376
|
+
vo.errJsonField = fk
|
|
377
|
+
vo.errJson = fk + ': ' + vo.$t('valInvalidJson')
|
|
378
|
+
return
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// 3) 確定打 API 才開 loading
|
|
384
|
+
vo.$ui.updateLoading(true)
|
|
385
|
+
|
|
386
|
+
// 4) 執行 async,各自 catch + 旗標短路
|
|
387
|
+
let okSave = false
|
|
388
|
+
await vo.$fapi.saveApi(cloneDeep(vo.form))
|
|
389
|
+
.then(function() { okSave = true })
|
|
390
|
+
.catch(function(err) { console.log('saveApi', err); vo.errSave = vo.$transErr(err) }) //err 為後端 err-key,依 lang 反查顯示
|
|
391
|
+
if (!okSave) return
|
|
392
|
+
|
|
393
|
+
// 5) 全成功
|
|
394
|
+
vo.$emit('saved')
|
|
395
|
+
//成功訊息改用 confirm modal($dg.showCheckYes)而非 toast:toast 是插入後又移除的暫時 DOM,
|
|
396
|
+
//新版 chromium 在 insert/remove 後會把整頁 render 原點偏移 1px(headless 偶發、實測 toast 關掉即穩),
|
|
397
|
+
//modal 是「顯示著被截」不會有移除殘留,且對齊 w-web-sso 之成功 modal。
|
|
398
|
+
vo.$dg.showCheckYes(vo.$t('saveSuccess'), { type: 'success' })
|
|
399
|
+
return 'ok'
|
|
400
|
+
|
|
401
|
+
}
|
|
402
|
+
return core()
|
|
403
|
+
},
|
|
404
|
+
|
|
405
|
+
onClickDelete: function() {
|
|
406
|
+
let vo = this
|
|
407
|
+
vo.$dg.showCheckYesNo(vo.$t('confirmDeleteApi'))
|
|
408
|
+
.then(function() { vo.doDelete() })
|
|
409
|
+
.catch(function(err) { if (err === 'close') return; console.log('showCheckYesNo', err) })
|
|
410
|
+
},
|
|
411
|
+
|
|
412
|
+
doDelete: function() {
|
|
413
|
+
let vo = this
|
|
414
|
+
let core = async function() {
|
|
415
|
+
|
|
416
|
+
// 1) 清空錯誤
|
|
417
|
+
vo.errSave = ''
|
|
418
|
+
|
|
419
|
+
// 2) 同步檢測(無需額外檢測,id 由 item 帶入)
|
|
420
|
+
|
|
421
|
+
// 3) 開 loading
|
|
422
|
+
vo.$ui.updateLoading(true)
|
|
423
|
+
|
|
424
|
+
// 4) 執行 async
|
|
425
|
+
let okDel = false
|
|
426
|
+
await vo.$fapi.deleteApi(vo.form.id)
|
|
427
|
+
.then(function() { okDel = true })
|
|
428
|
+
.catch(function(err) { console.log('deleteApi', err); vo.errSave = vo.$transErr(err) }) //err 為後端 err-key,依 lang 反查顯示
|
|
429
|
+
if (!okDel) return
|
|
430
|
+
|
|
431
|
+
// 5) 全成功
|
|
432
|
+
vo.$emit('deleted')
|
|
433
|
+
vo.$dg.showCheckYes(vo.$t('deleteSuccess'), { type: 'success' }) //同 saveSuccess:toast → confirm modal(避免移除殘留位移、對齊 SSO);type:success 顯綠勾
|
|
434
|
+
return 'ok'
|
|
435
|
+
|
|
436
|
+
}
|
|
437
|
+
core()
|
|
438
|
+
.catch(function(err) { console.log('catch', err); vo.$alert(vo.$t('anUnexpectedErrorOccurred'), 'error') })
|
|
439
|
+
.finally(function() { vo.$ui.updateLoading(false) })
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
onClickCancel: function() {
|
|
443
|
+
let vo = this
|
|
444
|
+
vo.$emit('cancel')
|
|
445
|
+
},
|
|
446
|
+
|
|
447
|
+
},
|
|
448
|
+
}
|
|
449
|
+
</script>
|
|
450
|
+
|
|
451
|
+
<style scoped>
|
|
452
|
+
.bk-title-sec {
|
|
453
|
+
font-size: var(--fs-h3);
|
|
454
|
+
font-weight: 600;
|
|
455
|
+
color: var(--c-1);
|
|
456
|
+
padding: 6px 0px 10px 0px;
|
|
457
|
+
border-bottom: 1px solid var(--border);
|
|
458
|
+
margin-bottom: 12px;
|
|
459
|
+
}
|
|
460
|
+
.bk-title {
|
|
461
|
+
font-size: var(--fs-xs);
|
|
462
|
+
font-weight: 500;
|
|
463
|
+
color: var(--c-2);
|
|
464
|
+
padding: 0 0 6px 0;
|
|
465
|
+
}
|
|
466
|
+
.bk-item {
|
|
467
|
+
padding: 3px 5px;
|
|
468
|
+
font-size: 0.9rem;
|
|
469
|
+
line-height: 0.9rem;
|
|
470
|
+
border-radius: var(--radius-lg);
|
|
471
|
+
border: 1px solid var(--border);
|
|
472
|
+
background: var(--bg-1);
|
|
473
|
+
}
|
|
474
|
+
.bk-row {
|
|
475
|
+
display: flex;
|
|
476
|
+
flex-direction: column;
|
|
477
|
+
/* padding-top 大於 padding-bottom:使「組間」(上一列欄位→下一列小標) 間距明顯大於「組內」(小標→說明→欄位),小標歸屬清楚 */
|
|
478
|
+
padding: 12px 0 6px 0;
|
|
479
|
+
}
|
|
480
|
+
.bk-col-label {
|
|
481
|
+
width: auto;
|
|
482
|
+
flex-shrink: 0;
|
|
483
|
+
}
|
|
484
|
+
.bk-col-field {
|
|
485
|
+
flex: 1;
|
|
486
|
+
}
|
|
487
|
+
.bk-input {
|
|
488
|
+
width: 100%;
|
|
489
|
+
box-sizing: border-box;
|
|
490
|
+
padding: 5px 8px;
|
|
491
|
+
font-size: var(--fs-body);
|
|
492
|
+
border-radius: var(--radius-lg);
|
|
493
|
+
border: 1px solid var(--border);
|
|
494
|
+
background: var(--bg-1);
|
|
495
|
+
color: var(--c-1);
|
|
496
|
+
outline: none;
|
|
497
|
+
transition: border-color .15s, box-shadow .15s;
|
|
498
|
+
}
|
|
499
|
+
.bk-input:focus {
|
|
500
|
+
border-color: var(--accent);
|
|
501
|
+
box-shadow: var(--focus);
|
|
502
|
+
}
|
|
503
|
+
.bk-textarea {
|
|
504
|
+
width: 100%;
|
|
505
|
+
box-sizing: border-box;
|
|
506
|
+
padding: 5px 8px;
|
|
507
|
+
font-size: var(--fs-sm);
|
|
508
|
+
border-radius: var(--radius-lg);
|
|
509
|
+
border: 1px solid var(--border);
|
|
510
|
+
background: var(--bg-1);
|
|
511
|
+
color: var(--c-1);
|
|
512
|
+
outline: none;
|
|
513
|
+
resize: vertical;
|
|
514
|
+
font-family: var(--font-code);
|
|
515
|
+
transition: border-color .15s, box-shadow .15s;
|
|
516
|
+
}
|
|
517
|
+
.bk-textarea:focus {
|
|
518
|
+
border-color: var(--accent);
|
|
519
|
+
box-shadow: var(--focus);
|
|
520
|
+
}
|
|
521
|
+
.bk-preview {
|
|
522
|
+
margin-top: 6px;
|
|
523
|
+
padding: 8px 10px;
|
|
524
|
+
}
|
|
525
|
+
.bk-err {
|
|
526
|
+
color: var(--danger);
|
|
527
|
+
font-size: var(--fs-xs);
|
|
528
|
+
padding: 3px 2px;
|
|
529
|
+
}
|
|
530
|
+
.bk-hint {
|
|
531
|
+
color: var(--c-3);
|
|
532
|
+
font-size: var(--fs-xs);
|
|
533
|
+
line-height: 1.6;
|
|
534
|
+
margin: 0 0 8px 0;
|
|
535
|
+
white-space: pre-line;
|
|
536
|
+
}
|
|
537
|
+
.btn-save {
|
|
538
|
+
padding: 7px 18px;
|
|
539
|
+
font-size: var(--fs-body);
|
|
540
|
+
border-radius: var(--radius-lg);
|
|
541
|
+
border: 1px solid var(--accent);
|
|
542
|
+
background: var(--accent);
|
|
543
|
+
color: #fff;
|
|
544
|
+
cursor: pointer;
|
|
545
|
+
transition: background-color .15s, border-color .15s;
|
|
546
|
+
}
|
|
547
|
+
.btn-save:hover {
|
|
548
|
+
background: var(--accent-hover);
|
|
549
|
+
border-color: var(--accent-hover);
|
|
550
|
+
}
|
|
551
|
+
.btn-delete {
|
|
552
|
+
padding: 7px 18px;
|
|
553
|
+
font-size: var(--fs-body);
|
|
554
|
+
border-radius: var(--radius-lg);
|
|
555
|
+
border: 1px solid var(--danger);
|
|
556
|
+
background: transparent;
|
|
557
|
+
color: var(--danger);
|
|
558
|
+
cursor: pointer;
|
|
559
|
+
transition: background-color .15s;
|
|
560
|
+
}
|
|
561
|
+
.btn-delete:hover {
|
|
562
|
+
background: var(--danger-bg);
|
|
563
|
+
}
|
|
564
|
+
.btn-cancel {
|
|
565
|
+
padding: 7px 18px;
|
|
566
|
+
font-size: var(--fs-body);
|
|
567
|
+
border-radius: var(--radius-lg);
|
|
568
|
+
border: 1px solid var(--border);
|
|
569
|
+
background: transparent;
|
|
570
|
+
color: var(--c-2);
|
|
571
|
+
cursor: pointer;
|
|
572
|
+
transition: background-color .15s;
|
|
573
|
+
}
|
|
574
|
+
.btn-cancel:hover {
|
|
575
|
+
background: var(--bg-3);
|
|
576
|
+
}
|
|
577
|
+
</style>
|