@bytenew/bn-bus-ui 1.1.461 → 1.1.463

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 (167) hide show
  1. package/install.js +134 -0
  2. package/package.json +20 -4
  3. package/packages/BnAddress/index.vue +141 -0
  4. package/packages/BnAddressParse/index.vue +75 -0
  5. package/packages/BnAdvancedFilter/BnFilterView.vue +145 -0
  6. package/packages/BnAdvancedFilter/index.vue +345 -0
  7. package/packages/BnAdvancedFilter/util.js +171 -0
  8. package/packages/BnCascader/BnCascader.vue +543 -0
  9. package/packages/BnCascader/BnCascaderPanel.vue +1331 -0
  10. package/packages/BnCascader/cascaderDisplay.js +102 -0
  11. package/packages/BnCheck/BnCheck.vue +253 -0
  12. package/packages/BnColumnConfig/columnConfigDialog.vue +134 -0
  13. package/packages/BnColumnConfig/component/childrenFormSetting/assocTable.vue +143 -0
  14. package/packages/BnColumnConfig/component/childrenFormSetting/assocTableSearch.vue +314 -0
  15. package/packages/BnColumnConfig/component/childrenFormSetting/index.vue +243 -0
  16. package/packages/BnColumnConfig/component/defaultSet/defaultSet.vue +114 -0
  17. package/packages/BnColumnConfig/component/defaultSet/stringDefault.vue +210 -0
  18. package/packages/BnColumnConfig/component/funcExprDialog/funcExprDialog.vue +126 -0
  19. package/packages/BnColumnConfig/component/packageFilter/index.vue +141 -0
  20. package/packages/BnColumnConfig/component/paraExplainSet/index.vue +156 -0
  21. package/packages/BnColumnConfig/component/setOption/setOption.vue +321 -0
  22. package/packages/BnColumnConfig/component/setRelationOption/ConditionList.vue +277 -0
  23. package/packages/BnColumnConfig/component/setRelationOption/LevelHeader.vue +144 -0
  24. package/packages/BnColumnConfig/component/setRelationOption/setRelationOption.vue +642 -0
  25. package/packages/BnColumnConfig/data.js +129 -0
  26. package/packages/BnColumnConfig/index.scss +23 -0
  27. package/packages/BnColumnConfig/index.vue +309 -0
  28. package/packages/BnCondVal/BnCondVal.vue +112 -0
  29. package/packages/BnCondVal/itemVal/dateRegVal.vue +39 -0
  30. package/packages/BnCondVal/itemVal/dateVal.vue +39 -0
  31. package/packages/BnCondVal/itemVal/numRegVal.vue +67 -0
  32. package/packages/BnCondVal/itemVal/numVal.vue +44 -0
  33. package/packages/BnCondVal/itemVal/relationVal.vue +73 -0
  34. package/packages/BnCondVal/itemVal/selectColumnVal.vue +58 -0
  35. package/packages/BnCondVal/itemVal/selectVal.vue +59 -0
  36. package/packages/BnCondVal/itemVal/stringVal.vue +156 -0
  37. package/packages/BnCondition/index.vue +551 -0
  38. package/packages/BnCondition/util.js +232 -0
  39. package/packages/BnDatePicker/BnDatePicker.vue +194 -0
  40. package/packages/BnDrop/BnDrop.vue +917 -0
  41. package/packages/BnEmptyTip/BnEmptyTip.vue +107 -0
  42. package/packages/BnExportOrder/BnExportOrder.vue +241 -0
  43. package/packages/BnExportOrder/validatorCode.vue +94 -0
  44. package/packages/BnFileView/BnFileView.vue +271 -0
  45. package/packages/BnFileView/FileDetail.vue +125 -0
  46. package/packages/BnFileView/videoPreview.vue +70 -0
  47. package/packages/BnFilterOption/BnFilterOption.vue +160 -0
  48. package/packages/BnFunExpr/BnFunExpr.vue +608 -0
  49. package/packages/BnImportOrder/BnImportOrder.vue +323 -0
  50. package/packages/BnImportTemplate/BnImportTemplate.vue +866 -0
  51. package/packages/BnImportTemplate/assets/merge_tip_img.png +0 -0
  52. package/packages/BnImportTemplate/assets/sheet_tip.png +0 -0
  53. package/packages/BnImportTemplate/assets/xls.png +0 -0
  54. package/packages/BnImportTemplate/components/ImportTemplateTrigger.vue +198 -0
  55. package/packages/BnImportTemplate/components/TemplateEditDialog.vue +340 -0
  56. package/packages/BnImportTemplate/components/TemplateFieldsConfig.vue +401 -0
  57. package/packages/BnImportTemplate/components/TemplateListDialog.vue +297 -0
  58. package/packages/BnInpNum/BnInpNum.vue +165 -0
  59. package/packages/BnMenus/BnMenus.vue +502 -0
  60. package/packages/BnMenus/MenuItem.vue +321 -0
  61. package/packages/BnOrderCard/BnOrderCard.vue +389 -0
  62. package/packages/BnOrderCard/orderRemark.vue +178 -0
  63. package/packages/BnOrderCard/util.js +94 -0
  64. package/packages/BnOrderDetail/BnOrderDetail.vue +338 -0
  65. package/packages/BnOrderDetail/filterLogByUser.vue +108 -0
  66. package/packages/BnOrderDetail/orderLogs.vue +53 -0
  67. package/packages/BnOrderDetail/showSubForm/index.vue +41 -0
  68. package/packages/BnOrderDetail/showSubForm/showChildTable.vue +61 -0
  69. package/packages/BnOrderDetail/showSubForm/showTimeLine.vue +131 -0
  70. package/packages/BnOrderDetail/showSubForm/tableCellCopy.vue +84 -0
  71. package/packages/BnOrderShare/index.vue +378 -0
  72. package/packages/BnOrderShare/shareUrlInp.vue +54 -0
  73. package/packages/BnRadio/BnRadio.vue +181 -0
  74. package/packages/BnRelation/BnRelation.vue +120 -0
  75. package/packages/BnSelect/BnSelect.vue +485 -0
  76. package/packages/BnSmartForm/BnBatchForm.vue +334 -0
  77. package/packages/BnSmartForm/BnBatchFormDialog.vue +423 -0
  78. package/packages/BnSmartForm/BnSmartElf/elfLog/index.vue +57 -0
  79. package/packages/BnSmartForm/BnSmartElf/index.vue +95 -0
  80. package/packages/BnSmartForm/BnSmartFormPsychic.js +629 -0
  81. package/packages/BnSmartForm/BnSmartFormUtil.js +524 -0
  82. package/packages/BnSmartForm/addressForm/index.vue +73 -0
  83. package/packages/BnSmartForm/checkboxForm/index.vue +99 -0
  84. package/packages/BnSmartForm/childrenForm/childFormFile.vue +237 -0
  85. package/packages/BnSmartForm/childrenForm/childrenFormBody.vue +260 -0
  86. package/packages/BnSmartForm/childrenForm/index.vue +110 -0
  87. package/packages/BnSmartForm/childrenForm/searchInventory.vue +115 -0
  88. package/packages/BnSmartForm/chooseAssocTable/chooseAssocTable.vue +451 -0
  89. package/packages/BnSmartForm/chooseAssocTable/chooseChildGood.vue +229 -0
  90. package/packages/BnSmartForm/chooseAssocTable/tableCellCopy.vue +84 -0
  91. package/packages/BnSmartForm/chooseChildOrder/chooseChildOrder.vue +158 -0
  92. package/packages/BnSmartForm/chooseIPaasData/chooseIPaasData.vue +307 -0
  93. package/packages/BnSmartForm/chooseIPaasData/tableCellCopy.vue +84 -0
  94. package/packages/BnSmartForm/choosePackage/choosePackage.vue +361 -0
  95. package/packages/BnSmartForm/dateDualForm/index.vue +37 -0
  96. package/packages/BnSmartForm/dateForm/index.vue +38 -0
  97. package/packages/BnSmartForm/fileForm/fileFormData.js +50 -0
  98. package/packages/BnSmartForm/fileForm/index.vue +240 -0
  99. package/packages/BnSmartForm/formItemFooter/formItemFooter.vue +38 -0
  100. package/packages/BnSmartForm/formItemTop/formItemTop.vue +42 -0
  101. package/packages/BnSmartForm/index.vue +1201 -0
  102. package/packages/BnSmartForm/numberForm/index.vue +63 -0
  103. package/packages/BnSmartForm/radioForm/index.vue +72 -0
  104. package/packages/BnSmartForm/receiveForm/index.vue +112 -0
  105. package/packages/BnSmartForm/relationForm/index.vue +82 -0
  106. package/packages/BnSmartForm/scoreForm/index.vue +39 -0
  107. package/packages/BnSmartForm/selectForm/index.vue +55 -0
  108. package/packages/BnSmartForm/showValForm/index.vue +42 -0
  109. package/packages/BnSmartForm/showValForm/showValFormTable.vue +104 -0
  110. package/packages/BnSmartForm/smartFormsCommon.scss +43 -0
  111. package/packages/BnSmartForm/stringForm/index.vue +170 -0
  112. package/packages/BnVirtPopover/index.vue +319 -0
  113. package/packages/BnWebLog/BnWebLog.vue +140 -0
  114. package/packages/BnWorkSettingDrop/advancedOptions.js +112 -0
  115. package/packages/BnWorkSettingDrop/benBenAIUtil.js +89 -0
  116. package/packages/BnWorkSettingDrop/index.vue +292 -0
  117. package/packages/font/iconfont.css +243 -0
  118. package/packages/font/iconfont.ttf +0 -0
  119. package/packages/font/iconfont.woff +0 -0
  120. package/packages/font/iconfont.woff2 +0 -0
  121. package/utils/addressParse-old.js +645 -0
  122. package/utils/addressParse.js +735 -0
  123. package/utils/config.js +68 -0
  124. package/utils/index.js +1171 -0
  125. package/dist/assocTableSearch-C14i_zJO.js +0 -349
  126. package/dist/assocTableSearch.css +0 -1
  127. package/dist/bn-bus-ui.es.js +0 -65
  128. package/dist/bn-bus-ui.umd.js +0 -49
  129. package/dist/chooseIPaasData-Cl_5qkFA.js +0 -391
  130. package/dist/chooseIPaasData.css +0 -1
  131. package/dist/defaultSet-I4xpf8a4.js +0 -297
  132. package/dist/defaultSet.css +0 -1
  133. package/dist/fileFormData-D_Q1vylE.js +0 -53
  134. package/dist/formItemFooter-CTA7rDtV.js +0 -108
  135. package/dist/formItemFooter.css +0 -1
  136. package/dist/funcExprDialog-Cm5BiRM3.js +0 -139
  137. package/dist/funcExprDialog.css +0 -1
  138. package/dist/index-B6b4uj8v.js +0 -51
  139. package/dist/index-BWdkDTbz.js +0 -109
  140. package/dist/index-BdZ1zOap.js +0 -89
  141. package/dist/index-BdzNjjMC.js +0 -64
  142. package/dist/index-BfpZqab2.js +0 -66
  143. package/dist/index-BmkiB4hr.js +0 -66
  144. package/dist/index-Br1sqCoo.js +0 -58
  145. package/dist/index-C9qrl-yc.js +0 -183
  146. package/dist/index-CXFJXCn5.js +0 -746
  147. package/dist/index-DF114jZq.js +0 -135
  148. package/dist/index-DFPfZ_Il.js +0 -178
  149. package/dist/index-DSEtu7TN.js +0 -44
  150. package/dist/index-Did0UUWV.js +0 -221
  151. package/dist/index-DrPj-tmI.js +0 -45
  152. package/dist/index-DzDf9s2W.js +0 -89
  153. package/dist/index-LnjudNEI.js +0 -118
  154. package/dist/index-ObCfCmDT.js +0 -45
  155. package/dist/index.css +0 -1
  156. package/dist/index2.css +0 -1
  157. package/dist/index3.css +0 -1
  158. package/dist/index4.css +0 -1
  159. package/dist/index5.css +0 -1
  160. package/dist/index6.css +0 -1
  161. package/dist/index7.css +0 -1
  162. package/dist/install-C-scqkds.js +0 -23103
  163. package/dist/install.css +0 -1
  164. package/dist/setOption-CSnWzOny.js +0 -329
  165. package/dist/setOption.css +0 -1
  166. package/dist/setRelationOption-CJcHdfaa.js +0 -5217
  167. package/dist/setRelationOption.css +0 -1
@@ -0,0 +1,543 @@
1
+ <!--
2
+ @Description: 级联选择器(完整版):选择框触发器 + 悬浮面板(BnCascaderPanel)
3
+ @Features:
4
+ - 点击选择框弹出级联面板,单选选中后自动收起面板
5
+ - 单选展示完整路径文本;多选展示 tag 列表,支持折叠与 tooltip
6
+ - 支持清空、单 tag 删除、禁用、三种尺寸(large / default / small)
7
+ - 面板相关能力(远程加载、lazy、列虚拟滚动等)均透传自 BnCascaderPanel
8
+ @Usage:
9
+ 基础:v-model 绑定选中值,options 传入本地树
10
+ 多选折叠:multiple collapse-tags :max-collapse-tags="3"
11
+ 自定义面板顶栏:#top 插槽(透传给 BnCascaderPanel)
12
+ @modelValue 格式(与 BnCascaderPanel 一致):
13
+ 单选 labelInValue=false → [1, 2, 3]
14
+ 单选 labelInValue=true → [{id:1, title:'...'}, ...]
15
+ 多选 labelInValue=false → [[1,2,3], [4,5,6]]
16
+ 多选 labelInValue=true → [[{id:1,...},...], [...]]
17
+ @Emits:
18
+ update:modelValue 选中值变化
19
+ change 选中值变化(与 update 同步触发)
20
+ visible-change 下拉面板显隐变化
21
+ @Slots:
22
+ top 面板工具栏扩展区(如清空按钮),透传至 BnCascaderPanel
23
+ @VERSION: 1.0
24
+ -->
25
+ <template>
26
+ <!-- el-popover 承载下拉面板,trigger 为自定义选择框 -->
27
+ <el-popover
28
+ ref="popoverRef"
29
+ :placement="placement"
30
+ trigger="click"
31
+ :show-arrow="false"
32
+ :show-after="0"
33
+ :hide-after="0"
34
+ transition="BnCascader-no-transition"
35
+ :disabled="disabled"
36
+ :teleported="teleported"
37
+ :popper-class="`BnCascader-popper ${popperClass}`.trim()"
38
+ @show="handlePopoverShow"
39
+ @hide="handlePopoverHide"
40
+ >
41
+ <!-- 触发器:模拟 Element Plus Cascader 选择框 -->
42
+ <template #reference>
43
+ <div class="BnCascader__trigger" :class="triggerClass" @mouseenter="hovering = true" @mouseleave="hovering = false">
44
+ <!-- 选中内容区 -->
45
+ <div class="BnCascader__selection">
46
+ <!-- 未选中:占位文案 -->
47
+ <span v-if="isEmptyValue" class="BnCascader__placeholder">{{ placeholder }}</span>
48
+
49
+ <!-- 单选:展示整条路径,如 Guide / Navigation / Top Navigation -->
50
+ <span
51
+ v-else-if="!multiple"
52
+ class="BnCascader__single-label"
53
+ :title="singleDisplayText"
54
+ >{{ singleDisplayText }}</span>
55
+
56
+ <!-- 多选:tag 列表,支持 collapseTags 折叠 -->
57
+ <div v-else class="BnCascader__tags">
58
+ <span
59
+ v-for="tag in visibleTags"
60
+ :key="tag.index"
61
+ class="BnCascader__tag"
62
+ >
63
+ <span class="BnCascader__tag-text" :title="tag.label">{{ tag.label }}</span>
64
+ <!-- 点击 x 删除单个 tag,不影响面板展开状态 -->
65
+ <i
66
+ v-if="!disabled"
67
+ class="BnCascader__tag-close bnUIcon bnUIcon-close"
68
+ @click.stop="removeTag(tag.index)"
69
+ />
70
+ </span>
71
+ <!-- 折叠时展示 +N,hover 可查看被折叠的全部 tag -->
72
+ <el-tooltip
73
+ v-if="collapsedCount > 0"
74
+ :disabled="!collapseTagsTooltip"
75
+ effect="dark"
76
+ placement="top"
77
+ >
78
+ <template #content>
79
+ <div class="BnCascader__collapse-tooltip">
80
+ <el-scrollbar max-height="320px">
81
+ <div v-for="tag in collapsedTags" :key="tag.index">{{ formatDisplayText(tag.path) }}</div>
82
+ </el-scrollbar>
83
+ </div>
84
+ </template>
85
+ <span class="BnCascader__tag BnCascader__tag--collapse">+ {{ collapsedCount }}</span>
86
+ </el-tooltip>
87
+ </div>
88
+ </div>
89
+
90
+ <!-- 右侧图标:hover 有值且 clearable 时清空替换箭头,否则展示下拉箭头 -->
91
+ <span class="BnCascader__suffix">
92
+ <i
93
+ v-if="showClear"
94
+ class="BnCascader__clear bnUIcon bnUIcon-clear"
95
+ @click.stop="clearValue"
96
+ />
97
+ <i
98
+ v-else
99
+ class="BnCascader__arrow bnUIcon bnUIcon-down"
100
+ :class="{ 'is-reverse': popoverVisible }"
101
+ />
102
+ </span>
103
+ </div>
104
+ </template>
105
+
106
+ <!-- 级联面板:props 透传 + v-model 双向绑定 -->
107
+ <BnCascaderPanel
108
+ ref="panelRef"
109
+ v-bind="$props"
110
+ v-model="panelValueModel"
111
+ @change="handleChange"
112
+ @changeCheckToLast="$emit('update:checkToLast',$event)"
113
+ @loadOver="loadOption = true"
114
+ @close="handlePanelClose">
115
+ <template v-if="$slots.top" #top>
116
+ <slot name="top"/>
117
+ </template>
118
+ </BnCascaderPanel>
119
+ </el-popover>
120
+ </template>
121
+
122
+ <script>
123
+ import {formatPathDisplay, isEmptyValue as checkEmptyValue} from './cascaderDisplay.js';
124
+ export default {
125
+ name: 'BnCascader',
126
+ props: {
127
+ /** 绑定值,格式见文件头 @modelValue 说明 */
128
+ modelValue: {},
129
+ /** 本地级联选项树,默认 [{ id, title, children }] */
130
+ options: { type: Array, default: () => [] },
131
+ /** 是否多选 */
132
+ multiple: Boolean,
133
+ /** 选项字段映射,如 { value: 'id', label: 'title', children: 'children' } */
134
+ optionProps: { default: () => ({}) },
135
+ /** labelInValue 为 true 时,返回对象保留的字段列表 */
136
+ valueProps: { type: Array },
137
+ /** true 返回完整对象路径,false 返回 id 路径 */
138
+ labelInValue: { type: Boolean, default: true },
139
+ /** 是否禁用 */
140
+ disabled: { type: Boolean, default: false },
141
+ /** 「选到最后一级」:多选勾选父级时选中所有叶子;单选开启后仅叶子可选 */
142
+ checkToLast: { default: false },
143
+ /** 是否隐藏面板内「选到最后一级」开关 */
144
+ hideCheckToLast: { type: Boolean, default: false },
145
+ /** 远程请求方法,签名 (url, data) => Promise */
146
+ postFunc: Function,
147
+ /** 远程请求附加参数 */
148
+ postData: { type: Object, default: () => ({}) },
149
+ /** 远程接口路径 */
150
+ pathUrl: { type: String, default: '' },
151
+ /** 远程模式:tree 一次拉树 / lazy 按级懒加载 */
152
+ remoteMode: { type: String, default: 'tree' },
153
+ /** lazy 模式请求体中的层级字段名 */
154
+ lazyLevelKey: { type: String, default: 'level' },
155
+ /** lazy 模式起始层级(默认 1,展开第一层时传 2) */
156
+ lazyLevelStart: { type: Number, default: 1 },
157
+ /** lazy 模式叶子节点标识字段 */
158
+ leafKey: { type: String, default: 'leaf' },
159
+ /** 远程 tree 模式是否在 mounted 时自动初始化 */
160
+ isInitOptions: { type: Boolean, default: true },
161
+ /** 单列超过该数量启用虚拟滚动 */
162
+ virtualThreshold: { type: Number, default: 40 },
163
+ /** 面板每列最大高度(px) */
164
+ columnHeight: { type: Number, default: 300 },
165
+ /** 未选中时的占位文案 */
166
+ placeholder: { type: String, default: '请选择' },
167
+ /** 是否显示清空按钮(hover 时替换箭头图标) */
168
+ clearable: { type: Boolean, default: true },
169
+ /** 路径各级之间的分隔符 */
170
+ separator: { type: String, default: ' / ' },
171
+ /** 单选是否展示完整层级路径 */
172
+ showAllLevels: { type: Boolean, default: true },
173
+ /** 多选 tag 是否折叠超出部分 */
174
+ collapseTags: { type: Boolean, default: false },
175
+ /** 折叠 tag 的 +N 是否启用 tooltip 展示全部 */
176
+ collapseTagsTooltip: { type: Boolean, default: true },
177
+ /** collapseTags 为 true 时,最多展示几个 tag */
178
+ maxCollapseTags: { type: Number, default: 1 },
179
+ /** popover 弹出位置,同 el-popover placement */
180
+ placement: { type: String, default: 'bottom-start' },
181
+ /** 面板是否 teleport 到 body */
182
+ teleported: { type: Boolean, default: true },
183
+ /** 面板 popper 附加 class */
184
+ popperClass: { type: String, default: '' },
185
+ /** 选择框尺寸:large / default / small */
186
+ size: {
187
+ type: String,
188
+ default: 'default',
189
+ validator: v => ['large', 'default', 'small'].includes(v)
190
+ }
191
+ },
192
+ emits: ['update:modelValue', 'change', 'visible-change','update:checkToLast'],
193
+ data() {
194
+ return {
195
+ /** popover 显隐本地状态,用于触发器样式与 visible-change */
196
+ popoverVisible: false,
197
+ /** 鼠标是否悬停在触发器上,用于控制清空按钮显示 */
198
+ hovering: false,
199
+ // 面板是否远程加载选项
200
+ loadOption: false,
201
+ };
202
+ },
203
+ computed: {
204
+ /** 路径展示相关配置,传给 cascaderDisplay 工具函数 */
205
+ displayOptions() {
206
+ return {
207
+ labelInValue: this.labelInValue,
208
+ optionProps: this.optionProps,
209
+ options: this.displayRootOptions,
210
+ separator: this.separator,
211
+ showAllLevels: this.showAllLevels
212
+ };
213
+ },
214
+ /** 回显解析用的选项树:优先 Panel 已加载数据(含远程 lazy),否则用 props.options */
215
+ displayRootOptions() {
216
+ const panelOptions = this.$refs.panelRef?.rootOptions;
217
+ if (Array.isArray(panelOptions) && panelOptions.length) {
218
+ return panelOptions;
219
+ }
220
+ return this.options || [];
221
+ },
222
+ /** 当前值是否为空(单选 null/[],多选 []) */
223
+ isEmptyValue() {
224
+ return checkEmptyValue(this.modelValue, {
225
+ multiple: this.multiple,
226
+ labelInValue: this.labelInValue
227
+ });
228
+ },
229
+ /** 单选模式下触发器展示的完整路径文本 */
230
+ singleDisplayText() {
231
+ return this.formatDisplayText(this.modelValue);
232
+ },
233
+ /** 多选模式下全部 tag 数量 */
234
+ selectedCount() {
235
+ return Array.isArray(this.modelValue) ? this.modelValue.length : 0;
236
+ },
237
+ /** 多选模式下当前可见 tag(受 collapseTags / maxCollapseTags 影响,仅格式化可见项) */
238
+ visibleTags() {
239
+ if (!this.selectedCount) {
240
+ return [];
241
+ }
242
+ const end = this.collapseTags
243
+ ? Math.min(this.maxCollapseTags, this.selectedCount)
244
+ : this.selectedCount;
245
+ const tags = [];
246
+ for (let index = 0; index < end; index++) {
247
+ const path = this.modelValue[index];
248
+ const label = this.formatDisplayText(path);
249
+ if (label) {
250
+ tags.push({ index, label, path });
251
+ }
252
+ }
253
+ return tags;
254
+ },
255
+ /** 多选模式下被折叠隐藏的 tag 列表(仅保留 path,展示时再格式化) */
256
+ collapsedTags() {
257
+ if (!this.collapseTags || this.selectedCount <= this.maxCollapseTags) {
258
+ return [];
259
+ }
260
+ return this.modelValue.slice(this.maxCollapseTags).map((path, offset) => ({
261
+ index: this.maxCollapseTags + offset,
262
+ path
263
+ }));
264
+ },
265
+ /** 被折叠的 tag 数量(+N 中的 N) */
266
+ collapsedCount() {
267
+ if (!this.collapseTags || this.selectedCount <= this.maxCollapseTags) {
268
+ return 0;
269
+ }
270
+ return this.selectedCount - this.maxCollapseTags;
271
+ },
272
+ /**
273
+ * Panel v-model 代理:读 modelValue prop,写时 emit 并在单选时关闭面板
274
+ */
275
+ panelValueModel: {
276
+ get() {
277
+ return this.modelValue;
278
+ },
279
+ set(value) {
280
+ this.handleValueUpdate(value);
281
+ }
282
+ },
283
+ /** 是否展示清空图标:可清空 + 未禁用 + 有值 + 鼠标悬停 */
284
+ showClear() {
285
+ return this.clearable && !this.disabled && !this.isEmptyValue && this.hovering;
286
+ },
287
+ /** 触发器动态 class:禁用 / 聚焦 / 多选 / 尺寸 */
288
+ triggerClass() {
289
+ return {
290
+ 'is-disabled': this.disabled,
291
+ 'is-focus': this.popoverVisible,
292
+ 'is-multiple': this.multiple,
293
+ [`BnCascader__trigger--${this.size}`]: true
294
+ };
295
+ }
296
+ },
297
+ watch: {
298
+ /** 面板显隐变化时向外抛出 visible-change */
299
+ popoverVisible(val) {
300
+ this.$emit('visible-change', val);
301
+ if (!val) {
302
+ this.$refs.panelRef?.clearSearch?.();
303
+ }
304
+ }
305
+ },
306
+ methods: {
307
+ /**
308
+ * 格式化单条路径展示文本
309
+ * labelInValue=false 时优先从 Panel 已加载树按 value 解析 title,远程 lazy 同样适用
310
+ */
311
+ formatDisplayText(path) {
312
+ if (!this.labelInValue && (!this.pathUrl || this.loadOption)) {
313
+ const panelText = this.$refs.panelRef?.getPathDisplayText?.(path, {
314
+ separator: this.separator,
315
+ showAllLevels: this.showAllLevels
316
+ });
317
+ if (panelText) {
318
+ return panelText;
319
+ }
320
+ }
321
+ return formatPathDisplay(path, this.displayOptions);
322
+ },
323
+ /** popover 打开:同步状态、聚焦搜索;禁用时立即关闭 */
324
+ handlePopoverShow() {
325
+ if (this.disabled) {
326
+ this.$refs.popoverRef?.hide?.();
327
+ return;
328
+ }
329
+ this.popoverVisible = true;
330
+ this.$refs.panelRef?.focusSearchInput?.();
331
+ },
332
+ /** popover 关闭:同步本地显隐状态 */
333
+ handlePopoverHide() {
334
+ this.popoverVisible = false;
335
+ },
336
+ /**
337
+ * Panel 选中值更新
338
+ * @param {*} value 新选中值
339
+ */
340
+ handleValueUpdate(value) {
341
+ this.$emit('update:modelValue', value);
342
+ },
343
+ /** 单选选中后关闭面板;使用位置:Panel @close */
344
+ handlePanelClose() {
345
+ if (this.multiple) {
346
+ return;
347
+ }
348
+ this.$refs.popoverRef?.hide?.();
349
+ },
350
+ /** 透传 Panel change 事件 */
351
+ handleChange(value) {
352
+ this.$emit('change', value);
353
+ },
354
+ /** 点击清空图标:重置为 empty 并触发 change */
355
+ clearValue() {
356
+ if (this.disabled) {
357
+ return;
358
+ }
359
+ const empty = this.multiple ? [] : (this.labelInValue ? null : []);
360
+ this.$emit('update:modelValue', empty);
361
+ this.$emit('change', empty);
362
+ },
363
+ /**
364
+ * 删除多选 tag
365
+ * @param {Number} index tag 在 modelValue 数组中的下标
366
+ */
367
+ removeTag(index) {
368
+ if (this.disabled || !this.multiple || !Array.isArray(this.modelValue)) {
369
+ return;
370
+ }
371
+ const next = [...this.modelValue];
372
+ next.splice(index, 1);
373
+ this.$emit('update:modelValue', next);
374
+ this.$emit('change', next);
375
+ }
376
+ }
377
+ };
378
+ </script>
379
+
380
+ <!-- popover 全局样式:去掉默认 padding,宽度随面板内容自适应 -->
381
+ <style>
382
+ .BnCascader-popper.el-popover.el-popper {
383
+ padding: 0 !important;
384
+ width: auto !important;
385
+ min-width: 0 !important;
386
+ }
387
+
388
+ /* 禁用 popover 显隐过渡,避免打开/关闭延迟 */
389
+ .BnCascader-no-transition-enter-active,
390
+ .BnCascader-no-transition-leave-active {
391
+ transition: none !important;
392
+ }
393
+ </style>
394
+
395
+ <style scoped lang="scss">
396
+ @import '../font/iconfont.css';
397
+
398
+ /* 触发器主体:对齐 Element Plus Select/Cascader 外观 */
399
+ .BnCascader__trigger {
400
+ position: relative;
401
+ display: inline-flex;
402
+ align-items: center;
403
+ width: 100%;
404
+ min-height: 32px;
405
+ padding: 1px 30px 1px 11px;
406
+ box-sizing: border-box;
407
+ font-size: 14px;
408
+ line-height: 24px;
409
+ color: #606266;
410
+ background-color: #fff;
411
+ border: 1px solid #dcdfe6;
412
+ border-radius: 4px;
413
+ cursor: pointer;
414
+
415
+ &:hover:not(.is-disabled) {
416
+ border-color: #c0c4cc;
417
+ }
418
+
419
+ &.is-focus:not(.is-disabled) {
420
+ border-color: #409eff;
421
+ }
422
+
423
+ &.is-disabled {
424
+ color: #a8abb2;
425
+ background-color: #f5f7fa;
426
+ border-color: #e4e7ed;
427
+ cursor: not-allowed;
428
+ }
429
+
430
+ &--large {
431
+ min-height: 40px;
432
+ font-size: 14px;
433
+ }
434
+
435
+ &--small {
436
+ min-height: 24px;
437
+ font-size: 12px;
438
+ padding-top: 0;
439
+ padding-bottom: 0;
440
+ }
441
+ }
442
+
443
+ /* 选中内容区,占据除 suffix 外的剩余宽度 */
444
+ .BnCascader__selection {
445
+ flex: 1;
446
+ min-width: 0;
447
+ overflow: hidden;
448
+ }
449
+
450
+ .BnCascader__placeholder {
451
+ color: #a8abb2;
452
+ }
453
+
454
+ /* 单选路径文本溢出省略 */
455
+ .BnCascader__single-label {
456
+ display: block;
457
+ overflow: hidden;
458
+ text-overflow: ellipsis;
459
+ white-space: nowrap;
460
+ }
461
+
462
+ /* 多选 tag 容器 */
463
+ .BnCascader__tags {
464
+ display: flex;
465
+ flex-wrap: wrap;
466
+ align-items: center;
467
+ gap: 6px;
468
+ padding: 2px 0;
469
+ }
470
+
471
+ .BnCascader__tag {
472
+ display: inline-flex;
473
+ align-items: center;
474
+ max-width: 100%;
475
+ height: 24px;
476
+ padding: 0 8px;
477
+ font-size: 12px;
478
+ color: #909399;
479
+ background: #f0f2f5;
480
+ border-radius: 4px;
481
+ box-sizing: border-box;
482
+
483
+ &--collapse {
484
+ padding: 0 8px;
485
+ cursor: default;
486
+ background: #f0f2f5;
487
+ }
488
+ }
489
+
490
+ .BnCascader__tag-text {
491
+ overflow: hidden;
492
+ text-overflow: ellipsis;
493
+ white-space: nowrap;
494
+ }
495
+
496
+ .BnCascader__tag-close {
497
+ margin-left: 4px;
498
+ font-size: 12px;
499
+ color: #909399;
500
+ cursor: pointer;
501
+ border-radius: 50%;
502
+ flex-shrink: 0;
503
+
504
+ &:hover {
505
+ color: #409eff;
506
+ background: #ecf5ff;
507
+ }
508
+ }
509
+
510
+ /* 右侧 suffix:清空 / 箭头互斥展示,固定宽度不占双图标空间 */
511
+ .BnCascader__suffix {
512
+ position: absolute;
513
+ top: 50%;
514
+ right: 8px;
515
+ display: inline-flex;
516
+ align-items: center;
517
+ transform: translateY(-50%);
518
+ color: #a8abb2;
519
+ }
520
+
521
+ .BnCascader__clear {
522
+ font-size: 14px;
523
+ cursor: pointer;
524
+
525
+ &:hover {
526
+ color: #909399;
527
+ }
528
+ }
529
+
530
+ .BnCascader__arrow {
531
+ font-size: 12px;
532
+
533
+ &.is-reverse {
534
+ transform: rotate(180deg);
535
+ }
536
+ }
537
+
538
+ /* 折叠 tag tooltip 内容 */
539
+ .BnCascader__collapse-tooltip {
540
+ max-width: 280px;
541
+ line-height: 1.6;
542
+ }
543
+ </style>