vue2-client 1.22.2 → 1.22.3

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 (170) hide show
  1. package/.claude/settings.local.json +30 -30
  2. package/.env.his +19 -19
  3. package/.eslintrc.js +74 -74
  4. package/.history/.eslintrc_20260521171150.js +74 -0
  5. package/.history/.eslintrc_20260521171213.js +74 -0
  6. package/.history/src/base-client/components/common/HIS/HAddNativeForm/HAddNativeForm_20260601154443.vue +726 -0
  7. package/.history/src/base-client/components/common/HIS/HAddNativeForm/HAddNativeForm_20260601154700.vue +478 -0
  8. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260512175435.vue +706 -0
  9. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260512175450.vue +694 -0
  10. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260611152602.vue +755 -0
  11. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513145941.vue +524 -0
  12. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513153133.vue +731 -0
  13. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513160316.vue +525 -0
  14. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260601144150.vue +1046 -0
  15. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260310142713.vue +512 -0
  16. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260310145118.vue +511 -0
  17. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260311094834.vue +696 -0
  18. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260320143028.vue +693 -0
  19. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260409101450.vue +677 -0
  20. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508164645.vue +758 -0
  21. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508164714.vue +693 -0
  22. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508171651.vue +716 -0
  23. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260509133717.vue +695 -0
  24. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260509171115.vue +664 -0
  25. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513140637.vue +1455 -0
  26. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513140935.vue +1441 -0
  27. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513150818.vue +1441 -0
  28. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513153119.vue +1442 -0
  29. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513153126.vue +1486 -0
  30. package/.history/src/base-client/components/common/XForm/XFormItem_20260513140854.vue +1607 -0
  31. package/.history/src/base-client/components/common/XMarkdownViewer/XMarkdownViewer_20260519140403.vue +643 -0
  32. package/.history/src/base-client/components/common/XMarkdownViewer/XMarkdownViewer_20260519140829.vue +628 -0
  33. package/.history/src/base-client/components/common/XMarkdownViewer/demo_20260519142824.vue +104 -0
  34. package/.history/src/base-client/components/common/XMarkdownViewer/demo_20260519143155.vue +102 -0
  35. package/.history/src/base-client/components/common/XReportGrid/XReport_20260309171231.vue +1241 -0
  36. package/.history/src/base-client/components/common/XReportGrid/XReport_20260309171441.vue +1223 -0
  37. package/.history/src/base-client/components/his/HAi/HAi_20260612174826.vue +472 -0
  38. package/.history/src/base-client/components/his/HAi/HAi_20260612175839.vue +538 -0
  39. package/.history/src/base-client/components/his/HAi/HAi_20260615103331.vue +650 -0
  40. package/.history/src/base-client/components/his/XHDescriptions/XHDescriptions_20260424134504.vue +1469 -0
  41. package/.history/src/base-client/components/his/XSidebar/XSidebar_20260610171133.vue +788 -0
  42. package/.history/src/base-client/components/his/XSidebar/XSidebar_20260610171151.vue +780 -0
  43. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260511170841.vue +585 -0
  44. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260511171138.vue +787 -0
  45. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260512141830.vue +739 -0
  46. package/.history/src/components/STable/index_20260409155138.js +806 -0
  47. package/.history/src/components/STable/index_20260409155218.js +814 -0
  48. package/.history/src/expression/core/Expression_20260305164427.js +1371 -0
  49. package/.history/src/expression/core/Expression_20260305170258.js +1358 -0
  50. package/.history/src/expression/core/Program_20260305111830.js +944 -0
  51. package/.history/src/expression/core/Program_20260305112041.js +931 -0
  52. package/.history/src/logic/LogicRunner_20260304154306.js +170 -0
  53. package/.history/src/logic/LogicRunner_20260304155553.js +112 -0
  54. package/.history/src/logic/LogicRunner_20260305105834.js +112 -0
  55. package/.history/src/logic/LogicRunner_20260305112718.js +129 -0
  56. package/.history/src/logic/LogicRunner_20260305182436.js +133 -0
  57. package/.history/src/logic/LogicRunner_20260306151301.js +213 -0
  58. package/.history/src/logic/LogicRunner_20260306152419.js +213 -0
  59. package/.history/src/logic/plugins/common/DateTools_20260305154159.js +61 -0
  60. package/.history/src/logic/plugins/common/DateTools_20260305154217.js +44 -0
  61. package/.history/src/logic/plugins/common/DateTools_20260305161014.js +44 -0
  62. package/.history/src/logic/plugins/common/HttpTools_20260305164352.js +80 -0
  63. package/.history/src/logic/plugins/common/HttpTools_20260305170258.js +75 -0
  64. package/.history/src/logic/plugins/common/HttpTools_20260305171634.js +75 -0
  65. package/.history/src/logic/plugins/common/HttpTools_20260306152419.js +72 -0
  66. package/.history/src/services/api/restTools_20260427142149.js +245 -0
  67. package/.history/src/services/api/restTools_20260427142853.js +230 -0
  68. package/.history/src/services/api/restTools_20260519135558.js +230 -0
  69. package/.history/src/services/api/restTools_20260519140825.js +230 -0
  70. package/.history/src/services/api/restTools_20260519151223.js +230 -0
  71. package/.history/src/utils/indexedDB_20260306150918.js +593 -0
  72. package/.history/src/utils/indexedDB_20260306151301.js +586 -0
  73. package/.idea/af-vue2-client.iml +9 -0
  74. package/.idea/codeStyles/Project.xml +62 -0
  75. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  76. package/.idea/misc.xml +6 -0
  77. package/.idea/modules.xml +1 -1
  78. package/Components.md +60 -60
  79. package/index.js +31 -31
  80. package/jest-transform-stub.js +8 -8
  81. package/jest.setup.js +7 -7
  82. package/package.json +1 -1
  83. package/preview-input-box.html +180 -0
  84. package/src/assets/img/querySlotDemo.svg +15 -15
  85. package/src/base-client/components/common/AmapMarker/AmapPointRendering.vue +120 -120
  86. package/src/base-client/components/common/CitySelect/index.js +3 -3
  87. package/src/base-client/components/common/CitySelect/index.md +109 -109
  88. package/src/base-client/components/common/FormGroupEdit/index.js +3 -3
  89. package/src/base-client/components/common/FormGroupEdit/index.md +43 -43
  90. package/src/base-client/components/common/HIS/HButtons/HButtons.vue +55 -1
  91. package/src/base-client/components/common/HIS/HForm/HForm.vue +1186 -1186
  92. package/src/base-client/components/common/HIS/HTab/HTab.vue +88 -1
  93. package/src/base-client/components/common/JSONToTree/jsontotree.vue +271 -271
  94. package/src/base-client/components/common/PersonSetting/index.js +3 -3
  95. package/src/base-client/components/common/Tree/index.js +2 -2
  96. package/src/base-client/components/common/Upload/index.js +3 -3
  97. package/src/base-client/components/common/XAddNativeForm/index.md +146 -146
  98. package/src/base-client/components/common/XAddReport/XAddReport.vue +16 -1
  99. package/src/base-client/components/common/XCard/XCard.vue +64 -64
  100. package/src/base-client/components/common/XDataDrawer/XDataDrawer.vue +180 -180
  101. package/src/base-client/components/common/XDataDrawer/index.js +3 -3
  102. package/src/base-client/components/common/XDataDrawer/index.md +41 -41
  103. package/src/base-client/components/common/XDescriptions/index.js +3 -3
  104. package/src/base-client/components/common/XDescriptions/index.md +382 -382
  105. package/src/base-client/components/common/XForm/index.md +178 -178
  106. package/src/base-client/components/common/XInput/XInput.vue +32 -1
  107. package/src/base-client/components/common/XInspectionDetailDrawer/index.vue +1 -1
  108. package/src/base-client/components/common/XMarkdownViewer/demo.vue +102 -102
  109. package/src/base-client/components/common/XStepView/XStepView.vue +252 -252
  110. package/src/base-client/components/common/XStepView/index.js +3 -3
  111. package/src/base-client/components/common/XStepView/index.md +31 -31
  112. package/src/base-client/components/common/XTable/index.md +255 -255
  113. package/src/base-client/components/his/HAi/HAi.vue +1177 -436
  114. package/src/base-client/components/his/XList/XList.vue +337 -58
  115. package/src/base-client/components/his/XSidebar/XSidebar.vue +36 -12
  116. package/src/base-client/components/his/XTransfer/index.md +327 -327
  117. package/src/base-client/components/system/DictionaryDetailsView/DictionaryDetailsView.vue +232 -232
  118. package/src/base-client/plugins/Config.js +19 -19
  119. package/src/base-client/plugins/tabs-page-plugin.js +39 -39
  120. package/src/components/Charts/Bar.vue +62 -62
  121. package/src/components/Charts/ChartCard.vue +134 -134
  122. package/src/components/Charts/Liquid.vue +67 -67
  123. package/src/components/Charts/MiniArea.vue +39 -39
  124. package/src/components/Charts/MiniBar.vue +39 -39
  125. package/src/components/Charts/MiniProgress.vue +75 -75
  126. package/src/components/Charts/MiniSmoothArea.vue +40 -40
  127. package/src/components/Charts/Radar.vue +68 -68
  128. package/src/components/Charts/RankList.vue +77 -77
  129. package/src/components/Charts/TagCloud.vue +113 -113
  130. package/src/components/Charts/TransferBar.vue +64 -64
  131. package/src/components/Charts/Trend.vue +82 -82
  132. package/src/components/Charts/chart.less +12 -12
  133. package/src/components/Charts/smooth.area.less +13 -13
  134. package/src/components/NumberInfo/NumberInfo.vue +54 -54
  135. package/src/components/NumberInfo/index.js +3 -3
  136. package/src/components/NumberInfo/index.less +54 -54
  137. package/src/components/NumberInfo/index.md +43 -43
  138. package/src/components/STable/index.js +953 -953
  139. package/src/components/card/ChartCard.vue +79 -79
  140. package/src/components/chart/Bar.vue +60 -60
  141. package/src/components/chart/MiniArea.vue +67 -67
  142. package/src/components/chart/MiniBar.vue +59 -59
  143. package/src/components/chart/MiniProgress.vue +57 -57
  144. package/src/components/chart/Radar.vue +80 -80
  145. package/src/components/chart/RankingList.vue +60 -60
  146. package/src/components/chart/Trend.vue +79 -79
  147. package/src/components/chart/index.less +9 -9
  148. package/src/components/checkbox/ColorCheckbox.vue +157 -157
  149. package/src/components/input/IInput.vue +66 -66
  150. package/src/components/menu/SideMenu.vue +75 -75
  151. package/src/components/menu/menu.js +273 -273
  152. package/src/components/tool/AStepItem.vue +60 -60
  153. package/src/layouts/CommonLayout.vue +56 -56
  154. package/src/lib.js +1 -1
  155. package/src/mock/extend/index.js +84 -84
  156. package/src/mock/goods/index.js +108 -108
  157. package/src/pages/dashboard/workplace/WorkPlace.vue +141 -141
  158. package/src/pages/system/dictionary/index.vue +44 -44
  159. package/src/pages/system/monitor/loginInfor/index.vue +37 -37
  160. package/src/pages/system/monitor/operLog/index.vue +37 -37
  161. package/src/services/api/cas.js +79 -79
  162. package/src/store/modules/setting.js +119 -119
  163. package/src/utils/errorCode.js +6 -6
  164. package//350/277/201/347/247/273/346/227/245/345/277/227.md +15 -15
  165. package/.idea/MarsCodeWorkspaceAppSettings.xml +0 -7
  166. package/.idea/google-java-format.xml +0 -6
  167. package/.idea/inspectionProfiles/Project_Default.xml +0 -24
  168. package/.idea/jsLinters/eslint.xml +0 -6
  169. package/.idea/vue2-client.iml +0 -12
  170. package/.vscode/settings.json +0 -28
@@ -0,0 +1,780 @@
1
+ <template>
2
+ <div
3
+ ref="drawerRoot"
4
+ class="drawer"
5
+ :class="[{ 'drawer-collapsed': !isOpen, 'position-right': position === 'right' }, wrapperClassObject()]"
6
+ :style="drawerStyle">
7
+ <div
8
+ v-show="!isFrameConfig || showToggleInFrame"
9
+ class="drawer-toggle"
10
+ :class="{ 'toggle-collapsed': !isOpen }"
11
+ :style="[toggleButtonStyle, toggleButtonPositionStyle]"
12
+ @click="toggleDrawer">
13
+ <div class="arrow">
14
+ {{ arrowChar }}
15
+ </div>
16
+ </div>
17
+ <div class="drawer-content" v-show="isOpen" :style="contentStyle">
18
+ <x-report
19
+ ref="x_report"
20
+ :configName="queryParamsName"
21
+ :server-name="serverName"
22
+ :show-img-in-cell="true"
23
+ :display-only="true"
24
+ :edit-mode="false"
25
+ :show-save-button="false"
26
+ :no-padding="true"
27
+ :dont-format="true">
28
+ </x-report>
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <script>
34
+
35
+ import XReport from '@vue2-client/base-client/components/common/XReportGrid'
36
+ import { shortcutManager } from '@vue2-client/base-client/utils/shortcutManager'
37
+
38
+ export default {
39
+ components: {
40
+ XReport
41
+ },
42
+ name: 'XSidebar',
43
+ inject: {
44
+ getGridScopePath: { default: null }
45
+ },
46
+ props: {
47
+ // 配置参数
48
+ queryParamsName: {
49
+ type: String,
50
+ default: ''
51
+ },
52
+ serverName: {
53
+ type: String,
54
+ default: 'af-his'
55
+ },
56
+ // Frame 配置下是否依然显示收缩按钮(默认为 false,保持兼容老用法)
57
+ showToggleInFrame: {
58
+ type: Boolean,
59
+ default: false
60
+ },
61
+ // 是否允许该组件主动调整同级布局(默认不影响其它页面)
62
+ affectLayout: {
63
+ type: Boolean,
64
+ default: false
65
+ },
66
+ // 展开时所占宽度百分比(percent模式使用,影响父级 ant-col 的 flex 与 max-width)
67
+ expandedWidthPercent: {
68
+ type: Number,
69
+ default: 33.3
70
+ },
71
+ // 收缩时所占宽度百分比(percent模式使用)
72
+ collapsedWidthPercent: {
73
+ type: Number,
74
+ default: 2
75
+ },
76
+ // 展开时所占宽度像素值(px模式使用)
77
+ expandedWidth: {
78
+ type: Number,
79
+ default: 602
80
+ },
81
+ // 收缩时所占宽度像素值(px模式使用)
82
+ collapsedWidth: {
83
+ type: Number,
84
+ default: 26
85
+ },
86
+ // 侧边栏位置: 'left' 左侧侧边栏,'right' 右侧侧边栏
87
+ position: {
88
+ type: String,
89
+ default: 'left',
90
+ validator: value => ['left', 'right'].includes(value)
91
+ },
92
+ // 总宽度像素值(px模式使用)
93
+ totalWidth: {
94
+ type: Number,
95
+ default: 1638
96
+ },
97
+ // 宽度计算模式:'percent' 百分比模式,'px' 像素模式
98
+ // 使用示例:
99
+ // percent模式: <x-sidebar :width-mode="'percent'" :expanded-width-percent="40" :collapsed-width-percent="3" />
100
+ // px模式: <x-sidebar :width-mode="'px'" :expanded-width="500" :collapsed-width="30" />
101
+ widthMode: {
102
+ type: String,
103
+ default: 'percent',
104
+ validator: value => ['percent', 'px'].includes(value)
105
+ },
106
+ // 折叠时保持的行高(px),由外部传入
107
+ rowHeight: {
108
+ type: Number,
109
+ default: null
110
+ }
111
+ },
112
+ data () {
113
+ return {
114
+ isOpen: this.queryParamsName?.endsWith('Frame') || false,
115
+ // 定义主内容区域的最大和最小宽度百分比
116
+ mainWithData: [{ max: 80, min: 50 }],
117
+ rowResizeObserver: null,
118
+ drawerResizeObserver: null,
119
+ syncDrawerMinHeightRafId: null,
120
+ // 记录所在 a-row 有史以来出现过的最大高度,只增不减,展开/收起基准统一
121
+ maxRowHeight: null,
122
+ // 记录抽屉自身高度,用于按钮居中
123
+ drawerHeight: null
124
+ }
125
+ },
126
+ computed: {
127
+ isFrameConfig () {
128
+ return this.queryParamsName?.endsWith('Frame') || false
129
+ },
130
+ sidebarSnapshotKey () {
131
+ const routePath = this.$route?.path || 'default'
132
+ let parentPath = ''
133
+ if (typeof this.getGridScopePath === 'function') {
134
+ parentPath = this.getGridScopePath()
135
+ }
136
+ const myFullPath = parentPath
137
+ ? `${parentPath}/${this.queryParamsName}`
138
+ : this.queryParamsName
139
+ return `sidebar:${routePath}::${myFullPath}`
140
+ },
141
+ drawerStyle () {
142
+ const isPx = this.widthMode === 'px'
143
+ const base = !this.isOpen
144
+ ? isPx
145
+ ? { width: `${this.collapsedWidth}px` }
146
+ : { width: `${this.collapsedWidthPercent}%` }
147
+ : isPx
148
+ ? { width: `${this.expandedWidth}px`, display: 'flex', flexDirection: 'row', alignItems: 'stretch' }
149
+ : { width: `${this.expandedWidthPercent}%`, display: 'flex', flexDirection: 'row', alignItems: 'stretch' }
150
+ if (this.rowHeight) {
151
+ base['--sidebar-row-height'] = this.rowHeight + 'px'
152
+ }
153
+ return base
154
+ },
155
+ contentStyle () {
156
+ const isPx = this.widthMode === 'px'
157
+ if (!this.isOpen) return { display: 'none' }
158
+ if (isPx) {
159
+ const contentWidth = Math.max(0, (this.expandedWidth || 0) - (this.collapsedWidth || 0))
160
+ return { width: `${contentWidth}px`, flex: '1 1 auto', overflow: 'hidden' }
161
+ }
162
+ const contentPercent = Math.max(0, (this.expandedWidthPercent || 0) - (this.collapsedWidthPercent || 0))
163
+ return { width: `${contentPercent}%`, flex: '1 1 auto', overflow: 'hidden' }
164
+ },
165
+ toggleButtonStyle () {
166
+ const isPx = this.widthMode === 'px'
167
+ const width = isPx ? `${this.collapsedWidth}px` : `${this.collapsedWidthPercent}%`
168
+ // 优先用外部传入的 rowHeight,否则用内部计算的行高
169
+ const rowH = this.rowHeight || this.maxRowHeight
170
+ const top = rowH ? `${rowH / 2 - 24}px` : '50%'
171
+ return { width, top }
172
+ },
173
+ // 根据侧边栏位置和展开状态返回箭头字符
174
+ arrowChar () {
175
+ if (this.position === 'right') {
176
+ // 右侧侧边栏:展开时箭头指向右(收回),折叠时箭头指向左(展开)
177
+ return this.isOpen ? '‹' : '›'
178
+ }
179
+ // 左侧侧边栏:展开时箭头指向左(收回),折叠时箭头指向右(展开)
180
+ return this.isOpen ? '›' : '‹'
181
+ },
182
+ // 切换按钮的定位样式
183
+ toggleButtonPositionStyle () {
184
+ if (this.position === 'right') {
185
+ return { right: 0 }
186
+ }
187
+ return { left: 0 }
188
+ }
189
+ },
190
+ mounted () {
191
+ console.log('[XSidebar] mounted, isOpen:', this.isOpen, 'queryParamsName:', this.queryParamsName)
192
+ // 在挂载后调整父元素宽度(方法内部已区分是否影响布局)
193
+ this.updateLayout(this.isOpen)
194
+ // 如果抽屉初始状态为打开,设置padding
195
+ if (this.isOpen) {
196
+ this.updateCardBodyPadding()
197
+ this.activateSidebarScope()
198
+ } else {
199
+ // 折叠状态:延迟停用,等内层组件注册完成
200
+ this.scheduleDeactivateSidebarScope()
201
+ }
202
+ // 同步计算一次最大行高(此时 this.$el 已挂载,computed 属性立即响应,按钮 top 立即就位)
203
+ this.computeMaxRowHeight()
204
+ this.$nextTick(() => {
205
+ this.bindRowResizeObserver()
206
+ this.bindDrawerResizeObserver()
207
+ })
208
+ },
209
+ beforeDestroy () {
210
+ if (this._deactivateRetryTimer) {
211
+ clearTimeout(this._deactivateRetryTimer)
212
+ this._deactivateRetryTimer = null
213
+ }
214
+ if (this.syncDrawerMinHeightRafId) {
215
+ cancelAnimationFrame(this.syncDrawerMinHeightRafId)
216
+ this.syncDrawerMinHeightRafId = null
217
+ }
218
+ this.unbindRowResizeObserver()
219
+ this.unbindDrawerResizeObserver()
220
+ this.deactivateSidebarScope()
221
+ },
222
+ methods: {
223
+ // ========== 作用域管理 ==========
224
+ activateSidebarScope () {
225
+ if (!shortcutManager.isEnabled) return
226
+ const snapshot = shortcutManager.routeStateSnapshots.get(this.sidebarSnapshotKey)
227
+ if (snapshot?.tabStates?.size > 0) {
228
+ // 只恢复之前是激活状态的侧边栏内部作用域
229
+ snapshot.tabStates.forEach((wasActive, scopeId) => {
230
+ if (wasActive) {
231
+ shortcutManager.scopeActive.set(scopeId, true)
232
+ }
233
+ })
234
+ shortcutManager.routeStateSnapshots.delete(this.sidebarSnapshotKey)
235
+ }
236
+ },
237
+ scheduleDeactivateSidebarScope (retryCount = 0) {
238
+ const maxRetries = 20 // 增加到 20 次(2 秒)
239
+ const retryDelay = 100
240
+
241
+ this.$nextTick(() => {
242
+ if (this.isOpen) return
243
+
244
+ // 先尝试停用
245
+ this.deactivateSidebarScope()
246
+
247
+ if (retryCount < maxRetries) {
248
+ // ✅ 关键修改:不管 hasActiveChildScope 是什么,都继续重试
249
+ // 目的:等待内部组件完成注册
250
+ this._deactivateRetryTimer = setTimeout(() => {
251
+ this._deactivateRetryTimer = null
252
+ this.scheduleDeactivateSidebarScope(retryCount + 1)
253
+ }, retryDelay)
254
+ }
255
+ })
256
+ },
257
+ deactivateSidebarScope () {
258
+ if (!shortcutManager.isEnabled) return
259
+
260
+ let parentPath = ''
261
+ if (typeof this.getGridScopePath === 'function') {
262
+ parentPath = this.getGridScopePath()
263
+ }
264
+ const routePath = this.$route?.path || 'default'
265
+ const myFullPath = parentPath
266
+ ? `${parentPath}/${this.queryParamsName}`
267
+ : this.queryParamsName
268
+ const sidebarPrefix = `${routePath}::${myFullPath}/`
269
+
270
+ // 只收集侧边栏内部的作用域
271
+ const sidebarScopes = new Map()
272
+ shortcutManager.scopeActive.forEach((active, scopeId) => {
273
+ if (scopeId.startsWith(sidebarPrefix)) {
274
+ sidebarScopes.set(scopeId, active)
275
+ }
276
+ })
277
+
278
+ // 没有内部作用域,跳过
279
+ if (sidebarScopes.size === 0) return
280
+
281
+ // 检查是否有激活的
282
+ let hasActive = false
283
+ sidebarScopes.forEach((active) => {
284
+ if (active) hasActive = true
285
+ })
286
+ if (!hasActive) return
287
+
288
+ // 保存快照
289
+ shortcutManager.routeStateSnapshots.set(this.sidebarSnapshotKey, {
290
+ tabStates: new Map(sidebarScopes),
291
+ lastAccess: Date.now()
292
+ })
293
+
294
+ // 只停用侧边栏内部的
295
+ sidebarScopes.forEach((_, scopeId) => {
296
+ shortcutManager.setScopeActive(scopeId, false)
297
+ })
298
+ },
299
+ toggleDrawer () {
300
+ console.log('[XSidebar] toggleDrawer called, isOpen before:', this.isOpen, 'position:', this.position)
301
+ // 展开前读一次行高(此时仍为展开状态),更新最大高度记录,确保收起后基准正确
302
+ if (!this.isOpen) {
303
+ const row = this.getSidebarParentRow()
304
+ if (row) {
305
+ const h = Math.round(row.offsetHeight || row.getBoundingClientRect().height)
306
+ if (h > 0) {
307
+ if (this.maxRowHeight === null || h > this.maxRowHeight) {
308
+ this.maxRowHeight = h
309
+ }
310
+ }
311
+ }
312
+ }
313
+ const wasOpen = this.isOpen
314
+ this.isOpen = !this.isOpen
315
+ console.log('[XSidebar] isOpen after toggle:', this.isOpen)
316
+ console.log('[XSidebar] drawerStyle:', JSON.stringify(this.drawerStyle))
317
+ console.log('[XSidebar] contentStyle:', JSON.stringify(this.contentStyle))
318
+ this.$emit('on-drawer-change', this.isOpen)
319
+ this.updateLayout(this.isOpen)
320
+
321
+ if (this.isOpen && !wasOpen) {
322
+ this.activateSidebarScope()
323
+ } else if (!this.isOpen && wasOpen) {
324
+ this.deactivateSidebarScope()
325
+ }
326
+
327
+ if (this.isOpen) {
328
+ // 展开后行高可能微增,读一次最新值(只增不减)
329
+ this.syncDrawerMinHeightToParentRow()
330
+ this.$nextTick(() => {
331
+ this.updateCardBodyPadding()
332
+ })
333
+ }
334
+ },
335
+ getSidebarParentRow () {
336
+ if (!this.$el) return null
337
+ let currentCol = this.$el.parentNode
338
+ while (
339
+ currentCol &&
340
+ (!currentCol.className ||
341
+ !currentCol.className.includes ||
342
+ !currentCol.className.includes('ant-col'))
343
+ ) {
344
+ currentCol = currentCol.parentNode
345
+ }
346
+ if (!currentCol || !currentCol.parentNode) return null
347
+ const row = currentCol.parentNode
348
+ if (!row.className || !row.className.includes('ant-row')) return null
349
+ return row
350
+ },
351
+ // 展开/收起共用同一套参照:用 CSS 变量记录行高,箭头始终相对于该值居中,
352
+ // 不走 CSS transition,彻底避免 min-height 动画化导致的"缓慢下移"问题
353
+ scheduleSyncDrawerMinHeight () {
354
+ if (this.syncDrawerMinHeightRafId) return
355
+ this.syncDrawerMinHeightRafId = requestAnimationFrame(() => {
356
+ this.syncDrawerMinHeightRafId = null
357
+ this.syncDrawerMinHeightToParentRow()
358
+ })
359
+ },
360
+ // 同步读取行高并更新 maxRowHeight,供 mounted 在渲染前调用
361
+ computeMaxRowHeight () {
362
+ const root = this.$refs.drawerRoot
363
+ if (!root) return
364
+ const row = this.getSidebarParentRow()
365
+ if (!row) return
366
+ const raw = row.offsetHeight || row.getBoundingClientRect().height
367
+ const h = Math.round(raw)
368
+ if (h > 0 && (this.maxRowHeight === null || h > this.maxRowHeight)) {
369
+ this.maxRowHeight = h
370
+ }
371
+ },
372
+ syncDrawerMinHeightToParentRow () {
373
+ this.$nextTick(() => {
374
+ const root = this.$refs.drawerRoot
375
+ if (!root) return
376
+ const row = this.getSidebarParentRow()
377
+ if (!row) return
378
+ const raw = row.offsetHeight || row.getBoundingClientRect().height
379
+ const h = Math.round(raw)
380
+ if (h <= 0) return
381
+ // 只增不减:记录有史以来出现过的最大行高,作为收起后的定位基准
382
+ if (this.maxRowHeight === null || h > this.maxRowHeight) {
383
+ this.maxRowHeight = h
384
+ }
385
+ if (!this.rowResizeObserver && typeof ResizeObserver !== 'undefined') {
386
+ this.rowResizeObserver = new ResizeObserver(() => {
387
+ this.scheduleSyncDrawerMinHeight()
388
+ })
389
+ this.rowResizeObserver.observe(row)
390
+ }
391
+ })
392
+ },
393
+ bindRowResizeObserver () {
394
+ if (typeof ResizeObserver === 'undefined') return
395
+ this.unbindRowResizeObserver()
396
+ const row = this.getSidebarParentRow()
397
+ if (!row) return
398
+ this.rowResizeObserver = new ResizeObserver(() => {
399
+ this.scheduleSyncDrawerMinHeight()
400
+ })
401
+ this.rowResizeObserver.observe(row)
402
+ },
403
+ unbindRowResizeObserver () {
404
+ if (this.rowResizeObserver) {
405
+ this.rowResizeObserver.disconnect()
406
+ this.rowResizeObserver = null
407
+ }
408
+ },
409
+ bindDrawerResizeObserver () {
410
+ if (typeof ResizeObserver === 'undefined') return
411
+ this.unbindDrawerResizeObserver()
412
+ const root = this.$refs.drawerRoot
413
+ if (!root) return
414
+ this.drawerResizeObserver = new ResizeObserver(() => {
415
+ this.updateDrawerHeight()
416
+ })
417
+ this.drawerResizeObserver.observe(root)
418
+ },
419
+ unbindDrawerResizeObserver () {
420
+ if (this.drawerResizeObserver) {
421
+ this.drawerResizeObserver.disconnect()
422
+ this.drawerResizeObserver = null
423
+ }
424
+ },
425
+ updateDrawerHeight () {
426
+ const root = this.$refs.drawerRoot
427
+ if (!root) return
428
+ const h = root.offsetHeight || root.getBoundingClientRect().height
429
+ if (h > 0) {
430
+ this.drawerHeight = Math.round(h)
431
+ }
432
+ },
433
+ // 通用的样式保护方法
434
+ protectElementStyles (element, stylesToProtect = ['padding', 'padding-left', 'padding-right', 'padding-top', 'padding-bottom', 'margin', 'background-color', 'color', 'font-size', 'border']) {
435
+ const protectedStyles = {}
436
+
437
+ // 保存需要保护的样式
438
+ stylesToProtect.forEach(style => {
439
+ const value = element.style.getPropertyValue(style)
440
+ if (value) {
441
+ protectedStyles[style] = value
442
+ }
443
+ })
444
+
445
+ return protectedStyles
446
+ },
447
+
448
+ // 恢复保护的样式
449
+ restoreElementStyles (element, protectedStyles) {
450
+ Object.entries(protectedStyles).forEach(([property, value]) => {
451
+ if (value) {
452
+ element.style.setProperty(property, value, 'important')
453
+ }
454
+ })
455
+ },
456
+
457
+ // 安全地设置布局样式,保护其他样式
458
+ safeSetLayoutStyles (element, layoutStyles) {
459
+ // 保护所有可能的样式配置
460
+ const protectedStyles = this.protectElementStyles(element)
461
+
462
+ // 设置布局样式
463
+ Object.entries(layoutStyles).forEach(([property, value]) => {
464
+ // 将驼峰命名转换为CSS标准命名
465
+ const cssProperty = property.replace(/([A-Z])/g, '-$1').toLowerCase()
466
+ element.style.setProperty(cssProperty, value)
467
+ })
468
+
469
+ // 恢复保护的样式
470
+ this.restoreElementStyles(element, protectedStyles)
471
+ },
472
+ wrapperClassObject () {
473
+ const attrs = this.$attrs || {}
474
+ const classes = {}
475
+ const booleanStyleKeys = ['']
476
+ booleanStyleKeys.forEach(key => {
477
+ const val = attrs[key]
478
+ const truthy = val === true || val === '' || val === 'true'
479
+ if (truthy) classes[`x-sidebar-${key}`] = true
480
+ })
481
+ return classes
482
+ },
483
+ // 更新card-body的padding
484
+ updateCardBodyPadding () {
485
+ // widthMode 为空时才需要处理
486
+ if (!this.widthMode) { return }
487
+ this.$nextTick(() => {
488
+ const cardBody = this.$el.querySelector('.ant-card-body')
489
+ if (cardBody) {
490
+ cardBody.style.padding = '0px'
491
+ } else {
492
+ // 如果找不到元素,可能需要等待XReport完全渲染
493
+ setTimeout(() => {
494
+ const cardBody = this.$el.querySelector('.ant-card-body')
495
+ if (cardBody) {
496
+ cardBody.style.padding = '0px'
497
+ }
498
+ }, 500)
499
+ }
500
+ })
501
+ },
502
+ // 获取同级的其他所有a-col元素
503
+ getSiblingCols (className) {
504
+ try {
505
+ // 找到当前组件所在的a-col
506
+ let currentCol = this.$el.parentNode
507
+ while (currentCol && !currentCol.className.includes('ant-col')) {
508
+ currentCol = currentCol.parentNode
509
+ }
510
+ if (!currentCol) {
511
+ console.warn('当前组件不在a-col内')
512
+ return []
513
+ }
514
+ // 找到a-col的父元素(a-row)
515
+ const row = currentCol.parentNode
516
+ if (!row || !row.className.includes('ant-row')) {
517
+ console.warn('未找到父级a-row元素')
518
+ return []
519
+ }
520
+
521
+ // 如果没有指定 className,则返回该行下所有的 a-col 同级元素
522
+ const allCols = Array.from(row.children).filter(child => {
523
+ const isCol = child.className && child.className.includes && child.className.includes('ant-col')
524
+ if (!isCol) return false
525
+ if (!className) return true
526
+ return child.className.includes(className)
527
+ })
528
+
529
+ // 过滤掉当前a-col,返回其他所有a-col
530
+ return allCols.filter(col => col !== currentCol)
531
+ } catch (error) {
532
+ console.error('获取同级a-col时出错:', error)
533
+ return []
534
+ }
535
+ },
536
+ // 在同一行中查找距离当前侧边栏最近的内容列(从右往左找第一个 a-col)
537
+ findNearestContentCol (otherCols, currentCol) {
538
+ if (!otherCols || otherCols.length === 0 || !currentCol || !currentCol.parentNode) {
539
+ return null
540
+ }
541
+ let prev = currentCol.previousSibling
542
+ while (prev) {
543
+ if (otherCols.includes(prev)) {
544
+ return prev
545
+ }
546
+ prev = prev.previousSibling
547
+ }
548
+ // 如果没找到明显靠近的,就兜底返回第一个同级列
549
+ return otherCols[0] || null
550
+ },
551
+ // 计算mainCol,currentCol可以设置的总宽度
552
+ computeRemainingWidth (allElements, mainCol, currentCol) {
553
+ if (!allElements || allElements.length === 0) {
554
+ return '0px'
555
+ }
556
+
557
+ // 排除 mainCol 和 currentCol
558
+ const filteredElements = allElements.filter(element =>
559
+ element !== mainCol && element !== currentCol
560
+ )
561
+
562
+ let totalWidth = 0
563
+
564
+ // 计算过滤后元素的总宽度(包括外边距)
565
+ filteredElements.forEach(element => {
566
+ if (element && element.style) {
567
+ const computedStyle = window.getComputedStyle(element)
568
+ const width = parseFloat(computedStyle.width) || 0
569
+ const marginLeft = parseFloat(computedStyle.marginLeft) || 0
570
+ const marginRight = parseFloat(computedStyle.marginRight) || 0
571
+ totalWidth += width + marginLeft + marginRight
572
+ }
573
+ })
574
+
575
+ // 添加 mainCol 和 currentCol 的左右外边距
576
+ const addMarginsFromElements = (element) => {
577
+ if (element && element.style) {
578
+ const computedStyle = window.getComputedStyle(element)
579
+ const marginLeft = parseFloat(computedStyle.marginLeft) || 0
580
+ const marginRight = parseFloat(computedStyle.marginRight) || 0
581
+ totalWidth += marginLeft + marginRight
582
+ }
583
+ }
584
+
585
+ addMarginsFromElements(mainCol)
586
+ addMarginsFromElements(currentCol)
587
+
588
+ return totalWidth > 0 ? `${totalWidth}px` : '0px'
589
+ },
590
+ updateLayout (isOpen) {
591
+ console.log('[XSidebar] updateLayout called, isOpen:', isOpen)
592
+ this.$nextTick(() => {
593
+ try {
594
+ // 获取当前行内所有与侧边栏同级的 a-col 列
595
+ const otherCols = this.getSiblingCols()
596
+ console.log('[XSidebar] otherCols length:', otherCols.length)
597
+ if (otherCols.length > 0) {
598
+ let currentCol = this.$el.parentNode
599
+ while (currentCol && !currentCol.className.includes('ant-col')) {
600
+ currentCol = currentCol.parentNode
601
+ }
602
+ if (currentCol) {
603
+ console.log('[XSidebar] currentCol found, widthMode:', this.widthMode, 'affectLayout:', this.affectLayout)
604
+ console.log('[XSidebar] currentCol.style before:', currentCol.style.flex, currentCol.style.maxWidth)
605
+ const triggerResize = () => {
606
+ this.$nextTick(() => {
607
+ const tabComponent = this.$el.querySelector('.ant-tabs')
608
+ if (tabComponent) {
609
+ tabComponent.style.width = '100%'
610
+ window.dispatchEvent(new Event('resize'))
611
+ }
612
+ })
613
+ }
614
+
615
+ if (isOpen) {
616
+ if (this.affectLayout) {
617
+ if (this.widthMode === 'px') {
618
+ const drawerWidth = this.expandedWidth || 602
619
+ // 使用安全的方式设置布局样式
620
+ this.safeSetLayoutStyles(currentCol, {
621
+ flex: `0 0 ${drawerWidth}px`,
622
+ maxWidth: `${drawerWidth}px`,
623
+ transition: 'all 0.3s'
624
+ })
625
+ const mainCol = this.findNearestContentCol(otherCols, currentCol)
626
+ if (mainCol) {
627
+ const remainingWidth = this.computeRemainingWidth(this.getSiblingCols(), mainCol, currentCol)
628
+
629
+ // 使用安全的方式设置布局样式
630
+ this.safeSetLayoutStyles(mainCol, {
631
+ flex: '1 1 auto',
632
+ maxWidth: `calc(100% - ${remainingWidth} - ${drawerWidth}px)`,
633
+ transition: 'all 0.3s'
634
+ })
635
+ }
636
+ } else {
637
+ const drawerWidth = (this.expandedWidthPercent || 33.3)
638
+ // 使用安全的方式设置布局样式
639
+ this.safeSetLayoutStyles(currentCol, {
640
+ flex: `0 0 ${drawerWidth}%`,
641
+ maxWidth: `${drawerWidth}%`,
642
+ transition: 'all 0.3s'
643
+ })
644
+ const mainCol = this.findNearestContentCol(otherCols, currentCol)
645
+ if (mainCol) {
646
+ const remainingWidth = this.computeRemainingWidth(this.getSiblingCols(), mainCol, currentCol)
647
+
648
+ // 使用安全的方式设置布局样式
649
+ this.safeSetLayoutStyles(mainCol, {
650
+ flex: `0 0 calc(100% - ${remainingWidth} - ${drawerWidth}%)`,
651
+ maxWidth: `calc(100% - ${remainingWidth} - ${drawerWidth}%)`,
652
+ transition: 'all 0.3s'
653
+ })
654
+ }
655
+ }
656
+ } else {
657
+ // 不影响布局时:仍然需要设置展开后的宽度
658
+ if (this.widthMode === 'px') {
659
+ const drawerWidth = this.expandedWidth || 602
660
+ currentCol.style.flex = `0 0 ${drawerWidth}px`
661
+ currentCol.style.maxWidth = `${drawerWidth}px`
662
+ } else {
663
+ const drawerWidth = this.expandedWidthPercent || 33.3
664
+ currentCol.style.flex = `0 0 ${drawerWidth}%`
665
+ currentCol.style.maxWidth = `${drawerWidth}%`
666
+ }
667
+ }
668
+ triggerResize()
669
+ } else {
670
+ // 收缩状态
671
+ const width = this.widthMode === 'px' ? this.collapsedWidth + 'px' : this.collapsedWidthPercent + '%'
672
+ // 使用安全的方式设置布局样式
673
+ this.safeSetLayoutStyles(currentCol, {
674
+ flex: '0 0 ' + width,
675
+ maxWidth: width,
676
+ transition: 'all 0.3s'
677
+ })
678
+ const mainCol = this.findNearestContentCol(otherCols, currentCol)
679
+ if (mainCol) {
680
+ const remainingWidth = this.computeRemainingWidth(this.getSiblingCols(), mainCol, currentCol)
681
+
682
+ // 使用安全的方式设置布局样式
683
+ this.safeSetLayoutStyles(mainCol, {
684
+ flex: '1 1 auto',
685
+ maxWidth: `calc(100% - ${remainingWidth} - ${width})`,
686
+ transition: 'all 0.3s'
687
+ })
688
+ }
689
+ triggerResize()
690
+ }
691
+ }
692
+ }
693
+ } catch (error) {
694
+ console.error('布局更新失败:', error)
695
+ }
696
+ this.syncDrawerMinHeightToParentRow()
697
+ })
698
+ }
699
+ },
700
+ watch: {
701
+ queryParamsName: {
702
+ immediate: true,
703
+ handler (newVal) {
704
+ if (newVal?.endsWith('Frame')) {
705
+ this.isOpen = true
706
+ // 确保布局更新
707
+ this.$nextTick(() => {
708
+ this.updateLayout(true)
709
+ this.updateCardBodyPadding()
710
+ this.syncDrawerMinHeightToParentRow()
711
+ this.activateSidebarScope()
712
+ })
713
+ }
714
+ }
715
+ }
716
+ }
717
+ }
718
+ </script>
719
+
720
+ <style scoped>
721
+ .drawer {
722
+ position: relative;
723
+ height: 100%;
724
+ min-height: 100%;
725
+ width: 100%;
726
+ background-color: #fff;
727
+ border-left: solid rgba(240, 242, 245) 2px;
728
+ /* 明确列出需要过渡的属性,min-height 和 height 永远不走过渡,避免箭头"慢慢下移" */
729
+ transition: width 0.3s ease, background-color 0.3s ease, border-color 0.3s ease,
730
+ box-shadow 0.3s ease, border-radius 0.3s ease;
731
+ border-radius: 10px;
732
+ }
733
+ /* 折叠时保持高度 */
734
+ .drawer-collapsed {
735
+ width: 26px;
736
+ box-shadow: none;
737
+ height: var(--sidebar-row-height, 100px) !important;
738
+ min-height: var(--sidebar-row-height, 100px);
739
+ }
740
+ /* 展开时高度由内容撑开,但最小高度用同一变量保持箭头位置一致 */
741
+ .drawer:not(.drawer-collapsed) {
742
+ min-height: var(--sidebar-row-height, 100px);
743
+ }
744
+ .drawer-toggle {
745
+ position: absolute;
746
+ left: 0;
747
+ width: 26px;
748
+ height: 48px;
749
+ cursor: pointer;
750
+ background-color: rgba(255, 255, 255, 0) !important;
751
+ display: flex;
752
+ align-items: center;
753
+ justify-content: center;
754
+ z-index: 1000;
755
+ border-radius: 0;
756
+ box-shadow: none;
757
+ }
758
+ /* 右侧侧边栏:按钮在右侧 */
759
+ .position-right > .drawer-toggle {
760
+ left: auto;
761
+ right: 0;
762
+ }
763
+ .arrow {
764
+ font-size: 20px;
765
+ line-height: 1;
766
+ color: #94979E;
767
+ }
768
+ .drawer-content {
769
+ height: 100%;
770
+ padding-right: 12px;
771
+ margin-left: 26px;
772
+ }
773
+ /* 右侧侧边栏的内容区域 */
774
+ .position-right > .drawer-content {
775
+ padding-right: 26px;
776
+ padding-left: 12px;
777
+ margin-left: 0;
778
+ margin-right: 26px;
779
+ }
780
+ </style>