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,453 @@
1
+ <template>
2
+ <WDialog
3
+ :show.sync="bShow"
4
+ :icon="mdiAccountEdit"
5
+ _maxWidth="1200"
6
+ _minWidth="1200"
7
+ :fullscreen="true"
8
+ :title="'編修使用者'"
9
+ :save-btn-tooltip="'儲存'"
10
+ :close-btn-tooltip="'關閉'"
11
+ @click-save="clickSave"
12
+ @click-close="clickClose"
13
+ @resize="resize"
14
+ >
15
+ <template v-slot:content>
16
+ <div style="min-height:400px;">
17
+
18
+ <div style="padding-top:20px;"></div>
19
+
20
+ <div style="padding:0px 20px 20px 20px; display:flex; align-items:center;">
21
+
22
+ <div style="padding-right:10px; color:#777; white-space:nowrap;">使用者姓名:</div>
23
+
24
+ <WText
25
+ style="width:100%;"
26
+ v-model="u.name"
27
+ ></WText>
28
+
29
+ </div>
30
+
31
+ <div style="padding:0px 20px 20px 20px; display:flex; align-items:center;">
32
+
33
+ <div style="padding-right:10px; color:#777; white-space:nowrap;">電子郵件:</div>
34
+
35
+ <WText
36
+ style="width:100%;"
37
+ v-model="u.email"
38
+ ></WText>
39
+
40
+ </div>
41
+
42
+ <div style="padding:0px 20px 20px 20px; display:flex; align-items:center;">
43
+
44
+ <div style="padding-right:10px; color:#777; white-space:nowrap;">來源:</div>
45
+
46
+ <WTextSuggest
47
+ style="width:200px;"
48
+ :noResultsText="'無'"
49
+ :items="userFroms"
50
+ v-model="u.from"
51
+ ></WTextSuggest>
52
+
53
+ </div>
54
+
55
+ <div style="padding-top:20px; border-top:1px solid #ddd;"></div>
56
+
57
+ <div style="padding:0px 20px 20px 20px;">
58
+
59
+ <div style="padding-bottom:5px; color:#777; white-space:nowrap;">隸屬權限群組:</div>
60
+
61
+ <div
62
+ style="display:inline-block; padding:0px 15px 15px 0px;"
63
+ :key="kg"
64
+ v-for="(g,kg) in groups"
65
+ >
66
+
67
+ <div style="padding:3px 15px 3px 0px; _border-radius:30px; _border:1px dashed #aaa; display:flex; align-content:center;">
68
+
69
+ <WCheckbox
70
+ :value="kpugs[g.id]"
71
+ _checkedIconColor="'rgba(200,70,20,0.8)'"
72
+ _uncheckedIconColor="'rgba(200,70,20,0.8)'"
73
+ @input="(v)=>{modifyUserRuleGroupsIds(g.id,v)}"
74
+ ></WCheckbox>
75
+
76
+ <div>
77
+ {{g.name}}
78
+ </div>
79
+
80
+ </div>
81
+
82
+ </div>
83
+
84
+ <div style="padding-bottom:5px; color:#777; white-space:nowrap;">使用者可用區塊:</div>
85
+
86
+ <div style="border:1px dashed #f26; background:rgba(255,50,100,0.05);">
87
+
88
+ <ruleGroup
89
+ :height="600"
90
+ :group="mergedGroup"
91
+ :showHead="false"
92
+ :editable="false"
93
+ ></ruleGroup>
94
+
95
+ </div>
96
+
97
+ </div>
98
+
99
+ <div style="padding-top:20px; border-top:1px solid #ddd;"></div>
100
+
101
+ <div style="padding:0px 20px 20px 20px; display:flex; align-items:center;">
102
+
103
+ <div style="padding-right:10px; color:#777; white-space:nowrap;">是否為管理者:</div>
104
+
105
+ <WSwitch
106
+ :value="u.isAdmin==='y'"
107
+ @input="(v)=>{u.isAdmin=v?'y':'n'}"
108
+ ></WSwitch>
109
+
110
+ </div>
111
+
112
+ <div style="padding:0px 20px 20px 20px; display:flex; align-items:center;">
113
+
114
+ <div style="padding-right:10px; color:#777; white-space:nowrap;">是否有效:</div>
115
+
116
+ <WSwitch
117
+ :value="u.isActive==='y'"
118
+ @input="(v)=>{u.isActive=v?'y':'n'}"
119
+ ></WSwitch>
120
+
121
+ </div>
122
+
123
+ <div style="padding-top:20px; border-top:1px solid #ddd;"></div>
124
+
125
+ <div style="padding:0px 20px 20px 20px; display:flex; align-items:center;">
126
+
127
+ <div style="padding-right:10px; color:#777; white-space:nowrap;">備註:</div>
128
+
129
+ <WText
130
+ style="width:100%;"
131
+ v-model="u.description"
132
+ ></WText>
133
+
134
+ </div>
135
+
136
+ <div style="padding-top:20px; border-top:1px solid #ddd;"></div>
137
+
138
+ <div style="padding:0px 20px 20px 20px; display:flex; align-items:center;">
139
+
140
+ <div style="padding-right:10px; color:#777; white-space:nowrap;">創建日期:</div>
141
+
142
+ <div style="padding:0px 7px; border-radius:20px; font-size:0.8rem; color:#fff; background:#A1887F;">
143
+ {{getCreateDay(u)}}
144
+ </div>
145
+
146
+ </div>
147
+
148
+ </div>
149
+ </template>
150
+ </WDialog>
151
+ </template>
152
+
153
+ <script>
154
+ import { mdiAccountEdit, mdiFileTree } from '@mdi/js/mdi.js'
155
+ import Vue from 'vue'
156
+ import get from 'lodash/get'
157
+ import each from 'lodash/each'
158
+ import map from 'lodash/map'
159
+ import trim from 'lodash/trim'
160
+ import uniq from 'lodash/uniq'
161
+ import filter from 'lodash/filter'
162
+ import join from 'lodash/join'
163
+ import sortBy from 'lodash/sortBy'
164
+ import cloneDeep from 'lodash/cloneDeep'
165
+ import genPm from 'wsemi/src/genPm.mjs'
166
+ import sep from 'wsemi/src/sep.mjs'
167
+ import timemsTZ2day from 'wsemi/src/timemsTZ2day.mjs'
168
+ import isernot from 'wsemi/src/isernot.mjs'
169
+ import isestr from 'wsemi/src/isestr.mjs'
170
+ import WDialog from 'w-component-vue/src/components/WDialog.vue'
171
+ import WText from 'w-component-vue/src/components/WText.vue'
172
+ import WTextSuggest from 'w-component-vue/src/components/WTextSuggest.vue'
173
+ import WSwitch from 'w-component-vue/src/components/WSwitch.vue'
174
+ import WCheckbox from 'w-component-vue/src/components/WCheckbox.vue'
175
+ import { getUserRules } from '../plugins/mShare.mjs'
176
+ import ruleGroup from './ruleGroup.vue'
177
+
178
+
179
+ export default {
180
+ components: {
181
+ WDialog,
182
+ WText,
183
+ WTextSuggest,
184
+ WSwitch,
185
+ WCheckbox,
186
+ ruleGroup,
187
+ },
188
+ props: {
189
+ },
190
+ data: function() {
191
+ return {
192
+ mdiAccountEdit,
193
+ mdiFileTree,
194
+
195
+ bShow: false,
196
+ pm: null,
197
+
198
+ // panelHeight: 100,
199
+
200
+ u: null,
201
+ kpugs: {},
202
+ mergedGroup: {},
203
+
204
+ }
205
+ },
206
+ mounted: function() {
207
+ //console.log('mounted')
208
+
209
+ let vo = this
210
+
211
+ //set
212
+ Vue.prototype.$dg.showVeUser = vo.show
213
+
214
+ },
215
+ computed: {
216
+
217
+ targets: function() {
218
+ return get(this, `$store.state.targets`)
219
+ },
220
+
221
+ ruleGroups: function() {
222
+ return get(this, `$store.state.ruleGroups`)
223
+ },
224
+
225
+ groups: function() {
226
+ // console.log('computed groups')
227
+
228
+ let vo = this
229
+
230
+ //rs, 此區程式碼等同於ruleGroups, 若確認後續無需求再移除
231
+ let rs = map(vo.ruleGroups, (v) => {
232
+ // let rules = JSON.parse(v.crules)
233
+ return {
234
+ ...v,
235
+ // rules,
236
+ }
237
+ })
238
+
239
+ //sortBy
240
+ rs = sortBy(rs, 'order')
241
+
242
+ return rs
243
+ },
244
+
245
+ users: function() {
246
+ return get(this, `$store.state.users`)
247
+ },
248
+
249
+ userFroms: function() {
250
+ let vo = this
251
+ let froms = map(vo.users, 'from')
252
+ froms = uniq(froms)
253
+ froms = filter(froms, isernot)
254
+ froms = sortBy(froms)
255
+ return froms
256
+ },
257
+
258
+ },
259
+ methods: {
260
+
261
+ resize: function(msg) {
262
+ // console.log('methods resize', msg)
263
+
264
+ let vo = this
265
+
266
+ // //panelHeight
267
+ // vo.panelHeight = msg.contentHeightMax - 59 //- 61.6
268
+
269
+ },
270
+
271
+ getCreateDay: function(u) {
272
+ let timeCreate = get(u, 'timeCreate', '')
273
+ return timemsTZ2day(timeCreate)
274
+ },
275
+
276
+ modifyUserRuleGroupsIds: function(ruleGroupsId, b) {
277
+ // console.log('methods modifyUserRuleGroupsIds', ruleGroupsId, b)
278
+
279
+ let vo = this
280
+
281
+ //kpugs, 因kugs初始化可能不是全部群組, 得用set才能觸發所有checkbox的value記憶體變更
282
+ // vo.kpugs[ruleGroupsId] = b
283
+ vo.$set(vo.kpugs, ruleGroupsId, b)
284
+
285
+ //modify ruleGroupsIds
286
+ let ruleGroupsIds = []
287
+ each(vo.kpugs, (v, k) => {
288
+ if (v) {
289
+ ruleGroupsIds.push(k)
290
+ }
291
+ })
292
+ ruleGroupsIds = join(ruleGroupsIds, ';')
293
+ vo.u.ruleGroupsIds = ruleGroupsIds
294
+ // console.log('ruleGroupsIds', ruleGroupsIds)
295
+
296
+ //calcMergedGroup
297
+ vo.calcMergedGroup()
298
+
299
+ },
300
+
301
+ calcMergedGroup: function() {
302
+ let vo = this
303
+
304
+ //save
305
+ let u = cloneDeep(vo.u)
306
+
307
+ //getUserRules
308
+ let urs = getUserRules(u, vo.ruleGroups, vo.targets)
309
+ // console.log('urs', urs)
310
+
311
+ //mergedGroup
312
+ let mergedGroup = {
313
+ id: 'merged-group',
314
+ name: 'merged-group',
315
+ crules: JSON.stringify(urs),
316
+ }
317
+
318
+ //mergedGroup
319
+ vo.mergedGroup = mergedGroup
320
+
321
+ },
322
+
323
+ clickSave: function(msg) {
324
+ //console.log('methods clickSave', msg)
325
+
326
+ let vo = this
327
+
328
+ async function core() {
329
+ let errTemp = null
330
+
331
+ //check
332
+ if (!isestr(vo.u.name)) {
333
+ vo.$alert(`使用者名稱不得為空`, { type: 'error' })
334
+ return
335
+ }
336
+
337
+ //show loading
338
+ vo.$ui.updateLoading(true)
339
+
340
+ //u
341
+ let u = {
342
+ id: vo.u.id,
343
+ name: trim(vo.u.name),
344
+ email: trim(vo.u.email),
345
+ description: trim(vo.u.description),
346
+ ruleGroupsIds: trim(vo.u.ruleGroupsIds),
347
+ from: trim(vo.u.from),
348
+ isVirtual: 'n', //儲存時則更改為非虛擬使用者, 也就是將外部系統(如SSO或AD)使用者資料另存至資料庫中, 用以識別
349
+ isAdmin: vo.u.isAdmin,
350
+ isActive: vo.u.isActive,
351
+ // userId, //insert時自動由後端給予
352
+ // timeCreate, //insert時自動由後端給予
353
+ // userIdUpdate: userId, //虛擬使用者皆與創建者相同
354
+ // timeUpdate: timeCreate,
355
+ }
356
+
357
+ //mode
358
+ let mode = 'save'
359
+ if (vo.u.isVirtual === 'y') { //若是儲存虛擬使用者, 代表是第1次儲存至資料庫中, 故需要insert來自動給予userId與timeCreate
360
+ mode = 'insert'
361
+ }
362
+ // console.log('vo.u.isVirtual', vo.u.isVirtual)
363
+
364
+ //insert or save
365
+ await vo.$fapi.users[mode](u)
366
+ .catch((err) => {
367
+ errTemp = err
368
+ })
369
+
370
+ //check
371
+ if (errTemp !== null) {
372
+ vo.$alert(`變更使用者失敗: ${errTemp}`, { type: 'error' })
373
+ return
374
+ }
375
+
376
+ //alert
377
+ vo.$alert(`變更使用者成功`)
378
+
379
+ }
380
+
381
+ //core
382
+ core()
383
+ .then(() => {
384
+
385
+ //resolve
386
+ vo.pm.resolve()
387
+
388
+ //hide
389
+ vo.bShow = false
390
+
391
+ })
392
+ .catch(() => { })
393
+ .finally(() => {
394
+
395
+ //save按鈕解除loading
396
+ msg.pm.resolve()
397
+
398
+ //hide loading
399
+ vo.$ui.updateLoading(false)
400
+
401
+ })
402
+
403
+ },
404
+
405
+ clickClose: function() {
406
+ //console.log('methods clickClose')
407
+
408
+ let vo = this
409
+
410
+ //reject
411
+ vo.pm.reject('close window')
412
+
413
+ //hide
414
+ vo.bShow = false
415
+
416
+ },
417
+
418
+ show: function (u) {
419
+ // console.log('methods show', u)
420
+
421
+ let vo = this
422
+
423
+ //pm
424
+ vo.pm = genPm()
425
+
426
+ //save u
427
+ u = cloneDeep(u)
428
+ vo.u = u
429
+
430
+ //save kpugs
431
+ let kpugs = {}
432
+ let ruleGroupsIds = get(u, 'ruleGroupsIds', '')
433
+ let s = sep(ruleGroupsIds, ';')
434
+ each(s, (v) => {
435
+ kpugs[v] = true
436
+ })
437
+ vo.kpugs = kpugs
438
+
439
+ //calcMergedGroup
440
+ vo.calcMergedGroup()
441
+
442
+ //bShow
443
+ vo.bShow = true
444
+
445
+ return vo.pm
446
+ },
447
+
448
+ }
449
+ }
450
+ </script>
451
+
452
+ <style scoped>
453
+ </style>