w-web-perm 1.1.12 → 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 (124) hide show
  1. package/README.md +158 -123
  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 +23023 -1125
  12. package/docs/index.html +2 -2
  13. package/docs/server_WWebPerm.mjs.html +232 -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 +2 -2
  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 +2 -2
  31. package/docs/src_js_cvKpToObj.mjs.html +44 -33
  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 +2 -2
  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 +47 -52
  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 +4 -4
  52. package/docs/src_js_joinNames.mjs.html +2 -2
  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 +230 -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 +270 -3
  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/wrapInjected.mjs +1 -1
  79. package/src/components/LayoutContentGrups.vue +396 -75
  80. package/src/components/LayoutContentPemis.vue +395 -75
  81. package/src/components/LayoutContentTargets.vue +261 -25
  82. package/src/components/LayoutContentUsers.vue +334 -97
  83. package/src/components/VeCgrups.vue +88 -129
  84. package/src/components/VeCpemis.vue +86 -129
  85. package/src/components/VeCrules.vue +15 -5
  86. package/src/components/VeGrupBlngUsers.vue +202 -89
  87. package/src/components/VePemiBlngGrups.vue +209 -99
  88. package/src/js/cvKpToObj.mjs +42 -31
  89. package/src/js/draftSync.mjs +70 -0
  90. package/src/js/eachOwn.mjs +1 -1
  91. package/src/js/editorRefRows.mjs +284 -0
  92. package/src/js/externalRows.mjs +266 -0
  93. package/src/js/externalUi.mjs +158 -0
  94. package/src/js/findRefRows.mjs +35 -0
  95. package/src/js/findTouchedDup.mjs +78 -0
  96. package/src/js/fromAudit.mjs +417 -0
  97. package/src/js/getAddImpact.mjs +197 -0
  98. package/src/js/getAuthWarn.mjs +391 -0
  99. package/src/js/getCascadePreview.mjs +186 -0
  100. package/src/js/getDelRefCount.mjs +138 -0
  101. package/src/js/getEffMode.mjs +20 -0
  102. package/src/js/getKpLossy.mjs +44 -49
  103. package/src/js/getNameErrs.mjs +194 -0
  104. package/src/js/getOwn.mjs +1 -1
  105. package/src/js/getPropKey.mjs +37 -0
  106. package/src/js/isAuthMode.mjs +2 -2
  107. package/src/js/pairRowsToSnapshot.mjs +84 -0
  108. package/src/js/refAudit.mjs +287 -0
  109. package/src/js/refCascade.mjs +500 -0
  110. package/src/js/relDialogSend.mjs +127 -0
  111. package/src/js/rowDigest.mjs +193 -0
  112. package/src/plugins/dataReloadGuard.mjs +37 -0
  113. package/src/plugins/mShare.mjs +144 -140
  114. package/src/plugins/mUI.mjs +3 -8
  115. package/src/schema/tables/users.mjs +152 -152
  116. package/dist/css/app.6918ec45.css +0 -1
  117. package/dist/js/app-legacy.7cb7e394.js +0 -1
  118. package/dist/js/app.7cb7e394.js +0 -1
  119. package/docs/src_js_getKeyOrderLost.mjs.html +0 -121
  120. package/docs/src_js_getKpWriteLost.mjs.html +0 -100
  121. package/docs/src_js_keepKeyOrder.mjs.html +0 -139
  122. package/src/js/getKeyOrderLost.mjs +0 -49
  123. package/src/js/getKpWriteLost.mjs +0 -28
  124. package/src/js/keepKeyOrder.mjs +0 -67
@@ -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%;"
@@ -175,14 +189,13 @@ import isEqual from 'lodash-es/isEqual.js'
175
189
  import cloneDeep from 'lodash-es/cloneDeep.js'
176
190
  import genPm from 'wsemi/src/genPm.mjs'
177
191
  import delay from 'wsemi/src/delay.mjs'
178
- import iseobj from 'wsemi/src/iseobj.mjs'
179
192
  import isestr from 'wsemi/src/isestr.mjs'
180
193
  import getOwn from '../js/getOwn.mjs'
181
194
  import cvKpToObj from '../js/cvKpToObj.mjs'
182
- import keepKeyOrder from '../js/keepKeyOrder.mjs'
183
195
  import getKpLossy from '../js/getKpLossy.mjs'
184
- import getKpWriteLost from '../js/getKpWriteLost.mjs'
185
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'
186
199
  import WDialog from 'w-component-vue/src/components/WDialog.vue'
187
200
  import WButtonCircle from 'w-component-vue/src/components/WButtonCircle.vue'
188
201
  import WAggridVue from 'w-aggrid-vue/src/components/WAggridVue.vue'
@@ -229,6 +242,9 @@ export default {
229
242
  itemsCheck: [],
230
243
  opt: null,
231
244
 
245
+ lossyHint: '', //無法掛在任何一列之警告文字(啟用而名稱非字串之項目), 無則 ''
246
+ lossyHintTitle: '',
247
+
232
248
  }
233
249
  },
234
250
  mounted: function() {
@@ -539,8 +555,8 @@ export default {
539
555
 
540
556
  let vo = this
541
557
 
542
- //check
543
- if (!isestr(name)) {
558
+ //check, 名稱 '' 為合法名稱(R-PRINCIPLE-00 f: 懸空之額外列可為 '', 須可改 mode/停用), 僅非字串者拒絕
559
+ if (typeof name !== 'string') {
544
560
  vo.$alert(`${vo.$t('cgrupEditNoName')}`, { type: 'error' })
545
561
  return
546
562
  }
@@ -548,30 +564,20 @@ export default {
548
564
  //rows
549
565
  let rows = get(vo, 'opt.rows', [])
550
566
 
551
- //find
552
- let r = null
553
- let kr = null
554
- each(rows, (v, k) => {
555
- if (get(v, 'name', '') === name) {
556
- r = v
557
- kr = k
558
- return false //跳出
559
- }
560
- })
567
+ //krs, 精確同名之全部列(getRowIdxs): 同名多列代表同一個引用, 一併套用使其恆一致(warnDupRowsInconsistent 僅作防呆);
568
+ //精確 ===, 表列無 name 欄(undefined)不再搶先命中名稱 '' 之額外列(修前 get(v, 'name', '') 找第一列)
569
+ let krs = getRowIdxs(rows, 'name', name)
561
570
 
562
571
  //check
563
- if (!iseobj(r)) {
572
+ if (size(krs) === 0) {
564
573
  vo.$alert(`${vo.$t('cgrupEditNoPemi')}`, { type: 'error' })
565
574
  return
566
575
  }
567
576
 
568
- //mode
569
- // let mode = th.value
570
- // console.log('mode', mode)
571
-
572
577
  //set
573
- set(vo, `opt.rows[${kr}].mode`, mode)
574
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
578
+ each(krs, (kr) => {
579
+ set(vo, `opt.rows[${kr}].mode`, mode)
580
+ })
575
581
 
576
582
  //refresh
577
583
  vo.refresh()
@@ -586,8 +592,8 @@ export default {
586
592
 
587
593
  let vo = this
588
594
 
589
- //check
590
- if (!isestr(name)) {
595
+ //check, 名稱 '' 為合法名稱(同 showVeCgrupsToggleItemModeByName)
596
+ if (typeof name !== 'string') {
591
597
  vo.$alert(`${vo.$t('cgrupEditNoName')}`, { type: 'error' })
592
598
  return
593
599
  }
@@ -595,31 +601,24 @@ export default {
595
601
  //rows
596
602
  let rows = get(vo, 'opt.rows', [])
597
603
 
598
- //find
599
- let r = null
600
- let kr = null
601
- each(rows, (v, k) => {
602
- if (get(v, 'name', '') === name) {
603
- r = v
604
- kr = k
605
- return false //跳出
606
- }
607
- })
604
+ //krs, 精確同名之全部列(理由同 showVeCgrupsToggleItemModeByName)
605
+ let krs = getRowIdxs(rows, 'name', name)
608
606
 
609
607
  //check
610
- if (!iseobj(r)) {
608
+ if (size(krs) === 0) {
611
609
  vo.$alert(`${vo.$t('cgrupEditNoPemi')}`, { type: 'error' })
612
610
  return
613
611
  }
614
612
 
615
- //enable
616
- let _enable = get(r, 'enable', 'n')
613
+ //enable, 同名列狀態恆一致, 取第一列切換後套用全部
614
+ let _enable = get(rows[krs[0]], 'enable', 'n')
617
615
  let enable = _enable === 'y' ? 'n' : 'y'
618
616
  // console.log('enable', enable)
619
617
 
620
618
  //set
621
- set(vo, `opt.rows[${kr}].enable`, enable)
622
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
619
+ each(krs, (kr) => {
620
+ set(vo, `opt.rows[${kr}].enable`, enable)
621
+ })
623
622
 
624
623
  //refresh
625
624
  vo.refresh()
@@ -638,26 +637,15 @@ export default {
638
637
  let rows = get(vo, 'opt.rows', [])
639
638
  // console.log('rows', rows)
640
639
 
641
- //kpRow
642
- let kpRow = Object.create(null) //無原型: 鍵為使用者資料, 不得命中 constructor 等原型鍵(規則帳本 R-KEY-01)
643
- each(rows, (r, kr) => {
644
- kpRow[r.name] = kr
645
- })
646
-
647
640
  //rowsEff
648
641
  let rowsEff = vo.getDisplayData()
649
642
  // console.log('rowsEff', rowsEff)
650
643
 
651
- //toggle
644
+ //toggle, 每個顯示中之列對其精確同名之全部列一併套用(getRowIdxs; 修前 kpRow[r.name] 只命中最後一個同名列, 全選後同名列不一致而被拒存)
652
645
  each(rowsEff, (r) => {
653
-
654
- //kr
655
- let kr = kpRow[r.name]
656
-
657
- //set
658
- set(vo, `opt.rows[${kr}].enable`, 'y')
659
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
660
-
646
+ each(getRowIdxs(rows, 'name', r.name), (kr) => {
647
+ set(vo, `opt.rows[${kr}].enable`, 'y')
648
+ })
661
649
  })
662
650
 
663
651
  //refresh
@@ -677,26 +665,15 @@ export default {
677
665
  let rows = get(vo, 'opt.rows', [])
678
666
  // console.log('rows', rows)
679
667
 
680
- //kpRow
681
- let kpRow = Object.create(null)
682
- each(rows, (r, kr) => {
683
- kpRow[r.name] = kr
684
- })
685
-
686
668
  //rowsEff
687
669
  let rowsEff = vo.getDisplayData()
688
670
  // console.log('rowsEff', rowsEff)
689
671
 
690
- //toggle
672
+ //toggle, 對精確同名之全部列一併套用(理由同 showVeCgrupsToggleItemsEnableAllYes)
691
673
  each(rowsEff, (r) => {
692
-
693
- //kr
694
- let kr = kpRow[r.name]
695
-
696
- //set
697
- set(vo, `opt.rows[${kr}].enable`, 'n')
698
- // console.log('vo.opt.rows[kr]', cloneDeep(vo.opt.rows[kr]))
699
-
674
+ each(getRowIdxs(rows, 'name', r.name), (kr) => {
675
+ set(vo, `opt.rows[${kr}].enable`, 'n')
676
+ })
700
677
  })
701
678
 
702
679
  //refresh
@@ -716,29 +693,21 @@ export default {
716
693
  let rows = get(vo, 'opt.rows', [])
717
694
  // console.log('rows', rows)
718
695
 
719
- //kpRow
720
- let kpRow = Object.create(null)
721
- each(rows, (r, kr) => {
722
- kpRow[r.name] = kr
723
- })
724
-
725
696
  //rowsEff
726
697
  let rowsEff = vo.getDisplayData()
727
698
  // console.log('rowsEff', rowsEff)
728
699
 
729
- //toggle
700
+ //toggle, 對精確同名之全部列一併套用(理由同 showVeCgrupsToggleItemsEnableAllYes; 同名列狀態一致, 各顯示列算出之反向值相同)
730
701
  each(rowsEff, (r) => {
731
702
 
732
- //kr
733
- let kr = kpRow[r.name]
734
-
735
703
  //enable
736
704
  let _enable = get(r, 'enable', 'n')
737
705
  let enable = _enable === 'y' ? 'n' : 'y'
738
706
 
739
707
  //set
740
- set(vo, `opt.rows[${kr}].enable`, enable)
741
- // 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
+ })
742
711
 
743
712
  })
744
713
 
@@ -807,43 +776,21 @@ export default {
807
776
  return false
808
777
  }
809
778
 
810
- //kpGrup
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)
811
789
  let kpGrup = Object.create(null)
812
- each(rows, (r) => {
813
- let name = get(r, 'name', '')
814
- let mode = get(r, 'mode', '')
815
- let enable = get(r, 'enable', '')
816
- if (!isestr(name)) {
817
- console.log(`invalid name`)
818
- return true //跳出換下一個
819
- }
820
- if (mode !== 'OR' && mode !== 'AND') {
821
- console.log(`invalid mode[${mode}]`)
822
- return true //跳出換下一個
823
- }
824
- if (!isestr(enable)) {
825
- console.log(`invalid enable`)
826
- return true //跳出換下一個
827
- }
828
- kpGrup[name] = {
829
- mode,
830
- isActive: enable,
831
- }
832
- })
790
+ putRowsToKp(kpGrup, rows, vo.rawModeMap)
833
791
  // console.log('kpGrup', kpGrup)
834
792
 
835
- //保留原鍵序(R-AUTH-ORDER-01, 主控複審 R3): 對話框為群組表序, 原字串已有之群組維持原相對順序、新增者附加於後;
836
- //伺服端 mergeRules 在沒有有效 OR 項時以第一個 AND 項為起始, 鍵序改變即改變授權
837
- let lostNames = getKpWriteLost(vo.kpOrig, kpGrup) //預期序由參考(解碼後之原資料)與欲寫出之物件於函數內導出
838
- kpGrup = keepKeyOrder(vo.kpOrig, kpGrup)
839
-
840
- //欲寫出之鍵序若被 JS 屬性序(整數式鍵恆先排)改變而使有效 AND 項之相對順序易位(如新啟用整數式名稱之 AND 群組)
841
- //→ 授權會改變, 編輯器無法在不改變授權下寫出, 拒存並顯示固定訊息(同無法無損表示, R-AUTH-LOSSY-01; 外審 minimax#2)
842
- if (size(lostNames) > 0) {
843
- vo.$ui.updateLoading(false) //showCheckYes 前關 loading
844
- await vo.$dg.showCheckYes(fmtLossyMsg(vo.$t('authLossyBlocked'), lostNames))
845
- return false
846
- }
793
+ //鍵序無關授權(R-AUTH-MERGE-00 第 4 條: 結果與項目之儲存順序、物件鍵序、陣列元素序無關), 故不需保留原鍵序, 亦無整數式名稱易位之拒存
847
794
 
848
795
  //cgrups
849
796
  let cgrups = JSON.stringify(kpGrup)
@@ -925,11 +872,13 @@ export default {
925
872
  //kpGrup, lossyNames(物件形式無法無損表示者, R-AUTH-LOSSY-01)
926
873
  let kpGrup = Object.create(null)
927
874
  let lossyNames = []
875
+ let rawModeMap = Object.create(null) //限制項之原始 mode(getRawModeMap), 存檔時未改者原樣寫回
928
876
  if (isestr(cgrups)) {
929
877
  try {
930
878
  let kpRaw = JSON5.parse(cgrups)
931
879
  kpGrup = cvKpToObj(kpRaw, { hasMode: true })
932
880
  lossyNames = getKpLossy(kpRaw)
881
+ rawModeMap = getRawModeMap(kpRaw)
933
882
  }
934
883
  catch (err) {
935
884
  console.log('cgrups', cgrups)
@@ -950,17 +899,9 @@ export default {
950
899
  let name = v.name
951
900
  // console.log('name', name)
952
901
 
953
- //mode
954
- let mode = get(p, 'mode', '')
955
- if (mode !== 'OR' && mode !== 'AND') {
956
- mode = 'OR'
957
- }
958
- // console.log('mode', mode)
959
-
960
- //enable
961
- let _enable = get(p, 'isActive', '')
962
- let enable = _enable === 'y' ? 'y' : 'n'
963
- // 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)
964
905
 
965
906
  //r
966
907
  let r = {
@@ -972,17 +913,35 @@ export default {
972
913
 
973
914
  return r
974
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
+ })
975
929
  // console.log('items', items)
976
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
+
977
936
  //save
978
937
  vo.isEditable = isEditable
979
938
  vo.user = user
980
939
  vo.items = items
981
940
 
982
- //存檔依據(非響應式): 解碼後之原資料(保序參考)、原字串、有損名稱、開啟時之列內容
983
- vo.kpOrig = kpGrup
941
+ //存檔依據(非響應式): 原字串、有損名稱、開啟時之列內容(含額外列)
984
942
  vo.cgrupsOrig = cgrups
985
943
  vo.lossyNames = lossyNames
944
+ vo.rawModeMap = rawModeMap
986
945
  vo.itemsInit = map(items, (r) => ({ name: r.name, mode: r.mode, enable: r.enable }))
987
946
 
988
947
  //genOpt