@nhdropshipping/y-components 1.0.68 → 1.0.70

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.cjs.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.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 }\" :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=\"type\"\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 </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch } 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 || '')\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 { width: 100%; }\n.y-input-wrap.is-block { display: block; width: 100%; }\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@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}\n</style>\n\n\n","<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 :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 </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}\n\nconst props = withDefaults(defineProps<Props>(), {\n alt: '',\n lazy: true,\n preview: true,\n fit: 'cover',\n radius: '0',\n className: ''\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// 新增:保存原始滚动条状态\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// 工具函数\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// 生命周期\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// 监听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</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: 3000,\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\"\n :class=\"[`ytree--${size}`, { 'ytree--disabled': disabled }]\"\n >\n <div class=\"ytree__container\">\n <div\n v-for=\"node in treeData\"\n :key=\"getNodeKey(node)\"\n class=\"ytree-node\"\n :class=\"{ 'ytree-node--current': isNodeCurrent(node), 'ytree-node--highlight': isNodeHighlighted(node) }\"\n >\n <div\n class=\"ytree-node__content\"\n :class=\"{ 'is-child-style': isChildStyleNode(node, node) }\"\n :style=\"{ paddingLeft: '8px' }\"\n :data-level=\"getNodeDepth(node, node)\"\n @click=\"handleNodeClick(node, node, null, node)\"\n @contextmenu=\"handleNodeContextMenu($event, node, node, null)\"\n >\n <!-- 展开/收起图标 -->\n <span\n v-if=\"hasChildren(node)\"\n class=\"ytree-node__expand-icon\"\n :class=\"{ 'is-expanded': isNodeExpanded(node) }\"\n @click.stop=\"handleExpandClick(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\n <span v-else class=\"w-[16px]\"></span>\n\n <!-- 复选框 -->\n <span\n v-if=\"showCheckbox\"\n class=\"ytree-node__checkbox\"\n :class=\"{\n 'is-checked': isNodeChecked(node),\n 'is-indeterminate': isNodeIndeterminate(node),\n }\"\n @click.stop=\"handleCheckClick(node)\"\n >\n <svg\n v-if=\"isNodeChecked(node)\"\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=\"isNodeIndeterminate(node)\"\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=\"getNodeIcon(node, node)\"\n :alt=\"isEmployeeNode(node) ? 'person' : 'dept'\"\n />\n\n <!-- 节点标签 -->\n <span\n class=\"ytree-node__label\"\n :class=\"{ 'is-employee': isEmployeeNode(node) }\"\n >\n {{ getNodeLabel(node) }}\n </span>\n\n <!-- 自定义节点内容插槽 -->\n <div class=\"ytree-node__custom-content\">\n <slot\n name=\"node-content\"\n :node=\"node\"\n :is-current=\"isNodeCurrent(node)\"\n :is-expanded=\"isNodeExpanded(node)\"\n :has-children=\"hasChildren(node)\"\n />\n </div>\n </div>\n\n <!-- 子节点 - 递归渲染 -->\n <transition name=\"ytree-node\">\n <div\n v-if=\"hasChildren(node) && isNodeExpanded(node)\"\n class=\"ytree-node__children\"\n >\n <div\n v-for=\"child in getNodeChildren(node)\"\n :key=\"getNodeKey(child)\"\n class=\"ytree-node\"\n :class=\"{ 'ytree-node--current': isNodeCurrent(child), 'ytree-node--highlight': isNodeHighlighted(child) }\"\n >\n <div\n class=\"ytree-node__content\"\n :class=\"{ 'is-child-style': isChildStyleNode(child, node) }\"\n :style=\"{ paddingLeft: `${6 + 14 + 2}px` }\"\n :data-level=\"getNodeDepth(node, child)\"\n @click=\"handleNodeClick(child, child, null, node)\"\n @contextmenu=\"handleNodeContextMenu($event, child, child, null)\"\n >\n <!-- 展开/收起图标 -->\n <span\n v-if=\"hasChildren(child)\"\n class=\"ytree-node__expand-icon\"\n :class=\"{ 'is-expanded': isNodeExpanded(child) }\"\n @click.stop=\"handleExpandClick(child)\"\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=\"w-[16px]\"></span>\n\n <!-- 复选框 -->\n <span\n v-if=\"showCheckbox\"\n class=\"ytree-node__checkbox\"\n :class=\"{\n 'is-checked': isNodeChecked(child),\n 'is-indeterminate': isNodeIndeterminate(child),\n }\"\n @click.stop=\"handleCheckClick(child)\"\n >\n <svg\n v-if=\"isNodeChecked(child)\"\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=\"isNodeIndeterminate(child)\"\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=\"getNodeIcon(child, node)\"\n :alt=\"isEmployeeNode(child) ? 'person' : 'dept'\"\n />\n\n <!-- 节点标签 -->\n <span\n class=\"ytree-node__label\"\n :class=\"{ 'is-employee': isEmployeeNode(child) }\"\n >\n {{ getNodeLabel(child) }}\n </span>\n\n <!-- 自定义节点内容插槽 -->\n <div class=\"ytree-node__custom-content\">\n <slot\n name=\"node-content\"\n :node=\"child\"\n :is-current=\"isNodeCurrent(child)\"\n :is-expanded=\"isNodeExpanded(child)\"\n :has-children=\"hasChildren(child)\"\n />\n </div>\n </div>\n\n <!-- 第三级子节点 -->\n <transition name=\"ytree-node\">\n <div\n v-if=\"hasChildren(child) && isNodeExpanded(child)\"\n class=\"ytree-node__children\"\n >\n <div\n v-for=\"grandChild in getNodeChildren(child)\"\n :key=\"getNodeKey(grandChild)\"\n class=\"ytree-node\"\n :class=\"{\n 'ytree-node--current': isNodeCurrent(grandChild),\n 'ytree-node--highlight': isNodeHighlighted(grandChild),\n }\"\n >\n <div\n class=\"ytree-node__content\"\n :class=\"{ 'is-child-style': isChildStyleNode(grandChild, node) }\"\n :style=\"{ paddingLeft: `${6 + 14 + 2 + 14 + 2}px` }\"\n :data-level=\"getNodeDepth(node, grandChild)\"\n @click=\"handleNodeClick(grandChild, grandChild, null, node)\"\n @contextmenu=\"\n handleNodeContextMenu(\n $event,\n grandChild,\n grandChild,\n null\n )\n \"\n >\n <!-- 展开/收起图标 -->\n <span\n v-if=\"hasChildren(grandChild)\"\n class=\"ytree-node__expand-icon\"\n :class=\"{ 'is-expanded': isNodeExpanded(grandChild) }\"\n @click.stop=\"handleExpandClick(grandChild)\"\n >\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n >\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=\"w-[16px]\"></span>\n\n <!-- 复选框 -->\n <span\n v-if=\"showCheckbox\"\n class=\"ytree-node__checkbox\"\n :class=\"{\n 'is-checked': isNodeChecked(grandChild),\n 'is-indeterminate': isNodeIndeterminate(grandChild),\n }\"\n @click.stop=\"handleCheckClick(grandChild)\"\n >\n <svg\n v-if=\"isNodeChecked(grandChild)\"\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=\"isNodeIndeterminate(grandChild)\"\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=\"getNodeIcon(grandChild, node)\"\n :alt=\"isEmployeeNode(grandChild) ? 'person' : 'dept'\"\n />\n\n <!-- 节点标签 -->\n <span\n class=\"ytree-node__label\"\n :class=\"{ 'is-employee': isEmployeeNode(grandChild) }\"\n >\n {{ getNodeLabel(grandChild) }}\n </span>\n\n <!-- 自定义节点内容插槽 -->\n <div class=\"ytree-node__custom-content\">\n <slot\n name=\"node-content\"\n :node=\"grandChild\"\n :is-current=\"isNodeCurrent(grandChild)\"\n :is-expanded=\"isNodeExpanded(grandChild)\"\n :has-children=\"hasChildren(grandChild)\"\n />\n </div>\n </div>\n\n <!-- 第四级子节点 -->\n <transition name=\"ytree-node\">\n <div\n v-if=\"\n hasChildren(grandChild) && isNodeExpanded(grandChild)\n \"\n class=\"ytree-node__children\"\n >\n <div\n v-for=\"greatGrandChild in getNodeChildren(grandChild)\"\n :key=\"getNodeKey(greatGrandChild)\"\n class=\"ytree-node\"\n :class=\"{\n 'ytree-node--current':\n isNodeCurrent(greatGrandChild),\n 'ytree-node--highlight': isNodeHighlighted(greatGrandChild),\n }\"\n >\n <div\n class=\"ytree-node__content\"\n :class=\"{ 'is-child-style': isChildStyleNode(greatGrandChild, node) }\"\n :style=\"{\n paddingLeft: `${6 + 14 + 2 + 14 + 2 + 14 + 2}px`,\n }\"\n :data-level=\"getNodeDepth(node, greatGrandChild)\"\n @click=\"\n handleNodeClick(\n greatGrandChild,\n greatGrandChild,\n null,\n node\n )\n \"\n @contextmenu=\"\n handleNodeContextMenu(\n $event,\n greatGrandChild,\n greatGrandChild,\n null\n )\n \"\n >\n <!-- 展开/收起图标 -->\n <span\n v-if=\"hasChildren(greatGrandChild)\"\n class=\"ytree-node__expand-icon\"\n :class=\"{\n 'is-expanded': isNodeExpanded(greatGrandChild),\n }\"\n @click.stop=\"handleExpandClick(greatGrandChild)\"\n >\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n >\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=\"w-[16px]\"></span>\n\n <!-- 复选框 -->\n <span\n v-if=\"showCheckbox\"\n class=\"ytree-node__checkbox\"\n :class=\"{\n 'is-checked': isNodeChecked(greatGrandChild),\n 'is-indeterminate':\n isNodeIndeterminate(greatGrandChild),\n }\"\n @click.stop=\"handleCheckClick(greatGrandChild)\"\n >\n <svg\n v-if=\"isNodeChecked(greatGrandChild)\"\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=\"isNodeIndeterminate(greatGrandChild)\"\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=\"getNodeIcon(greatGrandChild, node)\"\n :alt=\"\n isEmployeeNode(greatGrandChild)\n ? 'person'\n : 'dept'\n \"\n />\n\n <!-- 节点标签 -->\n <span\n class=\"ytree-node__label\"\n :class=\"{\n 'is-employee': isEmployeeNode(greatGrandChild),\n }\"\n >\n {{ getNodeLabel(greatGrandChild) }}\n </span>\n\n <!-- 自定义节点内容插槽 -->\n <div class=\"ytree-node__custom-content\">\n <slot\n name=\"node-content\"\n :node=\"greatGrandChild\"\n :is-current=\"isNodeCurrent(greatGrandChild)\"\n :is-expanded=\"isNodeExpanded(greatGrandChild)\"\n :has-children=\"hasChildren(greatGrandChild)\"\n />\n </div>\n </div>\n\n <!-- 第五级子节点 -->\n <transition name=\"ytree-node\">\n <div\n v-if=\"\n hasChildren(greatGrandChild) &&\n isNodeExpanded(greatGrandChild)\n \"\n class=\"ytree-node__children\"\n >\n <div\n v-for=\"greatGreatGrandChild in getNodeChildren(\n greatGrandChild\n )\"\n :key=\"getNodeKey(greatGreatGrandChild)\"\n class=\"ytree-node\"\n :class=\"{\n 'ytree-node--current':\n isNodeCurrent(greatGreatGrandChild),\n }\"\n >\n <div\n class=\"ytree-node__content\"\n :class=\"{ 'is-child-style': isChildStyleNode(greatGreatGrandChild, node) }\"\n :style=\"{\n paddingLeft: `${\n 6 + 14 + 2 + 14 + 2 + 14 + 2 + 14 + 2\n }px`,\n }\"\n :data-level=\"\n getNodeDepth(node, greatGreatGrandChild)\n \"\n @click=\"\n handleNodeClick(\n greatGreatGrandChild,\n greatGreatGrandChild,\n null,\n node\n )\n \"\n @contextmenu=\"\n handleNodeContextMenu(\n $event,\n greatGreatGrandChild,\n greatGreatGrandChild,\n null\n )\n \"\n >\n <!-- 展开/收起图标 -->\n <span\n v-if=\"hasChildren(greatGreatGrandChild)\"\n class=\"ytree-node__expand-icon\"\n :class=\"{\n 'is-expanded':\n isNodeExpanded(greatGreatGrandChild),\n }\"\n @click.stop=\"\n handleExpandClick(greatGreatGrandChild)\n \"\n >\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n >\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=\"w-[16px]\"></span>\n\n <!-- 复选框 -->\n <span\n v-if=\"showCheckbox\"\n class=\"ytree-node__checkbox\"\n :class=\"{\n 'is-checked':\n isNodeChecked(greatGreatGrandChild),\n 'is-indeterminate':\n isNodeIndeterminate(\n greatGreatGrandChild\n ),\n }\"\n @click.stop=\"\n handleCheckClick(greatGreatGrandChild)\n \"\n >\n <svg\n v-if=\"isNodeChecked(greatGreatGrandChild)\"\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=\"\n isNodeIndeterminate(\n greatGreatGrandChild\n )\n \"\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=\"getNodeIcon(greatGreatGrandChild, node)\"\n :alt=\"\n isEmployeeNode(greatGreatGrandChild)\n ? 'person'\n : 'dept'\n \"\n />\n\n <!-- 节点标签 -->\n <span\n class=\"ytree-node__label\"\n :class=\"{\n 'is-employee':\n isEmployeeNode(greatGreatGrandChild),\n }\"\n >\n {{ getNodeLabel(greatGreatGrandChild) }}\n </span>\n\n <!-- 自定义节点内容插槽 -->\n <div class=\"ytree-node__custom-content\">\n <slot\n name=\"node-content\"\n :node=\"greatGreatGrandChild\"\n :is-current=\"\n isNodeCurrent(greatGreatGrandChild)\n \"\n :is-expanded=\"\n isNodeExpanded(greatGreatGrandChild)\n \"\n :has-children=\"\n hasChildren(greatGreatGrandChild)\n \"\n />\n </div>\n </div>\n </div>\n </div>\n </transition>\n </div>\n </div>\n </transition>\n </div>\n </div>\n </transition>\n </div>\n </div>\n </transition>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, provide, watch } from \"vue\";\n// import 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(\"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\nprovide(\"treeStore\", store);\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\nfunction isNodeChecked(node: TreeNode): boolean {\n const nodeKey = getNodeKey(node);\n const directlyChecked = store.value.checkedKeys.has(nodeKey);\n\n // 如果直接选中,检查是否真的是全选状态\n if (directlyChecked) {\n if (hasChildren(node)) {\n const children = getNodeChildren(node);\n const checkedChildren = children.filter((child) => isNodeChecked(child));\n const indeterminateChildren = children.filter((child) =>\n isNodeIndeterminate(child)\n );\n\n // 只有当所有子节点都被选中且没有中间状态时,才显示为选中状态\n return (\n checkedChildren.length === children.length &&\n indeterminateChildren.length === 0\n );\n }\n return true;\n }\n\n // 如果有子节点且子节点全部选中,也返回true\n if (hasChildren(node)) {\n const children = getNodeChildren(node);\n // 检查是否有子节点处于中间状态\n const hasIndeterminateChild = children.some((child) =>\n isNodeIndeterminate(child)\n );\n if (hasIndeterminateChild) return false;\n\n return (\n children.length > 0 && children.every((child) => isNodeChecked(child))\n );\n }\n\n return false;\n}\n\nfunction isNodeIndeterminate(node: TreeNode): boolean {\n if (!hasChildren(node)) return false;\n\n const children = getNodeChildren(node);\n const checkedChildren = children.filter((child) => isNodeChecked(child));\n const indeterminateChildren = children.filter((child) =>\n isNodeIndeterminate(child)\n );\n\n // 如果子节点全部选中,则当前节点应该显示为选中状态(不是中间状态)\n if (checkedChildren.length === children.length) return false;\n\n // 如果子节点部分选中或有中间状态,则显示中间状态\n return checkedChildren.length > 0 || indeterminateChildren.length > 0;\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 // 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 // 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 // 兼容旧日志,统一到可配置级别\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 // 收集所有节点\n const allNodes: TreeNode[] = [];\n\n function collectAllNodes(nodes: TreeNode[]) {\n nodes.forEach((node) => {\n allNodes.push(node);\n if (hasChildren(node)) {\n collectAllNodes(getNodeChildren(node));\n }\n });\n }\n\n collectAllNodes(treeData.value);\n\n // 从叶子节点开始,向上更新父节点状态\n function updateNodeParents(node: TreeNode) {\n if (hasChildren(node)) {\n const children = getNodeChildren(node);\n const nodeKey = getNodeKey(node);\n\n // 检查子节点状态\n const checkedChildren = children.filter((child) => isNodeChecked(child));\n const indeterminateChildren = children.filter((child) =>\n isNodeIndeterminate(child)\n );\n\n // 如果所有子节点都被选中且没有中间状态,添加父节点到checkedKeys\n if (\n checkedChildren.length === children.length &&\n indeterminateChildren.length === 0\n ) {\n store.value.checkedKeys.add(nodeKey);\n } else if (\n checkedChildren.length > 0 ||\n indeterminateChildren.length > 0\n ) {\n // 如果有子节点被选中或有中间状态,也添加父节点到checkedKeys(用于中间状态传值)\n store.value.checkedKeys.add(nodeKey);\n } else {\n // 否则从checkedKeys中移除父节点\n store.value.checkedKeys.delete(nodeKey);\n }\n }\n }\n\n // 从叶子节点开始更新(倒序遍历)\n for (let i = allNodes.length - 1; i >= 0; i--) {\n updateNodeParents(allNodes[i]);\n }\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 `已启用从第${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\nwatch(() => props.defaultExpandAll, expandAllNodes, { immediate: true });\n\n// 当树数据变化时,如果设置了 defaultExpandAll,重新展开所有节点\nwatch(() => treeData.value, expandAllNodes, { 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 }\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('highlightAndExpandByIds 执行失败', e);\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 class=\"hint-tag-content\">\n <slot>{{ content }}</slot>\n </div>\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 } 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}\n\nconst props = withDefaults(defineProps<Props>(), {\n content: '',\n position: 'right',\n defaultExpanded: true,\n width: '280px',\n tooltip: '',\n borderColor: '#00a8e8'\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\nonMounted(() => {\n if (registerHintTag) {\n registerHintTag(instance)\n }\n})\n\nonUnmounted(() => {\n if (unregisterHintTag) {\n unregisterHintTag(instance)\n }\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: 1000;\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: 6px 10px;\n line-height: 1.5;\n max-height: 150px;\n overflow-y: auto;\n white-space: normal;\n word-break: break-word;\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.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</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","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","originalBodyStyle","RADIUS_TOKEN_MAP","containerClass","radiusValue","radiusStyle","imageClass","imageStyle","resolvedPreviewSrc","getScrollbarWidth","scrollDiv","lockBodyScroll","unlockBodyScroll","observer","setupIntersectionObserver","entries","entry","handleLoad","handleError","retryLoad","getPreviewUrl","handleErrorClick","handlePreview","previewUrl","img","timeoutId","isHandled","showPreviewModal","closePreview","handleWheel","zoomDirection","newZoom","watchSrc","nv","_vShow","dropdownRef","hideTimer","menuClass","menuStyle","showDropdown","hideDropdown","menu","menuRect","absoluteTop","absoluteLeft","menuWidth","menuHeight","transitionName","roundedClass","DEPT_ICON_URL","PERSON_ICON_URL","treeData","store","effectiveRestrictLevel","getNodeKey","node","getNodeLabel","isEmployeeNode","getNodeIcon","rootNode","dept","person","button","childStyleIcon","isChildStyleNode","hasChildren","children","getNodeChildren","getNodeDepth","targetNode","currentDepth","child","depth","isNodeExpanded","nodeKey","isNodeChecked","checkedChildren","indeterminateChildren","isNodeIndeterminate","isNodeCurrent","isNodeHighlighted","handleCheckClick","newCheckedState","currentExpandedKeys","cascadeChildren","check","childKey","preventAutoExpandFourthLevel","updateAllParentNodes","_node","handleExpandClick","allNodes","collectAllNodes","nodes","updateNodeParents","handleNodeClick","data","nodeComponent","isChildStyle","handleNodeContextMenu","keys","restrictLevel","getDepthByKey","targetKey","level","n","d","collectKeysToDepth","maxDepth","newExpandedKeys","filtered","expandAllNodes","collectExpandableKeys","allExpandableKeys","expandNodesWithCheckedPermissions","findPathsToCheckedNodes","parentPath","currentPath","checkedKeys","expandableKeys","highlightAndExpandByIds","ids","findPathToKey","nk","newPath","p","targetIds","keysToExpand","targetId","clearHighlights","clearCurrentNode","grandChild","greatGrandChild","_hoisted_33","_hoisted_34","_hoisted_36","_hoisted_37","greatGreatGrandChild","_hoisted_40","_hoisted_42","_hoisted_43","_hoisted_45","isExpanded","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","_mergeProps","_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","toggle","collapse","expand","inject","components","YTable","YPagination","YBadge","YDialog","YPopover","YImage","YDropdown","YDrawer","YTree","QueryEncapsulation","HintTag","app"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.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 }\" :style=\"{ width: width }\">\n <input\n ref=\"inputRef\"\n class=\"y-input\"\n :class=\"[`y-input--${size}`, { 'y-input--password': isPasswordType }]\"\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 <span\n v-if=\"isPasswordType\"\n class=\"y-input-password-toggle\"\n :class=\"`y-input-password-toggle--${size}`\"\n @click=\"togglePasswordVisibility\"\n :title=\"showPassword ? '隐藏密码' : '显示密码'\"\n >\n <svg\n v-if=\"showPassword\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"100%\"\n height=\"100%\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\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\n v-else\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"100%\"\n height=\"100%\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\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 </span>\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 showPassword = ref<boolean>(false) // 控制密码是否可见\n\nconst isPasswordType = computed(() => props.type === 'password')\nconst actualInputType = computed(() => {\n if (isPasswordType.value) {\n return showPassword.value ? 'text' : 'password'\n }\n return props.type\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\nfunction togglePasswordVisibility() {\n showPassword.value = !showPassword.value\n // 保持焦点在输入框\n if (inputRef.value) {\n inputRef.value.focus()\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\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--tiny.y-input--password {\n padding-right: 24px;\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--mini.y-input--password {\n padding-right: 28px;\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--small.y-input--password {\n padding-right: 32px;\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--medium.y-input--password {\n padding-right: 40px;\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--large.y-input--password {\n padding-right: 44px;\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.y-input-password-toggle {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #64748b;\n transition: color 0.2s ease;\n user-select: none;\n z-index: 1;\n width: 20px;\n height: 20px;\n}\n\n.y-input-password-toggle--tiny {\n right: 6px;\n width: 14px;\n height: 14px;\n}\n\n.y-input-password-toggle--mini {\n right: 8px;\n width: 16px;\n height: 16px;\n}\n\n.y-input-password-toggle--small {\n right: 10px;\n width: 18px;\n height: 18px;\n}\n\n.y-input-password-toggle--medium {\n right: 12px;\n width: 20px;\n height: 20px;\n}\n\n.y-input-password-toggle--large {\n right: 16px;\n width: 20px;\n height: 20px;\n}\n\n.y-input-password-toggle:hover {\n color: #60a5fa;\n}\n\n.y-input-password-toggle svg {\n display: block;\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 \n .y-input-password-toggle {\n color: #94a3b8;\n }\n \n .y-input-password-toggle:hover {\n color: #60a5fa;\n }\n}\n</style>\n\n\n","<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 :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 </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}\n\nconst props = withDefaults(defineProps<Props>(), {\n alt: '',\n lazy: true,\n preview: true,\n fit: 'cover',\n radius: '0',\n className: ''\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// 新增:保存原始滚动条状态\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// 工具函数\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// 生命周期\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// 监听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</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: 3000,\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': isNodeCurrent(node),\n 'ytree-node--highlight': isNodeHighlighted(node),\n }\"\n >\n <div\n class=\"ytree-node__content\"\n :class=\"{ 'is-child-style': isChildStyleNode(node, rootNode) }\"\n :style=\"{ paddingLeft: `${calculatePaddingLeft(level)}px` }\"\n :data-level=\"getNodeDepth(rootNode, node)\"\n @click=\"handleNodeClick(node, node, null, rootNode)\"\n @contextmenu=\"handleNodeContextMenu($event, node, node, null)\"\n >\n <!-- 展开/收起图标 -->\n <span\n v-if=\"hasChildren(node)\"\n class=\"ytree-node__expand-icon\"\n :class=\"{ 'is-expanded': isNodeExpanded(node) }\"\n @click.stop=\"handleExpandClick(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': isNodeChecked(node),\n 'is-indeterminate': isNodeIndeterminate(node),\n }\"\n @click.stop=\"handleCheckClick(node)\"\n >\n <svg\n v-if=\"isNodeChecked(node)\"\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=\"isNodeIndeterminate(node)\"\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=\"getNodeIcon(node, rootNode)\"\n :alt=\"isEmployeeNode(node) ? 'person' : 'dept'\"\n />\n\n <!-- 节点标签 -->\n <span\n class=\"ytree-node__label\"\n :class=\"{ 'is-employee': isEmployeeNode(node) }\"\n >\n {{ getNodeLabel(node) }}\n </span>\n\n <!-- 自定义节点内容插槽 -->\n <div class=\"ytree-node__custom-content\">\n <slot\n name=\"node-content\"\n :node=\"node\"\n :is-current=\"isNodeCurrent(node)\"\n :is-expanded=\"isNodeExpanded(node)\"\n :has-children=\"hasChildren(node)\"\n />\n </div>\n </div>\n\n <!-- 子节点 - 递归渲染 -->\n <transition name=\"ytree-node\">\n <div\n v-if=\"hasChildren(node) && isNodeExpanded(node)\"\n class=\"ytree-node__children\"\n >\n <YTreeNode\n v-for=\"child in getNodeChildren(node)\"\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 } 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// 计算 paddingLeft,每级增加 16px (14px 图标 + 2px 间距)\nfunction calculatePaddingLeft(level: number): number {\n if (level === 1) {\n return 8;\n }\n // 第一级是 8px,之后每级增加 16px (14px 图标宽度 + 2px 间距)\n return 8 + (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 } 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(\"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\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\nfunction isNodeChecked(node: TreeNode): boolean {\n const nodeKey = getNodeKey(node);\n const directlyChecked = store.value.checkedKeys.has(nodeKey);\n\n // 如果直接选中,检查是否真的是全选状态\n if (directlyChecked) {\n if (hasChildren(node)) {\n const children = getNodeChildren(node);\n const checkedChildren = children.filter((child) => isNodeChecked(child));\n const indeterminateChildren = children.filter((child) =>\n isNodeIndeterminate(child)\n );\n\n // 只有当所有子节点都被选中且没有中间状态时,才显示为选中状态\n return (\n checkedChildren.length === children.length &&\n indeterminateChildren.length === 0\n );\n }\n return true;\n }\n\n // 如果有子节点且子节点全部选中,也返回true\n if (hasChildren(node)) {\n const children = getNodeChildren(node);\n // 检查是否有子节点处于中间状态\n const hasIndeterminateChild = children.some((child) =>\n isNodeIndeterminate(child)\n );\n if (hasIndeterminateChild) return false;\n\n return (\n children.length > 0 && children.every((child) => isNodeChecked(child))\n );\n }\n\n return false;\n}\n\nfunction isNodeIndeterminate(node: TreeNode): boolean {\n if (!hasChildren(node)) return false;\n\n const children = getNodeChildren(node);\n const checkedChildren = children.filter((child) => isNodeChecked(child));\n const indeterminateChildren = children.filter((child) =>\n isNodeIndeterminate(child)\n );\n\n // 如果子节点全部选中,则当前节点应该显示为选中状态(不是中间状态)\n if (checkedChildren.length === children.length) return false;\n\n // 如果子节点部分选中或有中间状态,则显示中间状态\n return checkedChildren.length > 0 || indeterminateChildren.length > 0;\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 // 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 // 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 // 兼容旧日志,统一到可配置级别\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 // 收集所有节点\n const allNodes: TreeNode[] = [];\n\n function collectAllNodes(nodes: TreeNode[]) {\n nodes.forEach((node) => {\n allNodes.push(node);\n if (hasChildren(node)) {\n collectAllNodes(getNodeChildren(node));\n }\n });\n }\n\n collectAllNodes(treeData.value);\n\n // 从叶子节点开始,向上更新父节点状态\n function updateNodeParents(node: TreeNode) {\n if (hasChildren(node)) {\n const children = getNodeChildren(node);\n const nodeKey = getNodeKey(node);\n\n // 检查子节点状态\n const checkedChildren = children.filter((child) => isNodeChecked(child));\n const indeterminateChildren = children.filter((child) =>\n isNodeIndeterminate(child)\n );\n\n // 如果所有子节点都被选中且没有中间状态,添加父节点到checkedKeys\n if (\n checkedChildren.length === children.length &&\n indeterminateChildren.length === 0\n ) {\n store.value.checkedKeys.add(nodeKey);\n } else if (\n checkedChildren.length > 0 ||\n indeterminateChildren.length > 0\n ) {\n // 如果有子节点被选中或有中间状态,也添加父节点到checkedKeys(用于中间状态传值)\n store.value.checkedKeys.add(nodeKey);\n } else {\n // 否则从checkedKeys中移除父节点\n store.value.checkedKeys.delete(nodeKey);\n }\n }\n }\n\n // 从叶子节点开始更新(倒序遍历)\n for (let i = allNodes.length - 1; i >= 0; i--) {\n updateNodeParents(allNodes[i]);\n }\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 `已启用从第${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\nwatch(() => props.defaultExpandAll, expandAllNodes, { immediate: true });\n\n// 当树数据变化时,如果设置了 defaultExpandAll,重新展开所有节点\nwatch(() => treeData.value, expandAllNodes, { 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 }\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('highlightAndExpandByIds 执行失败', e);\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 class=\"hint-tag-content\">\n <slot>{{ content }}</slot>\n </div>\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 } 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}\n\nconst props = withDefaults(defineProps<Props>(), {\n content: '',\n position: 'right',\n defaultExpanded: true,\n width: '280px',\n tooltip: '',\n borderColor: '#00a8e8'\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\nonMounted(() => {\n if (registerHintTag) {\n registerHintTag(instance)\n }\n})\n\nonUnmounted(() => {\n if (unregisterHintTag) {\n unregisterHintTag(instance)\n }\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: 1000;\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: 6px 10px;\n line-height: 1.5;\n max-height: 150px;\n overflow-y: auto;\n white-space: normal;\n word-break: break-word;\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.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</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","showPassword","isPasswordType","actualInputType","watch","val","onInput","target","onFocus","onBlur","current","minVal","onEnter","onPaste","togglePasswordVisibility","_normalizeClass","_hoisted_4","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_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","originalBodyStyle","RADIUS_TOKEN_MAP","containerClass","radiusValue","radiusStyle","imageClass","imageStyle","resolvedPreviewSrc","getScrollbarWidth","scrollDiv","lockBodyScroll","unlockBodyScroll","observer","setupIntersectionObserver","entries","entry","handleLoad","handleError","retryLoad","getPreviewUrl","handleErrorClick","handlePreview","previewUrl","img","timeoutId","isHandled","showPreviewModal","closePreview","handleWheel","zoomDirection","newZoom","watchSrc","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","calculatePaddingLeft","level","_unref","child","YTreeNode","_withCtx","slotProps","_mergeProps","DEPT_ICON_URL","PERSON_ICON_URL","treeData","store","effectiveRestrictLevel","node","rootNode","dept","person","button","childStyleIcon","children","targetNode","currentDepth","depth","nodeKey","checkedChildren","indeterminateChildren","newCheckedState","currentExpandedKeys","cascadeChildren","check","childKey","preventAutoExpandFourthLevel","updateAllParentNodes","_node","allNodes","collectAllNodes","nodes","updateNodeParents","data","nodeComponent","isChildStyle","keys","restrictLevel","getDepthByKey","targetKey","n","d","collectKeysToDepth","maxDepth","newExpandedKeys","filtered","expandAllNodes","collectExpandableKeys","allExpandableKeys","expandNodesWithCheckedPermissions","findPathsToCheckedNodes","parentPath","currentPath","checkedKeys","expandableKeys","highlightAndExpandByIds","ids","findPathToKey","nk","newPath","p","targetIds","keysToExpand","targetId","clearHighlights","clearCurrentNode","isExpanded","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","toggle","collapse","expand","components","YTable","YPagination","YBadge","YDialog","YPopover","YImage","YDropdown","YDrawer","YTree","QueryEncapsulation","HintTag","app"],"mappings":"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"}