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,788 @@
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 expanded = isPx ? (parseFloat(this.expandedWidth) || 602) : (parseFloat(this.expandedWidthPercent) || 33.3)
144
+ const collapsed = isPx ? (parseFloat(this.collapsedWidth) || 26) : (parseFloat(this.collapsedWidthPercent) || 3)
145
+ const base = !this.isOpen
146
+ ? isPx
147
+ ? { width: `${collapsed}px` }
148
+ : { width: `${collapsed}%` }
149
+ : isPx
150
+ ? { width: `${expanded}px`, display: 'flex', flexDirection: 'row', alignItems: 'stretch' }
151
+ : { width: `${expanded}%`, display: 'flex', flexDirection: 'row', alignItems: 'stretch' }
152
+ if (this.rowHeight) {
153
+ base['--sidebar-row-height'] = this.rowHeight + 'px'
154
+ }
155
+ return base
156
+ },
157
+ contentStyle () {
158
+ const isPx = this.widthMode === 'px'
159
+ if (!this.isOpen) return { display: 'none' }
160
+ if (isPx) {
161
+ const expanded = parseFloat(this.expandedWidth) || 0
162
+ const collapsed = parseFloat(this.collapsedWidth) || 0
163
+ const contentWidth = Math.max(0, expanded - collapsed)
164
+ return { width: `${contentWidth}px`, flex: '1 1 auto', overflow: 'hidden' }
165
+ }
166
+ const expandedPct = parseFloat(this.expandedWidthPercent) || 0
167
+ const collapsedPct = parseFloat(this.collapsedWidthPercent) || 0
168
+ const contentPercent = Math.max(0, expandedPct - collapsedPct)
169
+ return { width: `${contentPercent}%`, flex: '1 1 auto', overflow: 'hidden' }
170
+ },
171
+ toggleButtonStyle () {
172
+ const isPx = this.widthMode === 'px'
173
+ const width = isPx ? `${this.collapsedWidth}px` : `${this.collapsedWidthPercent}%`
174
+ // 优先用外部传入的 rowHeight,否则用内部计算的行高
175
+ const rowH = this.rowHeight || this.maxRowHeight
176
+ const top = rowH ? `${rowH / 2 - 24}px` : '50%'
177
+ return { width, top }
178
+ },
179
+ // 根据侧边栏位置和展开状态返回箭头字符
180
+ arrowChar () {
181
+ if (this.position === 'right') {
182
+ // 右侧侧边栏:展开时箭头指向右(收回),折叠时箭头指向左(展开)
183
+ return this.isOpen ? '‹' : '›'
184
+ }
185
+ // 左侧侧边栏:展开时箭头指向左(收回),折叠时箭头指向右(展开)
186
+ return this.isOpen ? '›' : '‹'
187
+ },
188
+ // 切换按钮的定位样式
189
+ toggleButtonPositionStyle () {
190
+ if (this.position === 'right') {
191
+ return { right: 0 }
192
+ }
193
+ return { left: 0 }
194
+ }
195
+ },
196
+ mounted () {
197
+ console.log('[XSidebar] mounted, isOpen:', this.isOpen, 'queryParamsName:', this.queryParamsName)
198
+ // 在挂载后调整父元素宽度(方法内部已区分是否影响布局)
199
+ this.updateLayout(this.isOpen)
200
+ // 如果抽屉初始状态为打开,设置padding
201
+ if (this.isOpen) {
202
+ this.updateCardBodyPadding()
203
+ this.activateSidebarScope()
204
+ } else {
205
+ // 折叠状态:延迟停用,等内层组件注册完成
206
+ this.scheduleDeactivateSidebarScope()
207
+ }
208
+ // 同步计算一次最大行高(此时 this.$el 已挂载,computed 属性立即响应,按钮 top 立即就位)
209
+ this.computeMaxRowHeight()
210
+ this.$nextTick(() => {
211
+ this.bindRowResizeObserver()
212
+ this.bindDrawerResizeObserver()
213
+ })
214
+ },
215
+ beforeDestroy () {
216
+ if (this._deactivateRetryTimer) {
217
+ clearTimeout(this._deactivateRetryTimer)
218
+ this._deactivateRetryTimer = null
219
+ }
220
+ if (this.syncDrawerMinHeightRafId) {
221
+ cancelAnimationFrame(this.syncDrawerMinHeightRafId)
222
+ this.syncDrawerMinHeightRafId = null
223
+ }
224
+ this.unbindRowResizeObserver()
225
+ this.unbindDrawerResizeObserver()
226
+ this.deactivateSidebarScope()
227
+ },
228
+ methods: {
229
+ // ========== 作用域管理 ==========
230
+ activateSidebarScope () {
231
+ if (!shortcutManager.isEnabled) return
232
+ const snapshot = shortcutManager.routeStateSnapshots.get(this.sidebarSnapshotKey)
233
+ if (snapshot?.tabStates?.size > 0) {
234
+ // 只恢复之前是激活状态的侧边栏内部作用域
235
+ snapshot.tabStates.forEach((wasActive, scopeId) => {
236
+ if (wasActive) {
237
+ shortcutManager.scopeActive.set(scopeId, true)
238
+ }
239
+ })
240
+ shortcutManager.routeStateSnapshots.delete(this.sidebarSnapshotKey)
241
+ }
242
+ },
243
+ scheduleDeactivateSidebarScope (retryCount = 0) {
244
+ const maxRetries = 20 // 增加到 20 次(2 秒)
245
+ const retryDelay = 100
246
+
247
+ this.$nextTick(() => {
248
+ if (this.isOpen) return
249
+
250
+ // 先尝试停用
251
+ this.deactivateSidebarScope()
252
+
253
+ if (retryCount < maxRetries) {
254
+ // ✅ 关键修改:不管 hasActiveChildScope 是什么,都继续重试
255
+ // 目的:等待内部组件完成注册
256
+ this._deactivateRetryTimer = setTimeout(() => {
257
+ this._deactivateRetryTimer = null
258
+ this.scheduleDeactivateSidebarScope(retryCount + 1)
259
+ }, retryDelay)
260
+ }
261
+ })
262
+ },
263
+ deactivateSidebarScope () {
264
+ if (!shortcutManager.isEnabled) return
265
+
266
+ let parentPath = ''
267
+ if (typeof this.getGridScopePath === 'function') {
268
+ parentPath = this.getGridScopePath()
269
+ }
270
+ const routePath = this.$route?.path || 'default'
271
+ const myFullPath = parentPath
272
+ ? `${parentPath}/${this.queryParamsName}`
273
+ : this.queryParamsName
274
+ const sidebarPrefix = `${routePath}::${myFullPath}/`
275
+
276
+ // 只收集侧边栏内部的作用域
277
+ const sidebarScopes = new Map()
278
+ shortcutManager.scopeActive.forEach((active, scopeId) => {
279
+ if (scopeId.startsWith(sidebarPrefix)) {
280
+ sidebarScopes.set(scopeId, active)
281
+ }
282
+ })
283
+
284
+ // 没有内部作用域,跳过
285
+ if (sidebarScopes.size === 0) return
286
+
287
+ // 检查是否有激活的
288
+ let hasActive = false
289
+ sidebarScopes.forEach((active) => {
290
+ if (active) hasActive = true
291
+ })
292
+ if (!hasActive) return
293
+
294
+ // 保存快照
295
+ shortcutManager.routeStateSnapshots.set(this.sidebarSnapshotKey, {
296
+ tabStates: new Map(sidebarScopes),
297
+ lastAccess: Date.now()
298
+ })
299
+
300
+ // 只停用侧边栏内部的
301
+ sidebarScopes.forEach((_, scopeId) => {
302
+ shortcutManager.setScopeActive(scopeId, false)
303
+ })
304
+ },
305
+ toggleDrawer () {
306
+ console.log('[XSidebar] toggleDrawer called, isOpen before:', this.isOpen, 'position:', this.position)
307
+ // 展开前读一次行高(此时仍为展开状态),更新最大高度记录,确保收起后基准正确
308
+ if (!this.isOpen) {
309
+ const row = this.getSidebarParentRow()
310
+ if (row) {
311
+ const h = Math.round(row.offsetHeight || row.getBoundingClientRect().height)
312
+ if (h > 0) {
313
+ if (this.maxRowHeight === null || h > this.maxRowHeight) {
314
+ this.maxRowHeight = h
315
+ }
316
+ }
317
+ }
318
+ }
319
+ const wasOpen = this.isOpen
320
+ this.isOpen = !this.isOpen
321
+ console.log('[XSidebar] isOpen after toggle:', this.isOpen)
322
+ console.log('[XSidebar] drawerStyle:', JSON.stringify(this.drawerStyle))
323
+ console.log('[XSidebar] contentStyle:', JSON.stringify(this.contentStyle))
324
+ this.$emit('on-drawer-change', this.isOpen)
325
+ this.updateLayout(this.isOpen)
326
+
327
+ if (this.isOpen && !wasOpen) {
328
+ this.activateSidebarScope()
329
+ } else if (!this.isOpen && wasOpen) {
330
+ this.deactivateSidebarScope()
331
+ }
332
+
333
+ if (this.isOpen) {
334
+ // 展开后行高可能微增,读一次最新值(只增不减)
335
+ this.syncDrawerMinHeightToParentRow()
336
+ this.$nextTick(() => {
337
+ this.updateCardBodyPadding()
338
+ })
339
+ }
340
+ },
341
+ getSidebarParentRow () {
342
+ if (!this.$el) return null
343
+ let currentCol = this.$el.parentNode
344
+ while (
345
+ currentCol &&
346
+ (!currentCol.className ||
347
+ !currentCol.className.includes ||
348
+ !currentCol.className.includes('ant-col'))
349
+ ) {
350
+ currentCol = currentCol.parentNode
351
+ }
352
+ if (!currentCol || !currentCol.parentNode) return null
353
+ const row = currentCol.parentNode
354
+ if (!row.className || !row.className.includes('ant-row')) return null
355
+ return row
356
+ },
357
+ // 展开/收起共用同一套参照:用 CSS 变量记录行高,箭头始终相对于该值居中,
358
+ // 不走 CSS transition,彻底避免 min-height 动画化导致的"缓慢下移"问题
359
+ scheduleSyncDrawerMinHeight () {
360
+ if (this.syncDrawerMinHeightRafId) return
361
+ this.syncDrawerMinHeightRafId = requestAnimationFrame(() => {
362
+ this.syncDrawerMinHeightRafId = null
363
+ this.syncDrawerMinHeightToParentRow()
364
+ })
365
+ },
366
+ // 同步读取行高并更新 maxRowHeight,供 mounted 在渲染前调用
367
+ computeMaxRowHeight () {
368
+ const root = this.$refs.drawerRoot
369
+ if (!root) return
370
+ const row = this.getSidebarParentRow()
371
+ if (!row) return
372
+ const raw = row.offsetHeight || row.getBoundingClientRect().height
373
+ const h = Math.round(raw)
374
+ if (h > 0 && (this.maxRowHeight === null || h > this.maxRowHeight)) {
375
+ this.maxRowHeight = h
376
+ }
377
+ },
378
+ syncDrawerMinHeightToParentRow () {
379
+ this.$nextTick(() => {
380
+ const root = this.$refs.drawerRoot
381
+ if (!root) return
382
+ const row = this.getSidebarParentRow()
383
+ if (!row) return
384
+ const raw = row.offsetHeight || row.getBoundingClientRect().height
385
+ const h = Math.round(raw)
386
+ if (h <= 0) return
387
+ // 只增不减:记录有史以来出现过的最大行高,作为收起后的定位基准
388
+ if (this.maxRowHeight === null || h > this.maxRowHeight) {
389
+ this.maxRowHeight = h
390
+ }
391
+ if (!this.rowResizeObserver && typeof ResizeObserver !== 'undefined') {
392
+ this.rowResizeObserver = new ResizeObserver(() => {
393
+ this.scheduleSyncDrawerMinHeight()
394
+ })
395
+ this.rowResizeObserver.observe(row)
396
+ }
397
+ })
398
+ },
399
+ bindRowResizeObserver () {
400
+ if (typeof ResizeObserver === 'undefined') return
401
+ this.unbindRowResizeObserver()
402
+ const row = this.getSidebarParentRow()
403
+ if (!row) return
404
+ this.rowResizeObserver = new ResizeObserver(() => {
405
+ this.scheduleSyncDrawerMinHeight()
406
+ })
407
+ this.rowResizeObserver.observe(row)
408
+ },
409
+ unbindRowResizeObserver () {
410
+ if (this.rowResizeObserver) {
411
+ this.rowResizeObserver.disconnect()
412
+ this.rowResizeObserver = null
413
+ }
414
+ },
415
+ bindDrawerResizeObserver () {
416
+ if (typeof ResizeObserver === 'undefined') return
417
+ this.unbindDrawerResizeObserver()
418
+ const root = this.$refs.drawerRoot
419
+ if (!root) return
420
+ this.drawerResizeObserver = new ResizeObserver(() => {
421
+ this.updateDrawerHeight()
422
+ })
423
+ this.drawerResizeObserver.observe(root)
424
+ },
425
+ unbindDrawerResizeObserver () {
426
+ if (this.drawerResizeObserver) {
427
+ this.drawerResizeObserver.disconnect()
428
+ this.drawerResizeObserver = null
429
+ }
430
+ },
431
+ updateDrawerHeight () {
432
+ const root = this.$refs.drawerRoot
433
+ if (!root) return
434
+ const h = root.offsetHeight || root.getBoundingClientRect().height
435
+ if (h > 0) {
436
+ this.drawerHeight = Math.round(h)
437
+ }
438
+ },
439
+ // 通用的样式保护方法
440
+ protectElementStyles (element, stylesToProtect = ['padding', 'padding-left', 'padding-right', 'padding-top', 'padding-bottom', 'margin', 'background-color', 'color', 'font-size', 'border']) {
441
+ const protectedStyles = {}
442
+
443
+ // 保存需要保护的样式
444
+ stylesToProtect.forEach(style => {
445
+ const value = element.style.getPropertyValue(style)
446
+ if (value) {
447
+ protectedStyles[style] = value
448
+ }
449
+ })
450
+
451
+ return protectedStyles
452
+ },
453
+
454
+ // 恢复保护的样式
455
+ restoreElementStyles (element, protectedStyles) {
456
+ Object.entries(protectedStyles).forEach(([property, value]) => {
457
+ if (value) {
458
+ element.style.setProperty(property, value, 'important')
459
+ }
460
+ })
461
+ },
462
+
463
+ // 安全地设置布局样式,保护其他样式
464
+ safeSetLayoutStyles (element, layoutStyles) {
465
+ // 保护所有可能的样式配置
466
+ const protectedStyles = this.protectElementStyles(element)
467
+
468
+ // 设置布局样式
469
+ Object.entries(layoutStyles).forEach(([property, value]) => {
470
+ // 将驼峰命名转换为CSS标准命名
471
+ const cssProperty = property.replace(/([A-Z])/g, '-$1').toLowerCase()
472
+ element.style.setProperty(cssProperty, value)
473
+ })
474
+
475
+ // 恢复保护的样式
476
+ this.restoreElementStyles(element, protectedStyles)
477
+ },
478
+ wrapperClassObject () {
479
+ const attrs = this.$attrs || {}
480
+ const classes = {}
481
+ const booleanStyleKeys = ['']
482
+ booleanStyleKeys.forEach(key => {
483
+ const val = attrs[key]
484
+ const truthy = val === true || val === '' || val === 'true'
485
+ if (truthy) classes[`x-sidebar-${key}`] = true
486
+ })
487
+ return classes
488
+ },
489
+ // 更新card-body的padding
490
+ updateCardBodyPadding () {
491
+ // widthMode 为空时才需要处理
492
+ if (!this.widthMode) { return }
493
+ this.$nextTick(() => {
494
+ const cardBody = this.$el.querySelector('.ant-card-body')
495
+ if (cardBody) {
496
+ cardBody.style.padding = '0px'
497
+ } else {
498
+ // 如果找不到元素,可能需要等待XReport完全渲染
499
+ setTimeout(() => {
500
+ const cardBody = this.$el.querySelector('.ant-card-body')
501
+ if (cardBody) {
502
+ cardBody.style.padding = '0px'
503
+ }
504
+ }, 500)
505
+ }
506
+ })
507
+ },
508
+ // 获取同级的其他所有a-col元素
509
+ getSiblingCols (className) {
510
+ try {
511
+ // 找到当前组件所在的a-col
512
+ let currentCol = this.$el.parentNode
513
+ while (currentCol && !currentCol.className.includes('ant-col')) {
514
+ currentCol = currentCol.parentNode
515
+ }
516
+ if (!currentCol) {
517
+ console.warn('当前组件不在a-col内')
518
+ return []
519
+ }
520
+ // 找到a-col的父元素(a-row)
521
+ const row = currentCol.parentNode
522
+ if (!row || !row.className.includes('ant-row')) {
523
+ console.warn('未找到父级a-row元素')
524
+ return []
525
+ }
526
+
527
+ // 如果没有指定 className,则返回该行下所有的 a-col 同级元素
528
+ const allCols = Array.from(row.children).filter(child => {
529
+ const isCol = child.className && child.className.includes && child.className.includes('ant-col')
530
+ if (!isCol) return false
531
+ if (!className) return true
532
+ return child.className.includes(className)
533
+ })
534
+
535
+ // 过滤掉当前a-col,返回其他所有a-col
536
+ return allCols.filter(col => col !== currentCol)
537
+ } catch (error) {
538
+ console.error('获取同级a-col时出错:', error)
539
+ return []
540
+ }
541
+ },
542
+ // 在同一行中查找距离当前侧边栏最近的内容列(从右往左找第一个 a-col)
543
+ findNearestContentCol (otherCols, currentCol) {
544
+ if (!otherCols || otherCols.length === 0 || !currentCol || !currentCol.parentNode) {
545
+ return null
546
+ }
547
+ let prev = currentCol.previousSibling
548
+ while (prev) {
549
+ if (otherCols.includes(prev)) {
550
+ return prev
551
+ }
552
+ prev = prev.previousSibling
553
+ }
554
+ // 如果没找到明显靠近的,就兜底返回第一个同级列
555
+ return otherCols[0] || null
556
+ },
557
+ // 计算mainCol,currentCol可以设置的总宽度
558
+ computeRemainingWidth (allElements, mainCol, currentCol) {
559
+ if (!allElements || allElements.length === 0) {
560
+ return '0px'
561
+ }
562
+
563
+ // 排除 mainCol 和 currentCol
564
+ const filteredElements = allElements.filter(element =>
565
+ element !== mainCol && element !== currentCol
566
+ )
567
+
568
+ let totalWidth = 0
569
+
570
+ // 计算过滤后元素的总宽度(包括外边距)
571
+ filteredElements.forEach(element => {
572
+ if (element && element.style) {
573
+ const computedStyle = window.getComputedStyle(element)
574
+ const width = parseFloat(computedStyle.width) || 0
575
+ const marginLeft = parseFloat(computedStyle.marginLeft) || 0
576
+ const marginRight = parseFloat(computedStyle.marginRight) || 0
577
+ totalWidth += width + marginLeft + marginRight
578
+ }
579
+ })
580
+
581
+ // 添加 mainCol 和 currentCol 的左右外边距
582
+ const addMarginsFromElements = (element) => {
583
+ if (element && element.style) {
584
+ const computedStyle = window.getComputedStyle(element)
585
+ const marginLeft = parseFloat(computedStyle.marginLeft) || 0
586
+ const marginRight = parseFloat(computedStyle.marginRight) || 0
587
+ totalWidth += marginLeft + marginRight
588
+ }
589
+ }
590
+
591
+ addMarginsFromElements(mainCol)
592
+ addMarginsFromElements(currentCol)
593
+
594
+ return totalWidth > 0 ? `${totalWidth}px` : '0px'
595
+ },
596
+ updateLayout (isOpen) {
597
+ console.log('[XSidebar] updateLayout called, isOpen:', isOpen)
598
+ this.$nextTick(() => {
599
+ try {
600
+ // 获取当前行内所有与侧边栏同级的 a-col 列
601
+ const otherCols = this.getSiblingCols()
602
+ console.log('[XSidebar] otherCols length:', otherCols.length)
603
+ if (otherCols.length > 0) {
604
+ let currentCol = this.$el.parentNode
605
+ while (currentCol && !currentCol.className.includes('ant-col')) {
606
+ currentCol = currentCol.parentNode
607
+ }
608
+ if (currentCol) {
609
+ console.log('[XSidebar] currentCol found, widthMode:', this.widthMode, 'affectLayout:', this.affectLayout)
610
+ console.log('[XSidebar] currentCol.style before:', currentCol.style.flex, currentCol.style.maxWidth)
611
+ const triggerResize = () => {
612
+ this.$nextTick(() => {
613
+ const tabComponent = this.$el.querySelector('.ant-tabs')
614
+ if (tabComponent) {
615
+ tabComponent.style.width = '100%'
616
+ window.dispatchEvent(new Event('resize'))
617
+ }
618
+ })
619
+ }
620
+
621
+ if (isOpen) {
622
+ if (this.affectLayout) {
623
+ if (this.widthMode === 'px') {
624
+ const drawerWidth = parseFloat(this.expandedWidth) || 602
625
+ // 使用安全的方式设置布局样式
626
+ this.safeSetLayoutStyles(currentCol, {
627
+ flex: `0 0 ${drawerWidth}px`,
628
+ maxWidth: `${drawerWidth}px`,
629
+ transition: 'all 0.3s'
630
+ })
631
+ const mainCol = this.findNearestContentCol(otherCols, currentCol)
632
+ if (mainCol) {
633
+ const remainingWidth = this.computeRemainingWidth(this.getSiblingCols(), mainCol, currentCol)
634
+
635
+ // 使用安全的方式设置布局样式
636
+ this.safeSetLayoutStyles(mainCol, {
637
+ flex: '1 1 auto',
638
+ maxWidth: `calc(100% - ${remainingWidth} - ${drawerWidth}px)`,
639
+ transition: 'all 0.3s'
640
+ })
641
+ }
642
+ } else {
643
+ const drawerWidth = parseFloat(this.expandedWidthPercent) || 33.3
644
+ // 使用安全的方式设置布局样式
645
+ this.safeSetLayoutStyles(currentCol, {
646
+ flex: `0 0 ${drawerWidth}%`,
647
+ maxWidth: `${drawerWidth}%`,
648
+ transition: 'all 0.3s'
649
+ })
650
+ const mainCol = this.findNearestContentCol(otherCols, currentCol)
651
+ if (mainCol) {
652
+ const remainingWidth = this.computeRemainingWidth(this.getSiblingCols(), mainCol, currentCol)
653
+
654
+ // 使用安全的方式设置布局样式
655
+ this.safeSetLayoutStyles(mainCol, {
656
+ flex: `0 0 calc(100% - ${remainingWidth} - ${drawerWidth}%)`,
657
+ maxWidth: `calc(100% - ${remainingWidth} - ${drawerWidth}%)`,
658
+ transition: 'all 0.3s'
659
+ })
660
+ }
661
+ }
662
+ } else {
663
+ // 不影响布局时:仍然需要设置展开后的宽度
664
+ if (this.widthMode === 'px') {
665
+ const drawerWidth = parseFloat(this.expandedWidth) || 602
666
+ currentCol.style.flex = `0 0 ${drawerWidth}px`
667
+ currentCol.style.maxWidth = `${drawerWidth}px`
668
+ } else {
669
+ const drawerWidth = parseFloat(this.expandedWidthPercent) || 33.3
670
+ currentCol.style.flex = `0 0 ${drawerWidth}%`
671
+ currentCol.style.maxWidth = `${drawerWidth}%`
672
+ }
673
+ }
674
+ triggerResize()
675
+ } else {
676
+ // 收缩状态
677
+ const collapsed = parseFloat(this.collapsedWidth) || 26
678
+ const collapsedPct = parseFloat(this.collapsedWidthPercent) || 3
679
+ const width = this.widthMode === 'px' ? `${collapsed}px` : `${collapsedPct}%`
680
+ // 使用安全的方式设置布局样式
681
+ this.safeSetLayoutStyles(currentCol, {
682
+ flex: '0 0 ' + width,
683
+ maxWidth: width,
684
+ transition: 'all 0.3s'
685
+ })
686
+ const mainCol = this.findNearestContentCol(otherCols, currentCol)
687
+ if (mainCol) {
688
+ const remainingWidth = this.computeRemainingWidth(this.getSiblingCols(), mainCol, currentCol)
689
+
690
+ // 使用安全的方式设置布局样式
691
+ this.safeSetLayoutStyles(mainCol, {
692
+ flex: '1 1 auto',
693
+ maxWidth: `calc(100% - ${remainingWidth} - ${width})`,
694
+ transition: 'all 0.3s'
695
+ })
696
+ }
697
+ triggerResize()
698
+ }
699
+ }
700
+ }
701
+ } catch (error) {
702
+ console.error('布局更新失败:', error)
703
+ }
704
+ this.syncDrawerMinHeightToParentRow()
705
+ })
706
+ }
707
+ },
708
+ watch: {
709
+ queryParamsName: {
710
+ immediate: true,
711
+ handler (newVal) {
712
+ if (newVal?.endsWith('Frame')) {
713
+ this.isOpen = true
714
+ // 确保布局更新
715
+ this.$nextTick(() => {
716
+ this.updateLayout(true)
717
+ this.updateCardBodyPadding()
718
+ this.syncDrawerMinHeightToParentRow()
719
+ this.activateSidebarScope()
720
+ })
721
+ }
722
+ }
723
+ }
724
+ }
725
+ }
726
+ </script>
727
+
728
+ <style scoped>
729
+ .drawer {
730
+ position: relative;
731
+ height: 100%;
732
+ min-height: 100%;
733
+ width: 100%;
734
+ background-color: #fff;
735
+ border-left: solid rgba(240, 242, 245) 2px;
736
+ /* 明确列出需要过渡的属性,min-height 和 height 永远不走过渡,避免箭头"慢慢下移" */
737
+ transition: width 0.3s ease, background-color 0.3s ease, border-color 0.3s ease,
738
+ box-shadow 0.3s ease, border-radius 0.3s ease;
739
+ border-radius: 10px;
740
+ }
741
+ /* 折叠时保持高度 */
742
+ .drawer-collapsed {
743
+ width: 26px;
744
+ box-shadow: none;
745
+ height: var(--sidebar-row-height, 100px) !important;
746
+ min-height: var(--sidebar-row-height, 100px);
747
+ }
748
+ /* 展开时高度由内容撑开,但最小高度用同一变量保持箭头位置一致 */
749
+ .drawer:not(.drawer-collapsed) {
750
+ min-height: var(--sidebar-row-height, 100px);
751
+ }
752
+ .drawer-toggle {
753
+ position: absolute;
754
+ left: 0;
755
+ width: 26px;
756
+ height: 48px;
757
+ cursor: pointer;
758
+ background-color: rgba(255, 255, 255, 0) !important;
759
+ display: flex;
760
+ align-items: center;
761
+ justify-content: center;
762
+ z-index: 1000;
763
+ border-radius: 0;
764
+ box-shadow: none;
765
+ }
766
+ /* 右侧侧边栏:按钮在右侧 */
767
+ .position-right > .drawer-toggle {
768
+ left: auto;
769
+ right: 0;
770
+ }
771
+ .arrow {
772
+ font-size: 20px;
773
+ line-height: 1;
774
+ color: #94979E;
775
+ }
776
+ .drawer-content {
777
+ height: 100%;
778
+ padding-right: 12px;
779
+ margin-left: 26px;
780
+ }
781
+ /* 右侧侧边栏的内容区域 */
782
+ .position-right > .drawer-content {
783
+ padding-right: 26px;
784
+ padding-left: 12px;
785
+ margin-left: 0;
786
+ margin-right: 26px;
787
+ }
788
+ </style>