w-web-perm 1.1.11 → 1.1.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 (122) hide show
  1. package/README.md +158 -117
  2. package/dist/css/app.f09c7433.css +1 -0
  3. package/dist/index.tmp +1 -1
  4. package/dist/js/app-legacy.8af87052.js +1 -0
  5. package/dist/js/app.8af87052.js +1 -0
  6. package/dist/js/{chunk-vendors.3e9e3ef1.js → chunk-vendors-legacy.ece5a361.js} +1 -1
  7. package/dist/js/{chunk-vendors-legacy.3e9e3ef1.js → chunk-vendors.ece5a361.js} +1 -1
  8. package/dist/w-web-perm.umd.js +2 -2
  9. package/dist/w-web-perm.umd.js.map +1 -1
  10. package/docs/WWebPerm.html +84 -4
  11. package/docs/global.html +24747 -832
  12. package/docs/index.html +2 -2
  13. package/docs/server_WWebPerm.mjs.html +245 -32
  14. package/docs/server_cascadeWrite.mjs.html +225 -0
  15. package/docs/server_dataChannel.mjs.html +2 -2
  16. package/docs/server_keyCheck.mjs.html +353 -0
  17. package/docs/server_lockSave.mjs.html +2 -2
  18. package/docs/server_maskLog.mjs.html +2 -2
  19. package/docs/server_procCore.mjs.html +180 -41
  20. package/docs/server_staLogs_resolveShellWorker.mjs.html +2 -2
  21. package/docs/server_syncKeep.mjs.html +311 -0
  22. package/docs/server_tools_authRefsAudit.mjs.html +247 -0
  23. package/docs/server_tools_authRefsClean.mjs.html +335 -0
  24. package/docs/server_tools_fromTools.mjs.html +797 -0
  25. package/docs/server_tools_isMain.mjs.html +103 -0
  26. package/docs/server_tools_nameDupReport.mjs.html +280 -0
  27. package/docs/server_validateRows.mjs.html +15 -4
  28. package/docs/server_wrapInjected.mjs.html +3 -3
  29. package/docs/src_fetchJson.mjs.html +2 -2
  30. package/docs/src_js_cvKpToArr.mjs.html +125 -0
  31. package/docs/src_js_cvKpToObj.mjs.html +210 -0
  32. package/docs/src_js_draftSync.mjs.html +142 -0
  33. package/docs/src_js_eachOwn.mjs.html +3 -3
  34. package/docs/src_js_editorRefRows.mjs.html +356 -0
  35. package/docs/src_js_externalRows.mjs.html +338 -0
  36. package/docs/src_js_externalUi.mjs.html +230 -0
  37. package/docs/src_js_findRefRows.mjs.html +107 -0
  38. package/docs/src_js_findTouchedDup.mjs.html +150 -0
  39. package/docs/src_js_fmtLossyMsg.mjs.html +95 -0
  40. package/docs/src_js_fromAudit.mjs.html +489 -0
  41. package/docs/src_js_getAddImpact.mjs.html +269 -0
  42. package/docs/src_js_getAuthWarn.mjs.html +463 -0
  43. package/docs/src_js_getCascadePreview.mjs.html +258 -0
  44. package/docs/src_js_getDelRefCount.mjs.html +210 -0
  45. package/docs/src_js_getEffMode.mjs.html +92 -0
  46. package/docs/src_js_getKpLossy.mjs.html +155 -0
  47. package/docs/src_js_getNameErrs.mjs.html +266 -0
  48. package/docs/src_js_getOwn.mjs.html +3 -3
  49. package/docs/src_js_getPropKey.mjs.html +109 -0
  50. package/docs/src_js_getRuleEnable.mjs.html +2 -2
  51. package/docs/src_js_isAuthMode.mjs.html +92 -0
  52. package/docs/src_js_joinNames.mjs.html +96 -0
  53. package/docs/src_js_legendFit.mjs.html +2 -2
  54. package/docs/src_js_pairRowsToSnapshot.mjs.html +156 -0
  55. package/docs/src_js_refAudit.mjs.html +359 -0
  56. package/docs/src_js_refCascade.mjs.html +572 -0
  57. package/docs/src_js_relDialogSend.mjs.html +199 -0
  58. package/docs/src_js_rowDigest.mjs.html +265 -0
  59. package/docs/src_plugins_dataReloadGuard.mjs.html +109 -0
  60. package/docs/src_plugins_reuseDeletedIds.mjs.html +2 -2
  61. package/docs/src_plugins_submitGuard.mjs.html +2 -2
  62. package/g_authRefsClean.mjs +79 -0
  63. package/g_fixFromType.mjs +92 -0
  64. package/g_initialData.mjs +3 -3
  65. package/g_purgeFrom.mjs +127 -0
  66. package/package.json +1 -1
  67. package/server/WWebPerm.mjs +243 -30
  68. package/server/cascadeWrite.mjs +153 -0
  69. package/server/keyCheck.mjs +281 -0
  70. package/server/procCore.mjs +178 -39
  71. package/server/procLang.mjs +271 -0
  72. package/server/syncKeep.mjs +239 -0
  73. package/server/tools/authRefsAudit.mjs +175 -0
  74. package/server/tools/authRefsClean.mjs +263 -0
  75. package/server/tools/fromTools.mjs +725 -0
  76. package/server/tools/isMain.mjs +31 -0
  77. package/server/tools/nameDupReport.mjs +208 -0
  78. package/server/validateRows.mjs +13 -2
  79. package/server/wrapInjected.mjs +1 -1
  80. package/src/components/LayoutContentGrups.vue +399 -77
  81. package/src/components/LayoutContentPemis.vue +400 -78
  82. package/src/components/LayoutContentTargets.vue +261 -25
  83. package/src/components/LayoutContentUsers.vue +336 -98
  84. package/src/components/VeCgrups.vue +119 -115
  85. package/src/components/VeCpemis.vue +117 -115
  86. package/src/components/VeCrules.vue +18 -2
  87. package/src/components/VeGrupBlngUsers.vue +240 -73
  88. package/src/components/VePemiBlngGrups.vue +247 -83
  89. package/src/js/cvKpToArr.mjs +53 -0
  90. package/src/js/cvKpToObj.mjs +138 -0
  91. package/src/js/draftSync.mjs +70 -0
  92. package/src/js/eachOwn.mjs +1 -1
  93. package/src/js/editorRefRows.mjs +284 -0
  94. package/src/js/externalRows.mjs +266 -0
  95. package/src/js/externalUi.mjs +158 -0
  96. package/src/js/findRefRows.mjs +35 -0
  97. package/src/js/findTouchedDup.mjs +78 -0
  98. package/src/js/fmtLossyMsg.mjs +23 -0
  99. package/src/js/fromAudit.mjs +417 -0
  100. package/src/js/getAddImpact.mjs +197 -0
  101. package/src/js/getAuthWarn.mjs +391 -0
  102. package/src/js/getCascadePreview.mjs +186 -0
  103. package/src/js/getDelRefCount.mjs +138 -0
  104. package/src/js/getEffMode.mjs +20 -0
  105. package/src/js/getKpLossy.mjs +83 -0
  106. package/src/js/getNameErrs.mjs +194 -0
  107. package/src/js/getOwn.mjs +1 -1
  108. package/src/js/getPropKey.mjs +37 -0
  109. package/src/js/isAuthMode.mjs +20 -0
  110. package/src/js/joinNames.mjs +24 -0
  111. package/src/js/pairRowsToSnapshot.mjs +84 -0
  112. package/src/js/refAudit.mjs +287 -0
  113. package/src/js/refCascade.mjs +500 -0
  114. package/src/js/relDialogSend.mjs +127 -0
  115. package/src/js/rowDigest.mjs +193 -0
  116. package/src/plugins/dataReloadGuard.mjs +37 -0
  117. package/src/plugins/mShare.mjs +147 -174
  118. package/src/plugins/mUI.mjs +3 -8
  119. package/src/schema/tables/users.mjs +152 -152
  120. package/dist/css/app.6918ec45.css +0 -1
  121. package/dist/js/app-legacy.963e800c.js +0 -1
  122. package/dist/js/app.963e800c.js +0 -1
@@ -25,6 +25,16 @@
25
25
  @domresize="resizeHead"
26
26
  >
27
27
 
28
+ <!-- 無法掛在任何一列之警告: 理由同 VeCgrups 該處註解(R-PRINCIPLE-00 f) -->
29
+ <div
30
+ style="padding:10px 15px; font-size:0.8rem; color:#F57C00; display:flex; align-items:center;"
31
+ :title="lossyHintTitle"
32
+ v-if="lossyHint"
33
+ >
34
+ <img style="flex:0 0 auto; width:16px; height:16px; margin-right:4px;" :src="$ui.getIcon('warning')" />
35
+ <span>{{ lossyHint }}</span>
36
+ </div>
37
+
28
38
  <!-- 功能區 -->
29
39
  <div
30
40
  style="padding:5px; background:#fff; display:flex; align-items:center;"
@@ -127,7 +137,11 @@
127
137
  :opt="opt"
128
138
  >
129
139
  <template v-slot:cell-render="props">
130
- <span v-if="props.key==='name'">{{ props.value }}</span>
140
+ <template v-if="props.key==='name'">
141
+ <!-- 警告圖示: 理由同 VeCgrups 該處註解(無警告者與修前同一節點) -->
142
+ <span :title="props.row.warnText" v-if="props.row.warnText"><img style="vertical-align:sub; width:16px; height:16px; margin-right:4px;" :src="$ui.getIcon('warning')" />{{ props.value }}</span>
143
+ <span v-else>{{ props.value }}</span>
144
+ </template>
131
145
  <!-- flex 置中容器: 理由同 VeCgrups 該處註解 -->
132
146
  <div
133
147
  style="display:flex; align-items:center; height:100%;"
@@ -171,12 +185,17 @@ import map from 'lodash-es/map.js'
171
185
  import size from 'lodash-es/size.js'
172
186
  import filter from 'lodash-es/filter.js'
173
187
  import sortBy from 'lodash-es/sortBy.js'
188
+ import isEqual from 'lodash-es/isEqual.js'
174
189
  import cloneDeep from 'lodash-es/cloneDeep.js'
175
190
  import genPm from 'wsemi/src/genPm.mjs'
176
191
  import delay from 'wsemi/src/delay.mjs'
177
- import iseobj from 'wsemi/src/iseobj.mjs'
178
192
  import isestr from 'wsemi/src/isestr.mjs'
179
193
  import getOwn from '../js/getOwn.mjs'
194
+ import cvKpToObj from '../js/cvKpToObj.mjs'
195
+ import getKpLossy from '../js/getKpLossy.mjs'
196
+ import fmtLossyMsg from '../js/fmtLossyMsg.mjs'
197
+ import { getRefState, getRefRowsExtra, getDupRowsInconsistent, getRawModeMap, putRowsToKp, getRowIdxs } from '../js/editorRefRows.mjs'
198
+ import { getRefWarns, getItemWarnText, fmtWarn } from '../js/getAuthWarn.mjs'
180
199
  import WDialog from 'w-component-vue/src/components/WDialog.vue'
181
200
  import WButtonCircle from 'w-component-vue/src/components/WButtonCircle.vue'
182
201
  import WAggridVue from 'w-aggrid-vue/src/components/WAggridVue.vue'
@@ -223,6 +242,9 @@ export default {
223
242
  itemsCheck: [],
224
243
  opt: null,
225
244
 
245
+ lossyHint: '', //無法掛在任何一列之警告文字(啟用而名稱非字串之項目), 無則 ''
246
+ lossyHintTitle: '',
247
+
226
248
  }
227
249
  },
228
250
  mounted: function() {
@@ -531,8 +553,8 @@ export default {
531
553
 
532
554
  let vo = this
533
555
 
534
- //check
535
- if (!isestr(name)) {
556
+ //check, 名稱 '' 為合法名稱(R-PRINCIPLE-00 f: 懸空之額外列可為 '', 須可改 mode/停用), 僅非字串者拒絕
557
+ if (typeof name !== 'string') {
536
558
  vo.$alert(`${vo.$t('cpemiEditNoName')}`, { type: 'error' })
537
559
  return
538
560
  }
@@ -540,30 +562,19 @@ export default {
540
562
  //rows
541
563
  let rows = get(vo, 'opt.rows', [])
542
564
 
543
- //find
544
- let r = null
545
- let kr = null
546
- each(rows, (v, k) => {
547
- if (get(v, 'name', '') === name) {
548
- r = v
549
- kr = k
550
- return false //跳出
551
- }
552
- })
565
+ //krs, 精確同名之全部列(getRowIdxs; 理由同 VeCgrups.showVeCgrupsToggleItemModeByName)
566
+ let krs = getRowIdxs(rows, 'name', name)
553
567
 
554
568
  //check
555
- if (!iseobj(r)) {
569
+ if (size(krs) === 0) {
556
570
  vo.$alert(`${vo.$t('cpemiEditNoTarget')}`, { type: 'error' })
557
571
  return
558
572
  }
559
573
 
560
- //mode
561
- // let mode = th.value
562
- // console.log('mode', mode)
563
-
564
574
  //set
565
- set(vo, `opt.rows[${kr}].mode`, mode)
566
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
575
+ each(krs, (kr) => {
576
+ set(vo, `opt.rows[${kr}].mode`, mode)
577
+ })
567
578
 
568
579
  //refresh
569
580
  vo.refresh()
@@ -578,8 +589,8 @@ export default {
578
589
 
579
590
  let vo = this
580
591
 
581
- //check
582
- if (!isestr(name)) {
592
+ //check, 名稱 '' 為合法名稱(同 showVeCpemisToggleItemModeByName)
593
+ if (typeof name !== 'string') {
583
594
  vo.$alert(`${vo.$t('cpemiEditNoName')}`, { type: 'error' })
584
595
  return
585
596
  }
@@ -587,31 +598,24 @@ export default {
587
598
  //rows
588
599
  let rows = get(vo, 'opt.rows', [])
589
600
 
590
- //find
591
- let r = null
592
- let kr = null
593
- each(rows, (v, k) => {
594
- if (get(v, 'name', '') === name) {
595
- r = v
596
- kr = k
597
- return false //跳出
598
- }
599
- })
601
+ //krs, 精確同名之全部列(理由同 showVeCpemisToggleItemModeByName)
602
+ let krs = getRowIdxs(rows, 'name', name)
600
603
 
601
604
  //check
602
- if (!iseobj(r)) {
605
+ if (size(krs) === 0) {
603
606
  vo.$alert(`${vo.$t('cpemiEditNoTarget')}`, { type: 'error' })
604
607
  return
605
608
  }
606
609
 
607
- //enable
608
- let _enable = get(r, 'enable', 'n')
610
+ //enable, 同名列狀態恆一致, 取第一列切換後套用全部
611
+ let _enable = get(rows[krs[0]], 'enable', 'n')
609
612
  let enable = _enable === 'y' ? 'n' : 'y'
610
613
  // console.log('enable', enable)
611
614
 
612
615
  //set
613
- set(vo, `opt.rows[${kr}].enable`, enable)
614
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
616
+ each(krs, (kr) => {
617
+ set(vo, `opt.rows[${kr}].enable`, enable)
618
+ })
615
619
 
616
620
  //refresh
617
621
  vo.refresh()
@@ -630,26 +634,15 @@ export default {
630
634
  let rows = get(vo, 'opt.rows', [])
631
635
  // console.log('rows', rows)
632
636
 
633
- //kpRow
634
- let kpRow = Object.create(null) //無原型: 鍵為使用者資料, 不得命中 constructor 等原型鍵(規則帳本 R-KEY-01)
635
- each(rows, (r, kr) => {
636
- kpRow[r.name] = kr
637
- })
638
-
639
637
  //rowsEff
640
638
  let rowsEff = vo.getDisplayData()
641
639
  // console.log('rowsEff', rowsEff)
642
640
 
643
- //toggle
641
+ //toggle, 每個顯示中之列對其精確同名之全部列一併套用(getRowIdxs; 理由同 VeCgrups.showVeCgrupsToggleItemsEnableAllYes)
644
642
  each(rowsEff, (r) => {
645
-
646
- //kr
647
- let kr = kpRow[r.name]
648
-
649
- //set
650
- set(vo, `opt.rows[${kr}].enable`, 'y')
651
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
652
-
643
+ each(getRowIdxs(rows, 'name', r.name), (kr) => {
644
+ set(vo, `opt.rows[${kr}].enable`, 'y')
645
+ })
653
646
  })
654
647
 
655
648
  //refresh
@@ -669,26 +662,15 @@ export default {
669
662
  let rows = get(vo, 'opt.rows', [])
670
663
  // console.log('rows', rows)
671
664
 
672
- //kpRow
673
- let kpRow = Object.create(null)
674
- each(rows, (r, kr) => {
675
- kpRow[r.name] = kr
676
- })
677
-
678
665
  //rowsEff
679
666
  let rowsEff = vo.getDisplayData()
680
667
  // console.log('rowsEff', rowsEff)
681
668
 
682
- //toggle
669
+ //toggle, 對精確同名之全部列一併套用(理由同 showVeCpemisToggleItemsEnableAllYes)
683
670
  each(rowsEff, (r) => {
684
-
685
- //kr
686
- let kr = kpRow[r.name]
687
-
688
- //set
689
- set(vo, `opt.rows[${kr}].enable`, 'n')
690
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
691
-
671
+ each(getRowIdxs(rows, 'name', r.name), (kr) => {
672
+ set(vo, `opt.rows[${kr}].enable`, 'n')
673
+ })
692
674
  })
693
675
 
694
676
  //refresh
@@ -708,29 +690,21 @@ export default {
708
690
  let rows = get(vo, 'opt.rows', [])
709
691
  // console.log('rows', rows)
710
692
 
711
- //kpRow
712
- let kpRow = Object.create(null)
713
- each(rows, (r, kr) => {
714
- kpRow[r.name] = kr
715
- })
716
-
717
693
  //rowsEff
718
694
  let rowsEff = vo.getDisplayData()
719
695
  // console.log('rowsEff', rowsEff)
720
696
 
721
- //toggle
697
+ //toggle, 對精確同名之全部列一併套用(理由同 showVeCpemisToggleItemsEnableAllYes; 同名列狀態一致, 各顯示列算出之反向值相同)
722
698
  each(rowsEff, (r) => {
723
699
 
724
- //kr
725
- let kr = kpRow[r.name]
726
-
727
700
  //enable
728
701
  let _enable = get(r, 'enable', 'n')
729
702
  let enable = _enable === 'y' ? 'n' : 'y'
730
703
 
731
704
  //set
732
- set(vo, `opt.rows[${kr}].enable`, enable)
733
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
705
+ each(getRowIdxs(rows, 'name', r.name), (kr) => {
706
+ set(vo, `opt.rows[${kr}].enable`, enable)
707
+ })
734
708
 
735
709
  })
736
710
 
@@ -787,31 +761,34 @@ export default {
787
761
  let rows = get(vo, 'opt.rows', [])
788
762
  // console.log('rows', rows)
789
763
 
790
- //kpPemi
791
- let kpPemi = Object.create(null)
792
- each(rows, (r) => {
793
- let name = get(r, 'name', '')
794
- let mode = get(r, 'mode', '')
795
- let enable = get(r, 'enable', '')
796
- if (!isestr(name)) {
797
- console.log(`invalid name`)
798
- return true //跳出換下一個
764
+ //無法無損表示之授權資料(R-AUTH-LOSSY-01, 主控複審 R4): 原字串含物件形式無法無損表示之格(getKpLossy)時一律不重寫——
765
+ //列內容與開啟時相同 → 回傳原字串(未變更); 有任何變更 → 拒存並顯示固定訊息(對話框保持開啟, 可還原變更後關閉)
766
+ if (size(vo.lossyNames) > 0) {
767
+ let cur = map(rows, (r) => ({ name: r.name, mode: r.mode, enable: r.enable }))
768
+ if (isEqual(cur, vo.itemsInit)) {
769
+ return vo.cpemisOrig
799
770
  }
800
- if (mode !== 'OR' && mode !== 'AND') {
801
- console.log(`invalid mode[${mode}]`)
802
- return true //跳出換下一個
803
- }
804
- if (!isestr(enable)) {
805
- console.log(`invalid enable`)
806
- return true //跳出換下一個
807
- }
808
- kpPemi[name] = {
809
- mode,
810
- isActive: enable,
811
- }
812
- })
771
+ vo.$ui.updateLoading(false) //showCheckYes 前關 loading(modal 阻斷期間避免 loading 疊在底下)
772
+ await vo.$dg.showCheckYes(fmtLossyMsg(vo.$t('authLossyBlocked'), vo.lossyNames))
773
+ return false
774
+ }
775
+
776
+ //同名多列(權限表之歷史同名, R-PRINCIPLE-00 d): 理由同 VeCgrups.doSave——不一致者拒存並點名, 一致者寫出一次
777
+ let namesDupBad = getDupRowsInconsistent(rows)
778
+ if (size(namesDupBad) > 0) {
779
+ vo.$ui.updateLoading(false) //showCheckYes 前關 loading(modal 阻斷期間避免 loading 疊在底下)
780
+ await vo.$dg.showCheckYes(fmtWarn(vo.$t('warnDupRowsInconsistent'), { names: namesDupBad }))
781
+ return false
782
+ }
783
+
784
+ //kpPemi: 名稱為字串之列(含名稱 '' 與懸空之額外列)皆寫出, 不得丟棄啟用中之引用(R-PRINCIPLE-00 c/f); 共用 putRowsToKp(unit-editorRows 往返不變式)
785
+ //限制項仍為開啟時之「AND、啟用」者寫回原始 mode(vo.rawModeMap; 理由同 VeCgrups.doSave)
786
+ let kpPemi = Object.create(null)
787
+ putRowsToKp(kpPemi, rows, vo.rawModeMap)
813
788
  // console.log('kpPemi', kpPemi)
814
789
 
790
+ //鍵序無關授權(R-AUTH-MERGE-00 第 4 條: 結果與項目之儲存順序、物件鍵序、陣列元素序無關), 故不需保留原鍵序, 亦無整數式名稱易位之拒存
791
+
815
792
  //cpemis
816
793
  let cpemis = JSON.stringify(kpPemi)
817
794
  // console.log('cpemis', cpemis)
@@ -823,6 +800,11 @@ export default {
823
800
  core()
824
801
  .then((rows) => {
825
802
 
803
+ //拒存(無法無損表示之授權資料): 不 resolve、不關窗
804
+ if (rows === false) {
805
+ return
806
+ }
807
+
826
808
  //resolve
827
809
  vo.pm.resolve(rows)
828
810
 
@@ -884,11 +866,16 @@ export default {
884
866
  let cpemis = get(grup, 'cpemis', '')
885
867
  // console.log('cpemis', cpemis)
886
868
 
887
- //kpPemi
869
+ //kpPemi, lossyNames(物件形式無法無損表示者, R-AUTH-LOSSY-01)
888
870
  let kpPemi = Object.create(null)
871
+ let lossyNames = []
872
+ let rawModeMap = Object.create(null) //限制項之原始 mode(getRawModeMap), 存檔時未改者原樣寫回
889
873
  if (isestr(cpemis)) {
890
874
  try {
891
- kpPemi = JSON5.parse(cpemis)
875
+ let kpRaw = JSON5.parse(cpemis)
876
+ kpPemi = cvKpToObj(kpRaw, { hasMode: true })
877
+ lossyNames = getKpLossy(kpRaw)
878
+ rawModeMap = getRawModeMap(kpRaw)
892
879
  }
893
880
  catch (err) {
894
881
  console.log('cpemis', cpemis)
@@ -909,17 +896,9 @@ export default {
909
896
  let name = v.name
910
897
  // console.log('name', name)
911
898
 
912
- //mode
913
- let mode = get(p, 'mode', '')
914
- if (mode !== 'OR' && mode !== 'AND') {
915
- mode = 'OR'
916
- }
917
- // console.log('mode', mode)
918
-
919
- //enable
920
- let _enable = get(p, 'isActive', '')
921
- let enable = _enable === 'y' ? 'y' : 'n'
922
- // console.log('isActive', enable)
899
+ //mode, enable: 與伺服端同解讀(getRefState, 理由同 VeCgrups.show)
900
+ let { mode, enable } = getRefState(p)
901
+ // console.log('mode', mode, 'enable', enable)
923
902
 
924
903
  //r
925
904
  let r = {
@@ -931,13 +910,36 @@ export default {
931
910
 
932
911
  return r
933
912
  })
913
+
914
+ //額外列: 啟用中而權限表查無列之引用(懸空, 含名稱 '')各一列附於表列之後(理由同 VeCgrups.show, R-PRINCIPLE-00 c/f)
915
+ items = [...items, ...getRefRowsExtra(kpPemi, vo.pemis)]
916
+
917
+ //warnText: 各列引用之衝突提示(理由同 VeCgrups.show)
918
+ let resWarn = getRefWarns(cpemis, vo.pemis)
919
+ each(items, (r) => {
920
+ let codes = getOwn(resWarn.kpWarns, r.name, null)
921
+ if (codes !== null) {
922
+ r.warnText = getItemWarnText(codes, r.name, vo.$t, 'warnKindPemi')
923
+ }
924
+ })
934
925
  // console.log('items', items)
935
926
 
927
+ //lossyHint: 啟用而名稱非字串之項目(noName)無列可掛, 於內容區最上方提示(理由同 VeCgrups.show)
928
+ let namesNoName = resWarn.byCode.noName
929
+ vo.lossyHint = size(namesNoName) > 0 ? fmtWarn(vo.$t('warnRefNoName'), { names: namesNoName }) : ''
930
+ vo.lossyHintTitle = size(namesNoName) > 0 ? fmtLossyMsg(vo.$t('authLossyBlocked'), lossyNames) : ''
931
+
936
932
  //save
937
933
  vo.isEditable = isEditable
938
934
  vo.grup = grup
939
935
  vo.items = items
940
936
 
937
+ //存檔依據(非響應式): 原字串、有損名稱、開啟時之列內容(含額外列)
938
+ vo.cpemisOrig = cpemis
939
+ vo.lossyNames = lossyNames
940
+ vo.rawModeMap = rawModeMap
941
+ vo.itemsInit = map(items, (r) => ({ name: r.name, mode: r.mode, enable: r.enable }))
942
+
941
943
  //genOpt
942
944
  vo.genOpt()
943
945
 
@@ -127,7 +127,11 @@
127
127
  :opt="opt"
128
128
  >
129
129
  <template v-slot:cell-render="props">
130
- <span v-if="props.key==='id'">{{ props.value }}</span>
130
+ <template v-if="props.key==='id'">
131
+ <!-- 警告圖示(R-PRINCIPLE-00 a 之提示): 僅該管理對象於原 crules 重複列且有勾有不勾時(warnText, show 時由 getRuleWarns 取得)才渲染於 ID 左側; 無警告者與修前同一節點(不預留空間) -->
132
+ <span :title="props.row.warnText" v-if="props.row.warnText"><img style="vertical-align:sub; width:16px; height:16px; margin-right:4px;" :src="$ui.getIcon('warning')" />{{ props.value }}</span>
133
+ <span v-else>{{ props.value }}</span>
134
+ </template>
131
135
  <input v-else-if="props.key==='enable'" type="checkbox" :checked="props.value === 'y'" @click="toggleItemEnableById(props.row.id)" :disabled="!isEditable" />
132
136
  <span v-else>{{ props.value }}</span>
133
137
  </template>
@@ -164,7 +168,10 @@ import genPm from 'wsemi/src/genPm.mjs'
164
168
  import delay from 'wsemi/src/delay.mjs'
165
169
  import iseobj from 'wsemi/src/iseobj.mjs'
166
170
  import isestr from 'wsemi/src/isestr.mjs'
171
+ import getOwn from '../js/getOwn.mjs'
167
172
  import getRuleEnable from '../js/getRuleEnable.mjs'
173
+ import cvKpToObj from '../js/cvKpToObj.mjs'
174
+ import { getRuleWarns, fmtWarn } from '../js/getAuthWarn.mjs'
168
175
  import WDialog from 'w-component-vue/src/components/WDialog.vue'
169
176
  import WButtonCircle from 'w-component-vue/src/components/WButtonCircle.vue'
170
177
  import WAggridVue from 'w-aggrid-vue/src/components/WAggridVue.vue'
@@ -738,6 +745,9 @@ export default {
738
745
  })
739
746
  // console.log('kpRule', kpRule)
740
747
 
748
+ //兩態(勾/不勾): 勾=y、不勾=n; 未列等同 n, 重存把「未列」寫成顯式 n 不改變授權(R-AUTH-MERGE-00 第 1 條)——不增第三種狀態
749
+ //鍵序無關授權(同條第 4 條), 不需保留原鍵序
750
+
741
751
  //crules
742
752
  let crules = JSON.stringify(kpRule)
743
753
  // console.log('crules', crules)
@@ -813,7 +823,7 @@ export default {
813
823
  let kpRule = Object.create(null)
814
824
  if (isestr(crules)) {
815
825
  try {
816
- kpRule = JSON5.parse(crules)
826
+ kpRule = cvKpToObj(JSON5.parse(crules))
817
827
  }
818
828
  catch (err) {
819
829
  console.log('crules', crules)
@@ -823,6 +833,9 @@ export default {
823
833
  }
824
834
  // console.log('kpRule', kpRule)
825
835
 
836
+ //resRule: 原字串中同一管理對象重複列且有勾有不勾者(R-PRINCIPLE-00 a; 解碼已收嚴為 n, 與伺服端同), 供該列 ID 左側之警告圖示與 tooltip(存檔寫出顯式值即解除)
837
+ let resRule = getRuleWarns(crules)
838
+
826
839
  //items
827
840
  let items = map(vo.targets, (v) => {
828
841
  let enable = getRuleEnable(kpRule, v.id)
@@ -830,6 +843,9 @@ export default {
830
843
  id: v.id,
831
844
  enable,
832
845
  }
846
+ if (getOwn(resRule.kpConflict, v.id, false) === true) {
847
+ r.warnText = fmtWarn(vo.$t('warnRuleConflict'), { names: [v.id] })
848
+ }
833
849
  return r
834
850
  })
835
851
  // console.log('items', items)