w-web-perm 1.0.12 → 1.0.13

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 (68) hide show
  1. package/.vscode/launch.json +0 -1
  2. package/README.md +0 -1
  3. package/dist/css/app.f22995d1.css +1 -0
  4. package/dist/index.tmp +1 -1
  5. package/dist/js/app-legacy.82274c39.js +2 -0
  6. package/dist/js/app-legacy.82274c39.js.map +1 -0
  7. package/dist/js/app.82274c39.js +2 -0
  8. package/dist/js/app.82274c39.js.map +1 -0
  9. package/dist/js/chunk-vendors-legacy.d89048a8.js +13 -0
  10. package/dist/js/chunk-vendors-legacy.d89048a8.js.map +1 -0
  11. package/dist/js/chunk-vendors.d89048a8.js +13 -0
  12. package/dist/js/chunk-vendors.d89048a8.js.map +1 -0
  13. package/dist/w-web-perm.umd.js +2 -2
  14. package/dist/w-web-perm.umd.js.map +1 -1
  15. package/docs/WWebPerm.html +2 -2
  16. package/docs/WWebPerm.mjs.html +212 -64
  17. package/docs/index.html +1 -1
  18. package/g.backupDb.mjs +1 -1
  19. package/g.initialData.mjs +211 -111
  20. package/g.initialTestData.mjs +2 -1
  21. package/g.mjs +0 -0
  22. package/g.provideGrups.mjs +87 -0
  23. package/g.providePemis.mjs +43 -0
  24. package/g.provideTargets.mjs +20 -13
  25. package/g.provideUsers.mjs +45 -13
  26. package/package.json +8 -8
  27. package/script.txt +5 -5
  28. package/server/WWebPerm.mjs +211 -63
  29. package/server/provideGrups.mjs +64 -0
  30. package/server/{provideRuleGroups.mjs → providePemis.mjs} +14 -15
  31. package/server/provideTargets.mjs +8 -5
  32. package/server/provideUsers.mjs +9 -9
  33. package/src/App.vue +16 -3
  34. package/src/components/Layout.vue +13 -5
  35. package/src/components/LayoutContent.vue +31 -16
  36. package/src/components/LayoutContentGrups.vue +793 -0
  37. package/src/components/LayoutContentPemis.vue +793 -0
  38. package/src/components/LayoutContentTargets.vue +481 -307
  39. package/src/components/LayoutContentUsers.vue +796 -291
  40. package/src/components/VeCgrups.vue +926 -0
  41. package/src/components/VeCpemis.vue +926 -0
  42. package/src/components/VeCrules.vue +820 -0
  43. package/src/main.js +2 -2
  44. package/src/perm.mjs +5 -5
  45. package/src/plugins/mShare.mjs +444 -153
  46. package/src/plugins/mUI.mjs +37 -19
  47. package/src/schema/gi.mjs +1 -1
  48. package/src/schema/index.mjs +4 -2
  49. package/src/schema/tables/grups.mjs +154 -0
  50. package/src/schema/tables/{ruleGroups.mjs → pemis.mjs} +27 -16
  51. package/src/schema/tables/targets.mjs +49 -16
  52. package/src/schema/tables/users.mjs +55 -27
  53. package/src/store/mutations.mjs +375 -150
  54. package/srv.mjs +2 -2
  55. package/tableTags-web-perm.json +1 -1
  56. package/dist/css/app.f6c50bec.css +0 -1
  57. package/dist/js/app-legacy.767522f1.js +0 -2
  58. package/dist/js/app-legacy.767522f1.js.map +0 -1
  59. package/dist/js/app.767522f1.js +0 -2
  60. package/dist/js/app.767522f1.js.map +0 -1
  61. package/dist/js/chunk-vendors-legacy.b0d63e17.js +0 -13
  62. package/dist/js/chunk-vendors-legacy.b0d63e17.js.map +0 -1
  63. package/dist/js/chunk-vendors.b0d63e17.js +0 -13
  64. package/dist/js/chunk-vendors.b0d63e17.js.map +0 -1
  65. package/g.provideRuleGroups.mjs +0 -56
  66. package/src/components/LayoutContentGroups.vue +0 -671
  67. package/src/components/VeUser.vue +0 -446
  68. package/src/components/ruleGroup.vue +0 -645
@@ -13,170 +13,124 @@
13
13
  >
14
14
 
15
15
  <!-- 標題區 -->
16
- <div style="display:inline-block; vertical-align:top; padding:10px 0px 5px 20px;">
17
- <div style="display:flex; align-items:center; padding:5px 15px 5px 5px; border-bottom:3px solid #FF9100;">
16
+ <div style="padding:10px 10px 10px 20px;">
17
+ <div :style="`display:flex; align-items:center; padding:${drawer?'5px':'5px 5px 5px 20px'};`">
18
18
 
19
19
  <WIcon
20
20
  :icon="mdiAccountGroupOutline"
21
- :color="'#FF9800'"
21
+ :color="'#000'"
22
+ :size="26"
22
23
  ></WIcon>
23
24
 
24
- <div style="padding-left:10px; font-size:1.3rem; color:#d3912c;">
25
- {{$t('userPermissions')}}
25
+ <div style="padding-left:10px; font-size:1.4rem; color:#000;">
26
+ {{$t('managementUsers')}}
26
27
  </div>
27
28
 
28
29
  </div>
29
30
  </div>
30
31
 
31
- <!-- 編輯設定區 -->
32
- <div style="display:inline-block; vertical-align:top;">
33
-
34
- <div style="padding:15px 20px 15px 20px; background:#fff;">
35
-
36
- <div style="display:flex;">
37
- <WSwitch
38
- :text="$t('isEditabled')"
39
- :checkedSwitchCircleColor="'#D81B60'"
40
- :checkedSwitchCircleColorHover="'#f26'"
41
- :checkedSwitchBarColor="'#F8BBD0'"
42
- :checkedSwitchBarColorHover="'#F8BBD0'"
43
- v-model="isOperatable"
44
- ></WSwitch>
45
- </div>
46
-
47
- <div style="padding-top:5px; font-size:0.8rem; _color:#f26;" v-if="isOperatable">
48
- <div style="padding:3px 0px;">
49
- 1. {{$t('userMsg1')}}
50
- </div>
51
- <div style="padding:3px 0px;">
52
- 2. {{$t('userMsg2')}}
53
- </div>
54
- </div>
55
-
56
- </div>
57
-
58
- </div>
59
-
60
- <!-- 儲存變更提示區 -->
61
- <div
62
- 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;"
63
- v-if="isModified"
64
- >
65
-
66
- <WButtonChip
67
- :paddingStyle="{v:0,h:11}"
68
- :text="$t('saveChanges')"
69
- :icon="mdiCloudUploadOutline"
70
- :backgroundColor="'rgba(255,0,50,0.7)'"
71
- :backgroundColorHover="'rgba(255,0,50,0.8)'"
72
- :textColor="'#eee'"
73
- :textColorHover="'#fff'"
74
- :iconColor="'#eee'"
75
- :iconColorHover="'#fff'"
76
- @click="saveGroups"
77
- ></WButtonChip>
32
+ <!-- 功能區 -->
33
+ <div style="padding:5px; border-top:1px solid #ddd; display:flex; align-items:center;">
34
+
35
+ <template>
36
+
37
+ <WButtonCircle
38
+ :paddingStyle="{v:6,h:6}"
39
+ :tooltip="$t('userAdd')"
40
+ :icon="mdiPlus"
41
+ :backgroundColor="'#fff'"
42
+ :backgroundColorHover="'#f2f2f2'"
43
+ _textColor="'#eee'"
44
+ _textColorHover="'#fff'"
45
+ :iconColor="'#444'"
46
+ :iconColorHover="'#222'"
47
+ :shadow="false"
48
+ @click="addItem"
49
+ ></WButtonCircle>
50
+
51
+ <div style="padding-left:6px;"></div>
52
+
53
+ </template>
54
+
55
+ <template v-if="hasItemCheckOne">
56
+
57
+ <WButtonCircle
58
+ :paddingStyle="{v:6,h:6}"
59
+ :tooltip="$t('userCopy')"
60
+ :icon="mdiContentCopy"
61
+ :backgroundColor="'#fff'"
62
+ :backgroundColorHover="'#f2f2f2'"
63
+ _textColor="'#eee'"
64
+ _textColorHover="'#fff'"
65
+ :iconColor="'#444'"
66
+ :iconColorHover="'#222'"
67
+ :shadow="false"
68
+ @click="copyItem"
69
+ ></WButtonCircle>
70
+
71
+ <div style="padding-left:6px;"></div>
72
+
73
+ </template>
74
+
75
+ <template v-if="hasItemsCheck">
76
+
77
+ <WButtonCircle
78
+ :paddingStyle="{v:6,h:6}"
79
+ :tooltip="$t('userDeleteChecks')"
80
+ :icon="mdiTrashCanOutline"
81
+ :backgroundColor="'#fff'"
82
+ :backgroundColorHover="'#f2f2f2'"
83
+ _textColor="'#eee'"
84
+ _textColorHover="'#fff'"
85
+ :iconColor="'#444'"
86
+ :iconColorHover="'#222'"
87
+ :shadow="false"
88
+ @click="deleteItemsCheck"
89
+ ></WButtonCircle>
90
+
91
+ <div style="padding-left:6px;"></div>
92
+
93
+ </template>
94
+
95
+ <template v-if="isModified">
96
+
97
+ <WButtonCircle
98
+ :paddingStyle="{v:6,h:6}"
99
+ :tooltip="$t('saveChanges')"
100
+ :icon="mdiCloudUploadOutline"
101
+ :backgroundColor="'rgba(255,0,50,0.7)'"
102
+ :backgroundColorHover="'rgba(255,0,50,0.8)'"
103
+ :textColor="'#eee'"
104
+ :textColorHover="'#fff'"
105
+ :iconColor="'#eee'"
106
+ :iconColorHover="'#fff'"
107
+ :shadow="false"
108
+ @click="saveUsers"
109
+ ></WButtonCircle>
110
+
111
+ <div style="padding-left:6px;"></div>
112
+
113
+ </template>
78
114
 
79
115
  </div>
80
116
 
81
117
  </div>
82
118
 
83
- <div
84
- :style="`padding:${spacePading}px;`"
119
+ <template
85
120
  v-if="!firstLoading"
86
121
  >
87
122
 
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
-
90
- <div
91
- style="padding:20px 10px 10px 20px; border-bottom:3px solid #ddd;"
92
- v-domresize
93
- @domresize="resizeGroupInfor"
94
- >
95
-
96
- <div style="padding:0px 10px 10px 0px; display:inline-block; vertical-align:middle; color:#666; font-size:1.1rem;">
97
- {{$t('userList')}}
98
- </div>
99
-
100
- <div
101
- style="padding:0px 10px 10px 0px; display:inline-block; vertical-align:middle;"
102
- v-if="isOperatable"
103
- >
104
-
105
- <WButtonChip
106
- :paddingStyle="{v:0,h:11}"
107
- :text="$t('addUser')"
108
- :icon="mdiAccountPlusOutline"
109
- :backgroundColor="'rgba(255,0,50,0.7)'"
110
- :backgroundColorHover="'rgba(255,0,50,0.8)'"
111
- :textColor="'#eee'"
112
- :textColorHover="'#fff'"
113
- :iconColor="'#eee'"
114
- :iconColorHover="'#fff'"
115
- @click="clickAddUser"
116
- ></WButtonChip>
117
-
118
- </div>
119
-
120
- </div>
121
-
122
- <WPanelScrolly
123
- :style="`height:${usersGroupsHeight}px; _overflow-y:auto;`"
123
+ <template v-if="items">
124
+ <WAggridVueDyn
125
+ ref="rftable"
126
+ :style="`width:100%;`"
127
+ :height="contentHeight"
128
+ :opt="opt"
124
129
  >
125
- <div style="padding:10px;">
126
-
127
- <div
128
- style="padding:10px;"
129
- :key="'kus:'+kus"
130
- v-for="(us,kus) in usersGroups"
131
- >
130
+ </WAggridVueDyn>
131
+ </template>
132
132
 
133
- <div style="padding-bottom:5px; display:flex; align-items:center; border-bottom:1px dashed #ddd;">
134
- <div style="padding-right:5px; color:#888; font-size:0.8rem;">
135
- {{$t('from')}}:
136
- </div>
137
- <div style="color:#000; font-size:0.8rem;">
138
- {{getFrom(kus)}}
139
- </div>
140
- </div>
141
-
142
- <div style="padding-top:10px;">
143
-
144
- <div
145
- style="display:inline-block; margin:0px 10px 10px 0px;"
146
- :key="'ku:'+ku"
147
- v-for="(u,ku) in us"
148
- >
149
-
150
- <WButtonChip
151
- :text="u.name"
152
- :paddingStyle="{
153
- v: 2,
154
- h: 12,
155
- }"
156
- :icon="getIsAdmin(u)?mdiChessRook:''"
157
- :backgroundColor="getIsNotActive(u)?'rgba(130,130,130,0.8)':getIsAdmin(u)?'rgba(216, 27, 96, 0.8)':'rgba(50,110,230,0.8)'"
158
- :backgroundColorHover="getIsNotActive(u)?'rgba(130,130,130,0.9)':getIsAdmin(u)?'rgba(216, 27, 96, 0.9)':'rgba(50,110,230,0.9)'"
159
- :textColor="'#eee'"
160
- :textColorHover="'#fff'"
161
- :iconColor="'#eee'"
162
- :iconColorHover="'#fff'"
163
- :close="isOperatable"
164
- @click="clickEditUser(u)"
165
- @click-close="clickRemoveUser(u)"
166
- ></WButtonChip>
167
-
168
- </div>
169
-
170
- </div>
171
-
172
- </div>
173
-
174
- </div>
175
- </WPanelScrolly>
176
-
177
- </div>
178
-
179
- </div>
133
+ </template>
180
134
 
181
135
  <div style="padding:10px 15px; font-size:0.8rem;" v-else>
182
136
  {{$t('waitingData')}}
@@ -186,69 +140,94 @@
186
140
  </template>
187
141
 
188
142
  <script>
189
- import { mdiAccountGroupOutline, mdiAccountPlusOutline, mdiCheckboxMarkedCircle, mdiChessRook } from '@mdi/js/mdi.js'
190
- import get from 'lodash-es/get.js'
191
- import each from 'lodash-es/each.js'
192
- import keys from 'lodash-es/keys.js'
193
- import sortBy from 'lodash-es/sortBy.js'
194
- import find from 'lodash-es/find.js'
195
- import size from 'lodash-es/size.js'
196
- import groupBy from 'lodash-es/groupBy.js'
197
- import genID from 'wsemi/src/genID.mjs'
143
+ import { mdiAccountGroupOutline, mdiVectorPolylinePlus, mdiCheckboxMarkedCircle, mdiCloudUploadOutline, mdiTrashCanOutline, mdiPlus, mdiPencilOutline, mdiContentCopy } from '@mdi/js/mdi.js'
144
+ import get from 'lodash-es/get.js'
145
+ import set from 'lodash-es/set.js'
146
+ import each from 'lodash-es/each.js'
147
+ import size from 'lodash-es/size.js'
148
+ import filter from 'lodash-es/filter.js'
149
+ import sortBy from 'lodash-es/sortBy.js'
150
+ import cloneDeep from 'lodash-es/cloneDeep.js'
151
+ import haskey from 'wsemi/src/haskey.mjs'
198
152
  import isestr from 'wsemi/src/isestr.mjs'
199
153
  import iseobj from 'wsemi/src/iseobj.mjs'
200
- import waitFun from 'wsemi/src/waitFun.mjs'
154
+ import cstr from 'wsemi/src/cstr.mjs'
201
155
  import WIcon from 'w-component-vue/src/components/WIcon.vue'
202
- import WButtonChip from 'w-component-vue/src/components/WButtonChip.vue'
203
- import WSwitch from 'w-component-vue/src/components/WSwitch.vue'
204
- import WPanelScrolly from 'w-component-vue/src/components/WPanelScrolly.vue'
156
+ import WButtonCircle from 'w-component-vue/src/components/WButtonCircle.vue'
157
+ import WAggridVueDyn from 'w-component-vue/src/components/WAggridVueDyn.vue'
205
158
 
206
159
 
207
160
  export default {
208
161
  components: {
209
162
  WIcon,
210
- WButtonChip,
211
- WSwitch,
212
- WPanelScrolly,
163
+ WButtonCircle,
164
+ WAggridVueDyn,
213
165
  },
214
166
  props: {
167
+ drawer: {
168
+ type: Boolean,
169
+ default: false,
170
+ },
215
171
  },
216
172
  data: function() {
217
173
  return {
218
174
  mdiAccountGroupOutline,
219
- mdiAccountPlusOutline,
175
+ mdiVectorPolylinePlus,
220
176
  mdiCheckboxMarkedCircle,
221
- mdiChessRook,
177
+ mdiCloudUploadOutline,
178
+ mdiTrashCanOutline,
179
+ mdiPlus,
180
+ mdiPencilOutline,
181
+ mdiContentCopy,
222
182
 
223
183
  panelWidth: 100,
224
184
  panelHeight: 100,
225
185
  headHeight: 100,
226
- groupInforHeight: 100,
227
186
 
228
187
  firstLoading: true,
229
- isOperatable: true,
230
188
  isModified: false,
231
189
 
232
- pickGroupId: '',
190
+ items: [],
191
+ itemsCheck: [],
192
+ opt: null,
233
193
 
234
194
  }
235
195
  },
196
+ mounted: function() {
197
+ // console.log('mounted')
198
+
199
+ let vo = this
200
+
201
+ //註冊至$dg供使用
202
+ vo.$dg.showVeCgrupsById = vo.showVeCgrupsById
203
+ vo.$dg.toggleItemIsAdminById = vo.toggleItemIsAdminById
204
+ vo.$dg.toggleItemIsActiveById = vo.toggleItemIsActiveById
205
+
206
+ },
236
207
  computed: {
237
208
 
238
- users: function() {
239
- return get(this, `$store.state.users`)
209
+ targets: function() {
210
+ let rs = get(this, `$store.state.targets`)
211
+ rs = sortBy(rs, 'order')
212
+ return rs
240
213
  },
241
214
 
242
- usersGroups: function() {
243
- let gs = groupBy(this.users, 'from')
244
- let ks = keys(gs)
245
- ks = sortBy(ks)
246
- let gsTemp = {}
247
- each(ks, (k) => {
248
- gsTemp[k] = gs[k]
249
- })
250
- gs = gsTemp
251
- return gs
215
+ pemis: function() {
216
+ let rs = get(this, `$store.state.pemis`)
217
+ rs = sortBy(rs, 'order')
218
+ return rs
219
+ },
220
+
221
+ grups: function() {
222
+ let rs = get(this, `$store.state.grups`)
223
+ rs = sortBy(rs, 'order')
224
+ return rs
225
+ },
226
+
227
+ users: function() {
228
+ let rs = get(this, `$store.state.users`)
229
+ rs = sortBy(rs, 'order')
230
+ return rs
252
231
  },
253
232
 
254
233
  changeUsers: function() {
@@ -261,31 +240,146 @@ export default {
261
240
  return ''
262
241
  }
263
242
 
243
+ //cloneDeep
244
+ let items = cloneDeep(vo.users)
245
+
246
+ //save
247
+ vo.items = items
248
+
249
+ //genOpt
250
+ vo.genOpt()
251
+
264
252
  //firstLoading
265
253
  vo.firstLoading = false
266
254
 
267
255
  return ''
268
256
  },
269
257
 
270
- spacePading: function() {
258
+ contentHeight: function() {
271
259
  let vo = this
272
- if (vo.panelWidth < 400) {
273
- return 0
274
- }
275
- else if (vo.panelWidth < 800) {
276
- return 10
277
- }
278
- return 20
260
+
261
+ //h
262
+ let h = vo.panelHeight - vo.headHeight
263
+ h = Math.max(h, 0)
264
+
265
+ return h
279
266
  },
280
267
 
281
- usersGroupsHeight: function() {
268
+ hasItemsCheck: function() {
282
269
  let vo = this
283
270
 
284
271
  //h
285
- let h = vo.panelHeight - vo.headHeight - 2 * vo.spacePading - vo.groupInforHeight
286
- h = Math.max(h, 0)
272
+ let b = size(vo.itemsCheck) > 0
287
273
 
288
- return h
274
+ return b
275
+ },
276
+
277
+ hasItemCheckOne: function() {
278
+ let vo = this
279
+
280
+ //h
281
+ let b = size(vo.itemsCheck) === 1
282
+
283
+ return b
284
+ },
285
+
286
+ errItemsByName: function() {
287
+ let vo = this
288
+
289
+ //rows
290
+ let rows = get(vo, 'opt.rows', [])
291
+
292
+ //kpErr
293
+ let kpErr = {}
294
+ let kpName = {}
295
+ each(rows, (v, k) => {
296
+
297
+ //name
298
+ let name = get(v, 'name', '')
299
+
300
+ //check
301
+ if (!isestr(name)) {
302
+
303
+ //kpErr
304
+ kpErr[name] = vo.$t(`userNameEmpty`)
305
+
306
+ return true //跳出換下一個
307
+ }
308
+
309
+ //check
310
+ if (haskey(kpName, name)) {
311
+
312
+ //kpErr
313
+ kpErr[name] = vo.$t(`userNameDuplicate`)
314
+
315
+ return true //跳出換下一個
316
+ }
317
+
318
+ //kpName
319
+ kpName[name] = true
320
+
321
+ })
322
+
323
+ return kpErr
324
+ },
325
+
326
+ errItemsByEmail: function() {
327
+ let vo = this
328
+
329
+ //rows
330
+ let rows = get(vo, 'opt.rows', [])
331
+
332
+ //kpErr
333
+ let kpErr = {}
334
+ let kpEmail = {}
335
+ each(rows, (v, k) => {
336
+
337
+ //email
338
+ let email = get(v, 'email', '')
339
+
340
+ //check
341
+ if (!isestr(email)) {
342
+
343
+ //kpErr
344
+ kpErr[email] = vo.$t(`userEmailEmpty`)
345
+
346
+ return true //跳出換下一個
347
+ }
348
+
349
+ //check
350
+ if (haskey(kpEmail, email)) {
351
+
352
+ //kpErr
353
+ kpErr[email] = vo.$t(`userEmailDuplicate`)
354
+
355
+ return true //跳出換下一個
356
+ }
357
+
358
+ //kpEmail
359
+ kpEmail[email] = true
360
+
361
+ })
362
+
363
+ return kpErr
364
+ },
365
+
366
+ isError: function() {
367
+ let vo = this
368
+
369
+ let c = ''
370
+ let b = false
371
+ b = iseobj(vo.errItemsByName)
372
+ if (b) {
373
+ c = vo.$t('errInNames')
374
+ return c
375
+ }
376
+ b = iseobj(vo.errItemsByEmail)
377
+ if (b) {
378
+ c = vo.$t('errInEmails')
379
+ return c
380
+ }
381
+
382
+ return ''
289
383
  },
290
384
 
291
385
  },
@@ -312,146 +406,574 @@ export default {
312
406
 
313
407
  },
314
408
 
315
- resizeGroupInfor: function(msg) {
316
- // console.log('methods resizeGroupInfor', msg)
409
+ genOpt: function() {
410
+ // console.log('methods genOpt')
317
411
 
318
412
  let vo = this
319
413
 
320
- //groupInforHeight
321
- vo.groupInforHeight = msg.snew.offsetHeight
414
+ //default
415
+ vo.itemsCheck = []
416
+
417
+ //opt
418
+ let opt = null
419
+ if (size(vo.items) > 0) {
420
+
421
+ //ks
422
+ let ks = [
423
+ 'id',
424
+ 'name',
425
+ 'email',
426
+ 'description',
427
+ 'from',
428
+ 'cgrups',
429
+ 'isAdmin',
430
+ 'isActive',
431
+ 'userId',
432
+ 'timeCreate',
433
+ 'userIdUpdate',
434
+ 'timeUpdate',
435
+ ]
436
+ // console.log('ks', ks)
437
+
438
+ //kpHead
439
+ let kpHead = {
440
+ 'id': vo.$t('id'),
441
+ 'name': vo.$t('name'),
442
+ 'email': vo.$t('email'),
443
+ 'description': vo.$t('description'),
444
+ 'from': vo.$t('from'),
445
+ 'cgrups': vo.$t('userCgrups'),
446
+ 'isAdmin': vo.$t('isAdmin'),
447
+ 'isActive': vo.$t('isActive'),
448
+ 'userId': vo.$t('userId'),
449
+ 'timeCreate': vo.$t('timeCreate'),
450
+ 'userIdUpdate': vo.$t('userIdUpdate'),
451
+ 'timeUpdate': vo.$t('timeUpdate'),
452
+ }
322
453
 
323
- },
454
+ //opt
455
+ opt = {
456
+ language: vo.$t('aggridLanguage'),
457
+ rows: vo.items,
458
+ keys: ks,
459
+ kpHead,
460
+ // autoFitColumn: true,
461
+ defHeadFilter: true,
462
+ defCellAlignH: 'left',
463
+ kpHeadHide: {
464
+ 'id': true,
465
+ },
466
+ kpHeadFixLeft: {
467
+ 'name': true,
468
+ },
469
+ defHeadMinWidth: 150,
470
+ kpHeadWidth: {
471
+ 'cgrups': 100,
472
+ 'isAdmin': 100,
473
+ 'isActive': 100,
474
+ 'timeCreate': 220,
475
+ 'timeUpdate': 220,
476
+ },
477
+ kpHeadFilterType: {
478
+ 'id': 'text',
479
+ 'name': 'text',
480
+ 'email': 'text',
481
+ 'description': 'text',
482
+ 'from': 'text',
483
+ 'cgrups': 'text',
484
+ 'isAdmin': 'text',
485
+ 'isActive': 'text',
486
+ 'userId': 'text',
487
+ 'timeCreate': 'text',
488
+ 'userIdUpdate': 'text',
489
+ 'timeUpdate': 'text',
490
+ },
491
+ kpCellEditable: {
492
+ 'name': true,
493
+ 'email': true,
494
+ 'description': true,
495
+ 'from': true,
496
+ },
497
+ kpRowDrag: {
498
+ 'name': true,
499
+ },
500
+ kpHeadCheckBox: {
501
+ 'name': true,
502
+ },
503
+ kpHeadFilter: {
504
+ 'cgrups': false,
505
+ },
506
+ kpHeadSort: {
507
+ 'cgrups': false,
508
+ },
509
+ kpHeadFocusHighlight: { //雖然效果不完全, 但因按鈕與cell有padding可被點擊, 故還是需要開啟
510
+ 'cgrups': false,
511
+ },
512
+ kpCellRender: {
513
+ 'name': (v) => {
514
+ // console.log('kpCellRender name', v)
515
+
516
+ //err
517
+ let err = get(vo.errItemsByName, v, '')
518
+ // console.log(v, err)
519
+
520
+ //check
521
+ if (isestr(err)) {
522
+ v = `
523
+ <span title="${err}">
524
+ <span style="color:#F57C00;">${cstr(v)}</span>
525
+ <img style="vertical-align:sub; width:16px; height:16px;" src="${vo.$ui.getIcon('warning')}" />
526
+ </span>
527
+ `
528
+ }
529
+
530
+ return v
531
+ },
532
+ 'email': (v) => {
533
+ // console.log('kpCellRender email', v)
534
+
535
+ //err
536
+ let err = get(vo.errItemsByEmail, v, '')
537
+ // console.log(v, err)
538
+
539
+ //check
540
+ if (isestr(err)) {
541
+ v = `
542
+ <span title="${err}">
543
+ <span style="color:#F57C00;">${cstr(v)}</span>
544
+ <img style="vertical-align:sub; width:16px; height:16px;" src="${vo.$ui.getIcon('warning')}" />
545
+ </span>
546
+ `
547
+ }
548
+
549
+ return v
550
+ },
551
+ 'cgrups': (v, k, r) => {
552
+ // console.log('kpCellRender cgrups', v, k, r)
553
+
554
+ //id
555
+ let id = get(r, 'id', '')
556
+ // console.log('id', id, k, r)
557
+
558
+ //因kpHeadFocusHighlight設定false時, 仍會於點擊其他可focus的cell, 再點回時依然出現highlight的focus邊框, 故改使用stopPropagation強制吃掉點擊訊息
559
+ //因stopPropagation只吃掉訊息, 原本focus會處於原本可focus的cell, 再重複點時會於前個focus的cell出現highlight邊框, 故再多使用preventDefault阻止瀏覽器預設行為, 此等同於return false
560
+ let t = `
561
+ <div onclick="event.stopPropagation();event.preventDefault();" onmousedown="event.stopPropagation();event.preventDefault();">
562
+ <button style="width:100%;" onclick="$vo.$dg.showVeCgrupsById('${id}')">${vo.$t('userEditCgrupsSimple')}</button>
563
+ </div>
564
+ `
565
+
566
+ return t
567
+ },
568
+ 'isAdmin': (v, k, r) => {
569
+ // console.log('kpCellRender isAdmin', v, k, r)
570
+
571
+ //id
572
+ let id = get(r, 'id', '')
573
+ // console.log('id', id, k, r)
574
+
575
+ let t = `
576
+ <input type="checkbox" ${v === 'y' ? 'checked' : ''} onclick="$vo.$dg.toggleItemIsAdminById('${id}')" />
577
+ `
578
+
579
+ return t
580
+ },
581
+ 'isActive': (v, k, r) => {
582
+ // console.log('kpCellRender isActive', v, k, r)
583
+
584
+ //id
585
+ let id = get(r, 'id', '')
586
+ // console.log('id', id, k, r)
587
+
588
+ let t = `
589
+ <input type="checkbox" ${v === 'y' ? 'checked' : ''} onclick="$vo.$dg.toggleItemIsActiveById('${id}')" />
590
+ `
591
+
592
+ return t
593
+ },
594
+ },
595
+ rowsChange: (rs) => {
596
+ // console.log('rowsChange', rs)
597
+ // console.log('rowsChange cloneDeep(vo.opt.rows)', cloneDeep(vo.opt.rows))
598
+
599
+ //isModified
600
+ vo.isModified = true
601
+
602
+ },
603
+ rowChecked: (rs) => {
604
+ // console.log('rowChecked', rs)
605
+ // console.log('rowChecked cloneDeep(vo.opt.rows)', cloneDeep(vo.opt.rows))
606
+
607
+ //save itemsCheck
608
+ vo.itemsCheck = cloneDeep(rs)
609
+
610
+ },
611
+ }
612
+ // console.log('opt', opt)
324
613
 
325
- getFrom: function(kus) {
326
- // console.log('methods getFrom', kus)
327
- let vo = this
328
- if (!isestr(kus)) {
329
- kus = vo.$t('empty')
330
614
  }
331
- return kus
615
+
616
+ //save
617
+ vo.opt = opt
618
+
332
619
  },
333
620
 
334
- getIsAdmin: function(u) {
335
- return get(u, 'isAdmin') === 'y'
621
+ refresh: function() {
622
+ let vo = this
623
+
624
+ //cmp
625
+ let cmp = get(vo, '$refs.rftable.$refs.$self')
626
+ // console.log('cmp', cmp)
627
+
628
+ //refresh, 因set不會觸發kpCellRender, 故須另外調用組件函數refresh, 進而觸發kpCellRender, 使能更新數據
629
+ cmp.refresh()
630
+
336
631
  },
337
632
 
338
- getIsNotActive: function(u) {
339
- return get(u, 'isActive') === 'n'
633
+ toggleItemIsAdminById: function(id) {
634
+ // console.log('toggleItemIsAdminById', id)
635
+
636
+ let vo = this
637
+
638
+ //k
639
+ let k = 'isAdmin'
640
+
641
+ //check
642
+ if (!isestr(id)) {
643
+ vo.$alert(`${vo.$t('userEditNoId')}`, { type: 'error' })
644
+ return
645
+ }
646
+
647
+ //rows
648
+ let rows = get(vo, 'opt.rows', [])
649
+
650
+ //find
651
+ let r = null
652
+ let kr = null
653
+ each(rows, (v, k) => {
654
+ if (get(v, 'id', '') === id) {
655
+ r = v
656
+ kr = k
657
+ return false //跳出
658
+ }
659
+ })
660
+
661
+ //check
662
+ if (!iseobj(r)) {
663
+ vo.$alert(`${vo.$t('userEditNoUser')}`, { type: 'error' })
664
+ return
665
+ }
666
+
667
+ //v
668
+ let _v = get(r, k, 'n')
669
+ let v = _v === 'y' ? 'n' : 'y'
670
+ // console.log(k, v)
671
+
672
+ //set
673
+ set(vo, `opt.rows[${kr}].${k}`, v)
674
+ // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
675
+
676
+ //refresh
677
+ vo.refresh()
678
+
679
+ //isModified
680
+ vo.isModified = true
681
+
340
682
  },
341
683
 
342
- clickAddUser: function() {
343
- // console.log('methods clickAddUser')
684
+ toggleItemIsActiveById: function(id) {
685
+ // console.log('toggleItemIsActiveById', id)
344
686
 
345
687
  let vo = this
346
688
 
347
- async function core() {
348
- let errTemp = null
689
+ //k
690
+ let k = 'isActive'
349
691
 
350
- //show loading
351
- vo.$ui.updateLoading(true)
692
+ //check
693
+ if (!isestr(id)) {
694
+ vo.$alert(`${vo.$t('userEditNoId')}`, { type: 'error' })
695
+ return
696
+ }
352
697
 
353
- //u
354
- let u = {
355
- id: genID(),
356
- name: vo.$t('newUser'),
357
- from: '',
358
- isAdmin: 'n',
359
- isActive: 'y',
698
+ //rows
699
+ let rows = get(vo, 'opt.rows', [])
700
+
701
+ //find
702
+ let r = null
703
+ let kr = null
704
+ each(rows, (v, k) => {
705
+ if (get(v, 'id', '') === id) {
706
+ r = v
707
+ kr = k
708
+ return false //跳出
360
709
  }
710
+ })
361
711
 
362
- //save
363
- await vo.$fapi.users.insert(u)
364
- .catch((err) => {
365
- errTemp = err
366
- })
712
+ //check
713
+ if (!iseobj(r)) {
714
+ vo.$alert(`${vo.$t('userEditNoUser')}`, { type: 'error' })
715
+ return
716
+ }
367
717
 
368
- //check
369
- if (errTemp !== null) {
370
- vo.$alert(`${vo.$t('failedToAddUser')}: ${errTemp}`, { type: 'error' })
718
+ //v
719
+ let _v = get(r, k, 'n')
720
+ let v = _v === 'y' ? 'n' : 'y'
721
+ // console.log(k, v)
722
+
723
+ //set
724
+ set(vo, `opt.rows[${kr}].${k}`, v)
725
+ // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
726
+
727
+ //refresh
728
+ vo.refresh()
729
+
730
+ //isModified
731
+ vo.isModified = true
732
+
733
+ },
734
+
735
+ addItem: function() {
736
+ // console.log('method addItem')
737
+
738
+ let vo = this
739
+
740
+ //cloneDeep
741
+ let rows = get(vo, 'opt.rows', [])
742
+
743
+ //cloneDeep
744
+ rows = cloneDeep(rows)
745
+
746
+ //r
747
+ let r = vo.$ds.users.funNew()
748
+ r.name = vo.$s.getNameNew(rows, 'name', '', vo.$t('userAddNameNew'))
749
+ r.userId = `{${vo.$t('userAddIdNew')}}`
750
+ r.timeCreate = `{${vo.$t('userAddIdNew')}}`
751
+ r.userIdUpdate = `{${vo.$t('userAddIdNew')}}`
752
+ r.timeUpdate = `{${vo.$t('userAddIdNew')}}`
753
+ // console.log('r', r)
754
+
755
+ //添加至最首
756
+ rows = [
757
+ r,
758
+ ...rows,
759
+ ]
760
+
761
+ //save
762
+ vo.opt.rows = rows
763
+ // console.log('cloneDeep(vo.opt.rows)', cloneDeep(vo.opt.rows))
764
+
765
+ //isModified
766
+ vo.isModified = true
767
+
768
+ },
769
+
770
+ copyItem: function() {
771
+ // console.log('method copyItem')
772
+
773
+ let vo = this
774
+
775
+ //check
776
+ if (size(vo.itemsCheck) !== 1) {
777
+ console.log(`size(vo.itemsCheck) !== 1`, vo.itemsCheck)
778
+ vo.$alert(`${vo.$t('anUnexpectedErrorOccurred')}`, { type: 'error' })
779
+ return
780
+ }
781
+
782
+ //cloneDeep
783
+ let rows = get(vo, 'opt.rows', [])
784
+
785
+ //cloneDeep
786
+ rows = cloneDeep(rows)
787
+
788
+ //find
789
+ let tar = vo.itemsCheck[0]
790
+ let tarId = get(tar, 'data.id', '')
791
+ let row = null
792
+ each(rows, (v) => {
793
+ let id = get(v, 'id', '')
794
+ if (id === tarId) {
795
+ row = v
796
+ return false //跳出
371
797
  }
798
+ })
799
+ // console.log('tar', tar)
800
+ // console.log('row', row)
372
801
 
373
- //un
374
- let un = null
375
- await waitFun(() => {
376
- un = find(vo.users, { id: u.id })
377
- return iseobj(un) //確認g.id已存在
378
- })
379
- // console.log('un', un)
802
+ //check
803
+ if (!iseobj(row)) {
804
+ console.log(`!iseobj(row)`, row)
805
+ vo.$alert(`${vo.$t('anUnexpectedErrorOccurred')}`, { type: 'error' })
806
+ return
807
+ }
380
808
 
381
- //showVeUser
382
- vo.$dg.showVeUser(un)
383
- .catch(() => {})
809
+ //r
810
+ let r = cloneDeep(row)
811
+ let nameOld = r.name
812
+ let _r = vo.$ds.users.funNew()
813
+ r.id = _r.id //使用新建方式預先產生id避免重複
814
+ r.name = vo.$s.getNameNew(rows, 'name', nameOld, vo.$t('userCopyNameNew'))
815
+ r.userId = `{${vo.$t('userAddIdNew')}}`
816
+ r.timeCreate = `{${vo.$t('userAddIdNew')}}`
817
+ r.userIdUpdate = `{${vo.$t('userAddIdNew')}}`
818
+ r.timeUpdate = `{${vo.$t('userAddIdNew')}}`
819
+ // console.log('r', r)
820
+
821
+ //添加至最首
822
+ rows = [
823
+ r,
824
+ ...rows,
825
+ ]
826
+
827
+ //save
828
+ vo.opt.rows = rows
829
+ // console.log('cloneDeep(vo.opt.rows)', cloneDeep(vo.opt.rows))
830
+
831
+ //isModified
832
+ vo.isModified = true
384
833
 
385
- //alert
386
- vo.$alert(vo.$t('successfulToAddUser'))
834
+ },
835
+
836
+ deleteItemsCheck: function() {
837
+ // console.log('method deleteItemsCheck')
387
838
 
839
+ let vo = this
840
+
841
+ //check
842
+ if (size(vo.itemsCheck) === 0) {
843
+ console.log(`size(vo.itemsCheck) === 0`, vo.itemsCheck)
844
+ vo.$alert(`${vo.$t('anUnexpectedErrorOccurred')}`, { type: 'error' })
845
+ return
388
846
  }
389
847
 
390
- //core
391
- core()
392
- // .then((res) => {
393
- // console.log('then', res)
394
- // })
395
- .catch((err) => {
396
- console.log('catch', err)
397
- vo.$alert(vo.$t('anUnexpectedErrorOccurred'), { type: 'error' })
848
+ //cloneDeep
849
+ let rows = get(vo, 'opt.rows', [])
850
+
851
+ //cloneDeep
852
+ rows = cloneDeep(rows)
853
+
854
+ //filter
855
+ each(vo.itemsCheck, (v) => {
856
+ // console.log('v', v)
857
+ let id = get(v, 'data.id', '')
858
+ if (!isestr(id)) {
859
+ console.log(`invalid id`)
860
+ return true //跳出換下一個
861
+ }
862
+ rows = filter(rows, (vv) => {
863
+ return vv.id !== id
398
864
  })
399
- .finally(() => {
865
+ })
400
866
 
401
- //hide loading
402
- vo.$ui.updateLoading(false)
867
+ //clear
868
+ vo.itemsCheck = []
869
+
870
+ //save
871
+ vo.opt.rows = rows
872
+ // console.log('deleteItemsCheck cloneDeep(vo.opt.rows)', cloneDeep(vo.opt.rows))
873
+
874
+ //isModified
875
+ vo.isModified = true
876
+
877
+ },
878
+
879
+ showVeCgrupsById: function(id) {
880
+ // console.log('method showVeCgrupsById', id)
881
+
882
+ let vo = this
883
+
884
+ //check
885
+ if (!isestr(id)) {
886
+ vo.$alert(`${vo.$t('userEditCgrupsNoId')}`, { type: 'error' })
887
+ return
888
+ }
889
+
890
+ //rows
891
+ let rows = get(vo, 'opt.rows', [])
892
+
893
+ //find
894
+ let r = null
895
+ let kr = null
896
+ each(rows, (v, k) => {
897
+ if (get(v, 'id', '') === id) {
898
+ r = v
899
+ kr = k
900
+ return false //跳出
901
+ }
902
+ })
903
+
904
+ //check
905
+ if (!iseobj(r)) {
906
+ vo.$alert(`${vo.$t('userEditCgrupsNoUser')}`, { type: 'error' })
907
+ return
908
+ }
909
+
910
+ // //getUserRules
911
+ // let ur = vo.$s.getUserRules(r, vo.grups, vo.pemis, vo.targets)
912
+ // console.log('getUserRules ur', ur)
913
+
914
+ //showVeCgrups
915
+ vo.$dg.showVeCgrups(r)
916
+ .then((cgrups) => {
917
+ // console.log('cgrups', cgrups)
918
+
919
+ //set
920
+ set(vo, `opt.rows[${kr}].cgrups`, cgrups)
921
+ // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
922
+
923
+ //refresh
924
+ vo.refresh()
925
+
926
+ //isModified
927
+ vo.isModified = true
403
928
 
404
929
  })
930
+ .catch(() => {})
405
931
 
406
932
  },
407
933
 
408
- clickRemoveUser: function(u) {
409
- // console.log('methods clickRemoveUser', u)
934
+ saveUsers: function() {
935
+ // console.log('method saveUsers')
410
936
 
411
937
  let vo = this
412
938
 
413
939
  async function core() {
414
940
  let errTemp = null
415
941
 
416
- //showCheckYesNo
417
- let bExit = false
418
- let t_confirmToDeleteUser = vo.$t('confirmToDeleteUser')
419
- t_confirmToDeleteUser = t_confirmToDeleteUser.replace('{name}', u.name)
420
- await vo.$dg.showCheckYesNo(t_confirmToDeleteUser)
421
- .catch(() => {
422
- bExit = true
423
- })
424
- if (bExit) {
942
+ //show loading
943
+ vo.$ui.updateLoading(true)
944
+
945
+ //check
946
+ if (isestr(vo.isError)) {
947
+ vo.$alert(`${vo.isError}`, { type: 'error' })
425
948
  return
426
949
  }
427
950
 
428
- //show loading
429
- vo.$ui.updateLoading(true)
951
+ //rows
952
+ let rows = get(vo, 'opt.rows', [])
430
953
 
431
- //save
432
- await vo.$fapi.users.del(u)
954
+ //check
955
+ if (size(rows) === 0) {
956
+ vo.$alert(`${vo.$t('userAddEmpty')}`, { type: 'error' })
957
+ return
958
+ }
959
+
960
+ //updateUsers
961
+ await vo.$fapi.updateUsers(rows)
433
962
  .catch((err) => {
434
963
  errTemp = err
435
964
  })
436
965
 
437
966
  //check
438
967
  if (errTemp !== null) {
439
- vo.$alert(`${vo.$t('failedToDeleteUser')}: ${errTemp}`, { type: 'error' })
968
+ vo.$alert(`${vo.$t('userSaveUsersFail')}: ${errTemp}`, { type: 'error' })
440
969
  return
441
970
  }
442
971
 
443
- //un
444
- let un = null
445
- await waitFun(() => {
446
- un = find(vo.users, (v) => {
447
- return v.id === u.id
448
- })
449
- return !iseobj(un) //確認g.id已不存在
450
- })
451
- // console.log('un', un)
972
+ //isModified
973
+ vo.isModified = false
452
974
 
453
975
  //alert
454
- vo.$alert(vo.$t('successfulToDeleteUser'))
976
+ vo.$alert(vo.$t('userSaveUsersSuccess'))
455
977
 
456
978
  }
457
979
 
@@ -473,23 +995,6 @@ export default {
473
995
 
474
996
  },
475
997
 
476
- clickEditUser: function(u) {
477
- // console.log('clickEditGroup', u)
478
-
479
- let vo = this
480
-
481
- //check
482
- if (!vo.isOperatable) {
483
- vo.$alert(vo.$t('cannotShowUserDetailsInViewMode'), { type: 'error' })
484
- return
485
- }
486
-
487
- //showVeUser
488
- vo.$dg.showVeUser(u)
489
- .catch(() => {})
490
-
491
- },
492
-
493
998
  }
494
999
  }
495
1000
  </script>