w-web-perm 1.0.47 → 1.0.49

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 (96) hide show
  1. package/.github/workflows/ci-test.yml +2 -2
  2. package/_gh-pages-deploy/.nojekyll +0 -0
  3. package/_gh-pages-deploy/WWebPerm.html +938 -0
  4. package/_gh-pages-deploy/WWebPerm.mjs.html +1228 -0
  5. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  6. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  7. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  8. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  9. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  10. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  11. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  12. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  13. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  14. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  15. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  16. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  17. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  18. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  19. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  20. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  21. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  22. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  23. package/_gh-pages-deploy/index.html +84 -0
  24. package/_gh-pages-deploy/scripts/collapse.js +39 -0
  25. package/_gh-pages-deploy/scripts/commonNav.js +28 -0
  26. package/_gh-pages-deploy/scripts/linenumber.js +25 -0
  27. package/_gh-pages-deploy/scripts/nav.js +12 -0
  28. package/_gh-pages-deploy/scripts/polyfill.js +4 -0
  29. package/_gh-pages-deploy/scripts/prettify/Apache-License-2.0.txt +202 -0
  30. package/_gh-pages-deploy/scripts/prettify/lang-css.js +2 -0
  31. package/_gh-pages-deploy/scripts/prettify/prettify.js +28 -0
  32. package/_gh-pages-deploy/scripts/search.js +99 -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.d8b16216.css +1 -0
  36. package/dist/css/{chunk-vendors.f149e124.css → chunk-vendors.2d3ef2ba.css} +1 -1
  37. package/dist/index.tmp +2 -2
  38. package/dist/js/app-legacy.fb48310a.js +1 -0
  39. package/dist/js/app.fb48310a.js +1 -0
  40. package/dist/js/chunk-vendors-legacy.8fdd4435.js +21 -0
  41. package/dist/js/chunk-vendors.8fdd4435.js +21 -0
  42. package/dist/w-web-perm.umd.js +2 -2
  43. package/dist/w-web-perm.umd.js.map +1 -1
  44. package/docs/WWebPerm.html +2 -2
  45. package/docs/WWebPerm.mjs.html +138 -199
  46. package/docs/index.html +1 -1
  47. package/package.json +15 -11
  48. package/public/index.html +2 -2
  49. package/server/WWebPerm.mjs +137 -198
  50. package/server/procCore.mjs +169 -0
  51. package/server/procLang.mjs +197 -0
  52. package/server/procStaInfor.mjs +118 -0
  53. package/server/provideTabs.mjs +1 -1
  54. package/server/srLog.mjs +30 -0
  55. package/server/staLogs/staEvent.callWorker.mjs +46 -0
  56. package/server/staLogs/staEvent.mjs +116 -0
  57. package/server/staLogs/staEvent.shellWorker.mjs +19 -0
  58. package/server/staLogs/staEventTable.mjs +100 -0
  59. package/server/staLogs/test_staEvent.mjs +22 -0
  60. package/settings.json +40 -0
  61. package/src/components/Common/CheckYes.vue +18 -1
  62. package/src/components/Layout.vue +1 -1
  63. package/src/components/LayoutContent.vue +13 -1
  64. package/src/components/LayoutContentGrups.vue +48 -24
  65. package/src/components/LayoutContentPemis.vue +48 -24
  66. package/src/components/LayoutContentStaInfor.vue +536 -0
  67. package/src/components/LayoutContentTargets.vue +48 -24
  68. package/src/components/LayoutContentUsers.vue +48 -24
  69. package/src/components/LayoutState.vue +5 -0
  70. package/src/components/VeCgrups.vue +62 -20
  71. package/src/components/VeCpemis.vue +62 -20
  72. package/src/components/VeCrules.vue +58 -16
  73. package/src/components/VeGrupBlngUsers.vue +77 -32
  74. package/src/components/VePemiBlngGrups.vue +77 -32
  75. package/src/getPerm.mjs +7 -17
  76. package/src/getPermUserInfor.mjs +8 -18
  77. package/src/main.js +1 -0
  78. package/src/plugins/mShare.mjs +8 -13
  79. package/src/plugins/mUI.mjs +15 -7
  80. package/src/store/mutations.mjs +1 -1
  81. package/srv.mjs +76 -101
  82. package/tableTags.json +1 -1
  83. package/db/wperm/grups/data.mdb +0 -0
  84. package/db/wperm/grups/lock.mdb +0 -0
  85. package/db/wperm/pemis/data.mdb +0 -0
  86. package/db/wperm/pemis/lock.mdb +0 -0
  87. package/db/wperm/targets/data.mdb +0 -0
  88. package/db/wperm/targets/lock.mdb +0 -0
  89. package/db/wperm/users/data.mdb +0 -0
  90. package/db/wperm/users/lock.mdb +0 -0
  91. package/dist/css/app.30e81bfe.css +0 -1
  92. package/dist/js/app-legacy.f1277a07.js +0 -1
  93. package/dist/js/app.f1277a07.js +0 -1
  94. package/dist/js/chunk-vendors-legacy.e8703728.js +0 -21
  95. package/dist/js/chunk-vendors.e8703728.js +0 -21
  96. package/test/getUserRules.test.mjs +0 -899
@@ -128,34 +128,40 @@
128
128
 
129
129
  </div>
130
130
 
131
- <template v-if="items">
132
- <WAggridVue
133
- ref="rftable"
134
- :style="`width:100%;`"
135
- :height="contentHeight"
136
- :opt="opt"
137
- >
138
- <template v-slot:cell-render="props">
139
- <template v-if="props.key==='grupsNames'">
140
- <span v-for="(item, idx) in props.row.grups" :key="idx" style="display:inline-block; line-height:20px; height:20px;">
141
- <div style="display:flex;">
142
- <div :style="'padding:0px 5px; border-top-left-radius:4px; border-bottom-left-radius:4px; ' + (item.enable === 'y' ? 'border-left:1px solid #ac2451; border-right:1px solid #9e2149; border-top:1px solid #ac2451; border-bottom:1px solid #ac2451; background:#be295a; color:#fff;' : 'border-left:1px solid #aaaaaa; border-right:1px solid #aaaaaa; border-top:1px solid #aaaaaa; border-bottom:1px solid #aaaaaa; background:#ffffff; color:#555;')">
143
- {{ item.mode }}
144
- </div>
145
- <div :style="'padding:0px 5px; border-top-right-radius:4px; border-bottom-right-radius:4px; ' + (item.enable === 'y' ? '_border-left:1px solid #ac2451; border-right:1px solid #ac2451; border-top:1px solid #ac2451; border-bottom:1px solid #ac2451; background:#d22f64; color:#fff;' : '_border-left:1px solid #aaaaaa; border-right:1px solid #aaaaaa; border-top:1px solid #aaaaaa; border-bottom:1px solid #aaaaaa; background:#eeeeee; color:#555;')">
146
- {{ item.name }}
131
+ <template
132
+ v-if="!firstLoading"
133
+ >
134
+
135
+ <template v-if="items">
136
+ <WAggridVue
137
+ ref="rftable"
138
+ :style="`width:100%;`"
139
+ :height="contentHeight"
140
+ :opt="opt"
141
+ >
142
+ <template v-slot:cell-render="props">
143
+ <template v-if="props.key==='grupsNames'">
144
+ <span v-for="(item, idx) in props.row.grups" :key="idx" style="display:inline-block; line-height:20px; height:20px;">
145
+ <div style="display:flex;">
146
+ <div :style="'padding:0px 5px; border-top-left-radius:4px; border-bottom-left-radius:4px; ' + (item.enable === 'y' ? 'border-left:1px solid #ac2451; border-right:1px solid #9e2149; border-top:1px solid #ac2451; border-bottom:1px solid #ac2451; background:#be295a; color:#fff;' : 'border-left:1px solid #aaaaaa; border-right:1px solid #aaaaaa; border-top:1px solid #aaaaaa; border-bottom:1px solid #aaaaaa; background:#ffffff; color:#555;')">
147
+ {{ item.mode }}
148
+ </div>
149
+ <div :style="'padding:0px 5px; border-top-right-radius:4px; border-bottom-right-radius:4px; ' + (item.enable === 'y' ? '_border-left:1px solid #ac2451; border-right:1px solid #ac2451; border-top:1px solid #ac2451; border-bottom:1px solid #ac2451; background:#d22f64; color:#fff;' : '_border-left:1px solid #aaaaaa; border-right:1px solid #aaaaaa; border-top:1px solid #aaaaaa; border-bottom:1px solid #aaaaaa; background:#eeeeee; color:#555;')">
150
+ {{ item.name }}
151
+ </div>
147
152
  </div>
148
- </div>
149
- </span>
153
+ </span>
154
+ </template>
155
+ <select v-else-if="props.key==='mode'" @change="showVeGrupBlngUsersToggleItemModeByName(props.row.name, $event.target.value)" :disabled="!isEditable">
156
+ <option value="OR" :selected="props.row.mode === 'OR'">OR</option>
157
+ <option value="AND" :selected="props.row.mode === 'AND'">AND</option>
158
+ </select>
159
+ <input v-else-if="props.key==='enable'" type="checkbox" :checked="props.value === 'y'" @click="showVeGrupBlngUsersToggleItemEnableByName(props.row.name)" :disabled="!isEditable" />
160
+ <span v-else>{{ props.value }}</span>
150
161
  </template>
151
- <select v-else-if="props.key==='mode'" @change="showVeGrupBlngUsersToggleItemModeByName(props.row.name, $event.target.value)" :disabled="!isEditable">
152
- <option value="OR" :selected="props.row.mode === 'OR'">OR</option>
153
- <option value="AND" :selected="props.row.mode === 'AND'">AND</option>
154
- </select>
155
- <input v-else-if="props.key==='enable'" type="checkbox" :checked="props.value === 'y'" @click="showVeGrupBlngUsersToggleItemEnableByName(props.row.name)" :disabled="!isEditable" />
156
- <span v-else>{{ props.value }}</span>
157
- </template>
158
- </WAggridVue>
162
+ </WAggridVue>
163
+ </template>
164
+
159
165
  </template>
160
166
 
161
167
  <div
@@ -223,6 +229,8 @@ export default {
223
229
  panelHeight: 100,
224
230
  headHeight: 100,
225
231
 
232
+ firstLoading: true,
233
+ firstSetting: true,
226
234
  isEditable: false,
227
235
  isModified: false,
228
236
 
@@ -244,9 +252,26 @@ export default {
244
252
  Vue.prototype.$dg.showVeGrupBlngUsersToggleItemModeByName = vo.showVeGrupBlngUsersToggleItemModeByName
245
253
  Vue.prototype.$dg.showVeGrupBlngUsersToggleItemEnableByName = vo.showVeGrupBlngUsersToggleItemEnableByName
246
254
 
255
+ //firstSetting
256
+ if (vo.firstSetting) {
257
+ // console.log('webInfor', vo.webInfor)
258
+
259
+ //會觸發數據變更再導致opt變更導致觸發rowsChange等事件, 故得要延遲, 供組件偵測初始設定數據初始化之用
260
+ setTimeout(() => {
261
+ vo.firstSetting = false
262
+ // console.log('firstSetting', vo.firstSetting)
263
+ }, 1)
264
+
265
+ }
266
+
247
267
  },
248
268
  computed: {
249
269
 
270
+ syncState: function() {
271
+ let vo = this
272
+ return get(vo, '$store.state.syncState')
273
+ },
274
+
250
275
  targets: function() {
251
276
  let rs = get(this, `$store.state.targets`)
252
277
  rs = sortBy(rs, 'order')
@@ -434,6 +459,11 @@ export default {
434
459
  // console.log('rowsChange', rs)
435
460
  // console.log('rowsChange cloneDeep(vo.opt.rows)', cloneDeep(vo.opt.rows))
436
461
 
462
+ //check
463
+ if (!vo.syncState || vo.firstLoading || vo.firstSetting) {
464
+ return
465
+ }
466
+
437
467
  //isModified
438
468
  vo.isModified = true
439
469
 
@@ -935,7 +965,8 @@ export default {
935
965
 
936
966
  //check
937
967
  if (size(rows) === 0) {
938
- vo.$alert(`${vo.$t('userSaveUsersEmpty')}`, { type: 'error' })
968
+ vo.$ui.updateLoading(false) //showCheckYes 前關 loading(modal 阻斷、避免 clickSave 包裝層 loading 疊在 modal 後)
969
+ await vo.$dg.showCheckYes(`${vo.$t('userSaveUsersEmpty')}`)
939
970
  return
940
971
  }
941
972
 
@@ -947,12 +978,14 @@ export default {
947
978
 
948
979
  //check
949
980
  if (errTemp !== null) {
950
- vo.$alert(`${vo.$t('userSaveUsersFail')}: ${errTemp}`, { type: 'error' })
981
+ vo.$ui.updateLoading(false)
982
+ await vo.$dg.showCheckYes(`${vo.$t('userSaveUsersFail')}: ${vo.$tErr(errTemp)}`)
951
983
  return
952
984
  }
953
985
 
954
986
  //alert
955
- vo.$alert(vo.$t('userSaveUsersSuccess'))
987
+ vo.$ui.updateLoading(false)
988
+ await vo.$dg.showCheckYes(vo.$t('userSaveUsersSuccess'), { type: 'success' })
956
989
 
957
990
  },
958
991
 
@@ -976,6 +1009,18 @@ export default {
976
1009
 
977
1010
  let vo = this
978
1011
 
1012
+ //save按鈕第一行立刻釋放視覺鎖
1013
+ msg.pm.resolve()
1014
+
1015
+ //fire-and-forget, 不 await
1016
+ vo.doSave()
1017
+
1018
+ },
1019
+
1020
+ doSave: function() {
1021
+
1022
+ let vo = this
1023
+
979
1024
  async function core() {
980
1025
 
981
1026
  //show loading
@@ -1057,9 +1102,6 @@ export default {
1057
1102
  .catch(() => { })
1058
1103
  .finally(() => {
1059
1104
 
1060
- //save按鈕解除loading
1061
- msg.pm.resolve()
1062
-
1063
1105
  //hide loading
1064
1106
  vo.$ui.updateLoading(false)
1065
1107
 
@@ -1112,6 +1154,9 @@ export default {
1112
1154
  //genOpt
1113
1155
  vo.genOpt()
1114
1156
 
1157
+ //firstLoading
1158
+ vo.firstLoading = false
1159
+
1115
1160
  //bShow
1116
1161
  vo.bShow = true
1117
1162
 
@@ -128,34 +128,40 @@
128
128
 
129
129
  </div>
130
130
 
131
- <template v-if="items">
132
- <WAggridVue
133
- ref="rftable"
134
- :style="`width:100%;`"
135
- :height="contentHeight"
136
- :opt="opt"
137
- >
138
- <template v-slot:cell-render="props">
139
- <template v-if="props.key==='pemisNames'">
140
- <span v-for="(item, idx) in props.row.pemis" :key="idx" style="display:inline-block; line-height:20px; height:20px;">
141
- <div style="display:flex;">
142
- <div :style="'padding:0px 5px; border-top-left-radius:4px; border-bottom-left-radius:4px; ' + (item.enable === 'y' ? 'border-left:1px solid #ac2451; border-right:1px solid #9e2149; border-top:1px solid #ac2451; border-bottom:1px solid #ac2451; background:#be295a; color:#fff;' : 'border-left:1px solid #aaaaaa; border-right:1px solid #aaaaaa; border-top:1px solid #aaaaaa; border-bottom:1px solid #aaaaaa; background:#ffffff; color:#555;')">
143
- {{ item.mode }}
144
- </div>
145
- <div :style="'padding:0px 5px; border-top-right-radius:4px; border-bottom-right-radius:4px; ' + (item.enable === 'y' ? '_border-left:1px solid #ac2451; border-right:1px solid #ac2451; border-top:1px solid #ac2451; border-bottom:1px solid #ac2451; background:#d22f64; color:#fff;' : '_border-left:1px solid #aaaaaa; border-right:1px solid #aaaaaa; border-top:1px solid #aaaaaa; border-bottom:1px solid #aaaaaa; background:#eeeeee; color:#555;')">
146
- {{ item.name }}
131
+ <template
132
+ v-if="!firstLoading"
133
+ >
134
+
135
+ <template v-if="items">
136
+ <WAggridVue
137
+ ref="rftable"
138
+ :style="`width:100%;`"
139
+ :height="contentHeight"
140
+ :opt="opt"
141
+ >
142
+ <template v-slot:cell-render="props">
143
+ <template v-if="props.key==='pemisNames'">
144
+ <span v-for="(item, idx) in props.row.pemis" :key="idx" style="display:inline-block; line-height:20px; height:20px;">
145
+ <div style="display:flex;">
146
+ <div :style="'padding:0px 5px; border-top-left-radius:4px; border-bottom-left-radius:4px; ' + (item.enable === 'y' ? 'border-left:1px solid #ac2451; border-right:1px solid #9e2149; border-top:1px solid #ac2451; border-bottom:1px solid #ac2451; background:#be295a; color:#fff;' : 'border-left:1px solid #aaaaaa; border-right:1px solid #aaaaaa; border-top:1px solid #aaaaaa; border-bottom:1px solid #aaaaaa; background:#ffffff; color:#555;')">
147
+ {{ item.mode }}
148
+ </div>
149
+ <div :style="'padding:0px 5px; border-top-right-radius:4px; border-bottom-right-radius:4px; ' + (item.enable === 'y' ? '_border-left:1px solid #ac2451; border-right:1px solid #ac2451; border-top:1px solid #ac2451; border-bottom:1px solid #ac2451; background:#d22f64; color:#fff;' : '_border-left:1px solid #aaaaaa; border-right:1px solid #aaaaaa; border-top:1px solid #aaaaaa; border-bottom:1px solid #aaaaaa; background:#eeeeee; color:#555;')">
150
+ {{ item.name }}
151
+ </div>
147
152
  </div>
148
- </div>
149
- </span>
153
+ </span>
154
+ </template>
155
+ <select v-else-if="props.key==='mode'" @change="showVePemiBlngGrupsToggleItemModeByName(props.row.name, $event.target.value)" :disabled="!isEditable">
156
+ <option value="OR" :selected="props.row.mode === 'OR'">OR</option>
157
+ <option value="AND" :selected="props.row.mode === 'AND'">AND</option>
158
+ </select>
159
+ <input v-else-if="props.key==='enable'" type="checkbox" :checked="props.value === 'y'" @click="showVePemiBlngGrupsToggleItemEnableByName(props.row.name)" :disabled="!isEditable" />
160
+ <span v-else>{{ props.value }}</span>
150
161
  </template>
151
- <select v-else-if="props.key==='mode'" @change="showVePemiBlngGrupsToggleItemModeByName(props.row.name, $event.target.value)" :disabled="!isEditable">
152
- <option value="OR" :selected="props.row.mode === 'OR'">OR</option>
153
- <option value="AND" :selected="props.row.mode === 'AND'">AND</option>
154
- </select>
155
- <input v-else-if="props.key==='enable'" type="checkbox" :checked="props.value === 'y'" @click="showVePemiBlngGrupsToggleItemEnableByName(props.row.name)" :disabled="!isEditable" />
156
- <span v-else>{{ props.value }}</span>
157
- </template>
158
- </WAggridVue>
162
+ </WAggridVue>
163
+ </template>
164
+
159
165
  </template>
160
166
 
161
167
  <div
@@ -223,6 +229,8 @@ export default {
223
229
  panelHeight: 100,
224
230
  headHeight: 100,
225
231
 
232
+ firstLoading: true,
233
+ firstSetting: true,
226
234
  isEditable: false,
227
235
  isModified: false,
228
236
 
@@ -244,9 +252,26 @@ export default {
244
252
  Vue.prototype.$dg.showVePemiBlngGrupsToggleItemModeByName = vo.showVePemiBlngGrupsToggleItemModeByName
245
253
  Vue.prototype.$dg.showVePemiBlngGrupsToggleItemEnableByName = vo.showVePemiBlngGrupsToggleItemEnableByName
246
254
 
255
+ //firstSetting
256
+ if (vo.firstSetting) {
257
+ // console.log('webInfor', vo.webInfor)
258
+
259
+ //會觸發數據變更再導致opt變更導致觸發rowsChange等事件, 故得要延遲, 供組件偵測初始設定數據初始化之用
260
+ setTimeout(() => {
261
+ vo.firstSetting = false
262
+ // console.log('firstSetting', vo.firstSetting)
263
+ }, 1)
264
+
265
+ }
266
+
247
267
  },
248
268
  computed: {
249
269
 
270
+ syncState: function() {
271
+ let vo = this
272
+ return get(vo, '$store.state.syncState')
273
+ },
274
+
250
275
  targets: function() {
251
276
  let rs = get(this, `$store.state.targets`)
252
277
  rs = sortBy(rs, 'order')
@@ -434,6 +459,11 @@ export default {
434
459
  // console.log('rowsChange', rs)
435
460
  // console.log('rowsChange cloneDeep(vo.opt.rows)', cloneDeep(vo.opt.rows))
436
461
 
462
+ //check
463
+ if (!vo.syncState || vo.firstLoading || vo.firstSetting) {
464
+ return
465
+ }
466
+
437
467
  //isModified
438
468
  vo.isModified = true
439
469
 
@@ -935,7 +965,8 @@ export default {
935
965
 
936
966
  //check
937
967
  if (size(rows) === 0) {
938
- vo.$alert(`${vo.$t('grupSaveGrupsEmpty')}`, { type: 'error' })
968
+ vo.$ui.updateLoading(false) //showCheckYes 前關 loading(modal 阻斷、避免 clickSave 包裝層 loading 疊在 modal 後)
969
+ await vo.$dg.showCheckYes(`${vo.$t('grupSaveGrupsEmpty')}`)
939
970
  return
940
971
  }
941
972
 
@@ -947,12 +978,14 @@ export default {
947
978
 
948
979
  //check
949
980
  if (errTemp !== null) {
950
- vo.$alert(`${vo.$t('grupSaveGrupsFail')}: ${errTemp}`, { type: 'error' })
981
+ vo.$ui.updateLoading(false)
982
+ await vo.$dg.showCheckYes(`${vo.$t('grupSaveGrupsFail')}: ${vo.$tErr(errTemp)}`)
951
983
  return
952
984
  }
953
985
 
954
986
  //alert
955
- vo.$alert(vo.$t('grupSaveGrupsSuccess'))
987
+ vo.$ui.updateLoading(false)
988
+ await vo.$dg.showCheckYes(vo.$t('grupSaveGrupsSuccess'), { type: 'success' })
956
989
 
957
990
  },
958
991
 
@@ -976,6 +1009,18 @@ export default {
976
1009
 
977
1010
  let vo = this
978
1011
 
1012
+ //save按鈕第一行立刻釋放視覺鎖
1013
+ msg.pm.resolve()
1014
+
1015
+ //fire-and-forget, 不 await
1016
+ vo.doSave()
1017
+
1018
+ },
1019
+
1020
+ doSave: function() {
1021
+
1022
+ let vo = this
1023
+
979
1024
  async function core() {
980
1025
 
981
1026
  //show loading
@@ -1057,9 +1102,6 @@ export default {
1057
1102
  .catch(() => { })
1058
1103
  .finally(() => {
1059
1104
 
1060
- //save按鈕解除loading
1061
- msg.pm.resolve()
1062
-
1063
1105
  //hide loading
1064
1106
  vo.$ui.updateLoading(false)
1065
1107
 
@@ -1112,6 +1154,9 @@ export default {
1112
1154
  //genOpt
1113
1155
  vo.genOpt()
1114
1156
 
1157
+ //firstLoading
1158
+ vo.firstLoading = false
1159
+
1115
1160
  //bShow
1116
1161
  vo.bShow = true
1117
1162
 
package/src/getPerm.mjs CHANGED
@@ -12,10 +12,10 @@ async function getPerm(url, tokenTar, opt = {}) {
12
12
 
13
13
  //check
14
14
  if (!isestr(url)) {
15
- return Promise.reject('invalid url')
15
+ return Promise.reject('invalidUrl')
16
16
  }
17
17
  if (!isestr(tokenTar)) {
18
- return Promise.reject('invalid tokenTar')
18
+ return Promise.reject('invalidTokenTar')
19
19
  }
20
20
 
21
21
  //funConvertPerm
@@ -23,7 +23,7 @@ async function getPerm(url, tokenTar, opt = {}) {
23
23
 
24
24
  //url
25
25
  if (url.indexOf('token={token}') < 0) {
26
- return Promise.reject(`no 'token={token}' in url`)
26
+ return Promise.reject('noTokenInUrl')
27
27
  }
28
28
  url = url.replaceAll('{token}', tokenTar)
29
29
  // console.log('getPerm: url', url)
@@ -36,10 +36,7 @@ async function getPerm(url, tokenTar, opt = {}) {
36
36
 
37
37
  //check
38
38
  if (errTemp !== null) {
39
- console.log('res', res)
40
- console.log('errTemp', errTemp)
41
- console.log(`can not get user by url[${url}]`)
42
- return Promise.reject(`can not get user by url[${url}]`) //由SSO取得使用者資訊錯誤
39
+ return Promise.reject('cannotGetUserByUrl') //由SSO取得使用者資訊錯誤
43
40
  }
44
41
 
45
42
  //data
@@ -53,12 +50,7 @@ async function getPerm(url, tokenTar, opt = {}) {
53
50
 
54
51
  //check
55
52
  if (state !== 'success') {
56
- console.log('res', res)
57
- console.log('data', data)
58
- console.log('state', state)
59
- console.log('errTemp', msg)
60
- console.log(`can not get user data by url[${url}]`)
61
- return Promise.reject(`can not get user data by url[${url}]`) //取得使用者資訊失敗
53
+ return Promise.reject('cannotGetUserDataByUrl') //取得使用者資訊失敗
62
54
  }
63
55
 
64
56
  //ur
@@ -67,8 +59,7 @@ async function getPerm(url, tokenTar, opt = {}) {
67
59
 
68
60
  //check
69
61
  if (!iseobj(ur)) {
70
- console.log(`no user data by url[${url}]`)
71
- return Promise.reject(`no user data by url[${url}]`)
62
+ return Promise.reject('noUserDataByUrl')
72
63
  }
73
64
 
74
65
  //check
@@ -83,8 +74,7 @@ async function getPerm(url, tokenTar, opt = {}) {
83
74
 
84
75
  //check
85
76
  if (!iseobj(ur)) {
86
- console.log(`no user data after funConvertPerm`)
87
- return Promise.reject(`no user data after funConvertPerm`)
77
+ return Promise.reject('noUserDataAfterConvert')
88
78
  }
89
79
 
90
80
  }
@@ -12,13 +12,13 @@ async function getPermUserInfor(url, tokenSelf, userIdTar, opt = {}) {
12
12
 
13
13
  //check
14
14
  if (!isestr(url)) {
15
- return Promise.reject('invalid url')
15
+ return Promise.reject('invalidUrl')
16
16
  }
17
17
  if (!isestr(tokenSelf)) {
18
- return Promise.reject('invalid tokenSelf')
18
+ return Promise.reject('invalidTokenSelf')
19
19
  }
20
20
  if (!isestr(userIdTar)) {
21
- return Promise.reject('invalid userIdTar')
21
+ return Promise.reject('invalidUserIdTar')
22
22
  }
23
23
 
24
24
  //funConvertPerm
@@ -26,7 +26,7 @@ async function getPermUserInfor(url, tokenSelf, userIdTar, opt = {}) {
26
26
 
27
27
  //url
28
28
  if (url.indexOf('token={sysToken}') < 0 && url.indexOf('userId={userId}') < 0) {
29
- return Promise.reject(`no 'token={sysToken}', 'userId={userId}' in url`)
29
+ return Promise.reject('noTokenUserIdInUrl')
30
30
  }
31
31
  url = url.replaceAll('{sysToken}', tokenSelf) //系統介接用permToken
32
32
  url = url.replaceAll('{userId}', userIdTar)
@@ -40,10 +40,7 @@ async function getPermUserInfor(url, tokenSelf, userIdTar, opt = {}) {
40
40
 
41
41
  //check
42
42
  if (errTemp !== null) {
43
- console.log('res', res)
44
- console.log('errTemp', errTemp)
45
- console.log(`can not get user by url[${url}]`)
46
- return Promise.reject(`can not get user by url[${url}]`) //由SSO取得使用者資訊錯誤
43
+ return Promise.reject('cannotGetUserByUrl') //由SSO取得使用者資訊錯誤
47
44
  }
48
45
 
49
46
  //data
@@ -57,12 +54,7 @@ async function getPermUserInfor(url, tokenSelf, userIdTar, opt = {}) {
57
54
 
58
55
  //check
59
56
  if (state !== 'success') {
60
- console.log('res', res)
61
- console.log('data', data)
62
- console.log('state', state)
63
- console.log('errTemp', msg)
64
- console.log(`can not get user data by url[${url}]`)
65
- return Promise.reject(`can not get user data by url[${url}]`) //取得使用者資訊失敗
57
+ return Promise.reject('cannotGetUserDataByUrl') //取得使用者資訊失敗
66
58
  }
67
59
 
68
60
  //ur
@@ -71,8 +63,7 @@ async function getPermUserInfor(url, tokenSelf, userIdTar, opt = {}) {
71
63
 
72
64
  //check
73
65
  if (!iseobj(ur)) {
74
- console.log(`no user data by url[${url}]`)
75
- return Promise.reject(`no user data by url[${url}]`)
66
+ return Promise.reject('noUserDataByUrl')
76
67
  }
77
68
 
78
69
  //check
@@ -87,8 +78,7 @@ async function getPermUserInfor(url, tokenSelf, userIdTar, opt = {}) {
87
78
 
88
79
  //check
89
80
  if (!iseobj(ur)) {
90
- console.log(`no user data after funConvertPerm`)
91
- return Promise.reject(`no user data after funConvertPerm`)
81
+ return Promise.reject('noUserDataAfterConvert')
92
82
  }
93
83
 
94
84
  }
package/src/main.js CHANGED
@@ -32,6 +32,7 @@ let dssm = mDataSelectorSchema(ds)
32
32
  //prototype
33
33
  Vue.prototype.$ui = ui
34
34
  Vue.prototype.$t = ui.getKpText
35
+ Vue.prototype.$tErr = ui.tErr
35
36
  Vue.prototype.$s = s
36
37
  Vue.prototype.$dssm = dssm
37
38
  Vue.prototype.$ds = ds
@@ -479,25 +479,20 @@ function getUserRules(user, grups, pemis, targets) {
479
479
  }
480
480
  // console.log('merge _rules', cloneDeep(_rules))
481
481
 
482
- //expand _rules
482
+ //expand _rules:以「當前 targets」為輸出主軸——逐 target 取其解析後 isActive(取自合併 crules 的 kp、預設 'n')。
483
+ //如此只列現存管控對象;crules 仍引用但已從 targets 刪除的「孤兒 target」自然被濾掉,不再殘留於權限樹。
484
+ //(修正前:輸出 kp 全部 keys = crules keys ∪ targets,導致已刪 target 因 crules 殘留引用而仍出現在權限樹。)
483
485
  if (true) {
484
486
  let kp = {}
485
487
  each(_rules, (v) => {
486
488
  kp[v.name] = v.isActive
487
489
  })
488
- each(targets, (t) => {
489
- // console.log('t', t)
490
- if (!haskey(kp, t.id)) {
491
- kp[t.id] = 'n'
492
- }
493
- })
494
490
  let rs = []
495
- each(kp, (v, k) => {
496
- let r = {
497
- name: k,
498
- isActive: v,
499
- }
500
- rs.push(r)
491
+ each(targets, (t) => {
492
+ rs.push({
493
+ name: t.id,
494
+ isActive: get(kp, t.id, 'n'),
495
+ })
501
496
  })
502
497
  _rules = rs
503
498
  }
@@ -150,10 +150,9 @@ function getLang() {
150
150
  }
151
151
  }
152
152
 
153
- //return
154
- if (!isestr(lang)) {
155
- return 'eng'
156
- }
153
+ //validLang
154
+ lang = validLang(lang) //有可能給予非預期lang
155
+
157
156
  return lang
158
157
  }
159
158
 
@@ -165,9 +164,7 @@ function setLang(lang = null, from = '') {
165
164
  if (!isestr(lang)) {
166
165
  lang = getLang()
167
166
  }
168
- else {
169
- lang = validLang(lang)
170
- }
167
+ lang = validLang(lang)
171
168
  // console.log('get lang', lang)
172
169
 
173
170
  //check, 若有變更才commit
@@ -218,6 +215,16 @@ function getKpText(key) {
218
215
  }
219
216
 
220
217
 
218
+ function tErr(err) {
219
+ let key = isestr(err) ? err : 'anUnexpectedErrorOccurred'
220
+ let msg = getKpText(key) //後端 err key → 翻譯
221
+ if (msg === key) { //getKpText 查無 → 回傳 key 本身 → 非 procLang key (連線層 raw 等)
222
+ msg = getKpText('cannotConnectServer')
223
+ }
224
+ return msg
225
+ }
226
+
227
+
221
228
  function gv(o, k, cv = null) {
222
229
  let r = get(o, k, '')
223
230
  if (!isestr(r)) {
@@ -293,6 +300,7 @@ let mUI = {
293
300
 
294
301
  setLang,
295
302
  getKpText,
303
+ tErr,
296
304
 
297
305
  gv,
298
306
  syncHeight,
@@ -26,7 +26,7 @@ let state = {
26
26
  userToken: '',
27
27
  userSelf: {},
28
28
 
29
- lang: 'cht', //'eng', 'cht'
29
+ lang: 'eng', //'eng', 'cht'
30
30
  kpText: {}, //一定要放在vuex內, 否則無法用broadcast驅動變更語系文字
31
31
 
32
32
  }