@nhdropshipping/y-components 1.0.76 → 1.0.77

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/components/ybutton.vue","../src/components/yinput.vue","../src/components/ytable.vue","../src/components/yselect.vue","../src/components/ypagination.vue","../src/components/ybadge.vue","../src/components/ydialog.vue","../src/components/ypopover.vue","../src/components/ytime.vue","../src/components/yswitch.vue","../src/components/yimage.vue","../src/components/ydropdown.vue","../src/components/ydrawer.vue","../src/components/ytree-node.vue","../src/components/ytree.vue","../src/components/QueryEncapsulation.vue","../src/components/ymessage/ymessageToast.vue","../src/components/ymessage/ymessage.ts","../src/components/hintTag.vue","../src/index.ts"],"sourcesContent":["<template>\n <template v-if=\"!isGroup\">\n <button\n class=\"y-btn\"\n :class=\"[\n `y-btn--${variant}`,\n `y-btn--${size}`,\n { 'is-block': block, 'is-loading': loading },\n groupPosition !== 'single' ? 'is-grouped' : '',\n groupPositionClass\n ]\"\n :type=\"htmlType\"\n :disabled=\"disabled || loading\"\n :aria-busy=\"loading ? 'true' : 'false'\"\n :aria-disabled=\"(disabled || loading) ? 'true' : 'false'\"\n @click=\"onClick\"\n >\n <span class=\"content\"><slot /></span>\n </button>\n </template>\n <template v-else>\n <div class=\"y-btn-group\" role=\"group\">\n <button\n v-for=\"(item, index) in groupItems\"\n :key=\"item.value ?? index\"\n class=\"y-btn\"\n :class=\"[\n `y-btn--${item.variant ?? variant}`,\n `y-btn--${item.size ?? size}`,\n 'is-grouped',\n index === 0 ? 'group-pos-start' : (index === (groupItems?.length || 0) - 1 ? 'group-pos-end' : 'group-pos-middle'),\n { 'is-loading': item.loading || loading }\n ]\"\n :type=\"htmlType\"\n :disabled=\"(item.disabled ?? false) || disabled || loading || item.loading\"\n :aria-busy=\"(item.loading || loading) ? 'true' : 'false'\"\n :aria-disabled=\"((item.disabled ?? false) || disabled || loading || item.loading) ? 'true' : 'false'\"\n :aria-label=\"item.ariaLabel || item.label\"\n @click=\"onGroupItemClick(item, $event)\"\n >\n <span class=\"content\">\n <svg v-if=\"item.icon === 'chevron-left'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" d=\"M12.78 15.22a.75.75 0 01-1.06 0l-5-5a.75.75 0 010-1.06l5-5a.75.75 0 111.06 1.06L8.81 10l3.97 3.97a.75.75 0 010 1.06z\" clip-rule=\"evenodd\" />\n </svg>\n <svg v-else-if=\"item.icon === 'chevron-right'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" d=\"M7.22 4.78a.75.75 0 011.06 0l5 5a.75.75 0 010 1.06l-5 5a.75.75 0 11-1.06-1.06L11.19 10 7.22 6.03a.75.75 0 010-1.06z\" clip-rule=\"evenodd\" />\n </svg>\n <span v-if=\"item.label && !item.onlyIcon\">{{ item.label }}</span>\n </span>\n </button>\n </div>\n </template>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nconst props = withDefaults(defineProps<{\n htmlType?: 'button' | 'submit' | 'reset'\n variant?: 'primary' | 'secondary' | 'danger' | 'success' | 'info'\n size?: 'tiny' | 'mini' | 'small' | 'medium' | 'large'\n disabled?: boolean\n loading?: boolean\n block?: boolean\n /**\n * 组合按钮位置:\n * - single: 非组合(默认)\n * - start: 组合按钮的第一个\n * - middle: 组合按钮中间\n * - end: 组合按钮最后一个\n */\n groupPosition?: 'single' | 'start' | 'middle' | 'end'\n /**\n * 若提供,则此组件内部渲染为按钮组\n */\n groupItems?: Array<{\n label: string\n value?: string | number\n disabled?: boolean\n loading?: boolean\n variant?: 'primary' | 'secondary' | 'danger' | 'success' | 'info'\n size?: 'tiny' | 'mini' | 'small' | 'medium' | 'large'\n icon?: 'chevron-left' | 'chevron-right'\n onlyIcon?: boolean\n ariaLabel?: string\n }>\n}>(), {\n htmlType: 'button',\n variant: 'primary',\n size: 'medium',\n disabled: false,\n loading: false,\n block: false,\n groupPosition: 'single',\n groupItems: undefined,\n})\n\nconst emit = defineEmits<{\n (e: 'click', ev: MouseEvent): void\n (e: 'group-click', value: string | number | undefined, ev: MouseEvent): void\n}>()\n\nfunction onClick(ev: MouseEvent) {\n if (props.disabled || props.loading) {\n ev.preventDefault()\n ev.stopPropagation()\n return\n }\n emit('click', ev)\n}\n\nconst groupPositionClass = computed(() => {\n switch (props.groupPosition) {\n case 'start':\n return 'group-pos-start'\n case 'middle':\n return 'group-pos-middle'\n case 'end':\n return 'group-pos-end'\n default:\n return 'group-pos-single'\n }\n})\n\nconst isGroup = computed(() => Array.isArray(props.groupItems) && props.groupItems.length > 0)\n\nfunction onGroupItemClick(item: { value?: string | number; disabled?: boolean; loading?: boolean }, ev: MouseEvent) {\n if (props.disabled || props.loading || item.disabled || item.loading) {\n ev.preventDefault()\n ev.stopPropagation()\n return\n }\n emit('group-click', item.value, ev)\n}\n</script>\n\n<style scoped>\n.y-btn {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n border: none;\n border-radius: 10px;\n font-weight: 600;\n cursor: pointer;\n transition: transform 0.05s ease, opacity 0.2s ease;\n outline: none;\n}\n\n/* 尺寸变体 */\n.y-btn--tiny {\n height: 20px;\n padding: 0 6px;\n font-size: 10px;\n border-radius: 3px;\n}\n\n.y-btn--mini {\n height: 24px;\n padding: 0 8px;\n font-size: 11px;\n border-radius: 4px;\n}\n\n.y-btn--small {\n height: 32px;\n padding: 0 12px;\n font-size: 12px;\n border-radius: 5px;\n}\n\n.y-btn--medium {\n height: 44px;\n padding: 0 16px;\n font-size: 14px;\n border-radius: 7px;\n}\n\n.y-btn--large {\n height: 52px;\n padding: 0 20px;\n font-size: 16px;\n border-radius: 8px;\n}\n\n/* 变体样式 */\n.y-btn--primary {\n background: linear-gradient(90deg, #111827, #1f2937);\n color: #fff;\n}\n\n.y-btn--primary:hover { \n background: linear-gradient(90deg, #1f2937, #374151);\n}\n\n.y-btn--secondary {\n background: #f7f7f7;\n color: #374151;\n border: 1px solid #E2E8F0;\n}\n\n.y-btn--secondary:hover {\n background: #ebecee;\n border-color: #9ca3af;\n}\n\n.y-btn--danger {\n background: #c41e3a;\n color: #fff;\n border: 1px solid #c41e3a;\n}\n\n.y-btn--danger:hover {\n background: #ad152e;\n border-color: #ad152e;\n}\n\n.y-btn--success {\n background: #008060;\n color: #fff;\n border: 1px solid #008060;\n}\n\n.y-btn--success:hover {\n background: #006b4f;\n border-color: #006b4f;\n}\n\n.y-btn--info {\n background: #34b4fa;\n color: #fff;\n border: 1px solid #34b4fa;\n}\n\n.y-btn--info:hover {\n background: #1e9bdc;\n border-color: #1e9bdc;\n}\n\n.y-btn:active { \n transform: translateY(1px); \n}\n\n.y-btn.is-block { \n width: 100%; \n}\n\n.y-btn.is-loading { \n cursor: wait; \n opacity: 0.92; \n}\n\n/* 禁用态样式(单按钮与组按钮通用) */\n.y-btn:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.y-btn.is-loading .content { \n opacity: 0; \n}\n\n.y-btn.is-loading::after {\n content: '';\n position: absolute;\n left: 50%;\n top: 50%;\n width: 16px;\n height: 16px;\n transform: translate(-50%, -50%);\n border-radius: 50%;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: rgba(255,255,255,1);\n animation: spin 0.8s linear infinite;\n}\n\n.y-btn--tiny.is-loading::after {\n width: 10px;\n height: 10px;\n border-width: 1.5px;\n}\n\n.y-btn--mini.is-loading::after {\n width: 12px;\n height: 12px;\n border-width: 1.5px;\n}\n\n.y-btn--small.is-loading::after {\n width: 14px;\n height: 14px;\n border-width: 1.8px;\n}\n\n.y-btn--secondary.is-loading::after {\n border: 2px solid rgba(55, 65, 81, 0.3);\n border-top-color: rgba(55, 65, 81, 1);\n}\n\n.y-btn--danger.is-loading::after {\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: rgba(255,255,255,1);\n}\n\n.y-btn--success.is-loading::after {\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: rgba(255,255,255,1);\n}\n\n.y-btn--info.is-loading::after {\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: rgba(255,255,255,1);\n}\n\n/* 组合按钮样式(连体) */\n.y-btn-group { display: inline-flex; }\n.y-btn.is-grouped {\n border-radius: 0;\n}\n\n.y-btn.group-pos-start {\n border-top-left-radius: 7px;\n border-bottom-left-radius: 7px;\n}\n\n.y-btn.group-pos-middle {\n margin-left: -1px; /* 抵消边框以无缝连接 */\n}\n\n.y-btn.group-pos-end {\n margin-left: -1px; /* 抵消边框以无缝连接 */\n border-top-right-radius: 7px;\n border-bottom-right-radius: 7px;\n}\n\n/* 针对不同尺寸的圆角适配 */\n.y-btn--tiny.group-pos-start { border-top-left-radius: 3px; border-bottom-left-radius: 3px; }\n.y-btn--tiny.group-pos-end { border-top-right-radius: 3px; border-bottom-right-radius: 3px; }\n\n.y-btn--mini.group-pos-start { border-top-left-radius: 4px; border-bottom-left-radius: 4px; }\n.y-btn--mini.group-pos-end { border-top-right-radius: 4px; border-bottom-right-radius: 4px; }\n\n.y-btn--small.group-pos-start { border-top-left-radius: 5px; border-bottom-left-radius: 5px; }\n.y-btn--small.group-pos-end { border-top-right-radius: 5px; border-bottom-right-radius: 5px; }\n\n.y-btn--large.group-pos-start { border-top-left-radius: 8px; border-bottom-left-radius: 8px; }\n.y-btn--large.group-pos-end { border-top-right-radius: 8px; border-bottom-right-radius: 8px; }\n\n/* 提升 hover 时的层级,避免边框覆盖问题 */\n.y-btn.is-grouped { position: relative; z-index: 1; }\n.y-btn.is-grouped:hover { z-index: 2; }\n\n@keyframes spin {\n to { transform: translate(-50%, -50%) rotate(360deg); }\n}\n\n/* 图标尺寸与对齐 */\n.y-btn .icon {\n width: 16px;\n height: 16px;\n}\n\n@media (prefers-color-scheme: dark) {\n .y-btn--primary { \n background: linear-gradient(90deg, #0b1220, #111827); \n }\n \n .y-btn--secondary {\n background: rgba(2, 6, 23, 0.4);\n border-color: rgba(148, 163, 184, 0.18);\n color: #e5eef7;\n }\n \n .y-btn--secondary:hover {\n background: rgba(2, 6, 23, 0.6);\n border-color: rgba(148, 163, 184, 0.3);\n }\n}\n</style>","<template>\n <div class=\"y-input-wrap\" :class=\"{ 'is-block': block, 'has-password-toggle': showPasswordToggle }\" :style=\"{ width: width }\">\n <input\n ref=\"inputRef\"\n class=\"y-input\"\n :class=\"`y-input--${size}`\"\n :id=\"id\"\n :name=\"name\"\n :type=\"actualInputType\"\n :placeholder=\"inputPlaceholder\"\n :autocomplete=\"autocomplete\"\n :inputmode=\"inputmode\"\n :min=\"min\"\n :max=\"max\"\n :disabled=\"disabled\"\n :required=\"required\"\n :value=\"modelValue\"\n @input=\"onInput\"\n @focus=\"onFocus\"\n @blur=\"onBlur\"\n @keyup.enter=\"onEnter\"\n @paste=\"onPaste\"\n />\n <button\n v-if=\"showPasswordToggle\"\n type=\"button\"\n class=\"y-input-password-toggle\"\n :class=\"`y-input-password-toggle--${size}`\"\n @click=\"togglePasswordVisibility\"\n tabindex=\"-1\"\n >\n <svg v-if=\"passwordVisible\" class=\"y-input-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\"></path>\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\n </svg>\n <svg v-else class=\"y-input-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"></path>\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\n </svg>\n </button>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, computed } from 'vue'\n\nconst props = withDefaults(defineProps<{\n modelValue?: string\n type?: 'text' | 'email' | 'password' | 'search' | 'tel' | 'url' | 'number'\n placeholder?: string\n autocomplete?: string\n inputmode?: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url'\n id?: string\n name?: string\n disabled?: boolean\n required?: boolean\n block?: boolean\n size?: 'tiny' | 'mini' | 'small' | 'medium' | 'large'\n width?: string\n min?: string | number\n max?: string | number\n clearOnFocus?: boolean\n}>(), {\n modelValue: '',\n type: 'text',\n placeholder: '',\n autocomplete: 'off',\n inputmode: undefined,\n id: undefined,\n name: undefined,\n disabled: false,\n required: false,\n block: false,\n size: 'medium',\n width: '200px',\n min: undefined,\n max: undefined,\n clearOnFocus: false,\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n (e: 'enter', value: string): void\n (e: 'paste', value: string): void\n}>()\n\nconst inputRef = ref<HTMLInputElement | null>(null)\nconst previousValue = ref<string>('')\nconst hasChanged = ref<boolean>(false) // 标记用户是否修改了输入值\nconst isFocused = ref<boolean>(false) // 标记是否正在聚焦\nconst inputPlaceholder = ref<string>(props.placeholder || '')\nconst passwordVisible = ref<boolean>(false) // 密码是否可见\n\n// 计算是否显示密码切换按钮\nconst showPasswordToggle = computed(() => props.type === 'password')\n\n// 计算实际的输入类型\nconst actualInputType = computed(() => {\n if (props.type === 'password' && passwordVisible.value) {\n return 'text'\n }\n return props.type\n})\n\n// 切换密码显示/隐藏\nfunction togglePasswordVisibility() {\n passwordVisible.value = !passwordVisible.value\n}\n\nwatch(() => props.placeholder, (val) => {\n if (!isFocused.value) {\n inputPlaceholder.value = val || ''\n }\n})\n\nfunction onInput(ev: Event) {\n const target = ev.target as HTMLInputElement\n hasChanged.value = true // 标记用户已修改值\n emit('update:modelValue', target.value)\n}\n\nfunction onFocus() {\n isFocused.value = true\n if (props.clearOnFocus) {\n // 保存聚焦前的值\n previousValue.value = props.modelValue || ''\n // 重置修改标志\n hasChanged.value = false\n // 使用原值展示提示\n inputPlaceholder.value = previousValue.value || props.placeholder || ''\n // 清空输入框\n emit('update:modelValue', '')\n }\n}\n\nfunction onBlur() {\n isFocused.value = false\n if (props.clearOnFocus) {\n // 只有当用户没有修改值且失去焦点时值为空,才恢复之前的值\n if (!hasChanged.value && (!props.modelValue || props.modelValue === '')) {\n emit('update:modelValue', previousValue.value)\n }\n }\n\n // 如果传入了 min,并且当前值小于 min,则自动校正为最小值\n if (props.min !== undefined && props.modelValue !== undefined && props.modelValue !== '') {\n const current = Number(props.modelValue)\n const minVal = Number(props.min)\n if (!Number.isNaN(current) && !Number.isNaN(minVal) && current < minVal) {\n emit('update:modelValue', String(minVal))\n }\n }\n\n inputPlaceholder.value = props.placeholder || ''\n}\n\nfunction onEnter(ev: KeyboardEvent) {\n const target = ev.target as HTMLInputElement\n emit('enter', target.value)\n}\n\nfunction onPaste(ev: ClipboardEvent) {\n const target = ev.target as HTMLInputElement\n requestAnimationFrame(() => {\n emit('paste', target.value)\n })\n}\n</script>\n\n<style scoped>\n.y-input-wrap { \n width: 100%; \n position: relative;\n}\n.y-input-wrap.is-block { display: block; width: 100%; }\n.y-input-wrap.has-password-toggle .y-input {\n padding-right: 40px;\n}\n\n/* 继承登录页 .input 的视觉规范 */\n.y-input {\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n border: 1px solid #e2e8f0;\n border-radius: 10px;\n padding: 0 12px;\n font-size: 14px;\n outline: none;\n transition: box-shadow 0.2s ease, border-color 0.2s ease;\n background: #ffffff;\n color: #0b1a29;\n}\n\n/* 尺寸变体 */\n.y-input--tiny {\n height: 19px;\n padding: 0 6px;\n font-size: 10px;\n border-radius: 4px;\n}\n\n.y-input--mini {\n height: 24px;\n padding: 0 8px;\n font-size: 11px;\n border-radius: 6px;\n}\n\n.y-input--small {\n height: 32px;\n padding: 0 10px;\n font-size: 12px;\n border-radius: 8px;\n}\n\n.y-input--medium {\n height: 44px;\n padding: 0 12px;\n font-size: 14px;\n border-radius: 10px;\n}\n\n.y-input--large {\n height: 52px;\n padding: 0 16px;\n font-size: 16px;\n border-radius: 12px;\n}\n\n.y-input:focus {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59,130,246,0.15);\n}\n\n/* 密码切换按钮 */\n.y-input-password-toggle {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #64748b;\n transition: color 0.2s ease;\n outline: none;\n z-index: 1;\n}\n\n.y-input-password-toggle:hover {\n color: #475569;\n}\n\n.y-input-password-toggle:active {\n color: #334155;\n}\n\n.y-input-password-toggle--tiny {\n right: 4px;\n padding: 2px;\n}\n\n.y-input-password-toggle--mini {\n right: 6px;\n padding: 3px;\n}\n\n.y-input-password-toggle--small {\n right: 8px;\n padding: 4px;\n}\n\n.y-input-password-toggle--medium {\n right: 10px;\n padding: 5px;\n}\n\n.y-input-password-toggle--large {\n right: 12px;\n padding: 6px;\n}\n\n.y-input-icon {\n width: 18px;\n height: 18px;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.y-input-password-toggle--tiny .y-input-icon {\n width: 12px;\n height: 12px;\n}\n\n.y-input-password-toggle--mini .y-input-icon {\n width: 14px;\n height: 14px;\n}\n\n.y-input-password-toggle--small .y-input-icon {\n width: 16px;\n height: 16px;\n}\n\n.y-input-password-toggle--large .y-input-icon {\n width: 20px;\n height: 20px;\n}\n\n@media (prefers-color-scheme: dark) {\n .y-input {\n background: rgba(2,6,23,0.4);\n border-color: rgba(148,163,184,0.18);\n color: #e5eef7;\n }\n .y-input-password-toggle {\n color: rgba(148,163,184,0.7);\n }\n .y-input-password-toggle:hover {\n color: rgba(148,163,184,0.9);\n }\n .y-input-password-toggle:active {\n color: #e5eef7;\n }\n}\n</style>","<template>\n <div class=\"ytable-container\" ref=\"tableContainer\">\n <!-- 批量操作栏 -->\n <transition name=\"bulk-slide\">\n <div class=\"bulk-bar\" v-if=\"selectedItems.length && showBulkActions\">\n <div class=\"bulk-left\">已选择 {{ selectedItems.length }} 项</div>\n <div class=\"bulk-actions\">\n <slot name=\"bulk-actions\" :selectedItems=\"selectedItems\" :clearSelection=\"clearSelection\">\n <YButton size=\"small\" class=\"btn\" @click=\"clearSelection\">清除选择</YButton>\n </slot>\n </div>\n </div>\n </transition>\n\n <!-- 表格容器 -->\n <div class=\"card\">\n <!-- 表头右上角收起/展开所有提示标签按钮 -->\n <div class=\"table-header-actions\" v-if=\"hasHintTags\">\n <button \n class=\"toggle-all-hints-btn\" \n :class=\"{ 'is-expanded': allHintsExpanded }\"\n @click=\"toggleAllHints\"\n :title=\"allHintsExpanded ? '收起所有提示标签' : '展开所有提示标签'\"\n >\n <svg \n v-if=\"allHintsExpanded\"\n viewBox=\"0 0 24 24\" \n fill=\"none\" \n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"toggle-icon\"\n >\n <path \n d=\"M15 18L9 12L15 6\" \n stroke=\"currentColor\" \n stroke-width=\"2\" \n stroke-linecap=\"round\" \n stroke-linejoin=\"round\"\n />\n </svg>\n <svg \n v-else\n viewBox=\"0 0 24 24\" \n fill=\"none\" \n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"toggle-icon\"\n >\n <path \n d=\"M9 18L15 12L9 6\" \n stroke=\"currentColor\" \n stroke-width=\"2\" \n stroke-linecap=\"round\" \n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n <!-- 表头固定区域 -->\n <div class=\"table-header\" ref=\"headerRef\">\n <table class=\"table\">\n <colgroup>\n <col v-if=\"props.expandable\" style=\"width: 34px; min-width: 34px;\" />\n <col v-if=\"selectable\" style=\"width: 60px; min-width: 60px;\" />\n <col v-for=\"(col, i) in columns\" :key=\"col.key\"\n :style=\"{ width: headerColWidths[i] || undefined, minWidth: headerColWidths[i] || '80px' }\" />\n </colgroup>\n <thead>\n <tr>\n <th v-if=\"props.expandable\" class=\"col-expand\"></th>\n <!-- 选择列 -->\n <th v-if=\"selectable\" class=\"col-select\">\n <div class=\"select-header\">\n <input \n type=\"checkbox\" \n :checked=\"isAllVisibleSelected\" \n :indeterminate=\"isPartiallySelected\"\n :disabled=\"isAllVisibleDisabled\"\n @change=\"toggleSelectAllVisible\" \n />\n <span v-if=\"selectedItems.length > 0\" class=\"select-count\">{{ selectedItems.length }}</span>\n </div>\n </th>\n <!-- 动态列头:如果有选中项且提供了自定义表头插槽,则显示自定义内容 -->\n <th \n v-if=\"selectedItems.length > 0 && $slots['selected-header']\"\n :colspan=\"columns.length\"\n class=\"col-selected-header\"\n >\n <div class=\"selected-header-wrapper\">\n <slot name=\"selected-header\" :selectedItems=\"selectedItems\" :clearSelection=\"clearSelection\"></slot>\n </div>\n </th>\n <template v-else>\n <th \n v-for=\"(column, colIndex) in columns\" \n :key=\"column.key\" \n :class=\"getColumnClass(column, true)\"\n :style=\"getColumnStyle(column, colIndex, true)\"\n >\n {{ column.title }}\n </th>\n </template>\n </tr>\n </thead>\n </table>\n </div>\n \n <!-- 表格内容滚动区域 -->\n <div class=\"table-body-wrap\" ref=\"bodyWrapRef\" :class=\"{ 'is-loading': loading, 'is-empty': !pagedData.length && !loading }\" :style=\"{ maxHeight: tableMaxHeight }\">\n <!-- Loading 状态 -->\n <div v-if=\"loading\" class=\"loading-overlay\">\n <div class=\"loading-spinner\"></div>\n <div class=\"loading-text\">加载中...</div>\n </div>\n\n <!-- 空数据覆盖层 -->\n <div v-if=\"!pagedData.length && !loading\" class=\"empty-overlay\">\n <slot name=\"empty\">\n {{ emptyText }}\n </slot>\n </div>\n \n <table class=\"table\" :class=\"{ 'loading-table': loading }\" ref=\"bodyTableRef\">\n <colgroup>\n <col v-if=\"props.expandable\" style=\"width: 34px; min-width: 34px;\" />\n <col v-if=\"selectable\" style=\"width: 60px; min-width: 60px;\" />\n <col v-for=\"(col, i) in columns\" :key=\"col.key\"\n :style=\"{ width: headerColWidths[i] || undefined, minWidth: headerColWidths[i] || '80px' }\" />\n </colgroup>\n <tbody>\n <template v-for=\"(item, index) in pagedData\" :key=\"getRowKey(item, index)\">\n <tr\n :class=\"{ 'row-selected': isRowSelected(item, index) }\"\n @click=\"handleRowClick(item, index)\"\n >\n <td v-if=\"props.expandable\" class=\"col-expand\">\n <button class=\"expand-btn\" type=\"button\" @click.stop=\"toggleRowExpand(getRowKey(item, index))\">\n <span :class=\"['expand-icon', { 'is-open': isRowExpanded(getRowKey(item, index)) }]\"></span>\n </button>\n </td>\n <!-- 选择列 -->\n <td v-if=\"selectable\" class=\"col-select\" @click.stop>\n <input \n type=\"checkbox\" \n :value=\"getRowKey(item, index)\"\n :checked=\"selectedItems.includes(getRowKey(item, index))\" \n :disabled=\"isRowDisabled(item, index)\"\n @change.stop=\"toggleSelect(getRowKey(item, index))\" \n />\n </td>\n <!-- 动态数据列 -->\n <td \n v-for=\"(column, colIndex) in columns\" \n :key=\"column.key\"\n :class=\"getColumnClass(column)\"\n :style=\"getColumnStyle(column, colIndex, false)\"\n >\n <slot \n :name=\"`cell-${column.key}`\" \n :item=\"item\" \n :value=\"getNestedValue(item, column.key)\"\n :index=\"index\"\n >\n {{ formatCellValue(item, column) }}\n </slot>\n </td>\n </tr>\n <tr\n v-if=\"props.expandable && isRowExpanded(getRowKey(item, index))\"\n :key=\"`${getRowKey(item, index)}-expand`\"\n class=\"expand-row\"\n >\n <td :colspan=\"totalTableColumns\" class=\"expand-cell\">\n <slot name=\"expand\" :item=\"item\" :index=\"index\" />\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n </div>\n\n <!-- 分页 -->\n <YPagination\n class=\"align-right\"\n v-if=\"pagination\"\n v-model:current-page=\"currentPage\"\n v-model:page-size=\"pageSize\"\n :loading=\"props.loading\"\n :disable-next=\"shouldDisableNext\"\n :page-size-options=\"pageSizeOptions\"\n @page-change=\"handlePageChange\"\n @page-size-change=\"handlePageSizeChange\"\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch, onMounted, onUnmounted, nextTick, provide } from 'vue'\n\nexport interface TableColumn {\n key: string\n title: string\n width?: string | number\n align?: 'left' | 'center' | 'right'\n formatter?: (value: any, item: any) => string\n sortable?: boolean\n fixed?: 'left' | 'right'\n}\n\nexport interface TableProps {\n data: any[]\n columns: TableColumn[]\n selectable?: boolean\n showBulkActions?: boolean\n pagination?: boolean\n pageSize?: number\n currentPage?: number\n total?: number\n loading?: boolean\n pageSizeOptions?: Array<{ label: string; value: number }>\n rowKey?: string | ((item: any) => string | number)\n emptyText?: string\n searchKeyword?: string\n searchFields?: string[]\n stickyHeader?: boolean\n expandable?: boolean\n rowDisabled?: (item: any, index: number) => boolean\n selectedItems?: (string | number)[]\n rowSelectable?: boolean\n requireDeselectBeforeSelect?: boolean\n}\n\nconst props = withDefaults(defineProps<TableProps & {\n expandable?: boolean\n rowDisabled?: (item: any, index: number) => boolean\n selectedItems?: (string | number)[]\n rowSelectable?: boolean\n requireDeselectBeforeSelect?: boolean\n}>(), {\n selectable: false,\n showBulkActions: false,\n pagination: true,\n pageSize: 10,\n loading: false,\n pageSizeOptions: () => [\n { label: '1/页', value: 1 },\n { label: '20/页', value: 20 },\n { label: '50/页', value: 50 },\n { label: '100/页', value: 100 }\n ],\n rowKey: 'id',\n emptyText: '无数据',\n searchKeyword: '',\n searchFields: () => [],\n stickyHeader: false,\n rowDisabled: undefined,\n selectedItems: undefined,\n rowSelectable: false,\n requireDeselectBeforeSelect: true\n})\n\nconst emit = defineEmits<{\n edit: [item: any]\n select: [selectedItems: (string | number)[]]\n 'update:selectedItems': [selectedItems: (string | number)[]]\n 'page-change': [page: number]\n 'page-size-change': [size: number]\n 'row-click': [item: any, key: string | number | null]\n}>()\n\n// 响应式数据\nconst currentPage = ref(props.currentPage || 1)\nconst pageSize = ref(props.pageSize)\nconst selectedItems = ref<(string | number)[]>(props.selectedItems || [])\nconst selectedRowKey = ref<(string | number)[]>([])\nconst expandedKeys = ref<Set<string | number>>(new Set())\nconst tableMaxHeight = ref('none')\nconst tableContainer = ref<HTMLElement>()\nconst headerRef = ref<HTMLElement>()\nconst bodyWrapRef = ref<HTMLElement>()\nconst bodyTableRef = ref<HTMLTableElement>()\n// 头部列宽数组:优先使用外部列宽;未传则根据首行内容测量\nconst headerColWidths = ref<string[]>([])\nconst headerWidthMap = ref<Record<string, string>>({})\n// 存储默认表头的标准高度\nconst defaultHeaderHeight = ref<number>(35)\n\n// 管理所有 hintTag 实例\nconst hintTagInstances = ref<Set<any>>(new Set())\n\n// 计算是否有 hintTag 实例(用于控制按钮显示)\nconst hasHintTags = computed(() => hintTagInstances.value.size > 0)\n\n// 计算当前所有 hintTag 的展开状态\n// 使用 hintTagStateUpdateTrigger 确保响应式更新\nconst allHintsExpanded = computed(() => {\n // 引用 hintTagStateUpdateTrigger 以建立响应式依赖\n void hintTagStateUpdateTrigger.value\n \n if (hintTagInstances.value.size === 0) return false\n let expandedCount = 0\n hintTagInstances.value.forEach((instance) => {\n if (instance && instance.isExpanded) {\n expandedCount++\n }\n })\n return expandedCount === hintTagInstances.value.size\n})\n\n// 计算是否所有 hintTag 都已收起\nconst allHintsCollapsed = computed(() => {\n // 引用 hintTagStateUpdateTrigger 以建立响应式依赖\n void hintTagStateUpdateTrigger.value\n \n if (hintTagInstances.value.size === 0) return true\n let collapsedCount = 0\n hintTagInstances.value.forEach((instance) => {\n if (instance && !instance.isExpanded) {\n collapsedCount++\n }\n })\n return collapsedCount === hintTagInstances.value.size\n})\n\n// 注册 hintTag 实例\nfunction registerHintTag(instance: any) {\n hintTagInstances.value.add(instance)\n}\n\n// 注销 hintTag 实例\nfunction unregisterHintTag(instance: any) {\n hintTagInstances.value.delete(instance)\n}\n\n// 收起所有 hintTag\nfunction collapseAllHints() {\n hintTagInstances.value.forEach((instance) => {\n if (instance && typeof instance.collapse === 'function') {\n instance.collapse()\n }\n })\n}\n\n// 展开所有 hintTag\nfunction expandAllHints() {\n hintTagInstances.value.forEach((instance) => {\n if (instance && typeof instance.expand === 'function') {\n instance.expand()\n }\n })\n}\n\n// 切换所有 hintTag 的展开/收起状态\nfunction toggleAllHints() {\n if (allHintsExpanded.value) {\n // 如果全部展开,则全部收起\n collapseAllHints()\n } else {\n // 否则全部展开\n expandAllHints()\n }\n}\n\n// 用于触发计算属性重新计算的响应式变量\nconst hintTagStateUpdateTrigger = ref(0)\n\n// 通知 hintTag 状态变化的函数\nfunction notifyHintTagStateChange() {\n hintTagStateUpdateTrigger.value++\n}\n\n// 通过 provide 向子组件提供注册方法\nprovide('registerHintTag', registerHintTag)\nprovide('unregisterHintTag', unregisterHintTag)\nprovide('notifyHintTagStateChange', notifyHintTagStateChange)\n\nconst autoColumnKeys = computed(() =>\n props.columns\n .filter((col) => !normalizeWidth(col.width))\n .map((col) => col.key)\n)\n\nfunction getAutoColumnWidth(): string {\n const count = autoColumnKeys.value.length || 1\n const per = 100 / count\n return `${per.toFixed(6)}%`\n}\n\n// 自定义竖向滚动条状态\nconst vTrackRef = ref<HTMLElement>()\nconst vScroll = ref({\n show: false,\n thumbHeight: 40,\n thumbTop: 0\n})\nlet isDragging = false\nlet dragStartY = 0\nlet dragStartScrollTop = 0\n\n// 滚动条宽度(用于表头右侧固定列对齐)\nconst scrollbarWidth = ref(0)\n\nfunction normalizeWidth(width?: string | number): string | undefined {\n if (width === undefined || width === null) return undefined\n if (typeof width === 'number') {\n if (Number.isFinite(width)) {\n return `${width}px`\n }\n return undefined\n }\n const trimmed = String(width).trim()\n if (!trimmed) return undefined\n if (/^\\d+(\\.\\d+)?$/.test(trimmed)) {\n return `${trimmed}px`\n }\n return trimmed\n}\n\nfunction parseWidthNumber(width?: string | number): number | null {\n const normalized = normalizeWidth(width)\n if (!normalized) return null\n const parsed = parseFloat(normalized)\n return Number.isFinite(parsed) ? parsed : null\n}\n\n// 计算属性\n// const totalColumns = computed(() => {\n// let count = props.columns.length\n// if (props.selectable) count++\n// return count\n// })\n\nconst totalTableColumns = computed(() => {\n let count = props.columns.length\n if (props.selectable) count += 1\n if (props.expandable) count += 1\n return count\n})\n\nconst filteredData = computed(() => {\n if (!props.searchKeyword || !props.searchFields.length) {\n return props.data\n }\n \n const keyword = props.searchKeyword.toLowerCase()\n return props.data.filter((item) => {\n return props.searchFields!.some(field => {\n const value = getNestedValue(item, field)\n return String(value).toLowerCase().includes(keyword)\n })\n })\n})\n\n// 移除对 total 的依赖,不再计算总页数\n\nconst pagedData = computed(() => {\n if (!props.pagination) return filteredData.value\n // 服务端分页:不再依赖 total 和 totalPages,直接渲染传入数据\n return filteredData.value\n})\n\nconst isAllVisibleSelected = computed(() => {\n if (!props.selectable) return false\n const visibleKeys = pagedData.value\n .map((item, index) => ({ key: getRowKey(item, index), item, index }))\n .filter(({ item, index }) => !isRowDisabled(item, index))\n .map(({ key }) => key)\n return visibleKeys.length > 0 && visibleKeys.every(key => selectedItems.value.includes(key))\n})\n\n// 判断是否为部分选中状态(中间状态)\nconst isPartiallySelected = computed(() => {\n if (!props.selectable) return false\n if (isAllVisibleSelected.value) return false // 如果全选,则不是中间状态\n const visibleKeys = pagedData.value\n .map((item, index) => ({ key: getRowKey(item, index), item, index }))\n .filter(({ item, index }) => !isRowDisabled(item, index))\n .map(({ key }) => key)\n // 如果有可见的未禁用行,且部分被选中,则显示中间状态\n if (visibleKeys.length === 0) return false\n const selectedCount = visibleKeys.filter(key => selectedItems.value.includes(key)).length\n return selectedCount > 0 && selectedCount < visibleKeys.length\n})\n\nconst isAllVisibleDisabled = computed(() => {\n if (!props.selectable) return false\n // 如果所有可见行都被禁用,则全选按钮也禁用\n const visibleKeys = pagedData.value.map((item, index) => ({ item, index }))\n return visibleKeys.length > 0 && visibleKeys.every(({ item, index }) => isRowDisabled(item, index))\n})\n\n// 判断是否应该禁用下一页按钮\n// 当返回的数据量小于 pageSize 时,说明已经到最后一页了\nconst shouldDisableNext = computed(() => {\n if (!props.pagination) return false\n // 如果当前页数据量小于每页显示条数,说明已经是最后一页\n return pagedData.value.length < pageSize.value\n})\n\n// 计算固定列的累计宽度\nconst fixedLeftWidths = computed(() => {\n const widths: number[] = []\n let cumulativeWidth = props.selectable ? 60 : 0 // 选择列宽度\n \n for (let i = 0; i < props.columns.length; i++) {\n const col = props.columns[i]\n if (col.fixed === 'left') {\n let width = 80 // 默认宽度\n const parsedWidth = parseWidthNumber(col.width)\n if (parsedWidth !== null) {\n width = parsedWidth\n } else if (headerColWidths.value[i]) {\n const parsedHeaderWidth = parseWidthNumber(headerColWidths.value[i])\n width = parsedHeaderWidth ?? width\n }\n widths.push(cumulativeWidth)\n cumulativeWidth += width\n }\n }\n return widths\n})\n\nconst fixedRightWidths = computed(() => {\n const widths: number[] = []\n let cumulativeWidth = 0\n \n // 从右往左计算,但需要保证索引顺序正确\n // 先收集所有右侧固定列的宽度和索引\n const rightFixedColumns: Array<{ index: number; width: number }> = []\n for (let i = props.columns.length - 1; i >= 0; i--) {\n const col = props.columns[i]\n if (col.fixed === 'right') {\n let width = 80 // 默认宽度\n const parsedWidth = parseWidthNumber(col.width)\n if (parsedWidth !== null) {\n width = parsedWidth\n } else if (headerColWidths.value[i]) {\n const parsedHeaderWidth = parseWidthNumber(headerColWidths.value[i])\n width = parsedHeaderWidth ?? width\n }\n rightFixedColumns.push({ index: i, width })\n }\n }\n \n // 从右到左计算累计宽度(数组顺序:最右边的列索引最小)\n // widths[i] 对应第 i 个右侧固定列(从右往左数)的 right 偏移量\n for (let i = 0; i < rightFixedColumns.length; i++) {\n widths.push(cumulativeWidth)\n cumulativeWidth += rightFixedColumns[i].width\n }\n \n return widths\n})\n\n// 获取固定列的索引位置(用于查找对应的累计宽度)\nfunction getFixedColumnIndex(columnIndex: number, fixed: 'left' | 'right'): number {\n if (fixed === 'left') {\n let count = 0\n for (let i = 0; i < columnIndex; i++) {\n if (props.columns[i].fixed === 'left') {\n count++\n }\n }\n return count\n } else {\n // 对于右侧固定列,计算从右往左是第几个(索引0是最右边的)\n let count = 0\n for (let i = props.columns.length - 1; i > columnIndex; i--) {\n if (props.columns[i].fixed === 'right') {\n count++\n }\n }\n return count\n }\n}\n\n// 方法\nfunction getRowKey(item: any, index: number): string | number {\n if (typeof props.rowKey === 'function') {\n return props.rowKey(item)\n }\n return item[props.rowKey] || index\n}\n\n// 检查行是否被禁用\nfunction isRowDisabled(item: any, index: number): boolean {\n if (props.rowDisabled && typeof props.rowDisabled === 'function') {\n return props.rowDisabled(item, index)\n }\n return false\n}\n\nfunction isRowExpanded(key: string | number) {\n return expandedKeys.value.has(key)\n}\n\nfunction toggleRowExpand(key: string | number) {\n if (expandedKeys.value.has(key)) {\n expandedKeys.value.delete(key)\n } else {\n expandedKeys.value.add(key)\n }\n}\n\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj)\n}\n\nfunction getColumnClass(column: TableColumn, isHeader = false): string {\n const classes = [] as string[]\n if (column.align) {\n classes.push(`text-${column.align}`)\n }\n if (column.fixed === 'right') {\n classes.push('col-fixed-right')\n if (isHeader) classes.push('col-fixed-right-header')\n }\n if (column.fixed === 'left') {\n classes.push('col-fixed-left')\n if (isHeader) classes.push('col-fixed-left-header')\n }\n return classes.join(' ')\n}\n\nfunction getColumnStyle(column: TableColumn, columnIndex: number, isHeader: boolean): Record<string, string> {\n const style: Record<string, string> = {}\n \n const normalizedWidth = normalizeWidth(column.width)\n if (normalizedWidth) {\n // 如果设置了固定宽度,使用固定宽度\n style.width = normalizedWidth\n style.minWidth = normalizedWidth\n style.maxWidth = normalizedWidth\n } else {\n // 如果没有设置宽度,使用均等分配的宽度,确保列宽稳定\n const autoWidth = getAutoColumnWidth()\n style.width = autoWidth\n style.minWidth = autoWidth\n style.maxWidth = autoWidth\n }\n \n // 处理固定列的位置\n if (column.fixed === 'left') {\n const fixedIndex = getFixedColumnIndex(columnIndex, 'left')\n const leftOffset = fixedLeftWidths.value[fixedIndex] || 0\n style.left = `${leftOffset}px`\n style.zIndex = isHeader ? `${10 + fixedIndex}` : `${5 + fixedIndex}`\n } else if (column.fixed === 'right') {\n const fixedIndex = getFixedColumnIndex(columnIndex, 'right')\n const rightOffset = fixedRightWidths.value[fixedIndex] || 0\n \n // 对于表头的右侧固定列,减去2px以精确对齐\n // 这可能是因为边框或间距导致的细微差异\n if (isHeader) {\n style.right = `${rightOffset - 3}px`\n } else {\n style.right = `${rightOffset}px`\n }\n \n style.zIndex = isHeader ? `${10 + fixedIndex}` : `${5 + fixedIndex}`\n }\n \n return style\n}\n\nfunction formatCellValue(item: any, column: TableColumn): string {\n const value = getNestedValue(item, column.key)\n if (column.formatter) {\n return column.formatter(value, item)\n }\n return value || ''\n}\n\nfunction toggleSelect(key: string | number) {\n // 找到对应的行数据\n const rowData = pagedData.value.find((item, index) => getRowKey(item, index) === key)\n const rowIndex = pagedData.value.findIndex((item, index) => getRowKey(item, index) === key)\n \n // 如果行被禁用,不允许选择\n if (rowData && rowIndex >= 0 && isRowDisabled(rowData, rowIndex)) {\n return\n }\n \n if (selectedItems.value.includes(key)) {\n selectedItems.value = selectedItems.value.filter(x => x !== key)\n } else {\n selectedItems.value = [...selectedItems.value, key]\n }\n emit('select', selectedItems.value)\n emit('update:selectedItems', selectedItems.value)\n}\n\nfunction toggleSelectAllVisible() {\n // 只处理未禁用的行\n const visibleKeys = pagedData.value\n .map((item, index) => ({ key: getRowKey(item, index), item, index }))\n .filter(({ item, index }) => !isRowDisabled(item, index))\n .map(({ key }) => key)\n \n if (visibleKeys.length === 0) return\n \n if (visibleKeys.every(key => selectedItems.value.includes(key))) {\n selectedItems.value = selectedItems.value.filter(key => !visibleKeys.includes(key))\n } else {\n const union = new Set([...selectedItems.value, ...visibleKeys])\n selectedItems.value = Array.from(union)\n }\n emit('select', selectedItems.value)\n emit('update:selectedItems', selectedItems.value)\n}\n\nfunction clearSelection() {\n selectedItems.value = []\n emit('select', selectedItems.value)\n emit('update:selectedItems', selectedItems.value)\n}\n\n// 行点击选中处理\nfunction handleRowClick(item: any, index: number) {\n if (!props.rowSelectable) return\n \n const key = getRowKey(item, index)\n \n // 如果行被禁用,不允许选择\n if (isRowDisabled(item, index)) {\n return\n }\n \n // 根据 requireDeselectBeforeSelect 决定行为\n if (props.requireDeselectBeforeSelect) {\n // 模式1:可以多选,再次点击为取消\n if (selectedRowKey.value.includes(key)) {\n // 如果已选中,则取消选中\n selectedRowKey.value = selectedRowKey.value.filter(k => k !== key)\n emit('row-click', item, null)\n } else {\n // 如果未选中,则添加到选中列表\n selectedRowKey.value = [...selectedRowKey.value, key]\n emit('row-click', item, key)\n }\n } else {\n // 模式2:点击其他行时,自动切换选中状态(单选模式)\n if (selectedRowKey.value.includes(key)) {\n selectedRowKey.value = []\n emit('row-click', item, null)\n } else {\n selectedRowKey.value = [key]\n emit('row-click', item, key)\n }\n }\n}\n\n// 判断行是否被选中\nfunction isRowSelected(item: any, index: number): boolean {\n if (!props.rowSelectable) return false\n const key = getRowKey(item, index)\n return selectedRowKey.value.includes(key)\n}\n\n// 监听外部传入的 selectedItems prop,同步到内部状态\nwatch(() => props.selectedItems, (newVal) => {\n if (newVal !== undefined && Array.isArray(newVal)) {\n // 只有当外部传入的值与内部值不同时才更新,避免循环更新\n const currentSet = new Set(selectedItems.value)\n const newSet = new Set(newVal)\n if (currentSet.size !== newSet.size || \n ![...currentSet].every(key => newSet.has(key))) {\n selectedItems.value = [...newVal]\n }\n } else if (newVal === undefined && selectedItems.value.length > 0) {\n // 如果外部传入 undefined 且内部有选中项,清空内部选中状态\n selectedItems.value = []\n }\n}, { deep: true, immediate: true })\n\n// 监听搜索关键词变化,重置页码\nwatch(() => props.searchKeyword, () => {\n currentPage.value = 1\n})\n\n// 监听数据变化,重置页码(仅在客户端分页时)并清空选中行\nwatch(() => props.data, () => {\n // 只有在没有外部 total 的情况下(客户端分页)才重置页码\n if (!props.total) {\n currentPage.value = 1\n }\n // 数据变化时清空选中行状态\n if (props.rowSelectable) {\n selectedRowKey.value = []\n }\n}, { deep: true })\n\n// 分页事件处理\nfunction handlePageChange(page: number) {\n currentPage.value = page\n // 分页变化时清空选中行状态\n if (props.rowSelectable) {\n selectedRowKey.value = []\n }\n emit('page-change', page)\n}\n\nfunction handlePageSizeChange(size: number) {\n pageSize.value = size\n currentPage.value = 1 // 切换每页条数后重置到第一页\n // 分页大小变化时清空选中行状态\n if (props.rowSelectable) {\n selectedRowKey.value = []\n }\n emit('page-size-change', size)\n}\n\n// 父组件重置分页时,同步内部选中状态\nwatch(() => props.currentPage, (val) => {\n const next = typeof val === 'number' && val > 0 ? val : 1\n if (currentPage.value !== next) currentPage.value = next\n})\n\nwatch(() => props.pageSize, (val) => {\n const next = typeof val === 'number' && val > 0 ? val : 10\n if (pageSize.value !== next) pageSize.value = next\n})\n\n// 计算表格最大高度\nfunction calculateTableMaxHeight() {\n if (!tableContainer.value) return\n \n nextTick(() => {\n const containerRect = tableContainer.value!.getBoundingClientRect()\n const viewportHeight = window.innerHeight\n const containerTop = containerRect.top\n \n // 获取表头高度\n const headerElement = tableContainer.value!.querySelector('.table-header') as HTMLElement\n const headerHeight = headerElement ? headerElement.offsetHeight : 40\n \n // 获取分页组件高度\n let paginationHeight = 0\n if (props.pagination) {\n const paginationElement = tableContainer.value!.querySelector('.ypagination') as HTMLElement\n paginationHeight = paginationElement ? paginationElement.offsetHeight : 60\n }\n \n // 获取批量操作栏高度\n const bulkBarElement = tableContainer.value!.querySelector('.bulk-bar') as HTMLElement\n const bulkBarHeight = bulkBarElement ? bulkBarElement.offsetHeight : 0\n \n // 计算可用空间\n // 有分页时:减去表头高度、分页组件高度、批量操作栏高度、安全边距(20px)\n // 无分页时:减去表头高度、批量操作栏高度、安全边距(40px,离底部更远)\n const safeMargin = 20\n const reservedHeight = headerHeight + paginationHeight + bulkBarHeight + safeMargin\n const availableHeight = viewportHeight - containerTop - reservedHeight\n \n // 设置最小高度为200px,最大高度为可用空间\n const minHeight = 200\n const maxHeight = Math.max(minHeight, availableHeight)\n \n // 获取表格内容高度\n const tableContent = tableContainer.value!.querySelector('.table-body-wrap .table') as HTMLElement\n if (tableContent) {\n const contentHeight = tableContent.offsetHeight\n \n // 如果内容高度超过可用空间,则限制高度并显示滚动条\n if (contentHeight > availableHeight) {\n tableMaxHeight.value = `${maxHeight}px`\n } else {\n // 如果内容高度小于可用空间,则不限制高度\n tableMaxHeight.value = 'none'\n }\n }\n })\n}\n\n// 同步表头与内容的横向滚动\nlet isSyncingScroll = false // 防止循环同步\nfunction syncHeaderScroll() {\n if (!headerRef.value || !bodyWrapRef.value || isSyncingScroll) return\n if (headerRef.value.scrollLeft !== bodyWrapRef.value.scrollLeft) {\n isSyncingScroll = true\n headerRef.value.scrollLeft = bodyWrapRef.value.scrollLeft\n requestAnimationFrame(() => {\n isSyncingScroll = false\n })\n }\n}\n\n// 同步表头滚动到内容区域\nfunction syncBodyScroll() {\n if (!headerRef.value || !bodyWrapRef.value || isSyncingScroll) return\n if (bodyWrapRef.value.scrollLeft !== headerRef.value.scrollLeft) {\n isSyncingScroll = true\n bodyWrapRef.value.scrollLeft = headerRef.value.scrollLeft\n requestAnimationFrame(() => {\n isSyncingScroll = false\n })\n }\n}\n\n// 计算虚拟竖向滚动条尺寸与位置\nfunction updateVirtualScrollbar() {\n nextTick(() => {\n if (!bodyWrapRef.value) return\n const wrap = bodyWrapRef.value\n const contentHeight = wrap.scrollHeight\n const viewport = wrap.clientHeight\n const scrollTop = wrap.scrollTop\n const needVBar = contentHeight > viewport + 1\n vScroll.value.show = needVBar\n if (!needVBar) return\n\n const minThumb = 24\n const ratio = viewport / contentHeight\n const trackHeight = vTrackRef.value ? vTrackRef.value.clientHeight : viewport\n const thumbHeight = Math.max(minThumb, Math.floor(trackHeight * ratio))\n vScroll.value.thumbHeight = thumbHeight\n\n const maxThumbTop = Math.max(0, trackHeight - thumbHeight)\n const maxScrollTop = Math.max(1, contentHeight - viewport)\n vScroll.value.thumbTop = Math.min(maxThumbTop, Math.floor((scrollTop / maxScrollTop) * maxThumbTop))\n })\n}\n\nfunction onThumbMousemove(e: MouseEvent) {\n if (!isDragging || !bodyWrapRef.value || !vTrackRef.value) return\n e.preventDefault()\n const trackHeight = vTrackRef.value.clientHeight\n const maxThumbTop = Math.max(0, trackHeight - vScroll.value.thumbHeight)\n const wrap = bodyWrapRef.value\n const contentHeight = wrap.scrollHeight\n const viewport = wrap.clientHeight\n const maxScrollTop = Math.max(1, contentHeight - viewport)\n const deltaY = e.clientY - dragStartY\n const scrollDelta = (deltaY / Math.max(1, maxThumbTop)) * maxScrollTop\n wrap.scrollTop = Math.min(maxScrollTop, Math.max(0, dragStartScrollTop + scrollDelta))\n updateVirtualScrollbar()\n}\n\nfunction onThumbMouseup() {\n isDragging = false\n window.removeEventListener('mousemove', onThumbMousemove)\n window.removeEventListener('mouseup', onThumbMouseup)\n}\n\n// function onTrackMousedown(e: MouseEvent) {\n// if (!bodyWrapRef.value || !vTrackRef.value) return\n// // 点击轨道跳转:将滑块中心移动到点击处\n// const rect = vTrackRef.value.getBoundingClientRect()\n// const y = e.clientY - rect.top\n// const trackHeight = vTrackRef.value.clientHeight\n// const thumbHeight = vScroll.value.thumbHeight\n// const targetTop = Math.min(Math.max(0, y - thumbHeight / 2), Math.max(0, trackHeight - thumbHeight))\n//\n// const wrap = bodyWrapRef.value\n// const contentHeight = wrap.scrollHeight\n// const viewport = wrap.clientHeight\n// const maxScrollTop = Math.max(1, contentHeight - viewport)\n// const maxThumbTop = Math.max(1, trackHeight - thumbHeight)\n// const targetScrollTop = (targetTop / maxThumbTop) * maxScrollTop\n// wrap.scrollTop = targetScrollTop\n// updateVirtualScrollbar()\n// }\n\n// 计算/测量列宽:对未设置 width 的列,使用首行单元格的内容宽度\nfunction measureAutoColumnWidths() {\n nextTick(() => {\n // 如果已完整测量过列宽,则不再重复测量,避免分页切换时轻微跳动\n if (headerColWidths.value.length === props.columns.length && headerColWidths.value.every(w => !!w)) {\n return\n }\n const widths: string[] = []\n // 先用 props.columns 中显式宽度填充\n props.columns.forEach((col, index) => {\n const normalizedWidth = normalizeWidth(col.width)\n if (normalizedWidth) {\n widths.push(normalizedWidth)\n headerWidthMap.value[col.key] = normalizedWidth\n } else if (headerWidthMap.value[col.key]) {\n widths.push(headerWidthMap.value[col.key])\n } else {\n const fallback = headerColWidths.value[index]\n if (fallback) {\n widths.push(fallback)\n headerWidthMap.value[col.key] = fallback\n } else {\n const autoWidth = getAutoColumnWidth()\n widths.push(autoWidth)\n headerWidthMap.value[col.key] = autoWidth\n }\n }\n })\n\n const firstRow = bodyTableRef.value?.querySelector('tbody tr') as HTMLTableRowElement | null\n if (firstRow) {\n // 计算 data 列在 tbody 中的起始索引\n const startIndex = props.selectable ? 1 : 0\n const tds = Array.from(firstRow.children) as HTMLElement[]\n for (let i = 0; i < props.columns.length; i++) {\n if (!widths[i]) {\n const td = tds[startIndex + i] as HTMLElement | undefined\n if (td && td.clientWidth > 0) {\n const measured = `${td.clientWidth}px`\n widths[i] = measured\n headerWidthMap.value[props.columns[i].key] = measured\n } else {\n const autoWidth = getAutoColumnWidth()\n widths[i] = autoWidth\n headerWidthMap.value[props.columns[i].key] = autoWidth\n }\n }\n }\n } else {\n // 没有数据时,尽量沿用上一次测量结果,避免列宽跳动\n for (let i = 0; i < widths.length; i++) {\n if (!widths[i]) {\n const stored = headerWidthMap.value[props.columns[i]?.key || '']\n widths[i] = stored || headerColWidths.value[i] || '80px'\n if (props.columns[i]) {\n headerWidthMap.value[props.columns[i].key] = widths[i]\n }\n }\n }\n }\n headerColWidths.value = widths\n })\n}\n\n// 窗口大小变化和滚动时重新计算\nfunction handleResize() {\n calculateTableMaxHeight()\n updateHeaderScrollbarGutter()\n syncSelectedHeaderHeight()\n}\n\n// 监听数据变化,重新计算高度\nwatch(() => props.data, () => {\n nextTick(() => {\n calculateTableMaxHeight()\n // 不在数据变化时重新测量列宽,避免分页切换引起的列宽抖动\n syncHeaderScroll()\n updateHeaderScrollbarGutter()\n expandedKeys.value.clear()\n })\n}, { deep: true })\n\n// 监听分页变化,重新计算高度\nwatch([currentPage, pageSize], () => {\n nextTick(() => {\n calculateTableMaxHeight()\n // 分页切换不再重新测量列宽\n syncHeaderScroll()\n updateHeaderScrollbarGutter()\n })\n})\n\n// 列配置变化时,重置并测量列宽\nwatch(() => props.columns, () => {\n const nextWidths: string[] = []\n const nextMap: Record<string, string> = { ...headerWidthMap.value }\n\n props.columns.forEach((col, idx) => {\n const normalizedWidth = normalizeWidth(col.width)\n if (normalizedWidth) {\n nextWidths.push(normalizedWidth)\n nextMap[col.key] = normalizedWidth\n } else if (nextMap[col.key]) {\n nextWidths.push(nextMap[col.key])\n } else if (headerColWidths.value[idx]) {\n nextWidths.push(headerColWidths.value[idx])\n nextMap[col.key] = headerColWidths.value[idx]\n } else {\n nextWidths.push('')\n }\n })\n\n // 移除已经不存在的列的缓存\n const currentKeys = new Set(props.columns.map(col => col.key))\n Object.keys(nextMap).forEach((key) => {\n if (!currentKeys.has(key)) {\n delete nextMap[key]\n }\n })\n\n headerWidthMap.value = nextMap\n headerColWidths.value = nextWidths\n\n nextTick(() => {\n measureAutoColumnWidths()\n syncHeaderScroll()\n updateHeaderScrollbarGutter()\n syncSelectedHeaderHeight()\n })\n}, { deep: true })\n\n// 测量并存储默认表头的标准高度\nfunction measureDefaultHeaderHeight() {\n nextTick(() => {\n if (!headerRef.value) return\n const headerTable = headerRef.value.querySelector('.table')\n if (!headerTable) return\n \n // 只有当没有选中项时(显示默认表头)才测量\n if (selectedItems.value.length === 0) {\n const firstNormalTh = headerTable.querySelector('thead th:not(.col-select):not(.col-expand)') as HTMLElement\n if (firstNormalTh && firstNormalTh.offsetHeight > 0) {\n defaultHeaderHeight.value = firstNormalTh.offsetHeight\n }\n }\n })\n}\n\n// 同步自定义表头高度与默认表头高度\nfunction syncSelectedHeaderHeight() {\n nextTick(() => {\n if (!headerRef.value) return\n const headerTable = headerRef.value.querySelector('.table')\n if (!headerTable) return\n \n // 如果当前显示的是自定义表头,应用存储的默认高度\n const selectedHeader = headerTable.querySelector('.col-selected-header') as HTMLElement\n if (selectedHeader) {\n const wrapper = selectedHeader.querySelector('.selected-header-wrapper') as HTMLElement\n if (wrapper) {\n wrapper.style.height = `${defaultHeaderHeight.value}px`\n }\n } else {\n // 如果显示的是默认表头,更新存储的高度\n measureDefaultHeaderHeight()\n }\n })\n}\n\n// 监听选中项变化,重新计算高度(批量操作栏显示/隐藏)\nwatch(() => selectedItems.value, () => {\n nextTick(() => {\n calculateTableMaxHeight()\n updateHeaderScrollbarGutter()\n syncSelectedHeaderHeight()\n })\n}, { deep: true })\n\n// 监听 loading 状态变化,更新滚动条补偿\nwatch(() => props.loading, () => {\n nextTick(() => {\n updateHeaderScrollbarGutter()\n })\n})\n\n// 生命周期\nonMounted(() => {\n nextTick(() => {\n calculateTableMaxHeight()\n measureAutoColumnWidths()\n updateHeaderScrollbarGutter()\n updateVirtualScrollbar()\n measureDefaultHeaderHeight()\n syncSelectedHeaderHeight()\n })\n window.addEventListener('resize', handleResize)\n window.addEventListener('scroll', handleResize, true)\n // 监听内容滚动以同步表头\n bodyWrapRef.value?.addEventListener('scroll', () => {\n syncHeaderScroll()\n updateVirtualScrollbar()\n // 滚动时也更新滚动条补偿(因为滚动可能导致内容高度变化)\n updateHeaderScrollbarGutter()\n }, { passive: true })\n // 监听表头滚动以同步内容区域\n headerRef.value?.addEventListener('scroll', () => {\n syncBodyScroll()\n }, { passive: true })\n // 初始同步一次\n nextTick(() => syncHeaderScroll())\n \n // 使用 ResizeObserver 监听内容区域大小变化,实时更新滚动条补偿\n if (bodyWrapRef.value && typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => {\n updateHeaderScrollbarGutter()\n })\n resizeObserver.observe(bodyWrapRef.value)\n }\n})\n\nonUnmounted(() => {\n window.removeEventListener('resize', handleResize)\n window.removeEventListener('scroll', handleResize, true)\n bodyWrapRef.value?.removeEventListener('scroll', syncHeaderScroll)\n headerRef.value?.removeEventListener('scroll', syncBodyScroll)\n window.removeEventListener('mousemove', onThumbMousemove)\n window.removeEventListener('mouseup', onThumbMouseup)\n // 清理 ResizeObserver\n if (resizeObserver) {\n resizeObserver.disconnect()\n resizeObserver = null\n }\n})\n\n// 为表头添加与内容滚动条同宽的内边距,避免列错位\nlet lastScrollbarWidth = -1 // 缓存上次的滚动条宽度,避免不必要的 DOM 操作\nfunction updateHeaderScrollbarGutter() {\n if (!headerRef.value || !bodyWrapRef.value) return\n \n // 使用 requestAnimationFrame 确保在浏览器重绘后计算\n requestAnimationFrame(() => {\n if (!headerRef.value || !bodyWrapRef.value) return\n \n const wrap = bodyWrapRef.value\n // 计算滚动条宽度(容器总宽度 - 内容可见宽度)\n // 注意:这里需要考虑竖向滚动条(占用右侧空间)\n const currentScrollbarWidth = Math.ceil(wrap.offsetWidth - wrap.clientWidth)\n \n // 更新响应式变量\n scrollbarWidth.value = currentScrollbarWidth\n \n // 只有当滚动条宽度发生变化时才更新 DOM,避免不必要的操作\n if (currentScrollbarWidth !== lastScrollbarWidth) {\n lastScrollbarWidth = currentScrollbarWidth\n const headerTable = headerRef.value.querySelector('.table') as HTMLElement\n const bodyTable = bodyTableRef.value\n \n if (headerTable && bodyTable) {\n // 先移除之前的样式,确保测量准确\n headerRef.value.style.paddingRight = '0px'\n headerTable.style.width = ''\n headerTable.style.marginRight = ''\n \n // 测量表头和内容区域的 table 实际宽度\n // const headerTableWidth = headerTable.offsetWidth\n // const bodyTableWidth = bodyTable.offsetWidth\n \n // 计算宽度差异\n // const widthDiff = bodyTableWidth - headerTableWidth\n \n if (currentScrollbarWidth > 0) {\n // 如果有滚动条,需要补偿\n // 表头容器的 padding-right 用于补偿滚动条宽度\n headerRef.value.style.paddingRight = `${currentScrollbarWidth}px`\n // table 的宽度设置为 100%(相对于容器内容区域,不包括 padding)\n // 这样表头 table 的宽度就会和内容区域 table 的实际宽度一致\n headerTable.style.width = '100%'\n // 使用负 margin 让 table 向右偏移,填充 padding 区域\n // 这样表头 table 的右边缘就会和内容区域 table 的右边缘对齐\n headerTable.style.marginRight = `-${currentScrollbarWidth}px`\n } else {\n headerRef.value.style.paddingRight = '0px'\n headerTable.style.width = '100%'\n headerTable.style.marginRight = '0px'\n }\n }\n }\n })\n}\n\n// 使用 ResizeObserver 监听内容区域大小变化,自动更新滚动条补偿\nlet resizeObserver: ResizeObserver | null = null\n\n// 清理 hintTag 实例(组件卸载时)\nonUnmounted(() => {\n hintTagInstances.value.clear()\n})\n</script>\n\n<style scoped lang=\"less\">\n.ytable-container {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.bulk-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 10px;\n background: #FFFFFF;\n border: 1px solid #dfe3e8;\n border-radius: 6px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n.bulk-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* 批量操作栏出现/消失动画 */\n.bulk-slide-enter-active,\n.bulk-slide-leave-active {\n transition: all 0.2s ease;\n}\n\n.bulk-slide-enter-from,\n.bulk-slide-leave-to {\n transform: translateY(-8px);\n opacity: 0;\n}\n\n.card {\n border-radius: 6px;\n background: #fff;\n padding: 4px 5px;\n box-shadow: 0rem 0.3125rem 0.3125rem -0.15625rem rgba(0, 0, 0, 0.03),\n 0rem 0.1875rem 0.1875rem -0.09375rem rgba(0, 0, 0, 0.02),\n 0rem 0.125rem 0.125rem -0.0625rem rgba(0, 0, 0, 0.02),\n 0rem 0.0625rem 0.0625rem -0.03125rem rgba(0, 0, 0, 0.03),\n 0rem 0.03125rem 0.03125rem 0rem rgba(0, 0, 0, 0.04),\n 0rem 0rem 0rem 0.0625rem rgba(0, 0, 0, 0.06);\n position: relative;\n}\n\n/* 表头右上角操作按钮区域 */\n.table-header-actions {\n position: absolute;\n top: 8px;\n right: 12px;\n z-index: 10;\n pointer-events: auto;\n}\n\n.toggle-all-hints-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: #ffffff;\n color: #666666;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n cursor: pointer;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n transition: all 0.2s ease;\n padding: 0;\n}\n\n.toggle-all-hints-btn:hover {\n color: #333333;\n background: #f5f5f5;\n border-color: #d1d5db;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);\n}\n\n.toggle-all-hints-btn:active {\n transform: scale(0.95);\n}\n\n.toggle-all-hints-btn.is-expanded {\n color: #008060;\n border-color: #008060;\n}\n\n.toggle-all-hints-btn.is-expanded:hover {\n background: #f0f9f7;\n border-color: #006b52;\n}\n\n.toggle-icon {\n width: 16px;\n height: 16px;\n transition: transform 0.2s ease;\n}\n\n/* 表头固定区域 */\n.table-header {\n width: 100%;\n overflow-x: auto; /* 允许水平滚动 */\n overflow-y: hidden; /* 禁止垂直滚动 */\n /* 隐藏滚动条,但保持滚动功能 */\n scrollbar-width: none; /* Firefox */\n -ms-overflow-style: none; /* IE/Edge */\n /* 通过 JavaScript 动态设置 table 的 margin-right 来补偿滚动条宽度 */\n box-sizing: border-box;\n position: relative;\n}\n\n/* 隐藏表头区域的滚动条 */\n.table-header::-webkit-scrollbar {\n display: none;\n}\n\n/* 选中状态下的自定义表头 */\n.col-selected-header {\n padding: 0 !important;\n border-bottom: none !important;\n vertical-align: middle; /* 确保垂直对齐与默认表头一致 */\n}\n\n.selected-header-wrapper {\n width: 100%;\n background: #f8f9fa;\n border-bottom: 1px solid #dfe3e8;\n padding: 8px 12px; /* 上下 padding 与默认表头的 8px 8px 保持一致 */\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 8px;\n box-sizing: border-box;\n line-height: 1.5; /* 与默认表头的行高保持一致 */\n /* 使用固定高度确保与默认表头完全一致 */\n /* 默认表头: padding(8px * 2) + 内容高度(约12px * 1.5 = 18px) = 34px */\n height: 35px; /* 包含边框后的总高度 */\n}\n\n/* 表格内容滚动区域 */\n.table-body-wrap {\n width: 100%;\n overflow: auto;\n position: relative;\n padding-right: 0; // 右侧不留 padding\n /* 滚动条会占用空间,通过动态补偿表头来保持对齐 */\n}\n\n// 加载中时,确保最小高度存在,避免高度被收缩\n.table-body-wrap.is-loading {\n min-height: 200px;\n}\n\n// 空数据时保证最小高度,用于承载覆盖层\n.table-body-wrap.is-empty {\n min-height: 200px;\n}\n\n// 空数据覆盖层(不改变表格布局,避免副作用)\n.empty-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n pointer-events: none; // 允许滚动容器继续滚动(若需要)\n}\n\n// 仅在卡片内的滚动区域做“贴边”处理\n.card > .table-body-wrap {\n width: calc(100% + 4px);\n margin-right: -4px; // 抵消 .card 的 5px 右内边距\n}\n\n// 移除已废弃的 overflow: overlay,使用动态计算滚动条宽度来保持对齐\n\n/* 滚动条样式 - 只在内容区域 */\n.table-body-wrap::-webkit-scrollbar {\n width: 4px;\n height: 6px;\n}\n// 隐藏原生竖向滚动条(保留横向)\n.table-body-wrap::-webkit-scrollbar:vertical {\n width: 0;\n}\n\n// 明确指定水平滚动条厚度与侧边一致\n.table-body-wrap::-webkit-scrollbar:horizontal {\n height: 6px;\n}\n\n.table-body-wrap::-webkit-scrollbar-track {\n background: transparent;\n position: relative;\n \n // 添加顶部箭头\n &::before {\n content: '';\n position: absolute;\n top: 1px;\n left: 50%;\n transform: translateX(-50%);\n width: 0;\n height: 0;\n border-left: 2px solid transparent;\n border-right: 2px solid transparent;\n border-bottom: 3px solid #9ca3af;\n z-index: 1;\n transition: all 0.2s ease;\n }\n \n // 添加底部箭头\n &::after {\n content: '';\n position: absolute;\n bottom: 1px;\n left: 50%;\n transform: translateX(-50%);\n width: 0;\n height: 0;\n border-left: 2px solid transparent;\n border-right: 2px solid transparent;\n border-top: 3px solid #9ca3af;\n z-index: 1;\n transition: all 0.2s ease;\n }\n}\n\n// 水平滚动条轨道与左右箭头\n.table-body-wrap::-webkit-scrollbar-track:horizontal {\n background: transparent;\n position: relative;\n}\n\n.table-body-wrap::-webkit-scrollbar-track:horizontal::before {\n content: '';\n position: absolute;\n left: 1px;\n top: 50%;\n transform: translateY(-50%);\n width: 0;\n height: 0;\n border-top: 2px solid transparent;\n border-bottom: 2px solid transparent;\n border-right: 3px solid #9ca3af; // 左侧指向右的三角\n z-index: 1;\n transition: all 0.2s ease;\n}\n\n.table-body-wrap::-webkit-scrollbar-track:horizontal::after {\n content: '';\n position: absolute;\n right: 1px;\n top: 50%;\n transform: translateY(-50%);\n width: 0;\n height: 0;\n border-top: 2px solid transparent;\n border-bottom: 2px solid transparent;\n border-left: 3px solid #9ca3af; // 右侧指向左的三角\n z-index: 1;\n transition: all 0.2s ease;\n}\n\n.table-body-wrap::-webkit-scrollbar-thumb {\n background: #bac0ca;\n border-radius: 2px;\n transition: all 0.2s ease;\n margin: 4px 0; // 为箭头留出空间\n \n &:hover {\n background: #6b7280;\n }\n \n &:active {\n background: #4b5563;\n }\n}\n\n// 水平 thumb 预留左右边距,避免遮挡左右箭头\n.table-body-wrap::-webkit-scrollbar-thumb:horizontal {\n margin: 0 4px;\n}\n\n.table-body-wrap::-webkit-scrollbar-corner {\n background: transparent;\n}\n\n// Firefox 滚动条厚度与颜色(与侧边一致)\n.table-body-wrap {\n scrollbar-width: thin;\n scrollbar-color: #bac0ca transparent;\n}\n\n// 滚动条按钮样式(兼容性)\n.table-body-wrap::-webkit-scrollbar-button {\n display: block;\n height: 4px;\n background: transparent;\n \n // 顶部按钮\n &:vertical:start:decrement {\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 3'%3E%3Cpath fill='%239ca3af' d='M2 0L0 3h4z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: center;\n background-size: 4px 3px;\n }\n \n // 底部按钮\n &:vertical:end:increment {\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 3'%3E%3Cpath fill='%239ca3af' d='M2 3L0 0h4z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: center;\n background-size: 4px 3px;\n }\n \n &:hover {\n // 悬停时箭头颜色变深\n &:vertical:start:decrement {\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 3'%3E%3Cpath fill='%236b7280' d='M2 0L0 3h4z'/%3E%3C/svg%3E\");\n }\n \n &:vertical:end:increment {\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 3'%3E%3Cpath fill='%236b7280' d='M2 3L0 0h4z'/%3E%3C/svg%3E\");\n }\n }\n}\n\n.table {\n width: 100%;\n border-collapse: separate;\n border-spacing: 0;\n table-layout: fixed;\n}\n\n.table thead th {\n text-align: left;\n // font-weight: 600;\n font-size: 12px;\n color: #7c7c7c;\n background: #f8f9fa;\n border-bottom: 1px solid #dfe3e8;\n padding: 8px 8px;\n white-space: nowrap;\n}\n\n\n.table tbody td {\n padding: 4px 8px;\n border-bottom: 1px solid #f1f3f4;\n vertical-align: middle;\n text-align: left;\n font-size: 12px;\n // font-weight: 550;\n color: #535353;\n transition: background-color 0.3s ease;\n}\n\n/* 行选中样式 */\n.table tbody tr {\n transition: background-color 0.3s ease;\n}\n\n.table tbody tr.row-selected {\n background-color: #e6f4ff;\n}\n\n.table tbody tr.row-selected td {\n background-color: #e6f4ff;\n}\n\n.table tbody tr:hover:not(.row-selected) {\n background-color: #f5f5f5;\n}\n\n.col-select {\n width: auto;\n min-width: 60px;\n}\n\n.select-header {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n}\n\n.select-count {\n font-size: 11px;\n color: #1A1A1A;\n font-weight: 600;\n background: #f0f0f0;\n padding: 0 4px;\n border-radius: 3px;\n line-height: 1.4;\n white-space: nowrap;\n}\n\n.col-expand {\n width: 28px;\n text-align: center;\n}\n\n.expand-btn {\n width: 20px;\n height: 20px;\n border: none;\n border-radius: 4px;\n background: transparent;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s ease;\n}\n\n.expand-btn:hover {\n background: rgba(0, 0, 0, 0.05);\n}\n\n.expand-icon {\n display: inline-block;\n width: 0;\n height: 0;\n border-left: 5px solid transparent;\n border-right: 5px solid transparent;\n border-top: 7px solid #6b7280;\n transition: transform 0.2s ease;\n}\n\n.expand-icon.is-open {\n transform: rotate(180deg);\n}\n\n.expand-row .expand-cell {\n background: #f9fafb;\n}\n\n/* 通用固定列样式(右侧) */\n.table thead th.col-fixed-right,\n.table tbody td.col-fixed-right {\n position: sticky;\n /* right 值通过 JavaScript 动态设置 */\n background: #fff;\n /* z-index 通过 JavaScript 动态设置 */\n transition: background-color 0.3s ease;\n}\n.table tbody td.col-fixed-right {\n box-shadow: -6px 0 6px -6px rgba(0,0,0,0.08);\n}\n\n/* 通用固定列样式(左侧) */\n.table thead th.col-fixed-left,\n.table tbody td.col-fixed-left {\n position: sticky;\n /* left 值通过 JavaScript 动态设置 */\n background: #fff;\n /* z-index 通过 JavaScript 动态设置 */\n transition: background-color 0.3s ease;\n}\n.table tbody td.col-fixed-left {\n box-shadow: 6px 0 6px -6px rgba(0,0,0,0.08);\n}\n\n/* 选中行时固定列的背景色 */\n.table tbody tr.row-selected td.col-fixed-right,\n.table tbody tr.row-selected td.col-fixed-left {\n background-color: #e6f4ff;\n}\n\n.text-left { text-align: left; }\n.text-center { text-align: center; }\n.text-right { text-align: right; }\n\n\n.link {\n background: transparent;\n border: none;\n color: #2563eb;\n cursor: pointer;\n}\n\n.empty {\n text-align: center;\n color: #888;\n padding: 0;\n height: 200px; // 保底高度\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* 复选框主题色为 #1A1A1A */\n.table input[type=\"checkbox\"],\n.bulk-bar input[type=\"checkbox\"] {\n accent-color: #1A1A1A;\n}\n\n/* 复选框中间状态(indeterminate)样式 */\n.table input[type=\"checkbox\"]:indeterminate,\n.bulk-bar input[type=\"checkbox\"]:indeterminate {\n accent-color: #1A1A1A;\n}\n\n/* 聚焦时轻微外发光,保持无侵入 */\n.table input[type=\"checkbox\"]:focus-visible,\n.bulk-bar input[type=\"checkbox\"]:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px rgba(26, 26, 26, 0.2);\n border-radius: 3px;\n}\n\n/* Loading 状态样式 */\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.8);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n z-index: 10;\n}\n\n.loading-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid #f3f3f3;\n border-top: 3px solid #1A1A1A;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n margin-bottom: 8px;\n}\n\n.loading-text {\n font-size: 14px;\n color: #666;\n}\n\n@keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.loading-table {\n opacity: 0.6;\n pointer-events: none;\n}\n\n/* 右对齐分页(覆盖子组件内部的 space-between) */\n:deep(.ypagination.align-right) {\n justify-content: flex-end !important;\n}\n\n/* 自定义悬浮竖向滚动条 */\n.v-scrollbar {\n position: absolute;\n top: 0;\n right: 2px;\n bottom: 0;\n width: 8px;\n display: flex;\n align-items: stretch;\n z-index: 5;\n pointer-events: none; // 仅轨道与滑块可交互\n}\n\n.v-scrollbar-track {\n position: relative;\n width: 100%;\n margin: 4px 0;\n border-radius: 4px;\n background: rgba(0,0,0,0.03);\n transition: background 0.2s ease;\n pointer-events: auto;\n}\n\n.v-scrollbar:hover .v-scrollbar-track {\n background: rgba(0,0,0,0.06);\n}\n\n.v-scrollbar-thumb {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n border-radius: 4px;\n background: rgba(0,0,0,0.24);\n cursor: grab;\n pointer-events: auto;\n transition: background 0.2s ease, opacity 0.2s ease;\n}\n\n.v-scrollbar-thumb:hover {\n background: rgba(0,0,0,0.34);\n}\n\n.v-scrollbar-thumb:active {\n cursor: grabbing;\n background: rgba(0,0,0,0.42);\n}\n</style>\n","<template>\n <div class=\"yselect\" :class=\"{ 'yselect--disabled': disabled, [`yselect--${size}`]: true }\" :style=\"{ width: width }\" ref=\"selectContainer\">\n <div \n ref=\"triggerElement\"\n class=\"yselect__trigger\"\n :class=\"{ \n 'yselect__trigger--open': isOpen,\n 'yselect__trigger--disabled': disabled,\n 'yselect__trigger--error': error\n }\"\n @mousedown.prevent.stop=\"toggleDropdown\"\n @keydown.enter.prevent=\"toggleDropdown\"\n @keydown.space.prevent=\"toggleDropdown\"\n @keydown.escape=\"closeDropdown\"\n @keydown.arrow-down.prevent=\"openDropdown\"\n @keydown.arrow-up.prevent=\"openDropdown\"\n tabindex=\"0\"\n role=\"combobox\"\n :aria-expanded=\"isOpen\"\n :aria-haspopup=\"true\"\n >\n <span class=\"yselect__value\" :class=\"{ 'yselect__placeholder': !selectedLabel }\" v-if=\"!filterable || !isOpen\">\n <slot name=\"value\" :value=\"props.multiple ? selectedOptions : selectedOption\" :label=\"selectedLabel\" :multiple=\"props.multiple\">\n <template v-if=\"props.multiple\">\n <div class=\"yselect__tags\" v-if=\"selectedOptions.length > 0\">\n <span \n v-for=\"(option, idx) in selectedOptions\" \n :key=\"getOptionKey(option, idx)\"\n class=\"yselect__tag\"\n >\n <img \n v-if=\"(option as any)?.flagImg\"\n class=\"yselect__flag\"\n :src=\"(option as any).flagImg\"\n alt=\"flag\"\n />\n <span class=\"yselect__tag-text\">{{ getOptionLabel(option) }}</span>\n <span \n v-if=\"clearable && !disabled\"\n class=\"yselect__tag-close\"\n @click.stop=\"removeTag(option, $event)\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M2.5 2.5l5 5M7.5 2.5l-5 5\" stroke=\"currentColor\" stroke-width=\"1.2\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n </span>\n </div>\n <span v-else class=\"yselect__placeholder-text\">{{ placeholder }}</span>\n </template>\n <template v-else>\n <template v-if=\"selectedOption\">\n <img \n v-if=\"(selectedOption as any)?.flagImg\"\n class=\"yselect__flag\"\n :src=\"(selectedOption as any).flagImg\"\n alt=\"flag\"\n />\n {{ selectedLabel }}\n </template>\n <template v-else>\n {{ placeholder }}\n </template>\n </template>\n </slot>\n </span>\n <input\n v-else\n ref=\"inputElement\"\n class=\"yselect__input\"\n type=\"text\"\n :placeholder=\"props.multiple ? (selectedOptions.length > 0 ? `已选择 ${selectedOptions.length} 项` : placeholder) : (selectedLabel || placeholder)\"\n v-model=\"searchQuery\"\n @keydown.stop\n @keydown.arrow-down.prevent=\"moveHover(1)\"\n @keydown.arrow-up.prevent=\"moveHover(-1)\"\n @keydown.enter.prevent=\"selectHovered()\"\n @keydown.esc.prevent=\"closeDropdown\"\n @keydown.delete.prevent=\"handleClear\"\n />\n <span \n v-if=\"clearable && !disabled && (props.multiple ? selectedOptions.length > 0 : selectedOption)\"\n class=\"yselect__clear\"\n title=\"清空\"\n @click.stop=\"handleClear\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <path d=\"M3 3l6 6M9 3L3 9\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n <span class=\"yselect__arrow\" :class=\"{ 'yselect__arrow--open': isOpen }\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <path d=\"M3 4.5L6 7.5L9 4.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n </div>\n\n <transition name=\"yselect-dropdown\">\n <teleport to=\"body\">\n <div \n v-if=\"isOpen\" \n class=\"yselect__dropdown yselect__dropdown--portal\"\n :class=\"{ 'yselect__dropdown--top': shouldOpenUpward }\"\n :style=\"portalDropdownStyle\"\n @mousedown.stop\n @click.stop\n >\n <div class=\"yselect__options\" ref=\"optionsContainer\">\n <div\n v-for=\"(option, index) in displayedOptions\"\n :key=\"getOptionKey(option, index)\"\n class=\"yselect__option\"\n :class=\"{\n 'yselect__option--selected': isSelected(option),\n 'yselect__option--disabled': isOptionDisabled(option),\n 'yselect__option--hover': hoveredIndex === index\n }\"\n @click=\"selectOption(option, index)\"\n @mouseenter=\"hoveredIndex = index\"\n @mouseleave=\"hoveredIndex = -1\"\n >\n <slot name=\"option\" :option=\"option\" :index=\"index\" :selected=\"isSelected(option)\">\n <span v-if=\"props.multiple\" class=\"yselect__option-check\">\n <svg \n v-if=\"isSelected(option)\"\n width=\"14\" \n height=\"14\" \n viewBox=\"0 0 14 14\" \n fill=\"none\"\n >\n <path d=\"M2 7l3 3 7-7\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <img \n v-if=\"(option as any)?.flagImg\"\n class=\"yselect__flag\"\n :src=\"(option as any).flagImg\"\n alt=\"flag\"\n />\n {{ getOptionLabel(option) }}\n </slot>\n </div>\n </div>\n </div>\n </teleport>\n </transition>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch, nextTick, onMounted, onUnmounted } from 'vue'\n\nexport interface SelectOption {\n label: string\n value: any\n disabled?: boolean\n [key: string]: any\n}\n\nexport interface SelectProps {\n modelValue?: any | any[]\n options: SelectOption[] | any[]\n placeholder?: string\n disabled?: boolean\n error?: boolean\n clearable?: boolean\n clearTo?: any\n filterable?: boolean\n multiple?: boolean\n valueKey?: string\n labelKey?: string\n disabledKey?: string\n size?: 'small' | 'medium' | 'large'\n width?: string\n}\n\nconst props = withDefaults(defineProps<SelectProps>(), {\n placeholder: '请选择',\n disabled: false,\n error: false,\n clearable: true,\n clearTo: undefined,\n filterable: false,\n multiple: false,\n valueKey: 'value',\n labelKey: 'label',\n disabledKey: 'disabled',\n size: 'medium',\n width: '200px'\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: any | any[]]\n 'change': [value: any | any[], option: SelectOption | SelectOption[] | null]\n 'focus': [event: FocusEvent]\n 'blur': [event: FocusEvent]\n 'clear': []\n}>()\n\n// 响应式数据\nconst isOpen = ref(false)\nconst hoveredIndex = ref(-1)\nconst optionsContainer = ref<HTMLElement>()\nconst triggerElement = ref<HTMLElement>()\nconst selectContainer = ref<HTMLElement>()\nconst shouldOpenUpward = ref(false)\nconst inputElement = ref<HTMLInputElement>()\nconst searchQuery = ref('')\n\n// 计算属性\nconst selectedOption = computed(() => {\n if (props.multiple) return null\n return props.options.find(option => getOptionValue(option) === props.modelValue) || null\n})\n\nconst selectedOptions = computed(() => {\n if (!props.multiple) return []\n const values = Array.isArray(props.modelValue) ? props.modelValue : []\n return props.options.filter(option => values.includes(getOptionValue(option)))\n})\n\nconst selectedLabel = computed(() => {\n if (props.multiple) {\n const count = selectedOptions.value.length\n if (count === 0) return ''\n return `已选择 ${count} 项`\n }\n return selectedOption.value ? getOptionLabel(selectedOption.value) : ''\n})\n\nconst displayedOptions = computed(() => {\n if (!props.filterable) return props.options\n const query = searchQuery.value.trim().toLowerCase()\n if (!query) return props.options\n return props.options.filter((opt: any) => {\n const label = getOptionLabel(opt)\n return String(label).toLowerCase().includes(query)\n })\n})\n\n// const dropdownStyle = computed(() => {\n// const style: Record<string, string> = {}\n// \n// if (props.width === 'auto') {\n// style.width = '100%'\n// style.minWidth = 'auto'\n// } else {\n// style.width = props.width\n// style.minWidth = props.width\n// }\n// \n// return style\n// })\n\nconst portalDropdownStyle = computed(() => {\n const style: Record<string, string> = { position: 'fixed', zIndex: '4000' }\n const trigger = triggerElement.value\n if (!trigger) return style\n const rect = trigger.getBoundingClientRect()\n const width = (selectContainer.value?.getBoundingClientRect().width || rect.width)\n style.left = `${rect.left}px`\n style.width = `${width}px`\n if (shouldOpenUpward.value) {\n // 向上展开时,使用 bottom 定位而不是 top,这样更准确\n style.bottom = `${window.innerHeight - rect.top + 4}px`\n style.top = 'auto'\n } else {\n style.top = `${rect.bottom + 4}px`\n }\n return style\n})\n\n// 计算是否应该向上展开\nfunction calculateDropdownPosition() {\n if (!isOpen.value || !triggerElement.value) return\n \n nextTick(() => {\n const trigger = triggerElement.value\n if (!trigger) return\n \n const triggerRect = trigger.getBoundingClientRect()\n const viewportHeight = window.innerHeight\n const dropdownHeight = 200 // 预估下拉菜单高度\n \n // 计算下拉菜单底部位置\n const dropdownBottom = triggerRect.bottom + dropdownHeight + 4 // 4px 是 margin-top\n \n // 计算向上展开时下拉菜单顶部位置\n const dropdownTop = triggerRect.top - dropdownHeight - 4 // 4px 是 margin-bottom\n \n // 如果下拉菜单会超出视口底部,且向上展开不会超出视口顶部,则向上展开\n const shouldOpenDown = dropdownBottom <= viewportHeight - 20 // 20px 安全边距\n const canOpenUp = dropdownTop >= 20 // 20px 安全边距\n \n shouldOpenUpward.value = !shouldOpenDown && canOpenUp\n })\n}\n\n// 方法\nfunction getOptionValue(option: any): any {\n if (typeof option === 'object' && option !== null) {\n return option[props.valueKey]\n }\n return option\n}\n\nfunction getOptionLabel(option: any): string {\n if (typeof option === 'object' && option !== null) {\n return option[props.labelKey] || String(option[props.valueKey])\n }\n return String(option)\n}\n\nfunction getOptionKey(option: any, index: number): string | number {\n if (typeof option === 'object' && option !== null && option.id !== undefined) {\n return option.id\n }\n return getOptionValue(option) || index\n}\n\nfunction isSelected(option: any): boolean {\n if (props.multiple) {\n const values = Array.isArray(props.modelValue) ? props.modelValue : []\n return values.includes(getOptionValue(option))\n }\n return getOptionValue(option) === props.modelValue\n}\n\nfunction isOptionDisabled(option: any): boolean {\n if (typeof option === 'object' && option !== null) {\n return option[props.disabledKey] === true\n }\n return false\n}\n\nfunction toggleDropdown() {\n if (props.disabled) return\n isOpen.value ? closeDropdown() : openDropdown()\n}\n\nfunction openDropdown() {\n if (props.disabled) return\n isOpen.value = true\n nextTick(() => {\n calculateDropdownPosition()\n scrollToSelected()\n if (props.filterable && inputElement.value) {\n inputElement.value.focus()\n // 打开时默认清空,便于直接输入筛选\n searchQuery.value = ''\n }\n })\n}\n\nfunction closeDropdown() {\n isOpen.value = false\n hoveredIndex.value = -1\n shouldOpenUpward.value = false\n if (props.filterable) {\n searchQuery.value = ''\n }\n}\n\nfunction selectOption(option: any, _index: number) {\n if (isOptionDisabled(option)) return\n \n const value = getOptionValue(option)\n \n if (props.multiple) {\n const currentValues = Array.isArray(props.modelValue) ? [...props.modelValue] : []\n const optionValue = getOptionValue(option)\n const valueIndex = currentValues.indexOf(optionValue)\n \n if (valueIndex > -1) {\n // 取消选择\n currentValues.splice(valueIndex, 1)\n } else {\n // 添加选择\n currentValues.push(optionValue)\n }\n \n emit('update:modelValue', currentValues)\n emit('change', currentValues, selectedOptions.value)\n // 多选模式下不关闭下拉框\n } else {\n emit('update:modelValue', value)\n emit('change', value, option)\n closeDropdown()\n }\n}\n\nfunction handleClear() {\n if (!props.clearable || props.disabled) return\n const cleared = props.multiple ? (props.clearTo !== undefined ? props.clearTo : []) : props.clearTo\n emit('update:modelValue', cleared)\n emit('change', cleared, props.multiple ? [] : null)\n emit('clear')\n // 清空后关闭下拉并重置搜索\n if (!props.multiple) {\n closeDropdown()\n }\n}\n\nfunction removeTag(option: any, event: Event) {\n event.stopPropagation()\n if (props.disabled || !props.multiple) return\n \n const currentValues = Array.isArray(props.modelValue) ? [...props.modelValue] : []\n const optionValue = getOptionValue(option)\n const index = currentValues.indexOf(optionValue)\n \n if (index > -1) {\n currentValues.splice(index, 1)\n emit('update:modelValue', currentValues)\n emit('change', currentValues, selectedOptions.value)\n }\n}\n\nfunction moveHover(delta: number) {\n if (!displayedOptions.value || displayedOptions.value.length === 0) {\n hoveredIndex.value = -1\n return\n }\n let next = hoveredIndex.value\n const total = displayedOptions.value.length\n // 初次移动时从 -1 开始\n if (next === -1) {\n next = delta > 0 ? 0 : total - 1\n } else {\n next = (next + delta + total) % total\n }\n // 跳过禁用项,最多循环 total 次避免死循环\n let attempts = 0\n while (attempts < total && isOptionDisabled(displayedOptions.value[next])) {\n next = (next + delta + total) % total\n attempts++\n }\n hoveredIndex.value = attempts >= total ? -1 : next\n scrollHoverIntoView()\n}\n\nfunction selectHovered() {\n if (hoveredIndex.value < 0) return\n const option = displayedOptions.value[hoveredIndex.value]\n if (!option || isOptionDisabled(option)) return\n selectOption(option, hoveredIndex.value)\n}\n\nfunction scrollToSelected() {\n if (!optionsContainer.value) return\n \n const selectedElement = optionsContainer.value.querySelector('.yselect__option--selected') as HTMLElement | null\n if (selectedElement) {\n selectedElement.scrollIntoView({ block: 'nearest' })\n }\n}\n\nfunction scrollHoverIntoView() {\n if (!optionsContainer.value) return\n if (hoveredIndex.value < 0) return\n const optionNodes = optionsContainer.value.querySelectorAll('.yselect__option')\n const el = optionNodes[hoveredIndex.value] as HTMLElement | undefined\n if (el) el.scrollIntoView({ block: 'nearest' })\n}\n\nfunction handleClickOutside(event: Event) {\n const target = event.target as HTMLElement\n if (!selectContainer.value || !selectContainer.value.contains(target)) {\n closeDropdown()\n }\n}\n\n// 监听器\nwatch(() => props.modelValue, () => {\n hoveredIndex.value = -1\n})\n\n// 窗口大小变化和滚动时重新计算位置\nfunction handleResize() {\n if (isOpen.value) {\n calculateDropdownPosition()\n }\n}\n\n// 生命周期\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n window.addEventListener('resize', handleResize)\n window.addEventListener('scroll', handleResize, true)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('resize', handleResize)\n window.removeEventListener('scroll', handleResize, true)\n})\n</script>\n\n<style scoped lang=\"less\">\n.yselect {\n position: relative;\n display: inline-block;\n width: 100%;\n min-width: 0;\n flex-shrink: 0;\n}\n\n.yselect--disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.yselect__trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n min-width: 0;\n flex-shrink: 0;\n border: 1px solid #e2e8f0;\n background: #ffffff;\n cursor: pointer;\n transition: box-shadow 0.2s ease, border-color 0.2s ease;\n outline: none;\n line-height: 1.5;\n color: #0b1a29;\n box-sizing: border-box;\n}\n\n.yselect__trigger:hover:not(.yselect__trigger--disabled) {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.15);\n}\n\n.yselect__trigger:focus {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.15);\n}\n\n.yselect__trigger--open {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.15);\n}\n\n.yselect__trigger--disabled {\n background: #f9fafb;\n cursor: not-allowed;\n color: #9ca3af;\n}\n\n.yselect__trigger--error {\n border-color: #ef4444;\n}\n\n.yselect__trigger--error:focus {\n border-color: #ef4444;\n box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.15);\n}\n\n.yselect__value {\n flex: 1;\n overflow: hidden;\n color: #0b1a29;\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.yselect__tags {\n display: flex;\n flex-wrap: nowrap;\n gap: 4px;\n align-items: center;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n}\n\n.yselect__tag {\n display: inline-flex;\n align-items: center;\n padding: 2px 6px;\n background: #eff6ff;\n color: #1d4ed8;\n border-radius: 4px;\n font-size: 12px;\n line-height: 1.4;\n max-width: 120px;\n flex-shrink: 1;\n min-width: 0;\n}\n\n.yselect__tag-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-right: 4px;\n}\n\n.yselect__tag-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n cursor: pointer;\n color: #1d4ed8;\n flex-shrink: 0;\n margin-left: 2px;\n}\n\n.yselect__tag-close:hover {\n color: #1e40af;\n}\n\n.yselect__placeholder-text {\n color: #9ca3af;\n}\n\n.yselect__flag {\n width: 14px;\n height: 14px;\n object-fit: cover;\n border-radius: 2px;\n margin-right: 6px;\n}\n\n.yselect__placeholder {\n color: #9ca3af;\n}\n\n.yselect__input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n color: #0b1a29;\n font-size: inherit;\n line-height: 1.5;\n min-width: 0;\n}\n\n.yselect__input::placeholder {\n color: #9ca3af;\n}\n\n.yselect__trigger--disabled .yselect__value {\n color: #9ca3af;\n}\n\n.yselect__arrow {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n color: #6b7280;\n transition: transform 0.2s ease;\n flex-shrink: 0;\n}\n\n.yselect__clear {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n color: #9ca3af;\n margin-left: 6px;\n cursor: pointer;\n}\n\n.yselect__clear:hover {\n color: #6b7280;\n}\n\n.yselect__arrow--open {\n transform: rotate(180deg);\n}\n\n.yselect__dropdown {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n z-index: 1000;\n margin-top: 4px;\n background: #ffffff;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n box-shadow: 0 8px 20px rgba(2, 6, 23, 0.15);\n overflow: hidden;\n}\n\n.yselect__dropdown--top {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 4px;\n}\n\n.yselect__options {\n max-height: 200px;\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.yselect__option {\n display: flex;\n align-items: center;\n height: 36px;\n padding: 0 12px;\n cursor: pointer;\n transition: background-color 0.2s ease, color 0.2s ease;\n font-size: 13px;\n line-height: 1.5;\n color: #0b1a29;\n}\n\n.yselect__option-check {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n margin-right: 8px;\n flex-shrink: 0;\n color: #1d4ed8;\n}\n\n.yselect__option:hover:not(.yselect__option--disabled) {\n background-color: #F6F6F7;\n color: #303061;\n}\n\n.yselect__option--selected {\n background: #eff6ff;\n color: #1d4ed8;\n font-weight: 500;\n}\n\n.yselect__option--selected:hover {\n background: #dbeafe;\n}\n\n.yselect__option--disabled {\n color: #9ca3af;\n cursor: not-allowed;\n background: transparent;\n}\n\n.yselect__option--hover {\n background-color: #F6F6F7;\n color: #303061;\n}\n\n/* 尺寸变体 */\n.yselect--small .yselect__trigger {\n height: 32px;\n padding: 0 10px;\n font-size: 12px;\n border-radius: 6px;\n min-width: 80px;\n}\n\n.yselect--medium .yselect__trigger {\n height: 44px;\n padding: 0 12px;\n font-size: 14px;\n border-radius: 8px;\n min-width: 100px;\n}\n\n.yselect--multiple .yselect__trigger {\n min-height: 44px;\n height: auto;\n padding-top: 4px;\n padding-bottom: 4px;\n}\n\n.yselect--multiple.yselect--small .yselect__trigger {\n min-height: 32px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n\n.yselect--multiple.yselect--large .yselect__trigger {\n min-height: 52px;\n padding-top: 6px;\n padding-bottom: 6px;\n}\n\n.yselect--large .yselect__trigger {\n height: 52px;\n padding: 0 16px;\n font-size: 16px;\n border-radius: 10px;\n min-width: 120px;\n}\n\n/* 过渡动画 */\n.yselect-dropdown-enter-active,\n.yselect-dropdown-leave-active {\n transition: all 0.2s ease;\n transform-origin: top;\n}\n\n.yselect-dropdown-enter-from {\n opacity: 0;\n transform: scaleY(0.8) translateY(-8px);\n}\n\n.yselect-dropdown-leave-to {\n opacity: 0;\n transform: scaleY(0.8) translateY(-8px);\n}\n\n/* 滚动条样式 */\n.yselect__options::-webkit-scrollbar {\n width: 6px;\n}\n\n.yselect__options::-webkit-scrollbar-track {\n background: #f1f5f9;\n}\n\n.yselect__options::-webkit-scrollbar-thumb {\n background: #cbd5e1;\n border-radius: 3px;\n}\n\n.yselect__options::-webkit-scrollbar-thumb:hover {\n background: #94a3b8;\n}\n\n/* 暗色主题支持 */\n@media (prefers-color-scheme: dark) {\n .yselect__trigger {\n background: rgba(2, 6, 23, 0.4);\n border-color: rgba(148, 163, 184, 0.18);\n color: #e5eef7;\n }\n \n .yselect__placeholder {\n color: #9aa6b2;\n }\n \n .yselect__input::placeholder {\n color: #9aa6b2;\n }\n \n .yselect__trigger--disabled {\n background: rgba(2, 6, 23, 0.2);\n color: #9ca3af;\n }\n \n .yselect__value {\n color: #e5eef7;\n }\n \n .yselect__dropdown {\n background: rgba(2, 6, 23, 0.9);\n border-color: rgba(148, 163, 184, 0.18);\n }\n \n .yselect__option {\n color: #e5eef7;\n }\n \n .yselect__option:hover:not(.yselect__option--disabled) {\n background-color: #F6F6F7;\n color: #303061;\n }\n \n .yselect__option--hover {\n background-color: #F6F6F7;\n color: #303061;\n }\n}\n</style>\n","<template>\n <div class=\"ypagination\">\n <div class=\"page-actions\">\n <!-- 上一页按钮 -->\n <YButton\n size=\"small\"\n variant=\"secondary\"\n :disabled=\"currentPage === 1 || loading\"\n @click=\"goToPage(1)\"\n >首页</YButton\n >\n <!-- 在一个 YButton 中生成上一页/下一页组合按钮 -->\n <YButton\n class=\"ml-1\"\n variant=\"secondary\"\n size=\"small\"\n :groupItems=\"[\n { label: '上一页', value: 'prev', disabled: currentPage === 1 || loading, icon: 'chevron-left', onlyIcon: true, ariaLabel: '上一页' },\n { label: '下一页', value: 'next', disabled: loading || disableNext, icon: 'chevron-right', onlyIcon: true, ariaLabel: '下一页' }\n ]\"\n @group-click=\"onPagerGroupClick\"\n />\n\n <!-- 每页条数选择 -->\n <div class=\"page-size-select\">\n <YSelect\n v-model=\"pageSize\"\n :options=\"pageSizeOptions\"\n size=\"small\"\n width=\"105px\"\n :clearable=\"false\"\n :disabled=\"loading\"\n @change=\"handlePageSizeChange\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch } from \"vue\"\n// import type { SelectOption } from \"./YSelect.vue\";\n\nexport interface PaginationProps {\n currentPage: number;\n pageSize: number;\n loading?: boolean;\n pageSizeOptions?: Array<{ label: string; value: number }>;\n disableNext?: boolean; // 是否禁用下一页按钮\n}\n\nconst props = withDefaults(defineProps<PaginationProps>(), {\n loading: false,\n disableNext: false,\n pageSizeOptions: () => [\n { label: \"10/页\", value: 10 },\n { label: \"20/页\", value: 20 },\n { label: \"50/页\", value: 50 },\n { label: \"100/页\", value: 100 },\n ],\n});\n\nconst emit = defineEmits<{\n \"update:currentPage\": [page: number];\n \"update:pageSize\": [size: number];\n \"page-change\": [page: number];\n \"page-size-change\": [size: number];\n}>();\n\n// 响应式数据\nconst pageSize = ref(props.pageSize);\n\n// 每页条数选项\nconst pageSizeOptions = computed(() => props.pageSizeOptions);\n\n// 计算属性\n// 简化:不再计算总页数与页码列表\n\n// 使用计算属性来获取当前页,支持双向绑定\nconst currentPage = computed({\n get: () => props.currentPage,\n set: (value) => {\n emit(\"update:currentPage\", value);\n emit(\"page-change\", value);\n },\n});\n\n// 方法\nfunction goToPage(page: number) {\n if (props.loading) return;\n if (page >= 1 && page !== props.currentPage) {\n currentPage.value = page;\n }\n}\n\nfunction handlePageSizeChange(value: number) {\n if (props.loading) return; // loading 时不允许切换每页条数\n pageSize.value = value;\n emit(\"update:pageSize\", value);\n emit(\"page-size-change\", value);\n // 切换每页条数后,重置到第一页\n currentPage.value = 1;\n}\n\nfunction onPagerGroupClick(action?: string | number) {\n if (props.loading) return;\n if (action === 'prev') {\n goToPage(currentPage.value - 1);\n } else if (action === 'next') {\n goToPage(currentPage.value + 1);\n }\n}\n\n// 同步外部 pageSize\n// (不再根据 totalPages 回调修正 currentPage)\n// 外部如需限制页码由父组件控制\npageSize.value = props.pageSize;\n\n// 监听父组件变更以同步内部状态(确保选中项更新)\nwatch(\n () => props.pageSize,\n (val) => {\n if (typeof val === 'number' && pageSize.value !== val) {\n pageSize.value = val;\n }\n }\n);\n</script>\n\n<style scoped lang=\"less\">\n.ypagination {\n border-top: 1px solid #E6ECF2;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 10px 2px;\n gap: 12px;\n width: 100%;\n box-sizing: border-box;\n}\n\n.page-info {\n font-size: 14px;\n color: #666;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.page-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-shrink: 0;\n min-width: 0;\n}\n\n.btn-group {\n display: inline-flex;\n}\n\n.page-numbers {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-shrink: 0;\n min-width: 0;\n}\n\n.btn {\n height: 28px;\n padding: 0 6px;\n border-radius: 8px;\n border: 1px solid #ddd;\n background: #fff;\n cursor: pointer;\n font-size: 12px;\n transition: all 0.2s ease;\n white-space: nowrap;\n flex-shrink: 0;\n min-width: auto;\n}\n\n.btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn:hover:not(:disabled) {\n border-color: #999;\n background: #f8f8f8;\n}\n\n.page-btn {\n min-width: 28px;\n height: 28px;\n padding: 0 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 12px;\n}\n\n.page-btn.active {\n background: #474747;\n color: #fff;\n border-color: #474747;\n}\n\n.page-btn.active:hover {\n background: #121820;\n border-color: #121820;\n}\n\n.ellipsis {\n padding: 0 2px;\n color: #999;\n font-size: 12px;\n user-select: none;\n min-width: 12px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.page-size-select {\n flex-shrink: 0;\n min-width: 75px;\n margin-left: 25px;\n}\n\n/* 响应式设计 */\n@media (max-width: 768px) {\n .ypagination {\n flex-direction: column;\n gap: 8px;\n align-items: stretch;\n }\n\n .page-info {\n text-align: center;\n }\n\n .page-actions {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .page-numbers {\n order: 1;\n justify-content: center;\n }\n\n .btn:first-child,\n .btn:last-child {\n order: 2;\n }\n\n .select {\n order: 3;\n }\n}\n\n@media (max-width: 480px) {\n .page-numbers {\n gap: 2px;\n }\n\n .page-btn {\n min-width: 28px;\n height: 26px;\n padding: 0 6px;\n font-size: 12px;\n }\n\n .btn {\n height: 26px;\n padding: 0 8px;\n font-size: 12px;\n }\n\n .select {\n height: 26px;\n font-size: 12px;\n }\n}\n</style>\n","<template>\r\n <span\r\n class=\"y-badge\"\r\n :class=\"[\r\n `y-badge--${toneClass}`,\r\n `y-badge--${size}`,\r\n { 'is-outline': outline, 'is-pill': pill },\r\n progress ? `y-badge--progress-${progress}` : ''\r\n ]\"\r\n role=\"status\"\r\n :aria-label=\"ariaLabel\"\r\n >\r\n <span class=\"y-badge__inner\">\r\n <!-- 进度/图标优先渲染 -->\r\n <span v-if=\"progress\" class=\"y-badge__progress\" aria-hidden=\"true\">\r\n <svg v-if=\"progress === 'incomplete'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <circle cx=\"10\" cy=\"10\" r=\"5\" />\r\n </svg>\r\n <svg v-else-if=\"progress === 'partiallyComplete'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path d=\"M10 5a5 5 0 100 10V5z\" />\r\n <circle cx=\"10\" cy=\"10\" r=\"5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" />\r\n </svg>\r\n <svg v-else-if=\"progress === 'complete'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path fill-rule=\"evenodd\" d=\"M16.707 5.293a1 1 0 010 1.414l-7.25 7.25a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L8.75 11.086l6.543-6.543a1 1 0 011.414 0z\" clip-rule=\"evenodd\" />\r\n </svg>\r\n </span>\r\n\r\n <span v-else-if=\"icon\" class=\"y-badge__icon\" aria-hidden=\"true\">\r\n <svg v-if=\"icon === 'dot'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><circle cx=\"10\" cy=\"10\" r=\"4\"/></svg>\r\n <svg v-else-if=\"icon === 'check'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M16.707 5.293a1 1 0 010 1.414l-7.25 7.25a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L8.75 11.086l6.543-6.543a1 1 0 011.414 0z\" clip-rule=\"evenodd\" /></svg>\r\n <svg v-else-if=\"icon === 'alert'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.721-1.36 3.486 0l6.518 11.59c.75 1.334-.214 3.011-1.743 3.011H3.482c-1.53 0-2.493-1.677-1.743-3.01L8.257 3.1zM11 14a1 1 0 10-2 0 1 1 0 002 0zm-1-2a1 1 0 01-1-1V8a1 1 0 112 0v3a1 1 0 01-1 1z\" clip-rule=\"evenodd\"/></svg>\r\n <svg v-else class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><circle cx=\"10\" cy=\"10\" r=\"4\"/></svg>\r\n </span>\r\n\r\n <span class=\"y-badge__label\"><slot>{{ label }}</slot></span>\r\n </span>\r\n </span>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from 'vue'\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 视觉语气 */\r\n tone?: 'default' | 'informational' | 'success' | 'attention' | 'warning' | 'critical'\r\n /** 尺寸 */\r\n size?: 'small' | 'medium'\r\n /** 进度状态(与 icon 互斥,优先级更高) */\r\n progress?: 'incomplete' | 'partiallyComplete' | 'complete'\r\n /** 内置图标:dot | check | alert | placeholder(string 亦以 dot 代替) */\r\n icon?: 'dot' | 'check' | 'alert' | 'placeholder' | string | undefined\r\n /** 是否圆角胶囊 */\r\n pill?: boolean\r\n /** 描边样式(浅背景 + 边框) */\r\n outline?: boolean\r\n /** 文本标签(未提供 slot 时兜底) */\r\n label?: string\r\n}>(), {\r\n tone: 'default',\r\n size: 'medium',\r\n progress: undefined,\r\n icon: undefined,\r\n pill: true,\r\n outline: false,\r\n label: ''\r\n})\r\n\r\nconst toneClass = computed(() => props.tone || 'default')\r\n\r\nconst ariaLabel = computed(() => {\r\n const text = (props.label || '').trim()\r\n const tone = props.tone\r\n const prog = props.progress\r\n if (prog) {\r\n const progMap: Record<string, string> = {\r\n incomplete: '未完成',\r\n partiallyComplete: '部分完成',\r\n complete: '已完成',\r\n }\r\n return text ? `${text},进度:${progMap[prog] || prog}` : `进度:${progMap[prog] || prog}`\r\n }\r\n if (tone && tone !== 'default') {\r\n const toneMap: Record<string, string> = {\r\n informational: '信息',\r\n success: '成功',\r\n attention: '注意',\r\n warning: '警告',\r\n critical: '严重',\r\n default: '默认'\r\n }\r\n return text ? `${text},语气:${toneMap[tone] || tone}` : `语气:${toneMap[tone] || tone}`\r\n }\r\n return text || '标记'\r\n})\r\n</script>\r\n\r\n<style scoped>\r\n.y-badge {\r\n display: inline-flex;\r\n vertical-align: middle;\r\n line-height: 1;\r\n}\r\n\r\n.y-badge__inner {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n border: 1px solid transparent;\r\n border-radius: 6px;\r\n padding: 2px 8px;\r\n font-weight: 600;\r\n font-size: 12px;\r\n color: #111827;\r\n background-color: #f3f4f6;\r\n}\r\n\r\n/* 尺寸 */\r\n.y-badge--small .y-badge__inner { padding: 1px 6px; font-size: 11px; border-radius: 6px; }\r\n.y-badge--medium .y-badge__inner { padding: 3px 10px; font-size: 12px; border-radius: 8px; }\r\n\r\n/* 胶囊圆角 */\r\n.is-pill .y-badge__inner { border-radius: 9999px; }\r\n\r\n/* 图标与进度图标统一尺寸 */\r\n.y-badge .icon { width: 12px; height: 12px; }\r\n\r\n/* 语气色板(尽量贴近 Polaris 感觉) */\r\n/* default */\r\n.y-badge--default .y-badge__inner { color: #374151; background-color: #F3F4F6; border-color: transparent; }\r\n.is-outline.y-badge--default .y-badge__inner { background-color: #fff; color: #374151; border-color: #E5E7EB; }\r\n\r\n/* informational */\r\n.y-badge--informational .y-badge__inner { color: #0b5394; background-color: #eaf3ff; }\r\n.is-outline.y-badge--informational .y-badge__inner { background-color: #fff; color: #0b5394; border-color: #b3d4ff; }\r\n\r\n/* success */\r\n.y-badge--success .y-badge__inner { color: #006c4f; background-color: #e7f5f0; }\r\n.is-outline.y-badge--success .y-badge__inner { background-color: #fff; color: #006c4f; border-color: #a8e0cf; }\r\n\r\n/* attention(信息但强调) */\r\n.y-badge--attention .y-badge__inner { color: #5b3a00; background-color: #fff3cd; }\r\n.is-outline.y-badge--attention .y-badge__inner { background-color: #fff; color: #5b3a00; border-color: #ffe69c; }\r\n\r\n/* warning */\r\n.y-badge--warning .y-badge__inner { color: #7a4400; background-color: #fdecc8; }\r\n.is-outline.y-badge--warning .y-badge__inner { background-color: #fff; color: #7a4400; border-color: #fbd38d; }\r\n\r\n/* critical */\r\n.y-badge--critical .y-badge__inner { color: #9b1c1c; background-color: #fde8e8; }\r\n.is-outline.y-badge--critical .y-badge__inner { background-color: #fff; color: #9b1c1c; border-color: #f5b5b5; }\r\n\r\n/* 进度类修饰,主要影响图标颜色与对比度(背景跟随 tone) */\r\n.y-badge__progress .icon { opacity: 0.9; }\r\n\r\n/* 深色模式粗略处理 */\r\n@media (prefers-color-scheme: dark) {\r\n .y-badge__inner { color: #e5eef7; background-color: rgba(2, 6, 23, 0.4); border-color: rgba(148, 163, 184, 0.18); }\r\n .y-badge--default .y-badge__inner { color: #e5eef7; background-color: rgba(2, 6, 23, 0.4); }\r\n .is-outline .y-badge__inner { background-color: transparent; }\r\n\r\n .y-badge--informational .y-badge__inner { color: #b7d4ff; background-color: rgba(30, 64, 175, 0.3); border-color: rgba(96, 165, 250, 0.35); }\r\n .y-badge--success .y-badge__inner { color: #b7f0da; background-color: rgba(2, 44, 34, 0.4); border-color: rgba(45, 212, 191, 0.35); }\r\n .y-badge--attention .y-badge__inner { color: #ffe3a3; background-color: rgba(120, 53, 15, 0.35); border-color: rgba(251, 191, 36, 0.35); }\r\n .y-badge--warning .y-badge__inner { color: #ffd9a3; background-color: rgba(120, 53, 15, 0.35); border-color: rgba(251, 191, 36, 0.35); }\r\n .y-badge--critical .y-badge__inner { color: #ffc3c3; background-color: rgba(127, 29, 29, 0.35); border-color: rgba(248, 113, 113, 0.35); }\r\n}\r\n</style>\r\n","<template>\n <teleport to=\"body\">\n <div\n v-show=\"visible\"\n class=\"y-dialog-root\"\n role=\"dialog\"\n :aria-modal=\"true\"\n :aria-hidden=\"!visible\"\n :style=\"{ zIndex: String(zIndex) }\"\n >\n <div\n class=\"y-dialog-mask\"\n @click=\"onMaskClick\"\n ></div>\n\n <transition name=\"dialog-zoom-fade\">\n <div\n v-show=\"visible\"\n ref=\"panelRef\"\n class=\"y-dialog-panel\"\n :class=\"[ center ? 'is-center' : '' ]\"\n :style=\"panelStyle\"\n @keydown.esc.prevent.stop=\"onEsc\"\n tabindex=\"-1\"\n >\n <div v-if=\"showHeader\" class=\"y-dialog-header\">\n <slot name=\"header\">\n <div class=\"y-dialog-title\">{{ title }}</div>\n </slot>\n <button\n v-if=\"closable\"\n type=\"button\"\n class=\"y-dialog-close\"\n aria-label=\"Close\"\n @click=\"close\"\n >\n ✕\n </button>\n </div>\n\n <div class=\"y-dialog-body\">\n <slot />\n </div>\n\n <div v-if=\"$slots.footer\" class=\"y-dialog-footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </transition>\n </div>\n </teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue'\n\nconst props = withDefaults(defineProps<{\n modelValue?: boolean\n title?: string\n width?: string | number\n top?: string\n closable?: boolean\n maskClosable?: boolean\n zIndex?: number\n showHeader?: boolean\n center?: boolean\n}>(), {\n modelValue: false,\n title: '',\n width: '520px',\n top: '15vh',\n closable: true,\n maskClosable: true,\n zIndex: 3000,\n showHeader: true,\n center: false,\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n (e: 'open'): void\n (e: 'close'): void\n}>()\n\nconst visible = computed({\n get: () => props.modelValue,\n set: (v: boolean) => emit('update:modelValue', v),\n})\n\nconst panelRef = ref<HTMLElement | null>(null)\n\nconst panelStyle = computed(() => {\n const style: Record<string, string> = {}\n style.width = typeof props.width === 'number' ? `${props.width}px` : String(props.width)\n style.margin = '0 auto'\n style.top = props.top\n return style\n})\n\nfunction onMaskClick() {\n if (!props.maskClosable) return\n close()\n}\n\nfunction close() {\n if (!visible.value) return\n visible.value = false\n emit('close')\n}\n\nfunction onEsc() {\n if (props.closable) close()\n}\n\nfunction onKeydown(e: KeyboardEvent) {\n if (e.key === 'Escape') onEsc()\n}\n\nwatch(() => props.modelValue, (v) => {\n if (v) {\n emit('open')\n requestAnimationFrame(() => panelRef.value?.focus())\n document.addEventListener('keydown', onKeydown)\n document.body.style.overflow = 'hidden'\n } else {\n document.removeEventListener('keydown', onKeydown)\n document.body.style.overflow = ''\n }\n})\n\nonMounted(() => {\n if (props.modelValue) {\n document.addEventListener('keydown', onKeydown)\n document.body.style.overflow = 'hidden'\n }\n})\n\nonUnmounted(() => {\n document.removeEventListener('keydown', onKeydown)\n document.body.style.overflow = ''\n})\n</script>\n\n<style scoped lang=\"less\">\n.y-dialog-root {\n position: fixed;\n inset: 0;\n}\n\n.y-dialog-mask {\n position: absolute;\n inset: 0;\n background: rgba(2, 6, 23, 0.55);\n backdrop-filter: blur(2px);\n}\n\n.y-dialog-panel {\n position: relative;\n background: #ffffff;\n border-radius: 12px;\n border: 1px solid rgba(15, 23, 42, 0.06);\n box-shadow: 0 12px 40px rgba(2, 6, 23, 0.18);\n}\n\n.y-dialog-panel.is-center .y-dialog-title { text-align: center; width: 100%; }\n\n.y-dialog-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 16px;\n border-bottom: 1px solid rgba(15, 23, 42, 0.06);\n}\n\n.y-dialog-title {\n font-size: 16px;\n font-weight: 600;\n color: #0b1a29;\n}\n\n.y-dialog-close {\n appearance: none;\n border: none;\n background: transparent;\n color: #334155;\n font-size: 16px;\n line-height: 1;\n cursor: pointer;\n padding: 6px;\n border-radius: 8px;\n}\n.y-dialog-close:hover { background: rgba(15,23,42,0.05); }\n\n.y-dialog-body {\n padding: 16px;\n max-height: calc(85vh - 110px);\n overflow: auto;\n}\n\n.y-dialog-footer {\n padding: 12px 16px;\n border-top: 1px solid rgba(15, 23, 42, 0.06);\n}\n\n/* 进入/离场动画:缩放淡入 */\n.dialog-zoom-fade-enter-from,\n.dialog-zoom-fade-leave-to { transform: scale(0.96); opacity: 0; }\n.dialog-zoom-fade-enter-active,\n.dialog-zoom-fade-leave-active { transition: transform 200ms cubic-bezier(0.2, 0.6, 0.4, 1), opacity 200ms cubic-bezier(0.2, 0.6, 0.4, 1); }\n.dialog-zoom-fade-enter-to,\n.dialog-zoom-fade-leave-from { transform: scale(1); opacity: 1; }\n\n@media (prefers-color-scheme: dark) {\n .y-dialog-panel {\n background: rgba(15, 23, 42, 0.7);\n border-color: rgba(148, 163, 184, 0.12);\n box-shadow: 0 12px 40px rgba(2, 6, 23, 0.5);\n }\n .y-dialog-title { color: #e5eef7; }\n .y-dialog-close { color: #cbd5e1; }\n .y-dialog-close:hover { background: rgba(148,163,184,0.12); }\n}\n</style>\n\n\n","<template>\n <div class=\"ypopover\" ref=\"popoverRef\">\n <!-- 触发器 -->\n <div \n ref=\"triggerRef\"\n @click=\"handleTriggerClick\"\n @mouseenter=\"handleMouseEnter\"\n @mouseleave=\"handleMouseLeave\"\n >\n <slot name=\"reference\"></slot>\n </div>\n \n <!-- 弹出内容 -->\n <Teleport to=\"body\">\n <Transition name=\"ypopover-fade\">\n <div\n v-if=\"visible\"\n ref=\"contentRef\"\n class=\"ypopover__content\"\n :class=\"[\n `ypopover__content--${placement}`,\n {\n 'ypopover__content--dark': dark,\n 'ypopover__content--no-padding': !showPadding\n }\n ]\"\n :style=\"contentStyle\"\n @click.stop\n @mouseenter=\"handleContentMouseEnter\"\n @mouseleave=\"handleContentMouseLeave\"\n >\n <!-- 箭头 -->\n <div \n v-if=\"showArrow\"\n class=\"ypopover__arrow\"\n :class=\"`ypopover__arrow--${placement}`\"\n :style=\"arrowStyle\"\n ></div>\n \n <!-- 内容 -->\n <div class=\"ypopover__inner\">\n <slot></slot>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue'\n\ninterface Props {\n // 触发方式\n trigger?: 'click' | 'hover' | 'focus' | 'manual'\n // 弹出位置\n placement?: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end'\n // 是否显示箭头\n showArrow?: boolean\n // 是否显示内边距\n showPadding?: boolean\n // 是否深色主题\n dark?: boolean\n // 是否禁用\n disabled?: boolean\n // 延迟显示时间(hover模式)\n openDelay?: number\n // 延迟隐藏时间(hover模式)\n closeDelay?: number\n // 是否点击外部关闭\n closeOnClickOutside?: boolean\n // 是否点击内容关闭\n closeOnClickContent?: boolean\n // 弹出框宽度\n width?: string | number\n // 弹出框最大宽度\n maxWidth?: string | number\n // 弹出框偏移量\n offset?: number\n // 手动控制显示状态\n modelValue?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n trigger: 'click',\n placement: 'bottom',\n showArrow: true,\n showPadding: true,\n dark: false,\n disabled: false,\n openDelay: 0,\n closeDelay: 200,\n closeOnClickOutside: true,\n closeOnClickContent: false,\n width: 'auto',\n maxWidth: '300px',\n offset: 8,\n modelValue: false\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n 'show': []\n 'hide': []\n 'before-show': []\n 'before-hide': []\n}>()\n\n// 响应式数据\nconst popoverRef = ref<HTMLElement>()\nconst triggerRef = ref<HTMLElement>()\nconst contentRef = ref<HTMLElement>()\nconst visible = ref(false)\nconst triggerRect = ref<DOMRect>()\nconst contentRect = ref<DOMRect>()\nconst arrowPosition = ref<Record<string, string>>({})\n\n// 定时器\nlet openTimer: number | null = null\nlet closeTimer: number | null = null\n\n// 计算属性\nconst contentStyle = computed(() => {\n if (!visible.value || !triggerRect.value) return {}\n \n const style: Record<string, string> = {}\n \n // 设置宽度\n if (props.width !== 'auto') {\n style.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n \n // 设置最大宽度\n if (props.maxWidth) {\n style.maxWidth = typeof props.maxWidth === 'number' ? `${props.maxWidth}px` : props.maxWidth\n }\n \n // 计算位置\n const { top, left } = calculatePosition()\n style.top = `${top}px`\n style.left = `${left}px`\n \n return style\n})\n\nconst arrowStyle = computed(() => {\n if (!props.showArrow) return {}\n \n // 返回计算好的箭头位置,如果没有则使用默认居中\n if (Object.keys(arrowPosition.value).length > 0) {\n return arrowPosition.value\n }\n \n // 默认居中位置\n const style: Record<string, string> = {}\n if (props.placement.startsWith('top') || props.placement.startsWith('bottom')) {\n style.left = '50%'\n } else {\n style.top = '50%'\n }\n return style\n})\n\n// 计算弹出框位置\nfunction calculatePosition() {\n if (!triggerRect.value) return { top: 0, left: 0 }\n \n const { width: triggerWidth, height: triggerHeight, top: triggerTop, left: triggerLeft } = triggerRect.value\n const contentWidth = contentRef.value?.offsetWidth || 200\n const contentHeight = contentRef.value?.offsetHeight || 100\n \n let top = 0\n let left = 0\n \n switch (props.placement) {\n case 'top':\n top = triggerTop - contentHeight - props.offset\n left = triggerLeft + (triggerWidth - contentWidth) / 2\n break\n case 'top-start':\n top = triggerTop - contentHeight - props.offset\n left = triggerLeft\n break\n case 'top-end':\n top = triggerTop - contentHeight - props.offset\n left = triggerLeft + triggerWidth - contentWidth\n break\n case 'bottom':\n top = triggerTop + triggerHeight + props.offset\n left = triggerLeft + (triggerWidth - contentWidth) / 2\n break\n case 'bottom-start':\n top = triggerTop + triggerHeight + props.offset\n left = triggerLeft\n break\n case 'bottom-end':\n top = triggerTop + triggerHeight + props.offset\n left = triggerLeft + triggerWidth - contentWidth\n break\n case 'left':\n top = triggerTop + (triggerHeight - contentHeight) / 2\n left = triggerLeft - contentWidth - props.offset\n break\n case 'left-start':\n top = triggerTop\n left = triggerLeft - contentWidth - props.offset\n break\n case 'left-end':\n top = triggerTop + triggerHeight - contentHeight\n left = triggerLeft - contentWidth - props.offset\n break\n case 'right':\n top = triggerTop + (triggerHeight - contentHeight) / 2\n left = triggerLeft + triggerWidth + props.offset\n break\n case 'right-start':\n top = triggerTop\n left = triggerLeft + triggerWidth + props.offset\n break\n case 'right-end':\n top = triggerTop + triggerHeight - contentHeight\n left = triggerLeft + triggerWidth + props.offset\n break\n }\n \n // 边界检测\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n \n // 水平边界检测\n if (left < 8) left = 8\n if (left + contentWidth > viewportWidth - 8) {\n left = viewportWidth - contentWidth - 8\n }\n \n // 垂直边界检测\n if (top < 8) top = 8\n if (top + contentHeight > viewportHeight - 8) {\n top = viewportHeight - contentHeight - 8\n }\n \n return { top, left }\n}\n\n// 显示弹出框\nfunction show() {\n if (props.disabled || visible.value) return\n \n clearTimers()\n \n if (props.openDelay > 0) {\n openTimer = setTimeout(() => {\n doShow()\n }, props.openDelay)\n } else {\n doShow()\n }\n}\n\nfunction doShow() {\n emit('before-show')\n visible.value = true\n emit('update:modelValue', true)\n emit('show')\n \n // 使用双重 nextTick 确保 DOM 完全更新\n nextTick(() => {\n nextTick(() => {\n updatePosition()\n })\n })\n}\n\n// 隐藏弹出框\nfunction hide() {\n if (!visible.value) return\n \n clearTimers()\n \n if (props.closeDelay > 0) {\n closeTimer = setTimeout(() => {\n doHide()\n }, props.closeDelay)\n } else {\n doHide()\n }\n}\n\nfunction doHide() {\n emit('before-hide')\n visible.value = false\n emit('update:modelValue', false)\n emit('hide')\n}\n\n// 清除定时器\nfunction clearTimers() {\n if (openTimer) {\n clearTimeout(openTimer)\n openTimer = null\n }\n if (closeTimer) {\n clearTimeout(closeTimer)\n closeTimer = null\n }\n}\n\n// 计算箭头位置\nfunction calculateArrowPosition() {\n if (!props.showArrow || !triggerRect.value || !contentRef.value) {\n arrowPosition.value = {}\n return\n }\n \n const trigger = triggerRect.value\n const contentRect = contentRef.value.getBoundingClientRect()\n \n // 如果弹出框还没有正确的尺寸,使用默认居中\n if (contentRect.width === 0 || contentRect.height === 0) {\n const style: Record<string, string> = {}\n if (props.placement.startsWith('top') || props.placement.startsWith('bottom')) {\n style.left = '50%'\n } else {\n style.top = '50%'\n }\n arrowPosition.value = style\n return\n }\n \n const style: Record<string, string> = {}\n \n // 根据位置计算箭头位置\n if (props.placement.startsWith('top')) {\n style.bottom = '-6px'\n // 水平居中\n const triggerCenterX = trigger.left + trigger.width / 2\n const contentLeft = contentRect.left\n const arrowOffset = triggerCenterX - contentLeft\n style.left = `${Math.max(12, Math.min(arrowOffset, contentRect.width - 12))}px`\n } else if (props.placement.startsWith('bottom')) {\n style.top = '-6px'\n // 水平居中\n const triggerCenterX = trigger.left + trigger.width / 2\n const contentLeft = contentRect.left\n const arrowOffset = triggerCenterX - contentLeft\n style.left = `${Math.max(12, Math.min(arrowOffset, contentRect.width - 12))}px`\n } else if (props.placement.startsWith('left')) {\n style.right = '-6px'\n // 垂直居中\n const triggerCenterY = trigger.top + trigger.height / 2\n const contentTop = contentRect.top\n const arrowOffset = triggerCenterY - contentTop\n style.top = `${Math.max(12, Math.min(arrowOffset, contentRect.height - 12))}px`\n } else if (props.placement.startsWith('right')) {\n style.left = '-6px'\n // 垂直居中\n const triggerCenterY = trigger.top + trigger.height / 2\n const contentTop = contentRect.top\n const arrowOffset = triggerCenterY - contentTop\n style.top = `${Math.max(12, Math.min(arrowOffset, contentRect.height - 12))}px`\n }\n \n arrowPosition.value = style\n}\n\n// 更新位置\nfunction updatePosition() {\n if (!triggerRef.value) return\n \n triggerRect.value = triggerRef.value.getBoundingClientRect()\n \n if (contentRef.value) {\n contentRect.value = contentRef.value.getBoundingClientRect()\n \n // 计算箭头位置\n calculateArrowPosition()\n \n // 如果弹出框刚显示,使用 requestAnimationFrame 确保位置正确\n if (visible.value) {\n requestAnimationFrame(() => {\n if (contentRef.value) {\n contentRect.value = contentRef.value.getBoundingClientRect()\n calculateArrowPosition()\n }\n })\n }\n }\n}\n\n// 事件处理\nfunction handleTriggerClick() {\n if (props.disabled) return\n \n if (props.trigger === 'click') {\n if (visible.value) {\n hide()\n } else {\n show()\n }\n }\n}\n\nfunction handleMouseEnter() {\n if (props.disabled || props.trigger !== 'hover') return\n \n clearTimers()\n show()\n}\n\nfunction handleMouseLeave() {\n if (props.disabled || props.trigger !== 'hover') return\n \n hide()\n}\n\n// 鼠标进入弹出框内容\nfunction handleContentMouseEnter() {\n if (props.disabled || props.trigger !== 'hover') return\n \n clearTimers()\n}\n\n// 鼠标离开弹出框内容\nfunction handleContentMouseLeave() {\n if (props.disabled || props.trigger !== 'hover') return\n \n hide()\n}\n\n// 点击外部关闭\nfunction handleClickOutside(event: MouseEvent) {\n if (!props.closeOnClickOutside || !visible.value) return\n \n const target = event.target as HTMLElement\n if (\n popoverRef.value &&\n !popoverRef.value.contains(target) &&\n contentRef.value &&\n !contentRef.value.contains(target)\n ) {\n hide()\n }\n}\n\n// 点击内容关闭\n// function handleContentClick() {\n// if (props.closeOnClickContent) {\n// hide()\n// }\n// }\n\n// 监听 modelValue 变化\nwatch(() => props.modelValue, (newVal) => {\n if (newVal !== visible.value) {\n if (newVal) {\n show()\n } else {\n hide()\n }\n }\n})\n\n// 监听 visible 变化\nwatch(visible, (newVal) => {\n if (newVal) {\n document.addEventListener('click', handleClickOutside)\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition, true)\n\n // 初次显示时可能由于 Teleport 尚未完成渲染导致定位不准确,这里增加多次异步更新保证贴边自适应\n nextTick(() => {\n updatePosition()\n requestAnimationFrame(() => {\n updatePosition()\n })\n setTimeout(() => {\n updatePosition()\n }, 0)\n })\n } else {\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n }\n})\n\n// 生命周期\nonMounted(() => {\n if (props.modelValue) {\n show()\n }\n})\n\nonUnmounted(() => {\n clearTimers()\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n})\n\n// 暴露方法\ndefineExpose({\n show,\n hide,\n updatePosition\n})\n</script>\n\n<style scoped lang=\"less\">\n.ypopover {\n display: inline-block;\n}\n\n.ypopover__content {\n position: fixed;\n z-index: 2000;\n background: #ffffff;\n border: 1px solid #e4e7ed;\n border-radius: 4px;\n box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);\n word-wrap: break-word;\n max-width: 300px;\n}\n\n.ypopover__content--dark {\n background: #303133;\n border-color: #303133;\n color: #ffffff;\n}\n\n.ypopover__content--no-padding .ypopover__inner {\n padding: 0;\n}\n\n.ypopover__inner {\n padding: 8px 12px;\n font-size: 14px;\n line-height: 1.4;\n color: #606266;\n}\n\n.ypopover__content--dark .ypopover__inner {\n color: #ffffff;\n}\n\n// 滚动条样式优化\n.ypopover__content,\n.ypopover__inner {\n &::-webkit-scrollbar {\n width: 4px;\n height: 4px;\n }\n\n &::-webkit-scrollbar-track {\n background: transparent;\n border-radius: 2px;\n }\n\n &::-webkit-scrollbar-thumb {\n background: #E7E7E7;\n border-radius: 2px;\n transition: background 0.2s;\n\n &:hover {\n background: #D0D0D0;\n }\n }\n}\n\n.ypopover__content--dark {\n &::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n\n &:hover {\n background: rgba(255, 255, 255, 0.4);\n }\n }\n}\n\n// 穿透样式,应用到 slot 内容中的滚动元素\n:deep(*) {\n &::-webkit-scrollbar {\n width: 4px;\n height: 4px;\n }\n\n &::-webkit-scrollbar-track {\n background: transparent;\n border-radius: 2px;\n }\n\n &::-webkit-scrollbar-thumb {\n background: #E7E7E7;\n border-radius: 2px;\n transition: background 0.2s;\n\n &:hover {\n background: #D0D0D0;\n }\n }\n}\n\n.ypopover__content--dark :deep(*) {\n &::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n\n &:hover {\n background: rgba(255, 255, 255, 0.4);\n }\n }\n}\n\n.ypopover__arrow {\n position: absolute;\n width: 0;\n height: 0;\n border: 6px solid transparent;\n}\n\n.ypopover__arrow--top {\n border-top-color: #e4e7ed;\n border-bottom: none;\n transform: translateX(-50%);\n}\n\n.ypopover__arrow--top::after {\n content: '';\n position: absolute;\n top: -5px;\n left: -6px;\n border: 6px solid transparent;\n border-top-color: #ffffff;\n border-bottom: none;\n}\n\n.ypopover__arrow--bottom {\n border-bottom-color: #e4e7ed;\n border-top: none;\n transform: translateX(-50%);\n}\n\n.ypopover__arrow--bottom::after {\n content: '';\n position: absolute;\n bottom: -5px;\n left: -6px;\n border: 6px solid transparent;\n border-bottom-color: #ffffff;\n border-top: none;\n}\n\n.ypopover__arrow--left {\n border-left-color: #e4e7ed;\n border-right: none;\n transform: translateY(-50%);\n}\n\n.ypopover__arrow--left::after {\n content: '';\n position: absolute;\n left: -5px;\n top: -6px;\n border: 6px solid transparent;\n border-left-color: #ffffff;\n border-right: none;\n}\n\n.ypopover__arrow--right {\n border-right-color: #e4e7ed;\n border-left: none;\n transform: translateY(-50%);\n}\n\n.ypopover__arrow--right::after {\n content: '';\n position: absolute;\n right: -5px;\n top: -6px;\n border: 6px solid transparent;\n border-right-color: #ffffff;\n border-left: none;\n}\n\n// 深色主题箭头\n.ypopover__content--dark .ypopover__arrow--top {\n border-top-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--top::after {\n border-top-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--bottom {\n border-bottom-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--bottom::after {\n border-bottom-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--left {\n border-left-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--left::after {\n border-left-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--right {\n border-right-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--right::after {\n border-right-color: #303133;\n}\n\n// 过渡动画\n.ypopover-fade-enter-active,\n.ypopover-fade-leave-active {\n transition: opacity 0.2s ease;\n}\n\n.ypopover-fade-enter-from,\n.ypopover-fade-leave-to {\n opacity: 0;\n}\n</style>\n","<template>\n <div class=\"nh-time-search\" :class=\"[`nh-time--${size}`]\">\n <!-- 主要输入区域 -->\n <div class=\"relative\">\n <div\n ref=\"trigger\"\n @click=\"toggleDropdown\"\n @keydown=\"handleTriggerKeydown\"\n :class=\"['nh-time-trigger', { 'is-focus': isOpen, 'has-value': hasValue }]\"\n tabindex=\"0\"\n >\n <input\n readonly\n :value=\"displayText\"\n :placeholder=\"placeholder\"\n class=\"nh-time-input\"\n />\n <span class=\"nh-time-suffix\">\n <i \n v-if=\"clearable && hasValue\" \n @click.stop=\"handleClearClick\"\n class=\"nh-time-clear\"\n >\n <svg viewBox=\"0 0 1024 1024\" width=\"14\" height=\"14\">\n <path d=\"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1 1.9-11.2c1.5-1.2 3.3-1.9 5.2-1.9l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130.1 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z\" fill=\"currentColor\"/>\n </svg>\n </i>\n \n <i class=\"nh-time-icon\">\n <svg viewBox=\"0 0 1024 1024\" width=\"14\" height=\"14\">\n <path d=\"M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zM648 248v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h112v120H152V248h112v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h312zm184 584H192V424h640v408z\" fill=\"currentColor\"/>\n </svg>\n </i>\n \n <i class=\"nh-time-arrow\" :class=\"{ 'is-reverse': isOpen }\">\n <svg viewBox=\"0 0 1024 1024\" width=\"12\" height=\"12\">\n <path d=\"M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3 0.1-12.7-6.4-12.7z\" fill=\"currentColor\"/>\n </svg>\n </i>\n </span>\n </div>\n\n <!-- 下拉面板 -->\n <transition name=\"el-zoom-in-top\">\n <div\n v-if=\"isOpen\"\n ref=\"dropdown\"\n :class=\"dropdownClasses\"\n @keydown=\"handleDropdownKeydown\"\n >\n <!-- 快捷选项 -->\n <div class=\"nh-time-shortcuts\">\n <div class=\"nh-time-shortcuts-title\">快捷选项</div>\n <ul class=\"nh-time-shortcuts-list\">\n <li\n v-for=\"(shortcut, index) in shortcuts\"\n :key=\"shortcut.label\"\n @click=\"selectShortcut(shortcut)\"\n @keydown=\"handleShortcutKeydown($event, index)\"\n @mouseenter=\"handleShortcutMouseEnter(index)\"\n @mouseleave=\"handleShortcutMouseLeave\"\n :class=\"[\n 'nh-time-shortcut', \n { \n 'is-active': activeShortcutIndex === index,\n 'is-selected': selectedShortcutIndex === index\n }\n ]\"\n tabindex=\"0\"\n >\n {{ shortcut.label }}\n </li>\n </ul>\n </div>\n\n <!-- 自定义时间选择 -->\n <div class=\"nh-time-custom\">\n <div class=\"nh-time-custom-header\">\n <span>自定义时间</span>\n <!-- 新增:选择状态提示 -->\n <div class=\"nh-time-selection-status\">\n <span v-if=\"!tempStartDate && !tempEndDate\" class=\"status-text\">\n 请选择开始日期\n </span>\n <span v-else-if=\"tempStartDate && !tempEndDate\" class=\"status-text\">\n 请选择结束日期\n </span>\n <span v-else-if=\"tempStartDate && tempEndDate\" class=\"status-text status-complete\">\n 已选择完整范围\n </span>\n </div>\n </div>\n \n <!-- 日期选择器容器 -->\n <div class=\"nh-time-pickers\">\n <!-- 开始日期选择器 - 修改为通用日历 -->\n <div class=\"nh-time-picker\">\n <div class=\"nh-date-picker\">\n <!-- 年月选择器 -->\n <div class=\"nh-date-picker-header\">\n <button \n @click=\"changeMonth('start', -1)\"\n class=\"nh-date-picker-btn nh-date-picker-prev-btn\"\n type=\"button\"\n >\n <svg viewBox=\"0 0 1024 1024\" width=\"12\" height=\"12\">\n <path d=\"M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 0 0 0 50.3l450.8 352.1c5.2 4.1 12.9 0.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z\" fill=\"currentColor\"/>\n </svg>\n </button>\n <span class=\"nh-date-picker-header-label\">\n {{ formatYearMonth(startCalendar.year, startCalendar.month) }}\n </span>\n <button \n @click=\"changeMonth('start', 1)\"\n class=\"nh-date-picker-btn nh-date-picker-next-btn\"\n type=\"button\"\n >\n <svg viewBox=\"0 0 1024 1024\" width=\"12\" height=\"12\">\n <path d=\"M765.7 486.8L314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.8 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z\" fill=\"currentColor\"/>\n </svg>\n </button>\n </div>\n \n <!-- 星期标题 -->\n <div class=\"nh-date-picker-content\">\n <table class=\"nh-date-table\">\n <thead>\n <tr>\n <th v-for=\"day in weekDays\" :key=\"day\" class=\"nh-date-table-th\">{{ day }}</th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(week, weekIndex) in startCalendarDays\" :key=\"`start-week-${weekIndex}`\">\n <td \n v-for=\"(day, dayIndex) in week\" \n :key=\"`start-day-${weekIndex}-${dayIndex}`\"\n :class=\"getDateCellClass(day, 'start')\"\n @click=\"selectDate(day, 'start')\"\n >\n <div class=\"nh-date-table-cell\">\n <span v-if=\"day\">{{ day.day }}</span>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n \n <!-- 结束日期选择器 - 修改为通用日历 -->\n <div class=\"nh-time-picker\">\n <div class=\"nh-date-picker\">\n <!-- 年月选择器 -->\n <div class=\"nh-date-picker-header\">\n <button \n @click=\"changeMonth('end', -1)\"\n class=\"nh-date-picker-btn nh-date-picker-prev-btn\"\n type=\"button\"\n >\n <svg viewBox=\"0 0 1024 1024\" width=\"12\" height=\"12\">\n <path d=\"M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 0 0 0 50.3l450.8 352.1c5.2 4.1 12.9 0.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z\" fill=\"currentColor\"/>\n </svg>\n </button>\n <span class=\"nh-date-picker-header-label\">\n {{ formatYearMonth(endCalendar.year, endCalendar.month) }}\n </span>\n <button \n @click=\"changeMonth('end', 1)\"\n class=\"nh-date-picker-btn nh-date-picker-next-btn\"\n type=\"button\"\n >\n <svg viewBox=\"0 0 1024 1024\" width=\"12\" height=\"12\">\n <path d=\"M765.7 486.8L314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.8 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z\" fill=\"currentColor\"/>\n </svg>\n </button>\n </div>\n \n <!-- 日期表格 -->\n <div class=\"nh-date-picker-content\">\n <table class=\"nh-date-table\">\n <thead>\n <tr>\n <th v-for=\"day in weekDays\" :key=\"day\" class=\"nh-date-table-th\">{{ day }}</th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(week, weekIndex) in endCalendarDays\" :key=\"`end-week-${weekIndex}`\">\n <td \n v-for=\"(day, dayIndex) in week\" \n :key=\"`end-day-${weekIndex}-${dayIndex}`\"\n :class=\"getDateCellClass(day, 'end')\"\n @click=\"selectDate(day, 'end')\"\n >\n <div class=\"nh-date-table-cell\">\n <span v-if=\"day\">{{ day.day }}</span>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"nh-time-actions\">\n <YButton\n v-if=\"clearable\"\n @click=\"clearSelection\"\n :variant=\"'secondary'\"\n :size=\"size\"\n >\n 清空\n </YButton>\n <!-- 修改:优化确定按钮的状态提示 -->\n <YButton\n @click=\"confirmSelection\"\n :disabled=\"!canConfirm\"\n :variant=\"'primary'\"\n :size=\"size\"\n >\n {{ tempStartDate && !tempEndDate ? '继续选择结束日期' : '确认' }}\n </YButton>\n </div>\n </div>\n </div>\n </transition>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'\n\n// 定义类型\ninterface TimeRange {\n startDate: Date | null\n endDate: Date | null\n}\n\ninterface Shortcut {\n label: string\n getValue: () => TimeRange\n}\n\ninterface Props {\n modelValue?: TimeRange | { startDate: string | Date | number | null, endDate: string | Date | number | null }\n placeholder?: string\n shortcuts?: Shortcut[]\n clearable?: boolean\n format?: 'timestamp' | 'string' | 'date'\n includeTime?: boolean\n size?: 'mini' | 'small' | 'medium' | 'large'\n}\n\ninterface CalendarDay {\n date: Date\n day: number\n isCurrentMonth: boolean\n isToday: boolean\n isSelected: boolean\n isInRange: boolean\n isDisabled: boolean\n}\n\n// 定义 props,添加 includeTime 属性并提供默认值\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: () => ({ startDate: null, endDate: null }),\n placeholder: '请选择日期范围',\n clearable: true,\n format: 'timestamp',\n includeTime: false,\n size: 'small',\n shortcuts: () => [\n {\n label: '今天',\n getValue: () => {\n const today = new Date()\n const start = new Date(today.getFullYear(), today.getMonth(), today.getDate())\n const end = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59)\n return { startDate: start, endDate: end }\n }\n },\n {\n label: '昨天',\n getValue: () => {\n const yesterday = new Date()\n yesterday.setDate(yesterday.getDate() - 1)\n const start = new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate())\n const end = new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate(), 23, 59, 59)\n return { startDate: start, endDate: end }\n }\n },\n {\n label: '近7天',\n getValue: () => {\n const end = new Date()\n const start = new Date()\n start.setDate(start.getDate() - 6)\n start.setHours(0, 0, 0, 0)\n end.setHours(23, 59, 59, 999)\n return { startDate: start, endDate: end }\n }\n },\n {\n label: '近30天',\n getValue: () => {\n const end = new Date()\n const start = new Date()\n start.setDate(start.getDate() - 29)\n start.setHours(0, 0, 0, 0)\n end.setHours(23, 59, 59, 999)\n return { startDate: start, endDate: end }\n }\n },\n {\n label: '近3个月',\n getValue: () => {\n const end = new Date()\n const start = new Date()\n start.setMonth(start.getMonth() - 3)\n start.setHours(0, 0, 0, 0)\n end.setHours(23, 59, 59, 999)\n return { startDate: start, endDate: end }\n }\n }\n ]\n})\n\n// 定义 emits\nconst emit = defineEmits<{\n 'update:modelValue': [value: TimeRange | { startDate: string | number | null, endDate: string | number | null }]\n 'change': [value: TimeRange | { startDate: string | number | null, endDate: string | number | null }]\n}>()\n\n// 响应式数据\nconst isOpen = ref(false)\nconst activeShortcutIndex = ref(-1)\nconst selectedShortcutIndex = ref(-1)\nconst pendingValue = ref<TimeRange | null>(null)\nconst trigger = ref<HTMLElement>()\nconst dropdown = ref<HTMLElement>()\nconst dropdownPosition = ref({\n top: true,\n left: true\n})\n\n// 修改:日历相关的响应式数据\nconst startCalendar = ref({\n year: new Date().getFullYear(),\n month: new Date().getMonth()\n})\n\nconst endCalendar = ref({\n year: new Date().getFullYear(),\n month: new Date().getMonth() + 1\n})\n\n// 新增:确保结束日历月份不会与开始日历相同的函数\nconst ensureDifferentMonths = () => {\n const startTime = new Date(startCalendar.value.year, startCalendar.value.month).getTime()\n const endTime = new Date(endCalendar.value.year, endCalendar.value.month).getTime()\n \n if (startTime >= endTime) {\n // 如果开始月份大于等于结束月份,将结束月份设为开始月份的下一个月\n const nextMonth = new Date(startCalendar.value.year, startCalendar.value.month + 1)\n endCalendar.value.year = nextMonth.getFullYear()\n endCalendar.value.month = nextMonth.getMonth()\n }\n}\n\n// 新增:确保开始日历月份不会与结束日历相同的函数\nconst ensureDifferentMonthsReverse = () => {\n const startTime = new Date(startCalendar.value.year, startCalendar.value.month).getTime()\n const endTime = new Date(endCalendar.value.year, endCalendar.value.month).getTime()\n \n if (endTime <= startTime) {\n // 如果结束月份小于等于开始月份,将开始月份设为结束月份的上一个月\n const prevMonth = new Date(endCalendar.value.year, endCalendar.value.month - 1)\n startCalendar.value.year = prevMonth.getFullYear()\n startCalendar.value.month = prevMonth.getMonth()\n }\n}\n\nconst weekDays = ['一', '二', '三', '四', '五', '六', '日']\n\nconst tempStartDate = ref<Date | null>(null)\nconst tempEndDate = ref<Date | null>(null)\n\n// 修改:日期转换工具函数 - 支持时间戳\nconst parseDate = (date: string | Date | number | null): Date | null => {\n if (!date) return null\n if (date instanceof Date) return date\n if (typeof date === 'number') {\n // 时间戳格式\n return new Date(date)\n }\n if (typeof date === 'string') {\n const parsed = new Date(date)\n return isNaN(parsed.getTime()) ? null : parsed\n }\n return null\n}\n\n// 修改:格式化为字符串 - 根据 includeTime 决定返回格式\nconst formatDateToString = (date: Date | null): string | null => {\n if (!date) return null\n \n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n \n if (props.includeTime) {\n // 年月日时分秒格式: YYYY-MM-DD HH:mm:ss\n const hours = String(date.getHours()).padStart(2, '0')\n const minutes = String(date.getMinutes()).padStart(2, '0')\n const seconds = String(date.getSeconds()).padStart(2, '0')\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`\n } else {\n // 年月日格式: YYYY-MM-DD\n return `${year}-${month}-${day}`\n }\n}\n\n// 格式化为时间戳\nconst formatDateToTimestamp = (date: Date | null): number | null => {\n if (!date) return null\n return date.getTime()\n}\n\n// 修改:标准化输入值\nconst normalizeValue = (value: any): TimeRange => {\n if (!value) return { startDate: null, endDate: null }\n \n return {\n startDate: parseDate(value.startDate),\n endDate: parseDate(value.endDate)\n }\n}\n\n// 修改:格式化输出值 - 确保根据 includeTime 属性决定时间戳的精度\nconst formatOutputValue = (value: TimeRange) => {\n if (props.format === 'string') {\n // 返回根据 includeTime 决定的字符串格式\n return {\n startDate: formatDateToString(value.startDate),\n endDate: formatDateToString(value.endDate)\n }\n } else if (props.format === 'timestamp') {\n // 返回时间戳\n return {\n startDate: formatDateToTimestamp(value.startDate),\n endDate: formatDateToTimestamp(value.endDate)\n }\n } else {\n // format === 'date',返回Date对象\n return value\n }\n}\n\n// 工具函数\nconst formatYearMonth = (year: number, month: number) => {\n return `${String(month + 1).padStart(2, '0')}/${year}`\n}\n\nconst isSameDay = (date1: Date, date2: Date) => {\n return date1.getFullYear() === date2.getFullYear() &&\n date1.getMonth() === date2.getMonth() &&\n date1.getDate() === date2.getDate()\n}\n\nconst isDateInRange = (date: Date, start: Date | null, end: Date | null) => {\n if (!start || !end) return false\n return date >= start && date <= end\n}\n\n// 修改:检查当前值是否匹配某个快捷选项\nconst findMatchingShortcutIndex = (currentValue: any): number => {\n const normalizedValue = normalizeValue(currentValue)\n \n if (!normalizedValue?.startDate || !normalizedValue?.endDate) {\n return -1\n }\n\n for (let i = 0; i < props.shortcuts.length; i++) {\n const shortcutValue = props.shortcuts[i].getValue()\n \n if (shortcutValue.startDate && shortcutValue.endDate &&\n normalizedValue.startDate && normalizedValue.endDate) {\n \n // 比较日期时忽略时间部分\n const currentStart = new Date(normalizedValue.startDate.getFullYear(), \n normalizedValue.startDate.getMonth(), \n normalizedValue.startDate.getDate())\n const currentEnd = new Date(normalizedValue.endDate.getFullYear(), \n normalizedValue.endDate.getMonth(), \n normalizedValue.endDate.getDate())\n \n const shortcutStart = new Date(shortcutValue.startDate.getFullYear(), \n shortcutValue.startDate.getMonth(), \n shortcutValue.startDate.getDate())\n const shortcutEnd = new Date(shortcutValue.endDate.getFullYear(), \n shortcutValue.endDate.getMonth(), \n shortcutValue.endDate.getDate())\n \n if (currentStart.getTime() === shortcutStart.getTime() && \n currentEnd.getTime() === shortcutEnd.getTime()) {\n return i\n }\n }\n }\n \n return -1\n}\n\n// 修改:生成日历天数数据,调整日历布局\nconst generateCalendarDays = (year: number, month: number): CalendarDay[][] => {\n const firstDay = new Date(year, month, 1)\n const lastDay = new Date(year, month + 1, 0)\n const firstDayWeek = firstDay.getDay()\n const daysInMonth = lastDay.getDate()\n \n const days: CalendarDay[] = []\n const today = new Date()\n \n // 修改:确保每个月的第一天不在第一个位置\n // 如果当月第一天是周日(0),则显示上个月的6天\n // 否则显示上个月的(firstDayWeek-1)天\n const prevDaysCount = firstDayWeek === 0 ? 6 : firstDayWeek - 1\n \n // 添加上个月的日期 - 设为禁用\n // 修复:应基于当前月份计算上个月的最后一天,避免出现溢出到当月的日期(如 09/31 -> 10/01)\n const prevMonth = new Date(year, month, 0)\n for (let i = prevDaysCount - 1; i >= 0; i--) {\n const date = new Date(year, month - 1, prevMonth.getDate() - i)\n days.push({\n date,\n day: date.getDate(),\n isCurrentMonth: false,\n isToday: isSameDay(date, today),\n isSelected: false,\n isInRange: false,\n isDisabled: true // 禁用非当前月的日期\n })\n }\n \n // 添加当前月的日期\n for (let i = 1; i <= daysInMonth; i++) {\n const date = new Date(year, month, i)\n days.push({\n date,\n day: i,\n isCurrentMonth: true,\n isToday: isSameDay(date, today),\n isSelected: false,\n isInRange: false,\n isDisabled: false\n })\n }\n \n // 添加下个月的日期 - 设为禁用\n const remainingDays = 42 - days.length\n for (let i = 1; i <= remainingDays; i++) {\n const date = new Date(year, month + 1, i)\n days.push({\n date,\n day: i,\n isCurrentMonth: false,\n isToday: isSameDay(date, today),\n isSelected: false,\n isInRange: false,\n isDisabled: true // 禁用非当前月的日期\n })\n }\n \n // 将天数数组分组为周\n const weeks: CalendarDay[][] = []\n for (let i = 0; i < days.length; i += 7) {\n weeks.push(days.slice(i, i + 7))\n }\n \n return weeks\n}\n\n// 方法\nconst updateValue = (value: TimeRange) => {\n const formattedValue = formatOutputValue(value)\n emit('update:modelValue', formattedValue)\n emit('change', formattedValue)\n}\n\n// 新增:计算下拉面板最佳位置的函数\nconst calculateDropdownPosition = () => {\n if (!trigger.value || !dropdown.value) return\n\n const triggerRect = trigger.value.getBoundingClientRect()\n const dropdownRect = dropdown.value.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n const spaceBelow = viewportHeight - triggerRect.bottom\n const spaceAbove = triggerRect.top\n const dropdownHeight = dropdownRect.height || 400\n \n if (spaceBelow < dropdownHeight && spaceAbove > dropdownHeight) {\n dropdownPosition.value.top = false\n } else {\n dropdownPosition.value.top = true\n }\n\n const spaceRight = viewportWidth - triggerRect.left\n const dropdownWidth = dropdownRect.width || 640\n \n if (spaceRight < dropdownWidth) {\n dropdownPosition.value.left = false\n } else {\n dropdownPosition.value.left = true\n }\n}\n\nconst toggleDropdown = () => {\n isOpen.value = !isOpen.value\n if (isOpen.value) {\n // 初始化临时日期 - 使用标准化的值\n const normalizedValue = normalizeValue(props.modelValue)\n tempStartDate.value = normalizedValue?.startDate || null\n tempEndDate.value = normalizedValue?.endDate || null\n \n // 更新选中的快捷选项索引\n selectedShortcutIndex.value = findMatchingShortcutIndex(props.modelValue)\n \n // 重置键盘导航索引\n activeShortcutIndex.value = -1\n \n // 初始化日历显示月份\n if (normalizedValue?.startDate) {\n startCalendar.value.year = normalizedValue.startDate.getFullYear()\n startCalendar.value.month = normalizedValue.startDate.getMonth()\n }\n \n if (normalizedValue?.endDate) {\n endCalendar.value.year = normalizedValue.endDate.getFullYear()\n endCalendar.value.month = normalizedValue.endDate.getMonth()\n } else {\n // 如果没有结束日期,默认显示开始日期的下一个月\n const nextMonth = new Date(startCalendar.value.year, startCalendar.value.month + 1)\n endCalendar.value.year = nextMonth.getFullYear()\n endCalendar.value.month = nextMonth.getMonth()\n }\n \n // 确保两个日历显示不同的月份\n ensureDifferentMonths()\n \n nextTick(() => {\n calculateDropdownPosition()\n })\n }\n}\n\nconst handleClickOutside = (event: Event) => {\n const target = event.target as HTMLElement\n const triggerEl = trigger.value\n const dropdownEl = dropdown.value\n \n if (triggerEl && dropdownEl && \n !triggerEl.contains(target) && \n !dropdownEl.contains(target)) {\n isOpen.value = false\n activeShortcutIndex.value = -1\n }\n}\n\nconst handleTriggerKeydown = (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n toggleDropdown()\n } else if (event.key === 'ArrowDown') {\n event.preventDefault()\n isOpen.value = true\n nextTick(() => {\n calculateDropdownPosition()\n focusFirstShortcut()\n })\n }\n}\n\nconst handleDropdownKeydown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n isOpen.value = false\n activeShortcutIndex.value = -1\n trigger.value?.focus()\n }\n}\n \nconst handleShortcutKeydown = (event: KeyboardEvent, index: number) => {\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n activeShortcutIndex.value = Math.min(index + 1, props.shortcuts.length - 1)\n focusShortcut(activeShortcutIndex.value)\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n activeShortcutIndex.value = Math.max(index - 1, 0)\n focusShortcut(activeShortcutIndex.value)\n } else if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n selectShortcut(props.shortcuts[index])\n }\n}\n\nconst handleShortcutMouseEnter = (index: number) => {\n activeShortcutIndex.value = index\n}\n\nconst handleShortcutMouseLeave = () => {\n activeShortcutIndex.value = -1\n}\n\nconst focusFirstShortcut = () => {\n activeShortcutIndex.value = 0\n focusShortcut(0)\n}\n\nconst focusShortcut = (index: number) => {\n if (dropdown.value) {\n const shortcuts = dropdown.value.querySelectorAll('.nh-time-shortcut')\n const shortcutElement = shortcuts[index] as HTMLElement\n if (shortcutElement) {\n shortcutElement.focus()\n }\n }\n}\n\nconst selectShortcut = (shortcut: Shortcut) => {\n const value = shortcut.getValue()\n \n // 如果需要包含时间,确保时间部分正确设置\n if (props.includeTime && value.startDate && value.endDate) {\n value.startDate.setHours(0, 0, 0, 0)\n value.endDate.setHours(23, 59, 59, 999)\n }\n \n updateValue(value)\n \n // 更新选中的快捷选项索引\n selectedShortcutIndex.value = props.shortcuts.findIndex(s => s.label === shortcut.label)\n \n // 重置键盘导航索引\n activeShortcutIndex.value = -1\n \n isOpen.value = false\n}\n\n// 修改:选择日期时设置时间部分\nconst selectDate = (day: CalendarDay | null, type: 'start' | 'end') => {\n if (!day || day.isDisabled) return\n \n // 创建日期对象,根据是否需要保留时间部分设置时间\n let selectedDate: Date\n \n if (props.includeTime) {\n // 如果需要保留时分秒,则根据开始/结束位置设置不同的时间值\n selectedDate = new Date(day.date)\n if (type === 'start' || !tempStartDate.value) {\n // 开始日期设置为当天 00:00:00\n selectedDate.setHours(0, 0, 0, 0)\n } else {\n // 结束日期设置为当天 23:59:59\n selectedDate.setHours(23, 59, 59, 999)\n }\n } else {\n // 如果不需要保留时分秒,只保留年月日\n selectedDate = new Date(day.date.getFullYear(), day.date.getMonth(), day.date.getDate())\n }\n \n // 智能选择逻辑:\n // 1. 如果没有选择任何日期,当前选择的日期作为开始日期\n // 2. 如果已有开始日期但没有结束日期:\n // - 如果新选择的日期 >= 开始日期,设为结束日期\n // - 如果新选择的日期 < 开始日期,将新日期设为开始日期,原开始日期设为结束日期\n // 3. 如果已有开始和结束日期,重新开始选择:设为新的开始日期,清空结束日期\n \n if (!tempStartDate.value && !tempEndDate.value) {\n // 情况1:没有选择任何日期\n tempStartDate.value = selectedDate\n tempEndDate.value = null\n } else if (tempStartDate.value && !tempEndDate.value) {\n // 情况2:已有开始日期,没有结束日期\n if (selectedDate >= tempStartDate.value) {\n // 选择的日期大于等于开始日期,设为结束日期\n // 确保结束日期总是设置为 23:59:59\n if (props.includeTime) {\n selectedDate.setHours(23, 59, 59, 999)\n }\n tempEndDate.value = selectedDate\n } else {\n // 选择的日期小于开始日期,自动交换:新日期作为开始日期,原开始日期作为结束日期\n const endDate = tempStartDate.value\n // 确保结束日期总是设置为 23:59:59\n if (props.includeTime) {\n endDate.setHours(23, 59, 59, 999)\n }\n tempEndDate.value = endDate\n tempStartDate.value = selectedDate\n }\n } else {\n // 情况3:已有开始和结束日期,重新开始选择\n tempStartDate.value = selectedDate\n tempEndDate.value = null\n }\n \n // 清除快捷选项的选中状态,因为用户选择了自定义日期\n selectedShortcutIndex.value = -1\n \n // 更新待确认的值\n if (tempStartDate.value && tempEndDate.value) {\n // 确保结束日期总是设置为 23:59:59(如果启用了时间)\n const endDate = new Date(tempEndDate.value)\n if (props.includeTime) {\n endDate.setHours(23, 59, 59, 999)\n }\n pendingValue.value = { \n startDate: tempStartDate.value, \n endDate: endDate \n }\n } else {\n pendingValue.value = null\n }\n}\n\nconst getDateCellClass = (day: CalendarDay | null, type: 'start' | 'end') => {\n if (!day) return ['nh-date-table-td']\n \n const classes = ['nh-date-table-td']\n \n if (!day.isCurrentMonth) {\n classes.push('is-prev-month')\n }\n \n if (day.isToday) {\n classes.push('is-today')\n }\n \n if (day.isDisabled) {\n classes.push('is-disabled')\n }\n \n // 检查是否是选中的日期\n if (tempStartDate.value && isSameDay(day.date, tempStartDate.value)) {\n classes.push('is-selected', 'is-start')\n }\n \n if (tempEndDate.value && isSameDay(day.date, tempEndDate.value)) {\n classes.push('is-selected', 'is-end')\n }\n \n // 检查是否在选中范围内\n if (tempStartDate.value && tempEndDate.value && \n isDateInRange(day.date, tempStartDate.value, tempEndDate.value)) {\n classes.push('is-in-range')\n }\n \n return classes\n}\n\nconst confirmSelection = () => {\n if (pendingValue.value) {\n // 再次确保结束日期设置为 23:59:59(如果启用了时间)\n if (props.includeTime && pendingValue.value.endDate) {\n pendingValue.value.endDate.setHours(23, 59, 59, 999)\n }\n \n updateValue(pendingValue.value)\n // 检查新的值是否匹配某个快捷选项\n selectedShortcutIndex.value = findMatchingShortcutIndex(pendingValue.value)\n isOpen.value = false\n }\n}\n\nconst clearSelection = () => {\n updateValue({ startDate: null, endDate: null })\n resetSelection()\n activeShortcutIndex.value = -1\n isOpen.value = false\n}\n\n// 新增:监听窗口大小变化,重新计算位置\nconst handleResize = () => {\n if (isOpen.value) {\n nextTick(() => {\n calculateDropdownPosition()\n })\n }\n}\n\n// 计算属性\nconst startCalendarDays = computed(() => {\n return generateCalendarDays(startCalendar.value.year, startCalendar.value.month)\n})\n\nconst endCalendarDays = computed(() => {\n return generateCalendarDays(endCalendar.value.year, endCalendar.value.month)\n})\n\nconst displayText = computed(() => {\n const normalizedValue = normalizeValue(props.modelValue)\n \n if (!normalizedValue || !normalizedValue.startDate || !normalizedValue.endDate) {\n return ''\n }\n \n const formatDate = (date: Date) => {\n const year = String(date.getFullYear())\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n return `${year}/${month}/${day}`\n }\n \n const startStr = formatDate(normalizedValue.startDate)\n const endStr = formatDate(normalizedValue.endDate)\n \n // 如果是同一天且不包含时间,只显示一个日期\n if (!props.includeTime && startStr === endStr) {\n return startStr\n }\n \n return `${startStr} - ${endStr}`\n})\n\nconst dropdownClasses = computed(() => {\n return [\n 'nh-time-dropdown',\n {\n 'nh-time-dropdown-top': !dropdownPosition.value.top,\n 'nh-time-dropdown-right': !dropdownPosition.value.left\n }\n ]\n})\n\n// 新增计算属性:检查是否有值\nconst hasValue = computed(() => {\n const normalizedValue = normalizeValue(props.modelValue)\n return !!(normalizedValue?.startDate && normalizedValue?.endDate)\n})\n\n// 新增计算属性:检查是否可以确认 - 修改逻辑\nconst canConfirm = computed(() => {\n return !!(tempStartDate.value && tempEndDate.value)\n})\n\n// 修改:格式化显示日期(用于选择器标题)- 增强显示格式\n// const formatDisplayDate = (date: Date) => {\n// return new Intl.DateTimeFormat('zh-CN', {\n// month: '2-digit',\n// day: '2-digit'\n// }).format(date)\n// }\n\n// 新增:重置选择状态的方法\nconst resetSelection = () => {\n tempStartDate.value = null\n tempEndDate.value = null\n pendingValue.value = null\n selectedShortcutIndex.value = -1\n}\n\n// 监听器 - 修改以确保日历月份正确初始化\nwatch(() => props.modelValue, (newValue) => {\n const normalizedValue = normalizeValue(newValue)\n \n if (normalizedValue?.startDate) {\n const startDate = normalizedValue.startDate\n startCalendar.value.year = startDate.getFullYear()\n startCalendar.value.month = startDate.getMonth()\n }\n \n if (normalizedValue?.endDate) {\n const endDate = normalizedValue.endDate\n endCalendar.value.year = endDate.getFullYear()\n endCalendar.value.month = endDate.getMonth()\n } else if (normalizedValue?.startDate) {\n // 如果只有开始日期,结束日历显示下一个月\n const nextMonth = new Date(startCalendar.value.year, startCalendar.value.month + 1)\n endCalendar.value.year = nextMonth.getFullYear()\n endCalendar.value.month = nextMonth.getMonth()\n }\n \n // 确保两个日历显示不同的月份\n if (normalizedValue?.startDate || normalizedValue?.endDate) {\n ensureDifferentMonths()\n }\n \n // 当外部值改变时,更新选中的快捷选项\n if (!isOpen.value) {\n selectedShortcutIndex.value = findMatchingShortcutIndex(newValue)\n }\n}, { immediate: true, deep: true })\n\n// 新增:监听日历月份变化,确保不会显示相同月份\nwatch([startCalendar, endCalendar], () => {\n const startTime = new Date(startCalendar.value.year, startCalendar.value.month).getTime()\n const endTime = new Date(endCalendar.value.year, endCalendar.value.month).getTime()\n \n // 如果两个日历显示相同月份,自动调整\n if (startTime === endTime) {\n const nextMonth = new Date(startCalendar.value.year, startCalendar.value.month + 1)\n endCalendar.value.year = nextMonth.getFullYear()\n endCalendar.value.month = nextMonth.getMonth()\n }\n}, { deep: true })\n\n// 生命周期\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n window.addEventListener('resize', handleResize)\n window.addEventListener('scroll', handleResize)\n \n // 初始化时设置选中的快捷选项和日历月份\n selectedShortcutIndex.value = findMatchingShortcutIndex(props.modelValue)\n \n // 修复:初始化日历月份时使用标准化的值\n const normalizedValue = normalizeValue(props.modelValue)\n \n if (normalizedValue?.startDate) {\n startCalendar.value.year = normalizedValue.startDate.getFullYear()\n startCalendar.value.month = normalizedValue.startDate.getMonth()\n }\n \n if (normalizedValue?.endDate) {\n endCalendar.value.year = normalizedValue.endDate.getFullYear()\n endCalendar.value.month = normalizedValue.endDate.getMonth()\n } else {\n // 默认显示当前月和下个月\n const nextMonth = new Date(startCalendar.value.year, startCalendar.value.month + 1)\n endCalendar.value.year = nextMonth.getFullYear()\n endCalendar.value.month = nextMonth.getMonth()\n }\n \n ensureDifferentMonths()\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('resize', handleResize)\n window.removeEventListener('scroll', handleResize)\n})\n\n// 新增:处理输入框清空按钮点击\nconst handleClearClick = () => {\n if (!props.clearable) return\n \n updateValue({ startDate: null, endDate: null })\n resetSelection()\n activeShortcutIndex.value = -1\n}\n\n// 修改:日期选择相关方法\nconst changeMonth = (type: 'start' | 'end', direction: number) => {\n if (type === 'start') {\n const newDate = new Date(startCalendar.value.year, startCalendar.value.month + direction, 1)\n startCalendar.value.year = newDate.getFullYear()\n startCalendar.value.month = newDate.getMonth()\n \n // 确保结束月份不会与开始月份相同\n ensureDifferentMonths()\n } else {\n const newDate = new Date(endCalendar.value.year, endCalendar.value.month + direction, 1)\n endCalendar.value.year = newDate.getFullYear()\n endCalendar.value.month = newDate.getMonth()\n \n // 确保开始月份不会与结束月份相同\n ensureDifferentMonthsReverse()\n }\n}\n</script>\n\n<style scoped>\n/* 基础样式,与 YInput/YSelect 风格统一 */\n.nh-time-search {\n position: relative;\n display: inline-block;\n width: 250px;\n font-size: 14px;\n color: #0b1a29;\n}\n\n.nh-time-trigger {\n position: relative;\n display: inline-block;\n width: 100%;\n cursor: pointer;\n}\n\n.nh-time-trigger.is-focus .nh-time-input {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59,130,246,0.15);\n}\n\n.nh-time-input {\n background-color: #ffffff;\n border: 1px solid #e2e8f0;\n border-radius: 10px;\n box-sizing: border-box;\n color: #0b1a29;\n display: inline-block;\n font-size: inherit;\n outline: none;\n padding: 0 40px 0 12px;\n transition: box-shadow 0.2s ease, border-color 0.2s ease;\n width: 100%;\n cursor: pointer;\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif;\n}\n\n.nh-time-input:hover { border-color: #60a5fa; }\n\n.nh-time-input:focus {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59,130,246,0.15);\n outline: none;\n}\n\n.nh-time-input::placeholder {\n color: #9ca3af;\n}\n\n.nh-time-suffix {\n position: absolute;\n height: 100%;\n right: 8px;\n top: 0;\n display: flex;\n align-items: center;\n color: #6b7280;\n font-size: 14px;\n pointer-events: none;\n gap: 4px;\n}\n\n.nh-time-icon { display: flex; align-items: center; }\n\n.nh-time-arrow {\n display: flex;\n align-items: center;\n transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n.nh-time-clear {\n display: flex;\n align-items: center;\n cursor: pointer;\n color: #9ca3af;\n transition: all 0.2s ease;\n pointer-events: auto;\n}\n\n.nh-time-clear:hover {\n color: #6b7280;\n}\n\n.nh-time-clear:active {\n transform: scale(0.9);\n}\n\n/* 下拉面板样式 */\n.nh-time-dropdown {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n z-index: 50;\n background: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n box-shadow: 0 8px 20px rgba(2,6,23,0.15);\n display: flex;\n min-width: 640px;\n max-width: calc(100vw - 20px);\n box-sizing: border-box;\n overflow: hidden;\n}\n\n.nh-time-dropdown-top {\n top: auto;\n bottom: calc(100% + 4px);\n}\n\n.nh-time-dropdown-right {\n left: auto;\n right: 0;\n}\n\n/* 快捷选项样式 */\n.nh-time-shortcuts {\n width: 140px;\n border-right: 1px solid #e5e7eb;\n background-color: #f9fafb;\n}\n\n.nh-time-shortcuts-title {\n padding: 12px 16px 8px;\n color: #374151;\n font-size: 12px;\n font-weight: 500;\n border-bottom: 1px solid #e5e7eb;\n background-color: #f9fafb;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.nh-time-shortcuts-list {\n margin: 0;\n padding: 4px 0;\n list-style: none;\n}\n\n.nh-time-shortcut {\n display: block;\n width: 100%;\n padding: 8px 16px;\n margin: 0;\n font-size: 13px;\n color: #374151;\n cursor: pointer;\n border: none;\n background: none;\n text-align: left;\n outline: none;\n transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out;\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif;\n}\n\n.nh-time-shortcut:hover,\n.nh-time-shortcut.is-active {\n background-color: #f3f4f6;\n color: #1f2937;\n}\n\n.nh-time-shortcut:focus {\n background-color: #f3f4f6;\n outline: none;\n}\n\n.nh-time-shortcut.is-selected {\n background-color: #313B4A !important;\n color: #ffffff !important;\n}\n\n.nh-time-shortcut.is-selected:hover {\n background-color: #354051 !important;\n color: #ffffff !important;\n}\n\n.nh-time-shortcut:active {\n background-color: #e5e7eb;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n transform: translateY(1px);\n}\n\n/* 自定义时间选择样式 */\n.nh-time-custom {\n flex: 1;\n padding: 8px 16px;\n background-color: #ffffff;\n}\n\n.nh-time-custom-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.nh-time-custom-header span {\n font-size: 14px;\n font-weight: 500;\n color: #374151;\n}\n\n/* 选择状态提示样式 */\n.nh-time-selection-status {\n display: flex;\n align-items: center;\n}\n\n.status-text {\n font-size: 12px;\n color: #6b7280;\n padding: 4px 8px;\n border-radius: 4px;\n background-color: #f3f4f6;\n font-weight: 500;\n}\n\n.status-text.status-complete {\n color: #059669;\n background-color: #d1fae5;\n}\n\n.nh-time-pickers {\n display: flex;\n gap: 24px;\n margin-bottom: 8px;\n}\n\n.nh-time-picker {\n flex: 1;\n}\n\n.nh-time-picker-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 1px solid #f3f4f6;\n min-height: 40px;\n}\n\n.nh-time-picker-title {\n font-size: 13px;\n color: #6b7280;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.nh-time-picker-dates {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 2px;\n}\n\n.nh-time-picker-date {\n font-size: 11px;\n padding: 2px 6px;\n border-radius: 3px;\n font-weight: 500;\n}\n\n.nh-time-picker-date.start-date {\n color: #313B4A;\n background-color: #e4f0fd;\n}\n\n.nh-time-picker-date.end-date {\n color: #059669;\n background-color: #d1fae5;\n}\n\n.nh-time-picker-hint {\n display: flex;\n align-items: center;\n}\n\n.hint-text {\n font-size: 11px;\n color: #9ca3af;\n text-align: right;\n line-height: 1.3;\n max-width: 120px;\n}\n\n/* 日期选择器样式 */\n.nh-date-picker {\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n background: #ffffff;\n overflow: hidden;\n}\n\n.nh-date-picker:before {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: 8px;\n padding: 1px;\n background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8), rgba(229, 231, 235, 0.5));\n mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n pointer-events: none;\n}\n\n.nh-date-picker-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background-color: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.nh-date-picker-header-label {\n font-size: 14px;\n font-weight: 600;\n color: #374151;\n}\n\n.nh-date-picker-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n border-radius: 6px;\n color: #6b7280;\n transition: all 0.15s ease-in-out;\n}\n\n.nh-date-picker-btn:hover {\n background-color: #f3f4f6;\n color: #374151;\n}\n\n.nh-date-picker-btn:focus {\n outline: none;\n background-color: #f3f4f6;\n}\n\n.nh-date-picker-btn:active {\n transform: translateY(0);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.05);\n background: linear-gradient(to bottom, #f3f4f6, #e5e7eb);\n}\n\n.nh-date-picker-content {\n padding: 12px;\n background: linear-gradient(135deg, #ffffff, #fafafa);\n}\n\n/* 日期表格样式 */\n.nh-date-table {\n width: 100%;\n border-collapse: collapse;\n table-layout: fixed;\n}\n\n.nh-date-table-th {\n padding: 8px 4px;\n text-align: center;\n font-size: 11px;\n color: #6b7280;\n font-weight: 500;\n border-bottom: 1px solid #f3f4f6;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.nh-date-table-td {\n width: 32px;\n height: 32px;\n padding: 3px;\n box-sizing: border-box;\n}\n\n.nh-date-table-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 26px;\n width: 26px;\n margin: 0 auto;\n border-radius: 6px;\n font-size: 13px;\n color: #374151;\n transition: all 0.15s ease-in-out;\n position: relative;\n font-weight: 400;\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.02);\n}\n\n.nh-date-table-td:hover .nh-date-table-cell {\n background-color: #f3f4f6;\n color: #1f2937;\n}\n\n/* 日期状态样式 - 修改禁用状态但保留选中样式 */\n.nh-date-table-td.is-prev-month .nh-date-table-cell {\n color: #d1d5db;\n background-color: #f9fafb;\n cursor: not-allowed;\n}\n\n.nh-date-table-td.is-prev-month:hover .nh-date-table-cell {\n background-color: #f9fafb;\n color: #d1d5db;\n}\n\n/* 禁用状态的通用样式 */\n.nh-date-table-td.is-disabled .nh-date-table-cell {\n background-color: #f9fafb;\n color: #d1d5db;\n cursor: not-allowed;\n}\n\n.nh-date-table-td.is-disabled:hover .nh-date-table-cell {\n background-color: #f9fafb;\n color: #d1d5db;\n}\n\n/* 保留正常的选中状态样式 */\n.nh-date-table-td.is-selected .nh-date-table-cell {\n background-color: #313B4A;\n color: #ffffff;\n font-weight: 500;\n}\n\n.nh-date-table-td.is-in-range .nh-date-table-cell {\n background-color: #e4f0fd;\n color: #313B4A;\n}\n\n.nh-date-table-td.is-start .nh-date-table-cell,\n.nh-date-table-td.is-end .nh-date-table-cell {\n background-color: #313B4A;\n color: #ffffff;\n font-weight: 500;\n}\n\n/* 今天标记 */\n.nh-date-table-td.is-today .nh-date-table-cell {\n color: #c23616;\n font-weight: 600;\n}\n\n/* 修改:禁用且在选中范围内的日期显示为灰色背景 */\n.nh-date-table-td.is-disabled.is-in-range .nh-date-table-cell {\n background-color: #f3f4f6 !important;\n color: #9ca3af !important;\n cursor: not-allowed;\n}\n\n/* 修改:禁用且是开始/结束日期的样式 */\n.nh-date-table-td.is-disabled.is-start .nh-date-table-cell,\n.nh-date-table-td.is-disabled.is-end .nh-date-table-cell {\n background-color: #9ca3af !important;\n color: #ffffff !important;\n cursor: not-allowed;\n}\n\n.nh-date-table-td.is-disabled.is-selected .nh-date-table-cell {\n background-color: #9ca3af !important;\n color: #ffffff !important;\n cursor: not-allowed;\n}\n\n/* 修改:只有禁用且未选中的日期才显示完全禁用样式 */\n.nh-date-table-td.is-disabled:not(.is-selected):not(.is-start):not(.is-end):not(.is-in-range) .nh-date-table-cell {\n background-color: #f9fafb;\n color: #d1d5db;\n cursor: not-allowed;\n}\n\n.nh-date-table-td.is-disabled:not(.is-selected):not(.is-start):not(.is-end):not(.is-in-range):hover .nh-date-table-cell {\n background-color: #f9fafb;\n color: #d1d5db;\n}\n\n/* 今天标记 - 非当前月的禁用状态 */\n.nh-date-table-td.is-disabled.is-today:not(.is-selected):not(.is-start):not(.is-end):not(.is-in-range) .nh-date-table-cell {\n color: #d1d5db;\n font-weight: 600;\n background-color: #f9fafb;\n}\n\n/* 修改:禁用范围内日期的连接线样式 */\n.nh-date-table-td.is-disabled.is-in-range::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n height: 26px;\n background-color: rgba(156, 163, 175, 0.2);\n transform: translateY(-50%);\n z-index: -1;\n border: 1px solid rgba(156, 163, 175, 0.3);\n}\n\n/* 保留选中范围的连续效果 - 正常状态 */\n.nh-date-table-td.is-in-range:not(.is-disabled)::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n height: 26px;\n background-color: rgba(49, 59, 74, 0.1);\n transform: translateY(-50%);\n z-index: -1;\n border: 1px solid rgba(49, 59, 74, 0.2);\n}\n\n.nh-date-table-td.is-start.is-in-range::before {\n left: 50%;\n}\n\n.nh-date-table-td.is-end.is-in-range::before {\n right: 50%;\n}\n\n.nh-date-table-td.is-start.is-end.is-in-range::before {\n display: none;\n}\n\n/* 修改:禁用日期的视觉标记为灰色 */\n.nh-date-table-td.is-disabled.is-start .nh-date-table-cell::before {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 6px;\n height: 6px;\n background-color: #d1d5db;\n border-radius: 50%;\n z-index: 1;\n}\n\n.nh-date-table-td.is-disabled.is-end .nh-date-table-cell::after {\n content: '';\n position: absolute;\n bottom: 2px;\n right: 2px;\n width: 6px;\n height: 6px;\n background-color: #d1d5db;\n border-radius: 50%;\n z-index: 1;\n}\n\n/* 保留正常日期范围视觉标记 */\n.nh-date-table-td.is-start:not(.is-disabled) .nh-date-table-cell::before {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 6px;\n height: 6px;\n background-color: #ffffff;\n border-radius: 50%;\n z-index: 1;\n}\n\n.nh-date-table-td.is-end:not(.is-disabled) .nh-date-table-cell::after {\n content: '';\n position: absolute;\n bottom: 2px;\n right: 2px;\n width: 6px;\n height: 6px;\n background-color: #ffffff;\n border-radius: 50%;\n z-index: 1;\n}\n\n/* 只有完全禁用且未选中的日期才隐藏范围连接线和标记 */\n.nh-date-table-td.is-disabled:not(.is-selected):not(.is-start):not(.is-end):not(.is-in-range) .nh-date-table-cell::before,\n.nh-date-table-td.is-disabled:not(.is-selected):not(.is-start):not(.is-end):not(.is-in-range) .nh-date-table-cell::after {\n display: none;\n}\n\n.nh-time-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding-top: 2px;\n}\n\n/* 尺寸适配,与 YInput/YButton 保持一致 */\n.nh-time--mini .nh-time-input { height: 24px; border-radius: 6px; font-size: 11px; }\n.nh-time--small .nh-time-input { height: 32px; border-radius: 8px; font-size: 12px; }\n.nh-time--medium .nh-time-input { height: 44px; border-radius: 10px; font-size: 14px; }\n.nh-time--large .nh-time-input { height: 52px; border-radius: 12px; font-size: 16px; }\n\n/* 过渡动画 */\n.el-zoom-in-top-enter-active,\n.el-zoom-in-top-leave-active {\n opacity: 1;\n transform: scale(1);\n transition: opacity 0.2s ease-out, transform 0.2s ease-out;\n transform-origin: top;\n}\n\n.el-zoom-in-top-enter-from,\n.el-zoom-in-top-leave-to {\n opacity: 0;\n transform: scale(0.95);\n}\n\n/* 输入框状态优化 */\n.nh-time-trigger.has-value .nh-time-input {\n color: #1f2937;\n font-weight: 500;\n background-image: linear-gradient(to bottom, #ffffff, #f9fafb);\n}\n\n.nh-time-trigger:not(.has-value) .nh-time-input {\n color: #9ca3af;\n}\n\n/* 箭头旋转动画 */\n.nh-time-arrow {\n transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n.nh-time-arrow.is-reverse {\n transform: rotate(180deg);\n}\n\n/* 日历图标优化 */\n.nh-time-icon {\n display: flex;\n align-items: center;\n color: #6b7280;\n filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.1));\n}\n\n.nh-time-trigger.is-focus .nh-time-icon {\n color: #313B4A;\n filter: drop-shadow(0 1px 2px rgba(49, 59, 74, 0.2));\n}\n\n/* 输入框聚焦状态优化 */\n.nh-time-trigger.is-focus {\n box-shadow: 0 0 0 2px rgba(49, 59, 74, 0.2), 0 2px 5px rgba(0, 0, 0, 0.1);\n border-radius: 6px;\n}\n\n/* 清空按钮优化 */\n.nh-time-clear {\n opacity: 0;\n transition: all 0.2s ease;\n transform-origin: center;\n}\n\n.nh-time-trigger:hover .nh-time-clear,\n.nh-time-trigger.is-focus .nh-time-clear {\n opacity: 1;\n}\n\n/* 响应式设计 */\n@media (max-width: 768px) {\n .nh-time-search {\n width: 200px;\n }\n \n .nh-time-dropdown {\n min-width: 320px;\n max-width: calc(100vw - 20px);\n flex-direction: column;\n }\n \n .nh-time-shortcuts {\n width: 100%;\n border-right: none;\n border-bottom: 1px solid #e5e7eb;\n box-shadow: 0 2px 4px -2px rgba(0, 0, 0, 0.05);\n }\n \n .nh-time-shortcuts-list {\n display: flex;\n flex-wrap: wrap;\n padding: 8px;\n gap: 4px;\n }\n \n .nh-time-shortcut {\n flex: 1;\n min-width: 80px;\n text-align: center;\n padding: 6px 8px;\n border-radius: 4px;\n }\n \n .nh-time-pickers {\n flex-direction: column;\n gap: 12px;\n }\n \n .nh-date-picker-header-label {\n font-size: 13px;\n }\n \n .nh-date-table-cell {\n height: 24px;\n width: 24px;\n font-size: 12px;\n }\n \n .nh-date-table-td {\n height: 24px;\n width: 24px;\n }\n \n .nh-time-picker-header {\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n min-height: auto;\n }\n \n .nh-time-picker-dates {\n align-items: flex-start;\n width: 100%;\n }\n \n .hint-text {\n max-width: 100%;\n text-align: left;\n }\n \n .nh-time-actions {\n flex-direction: row;\n gap: 8px;\n }\n}\n\n/* 增强立体感的额外效果 */\n/* 悬停时的提升效果 */\n.nh-date-table-td:not(.is-disabled):hover {\n z-index: 1;\n}\n\n.nh-date-table-td:not(.is-disabled):active .nh-date-table-cell {\n transform: translateY(0);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n transition: all 0.1s ease;\n}\n\n/* 选中日期的脉冲动画效果 */\n@keyframes pulse {\n 0% {\n box-shadow: 0 0 0 0 rgba(49, 59, 74, 0.4);\n }\n 70% {\n box-shadow: 0 0 0 6px rgba(49, 59, 74, 0);\n }\n 100% {\n box-shadow: 0 0 0 0 rgba(49, 59, 74, 0);\n }\n}\n\n.nh-date-table-td.is-selected:not(.is-disabled) .nh-date-table-cell {\n animation: pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) 1;\n}\n\n/* 日期选择器边框渐变效果 */\n.nh-date-picker {\n position: relative;\n}\n\n.nh-date-picker:before {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: 8px;\n padding: 1px;\n background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8), rgba(229, 231, 235, 0.5));\n mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n pointer-events: none;\n}\n\n/* 月份切换按钮的点击效果 */\n.nh-date-picker-btn:active {\n transform: translateY(0);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.05);\n background: linear-gradient(to bottom, #f3f4f6, #e5e7eb);\n}\n\n/* 快捷选项的点击效果 */\n.nh-time-shortcut:active {\n background-color: #e5e7eb;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n transform: translateY(1px);\n}\n\n/* 下拉面板的内阴影效果 */\n.nh-time-dropdown:before {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: 10px;\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5);\n pointer-events: none;\n}\n\n/* 日期选择器内容区域的微妙渐变 */\n.nh-date-picker-content {\n background: linear-gradient(135deg, #ffffff, #fafafa);\n}\n\n/* 日期单元格的微妙阴影 */\n.nh-date-table-cell {\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.02);\n}\n\n/* 当前日期的特殊标记 */\n.nh-date-table-td.is-today .nh-date-table-cell:after {\n content: '';\n position: absolute;\n bottom: 3px;\n left: 50%;\n transform: translateX(-50%);\n width: 4px;\n height: 4px;\n background-color: #313B4A;\n border-radius: 50%;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n/* 选择状态完成的微妙动画 */\n@keyframes completeStatus {\n 0% {\n transform: scale(0.9);\n opacity: 0.7;\n }\n 50% {\n transform: scale(1.05);\n opacity: 1;\n }\n 100% {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n.status-text.status-complete {\n animation: completeStatus 0.3s ease-out;\n}\n\n/* 日历标题的微妙阴影 */\n.nh-date-picker-header-label {\n position: relative;\n z-index: 1;\n}\n\n.nh-date-picker-header-label:after {\n content: '';\n position: absolute;\n bottom: -2px;\n left: 0;\n width: 100%;\n height: 4px;\n background: linear-gradient(to right, rgba(49, 59, 74, 0), rgba(49, 59, 74, 0.1), rgba(49, 59, 74, 0));\n border-radius: 2px;\n z-index: -1;\n}\n\n/* 日期范围选择的过渡效果 */\n.nh-date-table-td.is-in-range .nh-date-table-cell {\n transition: background 0.3s ease, box-shadow 0.3s ease, color 0.3s ease;\n}\n\n/* 日期选择器的整体边框效果 */\n.nh-time-picker {\n position: relative;\n overflow: visible;\n}\n\n.nh-time-picker:after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: 10px;\n box-shadow: 0 0 0 1px rgba(229, 231, 235, 0.8);\n pointer-events: none;\n}\n</style>","<template>\n <button\n ref=\"rootEl\"\n class=\"yswitch\"\n :class=\"[\n `yswitch--${size}`,\n { 'yswitch--checked': isChecked, 'yswitch--disabled': disabled, 'yswitch--loading': loading }\n ]\"\n :style=\"switchStyle\"\n role=\"switch\"\n :aria-checked=\"isChecked\"\n :aria-disabled=\"disabled\"\n :disabled=\"disabled || loading\"\n @click=\"onToggle\"\n @keydown.enter.prevent=\"onToggle\"\n @keydown.space.prevent=\"onToggle\"\n >\n <span class=\"yswitch__track\"></span>\n <span class=\"yswitch__thumb\">\n <span v-if=\"loading\" class=\"yswitch__spinner\" aria-hidden=\"true\"></span>\n </span>\n <span v-if=\"showText\" class=\"yswitch__label\" :class=\"{ 'yswitch__label--left': !isChecked, 'yswitch__label--right': isChecked }\">\n {{ isChecked ? activeText : inactiveText }}\n </span>\n </button>\n \n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, onMounted } from 'vue'\n\nexport interface SwitchProps<T = boolean> {\n modelValue?: T\n trueValue?: T\n falseValue?: T\n disabled?: boolean\n loading?: boolean\n size?: 'small' | 'medium' | 'large'\n activeColor?: string\n inactiveColor?: string\n activeText?: string\n inactiveText?: string\n showText?: boolean\n}\n\nconst props = withDefaults(defineProps<SwitchProps>(), {\n modelValue: false,\n trueValue: true,\n falseValue: false,\n disabled: false,\n loading: false,\n size: 'medium',\n activeColor: '#10b981',\n inactiveColor: '#e5e7eb',\n activeText: '开',\n inactiveText: '关',\n showText: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: any]\n 'change': [value: any]\n 'focus': [event: FocusEvent]\n 'blur': [event: FocusEvent]\n}>()\n\nconst rootEl = ref<HTMLButtonElement>()\n\nconst isChecked = computed(() => props.modelValue === props.trueValue)\n\nconst switchStyle = computed(() => {\n const style: Record<string, string> = {}\n // 轨道背景色\n style.background = isChecked.value ? props.activeColor : props.inactiveColor\n return style\n})\n\nfunction onToggle() {\n if (props.disabled || props.loading) return\n const next = isChecked.value ? props.falseValue : props.trueValue\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nonMounted(() => {\n const el = rootEl.value\n if (!el) return\n el.addEventListener('focus', (e) => emit('focus', e as FocusEvent))\n el.addEventListener('blur', (e) => emit('blur', e as FocusEvent))\n})\n\n</script>\n\n<style scoped lang=\"less\">\n.yswitch {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: flex-start;\n border: none;\n cursor: pointer;\n outline: none;\n user-select: none;\n background: #e5e7eb;\n border-radius: 999px;\n transition: background-color 0.2s ease, box-shadow 0.2s ease;\n padding: 0;\n}\n\n.yswitch:focus-visible {\n box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.2);\n}\n\n.yswitch--disabled {\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.yswitch__track {\n position: absolute;\n inset: 0;\n border-radius: 999px;\n}\n\n.yswitch__thumb {\n position: relative;\n background: #ffffff;\n border-radius: 50%;\n transition: transform 0.2s ease;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.yswitch--small {\n width: 36px;\n height: 20px;\n}\n.yswitch--small .yswitch__thumb {\n width: 16px;\n height: 16px;\n transform: translateX(2px);\n}\n.yswitch--small.yswitch--checked .yswitch__thumb {\n transform: translateX(18px);\n}\n\n.yswitch--medium {\n width: 44px;\n height: 24px;\n}\n.yswitch--medium .yswitch__thumb {\n width: 20px;\n height: 20px;\n transform: translateX(2px);\n}\n.yswitch--medium.yswitch--checked .yswitch__thumb {\n transform: translateX(22px);\n}\n\n.yswitch--large {\n width: 45px;\n height: 32px;\n}\n.yswitch--large .yswitch__thumb {\n width: 28px;\n height: 28px;\n transform: translateX(2px);\n}\n.yswitch--large.yswitch--checked .yswitch__thumb {\n transform: translateX(26px);\n}\n\n.yswitch__label {\n margin-left: 8px;\n font-size: 12px;\n color: #4b5563;\n white-space: nowrap;\n}\n\n.yswitch__spinner {\n width: 12px;\n height: 12px;\n border: 2px solid rgba(0,0,0,0.15);\n border-top-color: rgba(0,0,0,0.45);\n border-radius: 50%;\n animation: yswitch-spin 0.8s linear infinite;\n}\n\n@keyframes yswitch-spin {\n to { transform: rotate(360deg); }\n}\n\n/* 暗色主题适配 */\n@media (prefers-color-scheme: dark) {\n .yswitch__label { color: #cbd5e1; }\n}\n\n</style>\n\n\n","<template>\n <div \n ref=\"containerRef\"\n class=\"yimage-container\"\n :class=\"containerClass\"\n >\n <!-- 懒加载占位符 -->\n <div \n v-if=\"!isLoaded && !hasError && !isInView\"\n class=\"yimage-placeholder\"\n :style=\"radiusStyle\"\n >\n <div class=\"yimage-placeholder-content\">\n <svg class=\"yimage-placeholder-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"></path>\n </svg>\n </div>\n </div>\n\n <!-- 加载动画 -->\n <div \n v-if=\"isLoading && !hasError\"\n class=\"yimage-loading\"\n :style=\"radiusStyle\"\n >\n <div class=\"yimage-loading-content\">\n <div class=\"yimage-spinner\"></div>\n </div>\n </div>\n\n <!-- 错误占位图 -->\n <div \n v-if=\"hasError\"\n class=\"yimage-error\"\n :style=\"radiusStyle\"\n @click=\"handleErrorClick\"\n >\n <img \n src=\"https://img.nihaojewelry.com/media/2025/6/27/1938511770352222208.png\" \n alt=\"Error Image\" \n class=\"yimage-error-image\"\n :style=\"radiusStyle\"\n />\n </div>\n\n <!-- 实际图片 -->\n <img\n v-show=\"isLoaded && !hasError\"\n ref=\"imageRef\"\n :src=\"imgSrc\"\n :alt=\"alt\"\n :class=\"imageClass\"\n @load=\"handleLoad\"\n @error=\"handleError\"\n @click.stop=\"handlePreview\"\n @mouseenter=\"onImageMouseEnter\"\n @mouseleave=\"onImageMouseLeave\"\n @mousemove=\"onImageMouseMove\"\n :style=\"imageStyle\"\n />\n \n <!-- 点击区域覆盖层,确保即使图片未完全加载也能点击 -->\n <div\n v-if=\"props.preview && (!isLoaded || isLoading || hasError || !isInView)\"\n class=\"yimage-preview-trigger\"\n @click.stop=\"handlePreview\"\n ></div>\n\n <!-- 大图预览遮罩 -->\n <Teleport to=\"body\" v-if=\"isMounted\">\n <transition name=\"fade\">\n <div \n v-if=\"showPreview\"\n class=\"yimage-preview-mask\"\n @click.self=\"closePreview\"\n @wheel.prevent=\"handleWheel\"\n >\n <div class=\"yimage-preview-content\" \n :class=\"{'is-active': showPreview}\">\n <!-- 预览图片 -->\n <img\n ref=\"previewImageRef\"\n :src=\"resolvedPreviewSrc\"\n :alt=\"alt\"\n class=\"yimage-preview-image\"\n :style=\"{ transform: `scale(${zoomLevel})` }\"\n @click.stop\n />\n </div>\n \n <!-- 图片信息 - 右下角,完整展示链接 -->\n <!-- <div class=\"fixed bottom-4 right-4 bg-black/50 text-white p-3 rounded max-w-md\">\n <p class=\"text-sm\">{{ alt || '图片预览' }}</p>\n <p class=\"text-xs text-gray-300 mt-1 break-all\">{{ previewSrc || props.src }}</p>\n <p class=\"text-xs text-gray-300 mt-1\">缩放: {{ Math.round(zoomLevel * 100) }}%</p>\n </div> -->\n </div>\n </transition>\n </Teleport>\n\n <!-- 鼠标移入侧边预览 -->\n <Teleport to=\"body\" v-if=\"isMounted && props.hoverPreview\">\n <transition name=\"hover-preview-fade\" appear>\n <div\n v-if=\"hoverPreview.visible && hoverPreview.src\"\n class=\"yimage-hover-preview\"\n :style=\"{\n top: hoverPreview.top + 'px',\n left: hoverPreview.left + 'px',\n width: hoverPreview.width + 'px',\n height: hoverPreview.height + 'px',\n }\"\n @mouseenter=\"onPreviewMouseEnter\"\n @mouseleave=\"onPreviewMouseLeave\"\n >\n <img :src=\"hoverPreview.src\" alt=\"图片预览\" />\n </div>\n </transition>\n </Teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'\nimport { Teleport } from 'vue'\nimport type { CSSProperties } from 'vue'\n\ninterface Props {\n src: string\n alt?: string\n width?: string | number\n height?: string | number\n lazy?: boolean\n preview?: boolean\n fit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\n radius?: string | number\n className?: string\n previewSrcList?: string | string[]\n hoverPreview?: boolean // 是否启用鼠标移入侧边显示大图预览\n hoverPreviewWidth?: number // 侧边预览窗口宽度\n hoverPreviewHeight?: number // 侧边预览窗口高度\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n alt: '',\n lazy: true,\n preview: true,\n fit: 'cover',\n radius: '0',\n className: '',\n hoverPreview: false,\n hoverPreviewWidth: 400,\n hoverPreviewHeight: 400\n})\n\nconst emit = defineEmits<{\n load: [event: Event]\n error: [event: Event]\n preview: [src: string]\n}>()\n\n// 响应式状态\nconst containerRef = ref<HTMLElement>()\nconst imageRef = ref<HTMLImageElement>()\nconst previewImageRef = ref<HTMLImageElement>()\nconst isLoaded = ref(false)\nconst isLoading = ref(false)\nconst hasError = ref(false)\nconst isInView = ref(false)\nconst showPreview = ref(false)\nconst imgSrc = ref('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDIwMCAyMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPCEtLSDog4zmma8gLS0+CiAgPHJlY3Qgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIGZpbGw9IiNGM0Y0RjYiLz4KICAKICA8IS0tIOWbvueJh+WbvuaghyAtLT4KICA8cmVjdCB4PSI1MCIgeT0iNDAiIHdpZHRoPSIxMDAiIGhlaWdodD0iODAiIHJ4PSI0IiBmaWxsPSIjRDFENURCIiBzdHJva2U9IiM5Q0EzQUYiIHN0cm9rZS13aWR0aD0iMiIvPgogIAogIDwhLS0g5Zu+54mH5YaF6YOo6KOF6aWwIC0tPgogIDxjaXJjbGUgY3g9IjgwIiBjeT0iNzAiIHI9IjgiIGZpbGw9IiM5Q0EzQUYiLz4KICA8cGF0aCBkPSJNNjAgMTAwIEw5MCA4NSBMMTIwIDk1IEwxNDAgODAiIHN0cm9rZT0iIzlDQTNBRiIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KICAKICA8IS0tIOaWh+WtlyAtLT4KICA8dGV4dCB4PSIxMDAiIHk9IjE2MCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzZCNzI4MCIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBmb250LXdlaWdodD0iNTAwIj4KICAgIEltYWdlIG5vdCBhdmFpbGFibGUKICA8L3RleHQ+Cjwvc3ZnPiA=')\nconst previewSrc = ref('')\nconst zoomLevel = ref(1)\nconst isMounted = ref(false)\n\n// 鼠标移入侧边预览相关状态\ntype HoverPreviewState = {\n visible: boolean\n src: string\n top: number\n left: number\n width: number\n height: number\n isHoveringPreview?: boolean\n}\nconst hoverPreview = ref<HoverPreviewState>({\n visible: false,\n src: '',\n top: 0,\n left: 0,\n width: 400,\n height: 400,\n isHoveringPreview: false\n})\n\n// 用于存储延迟隐藏的 timeout ID\nlet hidePreviewTimeout: ReturnType<typeof setTimeout> | null = null\n\n// 新增:保存原始滚动条状态\nconst originalBodyStyle = ref<{\n overflow: string\n paddingRight: string\n}>({\n overflow: '',\n paddingRight: ''\n})\n\n// 计算属性\nconst RADIUS_TOKEN_MAP: Record<string, string> = {\n none: '0px',\n sm: '0.125rem',\n md: '0.375rem',\n lg: '0.5rem',\n xl: '0.75rem',\n '2xl': '1rem',\n full: '9999px'\n}\n\nconst containerClass = computed(() => props.className || '')\n\nconst radiusValue = computed(() => {\n if (typeof props.radius === 'number') {\n return `${props.radius}px`\n }\n if (typeof props.radius === 'string') {\n if (/(px|%|rem|em)$/.test(props.radius)) {\n return props.radius\n }\n if (RADIUS_TOKEN_MAP[props.radius]) {\n return RADIUS_TOKEN_MAP[props.radius]\n }\n }\n return ''\n})\n\nconst radiusStyle = computed<CSSProperties>(() => {\n if (!radiusValue.value) {\n return {}\n }\n return {\n borderRadius: radiusValue.value\n }\n})\n\nconst imageClass = computed(() => {\n return [\n 'yimage-image',\n props.preview ? 'is-previewable' : ''\n ].filter(Boolean).join(' ')\n})\n\nconst imageStyle = computed(() => {\n const style: CSSProperties = {\n objectFit: props.fit || 'cover',\n backgroundColor: '#fff'\n }\n \n if (props.width) {\n style.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n \n if (props.height) {\n style.height = typeof props.height === 'number' ? `${props.height}px` : props.height\n }\n \n if (radiusValue.value) {\n style.borderRadius = radiusValue.value\n }\n \n return style\n})\n\nconst resolvedPreviewSrc = computed(() => {\n if (previewSrc.value) {\n return previewSrc.value\n }\n if (Array.isArray(props.previewSrcList)) {\n return props.previewSrcList.find(Boolean) || props.src\n }\n return props.previewSrcList || props.src\n})\n\n// 获取鼠标移入预览的图片URL\nconst getHoverPreviewSrc = computed(() => {\n if (Array.isArray(props.previewSrcList)) {\n return props.previewSrcList.find(Boolean) || props.src\n }\n return props.previewSrcList || props.src\n})\n\n// 工具函数\n// 新增:获取滚动条宽度\nconst getScrollbarWidth = () => {\n const scrollDiv = document.createElement('div')\n scrollDiv.style.cssText = 'width: 100px; height: 100px; overflow: scroll; position: absolute; top: -9999px;'\n document.body.appendChild(scrollDiv)\n const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth\n document.body.removeChild(scrollDiv)\n return scrollbarWidth\n}\n\n// 新增:锁定页面滚动\nconst lockBodyScroll = () => {\n // 保存原始样式\n originalBodyStyle.value = {\n overflow: document.body.style.overflow || '',\n paddingRight: document.body.style.paddingRight || ''\n }\n \n // 检查是否有滚动条\n const hasScrollbar = document.body.scrollHeight > window.innerHeight\n \n if (hasScrollbar) {\n const scrollbarWidth = getScrollbarWidth()\n // 设置右边距来防止页面跳动\n document.body.style.paddingRight = `${scrollbarWidth}px`\n }\n \n // 隐藏滚动条\n document.body.style.overflow = 'hidden'\n}\n\n// 新增:解锁页面滚动\nconst unlockBodyScroll = () => {\n // 恢复原始样式\n document.body.style.overflow = originalBodyStyle.value.overflow\n document.body.style.paddingRight = originalBodyStyle.value.paddingRight\n}\n\n// 懒加载逻辑\nlet observer: IntersectionObserver | null = null\n\nconst setupIntersectionObserver = () => {\n if (!props.lazy || !containerRef.value) return\n \n observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n isInView.value = true\n imgSrc.value = props.src\n observer?.unobserve(entry.target)\n }\n })\n },\n {\n rootMargin: '50px'\n }\n )\n \n observer.observe(containerRef.value)\n}\n\n// 事件处理\nconst handleLoad = (event: Event) => {\n isLoaded.value = true\n isLoading.value = false\n hasError.value = false\n emit('load', event)\n}\n\nconst handleError = (event: Event) => {\n hasError.value = true\n isLoading.value = false\n isLoaded.value = false\n emit('error', event)\n}\n\nconst retryLoad = () => {\n hasError.value = false\n isLoading.value = true\n isLoaded.value = false\n \n nextTick(() => {\n if (imageRef.value) {\n imageRef.value.src = props.src\n }\n })\n}\n\nconst getPreviewUrl = () => {\n if (Array.isArray(props.previewSrcList)) {\n return props.previewSrcList.find(Boolean) || props.src\n }\n return props.previewSrcList || props.src\n}\n\nconst handleErrorClick = () => {\n // 如果有预览源,即使加载失败也允许预览\n if (props.preview && (props.previewSrcList || props.src)) {\n handlePreview()\n } else {\n retryLoad()\n }\n}\n\nconst handlePreview = () => {\n if (!props.preview) return\n \n // 重置缩放级别\n zoomLevel.value = 1;\n \n // 使用预览源或原始源\n const previewUrl = getPreviewUrl();\n\n // 如果图片已经在当前 img 元素中加载完成,直接显示预览\n if (imageRef.value && imageRef.value.complete && imageRef.value.naturalWidth > 0) {\n previewSrc.value = previewUrl;\n nextTick(() => {\n showPreview.value = true;\n lockBodyScroll();\n emit('preview', previewUrl);\n });\n return;\n }\n \n // 预加载图片以避免闪烁\n const img = new Image();\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let isHandled = false;\n \n const showPreviewModal = () => {\n if (isHandled) return;\n isHandled = true;\n \n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n \n previewSrc.value = previewUrl;\n nextTick(() => {\n showPreview.value = true;\n lockBodyScroll();\n emit('preview', previewUrl);\n });\n };\n \n // 设置超时,防止预加载卡住\n timeoutId = setTimeout(() => {\n showPreviewModal();\n }, 500);\n \n img.onload = () => {\n showPreviewModal();\n };\n \n img.onerror = () => {\n // 如果预加载失败,仍然尝试显示\n showPreviewModal();\n };\n \n // 如果图片已经在缓存中,complete 会立即为 true\n img.src = previewUrl;\n \n // 检查图片是否已经在缓存中\n if (img.complete) {\n showPreviewModal();\n }\n}\n\nconst closePreview = () => {\n showPreview.value = false;\n \n // 等待过渡动画完成后恢复滚动\n setTimeout(() => {\n unlockBodyScroll();\n }, 300); // 与CSS过渡时间一致\n}\n\nconst handleWheel = (event: WheelEvent) => {\n // 确定缩放方向 (向上滚动放大,向下滚动缩小)\n const zoomDirection = event.deltaY < 0 ? 1 : -1;\n \n // 计算新的缩放级别 (每次缩放10%)\n const zoomStep = 0.1;\n let newZoom = zoomLevel.value + (zoomDirection * zoomStep);\n \n // 限制缩放范围在50%到200%之间\n newZoom = Math.max(0.5, Math.min(2.0, newZoom));\n \n // 更新缩放级别\n zoomLevel.value = newZoom;\n}\n\n// 鼠标移入侧边预览相关函数\nfunction updateImagePreviewPosition(target: EventTarget | null) {\n if (!(target instanceof HTMLElement)) return\n const rect = target.getBoundingClientRect()\n const padding = 12\n const viewportWidth = window.innerWidth || document.documentElement.clientWidth\n const viewportHeight = window.innerHeight || document.documentElement.clientHeight\n let left = rect.right + padding\n if (left + hoverPreview.value.width > viewportWidth - padding) {\n left = rect.left - hoverPreview.value.width - padding\n }\n let top = rect.top\n if (top + hoverPreview.value.height > viewportHeight - padding) {\n top = viewportHeight - hoverPreview.value.height - padding\n }\n if (top < padding) top = padding\n if (left < padding) left = padding\n hoverPreview.value.left = left\n hoverPreview.value.top = top\n}\n\nfunction onImageMouseEnter(event: MouseEvent) {\n if (!props.hoverPreview) return\n // 清除之前的隐藏延迟,确保快速切换时能立即显示\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n hoverPreview.value.isHoveringPreview = false\n hoverPreview.value.src = getHoverPreviewSrc.value\n hoverPreview.value.width = props.hoverPreviewWidth\n hoverPreview.value.height = props.hoverPreviewHeight\n hoverPreview.value.visible = true\n updateImagePreviewPosition(event.currentTarget)\n}\n\nfunction onImageMouseMove(event: MouseEvent) {\n if (!props.hoverPreview) return\n // 如果预览不可见,不更新位置\n if (!hoverPreview.value.visible) return\n // 清除可能的隐藏延迟,确保在鼠标移动时预览保持显示\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n updateImagePreviewPosition(event.currentTarget)\n}\n\nfunction onImageMouseLeave() {\n if (!props.hoverPreview) return\n // 如果鼠标已经在预览区域,不清除\n if (hoverPreview.value.isHoveringPreview) {\n return\n }\n // 清除之前的延迟\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n // 延迟隐藏,给鼠标移到预览区域的时间\n hidePreviewTimeout = setTimeout(() => {\n if (!hoverPreview.value.isHoveringPreview) {\n hoverPreview.value.visible = false\n hoverPreview.value.src = ''\n }\n hidePreviewTimeout = null\n }, 50)\n}\n\n// 鼠标移入预览区域\nfunction onPreviewMouseEnter() {\n if (!props.hoverPreview) return\n // 清除隐藏延迟\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n hoverPreview.value.isHoveringPreview = true\n}\n\n// 鼠标移出预览区域\nfunction onPreviewMouseLeave() {\n if (!props.hoverPreview) return\n hoverPreview.value.isHoveringPreview = false\n hoverPreview.value.visible = false\n hoverPreview.value.src = ''\n // 清除可能存在的延迟\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n}\n\n// 生命周期\nonMounted(() => {\n if (!props.lazy) {\n isInView.value = true\n } else {\n setupIntersectionObserver()\n }\n \n if (isInView.value) {\n isLoading.value = true\n }\n\n // 设置客户端渲染标志\n isMounted.value = true\n})\n\nonUnmounted(() => {\n if (observer) {\n observer.disconnect()\n }\n \n // 确保组件销毁时恢复滚动状态\n if (showPreview.value) {\n unlockBodyScroll()\n }\n \n // 清除可能存在的延迟隐藏\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n})\n\n// 监听src变化\nconst watchSrc = () => {\n if (props.src && isInView.value) {\n isLoading.value = true\n hasError.value = false\n isLoaded.value = false\n }\n}\n\nwatch(() => imgSrc.value, watchSrc)\nwatch(() => props.src, (nv) => {\n imgSrc.value = nv || ''\n})\n// 暴露方法\ndefineExpose({\n retryLoad,\n closePreview\n})\n</script>\n\n<style scoped>\n.yimage-container {\n position: relative;\n display: inline-block;\n overflow: hidden;\n}\n\n.yimage-placeholder,\n.yimage-loading,\n.yimage-error {\n width: 100%;\n height: 100%;\n}\n\n.yimage-placeholder {\n background-color: #e5e7eb;\n animation: yimage-pulse 2s ease-in-out infinite;\n}\n\n.yimage-placeholder-content {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n}\n\n.yimage-placeholder-icon {\n width: 24px;\n height: 24px;\n color: #9ca3af;\n}\n\n.yimage-loading {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(249, 250, 251, 0.9);\n pointer-events: none;\n}\n\n.yimage-loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n}\n\n.yimage-spinner {\n width: 32px;\n height: 32px;\n border: 4px solid rgba(26, 26, 26, 0.2);\n border-top-color: #1A1A1A;\n border-radius: 999px;\n animation: yimage-spin 1s linear infinite;\n}\n\n.yimage-error {\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: #f3f4f6;\n cursor: pointer;\n}\n\n.yimage-error-image {\n width: 70%;\n height: 70%;\n object-fit: contain;\n cursor: pointer;\n}\n\n.yimage-image {\n width: 100%;\n height: 100%;\n display: block;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.yimage-image.is-previewable {\n cursor: pointer;\n}\n\n.yimage-image.is-previewable:hover {\n opacity: 0.9;\n}\n\n.yimage-preview-trigger {\n position: absolute;\n inset: 0;\n cursor: pointer;\n z-index: 10;\n}\n\n.yimage-preview-mask {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.75);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 99999;\n}\n\n.yimage-preview-content {\n position: relative;\n max-width: 64rem;\n max-height: 100%;\n padding: 1rem;\n transform: scale(0.95);\n transition: transform 0.3s ease;\n}\n\n.yimage-preview-content.is-active {\n transform: scale(1);\n}\n\n.yimage-preview-image {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n border-radius: 0.5rem;\n box-shadow: 0 20px 45px rgba(0, 0, 0, 0.35);\n transition: transform 0.2s ease;\n}\n\n/* 过渡动画 */\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 0.3s ease;\n}\n\n.fade-enter-from,\n.fade-leave-to {\n opacity: 0;\n}\n\n/* 基础图片设置 */\nimg {\n display: block;\n -webkit-user-drag: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n}\n\n@keyframes yimage-pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n\n@keyframes yimage-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* 鼠标移入侧边预览样式 */\n.yimage-hover-preview {\n position: fixed;\n z-index: 2000;\n background: #fff;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);\n padding: 8px;\n pointer-events: auto;\n}\n\n.yimage-hover-preview img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n}\n\n.hover-preview-fade-enter-active,\n.hover-preview-fade-leave-active {\n transition: opacity 0.1s ease, transform 0.1s ease;\n}\n\n.hover-preview-fade-enter-from,\n.hover-preview-fade-leave-to {\n opacity: 0;\n transform: scale(0.96);\n}\n</style> ","<template>\n <div class=\"y-dropdown\" ref=\"dropdownRef\">\n <!-- 触发器 -->\n <div \n class=\"y-dropdown__trigger\" \n @mouseenter=\"showDropdown\"\n @mouseleave=\"hideDropdown\"\n >\n <slot name=\"trigger\">\n <button class=\"y-dropdown__button\">\n 下拉菜单\n </button>\n </slot>\n </div>\n\n <!-- 下拉菜单 -->\n <transition name=\"dropdown-fade\" appear>\n <div \n v-show=\"visible\"\n class=\"y-dropdown__menu\"\n :class=\"menuClass\"\n :style=\"menuStyle\"\n @mouseenter=\"showDropdown\"\n @mouseleave=\"hideDropdown\"\n >\n <slot>\n <div class=\"y-dropdown__item\">选项 1</div>\n <div class=\"y-dropdown__item\">选项 2</div>\n <div class=\"y-dropdown__item\">选项 3</div>\n </slot>\n </div>\n </transition>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'\n\ninterface Props {\n trigger?: 'hover' | 'click'\n placement?: 'bottom' | 'top' | 'left' | 'right'\n disabled?: boolean\n menuWidth?: number | string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n trigger: 'hover',\n placement: 'bottom',\n disabled: false,\n menuWidth: undefined\n})\n\nconst visible = ref(false)\nconst dropdownRef = ref<HTMLElement>()\nlet hideTimer: number | null = null\n\n// 计算菜单类名\nconst menuClass = computed(() => {\n return `y-dropdown__menu--${props.placement}`\n})\n\nconst menuStyle = computed(() => {\n if (!props.menuWidth) return {}\n const width =\n typeof props.menuWidth === 'number'\n ? `${props.menuWidth}px`\n : props.menuWidth\n return {\n width,\n minWidth: width,\n maxWidth: width\n }\n})\n\n// 显示下拉菜单\nconst showDropdown = () => {\n console.log('显示下拉菜单', visible.value)\n if (props.disabled) return\n \n // 清除隐藏定时器\n if (hideTimer) {\n clearTimeout(hideTimer)\n hideTimer = null\n }\n \n visible.value = true\n console.log('设置 visible 为 true', visible.value)\n \n // 立即计算位置,确保菜单在显示时就在正确位置\n nextTick(() => {\n updatePosition()\n })\n}\n\n// 隐藏下拉菜单\nconst hideDropdown = () => {\n console.log('隐藏下拉菜单')\n // 添加延迟,给用户时间移入菜单\n hideTimer = setTimeout(() => {\n visible.value = false\n console.log('设置 visible 为 false', visible.value)\n }, 150)\n}\n\n// 更新菜单位置\nconst updatePosition = () => {\n if (!dropdownRef.value) return\n \n const trigger = dropdownRef.value.querySelector('.y-dropdown__trigger') as HTMLElement\n const menu = dropdownRef.value.querySelector('.y-dropdown__menu') as HTMLElement\n \n if (!trigger || !menu) return\n \n // 获取触发器和菜单的尺寸信息\n const triggerRect = trigger.getBoundingClientRect()\n const menuRect = menu.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n \n // 重置位置样式\n menu.style.top = ''\n menu.style.left = ''\n menu.style.right = ''\n menu.style.bottom = ''\n menu.style.transform = ''\n \n let top = 0\n let left = 0\n \n // 根据 placement 设置基本位置\n switch (props.placement) {\n case 'bottom':\n top = triggerRect.height + 4\n left = 0\n break\n \n case 'top':\n top = -(menuRect.height + 4)\n left = 0\n break\n \n case 'right':\n top = 0\n left = triggerRect.width + 4\n break\n \n case 'left':\n top = 0\n left = -(menuRect.width + 4)\n break\n }\n \n // 计算相对于视口的绝对位置\n let absoluteTop = triggerRect.top + top\n let absoluteLeft = triggerRect.left + left\n \n // 水平边界检测和调整\n if (props.placement === 'bottom' || props.placement === 'top') {\n const menuWidth = menuRect.width || 260 // 使用实际菜单宽度\n \n // 如果菜单会超出右边界,向左偏移保持10px边距\n if (absoluteLeft + menuWidth > viewportWidth - 10) {\n absoluteLeft = viewportWidth - menuWidth - 10\n }\n \n // 如果菜单会超出左边界,向右偏移保持10px边距\n if (absoluteLeft < 10) {\n absoluteLeft = 10\n }\n }\n \n // 垂直边界检测和调整\n if (props.placement === 'left' || props.placement === 'right') {\n const menuHeight = menuRect.height || 200 // 使用实际菜单高度\n \n // 如果菜单会超出下边界,向上偏移保持10px边距\n if (absoluteTop + menuHeight > viewportHeight - 10) {\n absoluteTop = viewportHeight - menuHeight - 10\n }\n \n // 如果菜单会超出上边界,向下偏移保持10px边距\n if (absoluteTop < 10) {\n absoluteTop = 10\n }\n }\n \n // 应用位置(使用固定定位的绝对坐标)\n menu.style.top = `${absoluteTop}px`\n menu.style.left = `${absoluteLeft}px`\n}\n\n// 点击外部关闭\nconst handleClickOutside = (event: MouseEvent) => {\n if (props.trigger === 'click' && dropdownRef.value && !dropdownRef.value.contains(event.target as Node)) {\n visible.value = false\n }\n}\n\n// 窗口大小变化时重新计算位置\nconst handleResize = () => {\n if (visible.value) {\n updatePosition()\n }\n}\n\nonMounted(() => {\n if (props.trigger === 'click') {\n document.addEventListener('click', handleClickOutside)\n }\n // 监听窗口大小变化\n window.addEventListener('resize', handleResize)\n // 监听滚动事件\n window.addEventListener('scroll', handleResize)\n})\n\nonUnmounted(() => {\n if (props.trigger === 'click') {\n document.removeEventListener('click', handleClickOutside)\n }\n // 清理定时器\n if (hideTimer) {\n clearTimeout(hideTimer)\n }\n // 清理事件监听器\n window.removeEventListener('resize', handleResize)\n window.removeEventListener('scroll', handleResize)\n})\n\nwatch(\n () => props.menuWidth,\n () => {\n if (visible.value) {\n nextTick(() => {\n updatePosition()\n })\n }\n }\n)\n</script>\n\n<style scoped lang=\"less\">\n.y-dropdown {\n position: relative;\n display: inline-block;\n\n &__trigger {\n cursor: pointer;\n }\n\n &__button {\n height: 44px;\n padding: 0 16px;\n border: 1px solid #e2e8f0;\n border-radius: 10px;\n background: #fff;\n color: #0b1a29;\n cursor: pointer;\n font-size: 14px;\n transition: box-shadow 0.2s ease, border-color 0.2s ease;\n\n &:hover {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59,130,246,0.15);\n }\n }\n\n &__menu {\n position: fixed;\n z-index: 9999;\n min-width: 100px;\n max-width: 300px;\n background: #fff;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n box-shadow: 0 8px 20px rgba(2,6,23,0.15);\n white-space: nowrap;\n\n &--bottom {\n top: calc(100% + 4px);\n left: 0;\n }\n\n &--top {\n bottom: calc(100% + 4px);\n left: 0;\n }\n\n &--left {\n top: 0;\n right: calc(100% + 4px);\n }\n\n &--right {\n top: 0;\n left: calc(100% + 4px);\n }\n }\n\n &__item {\n height: 36px;\n padding: 0 12px;\n color: #0b1a29;\n cursor: pointer;\n display: flex;\n align-items: center;\n font-size: 13px;\n transition: background-color 0.2s ease, color 0.2s ease;\n\n &:hover {\n background-color: #F6F6F7;\n color: #303061;\n }\n\n &:not(:last-child) {\n border-bottom: 1px solid #f1f5f9;\n }\n }\n}\n\n// 动画效果 - 只使用透明度变化,不改变位置\n.dropdown-fade-enter-active {\n transition: opacity 0.15s ease-out;\n}\n\n.dropdown-fade-leave-active {\n transition: opacity 0.1s ease-in;\n}\n\n.dropdown-fade-enter-from,\n.dropdown-fade-leave-to {\n opacity: 0;\n}\n\n.dropdown-fade-enter-to,\n.dropdown-fade-leave-from {\n opacity: 1;\n}\n\n// 暗色主题支持\n@media (prefers-color-scheme: dark) {\n .y-dropdown__button {\n background: rgba(2,6,23,0.4);\n border-color: rgba(148,163,184,0.18);\n color: #e5eef7;\n }\n \n .y-dropdown__menu {\n background: rgba(2,6,23,0.9);\n border-color: rgba(148,163,184,0.18);\n }\n \n .y-dropdown__item {\n color: #e5eef7;\n \n &:hover {\n background-color: #F6F6F7;\n color: #303061;\n }\n \n &:not(:last-child) {\n border-bottom-color: rgba(148,163,184,0.1);\n }\n }\n}\n</style>\n","<template>\r\n <teleport to=\"body\">\r\n <div\r\n v-show=\"visible\"\r\n class=\"y-drawer-root\"\r\n role=\"dialog\"\r\n :aria-modal=\"true\"\r\n :aria-hidden=\"!visible\"\r\n :style=\"{ zIndex: String(zIndex) }\"\r\n >\r\n <div\r\n class=\"y-drawer-mask\"\r\n @click=\"onMaskClick\"\r\n ></div>\r\n\r\n <transition :name=\"transitionName\">\r\n <div\r\n v-show=\"visible\"\r\n ref=\"panelRef\"\r\n class=\"y-drawer-panel\"\r\n :class=\"[\r\n `is-${placement}`,\r\n roundedClass,\r\n ]\"\r\n :style=\"panelStyle\"\r\n @keydown.esc.prevent.stop=\"onEsc\"\r\n tabindex=\"-1\"\r\n >\r\n <div v-if=\"showHeader\" class=\"y-drawer-header\">\r\n <div class=\"y-drawer-title\">{{ title }}</div>\r\n <button\r\n v-if=\"closable\"\r\n type=\"button\"\r\n class=\"y-drawer-close\"\r\n aria-label=\"Close\"\r\n @click=\"close\"\r\n >\r\n ✕\r\n </button>\r\n </div>\r\n\r\n <div class=\"y-drawer-body\">\r\n <slot />\r\n </div>\r\n\r\n <div v-if=\"$slots.footer\" class=\"y-drawer-footer\">\r\n <slot name=\"footer\" />\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n </teleport>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue'\r\n\r\nconst props = withDefaults(defineProps<{\r\n modelValue?: boolean\r\n placement?: 'right' | 'bottom'\r\n width?: string | number\r\n height?: string | number\r\n title?: string\r\n closable?: boolean\r\n maskClosable?: boolean\r\n zIndex?: number\r\n showHeader?: boolean\r\n}>(), {\r\n modelValue: false,\r\n placement: 'right',\r\n width: '420px',\r\n height: '60vh',\r\n title: '',\r\n closable: true,\r\n maskClosable: true,\r\n zIndex: 100000,\r\n showHeader: true,\r\n})\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: boolean): void\r\n (e: 'open'): void\r\n (e: 'close'): void\r\n}>()\r\n\r\nconst visible = computed({\r\n get: () => props.modelValue,\r\n set: (v: boolean) => emit('update:modelValue', v),\r\n})\r\n\r\nconst panelRef = ref<HTMLElement | null>(null)\r\n\r\nconst transitionName = computed(() => props.placement === 'right' ? 'drawer-slide-right' : 'drawer-slide-bottom')\r\n\r\nconst roundedClass = computed(() => props.placement === 'right' ? 'rounded-left' : 'rounded-top')\r\n\r\nconst panelStyle = computed(() => {\r\n const style: Record<string, string> = {}\r\n if (props.placement === 'right') {\r\n style.width = typeof props.width === 'number' ? `${props.width}px` : String(props.width)\r\n style.height = '100%'\r\n style.right = '0'\r\n style.top = '0'\r\n } else {\r\n style.height = typeof props.height === 'number' ? `${props.height}px` : String(props.height)\r\n style.width = '100%'\r\n style.bottom = '0'\r\n style.left = '0'\r\n }\r\n return style\r\n})\r\n\r\nfunction onMaskClick() {\r\n if (!props.maskClosable) return\r\n close()\r\n}\r\n\r\nfunction close() {\r\n if (!visible.value) return\r\n visible.value = false\r\n emit('close')\r\n}\r\n\r\nfunction onEsc() {\r\n if (props.closable) close()\r\n}\r\n\r\nfunction onKeydown(e: KeyboardEvent) {\r\n if (e.key === 'Escape') onEsc()\r\n}\r\n\r\nwatch(() => props.modelValue, (v) => {\r\n if (v) {\r\n emit('open')\r\n // 聚焦,便于 Esc 关闭\r\n requestAnimationFrame(() => panelRef.value?.focus())\r\n document.addEventListener('keydown', onKeydown)\r\n document.body.style.overflow = 'hidden'\r\n } else {\r\n document.removeEventListener('keydown', onKeydown)\r\n document.body.style.overflow = ''\r\n }\r\n})\r\n\r\nonMounted(() => {\r\n if (props.modelValue) {\r\n document.addEventListener('keydown', onKeydown)\r\n document.body.style.overflow = 'hidden'\r\n }\r\n})\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener('keydown', onKeydown)\r\n document.body.style.overflow = ''\r\n})\r\n</script>\r\n\r\n<style scoped>\r\n.y-drawer-root {\r\n position: fixed;\r\n inset: 0;\r\n}\r\n\r\n.y-drawer-mask {\r\n position: absolute;\r\n inset: 0;\r\n background: rgba(2, 6, 23, 0.55);\r\n backdrop-filter: blur(2px);\r\n}\r\n\r\n.y-drawer-panel {\r\n position: absolute;\r\n display: flex;\r\n flex-direction: column;\r\n background: #ffffff;\r\n border: 1px solid rgba(15, 23, 42, 0.06);\r\n box-shadow: 0 12px 40px rgba(2, 6, 23, 0.18);\r\n}\r\n\r\n/* 圆角根据拉出方向,仅对露出的边做圆角 */\r\n.rounded-left { border-radius: 12px 0 0 12px; }\r\n.rounded-top { border-radius: 12px 12px 0 0; }\r\n\r\n.y-drawer-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 14px 16px;\r\n border-bottom: 1px solid rgba(15, 23, 42, 0.06);\r\n}\r\n\r\n.y-drawer-title {\r\n font-size: 16px;\r\n font-weight: 600;\r\n color: #0b1a29;\r\n}\r\n\r\n.y-drawer-close {\r\n appearance: none;\r\n border: none;\r\n background: transparent;\r\n color: #334155;\r\n font-size: 16px;\r\n line-height: 1;\r\n cursor: pointer;\r\n padding: 6px;\r\n border-radius: 8px;\r\n}\r\n.y-drawer-close:hover { background: rgba(15,23,42,0.05); }\r\n\r\n.y-drawer-body {\r\n padding: 16px;\r\n overflow: auto;\r\n}\r\n\r\n.y-drawer-footer {\r\n padding: 12px 16px;\r\n border-top: 1px solid rgba(15, 23, 42, 0.06);\r\n}\r\n\r\n/* 进入/离场动画:右侧 */\r\n.drawer-slide-right-enter-from,\r\n.drawer-slide-right-leave-to { transform: translateX(100%); opacity: 0.98; }\r\n.drawer-slide-right-enter-active,\r\n.drawer-slide-right-leave-active { transition: transform 220ms ease, opacity 220ms ease; }\r\n.drawer-slide-right-enter-to,\r\n.drawer-slide-right-leave-from { transform: translateX(0%); opacity: 1; }\r\n\r\n/* 进入/离场动画:底部 */\r\n.drawer-slide-bottom-enter-from,\r\n.drawer-slide-bottom-leave-to { transform: translateY(100%); opacity: 0.98; }\r\n.drawer-slide-bottom-enter-active,\r\n.drawer-slide-bottom-leave-active { transition: transform 220ms ease, opacity 220ms ease; }\r\n.drawer-slide-bottom-enter-to,\r\n.drawer-slide-bottom-leave-from { transform: translateY(0%); opacity: 1; }\r\n\r\n/* 位置占位 */\r\n.y-drawer-panel.is-right { right: 0; top: 0; bottom: 0; }\r\n.y-drawer-panel.is-bottom { left: 0; right: 0; bottom: 0; }\r\n\r\n@media (prefers-color-scheme: dark) {\r\n .y-drawer-panel {\r\n background: rgba(15, 23, 42, 0.7);\r\n border-color: rgba(148, 163, 184, 0.12);\r\n box-shadow: 0 12px 40px rgba(2, 6, 23, 0.5);\r\n }\r\n .y-drawer-title { color: #e5eef7; }\r\n .y-drawer-close { color: #cbd5e1; }\r\n .y-drawer-close:hover { background: rgba(148,163,184,0.12); }\r\n}\r\n</style>\r\n\r\n\r\n","<template>\n <div\n class=\"ytree-node\"\n :class=\"{\n 'ytree-node--current': isCurrent,\n 'ytree-node--highlight': isHighlighted,\n }\"\n >\n <div\n class=\"ytree-node__content\"\n :class=\"{ 'is-child-style': isChildStyle }\"\n :style=\"{ paddingLeft: `${paddingLeft}px` }\"\n :data-level=\"nodeDepth\"\n @click=\"handleNodeClick(props.node, props.node, null, props.rootNode)\"\n @contextmenu=\"handleNodeContextMenu($event, props.node, props.node, null)\"\n >\n <!-- 展开/收起图标 -->\n <span\n v-if=\"hasNodeChildren\"\n class=\"ytree-node__expand-icon\"\n :class=\"{ 'is-expanded': isExpanded }\"\n @click.stop=\"handleExpandClick(props.node)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <path\n d=\"M4.5 3L7.5 6L4.5 9\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n <span v-else class=\"ytree-node__expand-icon--empty\"></span>\n\n <!-- 复选框 -->\n <span\n v-if=\"showCheckbox\"\n class=\"ytree-node__checkbox\"\n :class=\"{\n 'is-checked': isChecked,\n 'is-indeterminate': isIndeterminate,\n }\"\n @click.stop=\"handleCheckClick(props.node)\"\n >\n <svg\n v-if=\"isChecked\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n >\n <path\n d=\"M2 6L4.5 8.5L10 3\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <svg\n v-else-if=\"isIndeterminate\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n >\n <path\n d=\"M2 6L10 6\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </span>\n\n <!-- 节点图标 -->\n <span\n v-if=\"iconClass\"\n class=\"ytree-node__icon\"\n :class=\"iconClass\"\n ></span>\n\n <!-- 节点头像/图标 -->\n <img\n class=\"ytree-node__avatar\"\n :src=\"nodeIcon\"\n :alt=\"isEmployee ? 'person' : 'dept'\"\n />\n\n <!-- 节点标签 -->\n <span\n class=\"ytree-node__label\"\n :class=\"{ 'is-employee': isEmployee }\"\n >\n {{ nodeLabel }}\n </span>\n\n <!-- 自定义节点内容插槽 -->\n <div class=\"ytree-node__custom-content\">\n <slot\n name=\"node-content\"\n :node=\"props.node\"\n :is-current=\"isCurrent\"\n :is-expanded=\"isExpanded\"\n :has-children=\"hasNodeChildren\"\n />\n </div>\n </div>\n\n <!-- 子节点 - 递归渲染 -->\n <transition name=\"ytree-node\">\n <div\n v-if=\"hasNodeChildren && isExpanded\"\n class=\"ytree-node__children\"\n >\n <YTreeNode\n v-for=\"child in nodeChildren\"\n :key=\"getNodeKey(child)\"\n :node=\"child\"\n :root-node=\"rootNode\"\n :level=\"level + 1\"\n :show-checkbox=\"showCheckbox\"\n :icon-class=\"iconClass\"\n :dept-icon-url=\"deptIconUrl\"\n :person-icon-url=\"personIconUrl\"\n :button-icon-url=\"buttonIconUrl\"\n :child-style-level=\"childStyleLevel\"\n :child-style-icon-url=\"childStyleIconUrl\"\n :enable-child-style-custom-click=\"enableChildStyleCustomClick\"\n :disabled=\"disabled\"\n :expand-on-click-node=\"expandOnClickNode\"\n >\n <template #node-content=\"slotProps\">\n <slot name=\"node-content\" v-bind=\"slotProps\" />\n </template>\n </YTreeNode>\n </div>\n </transition>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { inject, computed } from \"vue\";\nimport type { TreeNode } from \"./ytree.vue\";\nimport YTreeNode from \"./ytree-node.vue\";\n\ninterface Props {\n node: TreeNode;\n rootNode: TreeNode;\n level: number;\n showCheckbox?: boolean;\n iconClass?: string;\n deptIconUrl?: string;\n personIconUrl?: string;\n buttonIconUrl?: string;\n childStyleLevel?: number;\n childStyleIconUrl?: string;\n enableChildStyleCustomClick?: boolean;\n disabled?: boolean;\n expandOnClickNode?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n level: 1,\n showCheckbox: false,\n iconClass: \"\",\n deptIconUrl: \"\",\n personIconUrl: \"\",\n buttonIconUrl: \"\",\n childStyleLevel: undefined,\n childStyleIconUrl: \"\",\n enableChildStyleCustomClick: false,\n disabled: false,\n expandOnClickNode: true,\n});\n\n// 从父组件注入的方法和状态\nconst treeStore = inject<any>(\"treeStore\");\nconst getNodeKey = inject<(node: TreeNode) => string | number>(\"getNodeKey\");\nconst getNodeLabel = inject<(node: TreeNode) => string>(\"getNodeLabel\");\nconst getNodeChildren = inject<(node: TreeNode) => TreeNode[]>(\"getNodeChildren\");\nconst hasChildren = inject<(node: TreeNode) => boolean>(\"hasChildren\");\nconst isEmployeeNode = inject<(node: TreeNode) => boolean>(\"isEmployeeNode\");\nconst getNodeIcon = inject<(node: TreeNode, rootNode?: TreeNode) => string>(\"getNodeIcon\");\nconst getNodeDepth = inject<(node: TreeNode, targetNode: TreeNode) => number>(\"getNodeDepth\");\nconst isChildStyleNode = inject<(node: TreeNode, rootNode: TreeNode) => boolean>(\"isChildStyleNode\");\nconst isNodeExpanded = inject<(node: TreeNode) => boolean>(\"isNodeExpanded\");\nconst isNodeChecked = inject<(node: TreeNode) => boolean>(\"isNodeChecked\");\nconst isNodeIndeterminate = inject<(node: TreeNode) => boolean>(\"isNodeIndeterminate\");\nconst isNodeCurrent = inject<(node: TreeNode) => boolean>(\"isNodeCurrent\");\nconst isNodeHighlighted = inject<(node: TreeNode) => boolean>(\"isNodeHighlighted\");\nconst handleExpandClick = inject<(node: TreeNode) => void>(\"handleExpandClick\");\nconst handleCheckClick = inject<(node: TreeNode) => void>(\"handleCheckClick\");\nconst handleNodeClick = inject<(data: TreeNode, node: any, nodeComponent: any, rootNode?: TreeNode) => void>(\"handleNodeClick\");\nconst handleNodeContextMenu = inject<(event: Event, data: TreeNode, node: any, nodeComponent: any) => void>(\"handleNodeContextMenu\");\n\n// 使用 computed 缓存节点状态,减少重复计算\nconst nodeKey = computed(() => getNodeKey(props.node));\nconst nodeLabel = computed(() => getNodeLabel(props.node));\nconst nodeIcon = computed(() => getNodeIcon(props.node, props.rootNode));\nconst nodeDepth = computed(() => getNodeDepth(props.rootNode, props.node));\nconst isExpanded = computed(() => isNodeExpanded(props.node));\nconst isChecked = computed(() => isNodeChecked(props.node));\nconst isIndeterminate = computed(() => isNodeIndeterminate(props.node));\nconst isCurrent = computed(() => isNodeCurrent(props.node));\nconst isHighlighted = computed(() => isNodeHighlighted(props.node));\nconst hasNodeChildren = computed(() => hasChildren(props.node));\nconst nodeChildren = computed(() => getNodeChildren(props.node));\nconst isChildStyle = computed(() => isChildStyleNode(props.node, props.rootNode));\nconst isEmployee = computed(() => isEmployeeNode(props.node));\n\n// 计算 paddingLeft,每级增加 16px (14px 图标 + 2px 间距)\nconst paddingLeft = computed(() => {\n if (props.level === 1) {\n return 8;\n }\n // 第一级是 8px,之后每级增加 16px (14px 图标宽度 + 2px 间距)\n return 8 + (props.level - 1) * 16;\n});\n</script>\n\n<style scoped>\n/* 树节点样式 */\n.ytree-node {\n position: relative;\n}\n\n.ytree-node__content {\n display: flex;\n align-items: center;\n height: 24px;\n padding: 0 6px;\n cursor: pointer;\n transition: background-color 0.2s ease, color 0.2s ease;\n border-radius: 4px;\n margin: 0.5px 0;\n}\n\n.ytree-node__content:hover:not(.ytree-node--disabled .ytree-node__content) {\n background-color: #f6f6f7;\n color: #303061;\n}\n\n.ytree-node--current > .ytree-node__content {\n background-color: #f0f0f0;\n font-weight: bold;\n}\n\n/* 高亮节点样式(仅文本变绿,无背景) */\n.ytree-node--highlight > .ytree-node__content .ytree-node__label {\n color: #10b981 !important;\n font-weight: 600;\n}\n\n.ytree-node--disabled .ytree-node__content {\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n.ytree-node__expand-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n min-width: 14px;\n flex-shrink: 0;\n margin-right: 2px;\n color: #6b7280;\n transition: transform 0.2s ease, color 0.2s ease;\n cursor: pointer;\n border-radius: 2px;\n}\n\n.ytree-node__expand-icon svg {\n width: 12px;\n height: 12px;\n flex-shrink: 0;\n}\n\n.ytree-node__expand-icon:hover {\n color: #374151;\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.ytree-node__expand-icon.is-expanded {\n transform: rotate(90deg);\n}\n\n.ytree-node__expand-icon--empty {\n width: 14px;\n min-width: 14px;\n height: 14px;\n flex-shrink: 0;\n margin-right: 2px;\n}\n\n.ytree-node__checkbox {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 10px;\n height: 10px;\n min-width: 10px;\n flex-shrink: 0;\n margin-right: 4px;\n border: 1px solid #d1d5db;\n border-radius: 2px;\n background: #ffffff;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.ytree-node__checkbox svg {\n width: 12px;\n height: 12px;\n flex-shrink: 0;\n}\n\n.ytree-node__checkbox.is-checked {\n background-color: #3f8682;\n color: #ffffff;\n}\n\n.ytree-node__checkbox.is-indeterminate {\n background-color: #3f8682;\n border-color: #3f8682;\n color: #ffffff;\n}\n\n.ytree-node__checkbox.is-disabled {\n background-color: #f9fafb;\n border-color: #e5e7eb;\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n.ytree-node__icon {\n margin-right: 4px;\n font-size: 12px;\n color: #6b7280;\n flex-shrink: 0;\n}\n\n.ytree-node__label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n line-height: 1.4;\n font-weight: 500;\n}\n\n/* 子样式节点特殊样式 - 通过配置的级别动态应用 */\n.ytree-node__content.is-child-style .ytree-node__label {\n font-weight: 500 !important;\n color: #636363 !important;\n font-size: 12px !important;\n}\n\n/* 员工节点颜色样式 */\n.ytree-node__label.is-employee {\n font-weight: 500;\n color: #777777;\n font-size: 12px;\n}\n\n/* 高亮覆盖(优先级更高,放在子样式规则之后) */\n.ytree-node.ytree-node--highlight > .ytree-node__content .ytree-node__label,\n.ytree-node.ytree-node--highlight > .ytree-node__content.is-child-style .ytree-node__label {\n color: #00a761 !important;\n font-weight: bold !important;\n}\n\n.ytree-node__custom-content {\n display: flex;\n align-items: center;\n margin-left: auto;\n flex-shrink: 0;\n}\n\n.ytree-node__avatar {\n width: 14px;\n height: 14px;\n min-width: 14px;\n flex-shrink: 0;\n margin-right: 4px;\n border-radius: 2px;\n object-fit: cover;\n}\n\n.ytree-node__label.is-current {\n font-weight: 500;\n}\n\n.ytree-node__children {\n position: relative;\n}\n\n/* 过渡动画 */\n.ytree-node-enter-active,\n.ytree-node-leave-active {\n transition: all 0.3s ease;\n overflow: hidden;\n}\n\n.ytree-node-enter-from,\n.ytree-node-leave-to {\n opacity: 0;\n max-height: 0;\n}\n\n.ytree-node-enter-to,\n.ytree-node-leave-from {\n opacity: 1;\n max-height: 1000px;\n}\n\n/* 暗色主题支持 */\n@media (prefers-color-scheme: dark) {\n .ytree-node__content {\n color: #e5eef7;\n }\n\n .ytree-node__content:hover:not(.ytree-node--disabled .ytree-node__content) {\n background-color: rgba(2, 6, 23, 0.4);\n color: #e5eef7;\n }\n\n .ytree-node--current .ytree-node__content {\n background-color: rgba(59, 130, 246, 0.2);\n color: #60a5fa;\n }\n\n .ytree-node--disabled .ytree-node__content {\n color: #9ca3af;\n }\n\n .ytree-node__expand-icon {\n color: #9ca3af;\n }\n\n .ytree-node__expand-icon:hover {\n color: #cbd5e1;\n background-color: rgba(148, 163, 184, 0.1);\n }\n\n .ytree-node__checkbox {\n background: rgba(2, 6, 23, 0.4);\n border-color: rgba(148, 163, 184, 0.3);\n }\n\n .ytree-node__checkbox:hover:not(.is-disabled) {\n border-color: #60a5fa;\n background-color: rgba(59, 130, 246, 0.1);\n }\n\n .ytree-node__icon {\n color: #9ca3af;\n }\n\n /* 子样式节点暗色主题样式 */\n .ytree-node__content.is-child-style .ytree-node__label {\n color: #9ca3af !important;\n }\n}\n</style>\n\n","<template>\n <div\n class=\"ytree\"\n :class=\"[`ytree--${size}`, { 'ytree--disabled': disabled }]\"\n >\n <div class=\"ytree__container\">\n <YTreeNode\n v-for=\"node in treeData\"\n :key=\"getNodeKey(node)\"\n :node=\"node\"\n :root-node=\"node\"\n :level=\"1\"\n :show-checkbox=\"showCheckbox\"\n :icon-class=\"iconClass\"\n :dept-icon-url=\"deptIconUrl\"\n :person-icon-url=\"personIconUrl\"\n :button-icon-url=\"buttonIconUrl\"\n :child-style-level=\"childStyleLevel\"\n :child-style-icon-url=\"childStyleIconUrl\"\n :enable-child-style-custom-click=\"enableChildStyleCustomClick\"\n :disabled=\"disabled\"\n :expand-on-click-node=\"expandOnClickNode\"\n >\n <template #node-content=\"slotProps\">\n <slot name=\"node-content\" v-bind=\"slotProps\" />\n </template>\n </YTreeNode>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, provide, watch, markRaw, shallowRef } from \"vue\";\nimport YTreeNode from './ytree-node.vue'\n\n// 节点图标地址(部门/人员)\nconst DEPT_ICON_URL =\n \"https://image.nhdropshipping.com/fit-in/500x500/filters:format(webp)/media/2025/10/17/1979094146203385856/32.png\";\nconst PERSON_ICON_URL =\n \"https://image.nhdropshipping.com/fit-in/500x500/filters:format(webp)/media/2025/10/17/1979095296159907840/32.png\";\n\nexport interface TreeNode {\n id?: string | number;\n label: string;\n children?: TreeNode[];\n disabled?: boolean;\n isLeaf?: boolean;\n expanded?: boolean;\n checked?: boolean;\n indeterminate?: boolean;\n data?: any;\n [key: string]: any;\n}\n\nexport interface TreeProps {\n data?: TreeNode[];\n emptyText?: string;\n nodeKey?: string;\n props?: {\n children?: string;\n label?: string;\n disabled?: string;\n isLeaf?: string;\n };\n renderAfterExpand?: boolean;\n defaultExpandAll?: boolean;\n defaultExpandedKeys?: (string | number)[];\n defaultCheckedKeys?: (string | number)[];\n defaultSelectedKeys?: (string | number)[];\n checkStrictly?: boolean;\n checkOnClickNode?: boolean;\n checkDescendants?: boolean;\n autoExpandParent?: boolean;\n defaultChecked?: boolean;\n filterNodeMethod?: (value: any, data: TreeNode, node: any) => boolean;\n lazy?: boolean;\n load?: (node: TreeNode, resolve: (data: TreeNode[]) => void) => void;\n renderContent?: (h: any, node: TreeNode, data: any, store: any) => any;\n highlightCurrent?: boolean;\n expandOnClickNode?: boolean;\n currentNodeKey?: string | number;\n accordion?: boolean;\n indent?: number;\n iconClass?: string;\n showCheckbox?: boolean;\n draggable?: boolean;\n allowDrag?: (node: TreeNode) => boolean;\n allowDrop?: (\n draggingNode: TreeNode,\n dropNode: TreeNode,\n type: \"prev\" | \"inner\" | \"next\"\n ) => boolean;\n size?: \"small\" | \"medium\" | \"large\";\n disabled?: boolean;\n deptIconUrl?: string;\n personIconUrl?: string;\n buttonIconUrl?: string;\n // 是否启用第四级节点特殊处理(已废弃)\n enableFourthLevelSpecialHandling?: boolean;\n // 从第几级开始不进行任何\"默认/自动展开\"的级别阈值(如传 4 表示第4级及其以下不自动展开)\n restrictAutoExpandFromLevel?: number | undefined;\n // 子样式节点配置:定义第几级节点为子样式节点及其图标\n childStyleLevel?: number | undefined;\n childStyleIconUrl?: string;\n // 是否启用子样式节点自定义点击事件(如果启用,子样式节点点击会触发 child-node-click 事件而不是 node-click)\n enableChildStyleCustomClick?: boolean;\n}\n\nconst props = withDefaults(defineProps<TreeProps>(), {\n data: () => [],\n emptyText: \"暂无数据\",\n nodeKey: \"id\",\n props: () => ({\n children: \"children\",\n label: \"label\",\n disabled: \"disabled\",\n isLeaf: \"isLeaf\",\n }),\n renderAfterExpand: true,\n defaultExpandAll: false,\n defaultExpandedKeys: () => [],\n defaultCheckedKeys: () => [],\n defaultSelectedKeys: () => [],\n checkStrictly: false,\n checkOnClickNode: false,\n checkDescendants: true,\n autoExpandParent: true,\n defaultChecked: false,\n lazy: false,\n highlightCurrent: false,\n expandOnClickNode: true,\n accordion: false,\n indent: 18,\n iconClass: \"\",\n showCheckbox: false,\n draggable: false,\n size: \"medium\",\n disabled: false,\n deptIconUrl: \"\",\n personIconUrl: \"\",\n buttonIconUrl: \"\",\n enableFourthLevelSpecialHandling: false,\n restrictAutoExpandFromLevel: undefined,\n childStyleLevel: undefined,\n childStyleIconUrl: \"\",\n enableChildStyleCustomClick: false,\n});\n\nconst emit = defineEmits<{\n \"node-click\": [data: TreeNode, node: any, nodeComponent: any];\n \"node-contextmenu\": [\n event: Event,\n data: TreeNode,\n node: any,\n nodeComponent: any\n ];\n \"check-change\": [data: TreeNode, checked: boolean, indeterminate: boolean];\n check: [data: TreeNode, checked: any, indeterminate: any];\n \"current-change\": [data: TreeNode, node: any];\n \"node-expand\": [data: TreeNode, node: any, nodeComponent: any];\n \"node-collapse\": [data: TreeNode, node: any, nodeComponent: any];\n \"node-drag-start\": [node: TreeNode, event: DragEvent];\n \"node-drag-enter\": [\n draggingNode: TreeNode,\n dropNode: TreeNode,\n event: DragEvent\n ];\n \"node-drag-leave\": [\n draggingNode: TreeNode,\n dropNode: TreeNode,\n event: DragEvent\n ];\n \"node-drag-over\": [\n draggingNode: TreeNode,\n dropNode: TreeNode,\n event: DragEvent\n ];\n \"node-drag-end\": [\n draggingNode: TreeNode,\n dropNode: TreeNode,\n event: DragEvent\n ];\n \"node-drop\": [\n draggingNode: TreeNode,\n dropNode: TreeNode,\n dropType: \"before\" | \"after\" | \"inner\",\n event: DragEvent\n ];\n \"checked-keys-change\": [keys: Array<string | number>];\n \"child-node-click\": [data: TreeNode, node: any, nodeComponent: any];\n}>();\n\n// 计算属性\nconst treeData = computed(() => {\n // 移除生产环境的 console.log 以提升性能\n // console.log(\"ytree 组件接收到的数据:\", props.data);\n return props.data || [];\n});\n// const nodeProps = computed(() => props.props || {});\n\n// 提供全局状态\nconst store = ref({\n currentNode: null as TreeNode | null,\n currentKey: null as string | number | null,\n checkedKeys: new Set<string | number>(),\n expandedKeys: new Set<string | number>(),\n selectedKeys: new Set<string | number>(),\n highlightedKeys: new Set<string | number>(),\n});\n\n// 响应式版本号,用于触发 checkedKeys 变化的响应式更新\n// 由于 Vue 3 无法追踪 Set 内部变化,我们需要这个版本号来触发更新\nconst checkedKeysVersion = ref(0);\n\n// 触发 checkedKeys 更新的辅助函数\nfunction triggerCheckedKeysUpdate() {\n checkedKeysVersion.value++;\n // 同时重新赋值 Set,确保 Vue 能够追踪到变化\n store.value.checkedKeys = new Set(store.value.checkedKeys);\n}\n\n// 节点状态缓存,用于优化性能\nconst nodeStateCache = new Map<string | number, { checked: boolean; indeterminate: boolean; timestamp: number }>();\nconst CACHE_DURATION = 100; // 缓存持续时间(毫秒)\n\n// 清除所有缓存\nfunction clearAllCache() {\n nodeStateCache.clear();\n}\n\n// 清除节点及其所有子节点的缓存\nfunction clearNodeCache(node: TreeNode) {\n const nodeKey = getNodeKey(node);\n nodeStateCache.delete(nodeKey);\n if (hasChildren(node)) {\n getNodeChildren(node).forEach(clearNodeCache);\n }\n}\n\n// 清除过期的缓存\nfunction clearExpiredCache() {\n const now = Date.now();\n for (const [key, value] of nodeStateCache.entries()) {\n if (now - value.timestamp > CACHE_DURATION) {\n nodeStateCache.delete(key);\n }\n }\n}\n\nprovide(\"treeStore\", store);\n\n// 提供方法给子组件使用\nprovide(\"getNodeKey\", getNodeKey);\nprovide(\"getNodeLabel\", getNodeLabel);\nprovide(\"getNodeChildren\", getNodeChildren);\nprovide(\"hasChildren\", hasChildren);\nprovide(\"isEmployeeNode\", isEmployeeNode);\nprovide(\"getNodeIcon\", getNodeIcon);\nprovide(\"getNodeDepth\", getNodeDepth);\nprovide(\"isChildStyleNode\", isChildStyleNode);\nprovide(\"isNodeExpanded\", isNodeExpanded);\nprovide(\"isNodeChecked\", isNodeChecked);\nprovide(\"isNodeIndeterminate\", isNodeIndeterminate);\nprovide(\"isNodeCurrent\", isNodeCurrent);\nprovide(\"isNodeHighlighted\", isNodeHighlighted);\nprovide(\"handleExpandClick\", handleExpandClick);\nprovide(\"handleCheckClick\", handleCheckClick);\nprovide(\"handleNodeClick\", handleNodeClick);\nprovide(\"handleNodeContextMenu\", handleNodeContextMenu);\n\n// 方法\nconst effectiveRestrictLevel = computed<number | undefined>(() => {\n // 仅以新属性为准(组件化配置)。传入有效正数才启用限制\n return props.restrictAutoExpandFromLevel && props.restrictAutoExpandFromLevel > 0\n ? props.restrictAutoExpandFromLevel\n : undefined;\n});\n\nfunction getNodeKey(node: TreeNode): string | number {\n return node[props.nodeKey] || node.id || Math.random();\n}\n\nfunction getNodeLabel(node: TreeNode): string {\n return (props.props?.label ? node[props.props.label] : undefined) || node.label || \"\";\n}\n\nfunction isEmployeeNode(node: any): boolean {\n return Boolean(node?.data?.isEmployee);\n}\n\nfunction getNodeIcon(node: any, rootNode?: TreeNode): string {\n const dept = props.deptIconUrl || DEPT_ICON_URL;\n const person = props.personIconUrl || PERSON_ICON_URL;\n const button = props.buttonIconUrl || \"\";\n const childStyleIcon = props.childStyleIconUrl || \"\";\n \n // 优先检查是否是子样式节点\n if (rootNode && childStyleIcon && isChildStyleNode(node, rootNode)) {\n return childStyleIcon;\n }\n \n // 兼容旧的按钮节点判断逻辑\n if (node?.data?.isButton && button) return button;\n \n return isEmployeeNode(node) ? person : dept;\n}\n\nfunction hasChildren(node: TreeNode): boolean {\n const children = (props.props?.children ? node[props.props.children] : undefined) || node.children;\n return children && children.length > 0;\n}\n\nfunction getNodeChildren(node: TreeNode): TreeNode[] {\n return (props.props?.children ? node[props.props.children] : undefined) || node.children || [];\n}\n\n// 计算节点在树中的深度\nfunction getNodeDepth(\n node: TreeNode,\n targetNode: TreeNode,\n currentDepth: number = 1\n): number {\n if (node === targetNode) {\n return currentDepth;\n }\n\n const children = getNodeChildren(node);\n for (const child of children) {\n const depth = getNodeDepth(child, targetNode, currentDepth + 1);\n if (depth > 0) {\n return depth;\n }\n }\n\n return 0;\n}\n\n// 判断节点是否是子样式节点\nfunction isChildStyleNode(node: TreeNode, rootNode: TreeNode): boolean {\n if (!props.childStyleLevel || props.childStyleLevel < 1) {\n return false;\n }\n const depth = getNodeDepth(rootNode, node);\n return depth === props.childStyleLevel;\n}\n\n// 检查节点是否为第四级节点(按钮权限)\n// function isFourthLevelNode(node: TreeNode): boolean {\n// return Boolean(node.data?.isButton);\n// }\n\nfunction isNodeExpanded(node: TreeNode): boolean {\n const nodeKey = getNodeKey(node);\n return store.value.expandedKeys.has(nodeKey);\n}\n\n// 优化的节点状态计算函数,使用缓存和批量计算\n// 注意:此函数需要访问 store.value.checkedKeys 以确保响应式追踪\nfunction calculateNodeState(node: TreeNode, visited: Set<string | number> = new Set()): { checked: boolean; indeterminate: boolean } {\n const nodeKey = getNodeKey(node);\n \n // 防止循环引用\n if (visited.has(nodeKey)) {\n return { checked: false, indeterminate: false };\n }\n visited.add(nodeKey);\n\n // 直接访问 store.value.checkedKeys 以确保响应式追踪\n // 这是关键:Vue 需要能够追踪到这个访问\n const checkedKeys = store.value.checkedKeys;\n const directlyChecked = checkedKeys.has(nodeKey);\n \n // 叶子节点直接返回(不使用缓存,确保响应式)\n if (!hasChildren(node)) {\n return { checked: directlyChecked, indeterminate: false };\n }\n\n const children = getNodeChildren(node);\n if (children.length === 0) {\n return { checked: directlyChecked, indeterminate: false };\n }\n\n // 批量计算所有子节点状态\n let checkedCount = 0;\n let indeterminateCount = 0;\n \n for (const child of children) {\n const childState = calculateNodeState(child, visited);\n if (childState.checked) {\n checkedCount++;\n } else if (childState.indeterminate) {\n indeterminateCount++;\n }\n }\n\n let checked: boolean;\n let indeterminate: boolean;\n\n // 根据子节点状态计算父节点状态\n const allChildrenChecked = checkedCount === children.length && indeterminateCount === 0;\n const someChildrenChecked = checkedCount > 0 || indeterminateCount > 0;\n\n if (directlyChecked) {\n // 如果父节点直接选中,但子节点状态不一致,需要根据子节点状态调整\n if (allChildrenChecked) {\n // 所有子节点都选中,父节点也选中\n checked = true;\n indeterminate = false;\n } else if (someChildrenChecked) {\n // 部分子节点选中,父节点半选\n checked = false;\n indeterminate = true;\n } else {\n // 没有子节点选中,但父节点直接选中,保持选中状态\n checked = true;\n indeterminate = false;\n }\n } else {\n // 如果父节点没有直接选中,完全根据子节点状态决定\n if (allChildrenChecked) {\n // 所有子节点都选中,父节点也应该显示为选中\n checked = true;\n indeterminate = false;\n } else if (someChildrenChecked) {\n // 部分子节点选中,父节点半选\n checked = false;\n indeterminate = true;\n } else {\n // 所有子节点都未选中,父节点也未选中\n checked = false;\n indeterminate = false;\n }\n }\n\n return { checked, indeterminate };\n}\n\n// 确保这些函数能够被 Vue 正确追踪\nfunction isNodeChecked(node: TreeNode): boolean {\n // 访问 checkedKeysVersion 以确保响应式追踪\n // 这样每次 checkedKeys 变化时,这个函数都会重新计算\n const _ = checkedKeysVersion.value;\n return calculateNodeState(node).checked;\n}\n\nfunction isNodeIndeterminate(node: TreeNode): boolean {\n // 访问 checkedKeysVersion 以确保响应式追踪\n // 这样每次 checkedKeys 变化时,这个函数都会重新计算\n const _ = checkedKeysVersion.value;\n return calculateNodeState(node).indeterminate;\n}\n\nfunction isNodeCurrent(node: TreeNode): boolean {\n const key = getNodeKey(node);\n return store.value.currentKey === key;\n}\n\nfunction isNodeHighlighted(node: TreeNode): boolean {\n const key = getNodeKey(node);\n return store.value.highlightedKeys.has(key);\n}\n\nfunction handleCheckClick(node: TreeNode) {\n // 如果组件被禁用,不允许勾选操作\n if (props.disabled) return;\n\n const nodeKey = getNodeKey(node);\n const isChecked = store.value.checkedKeys.has(nodeKey);\n const newCheckedState = !isChecked;\n\n // 保存当前的展开状态,避免被勾选操作影响\n const currentExpandedKeys = new Set(store.value.expandedKeys);\n\n // 清除所有缓存,确保状态重新计算\n clearAllCache();\n\n // Update current node\n if (newCheckedState) {\n store.value.checkedKeys.add(nodeKey);\n } else {\n store.value.checkedKeys.delete(nodeKey);\n }\n\n // Cascade to children - 选中功能保持正常,但展开逻辑特殊处理\n function cascadeChildren(children: TreeNode[], check: boolean) {\n children.forEach((child) => {\n const childKey = getNodeKey(child);\n if (check) {\n store.value.checkedKeys.add(childKey);\n } else {\n store.value.checkedKeys.delete(childKey);\n }\n\n // 递归处理所有子节点,确保选中功能正常\n if (hasChildren(child)) {\n cascadeChildren(getNodeChildren(child), check);\n }\n });\n }\n\n // 正常递归选中所有子节点\n cascadeChildren(getNodeChildren(node), newCheckedState);\n\n // 特殊处理:如果选中了包含第四级子节点的节点,不自动展开第四级节点\n if (newCheckedState) {\n preventAutoExpandFourthLevel(node);\n }\n\n // Update all parent nodes recursively from bottom to top\n updateAllParentNodes();\n\n // 恢复展开状态,确保勾选操作不影响节点的展开收缩\n store.value.expandedKeys = currentExpandedKeys;\n\n // 再次清除所有缓存,确保 UI 更新\n clearAllCache();\n\n // Emit change\n emit(\"check-change\", node, newCheckedState, false);\n emit(\"check\", node, newCheckedState, false);\n emit(\"checked-keys-change\", Array.from(store.value.checkedKeys));\n}\n\n// 防止自动展开第四级节点的函数\nfunction preventAutoExpandFourthLevel(_node: TreeNode) {\n // 移除生产环境的 console.log 以提升性能\n // if (effectiveRestrictLevel.value) {\n // console.log(\n // `已启用从第${effectiveRestrictLevel.value}级开始不默认展开的限制(不主动收起已展开节点)`\n // );\n // }\n}\n\n// 重写 handleExpandClick 函数,确保第四级节点只能手动展开\nfunction handleExpandClick(node: TreeNode) {\n const nodeKey = getNodeKey(node);\n const isExpanded = store.value.expandedKeys.has(nodeKey);\n\n if (isExpanded) {\n // 收起节点\n store.value.expandedKeys.delete(nodeKey);\n emit(\"node-collapse\", node, node, null);\n } else {\n // 展开节点 - 第四级节点只能手动展开\n store.value.expandedKeys.add(nodeKey);\n emit(\"node-expand\", node, node, null);\n }\n}\n\n// 优化的父节点更新函数,只更新必要的父节点\nfunction updateAllParentNodes() {\n // 使用 Map 存储节点到父节点的映射,避免重复遍历\n const parentMap = new Map<string | number, TreeNode>();\n const allNodes: TreeNode[] = [];\n const nodeKeyMap = new Map<string | number, TreeNode>();\n\n function collectAllNodes(nodes: TreeNode[], parent?: TreeNode) {\n nodes.forEach((node) => {\n const nodeKey = getNodeKey(node);\n allNodes.push(node);\n nodeKeyMap.set(nodeKey, node);\n if (parent) {\n parentMap.set(nodeKey, parent);\n }\n if (hasChildren(node)) {\n collectAllNodes(getNodeChildren(node), node);\n }\n });\n }\n\n collectAllNodes(treeData.value);\n\n // 从叶子节点开始,向上更新父节点状态(只更新有子节点的节点)\n function updateNodeParents(node: TreeNode) {\n if (!hasChildren(node)) return;\n \n const children = getNodeChildren(node);\n const nodeKey = getNodeKey(node);\n\n // 批量计算子节点状态(每次调用使用新的 visited Set,避免循环引用)\n let checkedCount = 0;\n let indeterminateCount = 0;\n \n for (const child of children) {\n const childState = calculateNodeState(child);\n if (childState.checked) {\n checkedCount++;\n } else if (childState.indeterminate) {\n indeterminateCount++;\n }\n }\n\n // 根据子节点状态更新父节点\n // 如果所有子节点都选中,父节点也应该选中(添加到 checkedKeys)\n if (checkedCount === children.length && indeterminateCount === 0) {\n store.value.checkedKeys.add(nodeKey);\n } \n // 如果有部分子节点选中或半选,父节点应该半选(从 checkedKeys 中移除,让 indeterminate 生效)\n else if (checkedCount > 0 || indeterminateCount > 0) {\n // 部分选中状态:从 checkedKeys 中移除,让 calculateNodeState 计算 indeterminate\n store.value.checkedKeys.delete(nodeKey);\n } \n // 如果所有子节点都未选中,父节点也应该未选中(从 checkedKeys 中移除)\n else {\n store.value.checkedKeys.delete(nodeKey);\n }\n }\n\n // 从叶子节点开始更新(倒序遍历)\n for (let i = allNodes.length - 1; i >= 0; i--) {\n updateNodeParents(allNodes[i]);\n }\n \n // 清除所有缓存,确保 UI 更新\n clearAllCache();\n}\n\nfunction handleNodeClick(data: TreeNode, node: any, nodeComponent: any, rootNode?: TreeNode) {\n if (props.disabled) return;\n \n // 判断是否是子样式节点\n const isChildStyle = rootNode ? isChildStyleNode(data, rootNode) : false;\n \n // 如果启用了子样式节点自定义点击事件且是子样式节点,触发 child-node-click 事件\n if (props.enableChildStyleCustomClick && isChildStyle) {\n emit(\"child-node-click\", data, node, nodeComponent);\n return;\n }\n // 需求:当 expandOnClickNode=true 且为父节点时,优先展开/收起且不触发事件\n if (props.expandOnClickNode && hasChildren(data)) {\n handleExpandClick(data);\n return;\n }\n\n store.value.currentNode = data;\n store.value.currentKey = getNodeKey(data);\n\n // 权限树可用性:若展示复选框,点击整行也进行勾选切换\n if (props.showCheckbox) {\n handleCheckClick(data);\n }\n\n // 有无监听器都 emit,Vue 会按需处理\n emit(\"node-click\", data, node, nodeComponent);\n}\n\nfunction handleNodeContextMenu(\n event: Event,\n data: TreeNode,\n node: any,\n nodeComponent: any\n) {\n if (props.disabled) return;\n emit(\"node-contextmenu\", event, data, node, nodeComponent);\n}\n\n// 初始化默认状态\nwatch(\n () => props.defaultExpandedKeys,\n (keys) => {\n if (keys) {\n const restrictLevel = effectiveRestrictLevel.value;\n if (restrictLevel) {\n // 允许外部传入默认展开 keys,但需过滤:从 restrictLevel 起不自动展开\n // 同时保留“已手动展开”的受限级别节点\n\n // 计算节点深度工具\n function getDepthByKey(targetKey: string | number, nodes: TreeNode[], level = 1): number {\n for (const n of nodes) {\n if (getNodeKey(n) === targetKey) return level;\n if (hasChildren(n)) {\n const d = getDepthByKey(targetKey, getNodeChildren(n), level + 1);\n if (d > 0) return d;\n }\n }\n return 0;\n }\n\n // 仅保留小于限制级别的默认展开 keys\n const filtered = (keys || []).filter((k) => {\n const depth = getDepthByKey(k as any, treeData.value, 1);\n return depth > 0 && depth < restrictLevel;\n });\n const newExpandedKeys = new Set(filtered);\n\n // 自动补齐:将第 1 至 restrictLevel-1 级的所有可展开节点加入(确保 3/4 层也会展开)\n function collectKeysToDepth(nodes: TreeNode[], level: number, maxDepth: number) {\n nodes.forEach((node) => {\n if (level < maxDepth && hasChildren(node)) {\n newExpandedKeys.add(getNodeKey(node));\n collectKeysToDepth(getNodeChildren(node), level + 1, maxDepth);\n } else if (level < maxDepth && !hasChildren(node)) {\n // 叶子节点无需加入,但继续一致的遍历结构\n } else if (level >= maxDepth) {\n // 达到限制深度,停止自动补齐\n }\n });\n }\n collectKeysToDepth(treeData.value, 1, restrictLevel);\n\n // 保留当前“已展开”的受限级别节点(通常由用户手动展开)\n store.value.expandedKeys.forEach((key) => {\n const depth = getDepthByKey(key, treeData.value, 1);\n if (depth >= restrictLevel) {\n newExpandedKeys.add(key);\n }\n });\n\n store.value.expandedKeys = newExpandedKeys;\n } else {\n store.value.expandedKeys = new Set(keys);\n }\n }\n },\n { immediate: true }\n);\n\n// 处理 defaultExpandAll\nfunction expandAllNodes() {\n if (props.defaultExpandAll) {\n // 收集所有有子节点的节点ID\n const allExpandableKeys = new Set<string | number>();\n\n const restrictLevel = effectiveRestrictLevel.value;\n\n function collectExpandableKeys(nodes: TreeNode[], level: number = 1) {\n nodes.forEach((node) => {\n if (!hasChildren(node)) return;\n\n const children = getNodeChildren(node);\n\n if (restrictLevel) {\n // 达到或超过限制级别,则不再自动展开\n if (level >= restrictLevel) return;\n\n // 若下一层就是限制级别,则当前父节点也不自动展开,但递归子节点以便后续逻辑使用\n const hasChildAtRestrictLevel = level + 1 === restrictLevel;\n if (!hasChildAtRestrictLevel) {\n allExpandableKeys.add(getNodeKey(node));\n }\n collectExpandableKeys(children, level + 1);\n } else {\n // 普通模式:所有有子节点的层级默认展开\n allExpandableKeys.add(getNodeKey(node));\n collectExpandableKeys(children, level + 1);\n }\n });\n }\n\n collectExpandableKeys(treeData.value, 1);\n\n store.value.expandedKeys = allExpandableKeys;\n }\n}\n\n// 展开包含选中权限的节点路径\nfunction expandNodesWithCheckedPermissions() {\n if (props.defaultCheckedKeys && props.defaultCheckedKeys.length > 0) {\n const checkedKeys = new Set(props.defaultCheckedKeys);\n const expandableKeys = new Set<string | number>();\n\n function findPathsToCheckedNodes(\n nodes: TreeNode[],\n parentPath: (string | number)[] = []\n ) {\n nodes.forEach((node) => {\n const nodeKey = getNodeKey(node);\n const currentPath = [...parentPath, nodeKey];\n\n // 如果当前节点被选中,展开到它的所有父节点\n if (checkedKeys.has(nodeKey)) {\n parentPath.forEach((key) => expandableKeys.add(key));\n }\n\n // 递归处理子节点\n if (hasChildren(node)) {\n findPathsToCheckedNodes(getNodeChildren(node), currentPath);\n }\n });\n }\n\n findPathsToCheckedNodes(treeData.value);\n\n const restrictLevel = effectiveRestrictLevel.value;\n if (restrictLevel) {\n // 启用限制:保持当前展开状态,不进行自动展开\n // 移除生产环境的 console.log 以提升性能\n // console.log(\n // `已启用从第${restrictLevel}级开始不默认展开:保持当前展开状态不变`\n // );\n return;\n }\n // 普通模式:自动展开到包含选中权限的路径\n store.value.expandedKeys = expandableKeys;\n }\n}\n\n// 根据key查找节点\n// function findNodeByKey(key: string | number): TreeNode | null {\n// function searchNodes(nodes: TreeNode[]): TreeNode | null {\n// for (const node of nodes) {\n// if (getNodeKey(node) === key) {\n// return node;\n// }\n// if (hasChildren(node)) {\n// const found = searchNodes(getNodeChildren(node));\n// if (found) return found;\n// }\n// }\n// return null;\n// }\n// return searchNodes(treeData.value);\n// }\n\n// 使用防抖优化 watch,避免频繁触发\nlet expandAllNodesTimer: ReturnType<typeof setTimeout> | null = null;\nconst debouncedExpandAllNodes = () => {\n if (expandAllNodesTimer) clearTimeout(expandAllNodesTimer);\n expandAllNodesTimer = setTimeout(() => {\n expandAllNodes();\n expandAllNodesTimer = null;\n }, 50);\n};\n\nwatch(() => props.defaultExpandAll, expandAllNodes, { immediate: true });\n\n// 当树数据变化时,如果设置了 defaultExpandAll,重新展开所有节点(使用防抖)\nwatch(() => treeData.value, debouncedExpandAllNodes, { deep: true });\n\nwatch(\n () => props.defaultCheckedKeys,\n (keys) => {\n if (keys) {\n store.value.checkedKeys = new Set(keys);\n\n // 在权限树模式下,完全跳过自动展开逻辑,保持当前展开状态不变\n if (!props.enableFourthLevelSpecialHandling) {\n // 当选中权限变化时,展开包含这些权限的节点路径\n expandNodesWithCheckedPermissions();\n } else {\n // 移除生产环境的 console.log 以提升性能\n // console.log(\"权限树模式:跳过自动展开逻辑,保持当前展开状态\");\n }\n } else {\n store.value.checkedKeys.clear();\n }\n },\n { immediate: true }\n);\n\n// 根据传入的一组 id,展开到对应节点并高亮这些节点\nfunction highlightAndExpandByIds(ids: Array<string | number>) {\n try {\n const targetIds = Array.isArray(ids) ? ids : [];\n if (targetIds.length === 0) return;\n\n // 工具:查找到目标 key 的路径(返回 key 数组路径)\n function findPathToKey(\n nodes: TreeNode[],\n targetKey: string | number,\n path: (string | number)[] = []\n ): (string | number)[] | null {\n for (const n of nodes) {\n const nk = getNodeKey(n);\n const newPath = [...path, nk];\n if (nk === targetKey) return newPath;\n if (hasChildren(n)) {\n const p = findPathToKey(getNodeChildren(n), targetKey, newPath);\n if (p) return p;\n }\n }\n return null;\n }\n\n // 清除旧的高亮\n store.value.highlightedKeys.clear();\n\n // 累积需要展开的父级 key\n const keysToExpand = new Set<string | number>(store.value.expandedKeys);\n\n targetIds.forEach((targetId) => {\n const path = findPathToKey(treeData.value, targetId);\n if (path && path.length > 0) {\n // 父级全部加入展开集合(除最后一个自身)\n path.slice(0, -1).forEach((k) => keysToExpand.add(k));\n // 目标节点加入高亮集合\n store.value.highlightedKeys.add(path[path.length - 1]);\n }\n });\n\n // 应用展开\n store.value.expandedKeys = keysToExpand;\n } catch (e) {\n // 移除生产环境的 console.warn 以提升性能,仅在开发环境输出\n if (process.env.NODE_ENV === 'development') {\n console.warn('highlightAndExpandByIds 执行失败', e);\n }\n }\n}\n\n// 清除高亮\nfunction clearHighlights() {\n store.value.highlightedKeys.clear();\n}\n\n// 清除当前选中节点\nfunction clearCurrentNode() {\n store.value.currentNode = null;\n store.value.currentKey = null;\n}\n\ndefineExpose({ highlightAndExpandByIds, clearHighlights, clearCurrentNode });\n\nwatch(\n () => props.defaultSelectedKeys,\n (keys) => {\n if (keys) {\n store.value.selectedKeys = new Set(keys);\n }\n },\n { immediate: true }\n);\n</script>\n\n<style scoped>\n.ytree {\n position: relative;\n font-size: 14px;\n line-height: 1.5;\n color: #0b1a29;\n}\n\n.ytree--disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.ytree__container {\n position: relative;\n overflow: auto;\n}\n\n/* 尺寸变体 */\n.ytree--small {\n font-size: 12px;\n}\n\n.ytree--small .ytree__container {\n padding: 2px 0;\n}\n\n.ytree--medium {\n font-size: 13px;\n}\n\n.ytree--medium .ytree__container {\n padding: 4px 0;\n}\n\n.ytree--large {\n font-size: 14px;\n}\n\n.ytree--large .ytree__container {\n padding: 6px 0;\n}\n\n/* 树节点样式 */\n.ytree-node {\n position: relative;\n}\n\n.ytree-node__content {\n display: flex;\n align-items: center;\n height: 24px;\n padding: 0 6px;\n cursor: pointer;\n transition: background-color 0.2s ease, color 0.2s ease;\n border-radius: 4px;\n margin: 0.5px 0;\n}\n\n.ytree-node__content:hover:not(.ytree-node--disabled .ytree-node__content) {\n background-color: #f6f6f7;\n color: #303061;\n}\n\n.ytree-node--current > .ytree-node__content {\n background-color: #f0f0f0;\n font-weight: bold;\n}\n\n/* 高亮节点样式(仅文本变绿,无背景) */\n.ytree-node--highlight > .ytree-node__content .ytree-node__label {\n color: #10b981 !important;\n font-weight: 600;\n}\n\n.ytree-node--disabled .ytree-node__content {\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n.ytree-node__expand-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n margin-right: 2px;\n color: #6b7280;\n transition: transform 0.2s ease, color 0.2s ease;\n cursor: pointer;\n border-radius: 2px;\n}\n\n.ytree-node__expand-icon:hover {\n color: #374151;\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.ytree-node__expand-icon.is-expanded {\n transform: rotate(90deg);\n}\n\n.ytree-node__expand-icon--empty {\n width: 14px;\n height: 14px;\n margin-right: 4px;\n}\n\n.ytree-node__checkbox {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 10px;\n height: 10px;\n margin-right: 4px;\n border: 1px solid #d1d5db;\n border-radius: 2px;\n background: #ffffff;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n/* .ytree-node__checkbox:hover:not(.is-disabled) {\n border-color: #60a5fa;\n background-color: #f0f9ff;\n} */\n\n.ytree-node__checkbox.is-checked {\n background-color: #3f8682;\n color: #ffffff;\n}\n\n.ytree-node__checkbox.is-indeterminate {\n background-color: #3f8682;\n border-color: #3f8682;\n color: #ffffff;\n}\n\n.ytree-node__checkbox.is-disabled {\n background-color: #f9fafb;\n border-color: #e5e7eb;\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n.ytree-node__icon {\n margin-right: 4px;\n font-size: 12px;\n color: #6b7280;\n}\n\n.ytree-node__label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n line-height: 1.4;\n font-weight:500;\n}\n\n/* 子样式节点特殊样式 - 通过配置的级别动态应用 */\n.ytree-node__content.is-child-style .ytree-node__label {\n font-weight: 500 !important;\n color: #636363 !important;\n font-size: 12px !important;\n}\n\n/* 兼容旧的第四级节点样式(已废弃,保留以兼容旧代码) */\n.ytree--permission-tree .ytree-node__content[data-level=\"4\"] .ytree-node__label,\n.ytree--permission-tree .ytree-node[data-level=\"4\"] .ytree-node__label,\n.permission-tree .ytree-node__content[data-level=\"4\"] .ytree-node__label,\n.permission-tree .ytree-node[data-level=\"4\"] .ytree-node__label {\n font-weight: 500 !important;\n color: #636363 !important;\n font-size: 12px !important;\n}\n\n/* 员工节点颜色样式 */\n.ytree-node__label.is-employee {\n font-weight: 500;\n color: #777777;\n font-size: 12px;\n}\n\n/* 高亮覆盖(优先级更高,放在子样式规则之后) */\n.ytree-node.ytree-node--highlight > .ytree-node__content .ytree-node__label,\n.ytree-node.ytree-node--highlight > .ytree-node__content.is-child-style .ytree-node__label {\n color: #00a761 !important;\n font-weight: bold !important;\n}\n\n.ytree-node__custom-content {\n display: flex;\n align-items: center;\n margin-left: auto;\n flex-shrink: 0;\n}\n\n.ytree-node__avatar {\n width: 14px;\n height: 14px;\n margin-right: 4px;\n border-radius: 2px;\n object-fit: cover;\n}\n\n.ytree-node__label.is-current {\n font-weight: 500;\n}\n\n/* 暗色主题支持 */\n@media (prefers-color-scheme: dark) {\n .ytree {\n color: #e5eef7;\n }\n\n .ytree-node__content {\n color: #e5eef7;\n }\n\n .ytree-node__content:hover:not(.ytree-node--disabled .ytree-node__content) {\n background-color: rgba(2, 6, 23, 0.4);\n color: #e5eef7;\n }\n\n .ytree-node--current .ytree-node__content {\n background-color: rgba(59, 130, 246, 0.2);\n color: #60a5fa;\n }\n\n .ytree-node--disabled .ytree-node__content {\n color: #9ca3af;\n }\n\n .ytree-node__expand-icon {\n color: #9ca3af;\n }\n\n .ytree-node__expand-icon:hover {\n color: #cbd5e1;\n background-color: rgba(148, 163, 184, 0.1);\n }\n\n .ytree-node__checkbox {\n background: rgba(2, 6, 23, 0.4);\n border-color: rgba(148, 163, 184, 0.3);\n }\n\n .ytree-node__checkbox:hover:not(.is-disabled) {\n border-color: #60a5fa;\n background-color: rgba(59, 130, 246, 0.1);\n }\n\n .ytree-node__icon {\n color: #9ca3af;\n }\n\n /* 子样式节点暗色主题样式 */\n .ytree-node__content.is-child-style .ytree-node__label {\n color: #9ca3af !important;\n }\n\n /* 兼容旧的第四级节点暗色主题样式(已废弃,保留以兼容旧代码) */\n .ytree--permission-tree\n .ytree-node__content[data-level=\"4\"]\n .ytree-node__label,\n .ytree--permission-tree .ytree-node[data-level=\"4\"] .ytree-node__label,\n .permission-tree .ytree-node__content[data-level=\"4\"] .ytree-node__label,\n .permission-tree .ytree-node[data-level=\"4\"] .ytree-node__label {\n color: #9ca3af !important;\n }\n}\n</style>\n","<template>\n <div class=\"query-encapsulation\">\n <div class=\"query-encapsulation__container\">\n <div class=\"query-encapsulation__content\">\n <!-- 查询字段和操作按钮 -->\n <div class=\"query-encapsulation__fields\">\n <!-- 所有查询字段(带过渡动画,且不影响原有布局) -->\n <transition-group name=\"qf\" tag=\"div\" class=\"query-encapsulation__fields-group\">\n <div\n v-for=\"field in displayedFields\"\n :key=\"field.key\"\n class=\"query-encapsulation__field-item\"\n >\n <!-- 优先使用插槽自定义字段 -->\n <slot \n :name=\"`field-${field.key}`\" \n :field=\"field\" \n :value=\"searchForm[field.key]\"\n :update-value=\"(val: any) => updateFieldValue(field.key, val)\"\n >\n <!-- 默认渲染 -->\n <div class=\"query-encapsulation__field-wrapper\">\n <label v-if=\"Iflabel || field.type === 'switch'\" class=\"query-encapsulation__field-label\">{{ field.label }}</label>\n <component\n :is=\"getFieldComponent(field.type)\"\n v-model=\"searchForm[field.key]\"\n :placeholder=\"field.placeholder || `请输入${field.label}`\"\n :options=\"field.options\"\n :clearable=\"field.clearable !== false\"\n :size=\"field.size || 'small'\"\n :width=\"field.width || '180px'\"\n :format=\"field.format || 'timestamp'\"\n :include-time=\"field.includeTime || false\"\n :filterable=\"field.filterable === true\"\n :multiple=\"field.multiple === true\"\n :true-value=\"field.trueValue\"\n :false-value=\"field.falseValue\"\n :active-text=\"field.activeText\"\n :inactive-text=\"field.inactiveText\"\n :show-text=\"field.showText\"\n :active-color=\"field.activeColor || (field.type === 'switch' ? '#1B2433' : undefined)\"\n :inactive-color=\"field.inactiveColor\"\n v-on=\"getFieldListeners(field)\"\n @input=\"field.type !== 'switch' ? handleFieldChange(field) : undefined\"\n @change=\"field.type === 'switch' ? handleSwitchChange(field, $event) : handleFieldChange(field)\"\n />\n </div>\n </slot>\n </div>\n </transition-group>\n\n <!-- 展开/收起按钮 -->\n <div class=\"query-encapsulation__toggle\" v-if=\"hasHiddenFields\">\n <YButton variant=\"secondary\" size=\"small\" @click=\"toggleExpanded\">\n {{ isExpanded ? \"收起\" : \"展开\" }}\n <span\n class=\"query-encapsulation__toggle-icon\"\n :class=\"{ 'is-expanded': isExpanded }\"\n >▼</span\n >\n </YButton>\n </div>\n\n <!-- 操作按钮 -->\n <div class=\"query-encapsulation__actions\">\n <div class=\"query-encapsulation__actions-group\">\n <YButton\n variant=\"primary\"\n size=\"small\"\n @click=\"handleSearch\"\n :loading=\"loading\"\n >\n 搜索\n </YButton>\n <YButton\n variant=\"secondary\"\n size=\"small\"\n @click=\"handleReset\"\n :loading=\"loading\"\n >\n 重置\n </YButton>\n <slot name=\"extra-actions\"></slot>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {\n ref,\n reactive,\n computed,\n watch,\n onMounted,\n onBeforeUnmount,\n nextTick,\n} from \"vue\";\nimport YInput from \"./yinput.vue\";\nimport YSelect from \"./yselect.vue\";\nimport YButton from \"./ybutton.vue\";\nimport YTime from \"./ytime.vue\";\nimport YSwitch from \"./yswitch.vue\";\nimport type { SelectOption } from \"./yselect.vue\";\n\nexport interface QueryField {\n key: string;\n label: string;\n type: \"input\" | \"select\" | \"date\" | \"daterange\" | \"switch\";\n placeholder?: string;\n options?: SelectOption[];\n clearable?: boolean;\n size?: \"mini\" | \"small\" | \"medium\" | \"large\";\n width?: string;\n required?: boolean;\n hidden?: boolean; // 是否默认隐藏\n format?: \"timestamp\" | \"string\" | \"date\"; // 时间格式\n includeTime?: boolean; // 是否包含时间\n startKey?: string; // 开始时间的 key\n endKey?: string; // 结束时间的 key\n filterable?: boolean; // 可输入搜索(仅 select 支持)\n multiple?: boolean; // 是否多选(仅 select 支持)\n // switch 相关配置\n trueValue?: any; // switch 开启时的值\n falseValue?: any; // switch 关闭时的值\n activeText?: string; // switch 开启时的文本\n inactiveText?: string; // switch 关闭时的文本\n showText?: boolean; // switch 是否显示文本\n activeColor?: string; // switch 开启时的颜色\n inactiveColor?: string; // switch 关闭时的颜色\n onSwitchChange?: (value: any, field: QueryField) => void; // switch 切换时的自定义处理函数\n}\n\nexport interface QueryEncapsulationProps {\n Iflabel?: boolean;\n fields: QueryField[];\n maxVisibleFields?: number;\n loading?: boolean;\n modelValue?: Record<string, any>;\n}\n\nconst props = withDefaults(defineProps<QueryEncapsulationProps>(), {\n Iflabel: true,\n maxVisibleFields: 5,\n loading: false,\n modelValue: () => ({}),\n});\n\nconst emit = defineEmits<{\n \"update:modelValue\": [value: Record<string, any>];\n search: [payload: { data: Record<string, any>; raw: Record<string, any> }];\n reset: [];\n \"field-change\": [field: QueryField, value: any];\n}>();\n\n// 响应式数据\nconst isExpanded = ref(false);\nconst searchForm = reactive<Record<string, any>>({});\nconst autoTriggerTypes: QueryField[\"type\"][] = [\"select\", \"date\", \"daterange\", \"switch\"];\nlet autoSearchTimer: ReturnType<typeof setTimeout> | undefined;\n\n// 计算属性\nconst visibleFields = computed(() => {\n return props.fields.filter((field) => !field.hidden);\n});\n\n// 展示的字段(受展开/收起控制)\nconst displayedFields = computed(() => {\n if (isExpanded.value) return visibleFields.value;\n return visibleFields.value.slice(0, props.maxVisibleFields);\n});\n\n// const hiddenFields = computed(() => {\n// return visibleFields.value.slice(props.maxVisibleFields);\n// });\n\nconst hasHiddenFields = computed(() => {\n return visibleFields.value.length > props.maxVisibleFields;\n});\n\n// 方法\nfunction getFieldComponent(type: string) {\n switch (type) {\n case \"select\":\n return YSelect;\n case \"date\":\n case \"daterange\":\n return YTime;\n case \"switch\":\n return YSwitch;\n case \"input\":\n default:\n return YInput;\n }\n}\n\nfunction updateFieldValue(key: string, value: any) {\n searchForm[key] = value;\n const field = props.fields.find((f) => f.key === key);\n if (field) {\n handleFieldChange(field);\n }\n}\n\nfunction handleFieldChange(field: QueryField) {\n emit(\"field-change\", field, searchForm[field.key]);\n emit(\"update:modelValue\", { ...searchForm });\n if (autoTriggerTypes.includes(field.type)) {\n scheduleAutoSearch();\n }\n}\n\nfunction handleSwitchChange(field: QueryField, value: any) {\n // 如果配置了自定义处理函数,则调用它\n if (field.onSwitchChange && typeof field.onSwitchChange === 'function') {\n field.onSwitchChange(value, field);\n }\n // 仍然触发默认的字段变化处理(会自动触发搜索,因为 switch 已添加到 autoTriggerTypes)\n handleFieldChange(field);\n}\n\nfunction handleSearch() {\n // 过滤空值参数\n const searchParams = filterEmptyParams(searchForm);\n\n // 格式化参数(处理日期范围等特殊字段)\n const formattedParams = formatSearchParams(searchParams);\n\n const rawParams = { ...searchForm };\n\n // 将参数包裹在data对象中\n emit(\"search\", { data: formattedParams, raw: rawParams });\n}\n\nfunction handleReset() {\n // 重置所有字段\n Object.keys(searchForm).forEach((key) => {\n const field = props.fields.find((f) => f.key === key);\n if (field?.type === \"daterange\") {\n searchForm[key] = { startDate: null, endDate: null };\n } else if (field?.type === \"date\") {\n searchForm[key] = null;\n } else if (field?.type === \"switch\") {\n // switch 类型重置为 falseValue 或 false\n searchForm[key] = field.falseValue !== undefined ? field.falseValue : false;\n } else if (field?.type === \"select\" && field.multiple) {\n // 多选 select 类型重置为空数组\n searchForm[key] = [];\n } else {\n searchForm[key] = \"\";\n }\n });\n emit(\"reset\");\n emit(\"update:modelValue\", { ...searchForm });\n}\n\nfunction toggleExpanded() {\n isExpanded.value = !isExpanded.value;\n}\n\nfunction getFieldListeners(field: QueryField) {\n // 只有 input 类型需要特殊的事件监听\n if (field.type !== \"input\") {\n return {};\n }\n return {\n enter: () => handleInputQuickSearch(),\n paste: () => handleInputQuickSearch(),\n };\n}\n\nasync function handleInputQuickSearch() {\n await nextTick();\n handleSearch();\n}\n\nfunction scheduleAutoSearch() {\n if (autoSearchTimer) {\n clearTimeout(autoSearchTimer);\n }\n autoSearchTimer = setTimeout(() => {\n autoSearchTimer = undefined;\n nextTick().then(() => handleSearch());\n }, 0);\n}\n\n// 过滤空值参数\nfunction filterEmptyParams(params: Record<string, any>) {\n const filtered: Record<string, any> = {};\n\n Object.keys(params).forEach((key) => {\n const field = props.fields.find((f) => f.key === key);\n const rawValue = params[key];\n const value =\n typeof rawValue === \"string\" ? rawValue.trim() : rawValue;\n\n // 处理数组类型(多选字段)\n if (Array.isArray(value)) {\n if (value.length > 0) {\n filtered[key] = value;\n }\n return;\n }\n\n if (value === null || value === undefined || value === \"\") {\n return;\n }\n\n if (\n typeof value === \"object\" &&\n value.startDate &&\n value.endDate\n ) {\n if (value.startDate && value.endDate) {\n filtered[key] = value;\n }\n return;\n }\n\n if (field && (field.type === \"date\" || field.type === \"daterange\")) {\n if (value !== 0) {\n filtered[key] = value;\n }\n return;\n }\n\n filtered[key] = value;\n });\n\n return filtered;\n}\n\n// 格式化搜索参数\nfunction formatSearchParams(params: Record<string, any>) {\n const formatted: Record<string, any> = {};\n\n Object.keys(params).forEach((key) => {\n const value = params[key];\n const field = props.fields.find((f) => f.key === key);\n\n if (field) {\n // 根据字段类型格式化参数\n if (field.type === \"daterange\" && typeof value === \"object\") {\n // 日期范围字段:使用自定义的 key 或默认 key\n const startKey = field.startKey || `${key}Start`;\n const endKey = field.endKey || `${key}End`;\n\n // 只有当开始和结束日期都存在且不为0时才添加\n if (value.startDate && value.endDate && value.startDate !== 0 && value.endDate !== 0) {\n if (field.format === \"timestamp\") {\n formatted[startKey] = new Date(value.startDate).getTime();\n formatted[endKey] = new Date(value.endDate).getTime();\n } else {\n formatted[startKey] = value.startDate;\n formatted[endKey] = value.endDate;\n }\n }\n } else if (field.type === \"date\" && value && value !== 0) {\n // 单个日期字段\n if (field.format === \"timestamp\") {\n formatted[key] = new Date(value).getTime();\n } else {\n formatted[key] = value;\n }\n } else {\n // 普通字段直接传递\n formatted[key] = value;\n }\n } else {\n // 没有找到字段定义,直接传递\n formatted[key] = value;\n }\n });\n\n return formatted;\n}\n\n// 初始化表单数据\nfunction initFormData() {\n props.fields.forEach((field) => {\n if (searchForm[field.key] === undefined) {\n // 根据字段类型设置默认值\n if (field.type === \"daterange\") {\n searchForm[field.key] = props.modelValue?.[field.key] || {\n startDate: null,\n endDate: null,\n };\n } else if (field.type === \"date\") {\n searchForm[field.key] = props.modelValue?.[field.key] || null;\n } else if (field.type === \"switch\") {\n // switch 类型使用 falseValue 或 false 作为默认值\n searchForm[field.key] = props.modelValue?.[field.key] !== undefined \n ? props.modelValue[field.key] \n : (field.falseValue !== undefined ? field.falseValue : false);\n } else if (field.type === \"select\" && field.multiple) {\n // 多选 select 类型使用空数组作为默认值\n searchForm[field.key] = props.modelValue?.[field.key] !== undefined \n ? props.modelValue[field.key] \n : [];\n } else {\n searchForm[field.key] = props.modelValue?.[field.key] || \"\";\n }\n }\n });\n}\n\n// 监听外部数据变化\nwatch(\n () => props.modelValue,\n (newValue) => {\n if (newValue) {\n Object.assign(searchForm, newValue);\n }\n },\n { deep: true, immediate: true }\n);\n\n// 生命周期\nonMounted(() => {\n initFormData();\n});\n\nonBeforeUnmount(() => {\n if (autoSearchTimer) {\n clearTimeout(autoSearchTimer);\n autoSearchTimer = undefined;\n }\n});\n\n// 暴露方法供外部调用\ndefineExpose({\n search: handleSearch,\n reset: handleReset,\n});\n</script>\n\n<style scoped>\n/* 主容器 */\n.query-encapsulation {\n width: 100%;\n}\n\n.query-encapsulation__container {\n background: #ffffff;\n border-radius: 10px;\n padding: 16px;\n margin-bottom: 8px;\n box-shadow: \n 0rem 0.3125rem 0.3125rem -0.15625rem rgba(0, 0, 0, 0.03),\n 0rem 0.1875rem 0.1875rem -0.09375rem rgba(0, 0, 0, 0.02),\n 0rem 0.125rem 0.125rem -0.0625rem rgba(0, 0, 0, 0.02),\n 0rem 0.0625rem 0.0625rem -0.03125rem rgba(0, 0, 0, 0.03),\n 0rem 0.03125rem 0.03125rem 0rem rgba(0, 0, 0, 0.04),\n 0rem 0rem 0rem 0.0625rem rgba(0, 0, 0, 0.06);\n}\n\n.query-encapsulation__content {\n width: 100%;\n}\n\n/* 查询字段容器 */\n.query-encapsulation__fields {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n}\n\n.query-encapsulation__fields:last-child {\n margin-bottom: 0;\n}\n\n/* 字段组容器 - 修复 transition-group 布局问题 */\n.query-encapsulation__fields-group {\n display: contents;\n}\n\n/* 单个字段项 */\n.query-encapsulation__field-item {\n display: flex;\n align-items: center;\n transition: all 0.3s ease;\n}\n\n.query-encapsulation__field-wrapper {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* 字段标签 */\n.query-encapsulation__field-label {\n font-size: 13px;\n font-weight: 500;\n color: #374151;\n white-space: nowrap;\n min-width: fit-content;\n flex-shrink: 0;\n margin-right: 8px;\n}\n\n/* 展开/收起按钮 */\n.query-encapsulation__toggle {\n display: flex;\n align-items: center;\n margin-left: 0;\n}\n\n/* 展开/收起图标 */\n.query-encapsulation__toggle-icon {\n display: inline-block;\n margin-left: 4px;\n transition: transform 0.3s ease;\n font-size: 10px;\n}\n\n.query-encapsulation__toggle-icon.is-expanded {\n transform: rotate(180deg);\n}\n\n/* 操作按钮容器 */\n.query-encapsulation__actions {\n display: flex;\n align-items: center;\n}\n\n.query-encapsulation__actions-group {\n display: flex;\n gap: 8px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n/* 查询字段进出场与移动动画 */\n.qf-enter-active,\n.qf-leave-active {\n transition: all 0.2s ease;\n}\n\n.qf-enter-from,\n.qf-leave-to {\n opacity: 0;\n transform: translateY(-6px);\n}\n\n.qf-move {\n transition: transform 0.2s ease;\n}\n\n/* 响应式设计 - 移动优先 */\n/* 超大屏幕(1024px 及以下) */\n@media (max-width: 1024px) {\n .query-encapsulation__fields {\n gap: 10px;\n }\n}\n\n/* 中等屏幕(768px 及以下) */\n@media (max-width: 768px) {\n .query-encapsulation__container {\n padding: 10px;\n }\n}\n\n/* 小屏幕(640px 及以下) */\n@media (max-width: 640px) {\n .query-encapsulation__container {\n padding: 10px;\n }\n \n .query-encapsulation__fields {\n gap: 8px;\n }\n}\n\n/* 兼容性处理:如果浏览器不支持 contents,使用 flex 布局 */\n@supports not (display: contents) {\n .query-encapsulation__fields-group {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n }\n \n @media (max-width: 1024px) {\n .query-encapsulation__fields-group {\n gap: 10px;\n }\n }\n \n @media (max-width: 640px) {\n .query-encapsulation__fields-group {\n gap: 8px;\n }\n }\n}\n</style>\n","<template>\n <transition name=\"y-msg-fade\" @after-leave=\"onAfterLeave\">\n <div\n v-show=\"visible\"\n class=\"y-msg\"\n :class=\"[`y-msg--${type}`]\"\n :style=\"{ zIndex: zIndex }\"\n role=\"status\"\n aria-live=\"polite\"\n @mouseenter=\"handleMouseEnter\"\n @mouseleave=\"handleMouseLeave\"\n >\n <span class=\"y-msg__icon\" :class=\"`y-msg__icon--${type}`\" aria-hidden=\"true\">\n <svg v-if=\"type==='success'\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M20 6L9 17l-5-5\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n <svg v-else-if=\"type==='warning'\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n <svg v-else width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M12 9v4m0 4h.01M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </span>\n <div class=\"y-msg__content\" v-text=\"message\"></div>\n <button v-if=\"closable\" class=\"y-msg__close\" type=\"button\" @click=\"close\">✕</button>\n </div>\n </transition>\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, onBeforeUnmount, ref } from 'vue'\n\nconst props = withDefaults(defineProps<{\n id: number\n type?: 'success' | 'warning' | 'error'\n message: string\n duration?: number\n offset: number\n zIndex: number\n closable?: boolean\n onClose?: (id: number) => void\n}>(), {\n type: 'success',\n duration: 3000,\n closable: false,\n})\n\nconst visible = ref(false)\nlet timer: number | undefined\nlet remainingTime: number = 0\nlet startTime: number = 0\n\nonMounted(() => {\n // 先隐藏,下一帧再显示以触发过渡\n requestAnimationFrame(() => {\n visible.value = true\n if (props.duration && props.duration > 0) {\n startTimer(props.duration)\n }\n })\n})\n\nonBeforeUnmount(() => { \n clearTimer()\n})\n\nfunction startTimer(duration: number) {\n remainingTime = duration\n startTime = Date.now()\n timer = window.setTimeout(() => close(), duration)\n}\n\nfunction clearTimer() {\n if (timer) {\n window.clearTimeout(timer)\n timer = undefined\n }\n}\n\nfunction handleMouseEnter() {\n if (timer && props.duration && props.duration > 0) {\n clearTimer()\n // 计算剩余时间\n const elapsed = Date.now() - startTime\n remainingTime = Math.max(0, remainingTime - elapsed)\n }\n}\n\nfunction handleMouseLeave() {\n if (props.duration && props.duration > 0 && remainingTime > 0) {\n // 使用剩余时间重新启动计时器\n startTimer(remainingTime)\n }\n}\n\nfunction close() {\n visible.value = false\n}\n\nfunction onAfterLeave() {\n props.onClose?.(props.id)\n}\n</script>\n\n<style scoped>\n.y-msg {\n position: fixed;\n left: 50%;\n top: 0;\n transform: translate(-50%, 0);\n min-width: 260px;\n max-width: 86vw;\n box-sizing: border-box;\n padding: 10px 14px;\n border-radius: 12px;\n background: #ffffff;\n color: #0b1a29;\n display: flex;\n align-items: center;\n gap: 10px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n border: 1px solid rgba(15, 23, 42, 0.08);\n border-left-width: 3px;\n will-change: opacity, transform;\n transition:\n transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1),\n opacity 200ms ease;\n}\n\n.y-msg__icon { \n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n border-radius: 6px;\n padding: 4px;\n box-sizing: border-box;\n}\n.y-msg__icon--success { \n background-color: #047B5D; \n color: #ffffff; \n}\n.y-msg__icon--warning { \n background-color: #FFB800; \n color: #ffffff; \n}\n.y-msg__icon--error { \n background-color: #C41E3A; \n color: #ffffff; \n}\n.y-msg__content { \n margin-top: 2px;\n white-space: pre-wrap; \n word-break: break-word; \n line-height: 1.4;\n display: flex;\n align-items: center;\n /* font-weight: bold; */\n}\n.y-msg__close {\n margin-left: 8px;\n height: 22px; width: 22px;\n border: none; border-radius: 6px; background: transparent; color: inherit; cursor: pointer;\n}\n.y-msg__close:hover { background: rgba(2,6,23,0.06); }\n\n/* 状态色 - 背景统一为白色,通过图标和边框区分 */\n.y-msg--success { \n background: #ffffff; \n color: #0b1a29;\n}\n.y-msg--warning { \n background: #ffffff; \n color: #0b1a29;\n}\n.y-msg--error { \n background: #ffffff; \n color: #0b1a29;\n}\n\n@media (prefers-color-scheme: dark) {\n .y-msg { \n background: #1f2937; \n color: #ffffff;\n border-color: rgba(148, 163, 184, 0.2);\n border-left-width: 3px;\n }\n .y-msg--success { \n background: #1f2937; \n color: #ffffff;\n border-left-color: #047B5D;\n }\n .y-msg--warning { \n background: #1f2937; \n color: #ffffff;\n border-left-color: #FFB800;\n }\n .y-msg--error { \n background: #1f2937; \n color: #ffffff;\n border-left-color: #C41E3A;\n }\n}\n\n/* 进入/离开动效(自然惯性:更慢进入,稍快离开) */\n.y-msg-fade-enter-from { opacity: 0; transform: translate(-50%, -18px) scale(0.972); }\n.y-msg-fade-enter-active { transition: opacity 360ms cubic-bezier(0.22, 1, 0.36, 1), transform 360ms cubic-bezier(0.22, 1, 0.36, 1); }\n.y-msg-fade-leave-active { transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1), transform 220ms cubic-bezier(0.4, 0, 0.2, 1); }\n.y-msg-fade-leave-to { opacity: 0; transform: translate(-50%, -10px) scale(0.982); }\n\n/* 离场节点固定 top,不参与 top 过渡,仅做自身淡出/轻微位移,避免与重排叠加 */\n.y-msg.is-leaving { transition-property: opacity, transform; pointer-events: none; }\n\n@media (prefers-reduced-motion: reduce) {\n .y-msg, .y-msg-fade-enter-active, .y-msg-fade-leave-active { transition: none; }\n}\n</style>\n\n\n","import { createVNode, render } from 'vue'\nimport YMessageToast from './ymessageToast.vue'\n\nlet seed = 1\nconst GAP = 12\ntype InstanceItem = { id: number; el: HTMLElement; vm: any; height: number; leaving?: boolean }\nconst instances: Array<InstanceItem> = []\n\ntype YMessageType = 'success' | 'warning' | 'error'\n\ninterface MessageOptions {\n type?: YMessageType\n message: string\n duration?: number\n closable?: boolean\n}\n\nfunction calcOffset(): number {\n let offset = 20\n instances.forEach(inst => { offset += inst.height + GAP })\n return offset\n}\n\nfunction close(id: number) {\n const index = instances.findIndex(i => i.id === id)\n if (index === -1) return\n const { el } = instances[index]\n const node = el.firstElementChild as HTMLElement | null\n // 标记离场,锁定自身 top,避免与重排上移动画叠加造成闪烁\n if (node) {\n const computedTop = window.getComputedStyle(node).top\n node.style.top = computedTop\n node.classList.add('is-leaving')\n // 同步触发离场过渡(添加离场类后,不再参与 top 过渡)\n node.style.willChange = 'opacity, transform'\n }\n instances[index].leaving = true\n // 先让其他实例平滑上移,跳过离场中的实例\n updatePositions()\n // 等待过渡完成再卸载(避免闪断)\n const LEAVE_MS = 260\n setTimeout(() => {\n render(null, el)\n el.parentNode && el.parentNode.removeChild(el)\n const rmIndex = instances.findIndex(i => i.id === id)\n if (rmIndex !== -1) instances.splice(rmIndex, 1)\n updatePositions()\n }, LEAVE_MS)\n}\n\nfunction show(options: MessageOptions) {\n const id = seed++\n const el = document.createElement('div')\n document.body.appendChild(el)\n\n const vm = createVNode(YMessageToast, {\n id,\n type: options.type || 'success',\n message: options.message,\n duration: options.duration ?? 2500,\n offset: calcOffset(),\n zIndex: 3000 + id,\n closable: options.closable ?? false,\n onClose: (cid: number) => close(cid),\n })\n\n render(vm, el)\n\n const initialHeight = (el.firstElementChild as HTMLElement)?.offsetHeight || 0\n instances.push({ id, el, vm, height: initialHeight, leaving: false })\n updatePositions()\n\n // 等待一帧让过渡进入可见后,重新测量实际高度,避免初始为 0 导致重叠\n requestAnimationFrame(() => {\n const node = el.firstElementChild as HTMLElement | null\n if (!node) return\n const realHeight = node.offsetHeight || initialHeight || 0\n const inst = instances.find(i => i.id === id)\n if (inst) {\n inst.height = realHeight\n updatePositions()\n }\n })\n\n return { close: () => close(id) }\n}\n\nexport const YMessage = {\n success(message: string, durationOrOpts?: number | Omit<MessageOptions,'type'|'message'>) {\n const opts = typeof durationOrOpts === 'number' ? { duration: durationOrOpts } : (durationOrOpts || {})\n return show({ ...opts, type: 'success', message })\n },\n warning(message: string, durationOrOpts?: number | Omit<MessageOptions,'type'|'message'>) {\n const opts = typeof durationOrOpts === 'number' ? { duration: durationOrOpts } : (durationOrOpts || {})\n return show({ ...opts, type: 'warning', message })\n },\n error(message: string, durationOrOpts?: number | Omit<MessageOptions,'type'|'message'>) {\n const opts = typeof durationOrOpts === 'number' ? { duration: durationOrOpts } : (durationOrOpts || {})\n return show({ ...opts, type: 'error', message })\n },\n}\n\nexport type { YMessageType, MessageOptions }\n\n// 自动挂载到全局,无需 import 即可使用\nif (typeof window !== 'undefined') {\n ;(window as any).YMessage = YMessage\n // 同时挂载为全局变量(在非严格模式下可用)\n if (typeof (globalThis as any).YMessage === 'undefined') {\n ;(globalThis as any).YMessage = YMessage\n }\n}\n\nfunction updatePositions() {\n let offset = 20\n instances.forEach(inst => {\n const node = inst.el.firstElementChild as HTMLElement | null\n if (!node) return\n // const currentTop = parseFloat(node.style.top || '20') || 20\n const targetTop = offset\n // const dy = targetTop - currentTop\n // 用 transform 做平滑上移,避免频繁 top 导致回流\n node.style.transform = `translate(-50%, ${targetTop}px)`\n // 仅在首次定位时写入 top 以保证初始位置\n if (!node.style.top) node.style.top = '0px'\n if (!inst.leaving) {\n offset += (node.offsetHeight || inst.height) + GAP\n } else {\n const currentHeight = node.offsetHeight || inst.height\n offset += currentHeight + GAP\n }\n })\n}\n\n\n","<template>\n <div :class=\"['hint-tag-wrapper', `hint-tag-wrapper-${position}`]\">\n <transition name=\"hint-slide\">\n <div \n v-show=\"isExpanded\" \n :class=\"['hint-tag', `hint-tag-${position}`]\"\n :style=\"{ \n width: position === 'top' || position === 'bottom' ? 'auto' : width,\n borderColor: borderColor\n }\"\n >\n <div \n ref=\"contentRef\"\n class=\"hint-tag-content\"\n :class=\"{ 'hint-tag-content-clamp': maxLines }\"\n :style=\"maxLines ? { \n '--line-clamp': maxLines,\n lineHeight: '1.5',\n maxHeight: `${maxLines * 1.5}em`\n } : {}\"\n @mouseenter=\"handleMouseEnter\"\n @mouseleave=\"handleMouseLeave\"\n >\n <slot>{{ content }}</slot>\n </div>\n \n <!-- 完整内容弹窗 - 使用 Teleport 渲染到 body -->\n <Teleport to=\"body\">\n <transition name=\"popup-fade\">\n <div \n v-if=\"showPopup && isContentTruncated\"\n ref=\"popupRef\"\n class=\"hint-tag-popup\"\n @mouseenter=\"handlePopupEnter\"\n @mouseleave=\"handlePopupLeave\"\n >\n <div class=\"hint-tag-popup-content\">\n <slot>{{ content }}</slot>\n </div>\n </div>\n </transition>\n </Teleport>\n <div class=\"hint-tag-toggle\" @click=\"toggle\">\n <svg \n class=\"hint-tag-icon\"\n viewBox=\"0 0 24 24\" \n fill=\"none\" \n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path \n d=\"M15 18L9 12L15 6\" \n stroke=\"currentColor\" \n stroke-width=\"2\" \n stroke-linecap=\"round\" \n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </div>\n </transition>\n \n <!-- 收起后的小按钮 -->\n <transition name=\"hint-button-fade\">\n <div \n v-show=\"!isExpanded\" \n :class=\"['hint-tag-button', `hint-tag-button-${position}`]\"\n @click=\"toggle\"\n :title=\"tooltip || content\"\n >\n <svg \n class=\"hint-tag-button-icon\" \n viewBox=\"0 0 24 24\" \n fill=\"none\" \n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path \n d=\"M9 18L15 12L9 6\" \n stroke=\"currentColor\" \n stroke-width=\"2\" \n stroke-linecap=\"round\" \n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </transition>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref, inject, onMounted, onUnmounted, watch, onUpdated } from 'vue'\n\ninterface Props {\n content?: string\n position?: 'top' | 'right' | 'bottom' | 'left'\n defaultExpanded?: boolean\n width?: string\n tooltip?: string\n borderColor?: string\n maxLines?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n content: '',\n position: 'right',\n defaultExpanded: true,\n width: '280px',\n tooltip: '',\n borderColor: '#00a8e8',\n maxLines: undefined\n})\n\nconst contentRef = ref<HTMLElement | null>(null)\nconst popupRef = ref<HTMLElement | null>(null)\nconst isContentTruncated = ref(false)\nconst showPopup = ref(false)\nlet popupTimer: number | null = null\n\n// 检测内容是否被截断\nconst checkTruncation = () => {\n if (!props.maxLines || !contentRef.value) {\n isContentTruncated.value = false\n return\n }\n \n const element = contentRef.value\n \n // 在限制状态下,临时移除限制来检测完整高度\n const originalMaxHeight = element.style.maxHeight\n const hasClampClass = element.classList.contains('hint-tag-content-clamp')\n \n // 临时移除限制\n element.style.maxHeight = 'none'\n if (hasClampClass) {\n element.classList.remove('hint-tag-content-clamp')\n }\n \n // 获取完整内容的高度\n const fullHeight = element.scrollHeight\n const lineHeight = parseFloat(getComputedStyle(element).lineHeight) || 18\n const maxHeight = props.maxLines * lineHeight\n \n // 恢复原始样式\n element.style.maxHeight = originalMaxHeight\n if (hasClampClass) {\n element.classList.add('hint-tag-content-clamp')\n }\n \n // 检查内容是否被截断\n isContentTruncated.value = fullHeight > maxHeight\n}\n\n// 鼠标移入处理\nconst handleMouseEnter = () => {\n if (props.maxLines && isContentTruncated.value) {\n // 清除可能存在的定时器\n if (popupTimer) {\n clearTimeout(popupTimer)\n popupTimer = null\n }\n showPopup.value = true\n // 延迟定位弹窗,确保 DOM 已更新\n setTimeout(() => {\n updatePopupPosition()\n }, 0)\n }\n}\n\n// 鼠标移出处理\nconst handleMouseLeave = () => {\n // 延迟隐藏,给用户时间移动到弹窗\n popupTimer = window.setTimeout(() => {\n showPopup.value = false\n popupTimer = null\n }, 100)\n}\n\n// 弹窗鼠标移入处理\nconst handlePopupEnter = () => {\n // 清除隐藏定时器\n if (popupTimer) {\n clearTimeout(popupTimer)\n popupTimer = null\n }\n}\n\n// 弹窗鼠标移出处理\nconst handlePopupLeave = () => {\n showPopup.value = false\n}\n\n// 更新弹窗位置\nconst updatePopupPosition = () => {\n if (!popupRef.value || !contentRef.value) return\n \n const contentRect = contentRef.value.getBoundingClientRect()\n const popupRect = popupRef.value.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n const scrollX = window.scrollX || window.pageXOffset\n const scrollY = window.scrollY || window.pageYOffset\n \n let left = 0\n let top = 0\n \n switch (props.position) {\n case 'right':\n // 弹窗显示在内容右侧\n left = contentRect.right + 12\n top = contentRect.top + scrollY\n // 如果右侧空间不足,显示在左侧\n if (left + popupRect.width > viewportWidth + scrollX) {\n left = contentRect.left - popupRect.width - 12\n }\n // 垂直方向居中\n top = contentRect.top + scrollY + (contentRect.height - popupRect.height) / 2\n // 确保不超出视口\n if (top < scrollY) top = scrollY + 8\n if (top + popupRect.height > scrollY + viewportHeight) {\n top = scrollY + viewportHeight - popupRect.height - 8\n }\n break\n case 'left':\n // 弹窗显示在内容左侧\n left = contentRect.left - popupRect.width - 12\n top = contentRect.top + scrollY\n // 如果左侧空间不足,显示在右侧\n if (left < scrollX) {\n left = contentRect.right + 12\n }\n // 垂直方向居中\n top = contentRect.top + scrollY + (contentRect.height - popupRect.height) / 2\n // 确保不超出视口\n if (top < scrollY) top = scrollY + 8\n if (top + popupRect.height > scrollY + viewportHeight) {\n top = scrollY + viewportHeight - popupRect.height - 8\n }\n break\n case 'top':\n // 弹窗显示在内容上方\n left = contentRect.left + scrollX + (contentRect.width - popupRect.width) / 2\n top = contentRect.top - popupRect.height - 12\n // 如果上方空间不足,显示在下方\n if (top < scrollY) {\n top = contentRect.bottom + scrollY + 12\n }\n // 水平方向调整\n if (left < scrollX + 8) left = scrollX + 8\n if (left + popupRect.width > scrollX + viewportWidth) {\n left = scrollX + viewportWidth - popupRect.width - 8\n }\n break\n case 'bottom':\n // 弹窗显示在内容下方\n left = contentRect.left + scrollX + (contentRect.width - popupRect.width) / 2\n top = contentRect.bottom + scrollY + 12\n // 如果下方空间不足,显示在上方\n if (top + popupRect.height > scrollY + viewportHeight) {\n top = contentRect.top - popupRect.height - 12\n }\n // 水平方向调整\n if (left < scrollX + 8) left = scrollX + 8\n if (left + popupRect.width > scrollX + viewportWidth) {\n left = scrollX + viewportWidth - popupRect.width - 8\n }\n break\n }\n \n popupRef.value.style.left = `${left}px`\n popupRef.value.style.top = `${top}px`\n}\n\nonUpdated(() => {\n checkTruncation()\n})\n\n\nconst isExpanded = ref(props.defaultExpanded)\n\nconst toggle = () => {\n isExpanded.value = !isExpanded.value\n}\n\n// 收起方法(用于批量收起)\nconst collapse = () => {\n if (isExpanded.value) {\n isExpanded.value = false\n }\n}\n\n// 展开方法(用于批量展开)\nconst expand = () => {\n if (!isExpanded.value) {\n isExpanded.value = true\n }\n}\n\n// 暴露方法供外部调用\ndefineExpose({\n toggle,\n isExpanded,\n collapse,\n expand\n})\n\n// 尝试注册到父级 ytable 组件\nconst registerHintTag = inject<(instance: any) => void>('registerHintTag', null)\nconst unregisterHintTag = inject<(instance: any) => void>('unregisterHintTag', null)\nconst notifyHintTagStateChange = inject<() => void>('notifyHintTagStateChange', null)\n\n// 创建实例对象用于注册\nconst instance = {\n collapse,\n expand,\n toggle,\n get isExpanded() {\n return isExpanded.value\n }\n}\n\n// 监听状态变化,通知父组件更新\nwatch(() => isExpanded.value, () => {\n if (notifyHintTagStateChange) {\n notifyHintTagStateChange()\n }\n // 展开/收起后重新检测截断状态\n setTimeout(() => {\n checkTruncation()\n }, 0)\n})\n\n// 监听内容变化,重新检测截断状态\nwatch(() => [props.content, props.maxLines], () => {\n setTimeout(() => {\n checkTruncation()\n }, 0)\n})\n\n// 监听弹窗显示状态,更新位置\nwatch(showPopup, (newVal) => {\n if (newVal) {\n // 延迟定位弹窗,确保 DOM 已更新\n setTimeout(() => {\n updatePopupPosition()\n }, 0)\n // 监听滚动和窗口大小变化\n window.addEventListener('scroll', updatePopupPosition, true)\n window.addEventListener('resize', updatePopupPosition)\n } else {\n // 移除监听\n window.removeEventListener('scroll', updatePopupPosition, true)\n window.removeEventListener('resize', updatePopupPosition)\n }\n})\n\nonMounted(() => {\n checkTruncation()\n if (registerHintTag) {\n registerHintTag(instance)\n }\n})\n\nonUnmounted(() => {\n if (unregisterHintTag) {\n unregisterHintTag(instance)\n }\n // 清理定时器\n if (popupTimer) {\n clearTimeout(popupTimer)\n popupTimer = null\n }\n // 移除事件监听\n window.removeEventListener('scroll', updatePopupPosition, true)\n window.removeEventListener('resize', updatePopupPosition)\n})\n</script>\n\n<style scoped lang=\"less\">\n.hint-tag-wrapper {\n display: inline-block;\n position: relative;\n vertical-align: middle;\n margin-left: 4px;\n z-index: 10000;\n pointer-events: none;\n}\n\n.hint-tag {\n position: absolute;\n background: #ffffff;\n color: #333333;\n border-radius: 6px;\n border: 1px solid;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n display: flex;\n align-items: stretch;\n font-size: 12px;\n white-space: nowrap;\n pointer-events: auto;\n \n &.hint-tag-right {\n left: 0;\n top: 50%;\n transform: translateY(-50%);\n flex-direction: row;\n }\n \n &.hint-tag-left {\n right: 0;\n top: 50%;\n transform: translateY(-50%);\n flex-direction: row-reverse;\n }\n \n &.hint-tag-top {\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n flex-direction: column-reverse;\n margin-bottom: 4px;\n }\n \n &.hint-tag-bottom {\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n flex-direction: column;\n margin-top: 4px;\n }\n}\n\n.hint-tag-content {\n flex: 1;\n padding: 3px 10px;\n line-height: 1.5;\n white-space: normal;\n word-break: break-word;\n \n // 当没有设置 maxLines 时,使用滚动条\n &:not(.hint-tag-content-clamp) {\n max-height: 150px;\n overflow-y: auto;\n \n &::-webkit-scrollbar {\n width: 4px;\n }\n \n &::-webkit-scrollbar-track {\n background: #f3f4f6;\n border-radius: 4px;\n }\n \n &::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 4px;\n \n &:hover {\n background: #9ca3af;\n }\n }\n }\n \n // 当设置了 maxLines 时,使用多行省略\n &.hint-tag-content-clamp {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n overflow: hidden;\n text-overflow: ellipsis;\n -webkit-line-clamp: var(--line-clamp, 3);\n line-clamp: var(--line-clamp, 3);\n word-break: break-word;\n cursor: pointer;\n \n &:hover {\n opacity: 0.8;\n }\n }\n}\n\n.hint-tag-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 6px;\n cursor: pointer;\n background: #f3f4f6;\n transition: background 0.2s ease;\n flex-shrink: 0;\n color: #666666;\n \n &:hover {\n background: #e5e7eb;\n }\n \n .hint-tag-right & {\n border-radius: 0 6px 6px 0;\n }\n \n .hint-tag-left & {\n border-radius: 6px 0 0 6px;\n }\n \n .hint-tag-top & {\n border-radius: 6px 6px 0 0;\n }\n \n .hint-tag-bottom & {\n border-radius: 0 0 6px 6px;\n }\n}\n\n.hint-tag-icon {\n width: 16px;\n height: 16px;\n transition: transform 0.2s ease;\n \n .hint-tag-right & {\n transform: rotate(0deg); // 向左箭头(展开状态,点击后收起)\n }\n \n .hint-tag-left & {\n transform: rotate(180deg); // 向右箭头(展开状态,点击后收起)\n }\n \n .hint-tag-top & {\n transform: rotate(-90deg); // 向上箭头(展开状态,点击后收起)\n }\n \n .hint-tag-bottom & {\n transform: rotate(90deg); // 向下箭头(展开状态,点击后收起)\n }\n}\n\n.hint-tag-button {\n width: 20px;\n height: 20px;\n background: #ffffff;\n color: #666666;\n border: 1px solid #e5e7eb;\n border-radius: 50%;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);\n transition: transform 0.2s ease, box-shadow 0.2s ease, color 0.2s ease;\n pointer-events: auto;\n vertical-align: middle;\n \n &:hover {\n color: #333333;\n transform: scale(1.1);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n}\n\n.hint-tag-button-icon {\n width: 12px;\n height: 12px;\n transition: transform 0.2s ease;\n \n .hint-tag-button-right & {\n transform: rotate(0deg); // 收起状态,点击后展开,显示→\n }\n \n .hint-tag-button-left & {\n transform: rotate(180deg); // 收起状态,点击后展开,显示←\n }\n \n .hint-tag-button-top & {\n transform: rotate(-90deg); // 收起状态,点击后展开,显示↑\n }\n \n .hint-tag-button-bottom & {\n transform: rotate(90deg); // 收起状态,点击后展开,显示↓\n }\n}\n\n// 动画效果\n.hint-slide-enter-active,\n.hint-slide-leave-active {\n transition: all 0.3s ease;\n}\n\n.hint-tag-right {\n &.hint-slide-enter-from,\n &.hint-slide-leave-to {\n transform: translateY(-50%) translateX(-20px);\n opacity: 0;\n }\n}\n\n.hint-tag-left {\n &.hint-slide-enter-from,\n &.hint-slide-leave-to {\n transform: translateY(-50%) translateX(20px);\n opacity: 0;\n }\n}\n\n.hint-tag-top {\n &.hint-slide-enter-from,\n &.hint-slide-leave-to {\n transform: translateX(-50%) translateY(20px);\n opacity: 0;\n }\n}\n\n.hint-tag-bottom {\n &.hint-slide-enter-from,\n &.hint-slide-leave-to {\n transform: translateX(-50%) translateY(-20px);\n opacity: 0;\n }\n}\n\n.hint-button-fade-enter-active,\n.hint-button-fade-leave-active {\n transition: all 0.2s ease;\n}\n\n.hint-button-fade-enter-from,\n.hint-button-fade-leave-to {\n opacity: 0;\n transform: scale(0.5);\n}\n\n// 弹窗样式\n.hint-tag-popup {\n position: fixed;\n background: #ffffff;\n color: #333333;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);\n padding: 12px 16px;\n font-size: 12px;\n line-height: 1.6;\n max-width: 500px;\n max-height: 400px;\n overflow-y: auto;\n word-break: break-word;\n white-space: normal;\n z-index: 99999;\n pointer-events: auto;\n \n &::-webkit-scrollbar {\n width: 6px;\n }\n \n &::-webkit-scrollbar-track {\n background: #f3f4f6;\n border-radius: 4px;\n }\n \n &::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 4px;\n \n &:hover {\n background: #9ca3af;\n }\n }\n}\n\n.hint-tag-popup-content {\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n// 弹窗动画\n.popup-fade-enter-active,\n.popup-fade-leave-active {\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.popup-fade-enter-from,\n.popup-fade-leave-to {\n opacity: 0;\n transform: translateY(-8px) scale(0.95);\n}\n\n</style>\n","// 全局类型声明(确保 YMessage 全局类型可用)\ndeclare global {\n interface Window {\n YMessage: {\n success(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n warning(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n error(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n }\n }\n \n // 允许在全局作用域直接使用 YMessage(非严格模式)\n var YMessage: {\n success(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n warning(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n error(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n }\n}\n\n// 导出所有组件\nexport { default as YButton } from './components/ybutton.vue'\nexport { default as YInput } from './components/yinput.vue'\nexport { default as YTable } from './components/ytable.vue'\nexport { default as YSelect } from './components/yselect.vue'\nexport { default as YPagination } from './components/ypagination.vue'\nexport { default as YBadge } from './components/ybadge.vue'\nexport { default as YDialog } from './components/ydialog.vue'\nexport { default as YPopover } from './components/ypopover.vue'\nexport { default as YTime } from './components/ytime.vue'\nexport { default as YSwitch } from './components/yswitch.vue'\nexport { default as YImage } from './components/yimage.vue'\nexport { default as YDropdown } from './components/ydropdown.vue'\nexport { default as YDrawer } from './components/ydrawer.vue'\nexport { default as YTree } from './components/ytree.vue'\nexport { default as QueryEncapsulation } from './components/QueryEncapsulation.vue'\n\n// 导出 YMessage\nexport { YMessage } from './components/ymessage/ymessage'\nexport type { YMessageType, MessageOptions } from './components/ymessage/ymessage'\n\n// 导出类型\nexport type { SwitchProps } from './components/yswitch.vue'\nexport type { SelectOption } from './components/yselect.vue'\nexport type { PaginationProps } from './components/ypagination.vue'\n\n// 安装函数(用于 Vue.use())\nimport type { App } from 'vue'\nimport YButton from './components/ybutton.vue'\nimport YInput from './components/yinput.vue'\nimport YTable from './components/ytable.vue'\nimport YSelect from './components/yselect.vue'\nimport YPagination from './components/ypagination.vue'\nimport YBadge from './components/ybadge.vue'\nimport YDialog from './components/ydialog.vue'\nimport YPopover from './components/ypopover.vue'\nimport YTime from './components/ytime.vue'\nimport YSwitch from './components/yswitch.vue'\nimport YImage from './components/yimage.vue'\nimport YDropdown from './components/ydropdown.vue'\nimport YDrawer from './components/ydrawer.vue'\nimport YTree from './components/ytree.vue'\nimport HintTag from './components/hintTag.vue'\nimport QueryEncapsulation from './components/QueryEncapsulation.vue'\nimport { YMessage } from './components/ymessage/ymessage'\n\nconst components = {\n YButton,\n YInput,\n YTable,\n YSelect,\n YPagination,\n YBadge,\n YDialog,\n YPopover,\n YTime,\n YSwitch,\n YImage,\n YDropdown,\n YDrawer,\n YTree,\n QueryEncapsulation,\n HintTag,\n}\n\nexport default {\n install(app: App) {\n // 注册所有组件\n Object.keys(components).forEach((key) => {\n app.component(key, components[key as keyof typeof components])\n })\n \n // 将 YMessage 挂载到 Vue 全局属性,方便在模板中使用 this.$message\n app.config.globalProperties.$message = YMessage\n \n // 确保挂载到 window 对象,实现全局直接使用(无需 import)\n if (typeof window !== 'undefined') {\n ;(window as any).YMessage = YMessage\n }\n },\n}\n\n"],"names":["props","__props","emit","__emit","onClick","ev","groupPositionClass","computed","isGroup","onGroupItemClick","item","_openBlock","_createElementBlock","_hoisted_3","_Fragment","_renderList","index","_a","$event","_createElementVNode","_hoisted_5","_hoisted_6","_cache","_hoisted_7","_hoisted_8","_toDisplayString","_hoisted_2","_renderSlot","_ctx","inputRef","ref","previousValue","hasChanged","isFocused","inputPlaceholder","passwordVisible","showPasswordToggle","actualInputType","togglePasswordVisibility","watch","val","onInput","target","onFocus","onBlur","current","minVal","onEnter","onPaste","_normalizeClass","currentPage","pageSize","selectedItems","selectedRowKey","expandedKeys","tableMaxHeight","tableContainer","headerRef","bodyWrapRef","bodyTableRef","headerColWidths","headerWidthMap","defaultHeaderHeight","hintTagInstances","hasHintTags","allHintsExpanded","hintTagStateUpdateTrigger","expandedCount","instance","collapsedCount","registerHintTag","unregisterHintTag","collapseAllHints","expandAllHints","toggleAllHints","notifyHintTagStateChange","provide","autoColumnKeys","col","normalizeWidth","getAutoColumnWidth","vTrackRef","vScroll","isDragging","dragStartY","dragStartScrollTop","scrollbarWidth","width","trimmed","parseWidthNumber","normalized","parsed","totalTableColumns","count","filteredData","keyword","field","value","getNestedValue","pagedData","isAllVisibleSelected","visibleKeys","getRowKey","isRowDisabled","key","isPartiallySelected","selectedCount","isAllVisibleDisabled","shouldDisableNext","fixedLeftWidths","widths","cumulativeWidth","i","parsedWidth","fixedRightWidths","rightFixedColumns","getFixedColumnIndex","columnIndex","fixed","isRowExpanded","toggleRowExpand","obj","path","getColumnClass","column","isHeader","classes","getColumnStyle","style","normalizedWidth","autoWidth","fixedIndex","leftOffset","rightOffset","formatCellValue","toggleSelect","rowData","rowIndex","x","toggleSelectAllVisible","union","clearSelection","handleRowClick","k","isRowSelected","newVal","currentSet","newSet","handlePageChange","page","handlePageSizeChange","size","next","calculateTableMaxHeight","nextTick","containerRect","viewportHeight","containerTop","headerElement","headerHeight","paginationHeight","paginationElement","bulkBarElement","bulkBarHeight","reservedHeight","availableHeight","maxHeight","tableContent","isSyncingScroll","syncHeaderScroll","syncBodyScroll","updateVirtualScrollbar","wrap","contentHeight","viewport","scrollTop","needVBar","minThumb","ratio","trackHeight","thumbHeight","maxThumbTop","maxScrollTop","onThumbMousemove","e","scrollDelta","onThumbMouseup","measureAutoColumnWidths","w","fallback","firstRow","startIndex","tds","td","measured","stored","_b","handleResize","updateHeaderScrollbarGutter","syncSelectedHeaderHeight","nextWidths","nextMap","idx","currentKeys","measureDefaultHeaderHeight","headerTable","firstNormalTh","selectedHeader","wrapper","onMounted","resizeObserver","onUnmounted","lastScrollbarWidth","currentScrollbarWidth","bodyTable","_createVNode","_Transition","_hoisted_1","_component_YButton","_hoisted_4","_hoisted_9","_hoisted_10","_hoisted_11","_normalizeStyle","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_16","$slots","_hoisted_18","colIndex","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_24","_createBlock","_component_YPagination","isOpen","hoveredIndex","optionsContainer","triggerElement","selectContainer","shouldOpenUpward","inputElement","searchQuery","selectedOption","option","getOptionValue","selectedOptions","values","selectedLabel","getOptionLabel","displayedOptions","query","opt","label","portalDropdownStyle","trigger","rect","calculateDropdownPosition","triggerRect","dropdownHeight","dropdownBottom","dropdownTop","shouldOpenDown","canOpenUp","getOptionKey","isSelected","isOptionDisabled","toggleDropdown","closeDropdown","openDropdown","scrollToSelected","selectOption","_index","currentValues","optionValue","valueIndex","handleClear","cleared","removeTag","event","moveHover","delta","total","attempts","scrollHoverIntoView","selectHovered","selectedElement","el","handleClickOutside","_withModifiers","_createTextVNode","_Teleport","pageSizeOptions","goToPage","onPagerGroupClick","action","_component_YSelect","toneClass","ariaLabel","text","tone","prog","progMap","toneMap","visible","v","panelRef","panelStyle","onMaskClick","close","onEsc","onKeydown","popoverRef","triggerRef","contentRef","contentRect","arrowPosition","openTimer","closeTimer","contentStyle","top","left","calculatePosition","arrowStyle","triggerWidth","triggerHeight","triggerTop","triggerLeft","contentWidth","viewportWidth","show","clearTimers","doShow","updatePosition","hide","doHide","calculateArrowPosition","triggerCenterX","contentLeft","arrowOffset","triggerCenterY","contentTop","handleTriggerClick","handleMouseEnter","handleMouseLeave","handleContentMouseEnter","handleContentMouseLeave","__expose","activeShortcutIndex","selectedShortcutIndex","pendingValue","dropdown","dropdownPosition","startCalendar","endCalendar","ensureDifferentMonths","startTime","endTime","nextMonth","ensureDifferentMonthsReverse","prevMonth","weekDays","tempStartDate","tempEndDate","parseDate","date","formatDateToString","year","month","day","hours","minutes","seconds","formatDateToTimestamp","normalizeValue","formatOutputValue","formatYearMonth","isSameDay","date1","date2","isDateInRange","start","end","findMatchingShortcutIndex","currentValue","normalizedValue","shortcutValue","currentStart","currentEnd","shortcutStart","shortcutEnd","generateCalendarDays","firstDay","lastDay","firstDayWeek","daysInMonth","days","today","prevDaysCount","remainingDays","weeks","updateValue","formattedValue","dropdownRect","spaceBelow","spaceAbove","spaceRight","dropdownWidth","triggerEl","dropdownEl","handleTriggerKeydown","focusFirstShortcut","handleDropdownKeydown","handleShortcutKeydown","focusShortcut","selectShortcut","handleShortcutMouseEnter","handleShortcutMouseLeave","shortcutElement","shortcut","s","selectDate","type","selectedDate","endDate","getDateCellClass","confirmSelection","resetSelection","startCalendarDays","endCalendarDays","displayText","formatDate","startStr","endStr","dropdownClasses","hasValue","canConfirm","newValue","startDate","handleClearClick","changeMonth","direction","newDate","_hoisted_15","_hoisted_17","week","weekIndex","dayIndex","_hoisted_23","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","_hoisted_30","_hoisted_31","_hoisted_32","rootEl","isChecked","switchStyle","onToggle","containerRef","imageRef","previewImageRef","isLoaded","isLoading","hasError","isInView","showPreview","imgSrc","previewSrc","zoomLevel","isMounted","hoverPreview","hidePreviewTimeout","originalBodyStyle","RADIUS_TOKEN_MAP","containerClass","radiusValue","radiusStyle","imageClass","imageStyle","resolvedPreviewSrc","getHoverPreviewSrc","getScrollbarWidth","scrollDiv","lockBodyScroll","unlockBodyScroll","observer","setupIntersectionObserver","entries","entry","handleLoad","handleError","retryLoad","getPreviewUrl","handleErrorClick","handlePreview","previewUrl","img","timeoutId","isHandled","showPreviewModal","closePreview","handleWheel","zoomDirection","newZoom","updateImagePreviewPosition","padding","onImageMouseEnter","onImageMouseMove","onImageMouseLeave","onPreviewMouseEnter","onPreviewMouseLeave","nv","_vShow","dropdownRef","hideTimer","menuClass","menuStyle","showDropdown","hideDropdown","menu","menuRect","absoluteTop","absoluteLeft","menuWidth","menuHeight","transitionName","roundedClass","inject","getNodeKey","getNodeLabel","getNodeChildren","hasChildren","isEmployeeNode","getNodeIcon","getNodeDepth","isChildStyleNode","isNodeExpanded","isNodeChecked","isNodeIndeterminate","isNodeCurrent","isNodeHighlighted","handleExpandClick","handleCheckClick","handleNodeClick","handleNodeContextMenu","nodeLabel","nodeIcon","nodeDepth","isExpanded","isIndeterminate","isCurrent","isHighlighted","hasNodeChildren","nodeChildren","isChildStyle","isEmployee","paddingLeft","_unref","child","YTreeNode","_withCtx","slotProps","_mergeProps","DEPT_ICON_URL","PERSON_ICON_URL","treeData","store","checkedKeysVersion","nodeStateCache","clearAllCache","effectiveRestrictLevel","node","rootNode","dept","person","button","childStyleIcon","children","targetNode","currentDepth","depth","nodeKey","calculateNodeState","visited","directlyChecked","checkedCount","indeterminateCount","childState","checked","indeterminate","allChildrenChecked","someChildrenChecked","newCheckedState","currentExpandedKeys","cascadeChildren","check","childKey","updateAllParentNodes","parentMap","allNodes","nodeKeyMap","collectAllNodes","nodes","parent","updateNodeParents","data","nodeComponent","keys","restrictLevel","getDepthByKey","targetKey","level","n","d","collectKeysToDepth","maxDepth","newExpandedKeys","filtered","expandAllNodes","collectExpandableKeys","allExpandableKeys","expandNodesWithCheckedPermissions","findPathsToCheckedNodes","parentPath","currentPath","checkedKeys","expandableKeys","expandAllNodesTimer","debouncedExpandAllNodes","highlightAndExpandByIds","ids","findPathToKey","nk","newPath","p","targetIds","keysToExpand","targetId","clearHighlights","clearCurrentNode","searchForm","reactive","autoTriggerTypes","autoSearchTimer","visibleFields","displayedFields","hasHiddenFields","getFieldComponent","YSelect","YTime","YSwitch","YInput","updateFieldValue","f","handleFieldChange","scheduleAutoSearch","handleSwitchChange","handleSearch","searchParams","filterEmptyParams","formattedParams","formatSearchParams","rawParams","handleReset","toggleExpanded","getFieldListeners","handleInputQuickSearch","params","rawValue","formatted","startKey","endKey","initFormData","_c","_d","_e","onBeforeUnmount","_TransitionGroup","_resolveDynamicComponent","_toHandlers","YButton","timer","remainingTime","startTimer","clearTimer","duration","elapsed","onAfterLeave","seed","GAP","instances","calcOffset","offset","inst","id","computedTop","updatePositions","render","rmIndex","options","vm","createVNode","YMessageToast","cid","initialHeight","realHeight","YMessage","message","durationOrOpts","targetTop","currentHeight","popupRef","isContentTruncated","showPopup","popupTimer","checkTruncation","element","originalMaxHeight","hasClampClass","fullHeight","lineHeight","updatePopupPosition","handlePopupEnter","handlePopupLeave","popupRect","scrollX","scrollY","onUpdated","toggle","collapse","expand","components","YTable","YPagination","YBadge","YDialog","YPopover","YImage","YDropdown","YDrawer","YTree","QueryEncapsulation","HintTag","app"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/components/ybutton.vue","../src/components/yinput.vue","../src/components/ytable.vue","../src/components/yselect.vue","../src/components/ypagination.vue","../src/components/ybadge.vue","../src/components/ydialog.vue","../src/components/ypopover.vue","../src/components/ytime.vue","../src/components/yswitch.vue","../src/components/yimage.vue","../src/components/ydropdown.vue","../src/components/ydrawer.vue","../src/components/ytree-node.vue","../src/components/ytree.vue","../src/components/QueryEncapsulation.vue","../src/components/ymessage/ymessageToast.vue","../src/components/ymessage/ymessage.ts","../src/components/hintTag.vue","../src/index.ts"],"sourcesContent":["<template>\n <template v-if=\"!isGroup\">\n <button\n class=\"y-btn\"\n :class=\"[\n `y-btn--${variant}`,\n `y-btn--${size}`,\n { 'is-block': block, 'is-loading': loading },\n groupPosition !== 'single' ? 'is-grouped' : '',\n groupPositionClass\n ]\"\n :type=\"htmlType\"\n :disabled=\"disabled || loading\"\n :aria-busy=\"loading ? 'true' : 'false'\"\n :aria-disabled=\"(disabled || loading) ? 'true' : 'false'\"\n @click=\"onClick\"\n >\n <span class=\"content\"><slot /></span>\n </button>\n </template>\n <template v-else>\n <div class=\"y-btn-group\" role=\"group\">\n <button\n v-for=\"(item, index) in groupItems\"\n :key=\"item.value ?? index\"\n class=\"y-btn\"\n :class=\"[\n `y-btn--${item.variant ?? variant}`,\n `y-btn--${item.size ?? size}`,\n 'is-grouped',\n index === 0 ? 'group-pos-start' : (index === (groupItems?.length || 0) - 1 ? 'group-pos-end' : 'group-pos-middle'),\n { 'is-loading': item.loading || loading }\n ]\"\n :type=\"htmlType\"\n :disabled=\"(item.disabled ?? false) || disabled || loading || item.loading\"\n :aria-busy=\"(item.loading || loading) ? 'true' : 'false'\"\n :aria-disabled=\"((item.disabled ?? false) || disabled || loading || item.loading) ? 'true' : 'false'\"\n :aria-label=\"item.ariaLabel || item.label\"\n @click=\"onGroupItemClick(item, $event)\"\n >\n <span class=\"content\">\n <svg v-if=\"item.icon === 'chevron-left'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" d=\"M12.78 15.22a.75.75 0 01-1.06 0l-5-5a.75.75 0 010-1.06l5-5a.75.75 0 111.06 1.06L8.81 10l3.97 3.97a.75.75 0 010 1.06z\" clip-rule=\"evenodd\" />\n </svg>\n <svg v-else-if=\"item.icon === 'chevron-right'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" d=\"M7.22 4.78a.75.75 0 011.06 0l5 5a.75.75 0 010 1.06l-5 5a.75.75 0 11-1.06-1.06L11.19 10 7.22 6.03a.75.75 0 010-1.06z\" clip-rule=\"evenodd\" />\n </svg>\n <span v-if=\"item.label && !item.onlyIcon\">{{ item.label }}</span>\n </span>\n </button>\n </div>\n </template>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nconst props = withDefaults(defineProps<{\n htmlType?: 'button' | 'submit' | 'reset'\n variant?: 'primary' | 'secondary' | 'danger' | 'success' | 'info'\n size?: 'tiny' | 'mini' | 'small' | 'medium' | 'large'\n disabled?: boolean\n loading?: boolean\n block?: boolean\n /**\n * 组合按钮位置:\n * - single: 非组合(默认)\n * - start: 组合按钮的第一个\n * - middle: 组合按钮中间\n * - end: 组合按钮最后一个\n */\n groupPosition?: 'single' | 'start' | 'middle' | 'end'\n /**\n * 若提供,则此组件内部渲染为按钮组\n */\n groupItems?: Array<{\n label: string\n value?: string | number\n disabled?: boolean\n loading?: boolean\n variant?: 'primary' | 'secondary' | 'danger' | 'success' | 'info'\n size?: 'tiny' | 'mini' | 'small' | 'medium' | 'large'\n icon?: 'chevron-left' | 'chevron-right'\n onlyIcon?: boolean\n ariaLabel?: string\n }>\n}>(), {\n htmlType: 'button',\n variant: 'primary',\n size: 'medium',\n disabled: false,\n loading: false,\n block: false,\n groupPosition: 'single',\n groupItems: undefined,\n})\n\nconst emit = defineEmits<{\n (e: 'click', ev: MouseEvent): void\n (e: 'group-click', value: string | number | undefined, ev: MouseEvent): void\n}>()\n\nfunction onClick(ev: MouseEvent) {\n if (props.disabled || props.loading) {\n ev.preventDefault()\n ev.stopPropagation()\n return\n }\n emit('click', ev)\n}\n\nconst groupPositionClass = computed(() => {\n switch (props.groupPosition) {\n case 'start':\n return 'group-pos-start'\n case 'middle':\n return 'group-pos-middle'\n case 'end':\n return 'group-pos-end'\n default:\n return 'group-pos-single'\n }\n})\n\nconst isGroup = computed(() => Array.isArray(props.groupItems) && props.groupItems.length > 0)\n\nfunction onGroupItemClick(item: { value?: string | number; disabled?: boolean; loading?: boolean }, ev: MouseEvent) {\n if (props.disabled || props.loading || item.disabled || item.loading) {\n ev.preventDefault()\n ev.stopPropagation()\n return\n }\n emit('group-click', item.value, ev)\n}\n</script>\n\n<style scoped>\n.y-btn {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n border: none;\n border-radius: 10px;\n font-weight: 600;\n cursor: pointer;\n transition: transform 0.05s ease, opacity 0.2s ease;\n outline: none;\n}\n\n/* 尺寸变体 */\n.y-btn--tiny {\n height: 20px;\n padding: 0 6px;\n font-size: 10px;\n border-radius: 3px;\n}\n\n.y-btn--mini {\n height: 24px;\n padding: 0 8px;\n font-size: 11px;\n border-radius: 4px;\n}\n\n.y-btn--small {\n height: 32px;\n padding: 0 12px;\n font-size: 12px;\n border-radius: 5px;\n}\n\n.y-btn--medium {\n height: 44px;\n padding: 0 16px;\n font-size: 14px;\n border-radius: 7px;\n}\n\n.y-btn--large {\n height: 52px;\n padding: 0 20px;\n font-size: 16px;\n border-radius: 8px;\n}\n\n/* 变体样式 */\n.y-btn--primary {\n background: linear-gradient(90deg, #111827, #1f2937);\n color: #fff;\n}\n\n.y-btn--primary:hover { \n background: linear-gradient(90deg, #1f2937, #374151);\n}\n\n.y-btn--secondary {\n background: #f7f7f7;\n color: #374151;\n border: 1px solid #E2E8F0;\n}\n\n.y-btn--secondary:hover {\n background: #ebecee;\n border-color: #9ca3af;\n}\n\n.y-btn--danger {\n background: #c41e3a;\n color: #fff;\n border: 1px solid #c41e3a;\n}\n\n.y-btn--danger:hover {\n background: #ad152e;\n border-color: #ad152e;\n}\n\n.y-btn--success {\n background: #008060;\n color: #fff;\n border: 1px solid #008060;\n}\n\n.y-btn--success:hover {\n background: #006b4f;\n border-color: #006b4f;\n}\n\n.y-btn--info {\n background: #34b4fa;\n color: #fff;\n border: 1px solid #34b4fa;\n}\n\n.y-btn--info:hover {\n background: #1e9bdc;\n border-color: #1e9bdc;\n}\n\n.y-btn:active { \n transform: translateY(1px); \n}\n\n.y-btn.is-block { \n width: 100%; \n}\n\n.y-btn.is-loading { \n cursor: wait; \n opacity: 0.92; \n}\n\n/* 禁用态样式(单按钮与组按钮通用) */\n.y-btn:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.y-btn.is-loading .content { \n opacity: 0; \n}\n\n.y-btn.is-loading::after {\n content: '';\n position: absolute;\n left: 50%;\n top: 50%;\n width: 16px;\n height: 16px;\n transform: translate(-50%, -50%);\n border-radius: 50%;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: rgba(255,255,255,1);\n animation: spin 0.8s linear infinite;\n}\n\n.y-btn--tiny.is-loading::after {\n width: 10px;\n height: 10px;\n border-width: 1.5px;\n}\n\n.y-btn--mini.is-loading::after {\n width: 12px;\n height: 12px;\n border-width: 1.5px;\n}\n\n.y-btn--small.is-loading::after {\n width: 14px;\n height: 14px;\n border-width: 1.8px;\n}\n\n.y-btn--secondary.is-loading::after {\n border: 2px solid rgba(55, 65, 81, 0.3);\n border-top-color: rgba(55, 65, 81, 1);\n}\n\n.y-btn--danger.is-loading::after {\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: rgba(255,255,255,1);\n}\n\n.y-btn--success.is-loading::after {\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: rgba(255,255,255,1);\n}\n\n.y-btn--info.is-loading::after {\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: rgba(255,255,255,1);\n}\n\n/* 组合按钮样式(连体) */\n.y-btn-group { display: inline-flex; }\n.y-btn.is-grouped {\n border-radius: 0;\n}\n\n.y-btn.group-pos-start {\n border-top-left-radius: 7px;\n border-bottom-left-radius: 7px;\n}\n\n.y-btn.group-pos-middle {\n margin-left: -1px; /* 抵消边框以无缝连接 */\n}\n\n.y-btn.group-pos-end {\n margin-left: -1px; /* 抵消边框以无缝连接 */\n border-top-right-radius: 7px;\n border-bottom-right-radius: 7px;\n}\n\n/* 针对不同尺寸的圆角适配 */\n.y-btn--tiny.group-pos-start { border-top-left-radius: 3px; border-bottom-left-radius: 3px; }\n.y-btn--tiny.group-pos-end { border-top-right-radius: 3px; border-bottom-right-radius: 3px; }\n\n.y-btn--mini.group-pos-start { border-top-left-radius: 4px; border-bottom-left-radius: 4px; }\n.y-btn--mini.group-pos-end { border-top-right-radius: 4px; border-bottom-right-radius: 4px; }\n\n.y-btn--small.group-pos-start { border-top-left-radius: 5px; border-bottom-left-radius: 5px; }\n.y-btn--small.group-pos-end { border-top-right-radius: 5px; border-bottom-right-radius: 5px; }\n\n.y-btn--large.group-pos-start { border-top-left-radius: 8px; border-bottom-left-radius: 8px; }\n.y-btn--large.group-pos-end { border-top-right-radius: 8px; border-bottom-right-radius: 8px; }\n\n/* 提升 hover 时的层级,避免边框覆盖问题 */\n.y-btn.is-grouped { position: relative; z-index: 1; }\n.y-btn.is-grouped:hover { z-index: 2; }\n\n@keyframes spin {\n to { transform: translate(-50%, -50%) rotate(360deg); }\n}\n\n/* 图标尺寸与对齐 */\n.y-btn .icon {\n width: 16px;\n height: 16px;\n}\n\n@media (prefers-color-scheme: dark) {\n .y-btn--primary { \n background: linear-gradient(90deg, #0b1220, #111827); \n }\n \n .y-btn--secondary {\n background: rgba(2, 6, 23, 0.4);\n border-color: rgba(148, 163, 184, 0.18);\n color: #e5eef7;\n }\n \n .y-btn--secondary:hover {\n background: rgba(2, 6, 23, 0.6);\n border-color: rgba(148, 163, 184, 0.3);\n }\n}\n</style>","<template>\n <div class=\"y-input-wrap\" :class=\"{ 'is-block': block, 'has-password-toggle': showPasswordToggle }\" :style=\"{ width: width }\">\n <input\n ref=\"inputRef\"\n class=\"y-input\"\n :class=\"`y-input--${size}`\"\n :id=\"id\"\n :name=\"name\"\n :type=\"actualInputType\"\n :placeholder=\"inputPlaceholder\"\n :autocomplete=\"autocomplete\"\n :inputmode=\"inputmode\"\n :min=\"min\"\n :max=\"max\"\n :disabled=\"disabled\"\n :required=\"required\"\n :value=\"modelValue\"\n @input=\"onInput\"\n @focus=\"onFocus\"\n @blur=\"onBlur\"\n @keyup.enter=\"onEnter\"\n @paste=\"onPaste\"\n />\n <button\n v-if=\"showPasswordToggle\"\n type=\"button\"\n class=\"y-input-password-toggle\"\n :class=\"`y-input-password-toggle--${size}`\"\n @click=\"togglePasswordVisibility\"\n tabindex=\"-1\"\n >\n <svg v-if=\"passwordVisible\" class=\"y-input-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\"></path>\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\n </svg>\n <svg v-else class=\"y-input-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"></path>\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\n </svg>\n </button>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, computed } from 'vue'\n\nconst props = withDefaults(defineProps<{\n modelValue?: string\n type?: 'text' | 'email' | 'password' | 'search' | 'tel' | 'url' | 'number'\n placeholder?: string\n autocomplete?: string\n inputmode?: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url'\n id?: string\n name?: string\n disabled?: boolean\n required?: boolean\n block?: boolean\n size?: 'tiny' | 'mini' | 'small' | 'medium' | 'large'\n width?: string\n min?: string | number\n max?: string | number\n clearOnFocus?: boolean\n}>(), {\n modelValue: '',\n type: 'text',\n placeholder: '',\n autocomplete: 'off',\n inputmode: undefined,\n id: undefined,\n name: undefined,\n disabled: false,\n required: false,\n block: false,\n size: 'medium',\n width: '200px',\n min: undefined,\n max: undefined,\n clearOnFocus: false,\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n (e: 'enter', value: string): void\n (e: 'paste', value: string): void\n}>()\n\nconst inputRef = ref<HTMLInputElement | null>(null)\nconst previousValue = ref<string>('')\nconst hasChanged = ref<boolean>(false) // 标记用户是否修改了输入值\nconst isFocused = ref<boolean>(false) // 标记是否正在聚焦\nconst inputPlaceholder = ref<string>(props.placeholder || '')\nconst passwordVisible = ref<boolean>(false) // 密码是否可见\n\n// 计算是否显示密码切换按钮\nconst showPasswordToggle = computed(() => props.type === 'password')\n\n// 计算实际的输入类型\nconst actualInputType = computed(() => {\n if (props.type === 'password' && passwordVisible.value) {\n return 'text'\n }\n return props.type\n})\n\n// 切换密码显示/隐藏\nfunction togglePasswordVisibility() {\n passwordVisible.value = !passwordVisible.value\n}\n\nwatch(() => props.placeholder, (val) => {\n if (!isFocused.value) {\n inputPlaceholder.value = val || ''\n }\n})\n\nfunction onInput(ev: Event) {\n const target = ev.target as HTMLInputElement\n hasChanged.value = true // 标记用户已修改值\n emit('update:modelValue', target.value)\n}\n\nfunction onFocus() {\n isFocused.value = true\n if (props.clearOnFocus) {\n // 保存聚焦前的值\n previousValue.value = props.modelValue || ''\n // 重置修改标志\n hasChanged.value = false\n // 使用原值展示提示\n inputPlaceholder.value = previousValue.value || props.placeholder || ''\n // 清空输入框\n emit('update:modelValue', '')\n }\n}\n\nfunction onBlur() {\n isFocused.value = false\n if (props.clearOnFocus) {\n // 只有当用户没有修改值且失去焦点时值为空,才恢复之前的值\n if (!hasChanged.value && (!props.modelValue || props.modelValue === '')) {\n emit('update:modelValue', previousValue.value)\n }\n }\n\n // 如果传入了 min,并且当前值小于 min,则自动校正为最小值\n if (props.min !== undefined && props.modelValue !== undefined && props.modelValue !== '') {\n const current = Number(props.modelValue)\n const minVal = Number(props.min)\n if (!Number.isNaN(current) && !Number.isNaN(minVal) && current < minVal) {\n emit('update:modelValue', String(minVal))\n }\n }\n\n inputPlaceholder.value = props.placeholder || ''\n}\n\nfunction onEnter(ev: KeyboardEvent) {\n const target = ev.target as HTMLInputElement\n emit('enter', target.value)\n}\n\nfunction onPaste(ev: ClipboardEvent) {\n const target = ev.target as HTMLInputElement\n requestAnimationFrame(() => {\n emit('paste', target.value)\n })\n}\n</script>\n\n<style scoped>\n.y-input-wrap { \n width: 100%; \n position: relative;\n}\n.y-input-wrap.is-block { display: block; width: 100%; }\n.y-input-wrap.has-password-toggle .y-input {\n padding-right: 40px;\n}\n\n/* 继承登录页 .input 的视觉规范 */\n.y-input {\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n border: 1px solid #e2e8f0;\n border-radius: 10px;\n padding: 0 12px;\n font-size: 14px;\n outline: none;\n transition: box-shadow 0.2s ease, border-color 0.2s ease;\n background: #ffffff;\n color: #0b1a29;\n}\n\n/* 尺寸变体 */\n.y-input--tiny {\n height: 19px;\n padding: 0 6px;\n font-size: 10px;\n border-radius: 4px;\n}\n\n.y-input--mini {\n height: 24px;\n padding: 0 8px;\n font-size: 11px;\n border-radius: 6px;\n}\n\n.y-input--small {\n height: 32px;\n padding: 0 10px;\n font-size: 12px;\n border-radius: 8px;\n}\n\n.y-input--medium {\n height: 44px;\n padding: 0 12px;\n font-size: 14px;\n border-radius: 10px;\n}\n\n.y-input--large {\n height: 52px;\n padding: 0 16px;\n font-size: 16px;\n border-radius: 12px;\n}\n\n.y-input:focus {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59,130,246,0.15);\n}\n\n/* 密码切换按钮 */\n.y-input-password-toggle {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #64748b;\n transition: color 0.2s ease;\n outline: none;\n z-index: 1;\n}\n\n.y-input-password-toggle:hover {\n color: #475569;\n}\n\n.y-input-password-toggle:active {\n color: #334155;\n}\n\n.y-input-password-toggle--tiny {\n right: 4px;\n padding: 2px;\n}\n\n.y-input-password-toggle--mini {\n right: 6px;\n padding: 3px;\n}\n\n.y-input-password-toggle--small {\n right: 8px;\n padding: 4px;\n}\n\n.y-input-password-toggle--medium {\n right: 10px;\n padding: 5px;\n}\n\n.y-input-password-toggle--large {\n right: 12px;\n padding: 6px;\n}\n\n.y-input-icon {\n width: 18px;\n height: 18px;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.y-input-password-toggle--tiny .y-input-icon {\n width: 12px;\n height: 12px;\n}\n\n.y-input-password-toggle--mini .y-input-icon {\n width: 14px;\n height: 14px;\n}\n\n.y-input-password-toggle--small .y-input-icon {\n width: 16px;\n height: 16px;\n}\n\n.y-input-password-toggle--large .y-input-icon {\n width: 20px;\n height: 20px;\n}\n\n@media (prefers-color-scheme: dark) {\n .y-input {\n background: rgba(2,6,23,0.4);\n border-color: rgba(148,163,184,0.18);\n color: #e5eef7;\n }\n .y-input-password-toggle {\n color: rgba(148,163,184,0.7);\n }\n .y-input-password-toggle:hover {\n color: rgba(148,163,184,0.9);\n }\n .y-input-password-toggle:active {\n color: #e5eef7;\n }\n}\n</style>","<template>\n <div class=\"ytable-container\" ref=\"tableContainer\">\n <!-- 批量操作栏 -->\n <transition name=\"bulk-slide\">\n <div class=\"bulk-bar\" v-if=\"selectedItems.length && showBulkActions\">\n <div class=\"bulk-left\">已选择 {{ selectedItems.length }} 项</div>\n <div class=\"bulk-actions\">\n <slot name=\"bulk-actions\" :selectedItems=\"selectedItems\" :clearSelection=\"clearSelection\">\n <YButton size=\"small\" class=\"btn\" @click=\"clearSelection\">清除选择</YButton>\n </slot>\n </div>\n </div>\n </transition>\n\n <!-- 表格容器 -->\n <div class=\"card\">\n <!-- 表头右上角收起/展开所有提示标签按钮 -->\n <div class=\"table-header-actions\" v-if=\"hasHintTags\">\n <button \n class=\"toggle-all-hints-btn\" \n :class=\"{ 'is-expanded': allHintsExpanded }\"\n @click=\"toggleAllHints\"\n :title=\"allHintsExpanded ? '收起所有提示标签' : '展开所有提示标签'\"\n >\n <svg \n v-if=\"allHintsExpanded\"\n viewBox=\"0 0 24 24\" \n fill=\"none\" \n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"toggle-icon\"\n >\n <path \n d=\"M15 18L9 12L15 6\" \n stroke=\"currentColor\" \n stroke-width=\"2\" \n stroke-linecap=\"round\" \n stroke-linejoin=\"round\"\n />\n </svg>\n <svg \n v-else\n viewBox=\"0 0 24 24\" \n fill=\"none\" \n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"toggle-icon\"\n >\n <path \n d=\"M9 18L15 12L9 6\" \n stroke=\"currentColor\" \n stroke-width=\"2\" \n stroke-linecap=\"round\" \n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n <!-- 表头固定区域 -->\n <div class=\"table-header\" ref=\"headerRef\">\n <table class=\"table\">\n <colgroup>\n <col v-if=\"props.expandable\" style=\"width: 34px; min-width: 34px;\" />\n <col v-if=\"selectable\" style=\"width: 60px; min-width: 60px;\" />\n <col v-for=\"(col, i) in columns\" :key=\"col.key\"\n :style=\"{ width: headerColWidths[i] || undefined, minWidth: headerColWidths[i] || '80px' }\" />\n </colgroup>\n <thead>\n <tr>\n <th v-if=\"props.expandable\" class=\"col-expand\"></th>\n <!-- 选择列 -->\n <th v-if=\"selectable\" class=\"col-select\">\n <div class=\"select-header\">\n <input \n type=\"checkbox\" \n :checked=\"isAllVisibleSelected\" \n :indeterminate=\"isPartiallySelected\"\n :disabled=\"isAllVisibleDisabled\"\n @change=\"toggleSelectAllVisible\" \n />\n <span v-if=\"selectedItems.length > 0\" class=\"select-count\">{{ selectedItems.length }}</span>\n </div>\n </th>\n <!-- 动态列头:如果有选中项且提供了自定义表头插槽,则显示自定义内容 -->\n <th \n v-if=\"selectedItems.length > 0 && $slots['selected-header']\"\n :colspan=\"columns.length\"\n class=\"col-selected-header\"\n >\n <div class=\"selected-header-wrapper\">\n <slot name=\"selected-header\" :selectedItems=\"selectedItems\" :clearSelection=\"clearSelection\"></slot>\n </div>\n </th>\n <template v-else>\n <th \n v-for=\"(column, colIndex) in columns\" \n :key=\"column.key\" \n :class=\"getColumnClass(column, true)\"\n :style=\"getColumnStyle(column, colIndex, true)\"\n >\n {{ column.title }}\n </th>\n </template>\n </tr>\n </thead>\n </table>\n </div>\n \n <!-- 表格内容滚动区域 -->\n <div class=\"table-body-wrap\" ref=\"bodyWrapRef\" :class=\"{ 'is-loading': loading, 'is-empty': !pagedData.length && !loading }\" :style=\"{ maxHeight: tableMaxHeight }\">\n <!-- Loading 状态 -->\n <div v-if=\"loading\" class=\"loading-overlay\">\n <div class=\"loading-spinner\"></div>\n <div class=\"loading-text\">加载中...</div>\n </div>\n\n <!-- 空数据覆盖层 -->\n <div v-if=\"!pagedData.length && !loading\" class=\"empty-overlay\">\n <slot name=\"empty\">\n {{ emptyText }}\n </slot>\n </div>\n \n <table class=\"table\" :class=\"{ 'loading-table': loading }\" ref=\"bodyTableRef\">\n <colgroup>\n <col v-if=\"props.expandable\" style=\"width: 34px; min-width: 34px;\" />\n <col v-if=\"selectable\" style=\"width: 60px; min-width: 60px;\" />\n <col v-for=\"(col, i) in columns\" :key=\"col.key\"\n :style=\"{ width: headerColWidths[i] || undefined, minWidth: headerColWidths[i] || '80px' }\" />\n </colgroup>\n <tbody>\n <template v-for=\"(item, index) in pagedData\" :key=\"getRowKey(item, index)\">\n <tr\n :class=\"{ 'row-selected': isRowSelected(item, index) }\"\n @click=\"handleRowClick(item, index)\"\n >\n <td v-if=\"props.expandable\" class=\"col-expand\">\n <button class=\"expand-btn\" type=\"button\" @click.stop=\"toggleRowExpand(getRowKey(item, index))\">\n <span :class=\"['expand-icon', { 'is-open': isRowExpanded(getRowKey(item, index)) }]\"></span>\n </button>\n </td>\n <!-- 选择列 -->\n <td v-if=\"selectable\" class=\"col-select\" @click.stop>\n <input \n type=\"checkbox\" \n :value=\"getRowKey(item, index)\"\n :checked=\"selectedItems.includes(getRowKey(item, index))\" \n :disabled=\"isRowDisabled(item, index)\"\n @change.stop=\"toggleSelect(getRowKey(item, index))\" \n />\n </td>\n <!-- 动态数据列 -->\n <td \n v-for=\"(column, colIndex) in columns\" \n :key=\"column.key\"\n :class=\"getColumnClass(column)\"\n :style=\"getColumnStyle(column, colIndex, false)\"\n >\n <slot \n :name=\"`cell-${column.key}`\" \n :item=\"item\" \n :value=\"getNestedValue(item, column.key)\"\n :index=\"index\"\n >\n {{ formatCellValue(item, column) }}\n </slot>\n </td>\n </tr>\n <tr\n v-if=\"props.expandable && isRowExpanded(getRowKey(item, index))\"\n :key=\"`${getRowKey(item, index)}-expand`\"\n class=\"expand-row\"\n >\n <td :colspan=\"totalTableColumns\" class=\"expand-cell\">\n <slot name=\"expand\" :item=\"item\" :index=\"index\" />\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n </div>\n\n <!-- 分页 -->\n <YPagination\n class=\"align-right\"\n v-if=\"pagination\"\n v-model:current-page=\"currentPage\"\n v-model:page-size=\"pageSize\"\n :loading=\"props.loading\"\n :disable-next=\"shouldDisableNext\"\n :page-size-options=\"pageSizeOptions\"\n @page-change=\"handlePageChange\"\n @page-size-change=\"handlePageSizeChange\"\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch, onMounted, onUnmounted, nextTick, provide } from 'vue'\n\nexport interface TableColumn {\n key: string\n title: string\n width?: string | number\n align?: 'left' | 'center' | 'right'\n formatter?: (value: any, item: any) => string\n sortable?: boolean\n fixed?: 'left' | 'right'\n}\n\nexport interface TableProps {\n data: any[]\n columns: TableColumn[]\n selectable?: boolean\n showBulkActions?: boolean\n pagination?: boolean\n pageSize?: number\n currentPage?: number\n total?: number\n loading?: boolean\n pageSizeOptions?: Array<{ label: string; value: number }>\n rowKey?: string | ((item: any) => string | number)\n emptyText?: string\n searchKeyword?: string\n searchFields?: string[]\n stickyHeader?: boolean\n expandable?: boolean\n rowDisabled?: (item: any, index: number) => boolean\n selectedItems?: (string | number)[]\n rowSelectable?: boolean\n requireDeselectBeforeSelect?: boolean\n}\n\nconst props = withDefaults(defineProps<TableProps & {\n expandable?: boolean\n rowDisabled?: (item: any, index: number) => boolean\n selectedItems?: (string | number)[]\n rowSelectable?: boolean\n requireDeselectBeforeSelect?: boolean\n}>(), {\n selectable: false,\n showBulkActions: false,\n pagination: true,\n pageSize: 10,\n loading: false,\n pageSizeOptions: () => [\n { label: '1/页', value: 1 },\n { label: '20/页', value: 20 },\n { label: '50/页', value: 50 },\n { label: '100/页', value: 100 }\n ],\n rowKey: 'id',\n emptyText: '无数据',\n searchKeyword: '',\n searchFields: () => [],\n stickyHeader: false,\n rowDisabled: undefined,\n selectedItems: undefined,\n rowSelectable: false,\n requireDeselectBeforeSelect: true\n})\n\nconst emit = defineEmits<{\n edit: [item: any]\n select: [selectedItems: (string | number)[]]\n 'update:selectedItems': [selectedItems: (string | number)[]]\n 'page-change': [page: number]\n 'page-size-change': [size: number]\n 'row-click': [item: any, key: string | number | null]\n}>()\n\n// 响应式数据\nconst currentPage = ref(props.currentPage || 1)\nconst pageSize = ref(props.pageSize)\nconst selectedItems = ref<(string | number)[]>(props.selectedItems || [])\nconst selectedRowKey = ref<(string | number)[]>([])\nconst expandedKeys = ref<Set<string | number>>(new Set())\nconst tableMaxHeight = ref('none')\nconst tableContainer = ref<HTMLElement>()\nconst headerRef = ref<HTMLElement>()\nconst bodyWrapRef = ref<HTMLElement>()\nconst bodyTableRef = ref<HTMLTableElement>()\n// 头部列宽数组:优先使用外部列宽;未传则根据首行内容测量\nconst headerColWidths = ref<string[]>([])\nconst headerWidthMap = ref<Record<string, string>>({})\n// 存储默认表头的标准高度\nconst defaultHeaderHeight = ref<number>(35)\n\n// 管理所有 hintTag 实例\nconst hintTagInstances = ref<Set<any>>(new Set())\n\n// 计算是否有 hintTag 实例(用于控制按钮显示)\nconst hasHintTags = computed(() => hintTagInstances.value.size > 0)\n\n// 计算当前所有 hintTag 的展开状态\n// 使用 hintTagStateUpdateTrigger 确保响应式更新\nconst allHintsExpanded = computed(() => {\n // 引用 hintTagStateUpdateTrigger 以建立响应式依赖\n void hintTagStateUpdateTrigger.value\n \n if (hintTagInstances.value.size === 0) return false\n let expandedCount = 0\n hintTagInstances.value.forEach((instance) => {\n if (instance && instance.isExpanded) {\n expandedCount++\n }\n })\n return expandedCount === hintTagInstances.value.size\n})\n\n// 计算是否所有 hintTag 都已收起\nconst allHintsCollapsed = computed(() => {\n // 引用 hintTagStateUpdateTrigger 以建立响应式依赖\n void hintTagStateUpdateTrigger.value\n \n if (hintTagInstances.value.size === 0) return true\n let collapsedCount = 0\n hintTagInstances.value.forEach((instance) => {\n if (instance && !instance.isExpanded) {\n collapsedCount++\n }\n })\n return collapsedCount === hintTagInstances.value.size\n})\n\n// 注册 hintTag 实例\nfunction registerHintTag(instance: any) {\n hintTagInstances.value.add(instance)\n}\n\n// 注销 hintTag 实例\nfunction unregisterHintTag(instance: any) {\n hintTagInstances.value.delete(instance)\n}\n\n// 收起所有 hintTag\nfunction collapseAllHints() {\n hintTagInstances.value.forEach((instance) => {\n if (instance && typeof instance.collapse === 'function') {\n instance.collapse()\n }\n })\n}\n\n// 展开所有 hintTag\nfunction expandAllHints() {\n hintTagInstances.value.forEach((instance) => {\n if (instance && typeof instance.expand === 'function') {\n instance.expand()\n }\n })\n}\n\n// 切换所有 hintTag 的展开/收起状态\nfunction toggleAllHints() {\n if (allHintsExpanded.value) {\n // 如果全部展开,则全部收起\n collapseAllHints()\n } else {\n // 否则全部展开\n expandAllHints()\n }\n}\n\n// 用于触发计算属性重新计算的响应式变量\nconst hintTagStateUpdateTrigger = ref(0)\n\n// 通知 hintTag 状态变化的函数\nfunction notifyHintTagStateChange() {\n hintTagStateUpdateTrigger.value++\n}\n\n// 通过 provide 向子组件提供注册方法\nprovide('registerHintTag', registerHintTag)\nprovide('unregisterHintTag', unregisterHintTag)\nprovide('notifyHintTagStateChange', notifyHintTagStateChange)\n\nconst autoColumnKeys = computed(() =>\n props.columns\n .filter((col) => !normalizeWidth(col.width))\n .map((col) => col.key)\n)\n\nfunction getAutoColumnWidth(): string {\n const count = autoColumnKeys.value.length || 1\n const per = 100 / count\n return `${per.toFixed(6)}%`\n}\n\n// 自定义竖向滚动条状态\nconst vTrackRef = ref<HTMLElement>()\nconst vScroll = ref({\n show: false,\n thumbHeight: 40,\n thumbTop: 0\n})\nlet isDragging = false\nlet dragStartY = 0\nlet dragStartScrollTop = 0\n\n// 滚动条宽度(用于表头右侧固定列对齐)\nconst scrollbarWidth = ref(0)\n\nfunction normalizeWidth(width?: string | number): string | undefined {\n if (width === undefined || width === null) return undefined\n if (typeof width === 'number') {\n if (Number.isFinite(width)) {\n return `${width}px`\n }\n return undefined\n }\n const trimmed = String(width).trim()\n if (!trimmed) return undefined\n if (/^\\d+(\\.\\d+)?$/.test(trimmed)) {\n return `${trimmed}px`\n }\n return trimmed\n}\n\nfunction parseWidthNumber(width?: string | number): number | null {\n const normalized = normalizeWidth(width)\n if (!normalized) return null\n const parsed = parseFloat(normalized)\n return Number.isFinite(parsed) ? parsed : null\n}\n\n// 计算属性\n// const totalColumns = computed(() => {\n// let count = props.columns.length\n// if (props.selectable) count++\n// return count\n// })\n\nconst totalTableColumns = computed(() => {\n let count = props.columns.length\n if (props.selectable) count += 1\n if (props.expandable) count += 1\n return count\n})\n\nconst filteredData = computed(() => {\n if (!props.searchKeyword || !props.searchFields.length) {\n return props.data\n }\n \n const keyword = props.searchKeyword.toLowerCase()\n return props.data.filter((item) => {\n return props.searchFields!.some(field => {\n const value = getNestedValue(item, field)\n return String(value).toLowerCase().includes(keyword)\n })\n })\n})\n\n// 移除对 total 的依赖,不再计算总页数\n\nconst pagedData = computed(() => {\n if (!props.pagination) return filteredData.value\n // 服务端分页:不再依赖 total 和 totalPages,直接渲染传入数据\n return filteredData.value\n})\n\nconst isAllVisibleSelected = computed(() => {\n if (!props.selectable) return false\n const visibleKeys = pagedData.value\n .map((item, index) => ({ key: getRowKey(item, index), item, index }))\n .filter(({ item, index }) => !isRowDisabled(item, index))\n .map(({ key }) => key)\n return visibleKeys.length > 0 && visibleKeys.every(key => selectedItems.value.includes(key))\n})\n\n// 判断是否为部分选中状态(中间状态)\nconst isPartiallySelected = computed(() => {\n if (!props.selectable) return false\n if (isAllVisibleSelected.value) return false // 如果全选,则不是中间状态\n const visibleKeys = pagedData.value\n .map((item, index) => ({ key: getRowKey(item, index), item, index }))\n .filter(({ item, index }) => !isRowDisabled(item, index))\n .map(({ key }) => key)\n // 如果有可见的未禁用行,且部分被选中,则显示中间状态\n if (visibleKeys.length === 0) return false\n const selectedCount = visibleKeys.filter(key => selectedItems.value.includes(key)).length\n return selectedCount > 0 && selectedCount < visibleKeys.length\n})\n\nconst isAllVisibleDisabled = computed(() => {\n if (!props.selectable) return false\n // 如果所有可见行都被禁用,则全选按钮也禁用\n const visibleKeys = pagedData.value.map((item, index) => ({ item, index }))\n return visibleKeys.length > 0 && visibleKeys.every(({ item, index }) => isRowDisabled(item, index))\n})\n\n// 判断是否应该禁用下一页按钮\n// 当返回的数据量小于 pageSize 时,说明已经到最后一页了\nconst shouldDisableNext = computed(() => {\n if (!props.pagination) return false\n // 如果当前页数据量小于每页显示条数,说明已经是最后一页\n return pagedData.value.length < pageSize.value\n})\n\n// 计算固定列的累计宽度\nconst fixedLeftWidths = computed(() => {\n const widths: number[] = []\n let cumulativeWidth = props.selectable ? 60 : 0 // 选择列宽度\n \n for (let i = 0; i < props.columns.length; i++) {\n const col = props.columns[i]\n if (col.fixed === 'left') {\n let width = 80 // 默认宽度\n const parsedWidth = parseWidthNumber(col.width)\n if (parsedWidth !== null) {\n width = parsedWidth\n } else if (headerColWidths.value[i]) {\n const parsedHeaderWidth = parseWidthNumber(headerColWidths.value[i])\n width = parsedHeaderWidth ?? width\n }\n widths.push(cumulativeWidth)\n cumulativeWidth += width\n }\n }\n return widths\n})\n\nconst fixedRightWidths = computed(() => {\n const widths: number[] = []\n let cumulativeWidth = 0\n \n // 从右往左计算,但需要保证索引顺序正确\n // 先收集所有右侧固定列的宽度和索引\n const rightFixedColumns: Array<{ index: number; width: number }> = []\n for (let i = props.columns.length - 1; i >= 0; i--) {\n const col = props.columns[i]\n if (col.fixed === 'right') {\n let width = 80 // 默认宽度\n const parsedWidth = parseWidthNumber(col.width)\n if (parsedWidth !== null) {\n width = parsedWidth\n } else if (headerColWidths.value[i]) {\n const parsedHeaderWidth = parseWidthNumber(headerColWidths.value[i])\n width = parsedHeaderWidth ?? width\n }\n rightFixedColumns.push({ index: i, width })\n }\n }\n \n // 从右到左计算累计宽度(数组顺序:最右边的列索引最小)\n // widths[i] 对应第 i 个右侧固定列(从右往左数)的 right 偏移量\n for (let i = 0; i < rightFixedColumns.length; i++) {\n widths.push(cumulativeWidth)\n cumulativeWidth += rightFixedColumns[i].width\n }\n \n return widths\n})\n\n// 获取固定列的索引位置(用于查找对应的累计宽度)\nfunction getFixedColumnIndex(columnIndex: number, fixed: 'left' | 'right'): number {\n if (fixed === 'left') {\n let count = 0\n for (let i = 0; i < columnIndex; i++) {\n if (props.columns[i].fixed === 'left') {\n count++\n }\n }\n return count\n } else {\n // 对于右侧固定列,计算从右往左是第几个(索引0是最右边的)\n let count = 0\n for (let i = props.columns.length - 1; i > columnIndex; i--) {\n if (props.columns[i].fixed === 'right') {\n count++\n }\n }\n return count\n }\n}\n\n// 方法\nfunction getRowKey(item: any, index: number): string | number {\n if (typeof props.rowKey === 'function') {\n return props.rowKey(item)\n }\n return item[props.rowKey] || index\n}\n\n// 检查行是否被禁用\nfunction isRowDisabled(item: any, index: number): boolean {\n if (props.rowDisabled && typeof props.rowDisabled === 'function') {\n return props.rowDisabled(item, index)\n }\n return false\n}\n\nfunction isRowExpanded(key: string | number) {\n return expandedKeys.value.has(key)\n}\n\nfunction toggleRowExpand(key: string | number) {\n if (expandedKeys.value.has(key)) {\n expandedKeys.value.delete(key)\n } else {\n expandedKeys.value.add(key)\n }\n}\n\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj)\n}\n\nfunction getColumnClass(column: TableColumn, isHeader = false): string {\n const classes = [] as string[]\n if (column.align) {\n classes.push(`text-${column.align}`)\n }\n if (column.fixed === 'right') {\n classes.push('col-fixed-right')\n if (isHeader) classes.push('col-fixed-right-header')\n }\n if (column.fixed === 'left') {\n classes.push('col-fixed-left')\n if (isHeader) classes.push('col-fixed-left-header')\n }\n return classes.join(' ')\n}\n\nfunction getColumnStyle(column: TableColumn, columnIndex: number, isHeader: boolean): Record<string, string> {\n const style: Record<string, string> = {}\n \n const normalizedWidth = normalizeWidth(column.width)\n if (normalizedWidth) {\n // 如果设置了固定宽度,使用固定宽度\n style.width = normalizedWidth\n style.minWidth = normalizedWidth\n style.maxWidth = normalizedWidth\n } else {\n // 如果没有设置宽度,使用均等分配的宽度,确保列宽稳定\n const autoWidth = getAutoColumnWidth()\n style.width = autoWidth\n style.minWidth = autoWidth\n style.maxWidth = autoWidth\n }\n \n // 处理固定列的位置\n if (column.fixed === 'left') {\n const fixedIndex = getFixedColumnIndex(columnIndex, 'left')\n const leftOffset = fixedLeftWidths.value[fixedIndex] || 0\n style.left = `${leftOffset}px`\n style.zIndex = isHeader ? `${10 + fixedIndex}` : `${5 + fixedIndex}`\n } else if (column.fixed === 'right') {\n const fixedIndex = getFixedColumnIndex(columnIndex, 'right')\n const rightOffset = fixedRightWidths.value[fixedIndex] || 0\n \n // 对于表头的右侧固定列,减去2px以精确对齐\n // 这可能是因为边框或间距导致的细微差异\n if (isHeader) {\n style.right = `${rightOffset - 3}px`\n } else {\n style.right = `${rightOffset}px`\n }\n \n style.zIndex = isHeader ? `${10 + fixedIndex}` : `${5 + fixedIndex}`\n }\n \n return style\n}\n\nfunction formatCellValue(item: any, column: TableColumn): string {\n const value = getNestedValue(item, column.key)\n if (column.formatter) {\n return column.formatter(value, item)\n }\n return value || ''\n}\n\nfunction toggleSelect(key: string | number) {\n // 找到对应的行数据\n const rowData = pagedData.value.find((item, index) => getRowKey(item, index) === key)\n const rowIndex = pagedData.value.findIndex((item, index) => getRowKey(item, index) === key)\n \n // 如果行被禁用,不允许选择\n if (rowData && rowIndex >= 0 && isRowDisabled(rowData, rowIndex)) {\n return\n }\n \n if (selectedItems.value.includes(key)) {\n selectedItems.value = selectedItems.value.filter(x => x !== key)\n } else {\n selectedItems.value = [...selectedItems.value, key]\n }\n emit('select', selectedItems.value)\n emit('update:selectedItems', selectedItems.value)\n}\n\nfunction toggleSelectAllVisible() {\n // 只处理未禁用的行\n const visibleKeys = pagedData.value\n .map((item, index) => ({ key: getRowKey(item, index), item, index }))\n .filter(({ item, index }) => !isRowDisabled(item, index))\n .map(({ key }) => key)\n \n if (visibleKeys.length === 0) return\n \n if (visibleKeys.every(key => selectedItems.value.includes(key))) {\n selectedItems.value = selectedItems.value.filter(key => !visibleKeys.includes(key))\n } else {\n const union = new Set([...selectedItems.value, ...visibleKeys])\n selectedItems.value = Array.from(union)\n }\n emit('select', selectedItems.value)\n emit('update:selectedItems', selectedItems.value)\n}\n\nfunction clearSelection() {\n selectedItems.value = []\n emit('select', selectedItems.value)\n emit('update:selectedItems', selectedItems.value)\n}\n\n// 行点击选中处理\nfunction handleRowClick(item: any, index: number) {\n if (!props.rowSelectable) return\n \n const key = getRowKey(item, index)\n \n // 如果行被禁用,不允许选择\n if (isRowDisabled(item, index)) {\n return\n }\n \n // 根据 requireDeselectBeforeSelect 决定行为\n if (props.requireDeselectBeforeSelect) {\n // 模式1:可以多选,再次点击为取消\n if (selectedRowKey.value.includes(key)) {\n // 如果已选中,则取消选中\n selectedRowKey.value = selectedRowKey.value.filter(k => k !== key)\n emit('row-click', item, null)\n } else {\n // 如果未选中,则添加到选中列表\n selectedRowKey.value = [...selectedRowKey.value, key]\n emit('row-click', item, key)\n }\n } else {\n // 模式2:点击其他行时,自动切换选中状态(单选模式)\n if (selectedRowKey.value.includes(key)) {\n selectedRowKey.value = []\n emit('row-click', item, null)\n } else {\n selectedRowKey.value = [key]\n emit('row-click', item, key)\n }\n }\n}\n\n// 判断行是否被选中\nfunction isRowSelected(item: any, index: number): boolean {\n if (!props.rowSelectable) return false\n const key = getRowKey(item, index)\n return selectedRowKey.value.includes(key)\n}\n\n// 监听外部传入的 selectedItems prop,同步到内部状态\nwatch(() => props.selectedItems, (newVal) => {\n if (newVal !== undefined && Array.isArray(newVal)) {\n // 只有当外部传入的值与内部值不同时才更新,避免循环更新\n const currentSet = new Set(selectedItems.value)\n const newSet = new Set(newVal)\n if (currentSet.size !== newSet.size || \n ![...currentSet].every(key => newSet.has(key))) {\n selectedItems.value = [...newVal]\n }\n } else if (newVal === undefined && selectedItems.value.length > 0) {\n // 如果外部传入 undefined 且内部有选中项,清空内部选中状态\n selectedItems.value = []\n }\n}, { deep: true, immediate: true })\n\n// 监听搜索关键词变化,重置页码\nwatch(() => props.searchKeyword, () => {\n currentPage.value = 1\n})\n\n// 监听数据变化,重置页码(仅在客户端分页时)并清空选中行\nwatch(() => props.data, () => {\n // 只有在没有外部 total 的情况下(客户端分页)才重置页码\n if (!props.total) {\n currentPage.value = 1\n }\n // 数据变化时清空选中行状态\n if (props.rowSelectable) {\n selectedRowKey.value = []\n }\n}, { deep: true })\n\n// 分页事件处理\nfunction handlePageChange(page: number) {\n currentPage.value = page\n // 分页变化时清空选中行状态\n if (props.rowSelectable) {\n selectedRowKey.value = []\n }\n emit('page-change', page)\n}\n\nfunction handlePageSizeChange(size: number) {\n pageSize.value = size\n currentPage.value = 1 // 切换每页条数后重置到第一页\n // 分页大小变化时清空选中行状态\n if (props.rowSelectable) {\n selectedRowKey.value = []\n }\n emit('page-size-change', size)\n}\n\n// 父组件重置分页时,同步内部选中状态\nwatch(() => props.currentPage, (val) => {\n const next = typeof val === 'number' && val > 0 ? val : 1\n if (currentPage.value !== next) currentPage.value = next\n})\n\nwatch(() => props.pageSize, (val) => {\n const next = typeof val === 'number' && val > 0 ? val : 10\n if (pageSize.value !== next) pageSize.value = next\n})\n\n// 计算表格最大高度\nfunction calculateTableMaxHeight() {\n if (!tableContainer.value) return\n \n nextTick(() => {\n const containerRect = tableContainer.value!.getBoundingClientRect()\n const viewportHeight = window.innerHeight\n const containerTop = containerRect.top\n \n // 获取表头高度\n const headerElement = tableContainer.value!.querySelector('.table-header') as HTMLElement\n const headerHeight = headerElement ? headerElement.offsetHeight : 40\n \n // 获取分页组件高度\n let paginationHeight = 0\n if (props.pagination) {\n const paginationElement = tableContainer.value!.querySelector('.ypagination') as HTMLElement\n paginationHeight = paginationElement ? paginationElement.offsetHeight : 60\n }\n \n // 获取批量操作栏高度\n const bulkBarElement = tableContainer.value!.querySelector('.bulk-bar') as HTMLElement\n const bulkBarHeight = bulkBarElement ? bulkBarElement.offsetHeight : 0\n \n // 计算可用空间\n // 有分页时:减去表头高度、分页组件高度、批量操作栏高度、安全边距(20px)\n // 无分页时:减去表头高度、批量操作栏高度、安全边距(40px,离底部更远)\n const safeMargin = 20\n const reservedHeight = headerHeight + paginationHeight + bulkBarHeight + safeMargin\n const availableHeight = viewportHeight - containerTop - reservedHeight\n \n // 设置最小高度为200px,最大高度为可用空间\n const minHeight = 200\n const maxHeight = Math.max(minHeight, availableHeight)\n \n // 获取表格内容高度\n const tableContent = tableContainer.value!.querySelector('.table-body-wrap .table') as HTMLElement\n if (tableContent) {\n const contentHeight = tableContent.offsetHeight\n \n // 如果内容高度超过可用空间,则限制高度并显示滚动条\n if (contentHeight > availableHeight) {\n tableMaxHeight.value = `${maxHeight}px`\n } else {\n // 如果内容高度小于可用空间,则不限制高度\n tableMaxHeight.value = 'none'\n }\n }\n })\n}\n\n// 同步表头与内容的横向滚动\nlet isSyncingScroll = false // 防止循环同步\nfunction syncHeaderScroll() {\n if (!headerRef.value || !bodyWrapRef.value || isSyncingScroll) return\n if (headerRef.value.scrollLeft !== bodyWrapRef.value.scrollLeft) {\n isSyncingScroll = true\n headerRef.value.scrollLeft = bodyWrapRef.value.scrollLeft\n requestAnimationFrame(() => {\n isSyncingScroll = false\n })\n }\n}\n\n// 同步表头滚动到内容区域\nfunction syncBodyScroll() {\n if (!headerRef.value || !bodyWrapRef.value || isSyncingScroll) return\n if (bodyWrapRef.value.scrollLeft !== headerRef.value.scrollLeft) {\n isSyncingScroll = true\n bodyWrapRef.value.scrollLeft = headerRef.value.scrollLeft\n requestAnimationFrame(() => {\n isSyncingScroll = false\n })\n }\n}\n\n// 计算虚拟竖向滚动条尺寸与位置\nfunction updateVirtualScrollbar() {\n nextTick(() => {\n if (!bodyWrapRef.value) return\n const wrap = bodyWrapRef.value\n const contentHeight = wrap.scrollHeight\n const viewport = wrap.clientHeight\n const scrollTop = wrap.scrollTop\n const needVBar = contentHeight > viewport + 1\n vScroll.value.show = needVBar\n if (!needVBar) return\n\n const minThumb = 24\n const ratio = viewport / contentHeight\n const trackHeight = vTrackRef.value ? vTrackRef.value.clientHeight : viewport\n const thumbHeight = Math.max(minThumb, Math.floor(trackHeight * ratio))\n vScroll.value.thumbHeight = thumbHeight\n\n const maxThumbTop = Math.max(0, trackHeight - thumbHeight)\n const maxScrollTop = Math.max(1, contentHeight - viewport)\n vScroll.value.thumbTop = Math.min(maxThumbTop, Math.floor((scrollTop / maxScrollTop) * maxThumbTop))\n })\n}\n\nfunction onThumbMousemove(e: MouseEvent) {\n if (!isDragging || !bodyWrapRef.value || !vTrackRef.value) return\n e.preventDefault()\n const trackHeight = vTrackRef.value.clientHeight\n const maxThumbTop = Math.max(0, trackHeight - vScroll.value.thumbHeight)\n const wrap = bodyWrapRef.value\n const contentHeight = wrap.scrollHeight\n const viewport = wrap.clientHeight\n const maxScrollTop = Math.max(1, contentHeight - viewport)\n const deltaY = e.clientY - dragStartY\n const scrollDelta = (deltaY / Math.max(1, maxThumbTop)) * maxScrollTop\n wrap.scrollTop = Math.min(maxScrollTop, Math.max(0, dragStartScrollTop + scrollDelta))\n updateVirtualScrollbar()\n}\n\nfunction onThumbMouseup() {\n isDragging = false\n window.removeEventListener('mousemove', onThumbMousemove)\n window.removeEventListener('mouseup', onThumbMouseup)\n}\n\n// function onTrackMousedown(e: MouseEvent) {\n// if (!bodyWrapRef.value || !vTrackRef.value) return\n// // 点击轨道跳转:将滑块中心移动到点击处\n// const rect = vTrackRef.value.getBoundingClientRect()\n// const y = e.clientY - rect.top\n// const trackHeight = vTrackRef.value.clientHeight\n// const thumbHeight = vScroll.value.thumbHeight\n// const targetTop = Math.min(Math.max(0, y - thumbHeight / 2), Math.max(0, trackHeight - thumbHeight))\n//\n// const wrap = bodyWrapRef.value\n// const contentHeight = wrap.scrollHeight\n// const viewport = wrap.clientHeight\n// const maxScrollTop = Math.max(1, contentHeight - viewport)\n// const maxThumbTop = Math.max(1, trackHeight - thumbHeight)\n// const targetScrollTop = (targetTop / maxThumbTop) * maxScrollTop\n// wrap.scrollTop = targetScrollTop\n// updateVirtualScrollbar()\n// }\n\n// 计算/测量列宽:对未设置 width 的列,使用首行单元格的内容宽度\nfunction measureAutoColumnWidths() {\n nextTick(() => {\n // 如果已完整测量过列宽,则不再重复测量,避免分页切换时轻微跳动\n if (headerColWidths.value.length === props.columns.length && headerColWidths.value.every(w => !!w)) {\n return\n }\n const widths: string[] = []\n // 先用 props.columns 中显式宽度填充\n props.columns.forEach((col, index) => {\n const normalizedWidth = normalizeWidth(col.width)\n if (normalizedWidth) {\n widths.push(normalizedWidth)\n headerWidthMap.value[col.key] = normalizedWidth\n } else if (headerWidthMap.value[col.key]) {\n widths.push(headerWidthMap.value[col.key])\n } else {\n const fallback = headerColWidths.value[index]\n if (fallback) {\n widths.push(fallback)\n headerWidthMap.value[col.key] = fallback\n } else {\n const autoWidth = getAutoColumnWidth()\n widths.push(autoWidth)\n headerWidthMap.value[col.key] = autoWidth\n }\n }\n })\n\n const firstRow = bodyTableRef.value?.querySelector('tbody tr') as HTMLTableRowElement | null\n if (firstRow) {\n // 计算 data 列在 tbody 中的起始索引\n const startIndex = props.selectable ? 1 : 0\n const tds = Array.from(firstRow.children) as HTMLElement[]\n for (let i = 0; i < props.columns.length; i++) {\n if (!widths[i]) {\n const td = tds[startIndex + i] as HTMLElement | undefined\n if (td && td.clientWidth > 0) {\n const measured = `${td.clientWidth}px`\n widths[i] = measured\n headerWidthMap.value[props.columns[i].key] = measured\n } else {\n const autoWidth = getAutoColumnWidth()\n widths[i] = autoWidth\n headerWidthMap.value[props.columns[i].key] = autoWidth\n }\n }\n }\n } else {\n // 没有数据时,尽量沿用上一次测量结果,避免列宽跳动\n for (let i = 0; i < widths.length; i++) {\n if (!widths[i]) {\n const stored = headerWidthMap.value[props.columns[i]?.key || '']\n widths[i] = stored || headerColWidths.value[i] || '80px'\n if (props.columns[i]) {\n headerWidthMap.value[props.columns[i].key] = widths[i]\n }\n }\n }\n }\n headerColWidths.value = widths\n })\n}\n\n// 窗口大小变化和滚动时重新计算\nfunction handleResize() {\n calculateTableMaxHeight()\n updateHeaderScrollbarGutter()\n syncSelectedHeaderHeight()\n}\n\n// 监听数据变化,重新计算高度\nwatch(() => props.data, () => {\n nextTick(() => {\n calculateTableMaxHeight()\n // 不在数据变化时重新测量列宽,避免分页切换引起的列宽抖动\n syncHeaderScroll()\n updateHeaderScrollbarGutter()\n expandedKeys.value.clear()\n })\n}, { deep: true })\n\n// 监听分页变化,重新计算高度\nwatch([currentPage, pageSize], () => {\n nextTick(() => {\n calculateTableMaxHeight()\n // 分页切换不再重新测量列宽\n syncHeaderScroll()\n updateHeaderScrollbarGutter()\n })\n})\n\n// 列配置变化时,重置并测量列宽\nwatch(() => props.columns, () => {\n const nextWidths: string[] = []\n const nextMap: Record<string, string> = { ...headerWidthMap.value }\n\n props.columns.forEach((col, idx) => {\n const normalizedWidth = normalizeWidth(col.width)\n if (normalizedWidth) {\n nextWidths.push(normalizedWidth)\n nextMap[col.key] = normalizedWidth\n } else if (nextMap[col.key]) {\n nextWidths.push(nextMap[col.key])\n } else if (headerColWidths.value[idx]) {\n nextWidths.push(headerColWidths.value[idx])\n nextMap[col.key] = headerColWidths.value[idx]\n } else {\n nextWidths.push('')\n }\n })\n\n // 移除已经不存在的列的缓存\n const currentKeys = new Set(props.columns.map(col => col.key))\n Object.keys(nextMap).forEach((key) => {\n if (!currentKeys.has(key)) {\n delete nextMap[key]\n }\n })\n\n headerWidthMap.value = nextMap\n headerColWidths.value = nextWidths\n\n nextTick(() => {\n measureAutoColumnWidths()\n syncHeaderScroll()\n updateHeaderScrollbarGutter()\n syncSelectedHeaderHeight()\n })\n}, { deep: true })\n\n// 测量并存储默认表头的标准高度\nfunction measureDefaultHeaderHeight() {\n nextTick(() => {\n if (!headerRef.value) return\n const headerTable = headerRef.value.querySelector('.table')\n if (!headerTable) return\n \n // 只有当没有选中项时(显示默认表头)才测量\n if (selectedItems.value.length === 0) {\n const firstNormalTh = headerTable.querySelector('thead th:not(.col-select):not(.col-expand)') as HTMLElement\n if (firstNormalTh && firstNormalTh.offsetHeight > 0) {\n defaultHeaderHeight.value = firstNormalTh.offsetHeight\n }\n }\n })\n}\n\n// 同步自定义表头高度与默认表头高度\nfunction syncSelectedHeaderHeight() {\n nextTick(() => {\n if (!headerRef.value) return\n const headerTable = headerRef.value.querySelector('.table')\n if (!headerTable) return\n \n // 如果当前显示的是自定义表头,应用存储的默认高度\n const selectedHeader = headerTable.querySelector('.col-selected-header') as HTMLElement\n if (selectedHeader) {\n const wrapper = selectedHeader.querySelector('.selected-header-wrapper') as HTMLElement\n if (wrapper) {\n wrapper.style.height = `${defaultHeaderHeight.value}px`\n }\n } else {\n // 如果显示的是默认表头,更新存储的高度\n measureDefaultHeaderHeight()\n }\n })\n}\n\n// 监听选中项变化,重新计算高度(批量操作栏显示/隐藏)\nwatch(() => selectedItems.value, () => {\n nextTick(() => {\n calculateTableMaxHeight()\n updateHeaderScrollbarGutter()\n syncSelectedHeaderHeight()\n })\n}, { deep: true })\n\n// 监听 loading 状态变化,更新滚动条补偿\nwatch(() => props.loading, () => {\n nextTick(() => {\n updateHeaderScrollbarGutter()\n })\n})\n\n// 生命周期\nonMounted(() => {\n nextTick(() => {\n calculateTableMaxHeight()\n measureAutoColumnWidths()\n updateHeaderScrollbarGutter()\n updateVirtualScrollbar()\n measureDefaultHeaderHeight()\n syncSelectedHeaderHeight()\n })\n window.addEventListener('resize', handleResize)\n window.addEventListener('scroll', handleResize, true)\n // 监听内容滚动以同步表头\n bodyWrapRef.value?.addEventListener('scroll', () => {\n syncHeaderScroll()\n updateVirtualScrollbar()\n // 滚动时也更新滚动条补偿(因为滚动可能导致内容高度变化)\n updateHeaderScrollbarGutter()\n }, { passive: true })\n // 监听表头滚动以同步内容区域\n headerRef.value?.addEventListener('scroll', () => {\n syncBodyScroll()\n }, { passive: true })\n // 初始同步一次\n nextTick(() => syncHeaderScroll())\n \n // 使用 ResizeObserver 监听内容区域大小变化,实时更新滚动条补偿\n if (bodyWrapRef.value && typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => {\n updateHeaderScrollbarGutter()\n })\n resizeObserver.observe(bodyWrapRef.value)\n }\n})\n\nonUnmounted(() => {\n window.removeEventListener('resize', handleResize)\n window.removeEventListener('scroll', handleResize, true)\n bodyWrapRef.value?.removeEventListener('scroll', syncHeaderScroll)\n headerRef.value?.removeEventListener('scroll', syncBodyScroll)\n window.removeEventListener('mousemove', onThumbMousemove)\n window.removeEventListener('mouseup', onThumbMouseup)\n // 清理 ResizeObserver\n if (resizeObserver) {\n resizeObserver.disconnect()\n resizeObserver = null\n }\n})\n\n// 为表头添加与内容滚动条同宽的内边距,避免列错位\nlet lastScrollbarWidth = -1 // 缓存上次的滚动条宽度,避免不必要的 DOM 操作\nfunction updateHeaderScrollbarGutter() {\n if (!headerRef.value || !bodyWrapRef.value) return\n \n // 使用 requestAnimationFrame 确保在浏览器重绘后计算\n requestAnimationFrame(() => {\n if (!headerRef.value || !bodyWrapRef.value) return\n \n const wrap = bodyWrapRef.value\n // 计算滚动条宽度(容器总宽度 - 内容可见宽度)\n // 注意:这里需要考虑竖向滚动条(占用右侧空间)\n const currentScrollbarWidth = Math.ceil(wrap.offsetWidth - wrap.clientWidth)\n \n // 更新响应式变量\n scrollbarWidth.value = currentScrollbarWidth\n \n // 只有当滚动条宽度发生变化时才更新 DOM,避免不必要的操作\n if (currentScrollbarWidth !== lastScrollbarWidth) {\n lastScrollbarWidth = currentScrollbarWidth\n const headerTable = headerRef.value.querySelector('.table') as HTMLElement\n const bodyTable = bodyTableRef.value\n \n if (headerTable && bodyTable) {\n // 先移除之前的样式,确保测量准确\n headerRef.value.style.paddingRight = '0px'\n headerTable.style.width = ''\n headerTable.style.marginRight = ''\n \n // 测量表头和内容区域的 table 实际宽度\n // const headerTableWidth = headerTable.offsetWidth\n // const bodyTableWidth = bodyTable.offsetWidth\n \n // 计算宽度差异\n // const widthDiff = bodyTableWidth - headerTableWidth\n \n if (currentScrollbarWidth > 0) {\n // 如果有滚动条,需要补偿\n // 表头容器的 padding-right 用于补偿滚动条宽度\n headerRef.value.style.paddingRight = `${currentScrollbarWidth}px`\n // table 的宽度设置为 100%(相对于容器内容区域,不包括 padding)\n // 这样表头 table 的宽度就会和内容区域 table 的实际宽度一致\n headerTable.style.width = '100%'\n // 使用负 margin 让 table 向右偏移,填充 padding 区域\n // 这样表头 table 的右边缘就会和内容区域 table 的右边缘对齐\n headerTable.style.marginRight = `-${currentScrollbarWidth}px`\n } else {\n headerRef.value.style.paddingRight = '0px'\n headerTable.style.width = '100%'\n headerTable.style.marginRight = '0px'\n }\n }\n }\n })\n}\n\n// 使用 ResizeObserver 监听内容区域大小变化,自动更新滚动条补偿\nlet resizeObserver: ResizeObserver | null = null\n\n// 清理 hintTag 实例(组件卸载时)\nonUnmounted(() => {\n hintTagInstances.value.clear()\n})\n</script>\n\n<style scoped lang=\"less\">\n.ytable-container {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.bulk-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 10px;\n background: #FFFFFF;\n border: 1px solid #dfe3e8;\n border-radius: 6px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n.bulk-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* 批量操作栏出现/消失动画 */\n.bulk-slide-enter-active,\n.bulk-slide-leave-active {\n transition: all 0.2s ease;\n}\n\n.bulk-slide-enter-from,\n.bulk-slide-leave-to {\n transform: translateY(-8px);\n opacity: 0;\n}\n\n.card {\n border-radius: 6px;\n background: #fff;\n padding: 4px 5px;\n box-shadow: 0rem 0.3125rem 0.3125rem -0.15625rem rgba(0, 0, 0, 0.03),\n 0rem 0.1875rem 0.1875rem -0.09375rem rgba(0, 0, 0, 0.02),\n 0rem 0.125rem 0.125rem -0.0625rem rgba(0, 0, 0, 0.02),\n 0rem 0.0625rem 0.0625rem -0.03125rem rgba(0, 0, 0, 0.03),\n 0rem 0.03125rem 0.03125rem 0rem rgba(0, 0, 0, 0.04),\n 0rem 0rem 0rem 0.0625rem rgba(0, 0, 0, 0.06);\n position: relative;\n}\n\n/* 表头右上角操作按钮区域 */\n.table-header-actions {\n position: absolute;\n top: 8px;\n right: 12px;\n z-index: 10;\n pointer-events: auto;\n}\n\n.toggle-all-hints-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: #ffffff;\n color: #666666;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n cursor: pointer;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n transition: all 0.2s ease;\n padding: 0;\n}\n\n.toggle-all-hints-btn:hover {\n color: #333333;\n background: #f5f5f5;\n border-color: #d1d5db;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);\n}\n\n.toggle-all-hints-btn:active {\n transform: scale(0.95);\n}\n\n.toggle-all-hints-btn.is-expanded {\n color: #008060;\n border-color: #008060;\n}\n\n.toggle-all-hints-btn.is-expanded:hover {\n background: #f0f9f7;\n border-color: #006b52;\n}\n\n.toggle-icon {\n width: 16px;\n height: 16px;\n transition: transform 0.2s ease;\n}\n\n/* 表头固定区域 */\n.table-header {\n width: 100%;\n overflow-x: auto; /* 允许水平滚动 */\n overflow-y: hidden; /* 禁止垂直滚动 */\n /* 隐藏滚动条,但保持滚动功能 */\n scrollbar-width: none; /* Firefox */\n -ms-overflow-style: none; /* IE/Edge */\n /* 通过 JavaScript 动态设置 table 的 margin-right 来补偿滚动条宽度 */\n box-sizing: border-box;\n position: relative;\n}\n\n/* 隐藏表头区域的滚动条 */\n.table-header::-webkit-scrollbar {\n display: none;\n}\n\n/* 选中状态下的自定义表头 */\n.col-selected-header {\n padding: 0 !important;\n border-bottom: none !important;\n vertical-align: middle; /* 确保垂直对齐与默认表头一致 */\n}\n\n.selected-header-wrapper {\n width: 100%;\n background: #f8f9fa;\n border-bottom: 1px solid #dfe3e8;\n padding: 8px 12px; /* 上下 padding 与默认表头的 8px 8px 保持一致 */\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 8px;\n box-sizing: border-box;\n line-height: 1.5; /* 与默认表头的行高保持一致 */\n /* 使用固定高度确保与默认表头完全一致 */\n /* 默认表头: padding(8px * 2) + 内容高度(约12px * 1.5 = 18px) = 34px */\n height: 35px; /* 包含边框后的总高度 */\n}\n\n/* 表格内容滚动区域 */\n.table-body-wrap {\n width: 100%;\n overflow: auto;\n position: relative;\n padding-right: 0; // 右侧不留 padding\n /* 滚动条会占用空间,通过动态补偿表头来保持对齐 */\n}\n\n// 加载中时,确保最小高度存在,避免高度被收缩\n.table-body-wrap.is-loading {\n min-height: 200px;\n}\n\n// 空数据时保证最小高度,用于承载覆盖层\n.table-body-wrap.is-empty {\n min-height: 200px;\n}\n\n// 空数据覆盖层(不改变表格布局,避免副作用)\n.empty-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n pointer-events: none; // 允许滚动容器继续滚动(若需要)\n}\n\n// 仅在卡片内的滚动区域做“贴边”处理\n.card > .table-body-wrap {\n width: calc(100% + 4px);\n margin-right: -4px; // 抵消 .card 的 5px 右内边距\n}\n\n// 移除已废弃的 overflow: overlay,使用动态计算滚动条宽度来保持对齐\n\n/* 滚动条样式 - 只在内容区域 */\n.table-body-wrap::-webkit-scrollbar {\n width: 4px;\n height: 6px;\n}\n// 隐藏原生竖向滚动条(保留横向)\n.table-body-wrap::-webkit-scrollbar:vertical {\n width: 0;\n}\n\n// 明确指定水平滚动条厚度与侧边一致\n.table-body-wrap::-webkit-scrollbar:horizontal {\n height: 6px;\n}\n\n.table-body-wrap::-webkit-scrollbar-track {\n background: transparent;\n position: relative;\n \n // 添加顶部箭头\n &::before {\n content: '';\n position: absolute;\n top: 1px;\n left: 50%;\n transform: translateX(-50%);\n width: 0;\n height: 0;\n border-left: 2px solid transparent;\n border-right: 2px solid transparent;\n border-bottom: 3px solid #9ca3af;\n z-index: 1;\n transition: all 0.2s ease;\n }\n \n // 添加底部箭头\n &::after {\n content: '';\n position: absolute;\n bottom: 1px;\n left: 50%;\n transform: translateX(-50%);\n width: 0;\n height: 0;\n border-left: 2px solid transparent;\n border-right: 2px solid transparent;\n border-top: 3px solid #9ca3af;\n z-index: 1;\n transition: all 0.2s ease;\n }\n}\n\n// 水平滚动条轨道与左右箭头\n.table-body-wrap::-webkit-scrollbar-track:horizontal {\n background: transparent;\n position: relative;\n}\n\n.table-body-wrap::-webkit-scrollbar-track:horizontal::before {\n content: '';\n position: absolute;\n left: 1px;\n top: 50%;\n transform: translateY(-50%);\n width: 0;\n height: 0;\n border-top: 2px solid transparent;\n border-bottom: 2px solid transparent;\n border-right: 3px solid #9ca3af; // 左侧指向右的三角\n z-index: 1;\n transition: all 0.2s ease;\n}\n\n.table-body-wrap::-webkit-scrollbar-track:horizontal::after {\n content: '';\n position: absolute;\n right: 1px;\n top: 50%;\n transform: translateY(-50%);\n width: 0;\n height: 0;\n border-top: 2px solid transparent;\n border-bottom: 2px solid transparent;\n border-left: 3px solid #9ca3af; // 右侧指向左的三角\n z-index: 1;\n transition: all 0.2s ease;\n}\n\n.table-body-wrap::-webkit-scrollbar-thumb {\n background: #bac0ca;\n border-radius: 2px;\n transition: all 0.2s ease;\n margin: 4px 0; // 为箭头留出空间\n \n &:hover {\n background: #6b7280;\n }\n \n &:active {\n background: #4b5563;\n }\n}\n\n// 水平 thumb 预留左右边距,避免遮挡左右箭头\n.table-body-wrap::-webkit-scrollbar-thumb:horizontal {\n margin: 0 4px;\n}\n\n.table-body-wrap::-webkit-scrollbar-corner {\n background: transparent;\n}\n\n// Firefox 滚动条厚度与颜色(与侧边一致)\n.table-body-wrap {\n scrollbar-width: thin;\n scrollbar-color: #bac0ca transparent;\n}\n\n// 滚动条按钮样式(兼容性)\n.table-body-wrap::-webkit-scrollbar-button {\n display: block;\n height: 4px;\n background: transparent;\n \n // 顶部按钮\n &:vertical:start:decrement {\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 3'%3E%3Cpath fill='%239ca3af' d='M2 0L0 3h4z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: center;\n background-size: 4px 3px;\n }\n \n // 底部按钮\n &:vertical:end:increment {\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 3'%3E%3Cpath fill='%239ca3af' d='M2 3L0 0h4z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: center;\n background-size: 4px 3px;\n }\n \n &:hover {\n // 悬停时箭头颜色变深\n &:vertical:start:decrement {\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 3'%3E%3Cpath fill='%236b7280' d='M2 0L0 3h4z'/%3E%3C/svg%3E\");\n }\n \n &:vertical:end:increment {\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 3'%3E%3Cpath fill='%236b7280' d='M2 3L0 0h4z'/%3E%3C/svg%3E\");\n }\n }\n}\n\n.table {\n width: 100%;\n border-collapse: separate;\n border-spacing: 0;\n table-layout: fixed;\n}\n\n.table thead th {\n text-align: left;\n // font-weight: 600;\n font-size: 12px;\n color: #7c7c7c;\n background: #f8f9fa;\n border-bottom: 1px solid #dfe3e8;\n padding: 8px 8px;\n white-space: nowrap;\n}\n\n\n.table tbody td {\n padding: 4px 8px;\n border-bottom: 1px solid #f1f3f4;\n vertical-align: middle;\n text-align: left;\n font-size: 12px;\n // font-weight: 550;\n color: #535353;\n transition: background-color 0.3s ease;\n}\n\n/* 行选中样式 */\n.table tbody tr {\n transition: background-color 0.3s ease;\n}\n\n.table tbody tr.row-selected {\n background-color: #e6f4ff;\n}\n\n.table tbody tr.row-selected td {\n background-color: #e6f4ff;\n}\n\n.table tbody tr:hover:not(.row-selected) {\n background-color: #f5f5f5;\n}\n\n.col-select {\n width: auto;\n min-width: 60px;\n}\n\n.select-header {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n}\n\n.select-count {\n font-size: 11px;\n color: #1A1A1A;\n font-weight: 600;\n background: #f0f0f0;\n padding: 0 4px;\n border-radius: 3px;\n line-height: 1.4;\n white-space: nowrap;\n}\n\n.col-expand {\n width: 28px;\n text-align: center;\n}\n\n.expand-btn {\n width: 20px;\n height: 20px;\n border: none;\n border-radius: 4px;\n background: transparent;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s ease;\n}\n\n.expand-btn:hover {\n background: rgba(0, 0, 0, 0.05);\n}\n\n.expand-icon {\n display: inline-block;\n width: 0;\n height: 0;\n border-left: 5px solid transparent;\n border-right: 5px solid transparent;\n border-top: 7px solid #6b7280;\n transition: transform 0.2s ease;\n}\n\n.expand-icon.is-open {\n transform: rotate(180deg);\n}\n\n.expand-row .expand-cell {\n background: #f9fafb;\n}\n\n/* 通用固定列样式(右侧) */\n.table thead th.col-fixed-right,\n.table tbody td.col-fixed-right {\n position: sticky;\n /* right 值通过 JavaScript 动态设置 */\n background: #fff;\n /* z-index 通过 JavaScript 动态设置 */\n transition: background-color 0.3s ease;\n}\n.table tbody td.col-fixed-right {\n box-shadow: -6px 0 6px -6px rgba(0,0,0,0.08);\n}\n\n/* 通用固定列样式(左侧) */\n.table thead th.col-fixed-left,\n.table tbody td.col-fixed-left {\n position: sticky;\n /* left 值通过 JavaScript 动态设置 */\n background: #fff;\n /* z-index 通过 JavaScript 动态设置 */\n transition: background-color 0.3s ease;\n}\n.table tbody td.col-fixed-left {\n box-shadow: 6px 0 6px -6px rgba(0,0,0,0.08);\n}\n\n/* 选中行时固定列的背景色 */\n.table tbody tr.row-selected td.col-fixed-right,\n.table tbody tr.row-selected td.col-fixed-left {\n background-color: #e6f4ff;\n}\n\n.text-left { text-align: left; }\n.text-center { text-align: center; }\n.text-right { text-align: right; }\n\n\n.link {\n background: transparent;\n border: none;\n color: #2563eb;\n cursor: pointer;\n}\n\n.empty {\n text-align: center;\n color: #888;\n padding: 0;\n height: 200px; // 保底高度\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* 复选框主题色为 #1A1A1A */\n.table input[type=\"checkbox\"],\n.bulk-bar input[type=\"checkbox\"] {\n accent-color: #1A1A1A;\n}\n\n/* 复选框中间状态(indeterminate)样式 */\n.table input[type=\"checkbox\"]:indeterminate,\n.bulk-bar input[type=\"checkbox\"]:indeterminate {\n accent-color: #1A1A1A;\n}\n\n/* 聚焦时轻微外发光,保持无侵入 */\n.table input[type=\"checkbox\"]:focus-visible,\n.bulk-bar input[type=\"checkbox\"]:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px rgba(26, 26, 26, 0.2);\n border-radius: 3px;\n}\n\n/* Loading 状态样式 */\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.8);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n z-index: 10;\n}\n\n.loading-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid #f3f3f3;\n border-top: 3px solid #1A1A1A;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n margin-bottom: 8px;\n}\n\n.loading-text {\n font-size: 14px;\n color: #666;\n}\n\n@keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.loading-table {\n opacity: 0.6;\n pointer-events: none;\n}\n\n/* 右对齐分页(覆盖子组件内部的 space-between) */\n:deep(.ypagination.align-right) {\n justify-content: flex-end !important;\n}\n\n/* 自定义悬浮竖向滚动条 */\n.v-scrollbar {\n position: absolute;\n top: 0;\n right: 2px;\n bottom: 0;\n width: 8px;\n display: flex;\n align-items: stretch;\n z-index: 5;\n pointer-events: none; // 仅轨道与滑块可交互\n}\n\n.v-scrollbar-track {\n position: relative;\n width: 100%;\n margin: 4px 0;\n border-radius: 4px;\n background: rgba(0,0,0,0.03);\n transition: background 0.2s ease;\n pointer-events: auto;\n}\n\n.v-scrollbar:hover .v-scrollbar-track {\n background: rgba(0,0,0,0.06);\n}\n\n.v-scrollbar-thumb {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n border-radius: 4px;\n background: rgba(0,0,0,0.24);\n cursor: grab;\n pointer-events: auto;\n transition: background 0.2s ease, opacity 0.2s ease;\n}\n\n.v-scrollbar-thumb:hover {\n background: rgba(0,0,0,0.34);\n}\n\n.v-scrollbar-thumb:active {\n cursor: grabbing;\n background: rgba(0,0,0,0.42);\n}\n</style>\n","<template>\n <div class=\"yselect\" :class=\"{ 'yselect--disabled': disabled, [`yselect--${size}`]: true }\" :style=\"{ width: width }\" ref=\"selectContainer\">\n <div \n ref=\"triggerElement\"\n class=\"yselect__trigger\"\n :class=\"{ \n 'yselect__trigger--open': isOpen,\n 'yselect__trigger--disabled': disabled,\n 'yselect__trigger--error': error\n }\"\n @mousedown.prevent.stop=\"toggleDropdown\"\n @keydown.enter.prevent=\"toggleDropdown\"\n @keydown.space.prevent=\"toggleDropdown\"\n @keydown.escape=\"closeDropdown\"\n @keydown.arrow-down.prevent=\"openDropdown\"\n @keydown.arrow-up.prevent=\"openDropdown\"\n tabindex=\"0\"\n role=\"combobox\"\n :aria-expanded=\"isOpen\"\n :aria-haspopup=\"true\"\n >\n <span class=\"yselect__value\" :class=\"{ 'yselect__placeholder': !selectedLabel }\" v-if=\"!filterable || !isOpen\">\n <slot name=\"value\" :value=\"props.multiple ? selectedOptions : selectedOption\" :label=\"selectedLabel\" :multiple=\"props.multiple\">\n <template v-if=\"props.multiple\">\n <div class=\"yselect__tags\" v-if=\"selectedOptions.length > 0\">\n <span \n v-for=\"(option, idx) in selectedOptions\" \n :key=\"getOptionKey(option, idx)\"\n class=\"yselect__tag\"\n >\n <img \n v-if=\"(option as any)?.flagImg\"\n class=\"yselect__flag\"\n :src=\"(option as any).flagImg\"\n alt=\"flag\"\n />\n <span class=\"yselect__tag-text\">{{ getOptionLabel(option) }}</span>\n <span \n v-if=\"clearable && !disabled\"\n class=\"yselect__tag-close\"\n @click.stop=\"removeTag(option, $event)\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M2.5 2.5l5 5M7.5 2.5l-5 5\" stroke=\"currentColor\" stroke-width=\"1.2\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n </span>\n </div>\n <span v-else class=\"yselect__placeholder-text\">{{ placeholder }}</span>\n </template>\n <template v-else>\n <template v-if=\"selectedOption\">\n <img \n v-if=\"(selectedOption as any)?.flagImg\"\n class=\"yselect__flag\"\n :src=\"(selectedOption as any).flagImg\"\n alt=\"flag\"\n />\n {{ selectedLabel }}\n </template>\n <template v-else>\n {{ placeholder }}\n </template>\n </template>\n </slot>\n </span>\n <input\n v-else\n ref=\"inputElement\"\n class=\"yselect__input\"\n type=\"text\"\n :placeholder=\"props.multiple ? (selectedOptions.length > 0 ? `已选择 ${selectedOptions.length} 项` : placeholder) : (selectedLabel || placeholder)\"\n v-model=\"searchQuery\"\n @keydown.stop\n @keydown.arrow-down.prevent=\"moveHover(1)\"\n @keydown.arrow-up.prevent=\"moveHover(-1)\"\n @keydown.enter.prevent=\"selectHovered()\"\n @keydown.esc.prevent=\"closeDropdown\"\n @keydown.delete.prevent=\"handleClear\"\n />\n <span \n v-if=\"clearable && !disabled && (props.multiple ? selectedOptions.length > 0 : selectedOption)\"\n class=\"yselect__clear\"\n title=\"清空\"\n @click.stop=\"handleClear\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <path d=\"M3 3l6 6M9 3L3 9\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n <span class=\"yselect__arrow\" :class=\"{ 'yselect__arrow--open': isOpen }\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <path d=\"M3 4.5L6 7.5L9 4.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n </div>\n\n <transition name=\"yselect-dropdown\">\n <teleport to=\"body\">\n <div \n v-if=\"isOpen\" \n class=\"yselect__dropdown yselect__dropdown--portal\"\n :class=\"{ 'yselect__dropdown--top': shouldOpenUpward }\"\n :style=\"portalDropdownStyle\"\n @mousedown.stop\n @click.stop\n >\n <div class=\"yselect__options\" ref=\"optionsContainer\">\n <div\n v-for=\"(option, index) in displayedOptions\"\n :key=\"getOptionKey(option, index)\"\n class=\"yselect__option\"\n :class=\"{\n 'yselect__option--selected': isSelected(option),\n 'yselect__option--disabled': isOptionDisabled(option),\n 'yselect__option--hover': hoveredIndex === index\n }\"\n @click=\"selectOption(option, index)\"\n @mouseenter=\"hoveredIndex = index\"\n @mouseleave=\"hoveredIndex = -1\"\n >\n <slot name=\"option\" :option=\"option\" :index=\"index\" :selected=\"isSelected(option)\">\n <span v-if=\"props.multiple\" class=\"yselect__option-check\">\n <svg \n v-if=\"isSelected(option)\"\n width=\"14\" \n height=\"14\" \n viewBox=\"0 0 14 14\" \n fill=\"none\"\n >\n <path d=\"M2 7l3 3 7-7\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <img \n v-if=\"(option as any)?.flagImg\"\n class=\"yselect__flag\"\n :src=\"(option as any).flagImg\"\n alt=\"flag\"\n />\n {{ getOptionLabel(option) }}\n </slot>\n </div>\n </div>\n </div>\n </teleport>\n </transition>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch, nextTick, onMounted, onUnmounted } from 'vue'\n\nexport interface SelectOption {\n label: string\n value: any\n disabled?: boolean\n [key: string]: any\n}\n\nexport interface SelectProps {\n modelValue?: any | any[]\n options: SelectOption[] | any[]\n placeholder?: string\n disabled?: boolean\n error?: boolean\n clearable?: boolean\n clearTo?: any\n filterable?: boolean\n multiple?: boolean\n valueKey?: string\n labelKey?: string\n disabledKey?: string\n size?: 'small' | 'medium' | 'large'\n width?: string\n}\n\nconst props = withDefaults(defineProps<SelectProps>(), {\n placeholder: '请选择',\n disabled: false,\n error: false,\n clearable: true,\n clearTo: undefined,\n filterable: false,\n multiple: false,\n valueKey: 'value',\n labelKey: 'label',\n disabledKey: 'disabled',\n size: 'medium',\n width: '200px'\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: any | any[]]\n 'change': [value: any | any[], option: SelectOption | SelectOption[] | null]\n 'focus': [event: FocusEvent]\n 'blur': [event: FocusEvent]\n 'clear': []\n}>()\n\n// 响应式数据\nconst isOpen = ref(false)\nconst hoveredIndex = ref(-1)\nconst optionsContainer = ref<HTMLElement>()\nconst triggerElement = ref<HTMLElement>()\nconst selectContainer = ref<HTMLElement>()\nconst shouldOpenUpward = ref(false)\nconst inputElement = ref<HTMLInputElement>()\nconst searchQuery = ref('')\n\n// 计算属性\nconst selectedOption = computed(() => {\n if (props.multiple) return null\n return props.options.find(option => getOptionValue(option) === props.modelValue) || null\n})\n\nconst selectedOptions = computed(() => {\n if (!props.multiple) return []\n const values = Array.isArray(props.modelValue) ? props.modelValue : []\n return props.options.filter(option => values.includes(getOptionValue(option)))\n})\n\nconst selectedLabel = computed(() => {\n if (props.multiple) {\n const count = selectedOptions.value.length\n if (count === 0) return ''\n return `已选择 ${count} 项`\n }\n return selectedOption.value ? getOptionLabel(selectedOption.value) : ''\n})\n\nconst displayedOptions = computed(() => {\n if (!props.filterable) return props.options\n const query = searchQuery.value.trim().toLowerCase()\n if (!query) return props.options\n return props.options.filter((opt: any) => {\n const label = getOptionLabel(opt)\n return String(label).toLowerCase().includes(query)\n })\n})\n\n// const dropdownStyle = computed(() => {\n// const style: Record<string, string> = {}\n// \n// if (props.width === 'auto') {\n// style.width = '100%'\n// style.minWidth = 'auto'\n// } else {\n// style.width = props.width\n// style.minWidth = props.width\n// }\n// \n// return style\n// })\n\nconst portalDropdownStyle = computed(() => {\n const style: Record<string, string> = { position: 'fixed', zIndex: '4000' }\n const trigger = triggerElement.value\n if (!trigger) return style\n const rect = trigger.getBoundingClientRect()\n const width = (selectContainer.value?.getBoundingClientRect().width || rect.width)\n style.left = `${rect.left}px`\n style.width = `${width}px`\n if (shouldOpenUpward.value) {\n // 向上展开时,使用 bottom 定位而不是 top,这样更准确\n style.bottom = `${window.innerHeight - rect.top + 4}px`\n style.top = 'auto'\n } else {\n style.top = `${rect.bottom + 4}px`\n }\n return style\n})\n\n// 计算是否应该向上展开\nfunction calculateDropdownPosition() {\n if (!isOpen.value || !triggerElement.value) return\n \n nextTick(() => {\n const trigger = triggerElement.value\n if (!trigger) return\n \n const triggerRect = trigger.getBoundingClientRect()\n const viewportHeight = window.innerHeight\n const dropdownHeight = 200 // 预估下拉菜单高度\n \n // 计算下拉菜单底部位置\n const dropdownBottom = triggerRect.bottom + dropdownHeight + 4 // 4px 是 margin-top\n \n // 计算向上展开时下拉菜单顶部位置\n const dropdownTop = triggerRect.top - dropdownHeight - 4 // 4px 是 margin-bottom\n \n // 如果下拉菜单会超出视口底部,且向上展开不会超出视口顶部,则向上展开\n const shouldOpenDown = dropdownBottom <= viewportHeight - 20 // 20px 安全边距\n const canOpenUp = dropdownTop >= 20 // 20px 安全边距\n \n shouldOpenUpward.value = !shouldOpenDown && canOpenUp\n })\n}\n\n// 方法\nfunction getOptionValue(option: any): any {\n if (typeof option === 'object' && option !== null) {\n return option[props.valueKey]\n }\n return option\n}\n\nfunction getOptionLabel(option: any): string {\n if (typeof option === 'object' && option !== null) {\n return option[props.labelKey] || String(option[props.valueKey])\n }\n return String(option)\n}\n\nfunction getOptionKey(option: any, index: number): string | number {\n if (typeof option === 'object' && option !== null && option.id !== undefined) {\n return option.id\n }\n return getOptionValue(option) || index\n}\n\nfunction isSelected(option: any): boolean {\n if (props.multiple) {\n const values = Array.isArray(props.modelValue) ? props.modelValue : []\n return values.includes(getOptionValue(option))\n }\n return getOptionValue(option) === props.modelValue\n}\n\nfunction isOptionDisabled(option: any): boolean {\n if (typeof option === 'object' && option !== null) {\n return option[props.disabledKey] === true\n }\n return false\n}\n\nfunction toggleDropdown() {\n if (props.disabled) return\n isOpen.value ? closeDropdown() : openDropdown()\n}\n\nfunction openDropdown() {\n if (props.disabled) return\n isOpen.value = true\n nextTick(() => {\n calculateDropdownPosition()\n scrollToSelected()\n if (props.filterable && inputElement.value) {\n inputElement.value.focus()\n // 打开时默认清空,便于直接输入筛选\n searchQuery.value = ''\n }\n })\n}\n\nfunction closeDropdown() {\n isOpen.value = false\n hoveredIndex.value = -1\n shouldOpenUpward.value = false\n if (props.filterable) {\n searchQuery.value = ''\n }\n}\n\nfunction selectOption(option: any, _index: number) {\n if (isOptionDisabled(option)) return\n \n const value = getOptionValue(option)\n \n if (props.multiple) {\n const currentValues = Array.isArray(props.modelValue) ? [...props.modelValue] : []\n const optionValue = getOptionValue(option)\n const valueIndex = currentValues.indexOf(optionValue)\n \n if (valueIndex > -1) {\n // 取消选择\n currentValues.splice(valueIndex, 1)\n } else {\n // 添加选择\n currentValues.push(optionValue)\n }\n \n emit('update:modelValue', currentValues)\n emit('change', currentValues, selectedOptions.value)\n // 多选模式下不关闭下拉框\n } else {\n emit('update:modelValue', value)\n emit('change', value, option)\n closeDropdown()\n }\n}\n\nfunction handleClear() {\n if (!props.clearable || props.disabled) return\n const cleared = props.multiple ? (props.clearTo !== undefined ? props.clearTo : []) : props.clearTo\n emit('update:modelValue', cleared)\n emit('change', cleared, props.multiple ? [] : null)\n emit('clear')\n // 清空后关闭下拉并重置搜索\n if (!props.multiple) {\n closeDropdown()\n }\n}\n\nfunction removeTag(option: any, event: Event) {\n event.stopPropagation()\n if (props.disabled || !props.multiple) return\n \n const currentValues = Array.isArray(props.modelValue) ? [...props.modelValue] : []\n const optionValue = getOptionValue(option)\n const index = currentValues.indexOf(optionValue)\n \n if (index > -1) {\n currentValues.splice(index, 1)\n emit('update:modelValue', currentValues)\n emit('change', currentValues, selectedOptions.value)\n }\n}\n\nfunction moveHover(delta: number) {\n if (!displayedOptions.value || displayedOptions.value.length === 0) {\n hoveredIndex.value = -1\n return\n }\n let next = hoveredIndex.value\n const total = displayedOptions.value.length\n // 初次移动时从 -1 开始\n if (next === -1) {\n next = delta > 0 ? 0 : total - 1\n } else {\n next = (next + delta + total) % total\n }\n // 跳过禁用项,最多循环 total 次避免死循环\n let attempts = 0\n while (attempts < total && isOptionDisabled(displayedOptions.value[next])) {\n next = (next + delta + total) % total\n attempts++\n }\n hoveredIndex.value = attempts >= total ? -1 : next\n scrollHoverIntoView()\n}\n\nfunction selectHovered() {\n if (hoveredIndex.value < 0) return\n const option = displayedOptions.value[hoveredIndex.value]\n if (!option || isOptionDisabled(option)) return\n selectOption(option, hoveredIndex.value)\n}\n\nfunction scrollToSelected() {\n if (!optionsContainer.value) return\n \n const selectedElement = optionsContainer.value.querySelector('.yselect__option--selected') as HTMLElement | null\n if (selectedElement) {\n selectedElement.scrollIntoView({ block: 'nearest' })\n }\n}\n\nfunction scrollHoverIntoView() {\n if (!optionsContainer.value) return\n if (hoveredIndex.value < 0) return\n const optionNodes = optionsContainer.value.querySelectorAll('.yselect__option')\n const el = optionNodes[hoveredIndex.value] as HTMLElement | undefined\n if (el) el.scrollIntoView({ block: 'nearest' })\n}\n\nfunction handleClickOutside(event: Event) {\n const target = event.target as HTMLElement\n if (!selectContainer.value || !selectContainer.value.contains(target)) {\n closeDropdown()\n }\n}\n\n// 监听器\nwatch(() => props.modelValue, () => {\n hoveredIndex.value = -1\n})\n\n// 窗口大小变化和滚动时重新计算位置\nfunction handleResize() {\n if (isOpen.value) {\n calculateDropdownPosition()\n }\n}\n\n// 生命周期\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n window.addEventListener('resize', handleResize)\n window.addEventListener('scroll', handleResize, true)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('resize', handleResize)\n window.removeEventListener('scroll', handleResize, true)\n})\n</script>\n\n<style scoped lang=\"less\">\n.yselect {\n position: relative;\n display: inline-block;\n width: 100%;\n min-width: 0;\n flex-shrink: 0;\n}\n\n.yselect--disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.yselect__trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n min-width: 0;\n flex-shrink: 0;\n border: 1px solid #e2e8f0;\n background: #ffffff;\n cursor: pointer;\n transition: box-shadow 0.2s ease, border-color 0.2s ease;\n outline: none;\n line-height: 1.5;\n color: #0b1a29;\n box-sizing: border-box;\n}\n\n.yselect__trigger:hover:not(.yselect__trigger--disabled) {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.15);\n}\n\n.yselect__trigger:focus {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.15);\n}\n\n.yselect__trigger--open {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.15);\n}\n\n.yselect__trigger--disabled {\n background: #f9fafb;\n cursor: not-allowed;\n color: #9ca3af;\n}\n\n.yselect__trigger--error {\n border-color: #ef4444;\n}\n\n.yselect__trigger--error:focus {\n border-color: #ef4444;\n box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.15);\n}\n\n.yselect__value {\n flex: 1;\n overflow: hidden;\n color: #0b1a29;\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.yselect__tags {\n display: flex;\n flex-wrap: nowrap;\n gap: 4px;\n align-items: center;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n}\n\n.yselect__tag {\n display: inline-flex;\n align-items: center;\n padding: 2px 6px;\n background: #eff6ff;\n color: #1d4ed8;\n border-radius: 4px;\n font-size: 12px;\n line-height: 1.4;\n max-width: 120px;\n flex-shrink: 1;\n min-width: 0;\n}\n\n.yselect__tag-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-right: 4px;\n}\n\n.yselect__tag-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n cursor: pointer;\n color: #1d4ed8;\n flex-shrink: 0;\n margin-left: 2px;\n}\n\n.yselect__tag-close:hover {\n color: #1e40af;\n}\n\n.yselect__placeholder-text {\n color: #9ca3af;\n}\n\n.yselect__flag {\n width: 14px;\n height: 14px;\n object-fit: cover;\n border-radius: 2px;\n margin-right: 6px;\n}\n\n.yselect__placeholder {\n color: #9ca3af;\n}\n\n.yselect__input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n color: #0b1a29;\n font-size: inherit;\n line-height: 1.5;\n min-width: 0;\n}\n\n.yselect__input::placeholder {\n color: #9ca3af;\n}\n\n.yselect__trigger--disabled .yselect__value {\n color: #9ca3af;\n}\n\n.yselect__arrow {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n color: #6b7280;\n transition: transform 0.2s ease;\n flex-shrink: 0;\n}\n\n.yselect__clear {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n color: #9ca3af;\n margin-left: 6px;\n cursor: pointer;\n}\n\n.yselect__clear:hover {\n color: #6b7280;\n}\n\n.yselect__arrow--open {\n transform: rotate(180deg);\n}\n\n.yselect__dropdown {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n z-index: 1000;\n margin-top: 4px;\n background: #ffffff;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n box-shadow: 0 8px 20px rgba(2, 6, 23, 0.15);\n overflow: hidden;\n}\n\n.yselect__dropdown--top {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 4px;\n}\n\n.yselect__options {\n max-height: 200px;\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.yselect__option {\n display: flex;\n align-items: center;\n height: 36px;\n padding: 0 12px;\n cursor: pointer;\n transition: background-color 0.2s ease, color 0.2s ease;\n font-size: 13px;\n line-height: 1.5;\n color: #0b1a29;\n}\n\n.yselect__option-check {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n margin-right: 8px;\n flex-shrink: 0;\n color: #1d4ed8;\n}\n\n.yselect__option:hover:not(.yselect__option--disabled) {\n background-color: #F6F6F7;\n color: #303061;\n}\n\n.yselect__option--selected {\n background: #eff6ff;\n color: #1d4ed8;\n font-weight: 500;\n}\n\n.yselect__option--selected:hover {\n background: #dbeafe;\n}\n\n.yselect__option--disabled {\n color: #9ca3af;\n cursor: not-allowed;\n background: transparent;\n}\n\n.yselect__option--hover {\n background-color: #F6F6F7;\n color: #303061;\n}\n\n/* 尺寸变体 */\n.yselect--small .yselect__trigger {\n height: 32px;\n padding: 0 10px;\n font-size: 12px;\n border-radius: 6px;\n min-width: 80px;\n}\n\n.yselect--medium .yselect__trigger {\n height: 44px;\n padding: 0 12px;\n font-size: 14px;\n border-radius: 8px;\n min-width: 100px;\n}\n\n.yselect--multiple .yselect__trigger {\n min-height: 44px;\n height: auto;\n padding-top: 4px;\n padding-bottom: 4px;\n}\n\n.yselect--multiple.yselect--small .yselect__trigger {\n min-height: 32px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n\n.yselect--multiple.yselect--large .yselect__trigger {\n min-height: 52px;\n padding-top: 6px;\n padding-bottom: 6px;\n}\n\n.yselect--large .yselect__trigger {\n height: 52px;\n padding: 0 16px;\n font-size: 16px;\n border-radius: 10px;\n min-width: 120px;\n}\n\n/* 过渡动画 */\n.yselect-dropdown-enter-active,\n.yselect-dropdown-leave-active {\n transition: all 0.2s ease;\n transform-origin: top;\n}\n\n.yselect-dropdown-enter-from {\n opacity: 0;\n transform: scaleY(0.8) translateY(-8px);\n}\n\n.yselect-dropdown-leave-to {\n opacity: 0;\n transform: scaleY(0.8) translateY(-8px);\n}\n\n/* 滚动条样式 */\n.yselect__options::-webkit-scrollbar {\n width: 6px;\n}\n\n.yselect__options::-webkit-scrollbar-track {\n background: #f1f5f9;\n}\n\n.yselect__options::-webkit-scrollbar-thumb {\n background: #cbd5e1;\n border-radius: 3px;\n}\n\n.yselect__options::-webkit-scrollbar-thumb:hover {\n background: #94a3b8;\n}\n\n/* 暗色主题支持 */\n@media (prefers-color-scheme: dark) {\n .yselect__trigger {\n background: rgba(2, 6, 23, 0.4);\n border-color: rgba(148, 163, 184, 0.18);\n color: #e5eef7;\n }\n \n .yselect__placeholder {\n color: #9aa6b2;\n }\n \n .yselect__input::placeholder {\n color: #9aa6b2;\n }\n \n .yselect__trigger--disabled {\n background: rgba(2, 6, 23, 0.2);\n color: #9ca3af;\n }\n \n .yselect__value {\n color: #e5eef7;\n }\n \n .yselect__dropdown {\n background: rgba(2, 6, 23, 0.9);\n border-color: rgba(148, 163, 184, 0.18);\n }\n \n .yselect__option {\n color: #e5eef7;\n }\n \n .yselect__option:hover:not(.yselect__option--disabled) {\n background-color: #F6F6F7;\n color: #303061;\n }\n \n .yselect__option--hover {\n background-color: #F6F6F7;\n color: #303061;\n }\n}\n</style>\n","<template>\n <div class=\"ypagination\">\n <div class=\"page-actions\">\n <!-- 上一页按钮 -->\n <YButton\n size=\"small\"\n variant=\"secondary\"\n :disabled=\"currentPage === 1 || loading\"\n @click=\"goToPage(1)\"\n >首页</YButton\n >\n <!-- 在一个 YButton 中生成上一页/下一页组合按钮 -->\n <YButton\n class=\"ml-1\"\n variant=\"secondary\"\n size=\"small\"\n :groupItems=\"[\n { label: '上一页', value: 'prev', disabled: currentPage === 1 || loading, icon: 'chevron-left', onlyIcon: true, ariaLabel: '上一页' },\n { label: '下一页', value: 'next', disabled: loading || disableNext, icon: 'chevron-right', onlyIcon: true, ariaLabel: '下一页' }\n ]\"\n @group-click=\"onPagerGroupClick\"\n />\n\n <!-- 每页条数选择 -->\n <div class=\"page-size-select\">\n <YSelect\n v-model=\"pageSize\"\n :options=\"pageSizeOptions\"\n size=\"small\"\n width=\"105px\"\n :clearable=\"false\"\n :disabled=\"loading\"\n @change=\"handlePageSizeChange\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch } from \"vue\"\n// import type { SelectOption } from \"./YSelect.vue\";\n\nexport interface PaginationProps {\n currentPage: number;\n pageSize: number;\n loading?: boolean;\n pageSizeOptions?: Array<{ label: string; value: number }>;\n disableNext?: boolean; // 是否禁用下一页按钮\n}\n\nconst props = withDefaults(defineProps<PaginationProps>(), {\n loading: false,\n disableNext: false,\n pageSizeOptions: () => [\n { label: \"10/页\", value: 10 },\n { label: \"20/页\", value: 20 },\n { label: \"50/页\", value: 50 },\n { label: \"100/页\", value: 100 },\n ],\n});\n\nconst emit = defineEmits<{\n \"update:currentPage\": [page: number];\n \"update:pageSize\": [size: number];\n \"page-change\": [page: number];\n \"page-size-change\": [size: number];\n}>();\n\n// 响应式数据\nconst pageSize = ref(props.pageSize);\n\n// 每页条数选项\nconst pageSizeOptions = computed(() => props.pageSizeOptions);\n\n// 计算属性\n// 简化:不再计算总页数与页码列表\n\n// 使用计算属性来获取当前页,支持双向绑定\nconst currentPage = computed({\n get: () => props.currentPage,\n set: (value) => {\n emit(\"update:currentPage\", value);\n emit(\"page-change\", value);\n },\n});\n\n// 方法\nfunction goToPage(page: number) {\n if (props.loading) return;\n if (page >= 1 && page !== props.currentPage) {\n currentPage.value = page;\n }\n}\n\nfunction handlePageSizeChange(value: number) {\n if (props.loading) return; // loading 时不允许切换每页条数\n pageSize.value = value;\n emit(\"update:pageSize\", value);\n emit(\"page-size-change\", value);\n // 切换每页条数后,重置到第一页\n currentPage.value = 1;\n}\n\nfunction onPagerGroupClick(action?: string | number) {\n if (props.loading) return;\n if (action === 'prev') {\n goToPage(currentPage.value - 1);\n } else if (action === 'next') {\n goToPage(currentPage.value + 1);\n }\n}\n\n// 同步外部 pageSize\n// (不再根据 totalPages 回调修正 currentPage)\n// 外部如需限制页码由父组件控制\npageSize.value = props.pageSize;\n\n// 监听父组件变更以同步内部状态(确保选中项更新)\nwatch(\n () => props.pageSize,\n (val) => {\n if (typeof val === 'number' && pageSize.value !== val) {\n pageSize.value = val;\n }\n }\n);\n</script>\n\n<style scoped lang=\"less\">\n.ypagination {\n border-top: 1px solid #E6ECF2;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 10px 2px;\n gap: 12px;\n width: 100%;\n box-sizing: border-box;\n}\n\n.page-info {\n font-size: 14px;\n color: #666;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.page-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-shrink: 0;\n min-width: 0;\n}\n\n.btn-group {\n display: inline-flex;\n}\n\n.page-numbers {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-shrink: 0;\n min-width: 0;\n}\n\n.btn {\n height: 28px;\n padding: 0 6px;\n border-radius: 8px;\n border: 1px solid #ddd;\n background: #fff;\n cursor: pointer;\n font-size: 12px;\n transition: all 0.2s ease;\n white-space: nowrap;\n flex-shrink: 0;\n min-width: auto;\n}\n\n.btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn:hover:not(:disabled) {\n border-color: #999;\n background: #f8f8f8;\n}\n\n.page-btn {\n min-width: 28px;\n height: 28px;\n padding: 0 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 12px;\n}\n\n.page-btn.active {\n background: #474747;\n color: #fff;\n border-color: #474747;\n}\n\n.page-btn.active:hover {\n background: #121820;\n border-color: #121820;\n}\n\n.ellipsis {\n padding: 0 2px;\n color: #999;\n font-size: 12px;\n user-select: none;\n min-width: 12px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.page-size-select {\n flex-shrink: 0;\n min-width: 75px;\n margin-left: 25px;\n}\n\n/* 响应式设计 */\n@media (max-width: 768px) {\n .ypagination {\n flex-direction: column;\n gap: 8px;\n align-items: stretch;\n }\n\n .page-info {\n text-align: center;\n }\n\n .page-actions {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .page-numbers {\n order: 1;\n justify-content: center;\n }\n\n .btn:first-child,\n .btn:last-child {\n order: 2;\n }\n\n .select {\n order: 3;\n }\n}\n\n@media (max-width: 480px) {\n .page-numbers {\n gap: 2px;\n }\n\n .page-btn {\n min-width: 28px;\n height: 26px;\n padding: 0 6px;\n font-size: 12px;\n }\n\n .btn {\n height: 26px;\n padding: 0 8px;\n font-size: 12px;\n }\n\n .select {\n height: 26px;\n font-size: 12px;\n }\n}\n</style>\n","<template>\r\n <span\r\n class=\"y-badge\"\r\n :class=\"[\r\n `y-badge--${toneClass}`,\r\n `y-badge--${size}`,\r\n { 'is-outline': outline, 'is-pill': pill },\r\n progress ? `y-badge--progress-${progress}` : ''\r\n ]\"\r\n role=\"status\"\r\n :aria-label=\"ariaLabel\"\r\n >\r\n <span class=\"y-badge__inner\">\r\n <!-- 进度/图标优先渲染 -->\r\n <span v-if=\"progress\" class=\"y-badge__progress\" aria-hidden=\"true\">\r\n <svg v-if=\"progress === 'incomplete'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <circle cx=\"10\" cy=\"10\" r=\"5\" />\r\n </svg>\r\n <svg v-else-if=\"progress === 'partiallyComplete'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path d=\"M10 5a5 5 0 100 10V5z\" />\r\n <circle cx=\"10\" cy=\"10\" r=\"5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" />\r\n </svg>\r\n <svg v-else-if=\"progress === 'complete'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path fill-rule=\"evenodd\" d=\"M16.707 5.293a1 1 0 010 1.414l-7.25 7.25a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L8.75 11.086l6.543-6.543a1 1 0 011.414 0z\" clip-rule=\"evenodd\" />\r\n </svg>\r\n </span>\r\n\r\n <span v-else-if=\"icon\" class=\"y-badge__icon\" aria-hidden=\"true\">\r\n <svg v-if=\"icon === 'dot'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><circle cx=\"10\" cy=\"10\" r=\"4\"/></svg>\r\n <svg v-else-if=\"icon === 'check'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M16.707 5.293a1 1 0 010 1.414l-7.25 7.25a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L8.75 11.086l6.543-6.543a1 1 0 011.414 0z\" clip-rule=\"evenodd\" /></svg>\r\n <svg v-else-if=\"icon === 'alert'\" class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.721-1.36 3.486 0l6.518 11.59c.75 1.334-.214 3.011-1.743 3.011H3.482c-1.53 0-2.493-1.677-1.743-3.01L8.257 3.1zM11 14a1 1 0 10-2 0 1 1 0 002 0zm-1-2a1 1 0 01-1-1V8a1 1 0 112 0v3a1 1 0 01-1 1z\" clip-rule=\"evenodd\"/></svg>\r\n <svg v-else class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><circle cx=\"10\" cy=\"10\" r=\"4\"/></svg>\r\n </span>\r\n\r\n <span class=\"y-badge__label\"><slot>{{ label }}</slot></span>\r\n </span>\r\n </span>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from 'vue'\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 视觉语气 */\r\n tone?: 'default' | 'informational' | 'success' | 'attention' | 'warning' | 'critical'\r\n /** 尺寸 */\r\n size?: 'small' | 'medium'\r\n /** 进度状态(与 icon 互斥,优先级更高) */\r\n progress?: 'incomplete' | 'partiallyComplete' | 'complete'\r\n /** 内置图标:dot | check | alert | placeholder(string 亦以 dot 代替) */\r\n icon?: 'dot' | 'check' | 'alert' | 'placeholder' | string | undefined\r\n /** 是否圆角胶囊 */\r\n pill?: boolean\r\n /** 描边样式(浅背景 + 边框) */\r\n outline?: boolean\r\n /** 文本标签(未提供 slot 时兜底) */\r\n label?: string\r\n}>(), {\r\n tone: 'default',\r\n size: 'medium',\r\n progress: undefined,\r\n icon: undefined,\r\n pill: true,\r\n outline: false,\r\n label: ''\r\n})\r\n\r\nconst toneClass = computed(() => props.tone || 'default')\r\n\r\nconst ariaLabel = computed(() => {\r\n const text = (props.label || '').trim()\r\n const tone = props.tone\r\n const prog = props.progress\r\n if (prog) {\r\n const progMap: Record<string, string> = {\r\n incomplete: '未完成',\r\n partiallyComplete: '部分完成',\r\n complete: '已完成',\r\n }\r\n return text ? `${text},进度:${progMap[prog] || prog}` : `进度:${progMap[prog] || prog}`\r\n }\r\n if (tone && tone !== 'default') {\r\n const toneMap: Record<string, string> = {\r\n informational: '信息',\r\n success: '成功',\r\n attention: '注意',\r\n warning: '警告',\r\n critical: '严重',\r\n default: '默认'\r\n }\r\n return text ? `${text},语气:${toneMap[tone] || tone}` : `语气:${toneMap[tone] || tone}`\r\n }\r\n return text || '标记'\r\n})\r\n</script>\r\n\r\n<style scoped>\r\n.y-badge {\r\n display: inline-flex;\r\n vertical-align: middle;\r\n line-height: 1;\r\n}\r\n\r\n.y-badge__inner {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n border: 1px solid transparent;\r\n border-radius: 6px;\r\n padding: 2px 8px;\r\n font-weight: 600;\r\n font-size: 12px;\r\n color: #111827;\r\n background-color: #f3f4f6;\r\n}\r\n\r\n/* 尺寸 */\r\n.y-badge--small .y-badge__inner { padding: 1px 6px; font-size: 11px; border-radius: 6px; }\r\n.y-badge--medium .y-badge__inner { padding: 3px 10px; font-size: 12px; border-radius: 8px; }\r\n\r\n/* 胶囊圆角 */\r\n.is-pill .y-badge__inner { border-radius: 9999px; }\r\n\r\n/* 图标与进度图标统一尺寸 */\r\n.y-badge .icon { width: 12px; height: 12px; }\r\n\r\n/* 语气色板(尽量贴近 Polaris 感觉) */\r\n/* default */\r\n.y-badge--default .y-badge__inner { color: #374151; background-color: #F3F4F6; border-color: transparent; }\r\n.is-outline.y-badge--default .y-badge__inner { background-color: #fff; color: #374151; border-color: #E5E7EB; }\r\n\r\n/* informational */\r\n.y-badge--informational .y-badge__inner { color: #0b5394; background-color: #eaf3ff; }\r\n.is-outline.y-badge--informational .y-badge__inner { background-color: #fff; color: #0b5394; border-color: #b3d4ff; }\r\n\r\n/* success */\r\n.y-badge--success .y-badge__inner { color: #006c4f; background-color: #e7f5f0; }\r\n.is-outline.y-badge--success .y-badge__inner { background-color: #fff; color: #006c4f; border-color: #a8e0cf; }\r\n\r\n/* attention(信息但强调) */\r\n.y-badge--attention .y-badge__inner { color: #5b3a00; background-color: #fff3cd; }\r\n.is-outline.y-badge--attention .y-badge__inner { background-color: #fff; color: #5b3a00; border-color: #ffe69c; }\r\n\r\n/* warning */\r\n.y-badge--warning .y-badge__inner { color: #7a4400; background-color: #fdecc8; }\r\n.is-outline.y-badge--warning .y-badge__inner { background-color: #fff; color: #7a4400; border-color: #fbd38d; }\r\n\r\n/* critical */\r\n.y-badge--critical .y-badge__inner { color: #9b1c1c; background-color: #fde8e8; }\r\n.is-outline.y-badge--critical .y-badge__inner { background-color: #fff; color: #9b1c1c; border-color: #f5b5b5; }\r\n\r\n/* 进度类修饰,主要影响图标颜色与对比度(背景跟随 tone) */\r\n.y-badge__progress .icon { opacity: 0.9; }\r\n\r\n/* 深色模式粗略处理 */\r\n@media (prefers-color-scheme: dark) {\r\n .y-badge__inner { color: #e5eef7; background-color: rgba(2, 6, 23, 0.4); border-color: rgba(148, 163, 184, 0.18); }\r\n .y-badge--default .y-badge__inner { color: #e5eef7; background-color: rgba(2, 6, 23, 0.4); }\r\n .is-outline .y-badge__inner { background-color: transparent; }\r\n\r\n .y-badge--informational .y-badge__inner { color: #b7d4ff; background-color: rgba(30, 64, 175, 0.3); border-color: rgba(96, 165, 250, 0.35); }\r\n .y-badge--success .y-badge__inner { color: #b7f0da; background-color: rgba(2, 44, 34, 0.4); border-color: rgba(45, 212, 191, 0.35); }\r\n .y-badge--attention .y-badge__inner { color: #ffe3a3; background-color: rgba(120, 53, 15, 0.35); border-color: rgba(251, 191, 36, 0.35); }\r\n .y-badge--warning .y-badge__inner { color: #ffd9a3; background-color: rgba(120, 53, 15, 0.35); border-color: rgba(251, 191, 36, 0.35); }\r\n .y-badge--critical .y-badge__inner { color: #ffc3c3; background-color: rgba(127, 29, 29, 0.35); border-color: rgba(248, 113, 113, 0.35); }\r\n}\r\n</style>\r\n","<template>\n <teleport to=\"body\">\n <div\n v-show=\"visible\"\n class=\"y-dialog-root\"\n role=\"dialog\"\n :aria-modal=\"true\"\n :aria-hidden=\"!visible\"\n :style=\"{ zIndex: String(zIndex) }\"\n >\n <div\n class=\"y-dialog-mask\"\n @click=\"onMaskClick\"\n ></div>\n\n <transition name=\"dialog-zoom-fade\">\n <div\n v-show=\"visible\"\n ref=\"panelRef\"\n class=\"y-dialog-panel\"\n :class=\"[ center ? 'is-center' : '' ]\"\n :style=\"panelStyle\"\n @keydown.esc.prevent.stop=\"onEsc\"\n tabindex=\"-1\"\n >\n <div v-if=\"showHeader\" class=\"y-dialog-header\">\n <slot name=\"header\">\n <div class=\"y-dialog-title\">{{ title }}</div>\n </slot>\n <button\n v-if=\"closable\"\n type=\"button\"\n class=\"y-dialog-close\"\n aria-label=\"Close\"\n @click=\"close\"\n >\n ✕\n </button>\n </div>\n\n <div class=\"y-dialog-body\">\n <slot />\n </div>\n\n <div v-if=\"$slots.footer\" class=\"y-dialog-footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </transition>\n </div>\n </teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue'\n\nconst props = withDefaults(defineProps<{\n modelValue?: boolean\n title?: string\n width?: string | number\n top?: string\n closable?: boolean\n maskClosable?: boolean\n zIndex?: number\n showHeader?: boolean\n center?: boolean\n}>(), {\n modelValue: false,\n title: '',\n width: '520px',\n top: '15vh',\n closable: true,\n maskClosable: true,\n zIndex: 100001,\n showHeader: true,\n center: false,\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n (e: 'open'): void\n (e: 'close'): void\n}>()\n\nconst visible = computed({\n get: () => props.modelValue,\n set: (v: boolean) => emit('update:modelValue', v),\n})\n\nconst panelRef = ref<HTMLElement | null>(null)\n\nconst panelStyle = computed(() => {\n const style: Record<string, string> = {}\n style.width = typeof props.width === 'number' ? `${props.width}px` : String(props.width)\n style.margin = '0 auto'\n style.top = props.top\n return style\n})\n\nfunction onMaskClick() {\n if (!props.maskClosable) return\n close()\n}\n\nfunction close() {\n if (!visible.value) return\n visible.value = false\n emit('close')\n}\n\nfunction onEsc() {\n if (props.closable) close()\n}\n\nfunction onKeydown(e: KeyboardEvent) {\n if (e.key === 'Escape') onEsc()\n}\n\nwatch(() => props.modelValue, (v) => {\n if (v) {\n emit('open')\n requestAnimationFrame(() => panelRef.value?.focus())\n document.addEventListener('keydown', onKeydown)\n document.body.style.overflow = 'hidden'\n } else {\n document.removeEventListener('keydown', onKeydown)\n document.body.style.overflow = ''\n }\n})\n\nonMounted(() => {\n if (props.modelValue) {\n document.addEventListener('keydown', onKeydown)\n document.body.style.overflow = 'hidden'\n }\n})\n\nonUnmounted(() => {\n document.removeEventListener('keydown', onKeydown)\n document.body.style.overflow = ''\n})\n</script>\n\n<style scoped lang=\"less\">\n.y-dialog-root {\n position: fixed;\n inset: 0;\n}\n\n.y-dialog-mask {\n position: absolute;\n inset: 0;\n background: rgba(2, 6, 23, 0.55);\n backdrop-filter: blur(2px);\n}\n\n.y-dialog-panel {\n position: relative;\n background: #ffffff;\n border-radius: 12px;\n border: 1px solid rgba(15, 23, 42, 0.06);\n box-shadow: 0 12px 40px rgba(2, 6, 23, 0.18);\n}\n\n.y-dialog-panel.is-center .y-dialog-title { text-align: center; width: 100%; }\n\n.y-dialog-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 16px;\n border-bottom: 1px solid rgba(15, 23, 42, 0.06);\n}\n\n.y-dialog-title {\n font-size: 16px;\n font-weight: 600;\n color: #0b1a29;\n}\n\n.y-dialog-close {\n appearance: none;\n border: none;\n background: transparent;\n color: #334155;\n font-size: 16px;\n line-height: 1;\n cursor: pointer;\n padding: 6px;\n border-radius: 8px;\n}\n.y-dialog-close:hover { background: rgba(15,23,42,0.05); }\n\n.y-dialog-body {\n padding: 16px;\n max-height: calc(85vh - 110px);\n overflow: auto;\n}\n\n.y-dialog-footer {\n padding: 12px 16px;\n border-top: 1px solid rgba(15, 23, 42, 0.06);\n}\n\n/* 进入/离场动画:缩放淡入 */\n.dialog-zoom-fade-enter-from,\n.dialog-zoom-fade-leave-to { transform: scale(0.96); opacity: 0; }\n.dialog-zoom-fade-enter-active,\n.dialog-zoom-fade-leave-active { transition: transform 200ms cubic-bezier(0.2, 0.6, 0.4, 1), opacity 200ms cubic-bezier(0.2, 0.6, 0.4, 1); }\n.dialog-zoom-fade-enter-to,\n.dialog-zoom-fade-leave-from { transform: scale(1); opacity: 1; }\n\n@media (prefers-color-scheme: dark) {\n .y-dialog-panel {\n background: rgba(15, 23, 42, 0.7);\n border-color: rgba(148, 163, 184, 0.12);\n box-shadow: 0 12px 40px rgba(2, 6, 23, 0.5);\n }\n .y-dialog-title { color: #e5eef7; }\n .y-dialog-close { color: #cbd5e1; }\n .y-dialog-close:hover { background: rgba(148,163,184,0.12); }\n}\n</style>\n\n\n","<template>\n <div class=\"ypopover\" ref=\"popoverRef\">\n <!-- 触发器 -->\n <div \n ref=\"triggerRef\"\n @click=\"handleTriggerClick\"\n @mouseenter=\"handleMouseEnter\"\n @mouseleave=\"handleMouseLeave\"\n >\n <slot name=\"reference\"></slot>\n </div>\n \n <!-- 弹出内容 -->\n <Teleport to=\"body\">\n <Transition name=\"ypopover-fade\">\n <div\n v-if=\"visible\"\n ref=\"contentRef\"\n class=\"ypopover__content\"\n :class=\"[\n `ypopover__content--${placement}`,\n {\n 'ypopover__content--dark': dark,\n 'ypopover__content--no-padding': !showPadding\n }\n ]\"\n :style=\"contentStyle\"\n @click.stop\n @mouseenter=\"handleContentMouseEnter\"\n @mouseleave=\"handleContentMouseLeave\"\n >\n <!-- 箭头 -->\n <div \n v-if=\"showArrow\"\n class=\"ypopover__arrow\"\n :class=\"`ypopover__arrow--${placement}`\"\n :style=\"arrowStyle\"\n ></div>\n \n <!-- 内容 -->\n <div class=\"ypopover__inner\">\n <slot></slot>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue'\n\ninterface Props {\n // 触发方式\n trigger?: 'click' | 'hover' | 'focus' | 'manual'\n // 弹出位置\n placement?: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end'\n // 是否显示箭头\n showArrow?: boolean\n // 是否显示内边距\n showPadding?: boolean\n // 是否深色主题\n dark?: boolean\n // 是否禁用\n disabled?: boolean\n // 延迟显示时间(hover模式)\n openDelay?: number\n // 延迟隐藏时间(hover模式)\n closeDelay?: number\n // 是否点击外部关闭\n closeOnClickOutside?: boolean\n // 是否点击内容关闭\n closeOnClickContent?: boolean\n // 弹出框宽度\n width?: string | number\n // 弹出框最大宽度\n maxWidth?: string | number\n // 弹出框偏移量\n offset?: number\n // 手动控制显示状态\n modelValue?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n trigger: 'click',\n placement: 'bottom',\n showArrow: true,\n showPadding: true,\n dark: false,\n disabled: false,\n openDelay: 0,\n closeDelay: 200,\n closeOnClickOutside: true,\n closeOnClickContent: false,\n width: 'auto',\n maxWidth: '300px',\n offset: 8,\n modelValue: false\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n 'show': []\n 'hide': []\n 'before-show': []\n 'before-hide': []\n}>()\n\n// 响应式数据\nconst popoverRef = ref<HTMLElement>()\nconst triggerRef = ref<HTMLElement>()\nconst contentRef = ref<HTMLElement>()\nconst visible = ref(false)\nconst triggerRect = ref<DOMRect>()\nconst contentRect = ref<DOMRect>()\nconst arrowPosition = ref<Record<string, string>>({})\n\n// 定时器\nlet openTimer: number | null = null\nlet closeTimer: number | null = null\n\n// 计算属性\nconst contentStyle = computed(() => {\n if (!visible.value || !triggerRect.value) return {}\n \n const style: Record<string, string> = {}\n \n // 设置宽度\n if (props.width !== 'auto') {\n style.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n \n // 设置最大宽度\n if (props.maxWidth) {\n style.maxWidth = typeof props.maxWidth === 'number' ? `${props.maxWidth}px` : props.maxWidth\n }\n \n // 计算位置\n const { top, left } = calculatePosition()\n style.top = `${top}px`\n style.left = `${left}px`\n \n return style\n})\n\nconst arrowStyle = computed(() => {\n if (!props.showArrow) return {}\n \n // 返回计算好的箭头位置,如果没有则使用默认居中\n if (Object.keys(arrowPosition.value).length > 0) {\n return arrowPosition.value\n }\n \n // 默认居中位置\n const style: Record<string, string> = {}\n if (props.placement.startsWith('top') || props.placement.startsWith('bottom')) {\n style.left = '50%'\n } else {\n style.top = '50%'\n }\n return style\n})\n\n// 计算弹出框位置\nfunction calculatePosition() {\n if (!triggerRect.value) return { top: 0, left: 0 }\n \n const { width: triggerWidth, height: triggerHeight, top: triggerTop, left: triggerLeft } = triggerRect.value\n const contentWidth = contentRef.value?.offsetWidth || 200\n const contentHeight = contentRef.value?.offsetHeight || 100\n \n let top = 0\n let left = 0\n \n switch (props.placement) {\n case 'top':\n top = triggerTop - contentHeight - props.offset\n left = triggerLeft + (triggerWidth - contentWidth) / 2\n break\n case 'top-start':\n top = triggerTop - contentHeight - props.offset\n left = triggerLeft\n break\n case 'top-end':\n top = triggerTop - contentHeight - props.offset\n left = triggerLeft + triggerWidth - contentWidth\n break\n case 'bottom':\n top = triggerTop + triggerHeight + props.offset\n left = triggerLeft + (triggerWidth - contentWidth) / 2\n break\n case 'bottom-start':\n top = triggerTop + triggerHeight + props.offset\n left = triggerLeft\n break\n case 'bottom-end':\n top = triggerTop + triggerHeight + props.offset\n left = triggerLeft + triggerWidth - contentWidth\n break\n case 'left':\n top = triggerTop + (triggerHeight - contentHeight) / 2\n left = triggerLeft - contentWidth - props.offset\n break\n case 'left-start':\n top = triggerTop\n left = triggerLeft - contentWidth - props.offset\n break\n case 'left-end':\n top = triggerTop + triggerHeight - contentHeight\n left = triggerLeft - contentWidth - props.offset\n break\n case 'right':\n top = triggerTop + (triggerHeight - contentHeight) / 2\n left = triggerLeft + triggerWidth + props.offset\n break\n case 'right-start':\n top = triggerTop\n left = triggerLeft + triggerWidth + props.offset\n break\n case 'right-end':\n top = triggerTop + triggerHeight - contentHeight\n left = triggerLeft + triggerWidth + props.offset\n break\n }\n \n // 边界检测\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n \n // 水平边界检测\n if (left < 8) left = 8\n if (left + contentWidth > viewportWidth - 8) {\n left = viewportWidth - contentWidth - 8\n }\n \n // 垂直边界检测\n if (top < 8) top = 8\n if (top + contentHeight > viewportHeight - 8) {\n top = viewportHeight - contentHeight - 8\n }\n \n return { top, left }\n}\n\n// 显示弹出框\nfunction show() {\n if (props.disabled || visible.value) return\n \n clearTimers()\n \n if (props.openDelay > 0) {\n openTimer = setTimeout(() => {\n doShow()\n }, props.openDelay)\n } else {\n doShow()\n }\n}\n\nfunction doShow() {\n emit('before-show')\n visible.value = true\n emit('update:modelValue', true)\n emit('show')\n \n // 使用双重 nextTick 确保 DOM 完全更新\n nextTick(() => {\n nextTick(() => {\n updatePosition()\n })\n })\n}\n\n// 隐藏弹出框\nfunction hide() {\n if (!visible.value) return\n \n clearTimers()\n \n if (props.closeDelay > 0) {\n closeTimer = setTimeout(() => {\n doHide()\n }, props.closeDelay)\n } else {\n doHide()\n }\n}\n\nfunction doHide() {\n emit('before-hide')\n visible.value = false\n emit('update:modelValue', false)\n emit('hide')\n}\n\n// 清除定时器\nfunction clearTimers() {\n if (openTimer) {\n clearTimeout(openTimer)\n openTimer = null\n }\n if (closeTimer) {\n clearTimeout(closeTimer)\n closeTimer = null\n }\n}\n\n// 计算箭头位置\nfunction calculateArrowPosition() {\n if (!props.showArrow || !triggerRect.value || !contentRef.value) {\n arrowPosition.value = {}\n return\n }\n \n const trigger = triggerRect.value\n const contentRect = contentRef.value.getBoundingClientRect()\n \n // 如果弹出框还没有正确的尺寸,使用默认居中\n if (contentRect.width === 0 || contentRect.height === 0) {\n const style: Record<string, string> = {}\n if (props.placement.startsWith('top') || props.placement.startsWith('bottom')) {\n style.left = '50%'\n } else {\n style.top = '50%'\n }\n arrowPosition.value = style\n return\n }\n \n const style: Record<string, string> = {}\n \n // 根据位置计算箭头位置\n if (props.placement.startsWith('top')) {\n style.bottom = '-6px'\n // 水平居中\n const triggerCenterX = trigger.left + trigger.width / 2\n const contentLeft = contentRect.left\n const arrowOffset = triggerCenterX - contentLeft\n style.left = `${Math.max(12, Math.min(arrowOffset, contentRect.width - 12))}px`\n } else if (props.placement.startsWith('bottom')) {\n style.top = '-6px'\n // 水平居中\n const triggerCenterX = trigger.left + trigger.width / 2\n const contentLeft = contentRect.left\n const arrowOffset = triggerCenterX - contentLeft\n style.left = `${Math.max(12, Math.min(arrowOffset, contentRect.width - 12))}px`\n } else if (props.placement.startsWith('left')) {\n style.right = '-6px'\n // 垂直居中\n const triggerCenterY = trigger.top + trigger.height / 2\n const contentTop = contentRect.top\n const arrowOffset = triggerCenterY - contentTop\n style.top = `${Math.max(12, Math.min(arrowOffset, contentRect.height - 12))}px`\n } else if (props.placement.startsWith('right')) {\n style.left = '-6px'\n // 垂直居中\n const triggerCenterY = trigger.top + trigger.height / 2\n const contentTop = contentRect.top\n const arrowOffset = triggerCenterY - contentTop\n style.top = `${Math.max(12, Math.min(arrowOffset, contentRect.height - 12))}px`\n }\n \n arrowPosition.value = style\n}\n\n// 更新位置\nfunction updatePosition() {\n if (!triggerRef.value) return\n \n triggerRect.value = triggerRef.value.getBoundingClientRect()\n \n if (contentRef.value) {\n contentRect.value = contentRef.value.getBoundingClientRect()\n \n // 计算箭头位置\n calculateArrowPosition()\n \n // 如果弹出框刚显示,使用 requestAnimationFrame 确保位置正确\n if (visible.value) {\n requestAnimationFrame(() => {\n if (contentRef.value) {\n contentRect.value = contentRef.value.getBoundingClientRect()\n calculateArrowPosition()\n }\n })\n }\n }\n}\n\n// 事件处理\nfunction handleTriggerClick() {\n if (props.disabled) return\n \n if (props.trigger === 'click') {\n if (visible.value) {\n hide()\n } else {\n show()\n }\n }\n}\n\nfunction handleMouseEnter() {\n if (props.disabled || props.trigger !== 'hover') return\n \n clearTimers()\n show()\n}\n\nfunction handleMouseLeave() {\n if (props.disabled || props.trigger !== 'hover') return\n \n hide()\n}\n\n// 鼠标进入弹出框内容\nfunction handleContentMouseEnter() {\n if (props.disabled || props.trigger !== 'hover') return\n \n clearTimers()\n}\n\n// 鼠标离开弹出框内容\nfunction handleContentMouseLeave() {\n if (props.disabled || props.trigger !== 'hover') return\n \n hide()\n}\n\n// 点击外部关闭\nfunction handleClickOutside(event: MouseEvent) {\n if (!props.closeOnClickOutside || !visible.value) return\n \n const target = event.target as HTMLElement\n if (\n popoverRef.value &&\n !popoverRef.value.contains(target) &&\n contentRef.value &&\n !contentRef.value.contains(target)\n ) {\n hide()\n }\n}\n\n// 点击内容关闭\n// function handleContentClick() {\n// if (props.closeOnClickContent) {\n// hide()\n// }\n// }\n\n// 监听 modelValue 变化\nwatch(() => props.modelValue, (newVal) => {\n if (newVal !== visible.value) {\n if (newVal) {\n show()\n } else {\n hide()\n }\n }\n})\n\n// 监听 visible 变化\nwatch(visible, (newVal) => {\n if (newVal) {\n document.addEventListener('click', handleClickOutside)\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition, true)\n\n // 初次显示时可能由于 Teleport 尚未完成渲染导致定位不准确,这里增加多次异步更新保证贴边自适应\n nextTick(() => {\n updatePosition()\n requestAnimationFrame(() => {\n updatePosition()\n })\n setTimeout(() => {\n updatePosition()\n }, 0)\n })\n } else {\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n }\n})\n\n// 生命周期\nonMounted(() => {\n if (props.modelValue) {\n show()\n }\n})\n\nonUnmounted(() => {\n clearTimers()\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n})\n\n// 暴露方法\ndefineExpose({\n show,\n hide,\n updatePosition\n})\n</script>\n\n<style scoped lang=\"less\">\n.ypopover {\n display: inline-block;\n}\n\n.ypopover__content {\n position: fixed;\n z-index: 2000;\n background: #ffffff;\n border: 1px solid #e4e7ed;\n border-radius: 4px;\n box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);\n word-wrap: break-word;\n max-width: 300px;\n}\n\n.ypopover__content--dark {\n background: #303133;\n border-color: #303133;\n color: #ffffff;\n}\n\n.ypopover__content--no-padding .ypopover__inner {\n padding: 0;\n}\n\n.ypopover__inner {\n padding: 8px 12px;\n font-size: 14px;\n line-height: 1.4;\n color: #606266;\n}\n\n.ypopover__content--dark .ypopover__inner {\n color: #ffffff;\n}\n\n// 滚动条样式优化\n.ypopover__content,\n.ypopover__inner {\n &::-webkit-scrollbar {\n width: 4px;\n height: 4px;\n }\n\n &::-webkit-scrollbar-track {\n background: transparent;\n border-radius: 2px;\n }\n\n &::-webkit-scrollbar-thumb {\n background: #E7E7E7;\n border-radius: 2px;\n transition: background 0.2s;\n\n &:hover {\n background: #D0D0D0;\n }\n }\n}\n\n.ypopover__content--dark {\n &::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n\n &:hover {\n background: rgba(255, 255, 255, 0.4);\n }\n }\n}\n\n// 穿透样式,应用到 slot 内容中的滚动元素\n:deep(*) {\n &::-webkit-scrollbar {\n width: 4px;\n height: 4px;\n }\n\n &::-webkit-scrollbar-track {\n background: transparent;\n border-radius: 2px;\n }\n\n &::-webkit-scrollbar-thumb {\n background: #E7E7E7;\n border-radius: 2px;\n transition: background 0.2s;\n\n &:hover {\n background: #D0D0D0;\n }\n }\n}\n\n.ypopover__content--dark :deep(*) {\n &::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n\n &:hover {\n background: rgba(255, 255, 255, 0.4);\n }\n }\n}\n\n.ypopover__arrow {\n position: absolute;\n width: 0;\n height: 0;\n border: 6px solid transparent;\n}\n\n.ypopover__arrow--top {\n border-top-color: #e4e7ed;\n border-bottom: none;\n transform: translateX(-50%);\n}\n\n.ypopover__arrow--top::after {\n content: '';\n position: absolute;\n top: -5px;\n left: -6px;\n border: 6px solid transparent;\n border-top-color: #ffffff;\n border-bottom: none;\n}\n\n.ypopover__arrow--bottom {\n border-bottom-color: #e4e7ed;\n border-top: none;\n transform: translateX(-50%);\n}\n\n.ypopover__arrow--bottom::after {\n content: '';\n position: absolute;\n bottom: -5px;\n left: -6px;\n border: 6px solid transparent;\n border-bottom-color: #ffffff;\n border-top: none;\n}\n\n.ypopover__arrow--left {\n border-left-color: #e4e7ed;\n border-right: none;\n transform: translateY(-50%);\n}\n\n.ypopover__arrow--left::after {\n content: '';\n position: absolute;\n left: -5px;\n top: -6px;\n border: 6px solid transparent;\n border-left-color: #ffffff;\n border-right: none;\n}\n\n.ypopover__arrow--right {\n border-right-color: #e4e7ed;\n border-left: none;\n transform: translateY(-50%);\n}\n\n.ypopover__arrow--right::after {\n content: '';\n position: absolute;\n right: -5px;\n top: -6px;\n border: 6px solid transparent;\n border-right-color: #ffffff;\n border-left: none;\n}\n\n// 深色主题箭头\n.ypopover__content--dark .ypopover__arrow--top {\n border-top-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--top::after {\n border-top-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--bottom {\n border-bottom-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--bottom::after {\n border-bottom-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--left {\n border-left-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--left::after {\n border-left-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--right {\n border-right-color: #303133;\n}\n\n.ypopover__content--dark .ypopover__arrow--right::after {\n border-right-color: #303133;\n}\n\n// 过渡动画\n.ypopover-fade-enter-active,\n.ypopover-fade-leave-active {\n transition: opacity 0.2s ease;\n}\n\n.ypopover-fade-enter-from,\n.ypopover-fade-leave-to {\n opacity: 0;\n}\n</style>\n","<template>\n <div class=\"nh-time-search\" :class=\"[`nh-time--${size}`]\">\n <!-- 主要输入区域 -->\n <div class=\"relative\">\n <div\n ref=\"trigger\"\n @click=\"toggleDropdown\"\n @keydown=\"handleTriggerKeydown\"\n :class=\"['nh-time-trigger', { 'is-focus': isOpen, 'has-value': hasValue }]\"\n tabindex=\"0\"\n >\n <input\n readonly\n :value=\"displayText\"\n :placeholder=\"placeholder\"\n class=\"nh-time-input\"\n />\n <span class=\"nh-time-suffix\">\n <i \n v-if=\"clearable && hasValue\" \n @click.stop=\"handleClearClick\"\n class=\"nh-time-clear\"\n >\n <svg viewBox=\"0 0 1024 1024\" width=\"14\" height=\"14\">\n <path d=\"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1 1.9-11.2c1.5-1.2 3.3-1.9 5.2-1.9l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130.1 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z\" fill=\"currentColor\"/>\n </svg>\n </i>\n \n <i class=\"nh-time-icon\">\n <svg viewBox=\"0 0 1024 1024\" width=\"14\" height=\"14\">\n <path d=\"M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zM648 248v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h112v120H152V248h112v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h312zm184 584H192V424h640v408z\" fill=\"currentColor\"/>\n </svg>\n </i>\n \n <i class=\"nh-time-arrow\" :class=\"{ 'is-reverse': isOpen }\">\n <svg viewBox=\"0 0 1024 1024\" width=\"12\" height=\"12\">\n <path d=\"M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3 0.1-12.7-6.4-12.7z\" fill=\"currentColor\"/>\n </svg>\n </i>\n </span>\n </div>\n\n <!-- 下拉面板 -->\n <transition name=\"el-zoom-in-top\">\n <div\n v-if=\"isOpen\"\n ref=\"dropdown\"\n :class=\"dropdownClasses\"\n @keydown=\"handleDropdownKeydown\"\n >\n <!-- 快捷选项 -->\n <div class=\"nh-time-shortcuts\">\n <div class=\"nh-time-shortcuts-title\">快捷选项</div>\n <ul class=\"nh-time-shortcuts-list\">\n <li\n v-for=\"(shortcut, index) in shortcuts\"\n :key=\"shortcut.label\"\n @click=\"selectShortcut(shortcut)\"\n @keydown=\"handleShortcutKeydown($event, index)\"\n @mouseenter=\"handleShortcutMouseEnter(index)\"\n @mouseleave=\"handleShortcutMouseLeave\"\n :class=\"[\n 'nh-time-shortcut', \n { \n 'is-active': activeShortcutIndex === index,\n 'is-selected': selectedShortcutIndex === index\n }\n ]\"\n tabindex=\"0\"\n >\n {{ shortcut.label }}\n </li>\n </ul>\n </div>\n\n <!-- 自定义时间选择 -->\n <div class=\"nh-time-custom\">\n <div class=\"nh-time-custom-header\">\n <span>自定义时间</span>\n <!-- 新增:选择状态提示 -->\n <div class=\"nh-time-selection-status\">\n <span v-if=\"!tempStartDate && !tempEndDate\" class=\"status-text\">\n 请选择开始日期\n </span>\n <span v-else-if=\"tempStartDate && !tempEndDate\" class=\"status-text\">\n 请选择结束日期\n </span>\n <span v-else-if=\"tempStartDate && tempEndDate\" class=\"status-text status-complete\">\n 已选择完整范围\n </span>\n </div>\n </div>\n \n <!-- 日期选择器容器 -->\n <div class=\"nh-time-pickers\">\n <!-- 开始日期选择器 - 修改为通用日历 -->\n <div class=\"nh-time-picker\">\n <div class=\"nh-date-picker\">\n <!-- 年月选择器 -->\n <div class=\"nh-date-picker-header\">\n <button \n @click=\"changeMonth('start', -1)\"\n class=\"nh-date-picker-btn nh-date-picker-prev-btn\"\n type=\"button\"\n >\n <svg viewBox=\"0 0 1024 1024\" width=\"12\" height=\"12\">\n <path d=\"M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 0 0 0 50.3l450.8 352.1c5.2 4.1 12.9 0.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z\" fill=\"currentColor\"/>\n </svg>\n </button>\n <span class=\"nh-date-picker-header-label\">\n {{ formatYearMonth(startCalendar.year, startCalendar.month) }}\n </span>\n <button \n @click=\"changeMonth('start', 1)\"\n class=\"nh-date-picker-btn nh-date-picker-next-btn\"\n type=\"button\"\n >\n <svg viewBox=\"0 0 1024 1024\" width=\"12\" height=\"12\">\n <path d=\"M765.7 486.8L314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.8 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z\" fill=\"currentColor\"/>\n </svg>\n </button>\n </div>\n \n <!-- 星期标题 -->\n <div class=\"nh-date-picker-content\">\n <table class=\"nh-date-table\">\n <thead>\n <tr>\n <th v-for=\"day in weekDays\" :key=\"day\" class=\"nh-date-table-th\">{{ day }}</th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(week, weekIndex) in startCalendarDays\" :key=\"`start-week-${weekIndex}`\">\n <td \n v-for=\"(day, dayIndex) in week\" \n :key=\"`start-day-${weekIndex}-${dayIndex}`\"\n :class=\"getDateCellClass(day, 'start')\"\n @click=\"selectDate(day, 'start')\"\n >\n <div class=\"nh-date-table-cell\">\n <span v-if=\"day\">{{ day.day }}</span>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n \n <!-- 结束日期选择器 - 修改为通用日历 -->\n <div class=\"nh-time-picker\">\n <div class=\"nh-date-picker\">\n <!-- 年月选择器 -->\n <div class=\"nh-date-picker-header\">\n <button \n @click=\"changeMonth('end', -1)\"\n class=\"nh-date-picker-btn nh-date-picker-prev-btn\"\n type=\"button\"\n >\n <svg viewBox=\"0 0 1024 1024\" width=\"12\" height=\"12\">\n <path d=\"M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 0 0 0 50.3l450.8 352.1c5.2 4.1 12.9 0.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z\" fill=\"currentColor\"/>\n </svg>\n </button>\n <span class=\"nh-date-picker-header-label\">\n {{ formatYearMonth(endCalendar.year, endCalendar.month) }}\n </span>\n <button \n @click=\"changeMonth('end', 1)\"\n class=\"nh-date-picker-btn nh-date-picker-next-btn\"\n type=\"button\"\n >\n <svg viewBox=\"0 0 1024 1024\" width=\"12\" height=\"12\">\n <path d=\"M765.7 486.8L314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.8 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z\" fill=\"currentColor\"/>\n </svg>\n </button>\n </div>\n \n <!-- 日期表格 -->\n <div class=\"nh-date-picker-content\">\n <table class=\"nh-date-table\">\n <thead>\n <tr>\n <th v-for=\"day in weekDays\" :key=\"day\" class=\"nh-date-table-th\">{{ day }}</th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(week, weekIndex) in endCalendarDays\" :key=\"`end-week-${weekIndex}`\">\n <td \n v-for=\"(day, dayIndex) in week\" \n :key=\"`end-day-${weekIndex}-${dayIndex}`\"\n :class=\"getDateCellClass(day, 'end')\"\n @click=\"selectDate(day, 'end')\"\n >\n <div class=\"nh-date-table-cell\">\n <span v-if=\"day\">{{ day.day }}</span>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"nh-time-actions\">\n <YButton\n v-if=\"clearable\"\n @click=\"clearSelection\"\n :variant=\"'secondary'\"\n :size=\"size\"\n >\n 清空\n </YButton>\n <!-- 修改:优化确定按钮的状态提示 -->\n <YButton\n @click=\"confirmSelection\"\n :disabled=\"!canConfirm\"\n :variant=\"'primary'\"\n :size=\"size\"\n >\n {{ tempStartDate && !tempEndDate ? '继续选择结束日期' : '确认' }}\n </YButton>\n </div>\n </div>\n </div>\n </transition>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'\n\n// 定义类型\ninterface TimeRange {\n startDate: Date | null\n endDate: Date | null\n}\n\ninterface Shortcut {\n label: string\n getValue: () => TimeRange\n}\n\ninterface Props {\n modelValue?: TimeRange | { startDate: string | Date | number | null, endDate: string | Date | number | null }\n placeholder?: string\n shortcuts?: Shortcut[]\n clearable?: boolean\n format?: 'timestamp' | 'string' | 'date'\n includeTime?: boolean\n size?: 'mini' | 'small' | 'medium' | 'large'\n}\n\ninterface CalendarDay {\n date: Date\n day: number\n isCurrentMonth: boolean\n isToday: boolean\n isSelected: boolean\n isInRange: boolean\n isDisabled: boolean\n}\n\n// 定义 props,添加 includeTime 属性并提供默认值\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: () => ({ startDate: null, endDate: null }),\n placeholder: '请选择日期范围',\n clearable: true,\n format: 'timestamp',\n includeTime: false,\n size: 'small',\n shortcuts: () => [\n {\n label: '今天',\n getValue: () => {\n const today = new Date()\n const start = new Date(today.getFullYear(), today.getMonth(), today.getDate())\n const end = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59)\n return { startDate: start, endDate: end }\n }\n },\n {\n label: '昨天',\n getValue: () => {\n const yesterday = new Date()\n yesterday.setDate(yesterday.getDate() - 1)\n const start = new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate())\n const end = new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate(), 23, 59, 59)\n return { startDate: start, endDate: end }\n }\n },\n {\n label: '近7天',\n getValue: () => {\n const end = new Date()\n const start = new Date()\n start.setDate(start.getDate() - 6)\n start.setHours(0, 0, 0, 0)\n end.setHours(23, 59, 59, 999)\n return { startDate: start, endDate: end }\n }\n },\n {\n label: '近30天',\n getValue: () => {\n const end = new Date()\n const start = new Date()\n start.setDate(start.getDate() - 29)\n start.setHours(0, 0, 0, 0)\n end.setHours(23, 59, 59, 999)\n return { startDate: start, endDate: end }\n }\n },\n {\n label: '近3个月',\n getValue: () => {\n const end = new Date()\n const start = new Date()\n start.setMonth(start.getMonth() - 3)\n start.setHours(0, 0, 0, 0)\n end.setHours(23, 59, 59, 999)\n return { startDate: start, endDate: end }\n }\n }\n ]\n})\n\n// 定义 emits\nconst emit = defineEmits<{\n 'update:modelValue': [value: TimeRange | { startDate: string | number | null, endDate: string | number | null }]\n 'change': [value: TimeRange | { startDate: string | number | null, endDate: string | number | null }]\n}>()\n\n// 响应式数据\nconst isOpen = ref(false)\nconst activeShortcutIndex = ref(-1)\nconst selectedShortcutIndex = ref(-1)\nconst pendingValue = ref<TimeRange | null>(null)\nconst trigger = ref<HTMLElement>()\nconst dropdown = ref<HTMLElement>()\nconst dropdownPosition = ref({\n top: true,\n left: true\n})\n\n// 修改:日历相关的响应式数据\nconst startCalendar = ref({\n year: new Date().getFullYear(),\n month: new Date().getMonth()\n})\n\nconst endCalendar = ref({\n year: new Date().getFullYear(),\n month: new Date().getMonth() + 1\n})\n\n// 新增:确保结束日历月份不会与开始日历相同的函数\nconst ensureDifferentMonths = () => {\n const startTime = new Date(startCalendar.value.year, startCalendar.value.month).getTime()\n const endTime = new Date(endCalendar.value.year, endCalendar.value.month).getTime()\n \n if (startTime >= endTime) {\n // 如果开始月份大于等于结束月份,将结束月份设为开始月份的下一个月\n const nextMonth = new Date(startCalendar.value.year, startCalendar.value.month + 1)\n endCalendar.value.year = nextMonth.getFullYear()\n endCalendar.value.month = nextMonth.getMonth()\n }\n}\n\n// 新增:确保开始日历月份不会与结束日历相同的函数\nconst ensureDifferentMonthsReverse = () => {\n const startTime = new Date(startCalendar.value.year, startCalendar.value.month).getTime()\n const endTime = new Date(endCalendar.value.year, endCalendar.value.month).getTime()\n \n if (endTime <= startTime) {\n // 如果结束月份小于等于开始月份,将开始月份设为结束月份的上一个月\n const prevMonth = new Date(endCalendar.value.year, endCalendar.value.month - 1)\n startCalendar.value.year = prevMonth.getFullYear()\n startCalendar.value.month = prevMonth.getMonth()\n }\n}\n\nconst weekDays = ['一', '二', '三', '四', '五', '六', '日']\n\nconst tempStartDate = ref<Date | null>(null)\nconst tempEndDate = ref<Date | null>(null)\n\n// 修改:日期转换工具函数 - 支持时间戳\nconst parseDate = (date: string | Date | number | null): Date | null => {\n if (!date) return null\n if (date instanceof Date) return date\n if (typeof date === 'number') {\n // 时间戳格式\n return new Date(date)\n }\n if (typeof date === 'string') {\n const parsed = new Date(date)\n return isNaN(parsed.getTime()) ? null : parsed\n }\n return null\n}\n\n// 修改:格式化为字符串 - 根据 includeTime 决定返回格式\nconst formatDateToString = (date: Date | null): string | null => {\n if (!date) return null\n \n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n \n if (props.includeTime) {\n // 年月日时分秒格式: YYYY-MM-DD HH:mm:ss\n const hours = String(date.getHours()).padStart(2, '0')\n const minutes = String(date.getMinutes()).padStart(2, '0')\n const seconds = String(date.getSeconds()).padStart(2, '0')\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`\n } else {\n // 年月日格式: YYYY-MM-DD\n return `${year}-${month}-${day}`\n }\n}\n\n// 格式化为时间戳\nconst formatDateToTimestamp = (date: Date | null): number | null => {\n if (!date) return null\n return date.getTime()\n}\n\n// 修改:标准化输入值\nconst normalizeValue = (value: any): TimeRange => {\n if (!value) return { startDate: null, endDate: null }\n \n return {\n startDate: parseDate(value.startDate),\n endDate: parseDate(value.endDate)\n }\n}\n\n// 修改:格式化输出值 - 确保根据 includeTime 属性决定时间戳的精度\nconst formatOutputValue = (value: TimeRange) => {\n if (props.format === 'string') {\n // 返回根据 includeTime 决定的字符串格式\n return {\n startDate: formatDateToString(value.startDate),\n endDate: formatDateToString(value.endDate)\n }\n } else if (props.format === 'timestamp') {\n // 返回时间戳\n return {\n startDate: formatDateToTimestamp(value.startDate),\n endDate: formatDateToTimestamp(value.endDate)\n }\n } else {\n // format === 'date',返回Date对象\n return value\n }\n}\n\n// 工具函数\nconst formatYearMonth = (year: number, month: number) => {\n return `${String(month + 1).padStart(2, '0')}/${year}`\n}\n\nconst isSameDay = (date1: Date, date2: Date) => {\n return date1.getFullYear() === date2.getFullYear() &&\n date1.getMonth() === date2.getMonth() &&\n date1.getDate() === date2.getDate()\n}\n\nconst isDateInRange = (date: Date, start: Date | null, end: Date | null) => {\n if (!start || !end) return false\n return date >= start && date <= end\n}\n\n// 修改:检查当前值是否匹配某个快捷选项\nconst findMatchingShortcutIndex = (currentValue: any): number => {\n const normalizedValue = normalizeValue(currentValue)\n \n if (!normalizedValue?.startDate || !normalizedValue?.endDate) {\n return -1\n }\n\n for (let i = 0; i < props.shortcuts.length; i++) {\n const shortcutValue = props.shortcuts[i].getValue()\n \n if (shortcutValue.startDate && shortcutValue.endDate &&\n normalizedValue.startDate && normalizedValue.endDate) {\n \n // 比较日期时忽略时间部分\n const currentStart = new Date(normalizedValue.startDate.getFullYear(), \n normalizedValue.startDate.getMonth(), \n normalizedValue.startDate.getDate())\n const currentEnd = new Date(normalizedValue.endDate.getFullYear(), \n normalizedValue.endDate.getMonth(), \n normalizedValue.endDate.getDate())\n \n const shortcutStart = new Date(shortcutValue.startDate.getFullYear(), \n shortcutValue.startDate.getMonth(), \n shortcutValue.startDate.getDate())\n const shortcutEnd = new Date(shortcutValue.endDate.getFullYear(), \n shortcutValue.endDate.getMonth(), \n shortcutValue.endDate.getDate())\n \n if (currentStart.getTime() === shortcutStart.getTime() && \n currentEnd.getTime() === shortcutEnd.getTime()) {\n return i\n }\n }\n }\n \n return -1\n}\n\n// 修改:生成日历天数数据,调整日历布局\nconst generateCalendarDays = (year: number, month: number): CalendarDay[][] => {\n const firstDay = new Date(year, month, 1)\n const lastDay = new Date(year, month + 1, 0)\n const firstDayWeek = firstDay.getDay()\n const daysInMonth = lastDay.getDate()\n \n const days: CalendarDay[] = []\n const today = new Date()\n \n // 修改:确保每个月的第一天不在第一个位置\n // 如果当月第一天是周日(0),则显示上个月的6天\n // 否则显示上个月的(firstDayWeek-1)天\n const prevDaysCount = firstDayWeek === 0 ? 6 : firstDayWeek - 1\n \n // 添加上个月的日期 - 设为禁用\n // 修复:应基于当前月份计算上个月的最后一天,避免出现溢出到当月的日期(如 09/31 -> 10/01)\n const prevMonth = new Date(year, month, 0)\n for (let i = prevDaysCount - 1; i >= 0; i--) {\n const date = new Date(year, month - 1, prevMonth.getDate() - i)\n days.push({\n date,\n day: date.getDate(),\n isCurrentMonth: false,\n isToday: isSameDay(date, today),\n isSelected: false,\n isInRange: false,\n isDisabled: true // 禁用非当前月的日期\n })\n }\n \n // 添加当前月的日期\n for (let i = 1; i <= daysInMonth; i++) {\n const date = new Date(year, month, i)\n days.push({\n date,\n day: i,\n isCurrentMonth: true,\n isToday: isSameDay(date, today),\n isSelected: false,\n isInRange: false,\n isDisabled: false\n })\n }\n \n // 添加下个月的日期 - 设为禁用\n const remainingDays = 42 - days.length\n for (let i = 1; i <= remainingDays; i++) {\n const date = new Date(year, month + 1, i)\n days.push({\n date,\n day: i,\n isCurrentMonth: false,\n isToday: isSameDay(date, today),\n isSelected: false,\n isInRange: false,\n isDisabled: true // 禁用非当前月的日期\n })\n }\n \n // 将天数数组分组为周\n const weeks: CalendarDay[][] = []\n for (let i = 0; i < days.length; i += 7) {\n weeks.push(days.slice(i, i + 7))\n }\n \n return weeks\n}\n\n// 方法\nconst updateValue = (value: TimeRange) => {\n const formattedValue = formatOutputValue(value)\n emit('update:modelValue', formattedValue)\n emit('change', formattedValue)\n}\n\n// 新增:计算下拉面板最佳位置的函数\nconst calculateDropdownPosition = () => {\n if (!trigger.value || !dropdown.value) return\n\n const triggerRect = trigger.value.getBoundingClientRect()\n const dropdownRect = dropdown.value.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n const spaceBelow = viewportHeight - triggerRect.bottom\n const spaceAbove = triggerRect.top\n const dropdownHeight = dropdownRect.height || 400\n \n if (spaceBelow < dropdownHeight && spaceAbove > dropdownHeight) {\n dropdownPosition.value.top = false\n } else {\n dropdownPosition.value.top = true\n }\n\n const spaceRight = viewportWidth - triggerRect.left\n const dropdownWidth = dropdownRect.width || 640\n \n if (spaceRight < dropdownWidth) {\n dropdownPosition.value.left = false\n } else {\n dropdownPosition.value.left = true\n }\n}\n\nconst toggleDropdown = () => {\n isOpen.value = !isOpen.value\n if (isOpen.value) {\n // 初始化临时日期 - 使用标准化的值\n const normalizedValue = normalizeValue(props.modelValue)\n tempStartDate.value = normalizedValue?.startDate || null\n tempEndDate.value = normalizedValue?.endDate || null\n \n // 更新选中的快捷选项索引\n selectedShortcutIndex.value = findMatchingShortcutIndex(props.modelValue)\n \n // 重置键盘导航索引\n activeShortcutIndex.value = -1\n \n // 初始化日历显示月份\n if (normalizedValue?.startDate) {\n startCalendar.value.year = normalizedValue.startDate.getFullYear()\n startCalendar.value.month = normalizedValue.startDate.getMonth()\n }\n \n if (normalizedValue?.endDate) {\n endCalendar.value.year = normalizedValue.endDate.getFullYear()\n endCalendar.value.month = normalizedValue.endDate.getMonth()\n } else {\n // 如果没有结束日期,默认显示开始日期的下一个月\n const nextMonth = new Date(startCalendar.value.year, startCalendar.value.month + 1)\n endCalendar.value.year = nextMonth.getFullYear()\n endCalendar.value.month = nextMonth.getMonth()\n }\n \n // 确保两个日历显示不同的月份\n ensureDifferentMonths()\n \n nextTick(() => {\n calculateDropdownPosition()\n })\n }\n}\n\nconst handleClickOutside = (event: Event) => {\n const target = event.target as HTMLElement\n const triggerEl = trigger.value\n const dropdownEl = dropdown.value\n \n if (triggerEl && dropdownEl && \n !triggerEl.contains(target) && \n !dropdownEl.contains(target)) {\n isOpen.value = false\n activeShortcutIndex.value = -1\n }\n}\n\nconst handleTriggerKeydown = (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n toggleDropdown()\n } else if (event.key === 'ArrowDown') {\n event.preventDefault()\n isOpen.value = true\n nextTick(() => {\n calculateDropdownPosition()\n focusFirstShortcut()\n })\n }\n}\n\nconst handleDropdownKeydown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n isOpen.value = false\n activeShortcutIndex.value = -1\n trigger.value?.focus()\n }\n}\n \nconst handleShortcutKeydown = (event: KeyboardEvent, index: number) => {\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n activeShortcutIndex.value = Math.min(index + 1, props.shortcuts.length - 1)\n focusShortcut(activeShortcutIndex.value)\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n activeShortcutIndex.value = Math.max(index - 1, 0)\n focusShortcut(activeShortcutIndex.value)\n } else if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n selectShortcut(props.shortcuts[index])\n }\n}\n\nconst handleShortcutMouseEnter = (index: number) => {\n activeShortcutIndex.value = index\n}\n\nconst handleShortcutMouseLeave = () => {\n activeShortcutIndex.value = -1\n}\n\nconst focusFirstShortcut = () => {\n activeShortcutIndex.value = 0\n focusShortcut(0)\n}\n\nconst focusShortcut = (index: number) => {\n if (dropdown.value) {\n const shortcuts = dropdown.value.querySelectorAll('.nh-time-shortcut')\n const shortcutElement = shortcuts[index] as HTMLElement\n if (shortcutElement) {\n shortcutElement.focus()\n }\n }\n}\n\nconst selectShortcut = (shortcut: Shortcut) => {\n const value = shortcut.getValue()\n \n // 如果需要包含时间,确保时间部分正确设置\n if (props.includeTime && value.startDate && value.endDate) {\n value.startDate.setHours(0, 0, 0, 0)\n value.endDate.setHours(23, 59, 59, 999)\n }\n \n updateValue(value)\n \n // 更新选中的快捷选项索引\n selectedShortcutIndex.value = props.shortcuts.findIndex(s => s.label === shortcut.label)\n \n // 重置键盘导航索引\n activeShortcutIndex.value = -1\n \n isOpen.value = false\n}\n\n// 修改:选择日期时设置时间部分\nconst selectDate = (day: CalendarDay | null, type: 'start' | 'end') => {\n if (!day || day.isDisabled) return\n \n // 创建日期对象,根据是否需要保留时间部分设置时间\n let selectedDate: Date\n \n if (props.includeTime) {\n // 如果需要保留时分秒,则根据开始/结束位置设置不同的时间值\n selectedDate = new Date(day.date)\n if (type === 'start' || !tempStartDate.value) {\n // 开始日期设置为当天 00:00:00\n selectedDate.setHours(0, 0, 0, 0)\n } else {\n // 结束日期设置为当天 23:59:59\n selectedDate.setHours(23, 59, 59, 999)\n }\n } else {\n // 如果不需要保留时分秒,只保留年月日\n selectedDate = new Date(day.date.getFullYear(), day.date.getMonth(), day.date.getDate())\n }\n \n // 智能选择逻辑:\n // 1. 如果没有选择任何日期,当前选择的日期作为开始日期\n // 2. 如果已有开始日期但没有结束日期:\n // - 如果新选择的日期 >= 开始日期,设为结束日期\n // - 如果新选择的日期 < 开始日期,将新日期设为开始日期,原开始日期设为结束日期\n // 3. 如果已有开始和结束日期,重新开始选择:设为新的开始日期,清空结束日期\n \n if (!tempStartDate.value && !tempEndDate.value) {\n // 情况1:没有选择任何日期\n tempStartDate.value = selectedDate\n tempEndDate.value = null\n } else if (tempStartDate.value && !tempEndDate.value) {\n // 情况2:已有开始日期,没有结束日期\n if (selectedDate >= tempStartDate.value) {\n // 选择的日期大于等于开始日期,设为结束日期\n // 确保结束日期总是设置为 23:59:59\n if (props.includeTime) {\n selectedDate.setHours(23, 59, 59, 999)\n }\n tempEndDate.value = selectedDate\n } else {\n // 选择的日期小于开始日期,自动交换:新日期作为开始日期,原开始日期作为结束日期\n const endDate = tempStartDate.value\n // 确保结束日期总是设置为 23:59:59\n if (props.includeTime) {\n endDate.setHours(23, 59, 59, 999)\n }\n tempEndDate.value = endDate\n tempStartDate.value = selectedDate\n }\n } else {\n // 情况3:已有开始和结束日期,重新开始选择\n tempStartDate.value = selectedDate\n tempEndDate.value = null\n }\n \n // 清除快捷选项的选中状态,因为用户选择了自定义日期\n selectedShortcutIndex.value = -1\n \n // 更新待确认的值\n if (tempStartDate.value && tempEndDate.value) {\n // 确保结束日期总是设置为 23:59:59(如果启用了时间)\n const endDate = new Date(tempEndDate.value)\n if (props.includeTime) {\n endDate.setHours(23, 59, 59, 999)\n }\n pendingValue.value = { \n startDate: tempStartDate.value, \n endDate: endDate \n }\n } else {\n pendingValue.value = null\n }\n}\n\nconst getDateCellClass = (day: CalendarDay | null, type: 'start' | 'end') => {\n if (!day) return ['nh-date-table-td']\n \n const classes = ['nh-date-table-td']\n \n if (!day.isCurrentMonth) {\n classes.push('is-prev-month')\n }\n \n if (day.isToday) {\n classes.push('is-today')\n }\n \n if (day.isDisabled) {\n classes.push('is-disabled')\n }\n \n // 检查是否是选中的日期\n if (tempStartDate.value && isSameDay(day.date, tempStartDate.value)) {\n classes.push('is-selected', 'is-start')\n }\n \n if (tempEndDate.value && isSameDay(day.date, tempEndDate.value)) {\n classes.push('is-selected', 'is-end')\n }\n \n // 检查是否在选中范围内\n if (tempStartDate.value && tempEndDate.value && \n isDateInRange(day.date, tempStartDate.value, tempEndDate.value)) {\n classes.push('is-in-range')\n }\n \n return classes\n}\n\nconst confirmSelection = () => {\n if (pendingValue.value) {\n // 再次确保结束日期设置为 23:59:59(如果启用了时间)\n if (props.includeTime && pendingValue.value.endDate) {\n pendingValue.value.endDate.setHours(23, 59, 59, 999)\n }\n \n updateValue(pendingValue.value)\n // 检查新的值是否匹配某个快捷选项\n selectedShortcutIndex.value = findMatchingShortcutIndex(pendingValue.value)\n isOpen.value = false\n }\n}\n\nconst clearSelection = () => {\n updateValue({ startDate: null, endDate: null })\n resetSelection()\n activeShortcutIndex.value = -1\n isOpen.value = false\n}\n\n// 新增:监听窗口大小变化,重新计算位置\nconst handleResize = () => {\n if (isOpen.value) {\n nextTick(() => {\n calculateDropdownPosition()\n })\n }\n}\n\n// 计算属性\nconst startCalendarDays = computed(() => {\n return generateCalendarDays(startCalendar.value.year, startCalendar.value.month)\n})\n\nconst endCalendarDays = computed(() => {\n return generateCalendarDays(endCalendar.value.year, endCalendar.value.month)\n})\n\nconst displayText = computed(() => {\n const normalizedValue = normalizeValue(props.modelValue)\n \n if (!normalizedValue || !normalizedValue.startDate || !normalizedValue.endDate) {\n return ''\n }\n \n const formatDate = (date: Date) => {\n const year = String(date.getFullYear())\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n return `${year}/${month}/${day}`\n }\n \n const startStr = formatDate(normalizedValue.startDate)\n const endStr = formatDate(normalizedValue.endDate)\n \n // 如果是同一天且不包含时间,只显示一个日期\n if (!props.includeTime && startStr === endStr) {\n return startStr\n }\n \n return `${startStr} - ${endStr}`\n})\n\nconst dropdownClasses = computed(() => {\n return [\n 'nh-time-dropdown',\n {\n 'nh-time-dropdown-top': !dropdownPosition.value.top,\n 'nh-time-dropdown-right': !dropdownPosition.value.left\n }\n ]\n})\n\n// 新增计算属性:检查是否有值\nconst hasValue = computed(() => {\n const normalizedValue = normalizeValue(props.modelValue)\n return !!(normalizedValue?.startDate && normalizedValue?.endDate)\n})\n\n// 新增计算属性:检查是否可以确认 - 修改逻辑\nconst canConfirm = computed(() => {\n return !!(tempStartDate.value && tempEndDate.value)\n})\n\n// 修改:格式化显示日期(用于选择器标题)- 增强显示格式\n// const formatDisplayDate = (date: Date) => {\n// return new Intl.DateTimeFormat('zh-CN', {\n// month: '2-digit',\n// day: '2-digit'\n// }).format(date)\n// }\n\n// 新增:重置选择状态的方法\nconst resetSelection = () => {\n tempStartDate.value = null\n tempEndDate.value = null\n pendingValue.value = null\n selectedShortcutIndex.value = -1\n}\n\n// 监听器 - 修改以确保日历月份正确初始化\nwatch(() => props.modelValue, (newValue) => {\n const normalizedValue = normalizeValue(newValue)\n \n if (normalizedValue?.startDate) {\n const startDate = normalizedValue.startDate\n startCalendar.value.year = startDate.getFullYear()\n startCalendar.value.month = startDate.getMonth()\n }\n \n if (normalizedValue?.endDate) {\n const endDate = normalizedValue.endDate\n endCalendar.value.year = endDate.getFullYear()\n endCalendar.value.month = endDate.getMonth()\n } else if (normalizedValue?.startDate) {\n // 如果只有开始日期,结束日历显示下一个月\n const nextMonth = new Date(startCalendar.value.year, startCalendar.value.month + 1)\n endCalendar.value.year = nextMonth.getFullYear()\n endCalendar.value.month = nextMonth.getMonth()\n }\n \n // 确保两个日历显示不同的月份\n if (normalizedValue?.startDate || normalizedValue?.endDate) {\n ensureDifferentMonths()\n }\n \n // 当外部值改变时,更新选中的快捷选项\n if (!isOpen.value) {\n selectedShortcutIndex.value = findMatchingShortcutIndex(newValue)\n }\n}, { immediate: true, deep: true })\n\n// 新增:监听日历月份变化,确保不会显示相同月份\nwatch([startCalendar, endCalendar], () => {\n const startTime = new Date(startCalendar.value.year, startCalendar.value.month).getTime()\n const endTime = new Date(endCalendar.value.year, endCalendar.value.month).getTime()\n \n // 如果两个日历显示相同月份,自动调整\n if (startTime === endTime) {\n const nextMonth = new Date(startCalendar.value.year, startCalendar.value.month + 1)\n endCalendar.value.year = nextMonth.getFullYear()\n endCalendar.value.month = nextMonth.getMonth()\n }\n}, { deep: true })\n\n// 生命周期\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n window.addEventListener('resize', handleResize)\n window.addEventListener('scroll', handleResize)\n \n // 初始化时设置选中的快捷选项和日历月份\n selectedShortcutIndex.value = findMatchingShortcutIndex(props.modelValue)\n \n // 修复:初始化日历月份时使用标准化的值\n const normalizedValue = normalizeValue(props.modelValue)\n \n if (normalizedValue?.startDate) {\n startCalendar.value.year = normalizedValue.startDate.getFullYear()\n startCalendar.value.month = normalizedValue.startDate.getMonth()\n }\n \n if (normalizedValue?.endDate) {\n endCalendar.value.year = normalizedValue.endDate.getFullYear()\n endCalendar.value.month = normalizedValue.endDate.getMonth()\n } else {\n // 默认显示当前月和下个月\n const nextMonth = new Date(startCalendar.value.year, startCalendar.value.month + 1)\n endCalendar.value.year = nextMonth.getFullYear()\n endCalendar.value.month = nextMonth.getMonth()\n }\n \n ensureDifferentMonths()\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('resize', handleResize)\n window.removeEventListener('scroll', handleResize)\n})\n\n// 新增:处理输入框清空按钮点击\nconst handleClearClick = () => {\n if (!props.clearable) return\n \n updateValue({ startDate: null, endDate: null })\n resetSelection()\n activeShortcutIndex.value = -1\n}\n\n// 修改:日期选择相关方法\nconst changeMonth = (type: 'start' | 'end', direction: number) => {\n if (type === 'start') {\n const newDate = new Date(startCalendar.value.year, startCalendar.value.month + direction, 1)\n startCalendar.value.year = newDate.getFullYear()\n startCalendar.value.month = newDate.getMonth()\n \n // 确保结束月份不会与开始月份相同\n ensureDifferentMonths()\n } else {\n const newDate = new Date(endCalendar.value.year, endCalendar.value.month + direction, 1)\n endCalendar.value.year = newDate.getFullYear()\n endCalendar.value.month = newDate.getMonth()\n \n // 确保开始月份不会与结束月份相同\n ensureDifferentMonthsReverse()\n }\n}\n</script>\n\n<style scoped>\n/* 基础样式,与 YInput/YSelect 风格统一 */\n.nh-time-search {\n position: relative;\n display: inline-block;\n width: 250px;\n font-size: 14px;\n color: #0b1a29;\n}\n\n.nh-time-trigger {\n position: relative;\n display: inline-block;\n width: 100%;\n cursor: pointer;\n}\n\n.nh-time-trigger.is-focus .nh-time-input {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59,130,246,0.15);\n}\n\n.nh-time-input {\n background-color: #ffffff;\n border: 1px solid #e2e8f0;\n border-radius: 10px;\n box-sizing: border-box;\n color: #0b1a29;\n display: inline-block;\n font-size: inherit;\n outline: none;\n padding: 0 40px 0 12px;\n transition: box-shadow 0.2s ease, border-color 0.2s ease;\n width: 100%;\n cursor: pointer;\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif;\n}\n\n.nh-time-input:hover { border-color: #60a5fa; }\n\n.nh-time-input:focus {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59,130,246,0.15);\n outline: none;\n}\n\n.nh-time-input::placeholder {\n color: #9ca3af;\n}\n\n.nh-time-suffix {\n position: absolute;\n height: 100%;\n right: 8px;\n top: 0;\n display: flex;\n align-items: center;\n color: #6b7280;\n font-size: 14px;\n pointer-events: none;\n gap: 4px;\n}\n\n.nh-time-icon { display: flex; align-items: center; }\n\n.nh-time-arrow {\n display: flex;\n align-items: center;\n transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n.nh-time-clear {\n display: flex;\n align-items: center;\n cursor: pointer;\n color: #9ca3af;\n transition: all 0.2s ease;\n pointer-events: auto;\n}\n\n.nh-time-clear:hover {\n color: #6b7280;\n}\n\n.nh-time-clear:active {\n transform: scale(0.9);\n}\n\n/* 下拉面板样式 */\n.nh-time-dropdown {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n z-index: 50;\n background: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n box-shadow: 0 8px 20px rgba(2,6,23,0.15);\n display: flex;\n min-width: 640px;\n max-width: calc(100vw - 20px);\n box-sizing: border-box;\n overflow: hidden;\n}\n\n.nh-time-dropdown-top {\n top: auto;\n bottom: calc(100% + 4px);\n}\n\n.nh-time-dropdown-right {\n left: auto;\n right: 0;\n}\n\n/* 快捷选项样式 */\n.nh-time-shortcuts {\n width: 140px;\n border-right: 1px solid #e5e7eb;\n background-color: #f9fafb;\n}\n\n.nh-time-shortcuts-title {\n padding: 12px 16px 8px;\n color: #374151;\n font-size: 12px;\n font-weight: 500;\n border-bottom: 1px solid #e5e7eb;\n background-color: #f9fafb;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.nh-time-shortcuts-list {\n margin: 0;\n padding: 4px 0;\n list-style: none;\n}\n\n.nh-time-shortcut {\n display: block;\n width: 100%;\n padding: 8px 16px;\n margin: 0;\n font-size: 13px;\n color: #374151;\n cursor: pointer;\n border: none;\n background: none;\n text-align: left;\n outline: none;\n transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out;\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif;\n}\n\n.nh-time-shortcut:hover,\n.nh-time-shortcut.is-active {\n background-color: #f3f4f6;\n color: #1f2937;\n}\n\n.nh-time-shortcut:focus {\n background-color: #f3f4f6;\n outline: none;\n}\n\n.nh-time-shortcut.is-selected {\n background-color: #313B4A !important;\n color: #ffffff !important;\n}\n\n.nh-time-shortcut.is-selected:hover {\n background-color: #354051 !important;\n color: #ffffff !important;\n}\n\n.nh-time-shortcut:active {\n background-color: #e5e7eb;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n transform: translateY(1px);\n}\n\n/* 自定义时间选择样式 */\n.nh-time-custom {\n flex: 1;\n padding: 8px 16px;\n background-color: #ffffff;\n}\n\n.nh-time-custom-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.nh-time-custom-header span {\n font-size: 14px;\n font-weight: 500;\n color: #374151;\n}\n\n/* 选择状态提示样式 */\n.nh-time-selection-status {\n display: flex;\n align-items: center;\n}\n\n.status-text {\n font-size: 12px;\n color: #6b7280;\n padding: 4px 8px;\n border-radius: 4px;\n background-color: #f3f4f6;\n font-weight: 500;\n}\n\n.status-text.status-complete {\n color: #059669;\n background-color: #d1fae5;\n}\n\n.nh-time-pickers {\n display: flex;\n gap: 24px;\n margin-bottom: 8px;\n}\n\n.nh-time-picker {\n flex: 1;\n}\n\n.nh-time-picker-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 1px solid #f3f4f6;\n min-height: 40px;\n}\n\n.nh-time-picker-title {\n font-size: 13px;\n color: #6b7280;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.nh-time-picker-dates {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 2px;\n}\n\n.nh-time-picker-date {\n font-size: 11px;\n padding: 2px 6px;\n border-radius: 3px;\n font-weight: 500;\n}\n\n.nh-time-picker-date.start-date {\n color: #313B4A;\n background-color: #e4f0fd;\n}\n\n.nh-time-picker-date.end-date {\n color: #059669;\n background-color: #d1fae5;\n}\n\n.nh-time-picker-hint {\n display: flex;\n align-items: center;\n}\n\n.hint-text {\n font-size: 11px;\n color: #9ca3af;\n text-align: right;\n line-height: 1.3;\n max-width: 120px;\n}\n\n/* 日期选择器样式 */\n.nh-date-picker {\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n background: #ffffff;\n overflow: hidden;\n}\n\n.nh-date-picker:before {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: 8px;\n padding: 1px;\n background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8), rgba(229, 231, 235, 0.5));\n mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n pointer-events: none;\n}\n\n.nh-date-picker-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background-color: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.nh-date-picker-header-label {\n font-size: 14px;\n font-weight: 600;\n color: #374151;\n}\n\n.nh-date-picker-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n border-radius: 6px;\n color: #6b7280;\n transition: all 0.15s ease-in-out;\n}\n\n.nh-date-picker-btn:hover {\n background-color: #f3f4f6;\n color: #374151;\n}\n\n.nh-date-picker-btn:focus {\n outline: none;\n background-color: #f3f4f6;\n}\n\n.nh-date-picker-btn:active {\n transform: translateY(0);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.05);\n background: linear-gradient(to bottom, #f3f4f6, #e5e7eb);\n}\n\n.nh-date-picker-content {\n padding: 12px;\n background: linear-gradient(135deg, #ffffff, #fafafa);\n}\n\n/* 日期表格样式 */\n.nh-date-table {\n width: 100%;\n border-collapse: collapse;\n table-layout: fixed;\n}\n\n.nh-date-table-th {\n padding: 8px 4px;\n text-align: center;\n font-size: 11px;\n color: #6b7280;\n font-weight: 500;\n border-bottom: 1px solid #f3f4f6;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.nh-date-table-td {\n width: 32px;\n height: 32px;\n padding: 3px;\n box-sizing: border-box;\n}\n\n.nh-date-table-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 26px;\n width: 26px;\n margin: 0 auto;\n border-radius: 6px;\n font-size: 13px;\n color: #374151;\n transition: all 0.15s ease-in-out;\n position: relative;\n font-weight: 400;\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.02);\n}\n\n.nh-date-table-td:hover .nh-date-table-cell {\n background-color: #f3f4f6;\n color: #1f2937;\n}\n\n/* 日期状态样式 - 修改禁用状态但保留选中样式 */\n.nh-date-table-td.is-prev-month .nh-date-table-cell {\n color: #d1d5db;\n background-color: #f9fafb;\n cursor: not-allowed;\n}\n\n.nh-date-table-td.is-prev-month:hover .nh-date-table-cell {\n background-color: #f9fafb;\n color: #d1d5db;\n}\n\n/* 禁用状态的通用样式 */\n.nh-date-table-td.is-disabled .nh-date-table-cell {\n background-color: #f9fafb;\n color: #d1d5db;\n cursor: not-allowed;\n}\n\n.nh-date-table-td.is-disabled:hover .nh-date-table-cell {\n background-color: #f9fafb;\n color: #d1d5db;\n}\n\n/* 保留正常的选中状态样式 */\n.nh-date-table-td.is-selected .nh-date-table-cell {\n background-color: #313B4A;\n color: #ffffff;\n font-weight: 500;\n}\n\n.nh-date-table-td.is-in-range .nh-date-table-cell {\n background-color: #e4f0fd;\n color: #313B4A;\n}\n\n.nh-date-table-td.is-start .nh-date-table-cell,\n.nh-date-table-td.is-end .nh-date-table-cell {\n background-color: #313B4A;\n color: #ffffff;\n font-weight: 500;\n}\n\n/* 今天标记 */\n.nh-date-table-td.is-today .nh-date-table-cell {\n color: #c23616;\n font-weight: 600;\n}\n\n/* 修改:禁用且在选中范围内的日期显示为灰色背景 */\n.nh-date-table-td.is-disabled.is-in-range .nh-date-table-cell {\n background-color: #f3f4f6 !important;\n color: #9ca3af !important;\n cursor: not-allowed;\n}\n\n/* 修改:禁用且是开始/结束日期的样式 */\n.nh-date-table-td.is-disabled.is-start .nh-date-table-cell,\n.nh-date-table-td.is-disabled.is-end .nh-date-table-cell {\n background-color: #9ca3af !important;\n color: #ffffff !important;\n cursor: not-allowed;\n}\n\n.nh-date-table-td.is-disabled.is-selected .nh-date-table-cell {\n background-color: #9ca3af !important;\n color: #ffffff !important;\n cursor: not-allowed;\n}\n\n/* 修改:只有禁用且未选中的日期才显示完全禁用样式 */\n.nh-date-table-td.is-disabled:not(.is-selected):not(.is-start):not(.is-end):not(.is-in-range) .nh-date-table-cell {\n background-color: #f9fafb;\n color: #d1d5db;\n cursor: not-allowed;\n}\n\n.nh-date-table-td.is-disabled:not(.is-selected):not(.is-start):not(.is-end):not(.is-in-range):hover .nh-date-table-cell {\n background-color: #f9fafb;\n color: #d1d5db;\n}\n\n/* 今天标记 - 非当前月的禁用状态 */\n.nh-date-table-td.is-disabled.is-today:not(.is-selected):not(.is-start):not(.is-end):not(.is-in-range) .nh-date-table-cell {\n color: #d1d5db;\n font-weight: 600;\n background-color: #f9fafb;\n}\n\n/* 修改:禁用范围内日期的连接线样式 */\n.nh-date-table-td.is-disabled.is-in-range::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n height: 26px;\n background-color: rgba(156, 163, 175, 0.2);\n transform: translateY(-50%);\n z-index: -1;\n border: 1px solid rgba(156, 163, 175, 0.3);\n}\n\n/* 保留选中范围的连续效果 - 正常状态 */\n.nh-date-table-td.is-in-range:not(.is-disabled)::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n height: 26px;\n background-color: rgba(49, 59, 74, 0.1);\n transform: translateY(-50%);\n z-index: -1;\n border: 1px solid rgba(49, 59, 74, 0.2);\n}\n\n.nh-date-table-td.is-start.is-in-range::before {\n left: 50%;\n}\n\n.nh-date-table-td.is-end.is-in-range::before {\n right: 50%;\n}\n\n.nh-date-table-td.is-start.is-end.is-in-range::before {\n display: none;\n}\n\n/* 修改:禁用日期的视觉标记为灰色 */\n.nh-date-table-td.is-disabled.is-start .nh-date-table-cell::before {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 6px;\n height: 6px;\n background-color: #d1d5db;\n border-radius: 50%;\n z-index: 1;\n}\n\n.nh-date-table-td.is-disabled.is-end .nh-date-table-cell::after {\n content: '';\n position: absolute;\n bottom: 2px;\n right: 2px;\n width: 6px;\n height: 6px;\n background-color: #d1d5db;\n border-radius: 50%;\n z-index: 1;\n}\n\n/* 保留正常日期范围视觉标记 */\n.nh-date-table-td.is-start:not(.is-disabled) .nh-date-table-cell::before {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 6px;\n height: 6px;\n background-color: #ffffff;\n border-radius: 50%;\n z-index: 1;\n}\n\n.nh-date-table-td.is-end:not(.is-disabled) .nh-date-table-cell::after {\n content: '';\n position: absolute;\n bottom: 2px;\n right: 2px;\n width: 6px;\n height: 6px;\n background-color: #ffffff;\n border-radius: 50%;\n z-index: 1;\n}\n\n/* 只有完全禁用且未选中的日期才隐藏范围连接线和标记 */\n.nh-date-table-td.is-disabled:not(.is-selected):not(.is-start):not(.is-end):not(.is-in-range) .nh-date-table-cell::before,\n.nh-date-table-td.is-disabled:not(.is-selected):not(.is-start):not(.is-end):not(.is-in-range) .nh-date-table-cell::after {\n display: none;\n}\n\n.nh-time-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding-top: 2px;\n}\n\n/* 尺寸适配,与 YInput/YButton 保持一致 */\n.nh-time--mini .nh-time-input { height: 24px; border-radius: 6px; font-size: 11px; }\n.nh-time--small .nh-time-input { height: 32px; border-radius: 8px; font-size: 12px; }\n.nh-time--medium .nh-time-input { height: 44px; border-radius: 10px; font-size: 14px; }\n.nh-time--large .nh-time-input { height: 52px; border-radius: 12px; font-size: 16px; }\n\n/* 过渡动画 */\n.el-zoom-in-top-enter-active,\n.el-zoom-in-top-leave-active {\n opacity: 1;\n transform: scale(1);\n transition: opacity 0.2s ease-out, transform 0.2s ease-out;\n transform-origin: top;\n}\n\n.el-zoom-in-top-enter-from,\n.el-zoom-in-top-leave-to {\n opacity: 0;\n transform: scale(0.95);\n}\n\n/* 输入框状态优化 */\n.nh-time-trigger.has-value .nh-time-input {\n color: #1f2937;\n font-weight: 500;\n background-image: linear-gradient(to bottom, #ffffff, #f9fafb);\n}\n\n.nh-time-trigger:not(.has-value) .nh-time-input {\n color: #9ca3af;\n}\n\n/* 箭头旋转动画 */\n.nh-time-arrow {\n transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n.nh-time-arrow.is-reverse {\n transform: rotate(180deg);\n}\n\n/* 日历图标优化 */\n.nh-time-icon {\n display: flex;\n align-items: center;\n color: #6b7280;\n filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.1));\n}\n\n.nh-time-trigger.is-focus .nh-time-icon {\n color: #313B4A;\n filter: drop-shadow(0 1px 2px rgba(49, 59, 74, 0.2));\n}\n\n/* 输入框聚焦状态优化 */\n.nh-time-trigger.is-focus {\n box-shadow: 0 0 0 2px rgba(49, 59, 74, 0.2), 0 2px 5px rgba(0, 0, 0, 0.1);\n border-radius: 6px;\n}\n\n/* 清空按钮优化 */\n.nh-time-clear {\n opacity: 0;\n transition: all 0.2s ease;\n transform-origin: center;\n}\n\n.nh-time-trigger:hover .nh-time-clear,\n.nh-time-trigger.is-focus .nh-time-clear {\n opacity: 1;\n}\n\n/* 响应式设计 */\n@media (max-width: 768px) {\n .nh-time-search {\n width: 200px;\n }\n \n .nh-time-dropdown {\n min-width: 320px;\n max-width: calc(100vw - 20px);\n flex-direction: column;\n }\n \n .nh-time-shortcuts {\n width: 100%;\n border-right: none;\n border-bottom: 1px solid #e5e7eb;\n box-shadow: 0 2px 4px -2px rgba(0, 0, 0, 0.05);\n }\n \n .nh-time-shortcuts-list {\n display: flex;\n flex-wrap: wrap;\n padding: 8px;\n gap: 4px;\n }\n \n .nh-time-shortcut {\n flex: 1;\n min-width: 80px;\n text-align: center;\n padding: 6px 8px;\n border-radius: 4px;\n }\n \n .nh-time-pickers {\n flex-direction: column;\n gap: 12px;\n }\n \n .nh-date-picker-header-label {\n font-size: 13px;\n }\n \n .nh-date-table-cell {\n height: 24px;\n width: 24px;\n font-size: 12px;\n }\n \n .nh-date-table-td {\n height: 24px;\n width: 24px;\n }\n \n .nh-time-picker-header {\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n min-height: auto;\n }\n \n .nh-time-picker-dates {\n align-items: flex-start;\n width: 100%;\n }\n \n .hint-text {\n max-width: 100%;\n text-align: left;\n }\n \n .nh-time-actions {\n flex-direction: row;\n gap: 8px;\n }\n}\n\n/* 增强立体感的额外效果 */\n/* 悬停时的提升效果 */\n.nh-date-table-td:not(.is-disabled):hover {\n z-index: 1;\n}\n\n.nh-date-table-td:not(.is-disabled):active .nh-date-table-cell {\n transform: translateY(0);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n transition: all 0.1s ease;\n}\n\n/* 选中日期的脉冲动画效果 */\n@keyframes pulse {\n 0% {\n box-shadow: 0 0 0 0 rgba(49, 59, 74, 0.4);\n }\n 70% {\n box-shadow: 0 0 0 6px rgba(49, 59, 74, 0);\n }\n 100% {\n box-shadow: 0 0 0 0 rgba(49, 59, 74, 0);\n }\n}\n\n.nh-date-table-td.is-selected:not(.is-disabled) .nh-date-table-cell {\n animation: pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) 1;\n}\n\n/* 日期选择器边框渐变效果 */\n.nh-date-picker {\n position: relative;\n}\n\n.nh-date-picker:before {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: 8px;\n padding: 1px;\n background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8), rgba(229, 231, 235, 0.5));\n mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n pointer-events: none;\n}\n\n/* 月份切换按钮的点击效果 */\n.nh-date-picker-btn:active {\n transform: translateY(0);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.05);\n background: linear-gradient(to bottom, #f3f4f6, #e5e7eb);\n}\n\n/* 快捷选项的点击效果 */\n.nh-time-shortcut:active {\n background-color: #e5e7eb;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n transform: translateY(1px);\n}\n\n/* 下拉面板的内阴影效果 */\n.nh-time-dropdown:before {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: 10px;\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5);\n pointer-events: none;\n}\n\n/* 日期选择器内容区域的微妙渐变 */\n.nh-date-picker-content {\n background: linear-gradient(135deg, #ffffff, #fafafa);\n}\n\n/* 日期单元格的微妙阴影 */\n.nh-date-table-cell {\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.02);\n}\n\n/* 当前日期的特殊标记 */\n.nh-date-table-td.is-today .nh-date-table-cell:after {\n content: '';\n position: absolute;\n bottom: 3px;\n left: 50%;\n transform: translateX(-50%);\n width: 4px;\n height: 4px;\n background-color: #313B4A;\n border-radius: 50%;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n/* 选择状态完成的微妙动画 */\n@keyframes completeStatus {\n 0% {\n transform: scale(0.9);\n opacity: 0.7;\n }\n 50% {\n transform: scale(1.05);\n opacity: 1;\n }\n 100% {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n.status-text.status-complete {\n animation: completeStatus 0.3s ease-out;\n}\n\n/* 日历标题的微妙阴影 */\n.nh-date-picker-header-label {\n position: relative;\n z-index: 1;\n}\n\n.nh-date-picker-header-label:after {\n content: '';\n position: absolute;\n bottom: -2px;\n left: 0;\n width: 100%;\n height: 4px;\n background: linear-gradient(to right, rgba(49, 59, 74, 0), rgba(49, 59, 74, 0.1), rgba(49, 59, 74, 0));\n border-radius: 2px;\n z-index: -1;\n}\n\n/* 日期范围选择的过渡效果 */\n.nh-date-table-td.is-in-range .nh-date-table-cell {\n transition: background 0.3s ease, box-shadow 0.3s ease, color 0.3s ease;\n}\n\n/* 日期选择器的整体边框效果 */\n.nh-time-picker {\n position: relative;\n overflow: visible;\n}\n\n.nh-time-picker:after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: 10px;\n box-shadow: 0 0 0 1px rgba(229, 231, 235, 0.8);\n pointer-events: none;\n}\n</style>","<template>\n <button\n ref=\"rootEl\"\n class=\"yswitch\"\n :class=\"[\n `yswitch--${size}`,\n { 'yswitch--checked': isChecked, 'yswitch--disabled': disabled, 'yswitch--loading': loading }\n ]\"\n :style=\"switchStyle\"\n role=\"switch\"\n :aria-checked=\"isChecked\"\n :aria-disabled=\"disabled\"\n :disabled=\"disabled || loading\"\n @click=\"onToggle\"\n @keydown.enter.prevent=\"onToggle\"\n @keydown.space.prevent=\"onToggle\"\n >\n <span class=\"yswitch__track\"></span>\n <span class=\"yswitch__thumb\">\n <span v-if=\"loading\" class=\"yswitch__spinner\" aria-hidden=\"true\"></span>\n </span>\n <span v-if=\"showText\" class=\"yswitch__label\" :class=\"{ 'yswitch__label--left': !isChecked, 'yswitch__label--right': isChecked }\">\n {{ isChecked ? activeText : inactiveText }}\n </span>\n </button>\n \n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, onMounted } from 'vue'\n\nexport interface SwitchProps<T = boolean> {\n modelValue?: T\n trueValue?: T\n falseValue?: T\n disabled?: boolean\n loading?: boolean\n size?: 'small' | 'medium' | 'large'\n activeColor?: string\n inactiveColor?: string\n activeText?: string\n inactiveText?: string\n showText?: boolean\n}\n\nconst props = withDefaults(defineProps<SwitchProps>(), {\n modelValue: false,\n trueValue: true,\n falseValue: false,\n disabled: false,\n loading: false,\n size: 'medium',\n activeColor: '#10b981',\n inactiveColor: '#e5e7eb',\n activeText: '开',\n inactiveText: '关',\n showText: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: any]\n 'change': [value: any]\n 'focus': [event: FocusEvent]\n 'blur': [event: FocusEvent]\n}>()\n\nconst rootEl = ref<HTMLButtonElement>()\n\nconst isChecked = computed(() => props.modelValue === props.trueValue)\n\nconst switchStyle = computed(() => {\n const style: Record<string, string> = {}\n // 轨道背景色\n style.background = isChecked.value ? props.activeColor : props.inactiveColor\n return style\n})\n\nfunction onToggle() {\n if (props.disabled || props.loading) return\n const next = isChecked.value ? props.falseValue : props.trueValue\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nonMounted(() => {\n const el = rootEl.value\n if (!el) return\n el.addEventListener('focus', (e) => emit('focus', e as FocusEvent))\n el.addEventListener('blur', (e) => emit('blur', e as FocusEvent))\n})\n\n</script>\n\n<style scoped lang=\"less\">\n.yswitch {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: flex-start;\n border: none;\n cursor: pointer;\n outline: none;\n user-select: none;\n background: #e5e7eb;\n border-radius: 999px;\n transition: background-color 0.2s ease, box-shadow 0.2s ease;\n padding: 0;\n}\n\n.yswitch:focus-visible {\n box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.2);\n}\n\n.yswitch--disabled {\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.yswitch__track {\n position: absolute;\n inset: 0;\n border-radius: 999px;\n}\n\n.yswitch__thumb {\n position: relative;\n background: #ffffff;\n border-radius: 50%;\n transition: transform 0.2s ease;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.yswitch--small {\n width: 36px;\n height: 20px;\n}\n.yswitch--small .yswitch__thumb {\n width: 16px;\n height: 16px;\n transform: translateX(2px);\n}\n.yswitch--small.yswitch--checked .yswitch__thumb {\n transform: translateX(18px);\n}\n\n.yswitch--medium {\n width: 44px;\n height: 24px;\n}\n.yswitch--medium .yswitch__thumb {\n width: 20px;\n height: 20px;\n transform: translateX(2px);\n}\n.yswitch--medium.yswitch--checked .yswitch__thumb {\n transform: translateX(22px);\n}\n\n.yswitch--large {\n width: 45px;\n height: 32px;\n}\n.yswitch--large .yswitch__thumb {\n width: 28px;\n height: 28px;\n transform: translateX(2px);\n}\n.yswitch--large.yswitch--checked .yswitch__thumb {\n transform: translateX(26px);\n}\n\n.yswitch__label {\n margin-left: 8px;\n font-size: 12px;\n color: #4b5563;\n white-space: nowrap;\n}\n\n.yswitch__spinner {\n width: 12px;\n height: 12px;\n border: 2px solid rgba(0,0,0,0.15);\n border-top-color: rgba(0,0,0,0.45);\n border-radius: 50%;\n animation: yswitch-spin 0.8s linear infinite;\n}\n\n@keyframes yswitch-spin {\n to { transform: rotate(360deg); }\n}\n\n/* 暗色主题适配 */\n@media (prefers-color-scheme: dark) {\n .yswitch__label { color: #cbd5e1; }\n}\n\n</style>\n\n\n","<template>\n <div \n ref=\"containerRef\"\n class=\"yimage-container\"\n :class=\"containerClass\"\n >\n <!-- 懒加载占位符 -->\n <div \n v-if=\"!isLoaded && !hasError && !isInView\"\n class=\"yimage-placeholder\"\n :style=\"radiusStyle\"\n >\n <div class=\"yimage-placeholder-content\">\n <svg class=\"yimage-placeholder-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"></path>\n </svg>\n </div>\n </div>\n\n <!-- 加载动画 -->\n <div \n v-if=\"isLoading && !hasError\"\n class=\"yimage-loading\"\n :style=\"radiusStyle\"\n >\n <div class=\"yimage-loading-content\">\n <div class=\"yimage-spinner\"></div>\n </div>\n </div>\n\n <!-- 错误占位图 -->\n <div \n v-if=\"hasError\"\n class=\"yimage-error\"\n :style=\"radiusStyle\"\n @click=\"handleErrorClick\"\n >\n <img \n src=\"https://img.nihaojewelry.com/media/2025/6/27/1938511770352222208.png\" \n alt=\"Error Image\" \n class=\"yimage-error-image\"\n :style=\"radiusStyle\"\n />\n </div>\n\n <!-- 实际图片 -->\n <img\n v-show=\"isLoaded && !hasError\"\n ref=\"imageRef\"\n :src=\"imgSrc\"\n :alt=\"alt\"\n :class=\"imageClass\"\n @load=\"handleLoad\"\n @error=\"handleError\"\n @click.stop=\"handlePreview\"\n @mouseenter=\"onImageMouseEnter\"\n @mouseleave=\"onImageMouseLeave\"\n @mousemove=\"onImageMouseMove\"\n :style=\"imageStyle\"\n />\n \n <!-- 点击区域覆盖层,确保即使图片未完全加载也能点击 -->\n <div\n v-if=\"props.preview && (!isLoaded || isLoading || hasError || !isInView)\"\n class=\"yimage-preview-trigger\"\n @click.stop=\"handlePreview\"\n ></div>\n\n <!-- 大图预览遮罩 -->\n <Teleport to=\"body\" v-if=\"isMounted\">\n <transition name=\"fade\">\n <div \n v-if=\"showPreview\"\n class=\"yimage-preview-mask\"\n @click.self=\"closePreview\"\n @wheel.prevent=\"handleWheel\"\n >\n <div class=\"yimage-preview-content\" \n :class=\"{'is-active': showPreview}\">\n <!-- 预览图片 -->\n <img\n ref=\"previewImageRef\"\n :src=\"resolvedPreviewSrc\"\n :alt=\"alt\"\n class=\"yimage-preview-image\"\n :style=\"{ transform: `scale(${zoomLevel})` }\"\n @click.stop\n />\n </div>\n \n <!-- 图片信息 - 右下角,完整展示链接 -->\n <!-- <div class=\"fixed bottom-4 right-4 bg-black/50 text-white p-3 rounded max-w-md\">\n <p class=\"text-sm\">{{ alt || '图片预览' }}</p>\n <p class=\"text-xs text-gray-300 mt-1 break-all\">{{ previewSrc || props.src }}</p>\n <p class=\"text-xs text-gray-300 mt-1\">缩放: {{ Math.round(zoomLevel * 100) }}%</p>\n </div> -->\n </div>\n </transition>\n </Teleport>\n\n <!-- 鼠标移入侧边预览 -->\n <Teleport to=\"body\" v-if=\"isMounted && props.hoverPreview\">\n <transition name=\"hover-preview-fade\" appear>\n <div\n v-if=\"hoverPreview.visible && hoverPreview.src\"\n class=\"yimage-hover-preview\"\n :style=\"{\n top: hoverPreview.top + 'px',\n left: hoverPreview.left + 'px',\n width: hoverPreview.width + 'px',\n height: hoverPreview.height + 'px',\n }\"\n @mouseenter=\"onPreviewMouseEnter\"\n @mouseleave=\"onPreviewMouseLeave\"\n >\n <img :src=\"hoverPreview.src\" alt=\"图片预览\" />\n </div>\n </transition>\n </Teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'\nimport { Teleport } from 'vue'\nimport type { CSSProperties } from 'vue'\n\ninterface Props {\n src: string\n alt?: string\n width?: string | number\n height?: string | number\n lazy?: boolean\n preview?: boolean\n fit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\n radius?: string | number\n className?: string\n previewSrcList?: string | string[]\n hoverPreview?: boolean // 是否启用鼠标移入侧边显示大图预览\n hoverPreviewWidth?: number // 侧边预览窗口宽度\n hoverPreviewHeight?: number // 侧边预览窗口高度\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n alt: '',\n lazy: true,\n preview: true,\n fit: 'cover',\n radius: '0',\n className: '',\n hoverPreview: false,\n hoverPreviewWidth: 400,\n hoverPreviewHeight: 400\n})\n\nconst emit = defineEmits<{\n load: [event: Event]\n error: [event: Event]\n preview: [src: string]\n}>()\n\n// 响应式状态\nconst containerRef = ref<HTMLElement>()\nconst imageRef = ref<HTMLImageElement>()\nconst previewImageRef = ref<HTMLImageElement>()\nconst isLoaded = ref(false)\nconst isLoading = ref(false)\nconst hasError = ref(false)\nconst isInView = ref(false)\nconst showPreview = ref(false)\nconst imgSrc = ref('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDIwMCAyMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPCEtLSDog4zmma8gLS0+CiAgPHJlY3Qgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIGZpbGw9IiNGM0Y0RjYiLz4KICAKICA8IS0tIOWbvueJh+WbvuaghyAtLT4KICA8cmVjdCB4PSI1MCIgeT0iNDAiIHdpZHRoPSIxMDAiIGhlaWdodD0iODAiIHJ4PSI0IiBmaWxsPSIjRDFENURCIiBzdHJva2U9IiM5Q0EzQUYiIHN0cm9rZS13aWR0aD0iMiIvPgogIAogIDwhLS0g5Zu+54mH5YaF6YOo6KOF6aWwIC0tPgogIDxjaXJjbGUgY3g9IjgwIiBjeT0iNzAiIHI9IjgiIGZpbGw9IiM5Q0EzQUYiLz4KICA8cGF0aCBkPSJNNjAgMTAwIEw5MCA4NSBMMTIwIDk1IEwxNDAgODAiIHN0cm9rZT0iIzlDQTNBRiIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KICAKICA8IS0tIOaWh+WtlyAtLT4KICA8dGV4dCB4PSIxMDAiIHk9IjE2MCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzZCNzI4MCIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBmb250LXdlaWdodD0iNTAwIj4KICAgIEltYWdlIG5vdCBhdmFpbGFibGUKICA8L3RleHQ+Cjwvc3ZnPiA=')\nconst previewSrc = ref('')\nconst zoomLevel = ref(1)\nconst isMounted = ref(false)\n\n// 鼠标移入侧边预览相关状态\ntype HoverPreviewState = {\n visible: boolean\n src: string\n top: number\n left: number\n width: number\n height: number\n isHoveringPreview?: boolean\n}\nconst hoverPreview = ref<HoverPreviewState>({\n visible: false,\n src: '',\n top: 0,\n left: 0,\n width: 400,\n height: 400,\n isHoveringPreview: false\n})\n\n// 用于存储延迟隐藏的 timeout ID\nlet hidePreviewTimeout: ReturnType<typeof setTimeout> | null = null\n\n// 新增:保存原始滚动条状态\nconst originalBodyStyle = ref<{\n overflow: string\n paddingRight: string\n}>({\n overflow: '',\n paddingRight: ''\n})\n\n// 计算属性\nconst RADIUS_TOKEN_MAP: Record<string, string> = {\n none: '0px',\n sm: '0.125rem',\n md: '0.375rem',\n lg: '0.5rem',\n xl: '0.75rem',\n '2xl': '1rem',\n full: '9999px'\n}\n\nconst containerClass = computed(() => props.className || '')\n\nconst radiusValue = computed(() => {\n if (typeof props.radius === 'number') {\n return `${props.radius}px`\n }\n if (typeof props.radius === 'string') {\n if (/(px|%|rem|em)$/.test(props.radius)) {\n return props.radius\n }\n if (RADIUS_TOKEN_MAP[props.radius]) {\n return RADIUS_TOKEN_MAP[props.radius]\n }\n }\n return ''\n})\n\nconst radiusStyle = computed<CSSProperties>(() => {\n if (!radiusValue.value) {\n return {}\n }\n return {\n borderRadius: radiusValue.value\n }\n})\n\nconst imageClass = computed(() => {\n return [\n 'yimage-image',\n props.preview ? 'is-previewable' : ''\n ].filter(Boolean).join(' ')\n})\n\nconst imageStyle = computed(() => {\n const style: CSSProperties = {\n objectFit: props.fit || 'cover',\n backgroundColor: '#fff'\n }\n \n if (props.width) {\n style.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n \n if (props.height) {\n style.height = typeof props.height === 'number' ? `${props.height}px` : props.height\n }\n \n if (radiusValue.value) {\n style.borderRadius = radiusValue.value\n }\n \n return style\n})\n\nconst resolvedPreviewSrc = computed(() => {\n if (previewSrc.value) {\n return previewSrc.value\n }\n if (Array.isArray(props.previewSrcList)) {\n return props.previewSrcList.find(Boolean) || props.src\n }\n return props.previewSrcList || props.src\n})\n\n// 获取鼠标移入预览的图片URL\nconst getHoverPreviewSrc = computed(() => {\n if (Array.isArray(props.previewSrcList)) {\n return props.previewSrcList.find(Boolean) || props.src\n }\n return props.previewSrcList || props.src\n})\n\n// 工具函数\n// 新增:获取滚动条宽度\nconst getScrollbarWidth = () => {\n const scrollDiv = document.createElement('div')\n scrollDiv.style.cssText = 'width: 100px; height: 100px; overflow: scroll; position: absolute; top: -9999px;'\n document.body.appendChild(scrollDiv)\n const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth\n document.body.removeChild(scrollDiv)\n return scrollbarWidth\n}\n\n// 新增:锁定页面滚动\nconst lockBodyScroll = () => {\n // 保存原始样式\n originalBodyStyle.value = {\n overflow: document.body.style.overflow || '',\n paddingRight: document.body.style.paddingRight || ''\n }\n \n // 检查是否有滚动条\n const hasScrollbar = document.body.scrollHeight > window.innerHeight\n \n if (hasScrollbar) {\n const scrollbarWidth = getScrollbarWidth()\n // 设置右边距来防止页面跳动\n document.body.style.paddingRight = `${scrollbarWidth}px`\n }\n \n // 隐藏滚动条\n document.body.style.overflow = 'hidden'\n}\n\n// 新增:解锁页面滚动\nconst unlockBodyScroll = () => {\n // 恢复原始样式\n document.body.style.overflow = originalBodyStyle.value.overflow\n document.body.style.paddingRight = originalBodyStyle.value.paddingRight\n}\n\n// 懒加载逻辑\nlet observer: IntersectionObserver | null = null\n\nconst setupIntersectionObserver = () => {\n if (!props.lazy || !containerRef.value) return\n \n observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n isInView.value = true\n imgSrc.value = props.src\n observer?.unobserve(entry.target)\n }\n })\n },\n {\n rootMargin: '50px'\n }\n )\n \n observer.observe(containerRef.value)\n}\n\n// 事件处理\nconst handleLoad = (event: Event) => {\n isLoaded.value = true\n isLoading.value = false\n hasError.value = false\n emit('load', event)\n}\n\nconst handleError = (event: Event) => {\n hasError.value = true\n isLoading.value = false\n isLoaded.value = false\n emit('error', event)\n}\n\nconst retryLoad = () => {\n hasError.value = false\n isLoading.value = true\n isLoaded.value = false\n \n nextTick(() => {\n if (imageRef.value) {\n imageRef.value.src = props.src\n }\n })\n}\n\nconst getPreviewUrl = () => {\n if (Array.isArray(props.previewSrcList)) {\n return props.previewSrcList.find(Boolean) || props.src\n }\n return props.previewSrcList || props.src\n}\n\nconst handleErrorClick = () => {\n // 如果有预览源,即使加载失败也允许预览\n if (props.preview && (props.previewSrcList || props.src)) {\n handlePreview()\n } else {\n retryLoad()\n }\n}\n\nconst handlePreview = () => {\n if (!props.preview) return\n \n // 重置缩放级别\n zoomLevel.value = 1;\n \n // 使用预览源或原始源\n const previewUrl = getPreviewUrl();\n\n // 如果图片已经在当前 img 元素中加载完成,直接显示预览\n if (imageRef.value && imageRef.value.complete && imageRef.value.naturalWidth > 0) {\n previewSrc.value = previewUrl;\n nextTick(() => {\n showPreview.value = true;\n lockBodyScroll();\n emit('preview', previewUrl);\n });\n return;\n }\n \n // 预加载图片以避免闪烁\n const img = new Image();\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let isHandled = false;\n \n const showPreviewModal = () => {\n if (isHandled) return;\n isHandled = true;\n \n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n \n previewSrc.value = previewUrl;\n nextTick(() => {\n showPreview.value = true;\n lockBodyScroll();\n emit('preview', previewUrl);\n });\n };\n \n // 设置超时,防止预加载卡住\n timeoutId = setTimeout(() => {\n showPreviewModal();\n }, 500);\n \n img.onload = () => {\n showPreviewModal();\n };\n \n img.onerror = () => {\n // 如果预加载失败,仍然尝试显示\n showPreviewModal();\n };\n \n // 如果图片已经在缓存中,complete 会立即为 true\n img.src = previewUrl;\n \n // 检查图片是否已经在缓存中\n if (img.complete) {\n showPreviewModal();\n }\n}\n\nconst closePreview = () => {\n showPreview.value = false;\n \n // 等待过渡动画完成后恢复滚动\n setTimeout(() => {\n unlockBodyScroll();\n }, 300); // 与CSS过渡时间一致\n}\n\nconst handleWheel = (event: WheelEvent) => {\n // 确定缩放方向 (向上滚动放大,向下滚动缩小)\n const zoomDirection = event.deltaY < 0 ? 1 : -1;\n \n // 计算新的缩放级别 (每次缩放10%)\n const zoomStep = 0.1;\n let newZoom = zoomLevel.value + (zoomDirection * zoomStep);\n \n // 限制缩放范围在50%到200%之间\n newZoom = Math.max(0.5, Math.min(2.0, newZoom));\n \n // 更新缩放级别\n zoomLevel.value = newZoom;\n}\n\n// 鼠标移入侧边预览相关函数\nfunction updateImagePreviewPosition(target: EventTarget | null) {\n if (!(target instanceof HTMLElement)) return\n const rect = target.getBoundingClientRect()\n const padding = 12\n const viewportWidth = window.innerWidth || document.documentElement.clientWidth\n const viewportHeight = window.innerHeight || document.documentElement.clientHeight\n let left = rect.right + padding\n if (left + hoverPreview.value.width > viewportWidth - padding) {\n left = rect.left - hoverPreview.value.width - padding\n }\n let top = rect.top\n if (top + hoverPreview.value.height > viewportHeight - padding) {\n top = viewportHeight - hoverPreview.value.height - padding\n }\n if (top < padding) top = padding\n if (left < padding) left = padding\n hoverPreview.value.left = left\n hoverPreview.value.top = top\n}\n\nfunction onImageMouseEnter(event: MouseEvent) {\n if (!props.hoverPreview) return\n // 清除之前的隐藏延迟,确保快速切换时能立即显示\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n hoverPreview.value.isHoveringPreview = false\n hoverPreview.value.src = getHoverPreviewSrc.value\n hoverPreview.value.width = props.hoverPreviewWidth\n hoverPreview.value.height = props.hoverPreviewHeight\n hoverPreview.value.visible = true\n updateImagePreviewPosition(event.currentTarget)\n}\n\nfunction onImageMouseMove(event: MouseEvent) {\n if (!props.hoverPreview) return\n // 如果预览不可见,不更新位置\n if (!hoverPreview.value.visible) return\n // 清除可能的隐藏延迟,确保在鼠标移动时预览保持显示\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n updateImagePreviewPosition(event.currentTarget)\n}\n\nfunction onImageMouseLeave() {\n if (!props.hoverPreview) return\n // 如果鼠标已经在预览区域,不清除\n if (hoverPreview.value.isHoveringPreview) {\n return\n }\n // 清除之前的延迟\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n // 延迟隐藏,给鼠标移到预览区域的时间\n hidePreviewTimeout = setTimeout(() => {\n if (!hoverPreview.value.isHoveringPreview) {\n hoverPreview.value.visible = false\n hoverPreview.value.src = ''\n }\n hidePreviewTimeout = null\n }, 50)\n}\n\n// 鼠标移入预览区域\nfunction onPreviewMouseEnter() {\n if (!props.hoverPreview) return\n // 清除隐藏延迟\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n hoverPreview.value.isHoveringPreview = true\n}\n\n// 鼠标移出预览区域\nfunction onPreviewMouseLeave() {\n if (!props.hoverPreview) return\n hoverPreview.value.isHoveringPreview = false\n hoverPreview.value.visible = false\n hoverPreview.value.src = ''\n // 清除可能存在的延迟\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n}\n\n// 生命周期\nonMounted(() => {\n if (!props.lazy) {\n isInView.value = true\n } else {\n setupIntersectionObserver()\n }\n \n if (isInView.value) {\n isLoading.value = true\n }\n\n // 设置客户端渲染标志\n isMounted.value = true\n})\n\nonUnmounted(() => {\n if (observer) {\n observer.disconnect()\n }\n \n // 确保组件销毁时恢复滚动状态\n if (showPreview.value) {\n unlockBodyScroll()\n }\n \n // 清除可能存在的延迟隐藏\n if (hidePreviewTimeout) {\n clearTimeout(hidePreviewTimeout)\n hidePreviewTimeout = null\n }\n})\n\n// 监听src变化\nconst watchSrc = () => {\n if (props.src && isInView.value) {\n isLoading.value = true\n hasError.value = false\n isLoaded.value = false\n }\n}\n\nwatch(() => imgSrc.value, watchSrc)\nwatch(() => props.src, (nv) => {\n imgSrc.value = nv || ''\n})\n// 暴露方法\ndefineExpose({\n retryLoad,\n closePreview\n})\n</script>\n\n<style scoped>\n.yimage-container {\n position: relative;\n display: inline-block;\n overflow: hidden;\n}\n\n.yimage-placeholder,\n.yimage-loading,\n.yimage-error {\n width: 100%;\n height: 100%;\n}\n\n.yimage-placeholder {\n background-color: #e5e7eb;\n animation: yimage-pulse 2s ease-in-out infinite;\n}\n\n.yimage-placeholder-content {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n}\n\n.yimage-placeholder-icon {\n width: 24px;\n height: 24px;\n color: #9ca3af;\n}\n\n.yimage-loading {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(249, 250, 251, 0.9);\n pointer-events: none;\n}\n\n.yimage-loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n}\n\n.yimage-spinner {\n width: 32px;\n height: 32px;\n border: 4px solid rgba(26, 26, 26, 0.2);\n border-top-color: #1A1A1A;\n border-radius: 999px;\n animation: yimage-spin 1s linear infinite;\n}\n\n.yimage-error {\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: #f3f4f6;\n cursor: pointer;\n}\n\n.yimage-error-image {\n width: 70%;\n height: 70%;\n object-fit: contain;\n cursor: pointer;\n}\n\n.yimage-image {\n width: 100%;\n height: 100%;\n display: block;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.yimage-image.is-previewable {\n cursor: pointer;\n}\n\n.yimage-image.is-previewable:hover {\n opacity: 0.9;\n}\n\n.yimage-preview-trigger {\n position: absolute;\n inset: 0;\n cursor: pointer;\n z-index: 10;\n}\n\n.yimage-preview-mask {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.75);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 99999;\n}\n\n.yimage-preview-content {\n position: relative;\n max-width: 64rem;\n max-height: 100%;\n padding: 1rem;\n transform: scale(0.95);\n transition: transform 0.3s ease;\n}\n\n.yimage-preview-content.is-active {\n transform: scale(1);\n}\n\n.yimage-preview-image {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n border-radius: 0.5rem;\n box-shadow: 0 20px 45px rgba(0, 0, 0, 0.35);\n transition: transform 0.2s ease;\n}\n\n/* 过渡动画 */\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 0.3s ease;\n}\n\n.fade-enter-from,\n.fade-leave-to {\n opacity: 0;\n}\n\n/* 基础图片设置 */\nimg {\n display: block;\n -webkit-user-drag: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n}\n\n@keyframes yimage-pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n\n@keyframes yimage-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* 鼠标移入侧边预览样式 */\n.yimage-hover-preview {\n position: fixed;\n z-index: 2000;\n background: #fff;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);\n padding: 8px;\n pointer-events: auto;\n}\n\n.yimage-hover-preview img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n}\n\n.hover-preview-fade-enter-active,\n.hover-preview-fade-leave-active {\n transition: opacity 0.1s ease, transform 0.1s ease;\n}\n\n.hover-preview-fade-enter-from,\n.hover-preview-fade-leave-to {\n opacity: 0;\n transform: scale(0.96);\n}\n</style> ","<template>\n <div class=\"y-dropdown\" ref=\"dropdownRef\">\n <!-- 触发器 -->\n <div \n class=\"y-dropdown__trigger\" \n @mouseenter=\"showDropdown\"\n @mouseleave=\"hideDropdown\"\n >\n <slot name=\"trigger\">\n <button class=\"y-dropdown__button\">\n 下拉菜单\n </button>\n </slot>\n </div>\n\n <!-- 下拉菜单 -->\n <transition name=\"dropdown-fade\" appear>\n <div \n v-show=\"visible\"\n class=\"y-dropdown__menu\"\n :class=\"menuClass\"\n :style=\"menuStyle\"\n @mouseenter=\"showDropdown\"\n @mouseleave=\"hideDropdown\"\n >\n <slot>\n <div class=\"y-dropdown__item\">选项 1</div>\n <div class=\"y-dropdown__item\">选项 2</div>\n <div class=\"y-dropdown__item\">选项 3</div>\n </slot>\n </div>\n </transition>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'\n\ninterface Props {\n trigger?: 'hover' | 'click'\n placement?: 'bottom' | 'top' | 'left' | 'right'\n disabled?: boolean\n menuWidth?: number | string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n trigger: 'hover',\n placement: 'bottom',\n disabled: false,\n menuWidth: undefined\n})\n\nconst visible = ref(false)\nconst dropdownRef = ref<HTMLElement>()\nlet hideTimer: number | null = null\n\n// 计算菜单类名\nconst menuClass = computed(() => {\n return `y-dropdown__menu--${props.placement}`\n})\n\nconst menuStyle = computed(() => {\n if (!props.menuWidth) return {}\n const width =\n typeof props.menuWidth === 'number'\n ? `${props.menuWidth}px`\n : props.menuWidth\n return {\n width,\n minWidth: width,\n maxWidth: width\n }\n})\n\n// 显示下拉菜单\nconst showDropdown = () => {\n console.log('显示下拉菜单', visible.value)\n if (props.disabled) return\n \n // 清除隐藏定时器\n if (hideTimer) {\n clearTimeout(hideTimer)\n hideTimer = null\n }\n \n visible.value = true\n console.log('设置 visible 为 true', visible.value)\n \n // 立即计算位置,确保菜单在显示时就在正确位置\n nextTick(() => {\n updatePosition()\n })\n}\n\n// 隐藏下拉菜单\nconst hideDropdown = () => {\n console.log('隐藏下拉菜单')\n // 添加延迟,给用户时间移入菜单\n hideTimer = setTimeout(() => {\n visible.value = false\n console.log('设置 visible 为 false', visible.value)\n }, 150)\n}\n\n// 更新菜单位置\nconst updatePosition = () => {\n if (!dropdownRef.value) return\n \n const trigger = dropdownRef.value.querySelector('.y-dropdown__trigger') as HTMLElement\n const menu = dropdownRef.value.querySelector('.y-dropdown__menu') as HTMLElement\n \n if (!trigger || !menu) return\n \n // 获取触发器和菜单的尺寸信息\n const triggerRect = trigger.getBoundingClientRect()\n const menuRect = menu.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n \n // 重置位置样式\n menu.style.top = ''\n menu.style.left = ''\n menu.style.right = ''\n menu.style.bottom = ''\n menu.style.transform = ''\n \n let top = 0\n let left = 0\n \n // 根据 placement 设置基本位置\n switch (props.placement) {\n case 'bottom':\n top = triggerRect.height + 4\n left = 0\n break\n \n case 'top':\n top = -(menuRect.height + 4)\n left = 0\n break\n \n case 'right':\n top = 0\n left = triggerRect.width + 4\n break\n \n case 'left':\n top = 0\n left = -(menuRect.width + 4)\n break\n }\n \n // 计算相对于视口的绝对位置\n let absoluteTop = triggerRect.top + top\n let absoluteLeft = triggerRect.left + left\n \n // 水平边界检测和调整\n if (props.placement === 'bottom' || props.placement === 'top') {\n const menuWidth = menuRect.width || 260 // 使用实际菜单宽度\n \n // 如果菜单会超出右边界,向左偏移保持10px边距\n if (absoluteLeft + menuWidth > viewportWidth - 10) {\n absoluteLeft = viewportWidth - menuWidth - 10\n }\n \n // 如果菜单会超出左边界,向右偏移保持10px边距\n if (absoluteLeft < 10) {\n absoluteLeft = 10\n }\n }\n \n // 垂直边界检测和调整\n if (props.placement === 'left' || props.placement === 'right') {\n const menuHeight = menuRect.height || 200 // 使用实际菜单高度\n \n // 如果菜单会超出下边界,向上偏移保持10px边距\n if (absoluteTop + menuHeight > viewportHeight - 10) {\n absoluteTop = viewportHeight - menuHeight - 10\n }\n \n // 如果菜单会超出上边界,向下偏移保持10px边距\n if (absoluteTop < 10) {\n absoluteTop = 10\n }\n }\n \n // 应用位置(使用固定定位的绝对坐标)\n menu.style.top = `${absoluteTop}px`\n menu.style.left = `${absoluteLeft}px`\n}\n\n// 点击外部关闭\nconst handleClickOutside = (event: MouseEvent) => {\n if (props.trigger === 'click' && dropdownRef.value && !dropdownRef.value.contains(event.target as Node)) {\n visible.value = false\n }\n}\n\n// 窗口大小变化时重新计算位置\nconst handleResize = () => {\n if (visible.value) {\n updatePosition()\n }\n}\n\nonMounted(() => {\n if (props.trigger === 'click') {\n document.addEventListener('click', handleClickOutside)\n }\n // 监听窗口大小变化\n window.addEventListener('resize', handleResize)\n // 监听滚动事件\n window.addEventListener('scroll', handleResize)\n})\n\nonUnmounted(() => {\n if (props.trigger === 'click') {\n document.removeEventListener('click', handleClickOutside)\n }\n // 清理定时器\n if (hideTimer) {\n clearTimeout(hideTimer)\n }\n // 清理事件监听器\n window.removeEventListener('resize', handleResize)\n window.removeEventListener('scroll', handleResize)\n})\n\nwatch(\n () => props.menuWidth,\n () => {\n if (visible.value) {\n nextTick(() => {\n updatePosition()\n })\n }\n }\n)\n</script>\n\n<style scoped lang=\"less\">\n.y-dropdown {\n position: relative;\n display: inline-block;\n\n &__trigger {\n cursor: pointer;\n }\n\n &__button {\n height: 44px;\n padding: 0 16px;\n border: 1px solid #e2e8f0;\n border-radius: 10px;\n background: #fff;\n color: #0b1a29;\n cursor: pointer;\n font-size: 14px;\n transition: box-shadow 0.2s ease, border-color 0.2s ease;\n\n &:hover {\n border-color: #60a5fa;\n box-shadow: 0 0 0 4px rgba(59,130,246,0.15);\n }\n }\n\n &__menu {\n position: fixed;\n z-index: 9999;\n min-width: 100px;\n max-width: 300px;\n background: #fff;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n box-shadow: 0 8px 20px rgba(2,6,23,0.15);\n white-space: nowrap;\n\n &--bottom {\n top: calc(100% + 4px);\n left: 0;\n }\n\n &--top {\n bottom: calc(100% + 4px);\n left: 0;\n }\n\n &--left {\n top: 0;\n right: calc(100% + 4px);\n }\n\n &--right {\n top: 0;\n left: calc(100% + 4px);\n }\n }\n\n &__item {\n height: 36px;\n padding: 0 12px;\n color: #0b1a29;\n cursor: pointer;\n display: flex;\n align-items: center;\n font-size: 13px;\n transition: background-color 0.2s ease, color 0.2s ease;\n\n &:hover {\n background-color: #F6F6F7;\n color: #303061;\n }\n\n &:not(:last-child) {\n border-bottom: 1px solid #f1f5f9;\n }\n }\n}\n\n// 动画效果 - 只使用透明度变化,不改变位置\n.dropdown-fade-enter-active {\n transition: opacity 0.15s ease-out;\n}\n\n.dropdown-fade-leave-active {\n transition: opacity 0.1s ease-in;\n}\n\n.dropdown-fade-enter-from,\n.dropdown-fade-leave-to {\n opacity: 0;\n}\n\n.dropdown-fade-enter-to,\n.dropdown-fade-leave-from {\n opacity: 1;\n}\n\n// 暗色主题支持\n@media (prefers-color-scheme: dark) {\n .y-dropdown__button {\n background: rgba(2,6,23,0.4);\n border-color: rgba(148,163,184,0.18);\n color: #e5eef7;\n }\n \n .y-dropdown__menu {\n background: rgba(2,6,23,0.9);\n border-color: rgba(148,163,184,0.18);\n }\n \n .y-dropdown__item {\n color: #e5eef7;\n \n &:hover {\n background-color: #F6F6F7;\n color: #303061;\n }\n \n &:not(:last-child) {\n border-bottom-color: rgba(148,163,184,0.1);\n }\n }\n}\n</style>\n","<template>\r\n <teleport to=\"body\">\r\n <div\r\n v-show=\"visible\"\r\n class=\"y-drawer-root\"\r\n role=\"dialog\"\r\n :aria-modal=\"true\"\r\n :aria-hidden=\"!visible\"\r\n :style=\"{ zIndex: String(zIndex) }\"\r\n >\r\n <div\r\n class=\"y-drawer-mask\"\r\n @click=\"onMaskClick\"\r\n ></div>\r\n\r\n <transition :name=\"transitionName\">\r\n <div\r\n v-show=\"visible\"\r\n ref=\"panelRef\"\r\n class=\"y-drawer-panel\"\r\n :class=\"[\r\n `is-${placement}`,\r\n roundedClass,\r\n ]\"\r\n :style=\"panelStyle\"\r\n @keydown.esc.prevent.stop=\"onEsc\"\r\n tabindex=\"-1\"\r\n >\r\n <div v-if=\"showHeader\" class=\"y-drawer-header\">\r\n <div class=\"y-drawer-title\">{{ title }}</div>\r\n <button\r\n v-if=\"closable\"\r\n type=\"button\"\r\n class=\"y-drawer-close\"\r\n aria-label=\"Close\"\r\n @click=\"close\"\r\n >\r\n ✕\r\n </button>\r\n </div>\r\n\r\n <div class=\"y-drawer-body\">\r\n <slot />\r\n </div>\r\n\r\n <div v-if=\"$slots.footer\" class=\"y-drawer-footer\">\r\n <slot name=\"footer\" />\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n </teleport>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue'\r\n\r\nconst props = withDefaults(defineProps<{\r\n modelValue?: boolean\r\n placement?: 'right' | 'bottom'\r\n width?: string | number\r\n height?: string | number\r\n title?: string\r\n closable?: boolean\r\n maskClosable?: boolean\r\n zIndex?: number\r\n showHeader?: boolean\r\n}>(), {\r\n modelValue: false,\r\n placement: 'right',\r\n width: '420px',\r\n height: '60vh',\r\n title: '',\r\n closable: true,\r\n maskClosable: true,\r\n zIndex: 100000,\r\n showHeader: true,\r\n})\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: boolean): void\r\n (e: 'open'): void\r\n (e: 'close'): void\r\n}>()\r\n\r\nconst visible = computed({\r\n get: () => props.modelValue,\r\n set: (v: boolean) => emit('update:modelValue', v),\r\n})\r\n\r\nconst panelRef = ref<HTMLElement | null>(null)\r\n\r\nconst transitionName = computed(() => props.placement === 'right' ? 'drawer-slide-right' : 'drawer-slide-bottom')\r\n\r\nconst roundedClass = computed(() => props.placement === 'right' ? 'rounded-left' : 'rounded-top')\r\n\r\nconst panelStyle = computed(() => {\r\n const style: Record<string, string> = {}\r\n if (props.placement === 'right') {\r\n style.width = typeof props.width === 'number' ? `${props.width}px` : String(props.width)\r\n style.height = '100%'\r\n style.right = '0'\r\n style.top = '0'\r\n } else {\r\n style.height = typeof props.height === 'number' ? `${props.height}px` : String(props.height)\r\n style.width = '100%'\r\n style.bottom = '0'\r\n style.left = '0'\r\n }\r\n return style\r\n})\r\n\r\nfunction onMaskClick() {\r\n if (!props.maskClosable) return\r\n close()\r\n}\r\n\r\nfunction close() {\r\n if (!visible.value) return\r\n visible.value = false\r\n emit('close')\r\n}\r\n\r\nfunction onEsc() {\r\n if (props.closable) close()\r\n}\r\n\r\nfunction onKeydown(e: KeyboardEvent) {\r\n if (e.key === 'Escape') onEsc()\r\n}\r\n\r\nwatch(() => props.modelValue, (v) => {\r\n if (v) {\r\n emit('open')\r\n // 聚焦,便于 Esc 关闭\r\n requestAnimationFrame(() => panelRef.value?.focus())\r\n document.addEventListener('keydown', onKeydown)\r\n document.body.style.overflow = 'hidden'\r\n } else {\r\n document.removeEventListener('keydown', onKeydown)\r\n document.body.style.overflow = ''\r\n }\r\n})\r\n\r\nonMounted(() => {\r\n if (props.modelValue) {\r\n document.addEventListener('keydown', onKeydown)\r\n document.body.style.overflow = 'hidden'\r\n }\r\n})\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener('keydown', onKeydown)\r\n document.body.style.overflow = ''\r\n})\r\n</script>\r\n\r\n<style scoped>\r\n.y-drawer-root {\r\n position: fixed;\r\n inset: 0;\r\n}\r\n\r\n.y-drawer-mask {\r\n position: absolute;\r\n inset: 0;\r\n background: rgba(2, 6, 23, 0.55);\r\n backdrop-filter: blur(2px);\r\n}\r\n\r\n.y-drawer-panel {\r\n position: absolute;\r\n display: flex;\r\n flex-direction: column;\r\n background: #ffffff;\r\n border: 1px solid rgba(15, 23, 42, 0.06);\r\n box-shadow: 0 12px 40px rgba(2, 6, 23, 0.18);\r\n}\r\n\r\n/* 圆角根据拉出方向,仅对露出的边做圆角 */\r\n.rounded-left { border-radius: 12px 0 0 12px; }\r\n.rounded-top { border-radius: 12px 12px 0 0; }\r\n\r\n.y-drawer-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 14px 16px;\r\n border-bottom: 1px solid rgba(15, 23, 42, 0.06);\r\n}\r\n\r\n.y-drawer-title {\r\n font-size: 16px;\r\n font-weight: 600;\r\n color: #0b1a29;\r\n}\r\n\r\n.y-drawer-close {\r\n appearance: none;\r\n border: none;\r\n background: transparent;\r\n color: #334155;\r\n font-size: 16px;\r\n line-height: 1;\r\n cursor: pointer;\r\n padding: 6px;\r\n border-radius: 8px;\r\n}\r\n.y-drawer-close:hover { background: rgba(15,23,42,0.05); }\r\n\r\n.y-drawer-body {\r\n padding: 16px;\r\n overflow: auto;\r\n}\r\n\r\n.y-drawer-footer {\r\n padding: 12px 16px;\r\n border-top: 1px solid rgba(15, 23, 42, 0.06);\r\n}\r\n\r\n/* 进入/离场动画:右侧 */\r\n.drawer-slide-right-enter-from,\r\n.drawer-slide-right-leave-to { transform: translateX(100%); opacity: 0.98; }\r\n.drawer-slide-right-enter-active,\r\n.drawer-slide-right-leave-active { transition: transform 220ms ease, opacity 220ms ease; }\r\n.drawer-slide-right-enter-to,\r\n.drawer-slide-right-leave-from { transform: translateX(0%); opacity: 1; }\r\n\r\n/* 进入/离场动画:底部 */\r\n.drawer-slide-bottom-enter-from,\r\n.drawer-slide-bottom-leave-to { transform: translateY(100%); opacity: 0.98; }\r\n.drawer-slide-bottom-enter-active,\r\n.drawer-slide-bottom-leave-active { transition: transform 220ms ease, opacity 220ms ease; }\r\n.drawer-slide-bottom-enter-to,\r\n.drawer-slide-bottom-leave-from { transform: translateY(0%); opacity: 1; }\r\n\r\n/* 位置占位 */\r\n.y-drawer-panel.is-right { right: 0; top: 0; bottom: 0; }\r\n.y-drawer-panel.is-bottom { left: 0; right: 0; bottom: 0; }\r\n\r\n@media (prefers-color-scheme: dark) {\r\n .y-drawer-panel {\r\n background: rgba(15, 23, 42, 0.7);\r\n border-color: rgba(148, 163, 184, 0.12);\r\n box-shadow: 0 12px 40px rgba(2, 6, 23, 0.5);\r\n }\r\n .y-drawer-title { color: #e5eef7; }\r\n .y-drawer-close { color: #cbd5e1; }\r\n .y-drawer-close:hover { background: rgba(148,163,184,0.12); }\r\n}\r\n</style>\r\n\r\n\r\n","<template>\n <div\n class=\"ytree-node\"\n :class=\"{\n 'ytree-node--current': isCurrent,\n 'ytree-node--highlight': isHighlighted,\n }\"\n >\n <div\n class=\"ytree-node__content\"\n :class=\"{ 'is-child-style': isChildStyle }\"\n :style=\"{ paddingLeft: `${paddingLeft}px` }\"\n :data-level=\"nodeDepth\"\n @click=\"handleNodeClick(props.node, props.node, null, props.rootNode)\"\n @contextmenu=\"handleNodeContextMenu($event, props.node, props.node, null)\"\n >\n <!-- 展开/收起图标 -->\n <span\n v-if=\"hasNodeChildren\"\n class=\"ytree-node__expand-icon\"\n :class=\"{ 'is-expanded': isExpanded }\"\n @click.stop=\"handleExpandClick(props.node)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <path\n d=\"M4.5 3L7.5 6L4.5 9\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n <span v-else class=\"ytree-node__expand-icon--empty\"></span>\n\n <!-- 复选框 -->\n <span\n v-if=\"showCheckbox\"\n class=\"ytree-node__checkbox\"\n :class=\"{\n 'is-checked': isChecked,\n 'is-indeterminate': isIndeterminate,\n }\"\n @click.stop=\"handleCheckClick(props.node)\"\n >\n <svg\n v-if=\"isChecked\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n >\n <path\n d=\"M2 6L4.5 8.5L10 3\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <svg\n v-else-if=\"isIndeterminate\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n >\n <path\n d=\"M2 6L10 6\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </span>\n\n <!-- 节点图标 -->\n <span\n v-if=\"iconClass\"\n class=\"ytree-node__icon\"\n :class=\"iconClass\"\n ></span>\n\n <!-- 节点头像/图标 -->\n <img\n class=\"ytree-node__avatar\"\n :src=\"nodeIcon\"\n :alt=\"isEmployee ? 'person' : 'dept'\"\n />\n\n <!-- 节点标签 -->\n <span\n class=\"ytree-node__label\"\n :class=\"{ 'is-employee': isEmployee }\"\n >\n {{ nodeLabel }}\n </span>\n\n <!-- 自定义节点内容插槽 -->\n <div class=\"ytree-node__custom-content\">\n <slot\n name=\"node-content\"\n :node=\"props.node\"\n :is-current=\"isCurrent\"\n :is-expanded=\"isExpanded\"\n :has-children=\"hasNodeChildren\"\n />\n </div>\n </div>\n\n <!-- 子节点 - 递归渲染 -->\n <transition name=\"ytree-node\">\n <div\n v-if=\"hasNodeChildren && isExpanded\"\n class=\"ytree-node__children\"\n >\n <YTreeNode\n v-for=\"child in nodeChildren\"\n :key=\"getNodeKey(child)\"\n :node=\"child\"\n :root-node=\"rootNode\"\n :level=\"level + 1\"\n :show-checkbox=\"showCheckbox\"\n :icon-class=\"iconClass\"\n :dept-icon-url=\"deptIconUrl\"\n :person-icon-url=\"personIconUrl\"\n :button-icon-url=\"buttonIconUrl\"\n :child-style-level=\"childStyleLevel\"\n :child-style-icon-url=\"childStyleIconUrl\"\n :enable-child-style-custom-click=\"enableChildStyleCustomClick\"\n :disabled=\"disabled\"\n :expand-on-click-node=\"expandOnClickNode\"\n >\n <template #node-content=\"slotProps\">\n <slot name=\"node-content\" v-bind=\"slotProps\" />\n </template>\n </YTreeNode>\n </div>\n </transition>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { inject, computed } from \"vue\";\nimport type { TreeNode } from \"./ytree.vue\";\nimport YTreeNode from \"./ytree-node.vue\";\n\ninterface Props {\n node: TreeNode;\n rootNode: TreeNode;\n level: number;\n showCheckbox?: boolean;\n iconClass?: string;\n deptIconUrl?: string;\n personIconUrl?: string;\n buttonIconUrl?: string;\n childStyleLevel?: number;\n childStyleIconUrl?: string;\n enableChildStyleCustomClick?: boolean;\n disabled?: boolean;\n expandOnClickNode?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n level: 1,\n showCheckbox: false,\n iconClass: \"\",\n deptIconUrl: \"\",\n personIconUrl: \"\",\n buttonIconUrl: \"\",\n childStyleLevel: undefined,\n childStyleIconUrl: \"\",\n enableChildStyleCustomClick: false,\n disabled: false,\n expandOnClickNode: true,\n});\n\n// 从父组件注入的方法和状态\nconst treeStore = inject<any>(\"treeStore\");\nconst getNodeKey = inject<(node: TreeNode) => string | number>(\"getNodeKey\");\nconst getNodeLabel = inject<(node: TreeNode) => string>(\"getNodeLabel\");\nconst getNodeChildren = inject<(node: TreeNode) => TreeNode[]>(\"getNodeChildren\");\nconst hasChildren = inject<(node: TreeNode) => boolean>(\"hasChildren\");\nconst isEmployeeNode = inject<(node: TreeNode) => boolean>(\"isEmployeeNode\");\nconst getNodeIcon = inject<(node: TreeNode, rootNode?: TreeNode) => string>(\"getNodeIcon\");\nconst getNodeDepth = inject<(node: TreeNode, targetNode: TreeNode) => number>(\"getNodeDepth\");\nconst isChildStyleNode = inject<(node: TreeNode, rootNode: TreeNode) => boolean>(\"isChildStyleNode\");\nconst isNodeExpanded = inject<(node: TreeNode) => boolean>(\"isNodeExpanded\");\nconst isNodeChecked = inject<(node: TreeNode) => boolean>(\"isNodeChecked\");\nconst isNodeIndeterminate = inject<(node: TreeNode) => boolean>(\"isNodeIndeterminate\");\nconst isNodeCurrent = inject<(node: TreeNode) => boolean>(\"isNodeCurrent\");\nconst isNodeHighlighted = inject<(node: TreeNode) => boolean>(\"isNodeHighlighted\");\nconst handleExpandClick = inject<(node: TreeNode) => void>(\"handleExpandClick\");\nconst handleCheckClick = inject<(node: TreeNode) => void>(\"handleCheckClick\");\nconst handleNodeClick = inject<(data: TreeNode, node: any, nodeComponent: any, rootNode?: TreeNode) => void>(\"handleNodeClick\");\nconst handleNodeContextMenu = inject<(event: Event, data: TreeNode, node: any, nodeComponent: any) => void>(\"handleNodeContextMenu\");\n\n// 使用 computed 缓存节点状态,减少重复计算\nconst nodeKey = computed(() => getNodeKey(props.node));\nconst nodeLabel = computed(() => getNodeLabel(props.node));\nconst nodeIcon = computed(() => getNodeIcon(props.node, props.rootNode));\nconst nodeDepth = computed(() => getNodeDepth(props.rootNode, props.node));\nconst isExpanded = computed(() => isNodeExpanded(props.node));\nconst isChecked = computed(() => isNodeChecked(props.node));\nconst isIndeterminate = computed(() => isNodeIndeterminate(props.node));\nconst isCurrent = computed(() => isNodeCurrent(props.node));\nconst isHighlighted = computed(() => isNodeHighlighted(props.node));\nconst hasNodeChildren = computed(() => hasChildren(props.node));\nconst nodeChildren = computed(() => getNodeChildren(props.node));\nconst isChildStyle = computed(() => isChildStyleNode(props.node, props.rootNode));\nconst isEmployee = computed(() => isEmployeeNode(props.node));\n\n// 计算 paddingLeft,每级增加 16px (14px 图标 + 2px 间距)\nconst paddingLeft = computed(() => {\n if (props.level === 1) {\n return 8;\n }\n // 第一级是 8px,之后每级增加 16px (14px 图标宽度 + 2px 间距)\n return 8 + (props.level - 1) * 16;\n});\n</script>\n\n<style scoped>\n/* 树节点样式 */\n.ytree-node {\n position: relative;\n}\n\n.ytree-node__content {\n display: flex;\n align-items: center;\n height: 24px;\n padding: 0 6px;\n cursor: pointer;\n transition: background-color 0.2s ease, color 0.2s ease;\n border-radius: 4px;\n margin: 0.5px 0;\n}\n\n.ytree-node__content:hover:not(.ytree-node--disabled .ytree-node__content) {\n background-color: #f6f6f7;\n color: #303061;\n}\n\n.ytree-node--current > .ytree-node__content {\n background-color: #f0f0f0;\n font-weight: bold;\n}\n\n/* 高亮节点样式(仅文本变绿,无背景) */\n.ytree-node--highlight > .ytree-node__content .ytree-node__label {\n color: #10b981 !important;\n font-weight: 600;\n}\n\n.ytree-node--disabled .ytree-node__content {\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n.ytree-node__expand-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n min-width: 14px;\n flex-shrink: 0;\n margin-right: 2px;\n color: #6b7280;\n transition: transform 0.2s ease, color 0.2s ease;\n cursor: pointer;\n border-radius: 2px;\n}\n\n.ytree-node__expand-icon svg {\n width: 12px;\n height: 12px;\n flex-shrink: 0;\n}\n\n.ytree-node__expand-icon:hover {\n color: #374151;\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.ytree-node__expand-icon.is-expanded {\n transform: rotate(90deg);\n}\n\n.ytree-node__expand-icon--empty {\n width: 14px;\n min-width: 14px;\n height: 14px;\n flex-shrink: 0;\n margin-right: 2px;\n}\n\n.ytree-node__checkbox {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 10px;\n height: 10px;\n min-width: 10px;\n flex-shrink: 0;\n margin-right: 4px;\n border: 1px solid #d1d5db;\n border-radius: 2px;\n background: #ffffff;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.ytree-node__checkbox svg {\n width: 12px;\n height: 12px;\n flex-shrink: 0;\n}\n\n.ytree-node__checkbox.is-checked {\n background-color: #3f8682;\n color: #ffffff;\n}\n\n.ytree-node__checkbox.is-indeterminate {\n background-color: #3f8682;\n border-color: #3f8682;\n color: #ffffff;\n}\n\n.ytree-node__checkbox.is-disabled {\n background-color: #f9fafb;\n border-color: #e5e7eb;\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n.ytree-node__icon {\n margin-right: 4px;\n font-size: 12px;\n color: #6b7280;\n flex-shrink: 0;\n}\n\n.ytree-node__label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n line-height: 1.4;\n font-weight: 500;\n}\n\n/* 子样式节点特殊样式 - 通过配置的级别动态应用 */\n.ytree-node__content.is-child-style .ytree-node__label {\n font-weight: 500 !important;\n color: #636363 !important;\n font-size: 12px !important;\n}\n\n/* 员工节点颜色样式 */\n.ytree-node__label.is-employee {\n font-weight: 500;\n color: #777777;\n font-size: 12px;\n}\n\n/* 高亮覆盖(优先级更高,放在子样式规则之后) */\n.ytree-node.ytree-node--highlight > .ytree-node__content .ytree-node__label,\n.ytree-node.ytree-node--highlight > .ytree-node__content.is-child-style .ytree-node__label {\n color: #00a761 !important;\n font-weight: bold !important;\n}\n\n.ytree-node__custom-content {\n display: flex;\n align-items: center;\n margin-left: auto;\n flex-shrink: 0;\n}\n\n.ytree-node__avatar {\n width: 14px;\n height: 14px;\n min-width: 14px;\n flex-shrink: 0;\n margin-right: 4px;\n border-radius: 2px;\n object-fit: cover;\n}\n\n.ytree-node__label.is-current {\n font-weight: 500;\n}\n\n.ytree-node__children {\n position: relative;\n}\n\n/* 过渡动画 */\n.ytree-node-enter-active,\n.ytree-node-leave-active {\n transition: all 0.3s ease;\n overflow: hidden;\n}\n\n.ytree-node-enter-from,\n.ytree-node-leave-to {\n opacity: 0;\n max-height: 0;\n}\n\n.ytree-node-enter-to,\n.ytree-node-leave-from {\n opacity: 1;\n max-height: 1000px;\n}\n\n/* 暗色主题支持 */\n@media (prefers-color-scheme: dark) {\n .ytree-node__content {\n color: #e5eef7;\n }\n\n .ytree-node__content:hover:not(.ytree-node--disabled .ytree-node__content) {\n background-color: rgba(2, 6, 23, 0.4);\n color: #e5eef7;\n }\n\n .ytree-node--current .ytree-node__content {\n background-color: rgba(59, 130, 246, 0.2);\n color: #60a5fa;\n }\n\n .ytree-node--disabled .ytree-node__content {\n color: #9ca3af;\n }\n\n .ytree-node__expand-icon {\n color: #9ca3af;\n }\n\n .ytree-node__expand-icon:hover {\n color: #cbd5e1;\n background-color: rgba(148, 163, 184, 0.1);\n }\n\n .ytree-node__checkbox {\n background: rgba(2, 6, 23, 0.4);\n border-color: rgba(148, 163, 184, 0.3);\n }\n\n .ytree-node__checkbox:hover:not(.is-disabled) {\n border-color: #60a5fa;\n background-color: rgba(59, 130, 246, 0.1);\n }\n\n .ytree-node__icon {\n color: #9ca3af;\n }\n\n /* 子样式节点暗色主题样式 */\n .ytree-node__content.is-child-style .ytree-node__label {\n color: #9ca3af !important;\n }\n}\n</style>\n\n","<template>\n <div\n class=\"ytree\"\n :class=\"[`ytree--${size}`, { 'ytree--disabled': disabled }]\"\n >\n <div class=\"ytree__container\">\n <YTreeNode\n v-for=\"node in treeData\"\n :key=\"getNodeKey(node)\"\n :node=\"node\"\n :root-node=\"node\"\n :level=\"1\"\n :show-checkbox=\"showCheckbox\"\n :icon-class=\"iconClass\"\n :dept-icon-url=\"deptIconUrl\"\n :person-icon-url=\"personIconUrl\"\n :button-icon-url=\"buttonIconUrl\"\n :child-style-level=\"childStyleLevel\"\n :child-style-icon-url=\"childStyleIconUrl\"\n :enable-child-style-custom-click=\"enableChildStyleCustomClick\"\n :disabled=\"disabled\"\n :expand-on-click-node=\"expandOnClickNode\"\n >\n <template #node-content=\"slotProps\">\n <slot name=\"node-content\" v-bind=\"slotProps\" />\n </template>\n </YTreeNode>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, provide, watch, markRaw, shallowRef } from \"vue\";\nimport YTreeNode from './ytree-node.vue'\n\n// 节点图标地址(部门/人员)\nconst DEPT_ICON_URL =\n \"https://image.nhdropshipping.com/fit-in/500x500/filters:format(webp)/media/2025/10/17/1979094146203385856/32.png\";\nconst PERSON_ICON_URL =\n \"https://image.nhdropshipping.com/fit-in/500x500/filters:format(webp)/media/2025/10/17/1979095296159907840/32.png\";\n\nexport interface TreeNode {\n id?: string | number;\n label: string;\n children?: TreeNode[];\n disabled?: boolean;\n isLeaf?: boolean;\n expanded?: boolean;\n checked?: boolean;\n indeterminate?: boolean;\n data?: any;\n [key: string]: any;\n}\n\nexport interface TreeProps {\n data?: TreeNode[];\n emptyText?: string;\n nodeKey?: string;\n props?: {\n children?: string;\n label?: string;\n disabled?: string;\n isLeaf?: string;\n };\n renderAfterExpand?: boolean;\n defaultExpandAll?: boolean;\n defaultExpandedKeys?: (string | number)[];\n defaultCheckedKeys?: (string | number)[];\n defaultSelectedKeys?: (string | number)[];\n checkStrictly?: boolean;\n checkOnClickNode?: boolean;\n checkDescendants?: boolean;\n autoExpandParent?: boolean;\n defaultChecked?: boolean;\n filterNodeMethod?: (value: any, data: TreeNode, node: any) => boolean;\n lazy?: boolean;\n load?: (node: TreeNode, resolve: (data: TreeNode[]) => void) => void;\n renderContent?: (h: any, node: TreeNode, data: any, store: any) => any;\n highlightCurrent?: boolean;\n expandOnClickNode?: boolean;\n currentNodeKey?: string | number;\n accordion?: boolean;\n indent?: number;\n iconClass?: string;\n showCheckbox?: boolean;\n draggable?: boolean;\n allowDrag?: (node: TreeNode) => boolean;\n allowDrop?: (\n draggingNode: TreeNode,\n dropNode: TreeNode,\n type: \"prev\" | \"inner\" | \"next\"\n ) => boolean;\n size?: \"small\" | \"medium\" | \"large\";\n disabled?: boolean;\n deptIconUrl?: string;\n personIconUrl?: string;\n buttonIconUrl?: string;\n // 是否启用第四级节点特殊处理(已废弃)\n enableFourthLevelSpecialHandling?: boolean;\n // 从第几级开始不进行任何\"默认/自动展开\"的级别阈值(如传 4 表示第4级及其以下不自动展开)\n restrictAutoExpandFromLevel?: number | undefined;\n // 子样式节点配置:定义第几级节点为子样式节点及其图标\n childStyleLevel?: number | undefined;\n childStyleIconUrl?: string;\n // 是否启用子样式节点自定义点击事件(如果启用,子样式节点点击会触发 child-node-click 事件而不是 node-click)\n enableChildStyleCustomClick?: boolean;\n}\n\nconst props = withDefaults(defineProps<TreeProps>(), {\n data: () => [],\n emptyText: \"暂无数据\",\n nodeKey: \"id\",\n props: () => ({\n children: \"children\",\n label: \"label\",\n disabled: \"disabled\",\n isLeaf: \"isLeaf\",\n }),\n renderAfterExpand: true,\n defaultExpandAll: false,\n defaultExpandedKeys: () => [],\n defaultCheckedKeys: () => [],\n defaultSelectedKeys: () => [],\n checkStrictly: false,\n checkOnClickNode: false,\n checkDescendants: true,\n autoExpandParent: true,\n defaultChecked: false,\n lazy: false,\n highlightCurrent: false,\n expandOnClickNode: true,\n accordion: false,\n indent: 18,\n iconClass: \"\",\n showCheckbox: false,\n draggable: false,\n size: \"medium\",\n disabled: false,\n deptIconUrl: \"\",\n personIconUrl: \"\",\n buttonIconUrl: \"\",\n enableFourthLevelSpecialHandling: false,\n restrictAutoExpandFromLevel: undefined,\n childStyleLevel: undefined,\n childStyleIconUrl: \"\",\n enableChildStyleCustomClick: false,\n});\n\nconst emit = defineEmits<{\n \"node-click\": [data: TreeNode, node: any, nodeComponent: any];\n \"node-contextmenu\": [\n event: Event,\n data: TreeNode,\n node: any,\n nodeComponent: any\n ];\n \"check-change\": [data: TreeNode, checked: boolean, indeterminate: boolean];\n check: [data: TreeNode, checked: any, indeterminate: any];\n \"current-change\": [data: TreeNode, node: any];\n \"node-expand\": [data: TreeNode, node: any, nodeComponent: any];\n \"node-collapse\": [data: TreeNode, node: any, nodeComponent: any];\n \"node-drag-start\": [node: TreeNode, event: DragEvent];\n \"node-drag-enter\": [\n draggingNode: TreeNode,\n dropNode: TreeNode,\n event: DragEvent\n ];\n \"node-drag-leave\": [\n draggingNode: TreeNode,\n dropNode: TreeNode,\n event: DragEvent\n ];\n \"node-drag-over\": [\n draggingNode: TreeNode,\n dropNode: TreeNode,\n event: DragEvent\n ];\n \"node-drag-end\": [\n draggingNode: TreeNode,\n dropNode: TreeNode,\n event: DragEvent\n ];\n \"node-drop\": [\n draggingNode: TreeNode,\n dropNode: TreeNode,\n dropType: \"before\" | \"after\" | \"inner\",\n event: DragEvent\n ];\n \"checked-keys-change\": [keys: Array<string | number>];\n \"child-node-click\": [data: TreeNode, node: any, nodeComponent: any];\n}>();\n\n// 计算属性\nconst treeData = computed(() => {\n // 移除生产环境的 console.log 以提升性能\n // console.log(\"ytree 组件接收到的数据:\", props.data);\n return props.data || [];\n});\n// const nodeProps = computed(() => props.props || {});\n\n// 提供全局状态\nconst store = ref({\n currentNode: null as TreeNode | null,\n currentKey: null as string | number | null,\n checkedKeys: new Set<string | number>(),\n expandedKeys: new Set<string | number>(),\n selectedKeys: new Set<string | number>(),\n highlightedKeys: new Set<string | number>(),\n});\n\n// 响应式版本号,用于触发 checkedKeys 变化的响应式更新\n// 由于 Vue 3 无法追踪 Set 内部变化,我们需要这个版本号来触发更新\nconst checkedKeysVersion = ref(0);\n\n// 触发 checkedKeys 更新的辅助函数\nfunction triggerCheckedKeysUpdate() {\n checkedKeysVersion.value++;\n // 同时重新赋值 Set,确保 Vue 能够追踪到变化\n store.value.checkedKeys = new Set(store.value.checkedKeys);\n}\n\n// 节点状态缓存,用于优化性能\nconst nodeStateCache = new Map<string | number, { checked: boolean; indeterminate: boolean; timestamp: number }>();\nconst CACHE_DURATION = 100; // 缓存持续时间(毫秒)\n\n// 清除所有缓存\nfunction clearAllCache() {\n nodeStateCache.clear();\n}\n\n// 清除节点及其所有子节点的缓存\nfunction clearNodeCache(node: TreeNode) {\n const nodeKey = getNodeKey(node);\n nodeStateCache.delete(nodeKey);\n if (hasChildren(node)) {\n getNodeChildren(node).forEach(clearNodeCache);\n }\n}\n\n// 清除过期的缓存\nfunction clearExpiredCache() {\n const now = Date.now();\n for (const [key, value] of nodeStateCache.entries()) {\n if (now - value.timestamp > CACHE_DURATION) {\n nodeStateCache.delete(key);\n }\n }\n}\n\nprovide(\"treeStore\", store);\n\n// 提供方法给子组件使用\nprovide(\"getNodeKey\", getNodeKey);\nprovide(\"getNodeLabel\", getNodeLabel);\nprovide(\"getNodeChildren\", getNodeChildren);\nprovide(\"hasChildren\", hasChildren);\nprovide(\"isEmployeeNode\", isEmployeeNode);\nprovide(\"getNodeIcon\", getNodeIcon);\nprovide(\"getNodeDepth\", getNodeDepth);\nprovide(\"isChildStyleNode\", isChildStyleNode);\nprovide(\"isNodeExpanded\", isNodeExpanded);\nprovide(\"isNodeChecked\", isNodeChecked);\nprovide(\"isNodeIndeterminate\", isNodeIndeterminate);\nprovide(\"isNodeCurrent\", isNodeCurrent);\nprovide(\"isNodeHighlighted\", isNodeHighlighted);\nprovide(\"handleExpandClick\", handleExpandClick);\nprovide(\"handleCheckClick\", handleCheckClick);\nprovide(\"handleNodeClick\", handleNodeClick);\nprovide(\"handleNodeContextMenu\", handleNodeContextMenu);\n\n// 方法\nconst effectiveRestrictLevel = computed<number | undefined>(() => {\n // 仅以新属性为准(组件化配置)。传入有效正数才启用限制\n return props.restrictAutoExpandFromLevel && props.restrictAutoExpandFromLevel > 0\n ? props.restrictAutoExpandFromLevel\n : undefined;\n});\n\nfunction getNodeKey(node: TreeNode): string | number {\n return node[props.nodeKey] || node.id || Math.random();\n}\n\nfunction getNodeLabel(node: TreeNode): string {\n return (props.props?.label ? node[props.props.label] : undefined) || node.label || \"\";\n}\n\nfunction isEmployeeNode(node: any): boolean {\n return Boolean(node?.data?.isEmployee);\n}\n\nfunction getNodeIcon(node: any, rootNode?: TreeNode): string {\n const dept = props.deptIconUrl || DEPT_ICON_URL;\n const person = props.personIconUrl || PERSON_ICON_URL;\n const button = props.buttonIconUrl || \"\";\n const childStyleIcon = props.childStyleIconUrl || \"\";\n \n // 优先检查是否是子样式节点\n if (rootNode && childStyleIcon && isChildStyleNode(node, rootNode)) {\n return childStyleIcon;\n }\n \n // 兼容旧的按钮节点判断逻辑\n if (node?.data?.isButton && button) return button;\n \n return isEmployeeNode(node) ? person : dept;\n}\n\nfunction hasChildren(node: TreeNode): boolean {\n const children = (props.props?.children ? node[props.props.children] : undefined) || node.children;\n return children && children.length > 0;\n}\n\nfunction getNodeChildren(node: TreeNode): TreeNode[] {\n return (props.props?.children ? node[props.props.children] : undefined) || node.children || [];\n}\n\n// 计算节点在树中的深度\nfunction getNodeDepth(\n node: TreeNode,\n targetNode: TreeNode,\n currentDepth: number = 1\n): number {\n if (node === targetNode) {\n return currentDepth;\n }\n\n const children = getNodeChildren(node);\n for (const child of children) {\n const depth = getNodeDepth(child, targetNode, currentDepth + 1);\n if (depth > 0) {\n return depth;\n }\n }\n\n return 0;\n}\n\n// 判断节点是否是子样式节点\nfunction isChildStyleNode(node: TreeNode, rootNode: TreeNode): boolean {\n if (!props.childStyleLevel || props.childStyleLevel < 1) {\n return false;\n }\n const depth = getNodeDepth(rootNode, node);\n return depth === props.childStyleLevel;\n}\n\n// 检查节点是否为第四级节点(按钮权限)\n// function isFourthLevelNode(node: TreeNode): boolean {\n// return Boolean(node.data?.isButton);\n// }\n\nfunction isNodeExpanded(node: TreeNode): boolean {\n const nodeKey = getNodeKey(node);\n return store.value.expandedKeys.has(nodeKey);\n}\n\n// 优化的节点状态计算函数,使用缓存和批量计算\n// 注意:此函数需要访问 store.value.checkedKeys 以确保响应式追踪\nfunction calculateNodeState(node: TreeNode, visited: Set<string | number> = new Set()): { checked: boolean; indeterminate: boolean } {\n const nodeKey = getNodeKey(node);\n \n // 防止循环引用\n if (visited.has(nodeKey)) {\n return { checked: false, indeterminate: false };\n }\n visited.add(nodeKey);\n\n // 直接访问 store.value.checkedKeys 以确保响应式追踪\n // 这是关键:Vue 需要能够追踪到这个访问\n const checkedKeys = store.value.checkedKeys;\n const directlyChecked = checkedKeys.has(nodeKey);\n \n // 叶子节点直接返回(不使用缓存,确保响应式)\n if (!hasChildren(node)) {\n return { checked: directlyChecked, indeterminate: false };\n }\n\n const children = getNodeChildren(node);\n if (children.length === 0) {\n return { checked: directlyChecked, indeterminate: false };\n }\n\n // 批量计算所有子节点状态\n let checkedCount = 0;\n let indeterminateCount = 0;\n \n for (const child of children) {\n const childState = calculateNodeState(child, visited);\n if (childState.checked) {\n checkedCount++;\n } else if (childState.indeterminate) {\n indeterminateCount++;\n }\n }\n\n let checked: boolean;\n let indeterminate: boolean;\n\n // 根据子节点状态计算父节点状态\n const allChildrenChecked = checkedCount === children.length && indeterminateCount === 0;\n const someChildrenChecked = checkedCount > 0 || indeterminateCount > 0;\n\n if (directlyChecked) {\n // 如果父节点直接选中,但子节点状态不一致,需要根据子节点状态调整\n if (allChildrenChecked) {\n // 所有子节点都选中,父节点也选中\n checked = true;\n indeterminate = false;\n } else if (someChildrenChecked) {\n // 部分子节点选中,父节点半选\n checked = false;\n indeterminate = true;\n } else {\n // 没有子节点选中,但父节点直接选中,保持选中状态\n checked = true;\n indeterminate = false;\n }\n } else {\n // 如果父节点没有直接选中,完全根据子节点状态决定\n if (allChildrenChecked) {\n // 所有子节点都选中,父节点也应该显示为选中\n checked = true;\n indeterminate = false;\n } else if (someChildrenChecked) {\n // 部分子节点选中,父节点半选\n checked = false;\n indeterminate = true;\n } else {\n // 所有子节点都未选中,父节点也未选中\n checked = false;\n indeterminate = false;\n }\n }\n\n return { checked, indeterminate };\n}\n\n// 确保这些函数能够被 Vue 正确追踪\nfunction isNodeChecked(node: TreeNode): boolean {\n // 访问 checkedKeysVersion 以确保响应式追踪\n // 这样每次 checkedKeys 变化时,这个函数都会重新计算\n const _ = checkedKeysVersion.value;\n return calculateNodeState(node).checked;\n}\n\nfunction isNodeIndeterminate(node: TreeNode): boolean {\n // 访问 checkedKeysVersion 以确保响应式追踪\n // 这样每次 checkedKeys 变化时,这个函数都会重新计算\n const _ = checkedKeysVersion.value;\n return calculateNodeState(node).indeterminate;\n}\n\nfunction isNodeCurrent(node: TreeNode): boolean {\n const key = getNodeKey(node);\n return store.value.currentKey === key;\n}\n\nfunction isNodeHighlighted(node: TreeNode): boolean {\n const key = getNodeKey(node);\n return store.value.highlightedKeys.has(key);\n}\n\nfunction handleCheckClick(node: TreeNode) {\n // 如果组件被禁用,不允许勾选操作\n if (props.disabled) return;\n\n const nodeKey = getNodeKey(node);\n const isChecked = store.value.checkedKeys.has(nodeKey);\n const newCheckedState = !isChecked;\n\n // 保存当前的展开状态,避免被勾选操作影响\n const currentExpandedKeys = new Set(store.value.expandedKeys);\n\n // 清除所有缓存,确保状态重新计算\n clearAllCache();\n\n // Update current node\n if (newCheckedState) {\n store.value.checkedKeys.add(nodeKey);\n } else {\n store.value.checkedKeys.delete(nodeKey);\n }\n\n // Cascade to children - 选中功能保持正常,但展开逻辑特殊处理\n function cascadeChildren(children: TreeNode[], check: boolean) {\n children.forEach((child) => {\n const childKey = getNodeKey(child);\n if (check) {\n store.value.checkedKeys.add(childKey);\n } else {\n store.value.checkedKeys.delete(childKey);\n }\n\n // 递归处理所有子节点,确保选中功能正常\n if (hasChildren(child)) {\n cascadeChildren(getNodeChildren(child), check);\n }\n });\n }\n\n // 正常递归选中所有子节点\n cascadeChildren(getNodeChildren(node), newCheckedState);\n\n // 特殊处理:如果选中了包含第四级子节点的节点,不自动展开第四级节点\n if (newCheckedState) {\n preventAutoExpandFourthLevel(node);\n }\n\n // Update all parent nodes recursively from bottom to top\n updateAllParentNodes();\n\n // 恢复展开状态,确保勾选操作不影响节点的展开收缩\n store.value.expandedKeys = currentExpandedKeys;\n\n // 再次清除所有缓存,确保 UI 更新\n clearAllCache();\n\n // Emit change\n emit(\"check-change\", node, newCheckedState, false);\n emit(\"check\", node, newCheckedState, false);\n emit(\"checked-keys-change\", Array.from(store.value.checkedKeys));\n}\n\n// 防止自动展开第四级节点的函数\nfunction preventAutoExpandFourthLevel(_node: TreeNode) {\n // 移除生产环境的 console.log 以提升性能\n // if (effectiveRestrictLevel.value) {\n // console.log(\n // `已启用从第${effectiveRestrictLevel.value}级开始不默认展开的限制(不主动收起已展开节点)`\n // );\n // }\n}\n\n// 重写 handleExpandClick 函数,确保第四级节点只能手动展开\nfunction handleExpandClick(node: TreeNode) {\n const nodeKey = getNodeKey(node);\n const isExpanded = store.value.expandedKeys.has(nodeKey);\n\n if (isExpanded) {\n // 收起节点\n store.value.expandedKeys.delete(nodeKey);\n emit(\"node-collapse\", node, node, null);\n } else {\n // 展开节点 - 第四级节点只能手动展开\n store.value.expandedKeys.add(nodeKey);\n emit(\"node-expand\", node, node, null);\n }\n}\n\n// 优化的父节点更新函数,只更新必要的父节点\nfunction updateAllParentNodes() {\n // 使用 Map 存储节点到父节点的映射,避免重复遍历\n const parentMap = new Map<string | number, TreeNode>();\n const allNodes: TreeNode[] = [];\n const nodeKeyMap = new Map<string | number, TreeNode>();\n\n function collectAllNodes(nodes: TreeNode[], parent?: TreeNode) {\n nodes.forEach((node) => {\n const nodeKey = getNodeKey(node);\n allNodes.push(node);\n nodeKeyMap.set(nodeKey, node);\n if (parent) {\n parentMap.set(nodeKey, parent);\n }\n if (hasChildren(node)) {\n collectAllNodes(getNodeChildren(node), node);\n }\n });\n }\n\n collectAllNodes(treeData.value);\n\n // 从叶子节点开始,向上更新父节点状态(只更新有子节点的节点)\n function updateNodeParents(node: TreeNode) {\n if (!hasChildren(node)) return;\n \n const children = getNodeChildren(node);\n const nodeKey = getNodeKey(node);\n\n // 批量计算子节点状态(每次调用使用新的 visited Set,避免循环引用)\n let checkedCount = 0;\n let indeterminateCount = 0;\n \n for (const child of children) {\n const childState = calculateNodeState(child);\n if (childState.checked) {\n checkedCount++;\n } else if (childState.indeterminate) {\n indeterminateCount++;\n }\n }\n\n // 根据子节点状态更新父节点\n // 如果所有子节点都选中,父节点也应该选中(添加到 checkedKeys)\n if (checkedCount === children.length && indeterminateCount === 0) {\n store.value.checkedKeys.add(nodeKey);\n } \n // 如果有部分子节点选中或半选,父节点应该半选(从 checkedKeys 中移除,让 indeterminate 生效)\n else if (checkedCount > 0 || indeterminateCount > 0) {\n // 部分选中状态:从 checkedKeys 中移除,让 calculateNodeState 计算 indeterminate\n store.value.checkedKeys.delete(nodeKey);\n } \n // 如果所有子节点都未选中,父节点也应该未选中(从 checkedKeys 中移除)\n else {\n store.value.checkedKeys.delete(nodeKey);\n }\n }\n\n // 从叶子节点开始更新(倒序遍历)\n for (let i = allNodes.length - 1; i >= 0; i--) {\n updateNodeParents(allNodes[i]);\n }\n \n // 清除所有缓存,确保 UI 更新\n clearAllCache();\n}\n\nfunction handleNodeClick(data: TreeNode, node: any, nodeComponent: any, rootNode?: TreeNode) {\n if (props.disabled) return;\n \n // 判断是否是子样式节点\n const isChildStyle = rootNode ? isChildStyleNode(data, rootNode) : false;\n \n // 如果启用了子样式节点自定义点击事件且是子样式节点,触发 child-node-click 事件\n if (props.enableChildStyleCustomClick && isChildStyle) {\n emit(\"child-node-click\", data, node, nodeComponent);\n return;\n }\n // 需求:当 expandOnClickNode=true 且为父节点时,优先展开/收起且不触发事件\n if (props.expandOnClickNode && hasChildren(data)) {\n handleExpandClick(data);\n return;\n }\n\n store.value.currentNode = data;\n store.value.currentKey = getNodeKey(data);\n\n // 权限树可用性:若展示复选框,点击整行也进行勾选切换\n if (props.showCheckbox) {\n handleCheckClick(data);\n }\n\n // 有无监听器都 emit,Vue 会按需处理\n emit(\"node-click\", data, node, nodeComponent);\n}\n\nfunction handleNodeContextMenu(\n event: Event,\n data: TreeNode,\n node: any,\n nodeComponent: any\n) {\n if (props.disabled) return;\n emit(\"node-contextmenu\", event, data, node, nodeComponent);\n}\n\n// 初始化默认状态\nwatch(\n () => props.defaultExpandedKeys,\n (keys) => {\n if (keys) {\n const restrictLevel = effectiveRestrictLevel.value;\n if (restrictLevel) {\n // 允许外部传入默认展开 keys,但需过滤:从 restrictLevel 起不自动展开\n // 同时保留“已手动展开”的受限级别节点\n\n // 计算节点深度工具\n function getDepthByKey(targetKey: string | number, nodes: TreeNode[], level = 1): number {\n for (const n of nodes) {\n if (getNodeKey(n) === targetKey) return level;\n if (hasChildren(n)) {\n const d = getDepthByKey(targetKey, getNodeChildren(n), level + 1);\n if (d > 0) return d;\n }\n }\n return 0;\n }\n\n // 仅保留小于限制级别的默认展开 keys\n const filtered = (keys || []).filter((k) => {\n const depth = getDepthByKey(k as any, treeData.value, 1);\n return depth > 0 && depth < restrictLevel;\n });\n const newExpandedKeys = new Set(filtered);\n\n // 自动补齐:将第 1 至 restrictLevel-1 级的所有可展开节点加入(确保 3/4 层也会展开)\n function collectKeysToDepth(nodes: TreeNode[], level: number, maxDepth: number) {\n nodes.forEach((node) => {\n if (level < maxDepth && hasChildren(node)) {\n newExpandedKeys.add(getNodeKey(node));\n collectKeysToDepth(getNodeChildren(node), level + 1, maxDepth);\n } else if (level < maxDepth && !hasChildren(node)) {\n // 叶子节点无需加入,但继续一致的遍历结构\n } else if (level >= maxDepth) {\n // 达到限制深度,停止自动补齐\n }\n });\n }\n collectKeysToDepth(treeData.value, 1, restrictLevel);\n\n // 保留当前“已展开”的受限级别节点(通常由用户手动展开)\n store.value.expandedKeys.forEach((key) => {\n const depth = getDepthByKey(key, treeData.value, 1);\n if (depth >= restrictLevel) {\n newExpandedKeys.add(key);\n }\n });\n\n store.value.expandedKeys = newExpandedKeys;\n } else {\n store.value.expandedKeys = new Set(keys);\n }\n }\n },\n { immediate: true }\n);\n\n// 处理 defaultExpandAll\nfunction expandAllNodes() {\n if (props.defaultExpandAll) {\n // 收集所有有子节点的节点ID\n const allExpandableKeys = new Set<string | number>();\n\n const restrictLevel = effectiveRestrictLevel.value;\n\n function collectExpandableKeys(nodes: TreeNode[], level: number = 1) {\n nodes.forEach((node) => {\n if (!hasChildren(node)) return;\n\n const children = getNodeChildren(node);\n\n if (restrictLevel) {\n // 达到或超过限制级别,则不再自动展开\n if (level >= restrictLevel) return;\n\n // 若下一层就是限制级别,则当前父节点也不自动展开,但递归子节点以便后续逻辑使用\n const hasChildAtRestrictLevel = level + 1 === restrictLevel;\n if (!hasChildAtRestrictLevel) {\n allExpandableKeys.add(getNodeKey(node));\n }\n collectExpandableKeys(children, level + 1);\n } else {\n // 普通模式:所有有子节点的层级默认展开\n allExpandableKeys.add(getNodeKey(node));\n collectExpandableKeys(children, level + 1);\n }\n });\n }\n\n collectExpandableKeys(treeData.value, 1);\n\n store.value.expandedKeys = allExpandableKeys;\n }\n}\n\n// 展开包含选中权限的节点路径\nfunction expandNodesWithCheckedPermissions() {\n if (props.defaultCheckedKeys && props.defaultCheckedKeys.length > 0) {\n const checkedKeys = new Set(props.defaultCheckedKeys);\n const expandableKeys = new Set<string | number>();\n\n function findPathsToCheckedNodes(\n nodes: TreeNode[],\n parentPath: (string | number)[] = []\n ) {\n nodes.forEach((node) => {\n const nodeKey = getNodeKey(node);\n const currentPath = [...parentPath, nodeKey];\n\n // 如果当前节点被选中,展开到它的所有父节点\n if (checkedKeys.has(nodeKey)) {\n parentPath.forEach((key) => expandableKeys.add(key));\n }\n\n // 递归处理子节点\n if (hasChildren(node)) {\n findPathsToCheckedNodes(getNodeChildren(node), currentPath);\n }\n });\n }\n\n findPathsToCheckedNodes(treeData.value);\n\n const restrictLevel = effectiveRestrictLevel.value;\n if (restrictLevel) {\n // 启用限制:保持当前展开状态,不进行自动展开\n // 移除生产环境的 console.log 以提升性能\n // console.log(\n // `已启用从第${restrictLevel}级开始不默认展开:保持当前展开状态不变`\n // );\n return;\n }\n // 普通模式:自动展开到包含选中权限的路径\n store.value.expandedKeys = expandableKeys;\n }\n}\n\n// 根据key查找节点\n// function findNodeByKey(key: string | number): TreeNode | null {\n// function searchNodes(nodes: TreeNode[]): TreeNode | null {\n// for (const node of nodes) {\n// if (getNodeKey(node) === key) {\n// return node;\n// }\n// if (hasChildren(node)) {\n// const found = searchNodes(getNodeChildren(node));\n// if (found) return found;\n// }\n// }\n// return null;\n// }\n// return searchNodes(treeData.value);\n// }\n\n// 使用防抖优化 watch,避免频繁触发\nlet expandAllNodesTimer: ReturnType<typeof setTimeout> | null = null;\nconst debouncedExpandAllNodes = () => {\n if (expandAllNodesTimer) clearTimeout(expandAllNodesTimer);\n expandAllNodesTimer = setTimeout(() => {\n expandAllNodes();\n expandAllNodesTimer = null;\n }, 50);\n};\n\nwatch(() => props.defaultExpandAll, expandAllNodes, { immediate: true });\n\n// 当树数据变化时,如果设置了 defaultExpandAll,重新展开所有节点(使用防抖)\nwatch(() => treeData.value, debouncedExpandAllNodes, { deep: true });\n\nwatch(\n () => props.defaultCheckedKeys,\n (keys) => {\n if (keys) {\n store.value.checkedKeys = new Set(keys);\n\n // 在权限树模式下,完全跳过自动展开逻辑,保持当前展开状态不变\n if (!props.enableFourthLevelSpecialHandling) {\n // 当选中权限变化时,展开包含这些权限的节点路径\n expandNodesWithCheckedPermissions();\n } else {\n // 移除生产环境的 console.log 以提升性能\n // console.log(\"权限树模式:跳过自动展开逻辑,保持当前展开状态\");\n }\n } else {\n store.value.checkedKeys.clear();\n }\n },\n { immediate: true }\n);\n\n// 根据传入的一组 id,展开到对应节点并高亮这些节点\nfunction highlightAndExpandByIds(ids: Array<string | number>) {\n try {\n const targetIds = Array.isArray(ids) ? ids : [];\n if (targetIds.length === 0) return;\n\n // 工具:查找到目标 key 的路径(返回 key 数组路径)\n function findPathToKey(\n nodes: TreeNode[],\n targetKey: string | number,\n path: (string | number)[] = []\n ): (string | number)[] | null {\n for (const n of nodes) {\n const nk = getNodeKey(n);\n const newPath = [...path, nk];\n if (nk === targetKey) return newPath;\n if (hasChildren(n)) {\n const p = findPathToKey(getNodeChildren(n), targetKey, newPath);\n if (p) return p;\n }\n }\n return null;\n }\n\n // 清除旧的高亮\n store.value.highlightedKeys.clear();\n\n // 累积需要展开的父级 key\n const keysToExpand = new Set<string | number>(store.value.expandedKeys);\n\n targetIds.forEach((targetId) => {\n const path = findPathToKey(treeData.value, targetId);\n if (path && path.length > 0) {\n // 父级全部加入展开集合(除最后一个自身)\n path.slice(0, -1).forEach((k) => keysToExpand.add(k));\n // 目标节点加入高亮集合\n store.value.highlightedKeys.add(path[path.length - 1]);\n }\n });\n\n // 应用展开\n store.value.expandedKeys = keysToExpand;\n } catch (e) {\n // 移除生产环境的 console.warn 以提升性能,仅在开发环境输出\n if (process.env.NODE_ENV === 'development') {\n console.warn('highlightAndExpandByIds 执行失败', e);\n }\n }\n}\n\n// 清除高亮\nfunction clearHighlights() {\n store.value.highlightedKeys.clear();\n}\n\n// 清除当前选中节点\nfunction clearCurrentNode() {\n store.value.currentNode = null;\n store.value.currentKey = null;\n}\n\ndefineExpose({ highlightAndExpandByIds, clearHighlights, clearCurrentNode });\n\nwatch(\n () => props.defaultSelectedKeys,\n (keys) => {\n if (keys) {\n store.value.selectedKeys = new Set(keys);\n }\n },\n { immediate: true }\n);\n</script>\n\n<style scoped>\n.ytree {\n position: relative;\n font-size: 14px;\n line-height: 1.5;\n color: #0b1a29;\n}\n\n.ytree--disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.ytree__container {\n position: relative;\n overflow: auto;\n}\n\n/* 尺寸变体 */\n.ytree--small {\n font-size: 12px;\n}\n\n.ytree--small .ytree__container {\n padding: 2px 0;\n}\n\n.ytree--medium {\n font-size: 13px;\n}\n\n.ytree--medium .ytree__container {\n padding: 4px 0;\n}\n\n.ytree--large {\n font-size: 14px;\n}\n\n.ytree--large .ytree__container {\n padding: 6px 0;\n}\n\n/* 树节点样式 */\n.ytree-node {\n position: relative;\n}\n\n.ytree-node__content {\n display: flex;\n align-items: center;\n height: 24px;\n padding: 0 6px;\n cursor: pointer;\n transition: background-color 0.2s ease, color 0.2s ease;\n border-radius: 4px;\n margin: 0.5px 0;\n}\n\n.ytree-node__content:hover:not(.ytree-node--disabled .ytree-node__content) {\n background-color: #f6f6f7;\n color: #303061;\n}\n\n.ytree-node--current > .ytree-node__content {\n background-color: #f0f0f0;\n font-weight: bold;\n}\n\n/* 高亮节点样式(仅文本变绿,无背景) */\n.ytree-node--highlight > .ytree-node__content .ytree-node__label {\n color: #10b981 !important;\n font-weight: 600;\n}\n\n.ytree-node--disabled .ytree-node__content {\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n.ytree-node__expand-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n margin-right: 2px;\n color: #6b7280;\n transition: transform 0.2s ease, color 0.2s ease;\n cursor: pointer;\n border-radius: 2px;\n}\n\n.ytree-node__expand-icon:hover {\n color: #374151;\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.ytree-node__expand-icon.is-expanded {\n transform: rotate(90deg);\n}\n\n.ytree-node__expand-icon--empty {\n width: 14px;\n height: 14px;\n margin-right: 4px;\n}\n\n.ytree-node__checkbox {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 10px;\n height: 10px;\n margin-right: 4px;\n border: 1px solid #d1d5db;\n border-radius: 2px;\n background: #ffffff;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n/* .ytree-node__checkbox:hover:not(.is-disabled) {\n border-color: #60a5fa;\n background-color: #f0f9ff;\n} */\n\n.ytree-node__checkbox.is-checked {\n background-color: #3f8682;\n color: #ffffff;\n}\n\n.ytree-node__checkbox.is-indeterminate {\n background-color: #3f8682;\n border-color: #3f8682;\n color: #ffffff;\n}\n\n.ytree-node__checkbox.is-disabled {\n background-color: #f9fafb;\n border-color: #e5e7eb;\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n.ytree-node__icon {\n margin-right: 4px;\n font-size: 12px;\n color: #6b7280;\n}\n\n.ytree-node__label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n line-height: 1.4;\n font-weight:500;\n}\n\n/* 子样式节点特殊样式 - 通过配置的级别动态应用 */\n.ytree-node__content.is-child-style .ytree-node__label {\n font-weight: 500 !important;\n color: #636363 !important;\n font-size: 12px !important;\n}\n\n/* 兼容旧的第四级节点样式(已废弃,保留以兼容旧代码) */\n.ytree--permission-tree .ytree-node__content[data-level=\"4\"] .ytree-node__label,\n.ytree--permission-tree .ytree-node[data-level=\"4\"] .ytree-node__label,\n.permission-tree .ytree-node__content[data-level=\"4\"] .ytree-node__label,\n.permission-tree .ytree-node[data-level=\"4\"] .ytree-node__label {\n font-weight: 500 !important;\n color: #636363 !important;\n font-size: 12px !important;\n}\n\n/* 员工节点颜色样式 */\n.ytree-node__label.is-employee {\n font-weight: 500;\n color: #777777;\n font-size: 12px;\n}\n\n/* 高亮覆盖(优先级更高,放在子样式规则之后) */\n.ytree-node.ytree-node--highlight > .ytree-node__content .ytree-node__label,\n.ytree-node.ytree-node--highlight > .ytree-node__content.is-child-style .ytree-node__label {\n color: #00a761 !important;\n font-weight: bold !important;\n}\n\n.ytree-node__custom-content {\n display: flex;\n align-items: center;\n margin-left: auto;\n flex-shrink: 0;\n}\n\n.ytree-node__avatar {\n width: 14px;\n height: 14px;\n margin-right: 4px;\n border-radius: 2px;\n object-fit: cover;\n}\n\n.ytree-node__label.is-current {\n font-weight: 500;\n}\n\n/* 暗色主题支持 */\n@media (prefers-color-scheme: dark) {\n .ytree {\n color: #e5eef7;\n }\n\n .ytree-node__content {\n color: #e5eef7;\n }\n\n .ytree-node__content:hover:not(.ytree-node--disabled .ytree-node__content) {\n background-color: rgba(2, 6, 23, 0.4);\n color: #e5eef7;\n }\n\n .ytree-node--current .ytree-node__content {\n background-color: rgba(59, 130, 246, 0.2);\n color: #60a5fa;\n }\n\n .ytree-node--disabled .ytree-node__content {\n color: #9ca3af;\n }\n\n .ytree-node__expand-icon {\n color: #9ca3af;\n }\n\n .ytree-node__expand-icon:hover {\n color: #cbd5e1;\n background-color: rgba(148, 163, 184, 0.1);\n }\n\n .ytree-node__checkbox {\n background: rgba(2, 6, 23, 0.4);\n border-color: rgba(148, 163, 184, 0.3);\n }\n\n .ytree-node__checkbox:hover:not(.is-disabled) {\n border-color: #60a5fa;\n background-color: rgba(59, 130, 246, 0.1);\n }\n\n .ytree-node__icon {\n color: #9ca3af;\n }\n\n /* 子样式节点暗色主题样式 */\n .ytree-node__content.is-child-style .ytree-node__label {\n color: #9ca3af !important;\n }\n\n /* 兼容旧的第四级节点暗色主题样式(已废弃,保留以兼容旧代码) */\n .ytree--permission-tree\n .ytree-node__content[data-level=\"4\"]\n .ytree-node__label,\n .ytree--permission-tree .ytree-node[data-level=\"4\"] .ytree-node__label,\n .permission-tree .ytree-node__content[data-level=\"4\"] .ytree-node__label,\n .permission-tree .ytree-node[data-level=\"4\"] .ytree-node__label {\n color: #9ca3af !important;\n }\n}\n</style>\n","<template>\n <div class=\"query-encapsulation\">\n <div class=\"query-encapsulation__container\">\n <div class=\"query-encapsulation__content\">\n <!-- 查询字段和操作按钮 -->\n <div class=\"query-encapsulation__fields\">\n <!-- 所有查询字段(带过渡动画,且不影响原有布局) -->\n <transition-group name=\"qf\" tag=\"div\" class=\"query-encapsulation__fields-group\">\n <div\n v-for=\"field in displayedFields\"\n :key=\"field.key\"\n class=\"query-encapsulation__field-item\"\n >\n <!-- 优先使用插槽自定义字段 -->\n <slot \n :name=\"`field-${field.key}`\" \n :field=\"field\" \n :value=\"searchForm[field.key]\"\n :update-value=\"(val: any) => updateFieldValue(field.key, val)\"\n >\n <!-- 默认渲染 -->\n <div class=\"query-encapsulation__field-wrapper\">\n <label v-if=\"Iflabel || field.type === 'switch'\" class=\"query-encapsulation__field-label\">{{ field.label }}</label>\n <component\n :is=\"getFieldComponent(field.type)\"\n v-model=\"searchForm[field.key]\"\n :placeholder=\"field.placeholder || `请输入${field.label}`\"\n :options=\"field.options\"\n :clearable=\"field.clearable !== false\"\n :size=\"field.size || 'small'\"\n :width=\"field.width || '180px'\"\n :format=\"field.format || 'timestamp'\"\n :include-time=\"field.includeTime || false\"\n :filterable=\"field.filterable === true\"\n :multiple=\"field.multiple === true\"\n :true-value=\"field.trueValue\"\n :false-value=\"field.falseValue\"\n :active-text=\"field.activeText\"\n :inactive-text=\"field.inactiveText\"\n :show-text=\"field.showText\"\n :active-color=\"field.activeColor || (field.type === 'switch' ? '#1B2433' : undefined)\"\n :inactive-color=\"field.inactiveColor\"\n v-on=\"getFieldListeners(field)\"\n @input=\"field.type !== 'switch' ? handleFieldChange(field) : undefined\"\n @change=\"field.type === 'switch' ? handleSwitchChange(field, $event) : handleFieldChange(field)\"\n />\n </div>\n </slot>\n </div>\n </transition-group>\n\n <!-- 展开/收起按钮 -->\n <div class=\"query-encapsulation__toggle\" v-if=\"hasHiddenFields\">\n <YButton variant=\"secondary\" size=\"small\" @click=\"toggleExpanded\">\n {{ isExpanded ? \"收起\" : \"展开\" }}\n <span\n class=\"query-encapsulation__toggle-icon\"\n :class=\"{ 'is-expanded': isExpanded }\"\n >▼</span\n >\n </YButton>\n </div>\n\n <!-- 操作按钮 -->\n <div class=\"query-encapsulation__actions\">\n <div class=\"query-encapsulation__actions-group\">\n <YButton\n variant=\"primary\"\n size=\"small\"\n @click=\"handleSearch\"\n :loading=\"loading\"\n >\n 搜索\n </YButton>\n <YButton\n variant=\"secondary\"\n size=\"small\"\n @click=\"handleReset\"\n :loading=\"loading\"\n >\n 重置\n </YButton>\n <slot name=\"extra-actions\"></slot>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {\n ref,\n reactive,\n computed,\n watch,\n onMounted,\n onBeforeUnmount,\n nextTick,\n} from \"vue\";\nimport YInput from \"./yinput.vue\";\nimport YSelect from \"./yselect.vue\";\nimport YButton from \"./ybutton.vue\";\nimport YTime from \"./ytime.vue\";\nimport YSwitch from \"./yswitch.vue\";\nimport type { SelectOption } from \"./yselect.vue\";\n\nexport interface QueryField {\n key: string;\n label: string;\n type: \"input\" | \"select\" | \"date\" | \"daterange\" | \"switch\";\n placeholder?: string;\n options?: SelectOption[];\n clearable?: boolean;\n size?: \"mini\" | \"small\" | \"medium\" | \"large\";\n width?: string;\n required?: boolean;\n hidden?: boolean; // 是否默认隐藏\n format?: \"timestamp\" | \"string\" | \"date\"; // 时间格式\n includeTime?: boolean; // 是否包含时间\n startKey?: string; // 开始时间的 key\n endKey?: string; // 结束时间的 key\n filterable?: boolean; // 可输入搜索(仅 select 支持)\n multiple?: boolean; // 是否多选(仅 select 支持)\n // switch 相关配置\n trueValue?: any; // switch 开启时的值\n falseValue?: any; // switch 关闭时的值\n activeText?: string; // switch 开启时的文本\n inactiveText?: string; // switch 关闭时的文本\n showText?: boolean; // switch 是否显示文本\n activeColor?: string; // switch 开启时的颜色\n inactiveColor?: string; // switch 关闭时的颜色\n onSwitchChange?: (value: any, field: QueryField) => void; // switch 切换时的自定义处理函数\n}\n\nexport interface QueryEncapsulationProps {\n Iflabel?: boolean;\n fields: QueryField[];\n maxVisibleFields?: number;\n loading?: boolean;\n modelValue?: Record<string, any>;\n}\n\nconst props = withDefaults(defineProps<QueryEncapsulationProps>(), {\n Iflabel: true,\n maxVisibleFields: 5,\n loading: false,\n modelValue: () => ({}),\n});\n\nconst emit = defineEmits<{\n \"update:modelValue\": [value: Record<string, any>];\n search: [payload: { data: Record<string, any>; raw: Record<string, any> }];\n reset: [];\n \"field-change\": [field: QueryField, value: any];\n}>();\n\n// 响应式数据\nconst isExpanded = ref(false);\nconst searchForm = reactive<Record<string, any>>({});\nconst autoTriggerTypes: QueryField[\"type\"][] = [\"select\", \"date\", \"daterange\", \"switch\"];\nlet autoSearchTimer: ReturnType<typeof setTimeout> | undefined;\n\n// 计算属性\nconst visibleFields = computed(() => {\n return props.fields.filter((field) => !field.hidden);\n});\n\n// 展示的字段(受展开/收起控制)\nconst displayedFields = computed(() => {\n if (isExpanded.value) return visibleFields.value;\n return visibleFields.value.slice(0, props.maxVisibleFields);\n});\n\n// const hiddenFields = computed(() => {\n// return visibleFields.value.slice(props.maxVisibleFields);\n// });\n\nconst hasHiddenFields = computed(() => {\n return visibleFields.value.length > props.maxVisibleFields;\n});\n\n// 方法\nfunction getFieldComponent(type: string) {\n switch (type) {\n case \"select\":\n return YSelect;\n case \"date\":\n case \"daterange\":\n return YTime;\n case \"switch\":\n return YSwitch;\n case \"input\":\n default:\n return YInput;\n }\n}\n\nfunction updateFieldValue(key: string, value: any) {\n searchForm[key] = value;\n const field = props.fields.find((f) => f.key === key);\n if (field) {\n handleFieldChange(field);\n }\n}\n\nfunction handleFieldChange(field: QueryField) {\n emit(\"field-change\", field, searchForm[field.key]);\n emit(\"update:modelValue\", { ...searchForm });\n if (autoTriggerTypes.includes(field.type)) {\n scheduleAutoSearch();\n }\n}\n\nfunction handleSwitchChange(field: QueryField, value: any) {\n // 如果配置了自定义处理函数,则调用它\n if (field.onSwitchChange && typeof field.onSwitchChange === 'function') {\n field.onSwitchChange(value, field);\n }\n // 仍然触发默认的字段变化处理(会自动触发搜索,因为 switch 已添加到 autoTriggerTypes)\n handleFieldChange(field);\n}\n\nfunction handleSearch() {\n // 过滤空值参数\n const searchParams = filterEmptyParams(searchForm);\n\n // 格式化参数(处理日期范围等特殊字段)\n const formattedParams = formatSearchParams(searchParams);\n\n const rawParams = { ...searchForm };\n\n // 将参数包裹在data对象中\n emit(\"search\", { data: formattedParams, raw: rawParams });\n}\n\nfunction handleReset() {\n // 重置所有字段\n Object.keys(searchForm).forEach((key) => {\n const field = props.fields.find((f) => f.key === key);\n if (field?.type === \"daterange\") {\n searchForm[key] = { startDate: null, endDate: null };\n } else if (field?.type === \"date\") {\n searchForm[key] = null;\n } else if (field?.type === \"switch\") {\n // switch 类型重置为 falseValue 或 false\n searchForm[key] = field.falseValue !== undefined ? field.falseValue : false;\n } else if (field?.type === \"select\" && field.multiple) {\n // 多选 select 类型重置为空数组\n searchForm[key] = [];\n } else {\n searchForm[key] = \"\";\n }\n });\n emit(\"reset\");\n emit(\"update:modelValue\", { ...searchForm });\n}\n\nfunction toggleExpanded() {\n isExpanded.value = !isExpanded.value;\n}\n\nfunction getFieldListeners(field: QueryField) {\n // 只有 input 类型需要特殊的事件监听\n if (field.type !== \"input\") {\n return {};\n }\n return {\n enter: () => handleInputQuickSearch(),\n paste: () => handleInputQuickSearch(),\n };\n}\n\nasync function handleInputQuickSearch() {\n await nextTick();\n handleSearch();\n}\n\nfunction scheduleAutoSearch() {\n if (autoSearchTimer) {\n clearTimeout(autoSearchTimer);\n }\n autoSearchTimer = setTimeout(() => {\n autoSearchTimer = undefined;\n nextTick().then(() => handleSearch());\n }, 0);\n}\n\n// 过滤空值参数\nfunction filterEmptyParams(params: Record<string, any>) {\n const filtered: Record<string, any> = {};\n\n Object.keys(params).forEach((key) => {\n const field = props.fields.find((f) => f.key === key);\n const rawValue = params[key];\n const value =\n typeof rawValue === \"string\" ? rawValue.trim() : rawValue;\n\n // 处理数组类型(多选字段)\n if (Array.isArray(value)) {\n if (value.length > 0) {\n filtered[key] = value;\n }\n return;\n }\n\n if (value === null || value === undefined || value === \"\") {\n return;\n }\n\n if (\n typeof value === \"object\" &&\n value.startDate &&\n value.endDate\n ) {\n if (value.startDate && value.endDate) {\n filtered[key] = value;\n }\n return;\n }\n\n if (field && (field.type === \"date\" || field.type === \"daterange\")) {\n if (value !== 0) {\n filtered[key] = value;\n }\n return;\n }\n\n filtered[key] = value;\n });\n\n return filtered;\n}\n\n// 格式化搜索参数\nfunction formatSearchParams(params: Record<string, any>) {\n const formatted: Record<string, any> = {};\n\n Object.keys(params).forEach((key) => {\n const value = params[key];\n const field = props.fields.find((f) => f.key === key);\n\n if (field) {\n // 根据字段类型格式化参数\n if (field.type === \"daterange\" && typeof value === \"object\") {\n // 日期范围字段:使用自定义的 key 或默认 key\n const startKey = field.startKey || `${key}Start`;\n const endKey = field.endKey || `${key}End`;\n\n // 只有当开始和结束日期都存在且不为0时才添加\n if (value.startDate && value.endDate && value.startDate !== 0 && value.endDate !== 0) {\n if (field.format === \"timestamp\") {\n formatted[startKey] = new Date(value.startDate).getTime();\n formatted[endKey] = new Date(value.endDate).getTime();\n } else {\n formatted[startKey] = value.startDate;\n formatted[endKey] = value.endDate;\n }\n }\n } else if (field.type === \"date\" && value && value !== 0) {\n // 单个日期字段\n if (field.format === \"timestamp\") {\n formatted[key] = new Date(value).getTime();\n } else {\n formatted[key] = value;\n }\n } else {\n // 普通字段直接传递\n formatted[key] = value;\n }\n } else {\n // 没有找到字段定义,直接传递\n formatted[key] = value;\n }\n });\n\n return formatted;\n}\n\n// 初始化表单数据\nfunction initFormData() {\n props.fields.forEach((field) => {\n if (searchForm[field.key] === undefined) {\n // 根据字段类型设置默认值\n if (field.type === \"daterange\") {\n searchForm[field.key] = props.modelValue?.[field.key] || {\n startDate: null,\n endDate: null,\n };\n } else if (field.type === \"date\") {\n searchForm[field.key] = props.modelValue?.[field.key] || null;\n } else if (field.type === \"switch\") {\n // switch 类型使用 falseValue 或 false 作为默认值\n searchForm[field.key] = props.modelValue?.[field.key] !== undefined \n ? props.modelValue[field.key] \n : (field.falseValue !== undefined ? field.falseValue : false);\n } else if (field.type === \"select\" && field.multiple) {\n // 多选 select 类型使用空数组作为默认值\n searchForm[field.key] = props.modelValue?.[field.key] !== undefined \n ? props.modelValue[field.key] \n : [];\n } else {\n searchForm[field.key] = props.modelValue?.[field.key] || \"\";\n }\n }\n });\n}\n\n// 监听外部数据变化\nwatch(\n () => props.modelValue,\n (newValue) => {\n if (newValue) {\n Object.assign(searchForm, newValue);\n }\n },\n { deep: true, immediate: true }\n);\n\n// 生命周期\nonMounted(() => {\n initFormData();\n});\n\nonBeforeUnmount(() => {\n if (autoSearchTimer) {\n clearTimeout(autoSearchTimer);\n autoSearchTimer = undefined;\n }\n});\n\n// 暴露方法供外部调用\ndefineExpose({\n search: handleSearch,\n reset: handleReset,\n});\n</script>\n\n<style scoped>\n/* 主容器 */\n.query-encapsulation {\n width: 100%;\n}\n\n.query-encapsulation__container {\n background: #ffffff;\n border-radius: 10px;\n padding: 16px;\n margin-bottom: 8px;\n box-shadow: \n 0rem 0.3125rem 0.3125rem -0.15625rem rgba(0, 0, 0, 0.03),\n 0rem 0.1875rem 0.1875rem -0.09375rem rgba(0, 0, 0, 0.02),\n 0rem 0.125rem 0.125rem -0.0625rem rgba(0, 0, 0, 0.02),\n 0rem 0.0625rem 0.0625rem -0.03125rem rgba(0, 0, 0, 0.03),\n 0rem 0.03125rem 0.03125rem 0rem rgba(0, 0, 0, 0.04),\n 0rem 0rem 0rem 0.0625rem rgba(0, 0, 0, 0.06);\n}\n\n.query-encapsulation__content {\n width: 100%;\n}\n\n/* 查询字段容器 */\n.query-encapsulation__fields {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n}\n\n.query-encapsulation__fields:last-child {\n margin-bottom: 0;\n}\n\n/* 字段组容器 - 修复 transition-group 布局问题 */\n.query-encapsulation__fields-group {\n display: contents;\n}\n\n/* 单个字段项 */\n.query-encapsulation__field-item {\n display: flex;\n align-items: center;\n transition: all 0.3s ease;\n}\n\n.query-encapsulation__field-wrapper {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* 字段标签 */\n.query-encapsulation__field-label {\n font-size: 13px;\n font-weight: 500;\n color: #374151;\n white-space: nowrap;\n min-width: fit-content;\n flex-shrink: 0;\n margin-right: 8px;\n}\n\n/* 展开/收起按钮 */\n.query-encapsulation__toggle {\n display: flex;\n align-items: center;\n margin-left: 0;\n}\n\n/* 展开/收起图标 */\n.query-encapsulation__toggle-icon {\n display: inline-block;\n margin-left: 4px;\n transition: transform 0.3s ease;\n font-size: 10px;\n}\n\n.query-encapsulation__toggle-icon.is-expanded {\n transform: rotate(180deg);\n}\n\n/* 操作按钮容器 */\n.query-encapsulation__actions {\n display: flex;\n align-items: center;\n}\n\n.query-encapsulation__actions-group {\n display: flex;\n gap: 8px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n/* 查询字段进出场与移动动画 */\n.qf-enter-active,\n.qf-leave-active {\n transition: all 0.2s ease;\n}\n\n.qf-enter-from,\n.qf-leave-to {\n opacity: 0;\n transform: translateY(-6px);\n}\n\n.qf-move {\n transition: transform 0.2s ease;\n}\n\n/* 响应式设计 - 移动优先 */\n/* 超大屏幕(1024px 及以下) */\n@media (max-width: 1024px) {\n .query-encapsulation__fields {\n gap: 10px;\n }\n}\n\n/* 中等屏幕(768px 及以下) */\n@media (max-width: 768px) {\n .query-encapsulation__container {\n padding: 10px;\n }\n}\n\n/* 小屏幕(640px 及以下) */\n@media (max-width: 640px) {\n .query-encapsulation__container {\n padding: 10px;\n }\n \n .query-encapsulation__fields {\n gap: 8px;\n }\n}\n\n/* 兼容性处理:如果浏览器不支持 contents,使用 flex 布局 */\n@supports not (display: contents) {\n .query-encapsulation__fields-group {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n }\n \n @media (max-width: 1024px) {\n .query-encapsulation__fields-group {\n gap: 10px;\n }\n }\n \n @media (max-width: 640px) {\n .query-encapsulation__fields-group {\n gap: 8px;\n }\n }\n}\n</style>\n","<template>\n <transition name=\"y-msg-fade\" @after-leave=\"onAfterLeave\">\n <div\n v-show=\"visible\"\n class=\"y-msg\"\n :class=\"[`y-msg--${type}`]\"\n :style=\"{ zIndex: zIndex }\"\n role=\"status\"\n aria-live=\"polite\"\n @mouseenter=\"handleMouseEnter\"\n @mouseleave=\"handleMouseLeave\"\n >\n <span class=\"y-msg__icon\" :class=\"`y-msg__icon--${type}`\" aria-hidden=\"true\">\n <svg v-if=\"type==='success'\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M20 6L9 17l-5-5\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n <svg v-else-if=\"type==='warning'\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n <svg v-else width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M12 9v4m0 4h.01M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </span>\n <div class=\"y-msg__content\" v-text=\"message\"></div>\n <button v-if=\"closable\" class=\"y-msg__close\" type=\"button\" @click=\"close\">✕</button>\n </div>\n </transition>\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, onBeforeUnmount, ref } from 'vue'\n\nconst props = withDefaults(defineProps<{\n id: number\n type?: 'success' | 'warning' | 'error'\n message: string\n duration?: number\n offset: number\n zIndex: number\n closable?: boolean\n onClose?: (id: number) => void\n}>(), {\n type: 'success',\n duration: 3000,\n closable: false,\n})\n\nconst visible = ref(false)\nlet timer: number | undefined\nlet remainingTime: number = 0\nlet startTime: number = 0\n\nonMounted(() => {\n // 先隐藏,下一帧再显示以触发过渡\n requestAnimationFrame(() => {\n visible.value = true\n if (props.duration && props.duration > 0) {\n startTimer(props.duration)\n }\n })\n})\n\nonBeforeUnmount(() => { \n clearTimer()\n})\n\nfunction startTimer(duration: number) {\n remainingTime = duration\n startTime = Date.now()\n timer = window.setTimeout(() => close(), duration)\n}\n\nfunction clearTimer() {\n if (timer) {\n window.clearTimeout(timer)\n timer = undefined\n }\n}\n\nfunction handleMouseEnter() {\n if (timer && props.duration && props.duration > 0) {\n clearTimer()\n // 计算剩余时间\n const elapsed = Date.now() - startTime\n remainingTime = Math.max(0, remainingTime - elapsed)\n }\n}\n\nfunction handleMouseLeave() {\n if (props.duration && props.duration > 0 && remainingTime > 0) {\n // 使用剩余时间重新启动计时器\n startTimer(remainingTime)\n }\n}\n\nfunction close() {\n visible.value = false\n}\n\nfunction onAfterLeave() {\n props.onClose?.(props.id)\n}\n</script>\n\n<style scoped>\n.y-msg {\n position: fixed;\n left: 50%;\n top: 0;\n transform: translate(-50%, 0);\n min-width: 260px;\n max-width: 86vw;\n box-sizing: border-box;\n padding: 10px 14px;\n border-radius: 12px;\n background: #ffffff;\n color: #0b1a29;\n display: flex;\n align-items: center;\n gap: 10px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n border: 1px solid rgba(15, 23, 42, 0.08);\n border-left-width: 3px;\n will-change: opacity, transform;\n transition:\n transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1),\n opacity 200ms ease;\n}\n\n.y-msg__icon { \n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n border-radius: 6px;\n padding: 4px;\n box-sizing: border-box;\n}\n.y-msg__icon--success { \n background-color: #047B5D; \n color: #ffffff; \n}\n.y-msg__icon--warning { \n background-color: #FFB800; \n color: #ffffff; \n}\n.y-msg__icon--error { \n background-color: #C41E3A; \n color: #ffffff; \n}\n.y-msg__content { \n margin-top: 2px;\n white-space: pre-wrap; \n word-break: break-word; \n line-height: 1.4;\n display: flex;\n align-items: center;\n /* font-weight: bold; */\n}\n.y-msg__close {\n margin-left: 8px;\n height: 22px; width: 22px;\n border: none; border-radius: 6px; background: transparent; color: inherit; cursor: pointer;\n}\n.y-msg__close:hover { background: rgba(2,6,23,0.06); }\n\n/* 状态色 - 背景统一为白色,通过图标和边框区分 */\n.y-msg--success { \n background: #ffffff; \n color: #0b1a29;\n}\n.y-msg--warning { \n background: #ffffff; \n color: #0b1a29;\n}\n.y-msg--error { \n background: #ffffff; \n color: #0b1a29;\n}\n\n@media (prefers-color-scheme: dark) {\n .y-msg { \n background: #1f2937; \n color: #ffffff;\n border-color: rgba(148, 163, 184, 0.2);\n border-left-width: 3px;\n }\n .y-msg--success { \n background: #1f2937; \n color: #ffffff;\n border-left-color: #047B5D;\n }\n .y-msg--warning { \n background: #1f2937; \n color: #ffffff;\n border-left-color: #FFB800;\n }\n .y-msg--error { \n background: #1f2937; \n color: #ffffff;\n border-left-color: #C41E3A;\n }\n}\n\n/* 进入/离开动效(自然惯性:更慢进入,稍快离开) */\n.y-msg-fade-enter-from { opacity: 0; transform: translate(-50%, -18px) scale(0.972); }\n.y-msg-fade-enter-active { transition: opacity 360ms cubic-bezier(0.22, 1, 0.36, 1), transform 360ms cubic-bezier(0.22, 1, 0.36, 1); }\n.y-msg-fade-leave-active { transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1), transform 220ms cubic-bezier(0.4, 0, 0.2, 1); }\n.y-msg-fade-leave-to { opacity: 0; transform: translate(-50%, -10px) scale(0.982); }\n\n/* 离场节点固定 top,不参与 top 过渡,仅做自身淡出/轻微位移,避免与重排叠加 */\n.y-msg.is-leaving { transition-property: opacity, transform; pointer-events: none; }\n\n@media (prefers-reduced-motion: reduce) {\n .y-msg, .y-msg-fade-enter-active, .y-msg-fade-leave-active { transition: none; }\n}\n</style>\n\n\n","import { createVNode, render } from 'vue'\nimport YMessageToast from './ymessageToast.vue'\n\nlet seed = 1\nconst GAP = 12\ntype InstanceItem = { id: number; el: HTMLElement; vm: any; height: number; leaving?: boolean }\nconst instances: Array<InstanceItem> = []\n\ntype YMessageType = 'success' | 'warning' | 'error'\n\ninterface MessageOptions {\n type?: YMessageType\n message: string\n duration?: number\n closable?: boolean\n}\n\nfunction calcOffset(): number {\n let offset = 20\n instances.forEach(inst => { offset += inst.height + GAP })\n return offset\n}\n\nfunction close(id: number) {\n const index = instances.findIndex(i => i.id === id)\n if (index === -1) return\n const { el } = instances[index]\n const node = el.firstElementChild as HTMLElement | null\n // 标记离场,锁定自身 top,避免与重排上移动画叠加造成闪烁\n if (node) {\n const computedTop = window.getComputedStyle(node).top\n node.style.top = computedTop\n node.classList.add('is-leaving')\n // 同步触发离场过渡(添加离场类后,不再参与 top 过渡)\n node.style.willChange = 'opacity, transform'\n }\n instances[index].leaving = true\n // 先让其他实例平滑上移,跳过离场中的实例\n updatePositions()\n // 等待过渡完成再卸载(避免闪断)\n const LEAVE_MS = 260\n setTimeout(() => {\n render(null, el)\n el.parentNode && el.parentNode.removeChild(el)\n const rmIndex = instances.findIndex(i => i.id === id)\n if (rmIndex !== -1) instances.splice(rmIndex, 1)\n updatePositions()\n }, LEAVE_MS)\n}\n\nfunction show(options: MessageOptions) {\n const id = seed++\n const el = document.createElement('div')\n document.body.appendChild(el)\n\n const vm = createVNode(YMessageToast, {\n id,\n type: options.type || 'success',\n message: options.message,\n duration: options.duration ?? 2500,\n offset: calcOffset(),\n zIndex: 3000 + id,\n closable: options.closable ?? false,\n onClose: (cid: number) => close(cid),\n })\n\n render(vm, el)\n\n const initialHeight = (el.firstElementChild as HTMLElement)?.offsetHeight || 0\n instances.push({ id, el, vm, height: initialHeight, leaving: false })\n updatePositions()\n\n // 等待一帧让过渡进入可见后,重新测量实际高度,避免初始为 0 导致重叠\n requestAnimationFrame(() => {\n const node = el.firstElementChild as HTMLElement | null\n if (!node) return\n const realHeight = node.offsetHeight || initialHeight || 0\n const inst = instances.find(i => i.id === id)\n if (inst) {\n inst.height = realHeight\n updatePositions()\n }\n })\n\n return { close: () => close(id) }\n}\n\nexport const YMessage = {\n success(message: string, durationOrOpts?: number | Omit<MessageOptions,'type'|'message'>) {\n const opts = typeof durationOrOpts === 'number' ? { duration: durationOrOpts } : (durationOrOpts || {})\n return show({ ...opts, type: 'success', message })\n },\n warning(message: string, durationOrOpts?: number | Omit<MessageOptions,'type'|'message'>) {\n const opts = typeof durationOrOpts === 'number' ? { duration: durationOrOpts } : (durationOrOpts || {})\n return show({ ...opts, type: 'warning', message })\n },\n error(message: string, durationOrOpts?: number | Omit<MessageOptions,'type'|'message'>) {\n const opts = typeof durationOrOpts === 'number' ? { duration: durationOrOpts } : (durationOrOpts || {})\n return show({ ...opts, type: 'error', message })\n },\n}\n\nexport type { YMessageType, MessageOptions }\n\n// 自动挂载到全局,无需 import 即可使用\nif (typeof window !== 'undefined') {\n ;(window as any).YMessage = YMessage\n // 同时挂载为全局变量(在非严格模式下可用)\n if (typeof (globalThis as any).YMessage === 'undefined') {\n ;(globalThis as any).YMessage = YMessage\n }\n}\n\nfunction updatePositions() {\n let offset = 20\n instances.forEach(inst => {\n const node = inst.el.firstElementChild as HTMLElement | null\n if (!node) return\n // const currentTop = parseFloat(node.style.top || '20') || 20\n const targetTop = offset\n // const dy = targetTop - currentTop\n // 用 transform 做平滑上移,避免频繁 top 导致回流\n node.style.transform = `translate(-50%, ${targetTop}px)`\n // 仅在首次定位时写入 top 以保证初始位置\n if (!node.style.top) node.style.top = '0px'\n if (!inst.leaving) {\n offset += (node.offsetHeight || inst.height) + GAP\n } else {\n const currentHeight = node.offsetHeight || inst.height\n offset += currentHeight + GAP\n }\n })\n}\n\n\n","<template>\n <div :class=\"['hint-tag-wrapper', `hint-tag-wrapper-${position}`]\">\n <transition name=\"hint-slide\">\n <div \n v-show=\"isExpanded\" \n :class=\"['hint-tag', `hint-tag-${position}`]\"\n :style=\"{ \n width: position === 'top' || position === 'bottom' ? 'auto' : width,\n borderColor: borderColor\n }\"\n >\n <div \n ref=\"contentRef\"\n class=\"hint-tag-content\"\n :class=\"{ 'hint-tag-content-clamp': maxLines }\"\n :style=\"maxLines ? { \n '--line-clamp': maxLines,\n lineHeight: '1.5',\n maxHeight: `${maxLines * 1.5}em`\n } : {}\"\n @mouseenter=\"handleMouseEnter\"\n @mouseleave=\"handleMouseLeave\"\n >\n <slot>{{ content }}</slot>\n </div>\n \n <!-- 完整内容弹窗 - 使用 Teleport 渲染到 body -->\n <Teleport to=\"body\">\n <transition name=\"popup-fade\">\n <div \n v-if=\"showPopup && isContentTruncated\"\n ref=\"popupRef\"\n class=\"hint-tag-popup\"\n @mouseenter=\"handlePopupEnter\"\n @mouseleave=\"handlePopupLeave\"\n >\n <div class=\"hint-tag-popup-content\">\n <slot>{{ content }}</slot>\n </div>\n </div>\n </transition>\n </Teleport>\n <div class=\"hint-tag-toggle\" @click=\"toggle\">\n <svg \n class=\"hint-tag-icon\"\n viewBox=\"0 0 24 24\" \n fill=\"none\" \n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path \n d=\"M15 18L9 12L15 6\" \n stroke=\"currentColor\" \n stroke-width=\"2\" \n stroke-linecap=\"round\" \n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </div>\n </transition>\n \n <!-- 收起后的小按钮 -->\n <transition name=\"hint-button-fade\">\n <div \n v-show=\"!isExpanded\" \n :class=\"['hint-tag-button', `hint-tag-button-${position}`]\"\n @click=\"toggle\"\n :title=\"tooltip || content\"\n >\n <svg \n class=\"hint-tag-button-icon\" \n viewBox=\"0 0 24 24\" \n fill=\"none\" \n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path \n d=\"M9 18L15 12L9 6\" \n stroke=\"currentColor\" \n stroke-width=\"2\" \n stroke-linecap=\"round\" \n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </transition>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref, inject, onMounted, onUnmounted, watch, onUpdated } from 'vue'\n\ninterface Props {\n content?: string\n position?: 'top' | 'right' | 'bottom' | 'left'\n defaultExpanded?: boolean\n width?: string\n tooltip?: string\n borderColor?: string\n maxLines?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n content: '',\n position: 'right',\n defaultExpanded: true,\n width: '280px',\n tooltip: '',\n borderColor: '#00a8e8',\n maxLines: undefined\n})\n\nconst contentRef = ref<HTMLElement | null>(null)\nconst popupRef = ref<HTMLElement | null>(null)\nconst isContentTruncated = ref(false)\nconst showPopup = ref(false)\nlet popupTimer: number | null = null\n\n// 检测内容是否被截断\nconst checkTruncation = () => {\n if (!props.maxLines || !contentRef.value) {\n isContentTruncated.value = false\n return\n }\n \n const element = contentRef.value\n \n // 在限制状态下,临时移除限制来检测完整高度\n const originalMaxHeight = element.style.maxHeight\n const hasClampClass = element.classList.contains('hint-tag-content-clamp')\n \n // 临时移除限制\n element.style.maxHeight = 'none'\n if (hasClampClass) {\n element.classList.remove('hint-tag-content-clamp')\n }\n \n // 获取完整内容的高度\n const fullHeight = element.scrollHeight\n const lineHeight = parseFloat(getComputedStyle(element).lineHeight) || 18\n const maxHeight = props.maxLines * lineHeight\n \n // 恢复原始样式\n element.style.maxHeight = originalMaxHeight\n if (hasClampClass) {\n element.classList.add('hint-tag-content-clamp')\n }\n \n // 检查内容是否被截断\n isContentTruncated.value = fullHeight > maxHeight\n}\n\n// 鼠标移入处理\nconst handleMouseEnter = () => {\n if (props.maxLines && isContentTruncated.value) {\n // 清除可能存在的定时器\n if (popupTimer) {\n clearTimeout(popupTimer)\n popupTimer = null\n }\n showPopup.value = true\n // 延迟定位弹窗,确保 DOM 已更新\n setTimeout(() => {\n updatePopupPosition()\n }, 0)\n }\n}\n\n// 鼠标移出处理\nconst handleMouseLeave = () => {\n // 延迟隐藏,给用户时间移动到弹窗\n popupTimer = window.setTimeout(() => {\n showPopup.value = false\n popupTimer = null\n }, 100)\n}\n\n// 弹窗鼠标移入处理\nconst handlePopupEnter = () => {\n // 清除隐藏定时器\n if (popupTimer) {\n clearTimeout(popupTimer)\n popupTimer = null\n }\n}\n\n// 弹窗鼠标移出处理\nconst handlePopupLeave = () => {\n showPopup.value = false\n}\n\n// 更新弹窗位置\nconst updatePopupPosition = () => {\n if (!popupRef.value || !contentRef.value) return\n \n const contentRect = contentRef.value.getBoundingClientRect()\n const popupRect = popupRef.value.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n const scrollX = window.scrollX || window.pageXOffset\n const scrollY = window.scrollY || window.pageYOffset\n \n let left = 0\n let top = 0\n \n switch (props.position) {\n case 'right':\n // 弹窗显示在内容右侧\n left = contentRect.right + 12\n top = contentRect.top + scrollY\n // 如果右侧空间不足,显示在左侧\n if (left + popupRect.width > viewportWidth + scrollX) {\n left = contentRect.left - popupRect.width - 12\n }\n // 垂直方向居中\n top = contentRect.top + scrollY + (contentRect.height - popupRect.height) / 2\n // 确保不超出视口\n if (top < scrollY) top = scrollY + 8\n if (top + popupRect.height > scrollY + viewportHeight) {\n top = scrollY + viewportHeight - popupRect.height - 8\n }\n break\n case 'left':\n // 弹窗显示在内容左侧\n left = contentRect.left - popupRect.width - 12\n top = contentRect.top + scrollY\n // 如果左侧空间不足,显示在右侧\n if (left < scrollX) {\n left = contentRect.right + 12\n }\n // 垂直方向居中\n top = contentRect.top + scrollY + (contentRect.height - popupRect.height) / 2\n // 确保不超出视口\n if (top < scrollY) top = scrollY + 8\n if (top + popupRect.height > scrollY + viewportHeight) {\n top = scrollY + viewportHeight - popupRect.height - 8\n }\n break\n case 'top':\n // 弹窗显示在内容上方\n left = contentRect.left + scrollX + (contentRect.width - popupRect.width) / 2\n top = contentRect.top - popupRect.height - 12\n // 如果上方空间不足,显示在下方\n if (top < scrollY) {\n top = contentRect.bottom + scrollY + 12\n }\n // 水平方向调整\n if (left < scrollX + 8) left = scrollX + 8\n if (left + popupRect.width > scrollX + viewportWidth) {\n left = scrollX + viewportWidth - popupRect.width - 8\n }\n break\n case 'bottom':\n // 弹窗显示在内容下方\n left = contentRect.left + scrollX + (contentRect.width - popupRect.width) / 2\n top = contentRect.bottom + scrollY + 12\n // 如果下方空间不足,显示在上方\n if (top + popupRect.height > scrollY + viewportHeight) {\n top = contentRect.top - popupRect.height - 12\n }\n // 水平方向调整\n if (left < scrollX + 8) left = scrollX + 8\n if (left + popupRect.width > scrollX + viewportWidth) {\n left = scrollX + viewportWidth - popupRect.width - 8\n }\n break\n }\n \n popupRef.value.style.left = `${left}px`\n popupRef.value.style.top = `${top}px`\n}\n\nonUpdated(() => {\n checkTruncation()\n})\n\n\nconst isExpanded = ref(props.defaultExpanded)\n\nconst toggle = () => {\n isExpanded.value = !isExpanded.value\n}\n\n// 收起方法(用于批量收起)\nconst collapse = () => {\n if (isExpanded.value) {\n isExpanded.value = false\n }\n}\n\n// 展开方法(用于批量展开)\nconst expand = () => {\n if (!isExpanded.value) {\n isExpanded.value = true\n }\n}\n\n// 暴露方法供外部调用\ndefineExpose({\n toggle,\n isExpanded,\n collapse,\n expand\n})\n\n// 尝试注册到父级 ytable 组件\nconst registerHintTag = inject<(instance: any) => void>('registerHintTag', null)\nconst unregisterHintTag = inject<(instance: any) => void>('unregisterHintTag', null)\nconst notifyHintTagStateChange = inject<() => void>('notifyHintTagStateChange', null)\n\n// 创建实例对象用于注册\nconst instance = {\n collapse,\n expand,\n toggle,\n get isExpanded() {\n return isExpanded.value\n }\n}\n\n// 监听状态变化,通知父组件更新\nwatch(() => isExpanded.value, () => {\n if (notifyHintTagStateChange) {\n notifyHintTagStateChange()\n }\n // 展开/收起后重新检测截断状态\n setTimeout(() => {\n checkTruncation()\n }, 0)\n})\n\n// 监听内容变化,重新检测截断状态\nwatch(() => [props.content, props.maxLines], () => {\n setTimeout(() => {\n checkTruncation()\n }, 0)\n})\n\n// 监听弹窗显示状态,更新位置\nwatch(showPopup, (newVal) => {\n if (newVal) {\n // 延迟定位弹窗,确保 DOM 已更新\n setTimeout(() => {\n updatePopupPosition()\n }, 0)\n // 监听滚动和窗口大小变化\n window.addEventListener('scroll', updatePopupPosition, true)\n window.addEventListener('resize', updatePopupPosition)\n } else {\n // 移除监听\n window.removeEventListener('scroll', updatePopupPosition, true)\n window.removeEventListener('resize', updatePopupPosition)\n }\n})\n\nonMounted(() => {\n checkTruncation()\n if (registerHintTag) {\n registerHintTag(instance)\n }\n})\n\nonUnmounted(() => {\n if (unregisterHintTag) {\n unregisterHintTag(instance)\n }\n // 清理定时器\n if (popupTimer) {\n clearTimeout(popupTimer)\n popupTimer = null\n }\n // 移除事件监听\n window.removeEventListener('scroll', updatePopupPosition, true)\n window.removeEventListener('resize', updatePopupPosition)\n})\n</script>\n\n<style scoped lang=\"less\">\n.hint-tag-wrapper {\n display: inline-block;\n position: relative;\n vertical-align: middle;\n margin-left: 4px;\n z-index: 10000;\n pointer-events: none;\n}\n\n.hint-tag {\n position: absolute;\n background: #ffffff;\n color: #333333;\n border-radius: 6px;\n border: 1px solid;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n display: flex;\n align-items: stretch;\n font-size: 12px;\n white-space: nowrap;\n pointer-events: auto;\n \n &.hint-tag-right {\n left: 0;\n top: 50%;\n transform: translateY(-50%);\n flex-direction: row;\n }\n \n &.hint-tag-left {\n right: 0;\n top: 50%;\n transform: translateY(-50%);\n flex-direction: row-reverse;\n }\n \n &.hint-tag-top {\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n flex-direction: column-reverse;\n margin-bottom: 4px;\n }\n \n &.hint-tag-bottom {\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n flex-direction: column;\n margin-top: 4px;\n }\n}\n\n.hint-tag-content {\n flex: 1;\n padding: 3px 10px;\n line-height: 1.5;\n white-space: normal;\n word-break: break-word;\n \n // 当没有设置 maxLines 时,使用滚动条\n &:not(.hint-tag-content-clamp) {\n max-height: 150px;\n overflow-y: auto;\n \n &::-webkit-scrollbar {\n width: 4px;\n }\n \n &::-webkit-scrollbar-track {\n background: #f3f4f6;\n border-radius: 4px;\n }\n \n &::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 4px;\n \n &:hover {\n background: #9ca3af;\n }\n }\n }\n \n // 当设置了 maxLines 时,使用多行省略\n &.hint-tag-content-clamp {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n overflow: hidden;\n text-overflow: ellipsis;\n -webkit-line-clamp: var(--line-clamp, 3);\n line-clamp: var(--line-clamp, 3);\n word-break: break-word;\n cursor: pointer;\n \n &:hover {\n opacity: 0.8;\n }\n }\n}\n\n.hint-tag-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 6px;\n cursor: pointer;\n background: #f3f4f6;\n transition: background 0.2s ease;\n flex-shrink: 0;\n color: #666666;\n \n &:hover {\n background: #e5e7eb;\n }\n \n .hint-tag-right & {\n border-radius: 0 6px 6px 0;\n }\n \n .hint-tag-left & {\n border-radius: 6px 0 0 6px;\n }\n \n .hint-tag-top & {\n border-radius: 6px 6px 0 0;\n }\n \n .hint-tag-bottom & {\n border-radius: 0 0 6px 6px;\n }\n}\n\n.hint-tag-icon {\n width: 16px;\n height: 16px;\n transition: transform 0.2s ease;\n \n .hint-tag-right & {\n transform: rotate(0deg); // 向左箭头(展开状态,点击后收起)\n }\n \n .hint-tag-left & {\n transform: rotate(180deg); // 向右箭头(展开状态,点击后收起)\n }\n \n .hint-tag-top & {\n transform: rotate(-90deg); // 向上箭头(展开状态,点击后收起)\n }\n \n .hint-tag-bottom & {\n transform: rotate(90deg); // 向下箭头(展开状态,点击后收起)\n }\n}\n\n.hint-tag-button {\n width: 20px;\n height: 20px;\n background: #ffffff;\n color: #666666;\n border: 1px solid #e5e7eb;\n border-radius: 50%;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);\n transition: transform 0.2s ease, box-shadow 0.2s ease, color 0.2s ease;\n pointer-events: auto;\n vertical-align: middle;\n \n &:hover {\n color: #333333;\n transform: scale(1.1);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n}\n\n.hint-tag-button-icon {\n width: 12px;\n height: 12px;\n transition: transform 0.2s ease;\n \n .hint-tag-button-right & {\n transform: rotate(0deg); // 收起状态,点击后展开,显示→\n }\n \n .hint-tag-button-left & {\n transform: rotate(180deg); // 收起状态,点击后展开,显示←\n }\n \n .hint-tag-button-top & {\n transform: rotate(-90deg); // 收起状态,点击后展开,显示↑\n }\n \n .hint-tag-button-bottom & {\n transform: rotate(90deg); // 收起状态,点击后展开,显示↓\n }\n}\n\n// 动画效果\n.hint-slide-enter-active,\n.hint-slide-leave-active {\n transition: all 0.3s ease;\n}\n\n.hint-tag-right {\n &.hint-slide-enter-from,\n &.hint-slide-leave-to {\n transform: translateY(-50%) translateX(-20px);\n opacity: 0;\n }\n}\n\n.hint-tag-left {\n &.hint-slide-enter-from,\n &.hint-slide-leave-to {\n transform: translateY(-50%) translateX(20px);\n opacity: 0;\n }\n}\n\n.hint-tag-top {\n &.hint-slide-enter-from,\n &.hint-slide-leave-to {\n transform: translateX(-50%) translateY(20px);\n opacity: 0;\n }\n}\n\n.hint-tag-bottom {\n &.hint-slide-enter-from,\n &.hint-slide-leave-to {\n transform: translateX(-50%) translateY(-20px);\n opacity: 0;\n }\n}\n\n.hint-button-fade-enter-active,\n.hint-button-fade-leave-active {\n transition: all 0.2s ease;\n}\n\n.hint-button-fade-enter-from,\n.hint-button-fade-leave-to {\n opacity: 0;\n transform: scale(0.5);\n}\n\n// 弹窗样式\n.hint-tag-popup {\n position: fixed;\n background: #ffffff;\n color: #333333;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);\n padding: 12px 16px;\n font-size: 12px;\n line-height: 1.6;\n max-width: 500px;\n max-height: 400px;\n overflow-y: auto;\n word-break: break-word;\n white-space: normal;\n z-index: 99999;\n pointer-events: auto;\n \n &::-webkit-scrollbar {\n width: 6px;\n }\n \n &::-webkit-scrollbar-track {\n background: #f3f4f6;\n border-radius: 4px;\n }\n \n &::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 4px;\n \n &:hover {\n background: #9ca3af;\n }\n }\n}\n\n.hint-tag-popup-content {\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n// 弹窗动画\n.popup-fade-enter-active,\n.popup-fade-leave-active {\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.popup-fade-enter-from,\n.popup-fade-leave-to {\n opacity: 0;\n transform: translateY(-8px) scale(0.95);\n}\n\n</style>\n","// 全局类型声明(确保 YMessage 全局类型可用)\ndeclare global {\n interface Window {\n YMessage: {\n success(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n warning(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n error(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n }\n }\n \n // 允许在全局作用域直接使用 YMessage(非严格模式)\n var YMessage: {\n success(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n warning(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n error(message: string, opts?: { duration?: number; closable?: boolean }): { close: () => void }\n }\n}\n\n// 导出所有组件\nexport { default as YButton } from './components/ybutton.vue'\nexport { default as YInput } from './components/yinput.vue'\nexport { default as YTable } from './components/ytable.vue'\nexport { default as YSelect } from './components/yselect.vue'\nexport { default as YPagination } from './components/ypagination.vue'\nexport { default as YBadge } from './components/ybadge.vue'\nexport { default as YDialog } from './components/ydialog.vue'\nexport { default as YPopover } from './components/ypopover.vue'\nexport { default as YTime } from './components/ytime.vue'\nexport { default as YSwitch } from './components/yswitch.vue'\nexport { default as YImage } from './components/yimage.vue'\nexport { default as YDropdown } from './components/ydropdown.vue'\nexport { default as YDrawer } from './components/ydrawer.vue'\nexport { default as YTree } from './components/ytree.vue'\nexport { default as QueryEncapsulation } from './components/QueryEncapsulation.vue'\n\n// 导出 YMessage\nexport { YMessage } from './components/ymessage/ymessage'\nexport type { YMessageType, MessageOptions } from './components/ymessage/ymessage'\n\n// 导出类型\nexport type { SwitchProps } from './components/yswitch.vue'\nexport type { SelectOption } from './components/yselect.vue'\nexport type { PaginationProps } from './components/ypagination.vue'\n\n// 安装函数(用于 Vue.use())\nimport type { App } from 'vue'\nimport YButton from './components/ybutton.vue'\nimport YInput from './components/yinput.vue'\nimport YTable from './components/ytable.vue'\nimport YSelect from './components/yselect.vue'\nimport YPagination from './components/ypagination.vue'\nimport YBadge from './components/ybadge.vue'\nimport YDialog from './components/ydialog.vue'\nimport YPopover from './components/ypopover.vue'\nimport YTime from './components/ytime.vue'\nimport YSwitch from './components/yswitch.vue'\nimport YImage from './components/yimage.vue'\nimport YDropdown from './components/ydropdown.vue'\nimport YDrawer from './components/ydrawer.vue'\nimport YTree from './components/ytree.vue'\nimport HintTag from './components/hintTag.vue'\nimport QueryEncapsulation from './components/QueryEncapsulation.vue'\nimport { YMessage } from './components/ymessage/ymessage'\n\nconst components = {\n YButton,\n YInput,\n YTable,\n YSelect,\n YPagination,\n YBadge,\n YDialog,\n YPopover,\n YTime,\n YSwitch,\n YImage,\n YDropdown,\n YDrawer,\n YTree,\n QueryEncapsulation,\n HintTag,\n}\n\nexport default {\n install(app: App) {\n // 注册所有组件\n Object.keys(components).forEach((key) => {\n app.component(key, components[key as keyof typeof components])\n })\n \n // 将 YMessage 挂载到 Vue 全局属性,方便在模板中使用 this.$message\n app.config.globalProperties.$message = YMessage\n \n // 确保挂载到 window 对象,实现全局直接使用(无需 import)\n if (typeof window !== 'undefined') {\n ;(window as any).YMessage = YMessage\n }\n },\n}\n\n"],"names":["props","__props","emit","__emit","onClick","ev","groupPositionClass","computed","isGroup","onGroupItemClick","item","_openBlock","_createElementBlock","_hoisted_3","_Fragment","_renderList","index","_a","$event","_createElementVNode","_hoisted_5","_hoisted_6","_cache","_hoisted_7","_hoisted_8","_toDisplayString","_hoisted_2","_renderSlot","_ctx","inputRef","ref","previousValue","hasChanged","isFocused","inputPlaceholder","passwordVisible","showPasswordToggle","actualInputType","togglePasswordVisibility","watch","val","onInput","target","onFocus","onBlur","current","minVal","onEnter","onPaste","_normalizeClass","currentPage","pageSize","selectedItems","selectedRowKey","expandedKeys","tableMaxHeight","tableContainer","headerRef","bodyWrapRef","bodyTableRef","headerColWidths","headerWidthMap","defaultHeaderHeight","hintTagInstances","hasHintTags","allHintsExpanded","hintTagStateUpdateTrigger","expandedCount","instance","collapsedCount","registerHintTag","unregisterHintTag","collapseAllHints","expandAllHints","toggleAllHints","notifyHintTagStateChange","provide","autoColumnKeys","col","normalizeWidth","getAutoColumnWidth","vTrackRef","vScroll","isDragging","dragStartY","dragStartScrollTop","scrollbarWidth","width","trimmed","parseWidthNumber","normalized","parsed","totalTableColumns","count","filteredData","keyword","field","value","getNestedValue","pagedData","isAllVisibleSelected","visibleKeys","getRowKey","isRowDisabled","key","isPartiallySelected","selectedCount","isAllVisibleDisabled","shouldDisableNext","fixedLeftWidths","widths","cumulativeWidth","i","parsedWidth","fixedRightWidths","rightFixedColumns","getFixedColumnIndex","columnIndex","fixed","isRowExpanded","toggleRowExpand","obj","path","getColumnClass","column","isHeader","classes","getColumnStyle","style","normalizedWidth","autoWidth","fixedIndex","leftOffset","rightOffset","formatCellValue","toggleSelect","rowData","rowIndex","x","toggleSelectAllVisible","union","clearSelection","handleRowClick","k","isRowSelected","newVal","currentSet","newSet","handlePageChange","page","handlePageSizeChange","size","next","calculateTableMaxHeight","nextTick","containerRect","viewportHeight","containerTop","headerElement","headerHeight","paginationHeight","paginationElement","bulkBarElement","bulkBarHeight","reservedHeight","availableHeight","maxHeight","tableContent","isSyncingScroll","syncHeaderScroll","syncBodyScroll","updateVirtualScrollbar","wrap","contentHeight","viewport","scrollTop","needVBar","minThumb","ratio","trackHeight","thumbHeight","maxThumbTop","maxScrollTop","onThumbMousemove","e","scrollDelta","onThumbMouseup","measureAutoColumnWidths","w","fallback","firstRow","startIndex","tds","td","measured","stored","_b","handleResize","updateHeaderScrollbarGutter","syncSelectedHeaderHeight","nextWidths","nextMap","idx","currentKeys","measureDefaultHeaderHeight","headerTable","firstNormalTh","selectedHeader","wrapper","onMounted","resizeObserver","onUnmounted","lastScrollbarWidth","currentScrollbarWidth","bodyTable","_createVNode","_Transition","_hoisted_1","_component_YButton","_hoisted_4","_hoisted_9","_hoisted_10","_hoisted_11","_normalizeStyle","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_16","$slots","_hoisted_18","colIndex","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_24","_createBlock","_component_YPagination","isOpen","hoveredIndex","optionsContainer","triggerElement","selectContainer","shouldOpenUpward","inputElement","searchQuery","selectedOption","option","getOptionValue","selectedOptions","values","selectedLabel","getOptionLabel","displayedOptions","query","opt","label","portalDropdownStyle","trigger","rect","calculateDropdownPosition","triggerRect","dropdownHeight","dropdownBottom","dropdownTop","shouldOpenDown","canOpenUp","getOptionKey","isSelected","isOptionDisabled","toggleDropdown","closeDropdown","openDropdown","scrollToSelected","selectOption","_index","currentValues","optionValue","valueIndex","handleClear","cleared","removeTag","event","moveHover","delta","total","attempts","scrollHoverIntoView","selectHovered","selectedElement","el","handleClickOutside","_withModifiers","_createTextVNode","_Teleport","pageSizeOptions","goToPage","onPagerGroupClick","action","_component_YSelect","toneClass","ariaLabel","text","tone","prog","progMap","toneMap","visible","v","panelRef","panelStyle","onMaskClick","close","onEsc","onKeydown","popoverRef","triggerRef","contentRef","contentRect","arrowPosition","openTimer","closeTimer","contentStyle","top","left","calculatePosition","arrowStyle","triggerWidth","triggerHeight","triggerTop","triggerLeft","contentWidth","viewportWidth","show","clearTimers","doShow","updatePosition","hide","doHide","calculateArrowPosition","triggerCenterX","contentLeft","arrowOffset","triggerCenterY","contentTop","handleTriggerClick","handleMouseEnter","handleMouseLeave","handleContentMouseEnter","handleContentMouseLeave","__expose","activeShortcutIndex","selectedShortcutIndex","pendingValue","dropdown","dropdownPosition","startCalendar","endCalendar","ensureDifferentMonths","startTime","endTime","nextMonth","ensureDifferentMonthsReverse","prevMonth","weekDays","tempStartDate","tempEndDate","parseDate","date","formatDateToString","year","month","day","hours","minutes","seconds","formatDateToTimestamp","normalizeValue","formatOutputValue","formatYearMonth","isSameDay","date1","date2","isDateInRange","start","end","findMatchingShortcutIndex","currentValue","normalizedValue","shortcutValue","currentStart","currentEnd","shortcutStart","shortcutEnd","generateCalendarDays","firstDay","lastDay","firstDayWeek","daysInMonth","days","today","prevDaysCount","remainingDays","weeks","updateValue","formattedValue","dropdownRect","spaceBelow","spaceAbove","spaceRight","dropdownWidth","triggerEl","dropdownEl","handleTriggerKeydown","focusFirstShortcut","handleDropdownKeydown","handleShortcutKeydown","focusShortcut","selectShortcut","handleShortcutMouseEnter","handleShortcutMouseLeave","shortcutElement","shortcut","s","selectDate","type","selectedDate","endDate","getDateCellClass","confirmSelection","resetSelection","startCalendarDays","endCalendarDays","displayText","formatDate","startStr","endStr","dropdownClasses","hasValue","canConfirm","newValue","startDate","handleClearClick","changeMonth","direction","newDate","_hoisted_15","_hoisted_17","week","weekIndex","dayIndex","_hoisted_23","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","_hoisted_30","_hoisted_31","_hoisted_32","rootEl","isChecked","switchStyle","onToggle","containerRef","imageRef","previewImageRef","isLoaded","isLoading","hasError","isInView","showPreview","imgSrc","previewSrc","zoomLevel","isMounted","hoverPreview","hidePreviewTimeout","originalBodyStyle","RADIUS_TOKEN_MAP","containerClass","radiusValue","radiusStyle","imageClass","imageStyle","resolvedPreviewSrc","getHoverPreviewSrc","getScrollbarWidth","scrollDiv","lockBodyScroll","unlockBodyScroll","observer","setupIntersectionObserver","entries","entry","handleLoad","handleError","retryLoad","getPreviewUrl","handleErrorClick","handlePreview","previewUrl","img","timeoutId","isHandled","showPreviewModal","closePreview","handleWheel","zoomDirection","newZoom","updateImagePreviewPosition","padding","onImageMouseEnter","onImageMouseMove","onImageMouseLeave","onPreviewMouseEnter","onPreviewMouseLeave","nv","_vShow","dropdownRef","hideTimer","menuClass","menuStyle","showDropdown","hideDropdown","menu","menuRect","absoluteTop","absoluteLeft","menuWidth","menuHeight","transitionName","roundedClass","inject","getNodeKey","getNodeLabel","getNodeChildren","hasChildren","isEmployeeNode","getNodeIcon","getNodeDepth","isChildStyleNode","isNodeExpanded","isNodeChecked","isNodeIndeterminate","isNodeCurrent","isNodeHighlighted","handleExpandClick","handleCheckClick","handleNodeClick","handleNodeContextMenu","nodeLabel","nodeIcon","nodeDepth","isExpanded","isIndeterminate","isCurrent","isHighlighted","hasNodeChildren","nodeChildren","isChildStyle","isEmployee","paddingLeft","_unref","child","YTreeNode","_withCtx","slotProps","_mergeProps","DEPT_ICON_URL","PERSON_ICON_URL","treeData","store","checkedKeysVersion","nodeStateCache","clearAllCache","effectiveRestrictLevel","node","rootNode","dept","person","button","childStyleIcon","children","targetNode","currentDepth","depth","nodeKey","calculateNodeState","visited","directlyChecked","checkedCount","indeterminateCount","childState","checked","indeterminate","allChildrenChecked","someChildrenChecked","newCheckedState","currentExpandedKeys","cascadeChildren","check","childKey","updateAllParentNodes","parentMap","allNodes","nodeKeyMap","collectAllNodes","nodes","parent","updateNodeParents","data","nodeComponent","keys","restrictLevel","getDepthByKey","targetKey","level","n","d","collectKeysToDepth","maxDepth","newExpandedKeys","filtered","expandAllNodes","collectExpandableKeys","allExpandableKeys","expandNodesWithCheckedPermissions","findPathsToCheckedNodes","parentPath","currentPath","checkedKeys","expandableKeys","expandAllNodesTimer","debouncedExpandAllNodes","highlightAndExpandByIds","ids","findPathToKey","nk","newPath","p","targetIds","keysToExpand","targetId","clearHighlights","clearCurrentNode","searchForm","reactive","autoTriggerTypes","autoSearchTimer","visibleFields","displayedFields","hasHiddenFields","getFieldComponent","YSelect","YTime","YSwitch","YInput","updateFieldValue","f","handleFieldChange","scheduleAutoSearch","handleSwitchChange","handleSearch","searchParams","filterEmptyParams","formattedParams","formatSearchParams","rawParams","handleReset","toggleExpanded","getFieldListeners","handleInputQuickSearch","params","rawValue","formatted","startKey","endKey","initFormData","_c","_d","_e","onBeforeUnmount","_TransitionGroup","_resolveDynamicComponent","_toHandlers","YButton","timer","remainingTime","startTimer","clearTimer","duration","elapsed","onAfterLeave","seed","GAP","instances","calcOffset","offset","inst","id","computedTop","updatePositions","render","rmIndex","options","vm","createVNode","YMessageToast","cid","initialHeight","realHeight","YMessage","message","durationOrOpts","targetTop","currentHeight","popupRef","isContentTruncated","showPopup","popupTimer","checkTruncation","element","originalMaxHeight","hasClampClass","fullHeight","lineHeight","updatePopupPosition","handlePopupEnter","handlePopupLeave","popupRect","scrollX","scrollY","onUpdated","toggle","collapse","expand","components","YTable","YPagination","YBadge","YDialog","YPopover","YImage","YDropdown","YDrawer","YTree","QueryEncapsulation","HintTag","app"],"mappings":"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"}