w-web-api 1.0.51 → 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.
Files changed (86) hide show
  1. package/_gh-pages-deploy/.nojekyll +0 -0
  2. package/_gh-pages-deploy/WWebApi.html +898 -0
  3. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  4. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  5. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  6. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  7. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  8. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  9. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  10. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  11. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  12. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  13. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  14. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  15. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  16. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  17. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  18. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  19. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  20. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  21. package/_gh-pages-deploy/index.html +84 -0
  22. package/_gh-pages-deploy/scripts/collapse.js +39 -0
  23. package/_gh-pages-deploy/scripts/commonNav.js +28 -0
  24. package/_gh-pages-deploy/scripts/linenumber.js +25 -0
  25. package/_gh-pages-deploy/scripts/nav.js +12 -0
  26. package/_gh-pages-deploy/scripts/polyfill.js +4 -0
  27. package/_gh-pages-deploy/scripts/prettify/Apache-License-2.0.txt +202 -0
  28. package/_gh-pages-deploy/scripts/prettify/lang-css.js +2 -0
  29. package/_gh-pages-deploy/scripts/prettify/prettify.js +28 -0
  30. package/_gh-pages-deploy/scripts/search.js +99 -0
  31. package/{docs/WWebApi.mjs.html → _gh-pages-deploy/server_WWebApi.mjs.html} +118 -41
  32. package/_gh-pages-deploy/src_components_Common_CheckYesNo.vue.html +187 -0
  33. package/_gh-pages-deploy/styles/jsdoc.css +776 -0
  34. package/_gh-pages-deploy/styles/prettify.css +80 -0
  35. package/dist/css/app.fe69497a.css +1 -0
  36. package/dist/index.tmp +4 -2
  37. package/dist/js/app-legacy.15819aa7.js +1 -0
  38. package/dist/js/app.15819aa7.js +1 -0
  39. package/dist/js/chunk-vendors-legacy.c1a32dd1.js +15 -0
  40. package/dist/js/chunk-vendors.c1a32dd1.js +15 -0
  41. package/dist/w-web-api.umd.js +2 -2
  42. package/dist/w-web-api.umd.js.map +1 -1
  43. package/docs/WWebApi.html +2 -2
  44. package/docs/index.html +1 -1
  45. package/docs/server_WWebApi.mjs.html +1012 -0
  46. package/docs/src_components_Common_CheckYesNo.vue.html +187 -0
  47. package/g.getSettings.mjs +3 -0
  48. package/package.json +15 -11
  49. package/public/index.html +9 -2
  50. package/server/WWebApi.mjs +115 -38
  51. package/server/procApis.mjs +62 -0
  52. package/server/procLang.mjs +724 -0
  53. package/server/procProxy.mjs +120 -0
  54. package/server/srLog.mjs +30 -0
  55. package/server/staLogs/staEvent.mjs +129 -0
  56. package/server/staLogs/test_staEvent.mjs +132 -0
  57. package/settings.json +14 -0
  58. package/src/App.vue +11 -7
  59. package/src/assets/scalar-ui.css +113 -0
  60. package/src/components/Common/CheckYes.vue +102 -0
  61. package/src/components/Common/CheckYesNo.vue +115 -0
  62. package/src/components/Common/LoadingWinBar.vue +114 -0
  63. package/src/components/Layout.vue +33 -7
  64. package/src/components/LayoutContent.vue +308 -333
  65. package/src/components/LayoutContentEdit.vue +577 -0
  66. package/src/components/LayoutContentStats.vue +485 -0
  67. package/src/components/LayoutContentTest.vue +799 -0
  68. package/src/components/MdPanel.vue +80 -58
  69. package/src/main.js +8 -0
  70. package/src/plugins/mUI.mjs +58 -71
  71. package/src/schema/tables/apis.mjs +30 -0
  72. package/src/store/mutations.mjs +1 -1
  73. package/srv.mjs +47 -19
  74. package/tableTags.json +1 -1
  75. package/.github/workflows/ci-test.yml +0 -24
  76. package/.vscode/launch.json +0 -18
  77. package/db/wapis/apis/data.mdb +0 -0
  78. package/db/wapis/apis/lock.mdb +0 -0
  79. package/dist/css/app.b5cf2ef5.css +0 -1
  80. package/dist/js/app-legacy.fbfba810.js +0 -1
  81. package/dist/js/app.fbfba810.js +0 -1
  82. package/dist/js/chunk-vendors-legacy.735ec7d6.js +0 -13
  83. package/dist/js/chunk-vendors.735ec7d6.js +0 -13
  84. package/src/plugins/mLang.mjs +0 -250
  85. package/tableTags-web-api.json +0 -1
  86. package/test/all.test.mjs +0 -10
@@ -5,14 +5,14 @@
5
5
  </template>
6
6
 
7
7
  <script>
8
- // import get from 'lodash-es/get.js'
9
- // import find from 'lodash-es/find.js'
10
- // import each from 'lodash-es/each.js'
11
- // import map from 'lodash-es/map.js'
12
- // import size from 'lodash-es/size.js'
13
- // import sortBy from 'lodash-es/sortBy.js'
14
- // import isNumber from 'lodash-es/isNumber.js'
15
- // import cloneDeep from 'lodash-es/cloneDeep.js'
8
+ // import get from 'lodash-es/get.js'
9
+ // import find from 'lodash-es/find.js'
10
+ // import each from 'lodash-es/each.js'
11
+ // import map from 'lodash-es/map.js'
12
+ // import size from 'lodash-es/size.js'
13
+ // import sortBy from 'lodash-es/sortBy.js'
14
+ // import isNumber from 'lodash-es/isNumber.js'
15
+ // import cloneDeep from 'lodash-es/cloneDeep.js'
16
16
  // import sep from 'wsemi/src/sep.mjs'
17
17
  // import isobj from 'wsemi/src/isobj.mjs'
18
18
  // import iseobj from 'wsemi/src/iseobj.mjs'
@@ -73,80 +73,102 @@ export default {
73
73
  </script>
74
74
 
75
75
  <style scoped>
76
+ /* Scalar 風格 markdown 渲染:無外框、細列分隔、等寬欄、名稱欄加粗、標題退場感 */
77
+ .md {
78
+ font-size: 13px;
79
+ color: var(--c-1, #1b1b1b);
80
+ }
76
81
 
77
82
  .md >>> table {
78
83
  border-collapse: collapse;
79
- margin: 0;
80
- padding: 0;
84
+ width: 100%;
85
+ font-size: 13px;
86
+ margin: 2px 0 8px;
81
87
  word-break: initial;
82
88
  }
83
89
 
84
- .md >>> tr {
85
- margin: 0;
86
- padding: 0;
87
- }
88
-
89
90
  .md >>> table tr th {
90
- font-weight: bold;
91
- background: #eee;
92
- border: 1px solid #ddd;
93
- border-bottom: 0;
91
+ text-align: left;
92
+ font-weight: 600;
93
+ font-size: 11.5px;
94
+ letter-spacing: .03em;
95
+ color: var(--c-2, #6b7280);
96
+ background: transparent;
97
+ border: none;
98
+ border-bottom: 1px solid var(--border, #e6e8ec);
94
99
  margin: 0;
95
- padding: 6px 13px;
100
+ padding: 8px 18px 8px 0;
96
101
  }
97
102
 
98
103
  .md >>> table tr td {
99
- border: 1px solid #ddd;
104
+ border: none;
105
+ border-bottom: 1px solid var(--border-soft, #eef0f3);
106
+ color: var(--c-1, #1b1b1b);
107
+ font-family: var(--font-code, ui-monospace, Menlo, Consolas, monospace);
108
+ font-size: 12.5px;
109
+ vertical-align: top;
100
110
  margin: 0;
101
- padding: 6px 13px;
111
+ padding: 8px 18px 8px 0;
112
+ }
113
+
114
+ .md >>> table tbody tr:last-child td {
115
+ border-bottom: none;
102
116
  }
103
117
 
104
- .md >>> h1 {
105
- font-weight: bold;
106
- font-size: 1.2rem;
107
- line-height: 1.2rem;
108
- margin-top: 0.5rem;
109
- margin-bottom: 0.5rem;
118
+ .md >>> table tr td:first-child {
119
+ font-weight: 600;
120
+ color: var(--c-1, #1b1b1b);
110
121
  }
111
122
 
112
- .md >>> h2 {
113
- font-weight: bold;
114
- font-size: 1.1rem;
115
- line-height: 1.1rem;
116
- margin-top: 0.5rem;
117
- margin-bottom: 0.5rem;
123
+ /* 對齊 mockup:型別欄(第2欄)綠字、範例欄(第3欄)灰字 */
124
+ .md >>> table tr td:nth-child(2) {
125
+ color: var(--m-post, #069061);
118
126
  }
119
127
 
120
- .md >>> h3 {
121
- font-weight: bold;
122
- font-size: 1rem;
123
- line-height: 1rem;
124
- margin-top: 0.5rem;
125
- margin-bottom: 0.5rem;
128
+ .md >>> table tr td:nth-child(3) {
129
+ color: var(--c-2, #6b7280);
126
130
  }
127
131
 
128
- .md >>> h4 {
129
- font-weight: bold;
130
- font-size: 1rem;
131
- line-height: 1rem;
132
- margin-top: 0.5rem;
133
- margin-bottom: 0.5rem;
132
+ .md >>> h1,
133
+ .md >>> h2,
134
+ .md >>> h3,
135
+ .md >>> h4,
136
+ .md >>> h5,
137
+ .md >>> h6 {
138
+ font-weight: 600;
139
+ font-size: 13px;
140
+ line-height: 1.4;
141
+ color: var(--c-2, #6b7280);
142
+ margin: 8px 0 6px;
134
143
  }
135
144
 
136
- .md >>> h5 {
137
- font-weight: bold;
138
- font-size: 1rem;
139
- line-height: 1rem;
140
- margin-top: 0.5rem;
141
- margin-bottom: 0.5rem;
145
+ .md >>> p {
146
+ color: var(--c-2, #6b7280);
147
+ line-height: 1.6;
148
+ margin: 4px 0;
142
149
  }
143
150
 
144
- .md >>> h6 {
145
- font-weight: bold;
146
- font-size: 1rem;
147
- line-height: 1rem;
148
- margin-top: 0.5rem;
149
- margin-bottom: 0.5rem;
151
+ .md >>> code {
152
+ font-family: var(--font-code, ui-monospace, Menlo, Consolas, monospace);
153
+ font-size: 12px;
154
+ background: var(--bg-3, #eceef1);
155
+ border-radius: 4px;
156
+ padding: 1px 5px;
157
+ }
158
+
159
+ .md >>> pre {
160
+ font-family: var(--font-code, ui-monospace, Menlo, Consolas, monospace);
161
+ font-size: 12px;
162
+ background: var(--bg-2, #f7f8fa);
163
+ border: 1px solid var(--border, #e6e8ec);
164
+ border-radius: 8px;
165
+ padding: 12px 14px;
166
+ overflow: auto;
167
+ }
168
+
169
+ .md >>> pre code {
170
+ background: transparent;
171
+ padding: 0;
150
172
  }
151
173
 
152
174
  </style>
package/src/main.js CHANGED
@@ -4,6 +4,7 @@ import get from 'lodash-es/get.js'
4
4
  // import 'regenerator-runtime/runtime'
5
5
  // import 'intersection-observer' //需供Vuetify的Intersection Observer, 專案內有使用v-intersect才需引入, 而w-component-vue沒用v-intersect
6
6
  import Vue from 'vue'
7
+ import './assets/scalar-ui.css'
7
8
  import WServHapiClient from 'w-serv-hapi/src/WServHapiClient.mjs'
8
9
  import WAlert from 'w-component-vue/src/components/WAlert.mjs'
9
10
  import domMutation from 'w-component-vue/src/js/domMutation.mjs'
@@ -37,6 +38,13 @@ let dssm = mDataSelectorSchema(ds)
37
38
  //prototype
38
39
  Vue.prototype.$ui = ui
39
40
  Vue.prototype.$t = ui.getKpText
41
+ //$transErr:後端 reject 之 err-key → 依當前 lang 反查顯示文字。
42
+ //非字串或查無對應 key(getKpText 查不到會原樣回 key)則 fallback 'anUnexpectedErrorOccurred',避免顯示生 key。
43
+ Vue.prototype.$transErr = (err) => {
44
+ let key = (typeof err === 'string' && err) ? err : 'anUnexpectedErrorOccurred'
45
+ let msg = ui.getKpText(key)
46
+ return (msg && msg !== key) ? msg : ui.getKpText('anUnexpectedErrorOccurred')
47
+ }
40
48
  Vue.prototype.$s = s
41
49
  Vue.prototype.$dssm = dssm
42
50
  Vue.prototype.$ds = ds
@@ -42,7 +42,30 @@ import replace from 'wsemi/src/replace.mjs'
42
42
  import timemsTZ2past from 'wsemi/src/timemsTZ2past.mjs'
43
43
  import convertToTree from 'wsemi/src/convertToTree.mjs'
44
44
  // import WUiDwload from 'w-ui-dwload/src/WUiDwload.mjs'
45
- import kpLang from './mLang.mjs'
45
+
46
+
47
+ let kpFallback = {
48
+ csIng: {
49
+ eng: 'Connecting...',
50
+ cht: '連線中...',
51
+ },
52
+ csLogin: {
53
+ eng: 'Logged in',
54
+ cht: '已登入',
55
+ },
56
+ csLogout: {
57
+ eng: 'Logged out',
58
+ cht: '已登出',
59
+ },
60
+ csErrConn: {
61
+ eng: 'Unable to connect',
62
+ cht: '無法連線',
63
+ },
64
+ csErrLogin: {
65
+ eng: 'Login denied',
66
+ cht: '拒絕登入',
67
+ },
68
+ }
46
69
 
47
70
 
48
71
  let vo = Vue.prototype
@@ -109,16 +132,31 @@ function validLang(lang) {
109
132
  function getLang() {
110
133
  let lang = ''
111
134
 
112
- //from window
135
+ //from URL ?lang=(最高優先;供「以指定語系載入初始畫面」用,如分享連結 /?lang=cht,對齊 w-web-sso getLang)
136
+ if (!isestr(lang)) {
137
+ let _lang = ''
138
+ try {
139
+ _lang = new URLSearchParams(get(window, 'location.search', '')).get('lang') || ''
140
+ }
141
+ catch (err) {
142
+ _lang = ''
143
+ }
144
+ if (isestr(_lang)) {
145
+ lang = validLang(_lang) //URL 帶非預期 lang 時 validLang 退回 eng
146
+ }
147
+ }
148
+
149
+ //from window ___pmwperm___.language(server 注入之初始語系;對齊 w-web-sso window 注入來源)。
150
+ //須在 store 之前:store.state.lang 預設為非空 'eng'(mutations.mjs),若 store 在前會永遠 shadow 掉 window 注入值。
151
+ //dev 未注入時為模板符號 {language} → validLang 退回 eng。
113
152
  if (!isestr(lang)) {
114
153
  let _lang = get(window, '___pmwperm___.language', '')
115
- // console.log('_lang(from window)', _lang)
116
154
  if (isestr(_lang)) {
117
- lang = validLang(_lang) //有可能取到未取代前模板符號
155
+ lang = validLang(_lang)
118
156
  }
119
157
  }
120
158
 
121
- //from store
159
+ //from store(使用者執行期切換之語系;切換以 setLang(明確值) 直接寫入、其後無 setLang(null) 故能持久)
122
160
  if (!isestr(lang)) {
123
161
  let _lang = get(vo, '$store.state.lang', '')
124
162
  // console.log('_lang(from store)', _lang)
@@ -127,10 +165,9 @@ function getLang() {
127
165
  }
128
166
  }
129
167
 
130
- //return
131
- if (!isestr(lang)) {
132
- return 'eng'
133
- }
168
+ //validLang
169
+ lang = validLang(lang) //有可能給予非預期lang
170
+
134
171
  return lang
135
172
  }
136
173
 
@@ -142,87 +179,32 @@ function setLang(lang = null, from = '') {
142
179
  if (!isestr(lang)) {
143
180
  lang = getLang()
144
181
  }
145
- else {
146
- lang = validLang(lang)
147
- }
182
+ lang = validLang(lang)
148
183
  // console.log('get lang', lang)
149
184
 
150
185
  //check, 若有變更才commit
151
186
  if (true) {
152
- let _lang = get(vo, '$store.state.lang')
187
+ let _lang = get(vo, '$store.state.lang', '')
153
188
  if (lang !== _lang) {
154
189
  vo.$store.commit(vo.$store.types.UpdateLang, lang)
155
190
  // console.log('commit lang', lang)
156
191
  }
157
192
  }
158
193
 
159
- //genKpText, 切換lang得調用getKpLang重算kpText
160
- genKpText(lang)
161
-
162
- //forceUpdate
163
- forceUpdate()
164
-
165
- }
166
-
167
-
168
- function genKpText(lang) {
169
- // console.log('genKpText', lang)
170
-
171
- //kp
172
- let kp = {}
173
-
174
194
  //kpLang
175
- kp = {
176
- ...kp,
177
- ...kpLang,
178
- }
179
-
180
- //kpLangExt
181
- let kpLangExt = get(vo, '$store.state.webInfor.kpLangExt', {})
182
- // console.log('kpLangExt', kpLangExt)
183
- if (iseobj(kpLangExt)) {
184
- kp = {
185
- ...kp,
186
- ...kpLangExt,
187
- }
188
- }
189
-
190
- //webName
191
- let webName = get(vo, '$store.state.webInfor.webName', {})
192
- // console.log('webName', webName)
193
- if (iseobj(webName)) {
194
- kp = {
195
- ...kp,
196
- webName: {
197
- ...webName,
198
- },
199
- }
200
- }
201
-
202
- //webDescription
203
- let webDescription = get(vo, '$store.state.webInfor.webDescription', {})
204
- // console.log('webDescription', webDescription)
205
- if (iseobj(webDescription)) {
206
- kp = {
207
- ...kp,
208
- webDescription: {
209
- ...webDescription,
210
- },
211
- }
212
- }
195
+ let kpLang = get(vo, '$store.state.webInfor.kpLang', {})
213
196
 
214
197
  //kpText
215
- let kpText = {}
216
- each(kp, (v, k) => {
217
- kpText[k] = v[lang]
218
- })
219
- // console.log('kp', kp)
198
+ let kpText = get(kpLang, lang, {})
220
199
  // console.log('kpText', kpText)
221
200
 
222
201
  //commit
223
202
  vo.$store.commit(vo.$store.types.UpdateKpText, kpText)
224
203
  // console.log('commit kpText', kpText)
225
204
 
205
+ //forceUpdate
206
+ forceUpdate()
207
+
226
208
  }
227
209
 
228
210
 
@@ -235,6 +217,11 @@ function getKpText(key) {
235
217
 
236
218
  //t
237
219
  let t = get(kpText, key, '')
220
+ if (!isestr(t)) {
221
+ // fallback: 後端語系尚未載入時使用預設值
222
+ let lang = getLang()
223
+ t = get(kpFallback, `${key}.${lang}`, '')
224
+ }
238
225
  if (!isestr(t)) {
239
226
  t = key
240
227
  }
@@ -86,6 +86,34 @@ let settings = {
86
86
  name: '輸出範例',
87
87
  type: 'STRING',
88
88
  },
89
+ 'testBaseUrl': {
90
+ name: '測試基底網址',
91
+ type: 'STRING',
92
+ },
93
+ 'authType': {
94
+ name: '認證類型',
95
+ type: 'STRING',
96
+ },
97
+ 'authConfigJson': {
98
+ name: '認證設定JSON',
99
+ type: 'TEXT',
100
+ },
101
+ 'defaultHeadersJson': {
102
+ name: '預設標頭JSON',
103
+ type: 'TEXT',
104
+ },
105
+ 'defaultQueryJson': {
106
+ name: '預設查詢參數JSON',
107
+ type: 'TEXT',
108
+ },
109
+ 'defaultBodyJson': {
110
+ name: '預設請求內容JSON',
111
+ type: 'TEXT',
112
+ },
113
+ 'contentType': {
114
+ name: '內容類型',
115
+ type: 'STRING',
116
+ },
89
117
  'timeCreate': {
90
118
  name: '創建時間',
91
119
  type: 'STRING',
@@ -106,6 +134,8 @@ let funNew = (ndata = {}) => {
106
134
  o.timeCreate = nowms2str()
107
135
  o.timeUpdate = o.timeCreate
108
136
  o.isActive = 'y'
137
+ o.authType = isestr(o.authType) ? o.authType : 'none'
138
+ o.contentType = isestr(o.contentType) ? o.contentType : 'application/json'
109
139
  return o
110
140
  }
111
141
 
@@ -31,7 +31,7 @@ let state = {
31
31
  isAdmin: 'n',
32
32
  },
33
33
 
34
- lang: 'cht', //'eng', 'cht'
34
+ lang: 'eng', //'eng', 'cht'
35
35
  kpText: {}, //一定要放在vuex內, 否則無法用broadcast驅動變更語系文字
36
36
 
37
37
  }
package/srv.mjs CHANGED
@@ -1,22 +1,44 @@
1
1
  import WOrm from 'w-orm-lmdb/src/WOrmLmdb.mjs'
2
2
  import WWebApi from './server/WWebApi.mjs'
3
3
  import getSettings from './g.getSettings.mjs'
4
+ import get from 'lodash-es/get.js'
5
+ import iseobj from 'wsemi/src/iseobj.mjs'
6
+ import axios from 'axios'
7
+ import JSON5 from 'json5'
8
+ import fs from 'fs'
4
9
 
5
10
 
6
- //st
11
+ //st(db 等系統參數由 g.getSettings 提供,供 g.mOrm 共用)
7
12
  let st = getSettings()
8
13
 
14
+ //pathSettings:app 設定檔路徑,預設 ./settings.json;可由 `node srv.mjs <path>` 覆寫
15
+ //(供 e2e restartBackend / 部署帶不同設定,日後更細緻功能便於擴充)。settings.json 為 JSON5 格式。
16
+ let pathSettings = process.argv[2] || './settings.json'
17
+ let stApp = JSON5.parse(fs.readFileSync(pathSettings, 'utf8'))
18
+
9
19
  let url = st.dbUrl
10
20
  let db = st.dbName
21
+ let ssoBaseUrl = st.ssoBaseUrl
22
+ let ssoAppToken = st.ssoAppToken
23
+ let ssoLoginUrl = st.ssoLoginUrl
11
24
  let opt = {
12
25
 
13
26
  useCheckUser: false,
14
27
  getUserById: null,
15
28
  useExcludeWhenNotAdmin: false,
16
29
 
17
- serverPort: 11005,
30
+ serverPort: get(stApp, 'serverPort', 11005),
18
31
  subfolder: '', //mapi
19
- urlRedirect: 'https://www.google.com/', //本機測試時得先編譯, 再瀏覽: http://localhost:11005/
32
+ urlRedirect: ssoLoginUrl, //未登入時導向SSO登入頁, 本機測試時得先編譯, 再瀏覽: http://localhost:11005/
33
+
34
+ //語系(來自 settings.json):language 由 WWebApi 注入 index.html ({language}) → 初始畫面即此語系;
35
+ //showLanguage 控右上語系選單顯隱。e2e 可用 restartBackend(genTempSettings({language})) 改 server 初始語系。
36
+ showLanguage: get(stApp, 'showLanguage', 'y'),
37
+ language: get(stApp, 'language', 'eng'),
38
+
39
+ //log 資料夾與輪檔間隔(srLog 寫入 + staEvent 統計皆讀此)。e2e 可用 genTempSettings({logFd}) 指向合成 log 達 hermetic。
40
+ logFd: get(stApp, 'logFd', './_logs'),
41
+ logInterval: get(stApp, 'logInterval', 'hr'),
20
42
 
21
43
  webName: {
22
44
  'eng': 'API Service',
@@ -32,25 +54,31 @@ let opt = {
32
54
 
33
55
  let getUserByToken = async (token) => {
34
56
  // return {} //測試無法登入
35
- if (token === '{token-for-application}') { //提供外部應用系統作為存取使用者
36
- return {
37
- id: 'id-for-application',
38
- name: 'application',
39
- email: 'application@example.com',
40
- isAdmin: 'y',
41
- }
57
+ //開發階段 w-ui-loginout localhost 自動給 token 'sys'
58
+ if (token === 'sys') {
59
+ return { id: 'id-for-admin', name: '測試者', email: 'admin@example.com', isAdmin: 'y' }
60
+ }
61
+ //未設定 SSO app token 時(本機開發未接SSO), 不打SSO直接拒絕
62
+ if (!ssoAppToken) {
63
+ console.log('ssoAppToken 未設定, 略過 SSO 驗證')
64
+ return {}
42
65
  }
43
- if (token === 'sys') { //開發階段w-ui-loginout自動給予browser使用者(且位於localhost)的token為sys
44
- return {
45
- id: 'id-for-admin',
46
- name: '測試者',
47
- email: 'admin@example.com',
48
- isAdmin: 'y',
66
+ //呼叫 SSO 解析 token -> user
67
+ try {
68
+ let url = `${ssoBaseUrl}/api/getSsoUserInfor?token=${encodeURIComponent(ssoAppToken)}&key=token&value=${encodeURIComponent(token)}`
69
+ let res = await axios.get(url)
70
+ let state = get(res, 'data.state', '')
71
+ let u = get(res, 'data.msg', null)
72
+ if (state !== 'success' || !iseobj(u)) {
73
+ console.log('SSO getSsoUserInfor 失敗', state)
74
+ return {}
49
75
  }
76
+ return { id: u.id, name: u.name, email: u.email, isAdmin: u.isAdmin }
77
+ }
78
+ catch (err) {
79
+ console.log('SSO getSsoUserInfor error', err.message)
80
+ return {}
50
81
  }
51
- console.log('invalid token', token)
52
- console.log('於生產環境時得加入SSO等驗證token機制')
53
- return {}
54
82
  }
55
83
 
56
84
  let verifyClientUser = (user, from) => {
package/tableTags.json CHANGED
@@ -1 +1 @@
1
- {"apis":"2025-07-20T22:07:21+08:00|DSiCoa"}
1
+ {"apis":"2026-06-22T12:43:06+08:00|Yl6xfX"}
@@ -1,24 +0,0 @@
1
- name: Node.js CI
2
-
3
- on: [push]
4
-
5
- jobs:
6
- build:
7
-
8
- runs-on: ubuntu-latest
9
-
10
- strategy:
11
- matrix:
12
- node-version: [22.x]
13
-
14
- steps:
15
- - uses: actions/checkout@v2
16
- - name: Use Node.js ${{ matrix.node-version }}
17
- uses: actions/setup-node@v1
18
- with:
19
- node-version: ${{ matrix.node-version }}
20
- - run: npm cache clean -f
21
- - run: npm install
22
- - run: npm test
23
- env:
24
- CI: true
@@ -1,18 +0,0 @@
1
- {
2
- // 使用 IntelliSense 以得知可用的屬性。
3
- // 暫留以檢視現有屬性的描述。
4
- // 如需詳細資訊,請瀏覽: https://go.microsoft.com/fwlink/?linkid=830387
5
- "version": "0.2.0",
6
- "configurations": [
7
- {
8
- "type": "node",
9
- "request": "launch",
10
- "name": "啟動程式",
11
- "skipFiles": [
12
- "<node_internals>/**"
13
- ],
14
- "program": "${workspaceFolder}/srv.mjs",
15
- "runtimeArgs": []
16
- }
17
- ]
18
- }
Binary file
Binary file
@@ -1 +0,0 @@
1
- .pgc-rotate[data-v-5b4e8bee]{width:100%;height:100%;margin:auto;position:absolute;top:0;bottom:0;left:0;right:0;z-index:1;-webkit-transition:all .6s ease-in-out;transition:all .6s ease-in-out;-webkit-animation:progress-circular-rotate-5b4e8bee 1.4s linear infinite;animation:progress-circular-rotate-5b4e8bee 1.4s linear infinite;-webkit-transform-origin:center center;transform-origin:center center}.pgc-dash[data-v-5b4e8bee]{-webkit-animation:progress-circular-dash-5b4e8bee 1.4s ease-in-out infinite;animation:progress-circular-dash-5b4e8bee 1.4s ease-in-out infinite;stroke-linecap:round;stroke-dasharray:80,200;stroke-dashoffset:0px}@-webkit-keyframes progress-circular-dash-5b4e8bee{0%{stroke-dasharray:1,200;stroke-dashoffset:0px}50%{stroke-dasharray:100,200;stroke-dashoffset:-15px}to{stroke-dasharray:100,200;stroke-dashoffset:-124px}}@keyframes progress-circular-dash-5b4e8bee{0%{stroke-dasharray:1,200;stroke-dashoffset:0px}50%{stroke-dasharray:100,200;stroke-dashoffset:-15px}to{stroke-dasharray:100,200;stroke-dashoffset:-124px}}@-webkit-keyframes progress-circular-rotate-5b4e8bee{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes progress-circular-rotate-5b4e8bee{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.WPopperFix[data-popper-reference-hidden][data-v-14d6bcb4]{visibility:hidden;pointer-events:none}.sb[data-v-6ce5bdb1]{-webkit-transition:opacity .3s;transition:opacity .3s;scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.3) transparent}.sb[data-v-6ce5bdb1]::-webkit-scrollbar{width:8px;height:8px}.sb[data-v-6ce5bdb1]::-webkit-scrollbar-track{background:transparent}.sb[data-v-6ce5bdb1]::-webkit-scrollbar-thumb{background:rgba(0,0,0,.3);border-radius:20px;border:3px solid transparent}.ts[data-v-9a483320]{-webkit-transition:all .3s cubic-bezier(.25,.8,.5,1);transition:all .3s cubic-bezier(.25,.8,.5,1)}.bs[data-v-9a483320]{-webkit-box-shadow:0 8px 2px -8px rgba(0,0,0,.3),0 16px 24px 2px rgba(0,0,0,.3),0 6px 30px 5px rgba(0,0,0,.3);box-shadow:0 8px 2px -8px rgba(0,0,0,.3),0 16px 24px 2px rgba(0,0,0,.3),0 6px 30px 5px rgba(0,0,0,.3)}.fade-enter-active[data-v-a0c94508],.fade-leave-active[data-v-a0c94508]{-webkit-transition:all .3s;transition:all .3s}.fade-enter[data-v-a0c94508],.fade-leave-to[data-v-a0c94508]{-webkit-transform:scaleX(0);transform:scaleX(0)}.fade-enter-to[data-v-a0c94508],.fade-leave[data-v-a0c94508]{-webkit-transform:scaleX(100%);transform:scaleX(100%)}.caretRight[data-v-26dfca3e]{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:inline-block}.cc[data-v-26dfca3e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.circle[data-v-26dfca3e]{width:22px;height:22px;min-width:22px;min-height:22px;max-width:22px;max-height:22px;border-radius:50%}.md[data-v-1a0f86f5] table{border-collapse:collapse;margin:0;padding:0;word-break:normal}.md[data-v-1a0f86f5] tr{margin:0;padding:0}.md[data-v-1a0f86f5] table tr th{font-weight:700;background:#eee;border:1px solid #ddd;border-bottom:0;margin:0;padding:6px 13px}.md[data-v-1a0f86f5] table tr td{border:1px solid #ddd;margin:0;padding:6px 13px}.md[data-v-1a0f86f5] h1{font-size:1.2rem;line-height:1.2rem}.md[data-v-1a0f86f5] h1,.md[data-v-1a0f86f5] h2{font-weight:700;margin-top:.5rem;margin-bottom:.5rem}.md[data-v-1a0f86f5] h2{font-size:1.1rem;line-height:1.1rem}.md[data-v-1a0f86f5] h3,.md[data-v-1a0f86f5] h4,.md[data-v-1a0f86f5] h5,.md[data-v-1a0f86f5] h6{font-weight:700;font-size:1rem;line-height:1rem;margin-top:.5rem;margin-bottom:.5rem}.bk[data-v-56f2385e]{display:inline-block;width:200px;padding:0 10px 10px 0;vertical-align:top}.bk-title[data-v-56f2385e]{padding:3px;font-size:.8rem;color:#888}.bk-item[data-v-56f2385e]{padding:3px 5px;font-size:.9rem;line-height:.9rem;border-radius:5px;border:1px solid #ddd;background:#fff}body,html{font-family:微軟正黑體,Microsoft JhengHei,MicrosoftJhengHeiRegular,Avenir,Helvetica,Arial,sans-serif;overflow-y:hidden}a,button,div,input,p,pre,span,textarea{font-family:inherit}.fade-enter-active{-webkit-animation:go 1s;animation:go 1s}.fade-leave-active{-webkit-animation:back 1s;animation:back 1s}@-webkit-keyframes go{0%{opacity:0}to{opacity:1}}@keyframes go{0%{opacity:0}to{opacity:1}}@-webkit-keyframes back{0%{opacity:1}to{opacity:0}}@keyframes back{0%{opacity:1}to{opacity:0}}