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
+ <!-- 無法掛在任何一列之警告(R-PRINCIPLE-00 f: 啟用而名稱非字串之項目, 物件形式無法保留, 存檔被拒): 僅有此類項目時才渲染, 無則與修前同(不預留空間); 字級與內距沿用下方 waitingData 提示 -->
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
+ <!-- 警告圖示(R-PRINCIPLE-00 原則 3「提示」): 僅該列之引用有衝突(warnText, show 時由 getRefWarns 取得)時才渲染於名稱左側; 無警告者與修前同一節點(不預留空間) -->
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 置中容器: 22px 控制項以行內排版放入 27px 儲存格會偏下(上 4.77/下 0.23), 包一層 height:100% 之 flex 容器即上下各 2.5(同 w-aggrid-vue 範例 AppSlotCellRenderAlign.vue) -->
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() {
@@ -533,8 +555,8 @@ export default {
533
555
 
534
556
  let vo = this
535
557
 
536
- //check
537
- if (!isestr(name)) {
558
+ //check, 名稱 '' 為合法名稱(R-PRINCIPLE-00 f: 懸空之額外列可為 '', 須可改 mode/停用), 僅非字串者拒絕
559
+ if (typeof name !== 'string') {
538
560
  vo.$alert(`${vo.$t('cgrupEditNoName')}`, { type: 'error' })
539
561
  return
540
562
  }
@@ -542,30 +564,20 @@ export default {
542
564
  //rows
543
565
  let rows = get(vo, 'opt.rows', [])
544
566
 
545
- //find
546
- let r = null
547
- let kr = null
548
- each(rows, (v, k) => {
549
- if (get(v, 'name', '') === name) {
550
- r = v
551
- kr = k
552
- return false //跳出
553
- }
554
- })
567
+ //krs, 精確同名之全部列(getRowIdxs): 同名多列代表同一個引用, 一併套用使其恆一致(warnDupRowsInconsistent 僅作防呆);
568
+ //精確 ===, 表列無 name 欄(undefined)不再搶先命中名稱 '' 之額外列(修前 get(v, 'name', '') 找第一列)
569
+ let krs = getRowIdxs(rows, 'name', name)
555
570
 
556
571
  //check
557
- if (!iseobj(r)) {
572
+ if (size(krs) === 0) {
558
573
  vo.$alert(`${vo.$t('cgrupEditNoPemi')}`, { type: 'error' })
559
574
  return
560
575
  }
561
576
 
562
- //mode
563
- // let mode = th.value
564
- // console.log('mode', mode)
565
-
566
577
  //set
567
- set(vo, `opt.rows[${kr}].mode`, mode)
568
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
578
+ each(krs, (kr) => {
579
+ set(vo, `opt.rows[${kr}].mode`, mode)
580
+ })
569
581
 
570
582
  //refresh
571
583
  vo.refresh()
@@ -580,8 +592,8 @@ export default {
580
592
 
581
593
  let vo = this
582
594
 
583
- //check
584
- if (!isestr(name)) {
595
+ //check, 名稱 '' 為合法名稱(同 showVeCgrupsToggleItemModeByName)
596
+ if (typeof name !== 'string') {
585
597
  vo.$alert(`${vo.$t('cgrupEditNoName')}`, { type: 'error' })
586
598
  return
587
599
  }
@@ -589,31 +601,24 @@ export default {
589
601
  //rows
590
602
  let rows = get(vo, 'opt.rows', [])
591
603
 
592
- //find
593
- let r = null
594
- let kr = null
595
- each(rows, (v, k) => {
596
- if (get(v, 'name', '') === name) {
597
- r = v
598
- kr = k
599
- return false //跳出
600
- }
601
- })
604
+ //krs, 精確同名之全部列(理由同 showVeCgrupsToggleItemModeByName)
605
+ let krs = getRowIdxs(rows, 'name', name)
602
606
 
603
607
  //check
604
- if (!iseobj(r)) {
608
+ if (size(krs) === 0) {
605
609
  vo.$alert(`${vo.$t('cgrupEditNoPemi')}`, { type: 'error' })
606
610
  return
607
611
  }
608
612
 
609
- //enable
610
- let _enable = get(r, 'enable', 'n')
613
+ //enable, 同名列狀態恆一致, 取第一列切換後套用全部
614
+ let _enable = get(rows[krs[0]], 'enable', 'n')
611
615
  let enable = _enable === 'y' ? 'n' : 'y'
612
616
  // console.log('enable', enable)
613
617
 
614
618
  //set
615
- set(vo, `opt.rows[${kr}].enable`, enable)
616
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
619
+ each(krs, (kr) => {
620
+ set(vo, `opt.rows[${kr}].enable`, enable)
621
+ })
617
622
 
618
623
  //refresh
619
624
  vo.refresh()
@@ -632,26 +637,15 @@ export default {
632
637
  let rows = get(vo, 'opt.rows', [])
633
638
  // console.log('rows', rows)
634
639
 
635
- //kpRow
636
- let kpRow = Object.create(null) //無原型: 鍵為使用者資料, 不得命中 constructor 等原型鍵(規則帳本 R-KEY-01)
637
- each(rows, (r, kr) => {
638
- kpRow[r.name] = kr
639
- })
640
-
641
640
  //rowsEff
642
641
  let rowsEff = vo.getDisplayData()
643
642
  // console.log('rowsEff', rowsEff)
644
643
 
645
- //toggle
644
+ //toggle, 每個顯示中之列對其精確同名之全部列一併套用(getRowIdxs; 修前 kpRow[r.name] 只命中最後一個同名列, 全選後同名列不一致而被拒存)
646
645
  each(rowsEff, (r) => {
647
-
648
- //kr
649
- let kr = kpRow[r.name]
650
-
651
- //set
652
- set(vo, `opt.rows[${kr}].enable`, 'y')
653
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
654
-
646
+ each(getRowIdxs(rows, 'name', r.name), (kr) => {
647
+ set(vo, `opt.rows[${kr}].enable`, 'y')
648
+ })
655
649
  })
656
650
 
657
651
  //refresh
@@ -671,26 +665,15 @@ export default {
671
665
  let rows = get(vo, 'opt.rows', [])
672
666
  // console.log('rows', rows)
673
667
 
674
- //kpRow
675
- let kpRow = Object.create(null)
676
- each(rows, (r, kr) => {
677
- kpRow[r.name] = kr
678
- })
679
-
680
668
  //rowsEff
681
669
  let rowsEff = vo.getDisplayData()
682
670
  // console.log('rowsEff', rowsEff)
683
671
 
684
- //toggle
672
+ //toggle, 對精確同名之全部列一併套用(理由同 showVeCgrupsToggleItemsEnableAllYes)
685
673
  each(rowsEff, (r) => {
686
-
687
- //kr
688
- let kr = kpRow[r.name]
689
-
690
- //set
691
- set(vo, `opt.rows[${kr}].enable`, 'n')
692
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
693
-
674
+ each(getRowIdxs(rows, 'name', r.name), (kr) => {
675
+ set(vo, `opt.rows[${kr}].enable`, 'n')
676
+ })
694
677
  })
695
678
 
696
679
  //refresh
@@ -710,29 +693,21 @@ export default {
710
693
  let rows = get(vo, 'opt.rows', [])
711
694
  // console.log('rows', rows)
712
695
 
713
- //kpRow
714
- let kpRow = Object.create(null)
715
- each(rows, (r, kr) => {
716
- kpRow[r.name] = kr
717
- })
718
-
719
696
  //rowsEff
720
697
  let rowsEff = vo.getDisplayData()
721
698
  // console.log('rowsEff', rowsEff)
722
699
 
723
- //toggle
700
+ //toggle, 對精確同名之全部列一併套用(理由同 showVeCgrupsToggleItemsEnableAllYes; 同名列狀態一致, 各顯示列算出之反向值相同)
724
701
  each(rowsEff, (r) => {
725
702
 
726
- //kr
727
- let kr = kpRow[r.name]
728
-
729
703
  //enable
730
704
  let _enable = get(r, 'enable', 'n')
731
705
  let enable = _enable === 'y' ? 'n' : 'y'
732
706
 
733
707
  //set
734
- set(vo, `opt.rows[${kr}].enable`, enable)
735
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
708
+ each(getRowIdxs(rows, 'name', r.name), (kr) => {
709
+ set(vo, `opt.rows[${kr}].enable`, enable)
710
+ })
736
711
 
737
712
  })
738
713
 
@@ -789,31 +764,34 @@ export default {
789
764
  let rows = get(vo, 'opt.rows', [])
790
765
  // console.log('rows', rows)
791
766
 
792
- //kpGrup
793
- let kpGrup = Object.create(null)
794
- each(rows, (r) => {
795
- let name = get(r, 'name', '')
796
- let mode = get(r, 'mode', '')
797
- let enable = get(r, 'enable', '')
798
- if (!isestr(name)) {
799
- console.log(`invalid name`)
800
- return true //跳出換下一個
767
+ //無法無損表示之授權資料(R-AUTH-LOSSY-01, 主控複審 R4): 原字串含物件形式無法無損表示之格(getKpLossy)時一律不重寫——
768
+ //列內容與開啟時相同 → 回傳原字串(未變更); 有任何變更 → 拒存並顯示固定訊息(對話框保持開啟, 可還原變更後關閉)
769
+ if (size(vo.lossyNames) > 0) {
770
+ let cur = map(rows, (r) => ({ name: r.name, mode: r.mode, enable: r.enable }))
771
+ if (isEqual(cur, vo.itemsInit)) {
772
+ return vo.cgrupsOrig
801
773
  }
802
- if (mode !== 'OR' && mode !== 'AND') {
803
- console.log(`invalid mode[${mode}]`)
804
- return true //跳出換下一個
805
- }
806
- if (!isestr(enable)) {
807
- console.log(`invalid enable`)
808
- return true //跳出換下一個
809
- }
810
- kpGrup[name] = {
811
- mode,
812
- isActive: enable,
813
- }
814
- })
774
+ vo.$ui.updateLoading(false) //showCheckYes 前關 loading(modal 阻斷期間避免 loading 疊在底下)
775
+ await vo.$dg.showCheckYes(fmtLossyMsg(vo.$t('authLossyBlocked'), vo.lossyNames))
776
+ return false
777
+ }
778
+
779
+ //同名多列(群組表之歷史同名, R-PRINCIPLE-00 d): 各列之 (mode, enable) 不全相同者無法以物件形式寫出(寫出任一列即靜默捨棄其他列之設定), 拒存並點名(對話框保持開啟); 全相同則寫出一次
780
+ let namesDupBad = getDupRowsInconsistent(rows)
781
+ if (size(namesDupBad) > 0) {
782
+ vo.$ui.updateLoading(false) //showCheckYes 前關 loading(modal 阻斷期間避免 loading 疊在底下)
783
+ await vo.$dg.showCheckYes(fmtWarn(vo.$t('warnDupRowsInconsistent'), { names: namesDupBad }))
784
+ return false
785
+ }
786
+
787
+ //kpGrup: 名稱為字串之列(含名稱 '' 與懸空之額外列)皆寫出, 不得丟棄啟用中之引用(R-PRINCIPLE-00 c/f; 修前以 isestr(name) 略過 '', 懸空引用則根本無列); 共用 putRowsToKp(unit-editorRows 往返不變式)
788
+ //限制項(mode 缺或非法之啟用引用)仍為開啟時之「AND、啟用」者寫回原始 mode(vo.rawModeMap), 不寫成可當基底之合法 AND(否則停用該層唯一合法項後多給, R-PRINCIPLE-00 e)
789
+ let kpGrup = Object.create(null)
790
+ putRowsToKp(kpGrup, rows, vo.rawModeMap)
815
791
  // console.log('kpGrup', kpGrup)
816
792
 
793
+ //鍵序無關授權(R-AUTH-MERGE-00 第 4 條: 結果與項目之儲存順序、物件鍵序、陣列元素序無關), 故不需保留原鍵序, 亦無整數式名稱易位之拒存
794
+
817
795
  //cgrups
818
796
  let cgrups = JSON.stringify(kpGrup)
819
797
  // console.log('cgrups', cgrups)
@@ -825,6 +803,11 @@ export default {
825
803
  core()
826
804
  .then((rows) => {
827
805
 
806
+ //拒存(無法無損表示之授權資料): 不 resolve、不關窗
807
+ if (rows === false) {
808
+ return
809
+ }
810
+
828
811
  //resolve
829
812
  vo.pm.resolve(rows)
830
813
 
@@ -886,11 +869,16 @@ export default {
886
869
  let cgrups = get(user, 'cgrups', '')
887
870
  // console.log('cgrups', cgrups)
888
871
 
889
- //kpGrup
872
+ //kpGrup, lossyNames(物件形式無法無損表示者, R-AUTH-LOSSY-01)
890
873
  let kpGrup = Object.create(null)
874
+ let lossyNames = []
875
+ let rawModeMap = Object.create(null) //限制項之原始 mode(getRawModeMap), 存檔時未改者原樣寫回
891
876
  if (isestr(cgrups)) {
892
877
  try {
893
- kpGrup = JSON5.parse(cgrups)
878
+ let kpRaw = JSON5.parse(cgrups)
879
+ kpGrup = cvKpToObj(kpRaw, { hasMode: true })
880
+ lossyNames = getKpLossy(kpRaw)
881
+ rawModeMap = getRawModeMap(kpRaw)
894
882
  }
895
883
  catch (err) {
896
884
  console.log('cgrups', cgrups)
@@ -911,17 +899,9 @@ export default {
911
899
  let name = v.name
912
900
  // console.log('name', name)
913
901
 
914
- //mode
915
- let mode = get(p, 'mode', '')
916
- if (mode !== 'OR' && mode !== 'AND') {
917
- mode = 'OR'
918
- }
919
- // console.log('mode', mode)
920
-
921
- //enable
922
- let _enable = get(p, 'isActive', '')
923
- let enable = _enable === 'y' ? 'y' : 'n'
924
- // console.log('isActive', enable)
902
+ //mode, enable: 與伺服端同解讀(getRefState: 啟用者 mode 取有效值〔缺/非法 → AND〕, 純量值 { "G1": "y" } 亦為啟用 AND; 停用者 mode 缺/非法顯示 OR)
903
+ let { mode, enable } = getRefState(p)
904
+ // console.log('mode', mode, 'enable', enable)
925
905
 
926
906
  //r
927
907
  let r = {
@@ -933,13 +913,37 @@ export default {
933
913
 
934
914
  return r
935
915
  })
916
+
917
+ //額外列: 啟用中而群組表查無列之引用(懸空, 含名稱 '')各一列附於表列之後, 名稱唯讀、mode/enable 可改(可改為停用以解除); 伺服端仍以其 mode 參與(內容全 n),
918
+ //存檔若丟棄即放寬(R-PRINCIPLE-00 c/f). 停用之懸空引用無授權影響, 不產生額外列(存檔時照舊丟棄)
919
+ items = [...items, ...getRefRowsExtra(kpGrup, vo.grups)]
920
+
921
+ //warnText: 各列引用之衝突提示(R-PRINCIPLE-00 原則 3; 偵測同伺服端判準, getRefWarns 以原字串), 名稱儲存格左側之警告圖示與 tooltip; 同名多列各列皆出(ambiguous)
922
+ let resWarn = getRefWarns(cgrups, vo.grups)
923
+ each(items, (r) => {
924
+ let codes = getOwn(resWarn.kpWarns, r.name, null)
925
+ if (codes !== null) {
926
+ r.warnText = getItemWarnText(codes, r.name, vo.$t, 'warnKindGrup')
927
+ }
928
+ })
936
929
  // console.log('items', items)
937
930
 
931
+ //lossyHint: 啟用而名稱非字串之項目(noName)無列可掛, 於內容區最上方提示(存檔被拒, 見 doSave 之 lossyNames)
932
+ let namesNoName = resWarn.byCode.noName
933
+ vo.lossyHint = size(namesNoName) > 0 ? fmtWarn(vo.$t('warnRefNoName'), { names: namesNoName }) : ''
934
+ vo.lossyHintTitle = size(namesNoName) > 0 ? fmtLossyMsg(vo.$t('authLossyBlocked'), lossyNames) : ''
935
+
938
936
  //save
939
937
  vo.isEditable = isEditable
940
938
  vo.user = user
941
939
  vo.items = items
942
940
 
941
+ //存檔依據(非響應式): 原字串、有損名稱、開啟時之列內容(含額外列)
942
+ vo.cgrupsOrig = cgrups
943
+ vo.lossyNames = lossyNames
944
+ vo.rawModeMap = rawModeMap
945
+ vo.itemsInit = map(items, (r) => ({ name: r.name, mode: r.mode, enable: r.enable }))
946
+
943
947
  //genOpt
944
948
  vo.genOpt()
945
949