w-web-perm 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/.editorconfig +9 -0
  2. package/.eslintignore +3 -0
  3. package/.eslintrc.js +55 -0
  4. package/.github/workflows/ci-test.yml +24 -0
  5. package/.jsdoc +25 -0
  6. package/.vscode/launch.json +21 -0
  7. package/LICENSE +21 -0
  8. package/README.md +24 -0
  9. package/SECURITY.md +5 -0
  10. package/babel.config.js +15 -0
  11. package/dist/css/app.79b4b59b.css +1 -0
  12. package/dist/css/chunk-vendors.65775501.css +5 -0
  13. package/dist/index.tmp +1 -0
  14. package/dist/js/app-legacy.954e168c.js +2 -0
  15. package/dist/js/app-legacy.954e168c.js.map +1 -0
  16. package/dist/js/app.954e168c.js +2 -0
  17. package/dist/js/app.954e168c.js.map +1 -0
  18. package/dist/js/chunk-vendors-legacy.f5f1a231.js +13 -0
  19. package/dist/js/chunk-vendors-legacy.f5f1a231.js.map +1 -0
  20. package/dist/js/chunk-vendors.f5f1a231.js +13 -0
  21. package/dist/js/chunk-vendors.f5f1a231.js.map +1 -0
  22. package/dist/w-web-perm.umd.js +7 -0
  23. package/dist/w-web-perm.umd.js.map +1 -0
  24. package/docs/WWebPerm.html +826 -0
  25. package/docs/WWebPerm.mjs.html +558 -0
  26. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  27. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  28. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  29. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  30. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  31. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  32. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  33. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  34. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  35. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  36. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  37. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  38. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  39. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  40. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  41. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  42. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  43. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  44. package/docs/index.html +84 -0
  45. package/docs/scripts/collapse.js +39 -0
  46. package/docs/scripts/commonNav.js +28 -0
  47. package/docs/scripts/linenumber.js +25 -0
  48. package/docs/scripts/nav.js +12 -0
  49. package/docs/scripts/polyfill.js +4 -0
  50. package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  51. package/docs/scripts/prettify/lang-css.js +2 -0
  52. package/docs/scripts/prettify/prettify.js +28 -0
  53. package/docs/scripts/search.js +99 -0
  54. package/docs/styles/jsdoc.css +776 -0
  55. package/docs/styles/prettify.css +80 -0
  56. package/g.getSettings.mjs +17 -0
  57. package/g.mDb.mjs +10 -0
  58. package/g.mInitialTestData.mjs +20 -0
  59. package/g.mOrm.mjs +24 -0
  60. package/package.json +75 -0
  61. package/public/index.html +23 -0
  62. package/server/WWebPerm.mjs +486 -0
  63. package/src/App.vue +153 -0
  64. package/src/components/Common/CheckYes.vue +85 -0
  65. package/src/components/Common/CheckYesNo.vue +91 -0
  66. package/src/components/Common/LabelItem.vue +106 -0
  67. package/src/components/Common/LoadingWinBar.vue +87 -0
  68. package/src/components/Layout.vue +152 -0
  69. package/src/components/LayoutContent.vue +246 -0
  70. package/src/components/LayoutContentGroups.vue +664 -0
  71. package/src/components/LayoutContentTargets.vue +538 -0
  72. package/src/components/LayoutContentUsers.vue +493 -0
  73. package/src/components/LayoutState.vue +91 -0
  74. package/src/components/VeUser.vue +453 -0
  75. package/src/components/ruleGroup.vue +667 -0
  76. package/src/main.js +103 -0
  77. package/src/perm.mjs +61 -0
  78. package/src/plugins/mDataSelectorSchema.mjs +30 -0
  79. package/src/plugins/mDataSupport.mjs +66 -0
  80. package/src/plugins/mShare.mjs +366 -0
  81. package/src/plugins/mUI.mjs +229 -0
  82. package/src/plugins/mVuetify.mjs +12 -0
  83. package/src/schema/gi.mjs +8 -0
  84. package/src/schema/index.mjs +20 -0
  85. package/src/schema/tables/ruleGroups.mjs +100 -0
  86. package/src/schema/tables/targets.mjs +100 -0
  87. package/src/schema/tables/users.mjs +125 -0
  88. package/src/store/actions.mjs +1 -0
  89. package/src/store/getters.mjs +1 -0
  90. package/src/store/index.mjs +25 -0
  91. package/src/store/mutations.mjs +201 -0
  92. package/src/store/types.mjs +15 -0
  93. package/srv.mjs +52 -0
  94. package/tableTags-web-perm.json +1 -0
  95. package/test/all.test.mjs +10 -0
  96. package/toolg/addVersion.mjs +4 -0
  97. package/toolg/cleanFolder.mjs +4 -0
  98. package/toolg/gDistRollup.mjs +36 -0
  99. package/toolg/genEntry.mjs +23 -0
  100. package/toolg/modifyReadme.mjs +4 -0
  101. package/vue.config.js +15 -0
@@ -0,0 +1,538 @@
1
+ <template>
2
+ <div
3
+ style="height:100%;"
4
+ v-domresize
5
+ @domresize="resizePanel"
6
+ :changeTargets="changeTargets"
7
+ >
8
+
9
+ <div
10
+ style="border-bottom:1px solid #ddd;"
11
+ v-domresize
12
+ @domresize="resizeHead"
13
+ >
14
+
15
+ <!-- 標題區 -->
16
+ <div style="padding:30px 25px 0px 20px; background:#fff;">
17
+ <div style="padding:5px 15px 5px 5px; display:inline-block; border-bottom:3px solid #FF9100;">
18
+ <div style="display:flex; align-items:center;">
19
+
20
+ <WIcon
21
+ :icon="mdiGamepadCircle"
22
+ :color="'#FF9800'"
23
+ ></WIcon>
24
+
25
+ <div style="padding-left:10px; font-size:1.3rem; color:#d3912c;">
26
+ 管理區塊
27
+ </div>
28
+
29
+ </div>
30
+ </div>
31
+ </div>
32
+
33
+ <!-- 編輯設定區 -->
34
+ <div style="background:#fff;">
35
+
36
+ <div style="padding:20px 20px 15px 20px; background:#fff;">
37
+
38
+ <div style="display:flex;">
39
+ <WSwitch
40
+ :text="'是否編輯'"
41
+ :checkedSwitchCircleColor="'#D81B60'"
42
+ :checkedSwitchCircleColorHover="'#f26'"
43
+ :checkedSwitchBarColor="'#F8BBD0'"
44
+ :checkedSwitchBarColorHover="'#F8BBD0'"
45
+ _v-model="isOperatable"
46
+ :value="isOperatable"
47
+ @input="updateIsOperatable"
48
+ ></WSwitch>
49
+ </div>
50
+
51
+ <div style="padding-top:5px; font-size:0.8rem; _color:#f26;" v-if="isOperatable">
52
+ <div style="padding:3px 0px;">
53
+ 1. 請於各區塊右側點擊按鈕即可進行操作,例如變更名稱、插入或刪除區塊。
54
+ </div>
55
+ <div style="padding:3px 0px;">
56
+ 2. 編輯區塊時禁止顯隱子區塊功能。
57
+ </div>
58
+ </div>
59
+
60
+ </div>
61
+
62
+ <div
63
+ style="padding:10px 10px 12px 10px; border-top:1px solid #F48FB1; border-bottom:1px solid #F48FB1; background:#FCE4EC; display:flex; align-items:center; justify-content:flex-end;"
64
+ v-if="isModified"
65
+ >
66
+
67
+ <WButtonChip
68
+ :paddingStyle="{v:0,h:11}"
69
+ :text="'儲存變更'"
70
+ :icon="mdiCloudUploadOutline"
71
+ :backgroundColor="'rgba(255,0,50,0.7)'"
72
+ :backgroundColorHover="'rgba(255,0,50,0.8)'"
73
+ :textColor="'#eee'"
74
+ :textColorHover="'#fff'"
75
+ :iconColor="'#eee'"
76
+ :iconColorHover="'#fff'"
77
+ @click="saveRuleGroupsAndTargets"
78
+ ></WButtonChip>
79
+
80
+ </div>
81
+
82
+ </div>
83
+
84
+ </div>
85
+
86
+ <div :style="`padding:${spacePading}px;`" v-if="!firstLoading">
87
+
88
+ <div style="background:#fff; box-shadow:0 3px 1px -2px rgba(0,0,0,.2), 0 2px 2px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12);">
89
+ <WTree
90
+ ref="wt"
91
+ :viewHeightMax="treeHeight"
92
+ :separatorColor="'rgba(0,0,0,0.1)'"
93
+ :data.sync="treeBlocks"
94
+ :indent="0.5"
95
+ :iconToggleColor="'#666'"
96
+ :iconToggleBackgroundColor="'transparent'"
97
+ :iconToggleBackgroundColorHover="'transparent'"
98
+ :operatable="isOperatable"
99
+ :operateBtnTooltip="'編輯'"
100
+ :operateItemTextForRename="'變更名稱'"
101
+ :operateItemTextForInsertBefore="'插入前區塊'"
102
+ :operateItemTextForInsertChild="'插入子區塊'"
103
+ :operateItemTextForInsertAfter="'插入後區塊'"
104
+ :operateItemTextForDelete="'刪除區塊'"
105
+ :editorRenameSaveBtnText="'儲存'"
106
+ :editorRenameSaveBtnTextColor="'#444'"
107
+ :editorRenameSaveBtnTextColorHover="'#222'"
108
+ :editorRenameCancelBtnText="'取消'"
109
+ :editorRenameCancelBtnTextColor="'#444'"
110
+ :editorRenameCancelBtnTextColorHover="'#222'"
111
+ @click-operate-item="clickOperateItem"
112
+ ></WTree>
113
+ </div>
114
+
115
+ </div>
116
+
117
+ <div style="padding:10px 15px; font-size:0.8rem;" v-else>
118
+ 載入中...
119
+ </div>
120
+
121
+ </div>
122
+ </template>
123
+
124
+ <script>
125
+ import { mdiGamepadCircle, mdiStackOverflow, mdiAccountGroupOutline, mdiBallotRecountOutline, mdiCloudUploadOutline } from '@mdi/js/mdi.js'
126
+ import get from 'lodash/get'
127
+ import set from 'lodash/set'
128
+ import each from 'lodash/each'
129
+ import map from 'lodash/map'
130
+ import size from 'lodash/size'
131
+ import dropRight from 'lodash/dropRight'
132
+ import cloneDeep from 'lodash/cloneDeep'
133
+ import haskey from 'wsemi/src/haskey.mjs'
134
+ import genID from 'wsemi/src/genID.mjs'
135
+ import delay from 'wsemi/src/delay.mjs'
136
+ import flattenTree from 'wsemi/src/flattenTree.mjs'
137
+ import WIcon from 'w-component-vue/src/components/WIcon.vue'
138
+ import WButtonChip from 'w-component-vue/src/components/WButtonChip.vue'
139
+ import WSwitch from 'w-component-vue/src/components/WSwitch.vue'
140
+ import WTree from 'w-component-vue/src/components/WTree.vue'
141
+ import { getTreeBlocks } from '../plugins/mShare.mjs'
142
+
143
+
144
+ export default {
145
+ components: {
146
+ WIcon,
147
+ WButtonChip,
148
+ WSwitch,
149
+ WTree,
150
+ },
151
+ props: {
152
+ },
153
+ data: function() {
154
+ return {
155
+ mdiGamepadCircle,
156
+ mdiStackOverflow,
157
+ mdiAccountGroupOutline,
158
+ mdiBallotRecountOutline,
159
+ mdiCloudUploadOutline,
160
+
161
+ panelWidth: 100,
162
+ panelHeight: 100,
163
+ headHeight: 100,
164
+
165
+ firstLoading: true,
166
+ isOperatable: false,
167
+ isModified: false,
168
+
169
+ treeBlocks: null,
170
+ listRename: [],
171
+
172
+ }
173
+ },
174
+ mounted: function() {
175
+ // console.log('mounted')
176
+
177
+ let vo = this
178
+
179
+ //clear
180
+ vo.listRename = []
181
+
182
+ },
183
+ computed: {
184
+
185
+ targets: function() {
186
+ return get(this, `$store.state.targets`)
187
+ },
188
+
189
+ ruleGroups: function() {
190
+ return get(this, `$store.state.ruleGroups`)
191
+ },
192
+
193
+ changeTargets: function() {
194
+ // console.log('computed changeTargets')
195
+
196
+ let vo = this
197
+
198
+ //check
199
+ if (size(vo.targets) === 0) {
200
+ return ''
201
+ }
202
+
203
+ //getTreeBlocks
204
+ let treeBlocks = getTreeBlocks(vo.targets)
205
+
206
+ //save
207
+ vo.treeBlocks = treeBlocks
208
+
209
+ //firstLoading
210
+ vo.firstLoading = false
211
+
212
+ return ''
213
+ },
214
+
215
+ spacePading: function() {
216
+ let vo = this
217
+ if (vo.panelWidth < 400) {
218
+ return 0
219
+ }
220
+ else if (vo.panelWidth < 800) {
221
+ return 10
222
+ }
223
+ return 20
224
+ },
225
+
226
+ treeHeight: function() {
227
+ let vo = this
228
+
229
+ //h
230
+ let h = vo.panelHeight - vo.headHeight - 2 * vo.spacePading
231
+ h = Math.max(h, 0)
232
+
233
+ return h
234
+ },
235
+
236
+ },
237
+ methods: {
238
+
239
+ resizePanel: function(msg) {
240
+ // console.log('methods resizePanel', msg)
241
+
242
+ let vo = this
243
+
244
+ //panelWidth, panelHeight
245
+ vo.panelWidth = msg.snew.offsetWidth
246
+ vo.panelHeight = msg.snew.offsetHeight
247
+
248
+ },
249
+
250
+ resizeHead: function(msg) {
251
+ // console.log('methods resizeHead', msg)
252
+
253
+ let vo = this
254
+
255
+ //headHeight
256
+ vo.headHeight = msg.snew.offsetHeight
257
+
258
+ },
259
+
260
+ updateIsOperatable: function(isOperatable) {
261
+ // console.log('methods updateIsOperatable', isOperatable)
262
+
263
+ let vo = this
264
+
265
+ async function core() {
266
+ // let errTemp = null
267
+
268
+ //show loading
269
+ vo.$ui.updateLoading(true)
270
+
271
+ //isOperatable
272
+ if (isOperatable) {
273
+ //切換至編輯模式時
274
+ try {
275
+
276
+ //先顯示全部節點
277
+ let toUnfolding = true
278
+ let toLevel = null
279
+ vo.$refs.wt.toggleItemsAll(toUnfolding, toLevel)
280
+
281
+ //若節點多顯示全部節點須一些時間, 故延遲變更
282
+ await delay(300)
283
+
284
+ //update
285
+ vo.isOperatable = isOperatable
286
+
287
+
288
+ }
289
+ catch (err) {}
290
+ }
291
+ else {
292
+ //切換至顯示模式時
293
+
294
+ //update
295
+ vo.isOperatable = isOperatable
296
+
297
+ }
298
+
299
+ }
300
+
301
+ //core
302
+ core()
303
+ // .then((res) => {
304
+ // console.log('then', res)
305
+ // })
306
+ .catch((err) => {
307
+ console.log('catch', err)
308
+ vo.$alert(`發生非預期錯誤,請洽管理員`, { type: 'error' })
309
+ })
310
+ .finally(() => {
311
+
312
+ //hide loading
313
+ vo.$ui.updateLoading(false)
314
+
315
+ })
316
+
317
+ },
318
+
319
+ clickOperateItem: function(msg) {
320
+ // console.log('methods clickOperateItem', msg)
321
+
322
+ let vo = this
323
+
324
+ async function core() {
325
+
326
+ //fun, 僅處理並回傳新項目, 不處理其他項目
327
+ let fun = async function() {
328
+ let id = genID()
329
+ let text = '新區塊'
330
+ let dataNew = {
331
+ id,
332
+ text,
333
+ }
334
+ return dataNew
335
+ }
336
+
337
+ //targetInd
338
+ let targetInd = msg.rowItem.index
339
+
340
+ //operateItem
341
+ await msg.operateItem(targetInd, msg.opItem.key, fun)
342
+
343
+ //modifyTreeBlocks
344
+ vo.modifyTreeBlocks()
345
+
346
+ }
347
+
348
+ //core
349
+ core()
350
+ // .then((res) => {
351
+ // console.log('then', res)
352
+ // })
353
+ .catch((err) => {
354
+ console.log('catch', err)
355
+ vo.$alert(`發生非預期錯誤,請洽管理員`, { type: 'error' })
356
+ })
357
+
358
+ },
359
+
360
+ modifyTreeBlocks: function() {
361
+ // console.log('methods modifyTreeBlocks')
362
+
363
+ let vo = this
364
+
365
+ //treeBlocksTemp
366
+ let treeBlocksTemp = cloneDeep(vo.treeBlocks)
367
+
368
+ //flattenTree
369
+ let blocksNew = flattenTree(treeBlocksTemp)
370
+ // console.log('blocksNew', cloneDeep(blocksNew))
371
+
372
+ //calc id, parentId, order
373
+ each(blocksNew, (v, k) => {
374
+ if (size(v.nk) === 1) {
375
+ v.parentId = ''
376
+ v.id = v.text
377
+ }
378
+ else { //size(v.nk)>=3
379
+ let nkParent = dropRight(v.nk, 2)
380
+ let p = get(treeBlocksTemp, nkParent)
381
+ v.parentId = p.id
382
+ v.id = `${v.parentId}.${v.text}`
383
+ }
384
+ v.order = k //需重新給予order
385
+ set(treeBlocksTemp, v.nk, v)
386
+ })
387
+
388
+ //save
389
+ vo.treeBlocks = treeBlocksTemp
390
+ // console.log('treeBlocks', cloneDeep(treeBlocksTemp))
391
+
392
+ //isModified
393
+ vo.isModified = true
394
+
395
+ },
396
+
397
+ saveRuleGroupsAndTargets: function() {
398
+ // console.log('method saveRuleGroupsAndTargets')
399
+
400
+ let vo = this
401
+
402
+ //replaceObjKeys
403
+ let replaceObjKeys = (obj, kpKeys) => {
404
+ // console.log('methods replaceObjKeys', obj, kpKeys)
405
+
406
+ //r
407
+ let b = false
408
+ let r = {}
409
+ each(obj, (v, k) => {
410
+ if (haskey(kpKeys, k)) {
411
+ b = true
412
+ let kk = kpKeys[k]
413
+ r[kk] = v
414
+ }
415
+ else {
416
+ r[k] = v
417
+ }
418
+ })
419
+
420
+ return {
421
+ obj: r,
422
+ isChanged: b,
423
+ }
424
+ }
425
+
426
+ async function core() {
427
+ let errTemp = null
428
+
429
+ //show loading
430
+ vo.$ui.updateLoading(true)
431
+
432
+ //treeBlocksTemp
433
+ let treeBlocksTemp = cloneDeep(vo.treeBlocks)
434
+
435
+ //flattenTree
436
+ let blocksNew = flattenTree(treeBlocksTemp)
437
+ // console.log('blocksNew1', cloneDeep(blocksNew))
438
+
439
+ //kpDiffs
440
+ let kpDiffs = {}
441
+ map(blocksNew, (v, k) => {
442
+ if (v.id !== v.idTemp) {
443
+ kpDiffs[v.idTemp] = v.id
444
+ }
445
+ })
446
+ // console.log('kpDiffs', kpDiffs)
447
+
448
+ //gs
449
+ let gs = []
450
+ each(vo.ruleGroups, (v) => {
451
+ let rules = JSON.parse(v.crules)
452
+ let r = replaceObjKeys(rules, kpDiffs)
453
+ if (r.isChanged) {
454
+ gs.push({
455
+ id: v.id,
456
+ crules: JSON.stringify(r.obj),
457
+ })
458
+ }
459
+ })
460
+ // console.log('ruleGroups', vo.ruleGroups, gs)
461
+
462
+ //save
463
+ await vo.$fapi.ruleGroups.save(gs)
464
+ .catch((err) => {
465
+ errTemp = err
466
+ })
467
+
468
+ //check
469
+ if (errTemp !== null) {
470
+ vo.$alert(`連動變更權限群組失敗: ${errTemp}`, { type: 'error' })
471
+ return
472
+ }
473
+
474
+ //rs
475
+ let rs = map(blocksNew, (v, k) => {
476
+ return {
477
+ id: v.id,
478
+ order: v.order,
479
+ }
480
+ })
481
+ // console.log('targets rs', rs)
482
+
483
+ //delAll
484
+ await vo.$fapi.targets.delAll()
485
+ .catch((err) => {
486
+ errTemp = err
487
+ })
488
+
489
+ //check
490
+ if (errTemp !== null) {
491
+ vo.$alert(`清除既有區塊數據失敗: ${errTemp}`, { type: 'error' })
492
+ return
493
+ }
494
+
495
+ //save
496
+ await vo.$fapi.targets.save(rs)
497
+ .catch((err) => {
498
+ errTemp = err
499
+ })
500
+
501
+ //check
502
+ if (errTemp !== null) {
503
+ vo.$alert(`儲存區塊數據失敗: ${errTemp}`, { type: 'error' })
504
+ return
505
+ }
506
+
507
+ //isModified
508
+ vo.isModified = false
509
+
510
+ //alert
511
+ vo.$alert(`儲存區塊數據成功`)
512
+
513
+ }
514
+
515
+ //core
516
+ core()
517
+ // .then((res) => {
518
+ // console.log('then', res)
519
+ // })
520
+ .catch((err) => {
521
+ console.log('catch', err)
522
+ vo.$alert(`發生非預期錯誤,請洽管理員`, { type: 'error' })
523
+ })
524
+ .finally(() => {
525
+
526
+ //hide loading
527
+ vo.$ui.updateLoading(false)
528
+
529
+ })
530
+
531
+ },
532
+
533
+ }
534
+ }
535
+ </script>
536
+
537
+ <style scoped>
538
+ </style>