@rft-rc/recycle-ui 0.0.2 → 0.0.3-rc.11
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.
- package/README.md +38 -34
- package/dist/components/button/index.d.ts.map +1 -1
- package/dist/components/button/index.vue.d.ts +25 -6
- package/dist/components/button/index.vue.d.ts.map +1 -1
- package/dist/components/calendar/index.d.ts +5 -0
- package/dist/components/calendar/index.d.ts.map +1 -0
- package/dist/components/calendar/index.vue.d.ts +64 -0
- package/dist/components/calendar/index.vue.d.ts.map +1 -0
- package/dist/components/calendar/panel-content.vue.d.ts +38 -0
- package/dist/components/calendar/panel-content.vue.d.ts.map +1 -0
- package/dist/components/card/index.vue.d.ts +2 -2
- package/dist/components/card/index.vue.d.ts.map +1 -1
- package/dist/components/checkbox/button.vue.d.ts +51 -0
- package/dist/components/checkbox/button.vue.d.ts.map +1 -0
- package/dist/components/checkbox/group.vue.d.ts +58 -0
- package/dist/components/checkbox/group.vue.d.ts.map +1 -0
- package/dist/components/checkbox/index.d.ts +8 -0
- package/dist/components/checkbox/index.d.ts.map +1 -0
- package/dist/components/checkbox/index.vue.d.ts +60 -0
- package/dist/components/checkbox/index.vue.d.ts.map +1 -0
- package/dist/components/descriptions/index.d.ts +12 -0
- package/dist/components/descriptions/index.d.ts.map +1 -1
- package/dist/components/descriptions/index.vue.d.ts +3 -0
- package/dist/components/descriptions/index.vue.d.ts.map +1 -1
- package/dist/components/descriptions/item.vue.d.ts +3 -0
- package/dist/components/descriptions/item.vue.d.ts.map +1 -1
- package/dist/components/dropdown/index.d.ts +8 -0
- package/dist/components/dropdown/index.d.ts.map +1 -0
- package/dist/components/dropdown/index.vue.d.ts +49 -0
- package/dist/components/dropdown/index.vue.d.ts.map +1 -0
- package/dist/components/dropdown/item.vue.d.ts +24 -0
- package/dist/components/dropdown/item.vue.d.ts.map +1 -0
- package/dist/components/dropdown/menu.vue.d.ts +32 -0
- package/dist/components/dropdown/menu.vue.d.ts.map +1 -0
- package/dist/components/dropdown/types.d.ts +2 -0
- package/dist/components/dropdown/types.d.ts.map +1 -0
- package/dist/components/form/index.d.ts +8 -0
- package/dist/components/form/index.d.ts.map +1 -0
- package/dist/components/form/index.vue.d.ts +76 -0
- package/dist/components/form/index.vue.d.ts.map +1 -0
- package/dist/components/form/item.vue.d.ts +49 -0
- package/dist/components/form/item.vue.d.ts.map +1 -0
- package/dist/components/icon/index.d.ts +1 -1
- package/dist/components/icon/index.d.ts.map +1 -1
- package/dist/components/icon/index.vue.d.ts +1 -1
- package/dist/components/icon/index.vue.d.ts.map +1 -1
- package/dist/components/input/index.d.ts +5 -0
- package/dist/components/input/index.d.ts.map +1 -0
- package/dist/components/input/index.vue.d.ts +158 -0
- package/dist/components/input/index.vue.d.ts.map +1 -0
- package/dist/components/popup/index.d.ts +5 -0
- package/dist/components/popup/index.d.ts.map +1 -0
- package/dist/components/popup/index.vue.d.ts +70 -0
- package/dist/components/popup/index.vue.d.ts.map +1 -0
- package/dist/components/radio/button.vue.d.ts +42 -0
- package/dist/components/radio/button.vue.d.ts.map +1 -0
- package/dist/components/radio/group.vue.d.ts +50 -0
- package/dist/components/radio/group.vue.d.ts.map +1 -0
- package/dist/components/radio/index.d.ts +8 -0
- package/dist/components/radio/index.d.ts.map +1 -0
- package/dist/components/radio/index.vue.d.ts +48 -0
- package/dist/components/radio/index.vue.d.ts.map +1 -0
- package/dist/components/search-area/index.vue.d.ts +51 -11
- package/dist/components/search-area/index.vue.d.ts.map +1 -1
- package/dist/components/toast/index.vue.d.ts +2 -2
- package/dist/components/toast/index.vue.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +3190 -492
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +15 -4
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/components/button/index.vue","../src/components/button/index.ts","../src/components/descriptions/item.vue","../src/components/descriptions/index.vue","../src/components/descriptions/index.ts","../src/components/card/index.vue","../src/components/card/index.ts","../src/components/toast/index.vue","../src/components/toast/index.ts","../src/components/message/index.vue","../src/components/message/index.ts","../src/components/icon/index.vue","../src/components/icon/index.ts","../src/components/search-area/index.vue","../src/components/search-area/index.ts","../src/index.ts"],"sourcesContent":["<template>\r\n <button\r\n class=\"rc-button\"\r\n :class=\"[`rc-button--${type}`, `rc-button--${size}`, { 'is-plain': plain, 'is-block': block, 'is-disabled': disabled, 'is-loading': loading }]\"\r\n :style=\"{ borderRadius: radius }\"\r\n :disabled=\"disabled || loading\"\r\n @click=\"onClick\"\r\n >\r\n <span v-if=\"loading\" class=\"rc-button__spinner\" />\r\n <slot>{{ label }}</slot>\r\n </button>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from 'vue';\r\ntype ButtonType = 'default' | 'primary' | 'success' | 'warning' | 'danger';\r\ntype ButtonSize = 'mini' | 'small' | 'medium' | 'large';\r\n\r\ninterface Props {\r\n type?: ButtonType;\r\n size?: ButtonSize;\r\n plain?: boolean;\r\n block?: boolean;\r\n /** 按钮文本,提供时可不写默认插槽 */\r\n label?: string;\r\n /** 圆角;number 代表 px,string 支持百分比等写法(如 '50%')。也兼容 boolean,true 表示大圆角。 */\r\n round?: number | string | boolean;\r\n disabled?: boolean;\r\n loading?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n type: 'default',\r\n size: 'medium',\r\n plain: false,\r\n block: false,\r\n label: '',\r\n round: 6,\r\n disabled: false,\r\n loading: false,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n (e: 'click', ev: MouseEvent): void\r\n}>();\r\n\r\nconst onClick = (ev: MouseEvent) => {\r\n if (!props.disabled && !props.loading) emit('click', ev);\r\n};\r\n\r\nconst radius = computed(() => {\r\n const v = props.round;\r\n if (typeof v === 'boolean') return v ? '999px' : '6px';\r\n if (typeof v === 'number') return `${v}px`;\r\n return String(v);\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-button {\r\n --rc-primary: #1677ff;\r\n --rc-success: #00b578;\r\n --rc-warning: #ff8f1f;\r\n --rc-danger: #ff3141;\r\n --rc-text: #323233;\r\n --rc-border: #dcdee0;\r\n --rc-white: #ffffff;\r\n\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 36px;\r\n padding: 0 16px;\r\n border: 1px solid var(--rc-border);\r\n border-radius: 6px;\r\n background: var(--rc-white);\r\n color: var(--rc-text);\r\n cursor: pointer;\r\n user-select: none;\r\n transition: all .2s ease;\r\n\r\n &.is-disabled { cursor: not-allowed; opacity: .6; }\r\n &.is-block { display: flex; width: 100%; }\r\n &.is-plain { background: var(--rc-white); }\r\n &.is-loading { opacity: .85; }\r\n\r\n &__spinner {\r\n width: 14px;\r\n height: 14px;\r\n margin-right: 6px;\r\n border: 2px solid currentColor;\r\n border-top-color: transparent;\r\n border-radius: 50%;\r\n animation: rc-spin 0.8s linear infinite;\r\n }\r\n\r\n &--primary { background: var(--rc-primary); color: var(--rc-white); border-color: var(--rc-primary); }\r\n &--success { background: var(--rc-success); color: var(--rc-white); border-color: var(--rc-success); }\r\n &--warning { background: var(--rc-warning); color: var(--rc-white); border-color: var(--rc-warning); }\r\n &--danger { background: var(--rc-danger); color: var(--rc-white); border-color: var(--rc-danger); }\r\n\r\n &--mini { height: 24px; padding: 0 8px; font-size: 12px; }\r\n &--small { height: 28px; padding: 0 10px; font-size: 13px; }\r\n &--medium { height: 36px; padding: 0 16px; font-size: 14px; }\r\n &--large { height: 44px; padding: 0 20px; font-size: 16px; }\r\n}\r\n\r\n@keyframes rc-spin { to { transform: rotate(360deg) } }\r\n</style>\r\n\r\n\r\n\r\n","import type { App } from 'vue';\r\nimport Button from './index.vue';\r\n\r\n// 组件名使用全小写,以 <rc-button> 形式在模板中使用\r\n(Button as any).name = 'rc-button';\r\n\r\nexport function install(app: App) {\r\n app.component((Button as any).name, Button);\r\n return app;\r\n}\r\n\r\n\r\nexport default Button;\r\n","<template>\n <div class=\"rc-desc-item\" :style=\"{ width: computedWidth, flex: `0 0 ${computedWidth}` }\">\n <div class=\"rc-desc-item__label\" :style=\"labelStyle\">\n <slot name=\"label\">\n {{ label }}\n </slot>\n </div>\n <div class=\"rc-desc-item__value\">\n <slot>\n {{ value }}\n </slot>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject, Ref } from 'vue';\n\ndefineOptions({ name: 'rc-descriptions-item' });\n\nconst props = withDefaults(defineProps<{\n label?: string | number;\n value?: any;\n labelWidth?: string | number;\n /** 跨越的列数,默认 1,可传字符串数字 */\n span?: number | string;\n}>(), {\n label: '',\n value: '',\n labelWidth: '',\n span: 1,\n});\n\nconst providedWidth = inject<Ref<string>>('rcDescItemWidth', undefined as unknown as Ref<string>);\nconst providedSingleWidth = inject<Ref<string> | string>('rcDescSingleWidth', '' as unknown as Ref<string>);\nconst providedGap = inject<string>('rcDescGap', '0px');\nconst providedGapPx = inject<Ref<number> | number>('rcDescGapPx', 0 as unknown as Ref<number>);\nconst providedColCount = inject<Ref<number> | number>('rcDescColCount', 1 as unknown as Ref<number>);\nconst providedLabelWidth = inject<Ref<string> | string>('rcDescLabelWidth', '' as unknown as Ref<string>);\n\nconst spanNum = computed(() => {\n const n = typeof props.span === 'string' ? parseInt(props.span, 10) : props.span;\n const max = typeof (providedColCount as any)?.value === 'number' ? (providedColCount as any).value : (providedColCount as any);\n const safe = !Number.isNaN(n as number) && (n as number) > 0 ? (n as number) : 1;\n return Math.min(safe, max || 1);\n});\n\nconst computedWidth = computed(() => {\n const n = typeof (providedColCount as any)?.value === 'number' ? (providedColCount as any).value : (providedColCount as any);\n const gapPx = typeof (providedGapPx as any)?.value === 'number' ? (providedGapPx as any).value : (providedGapPx as any);\n const k = spanNum.value;\n if (!n || n <= 1) return '100%';\n if (k >= n) return '100%';\n // 展开为单层 calc:((100% - (n-1)*gap) * k / n + (k-1)*gap)\n const totalGap = (n - 1) * gapPx;\n const interGap = (k - 1) * gapPx;\n return `calc((100% - ${totalGap}px) * ${k} / ${n} + ${interGap}px)`;\n});\n\nconst labelStyle = computed(() => {\n const injected = typeof (providedLabelWidth as any)?.value === 'string'\n ? (providedLabelWidth as any).value\n : (providedLabelWidth as any);\n const w = props.labelWidth !== '' ? props.labelWidth : (injected || '');\n return w ? { width: typeof w === 'number' ? `${w}px` : String(w), flex: '0 0 auto' } : {};\n});\n</script>\n\n<style scoped>\n.rc-desc-item {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n padding: 6px 0;\n flex: 0 0 auto;\n}\n.rc-desc-item__label {\n color: #666;\n font-size: 14px;\n line-height: 22px;\n /* 不强制最小宽度,交由 label-width 控制 */\n min-width: 0;\n}\n.rc-desc-item__value {\n flex: 1 1 auto;\n font-size: 14px;\n line-height: 22px;\n}\n\n</style>\n\n\n","<template>\n <div class=\"rc-descriptions\">\n <div v-if=\"$slots.title || title\" class=\"rc-descriptions__title\">\n <slot name=\"title\">\n {{ title }}\n </slot>\n </div>\n <div class=\"rc-descriptions__body\" :style=\"{ gap: gapStyle }\" ref=\"wrapEl\">\n <template v-if=\"normalizedData.length\">\n <rcDescriptionsItem\n v-for=\"(it, idx) in normalizedData\"\n :key=\"idx\"\n :label=\"it.label\"\n :value=\"it.value\"\n :label-width=\"labelWidth\"\n />\n </template>\n <slot v-else />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, provide, ref, watchEffect } from 'vue';\nimport rcDescriptionsItem from './item.vue';\n\ndefineOptions({ name: 'rc-descriptions' });\n\ntype KeyMap = { key: string; value: string };\n\nconst props = withDefaults(defineProps<{\n title?: string;\n /** 每行展示的列数,支持数字或字符串数字 */\n column?: number | string;\n /** 列间距,支持数字(px)或字符串值,例如 '12px' */\n gap?: number | string;\n /** label 固定宽度,数字代表 px,也可直接传入 '120px' */\n labelWidth?: number | string | '';\n /** 直接通过数据渲染 */\n data?: Array<Record<string, any>>;\n /** data 的字段映射,如 { key: 'label', value: 'value' } */\n keyMap?: KeyMap;\n}>(), {\n column: 2,\n gap: 4,\n labelWidth: '',\n data: () => [],\n});\n\nconst wrapEl = ref<HTMLElement | null>(null);\nconst gapStyle = computed(() => (typeof props.gap === 'number' ? `${props.gap}px` : String(props.gap)));\nconst colCount = computed(() => {\n const n = typeof props.column === 'string' ? Number.parseInt(props.column as string, 10) : (props.column ?? 1);\n return !Number.isNaN(n) && n > 0 ? n : 1;\n});\n\n// compute child item width as percentage string or 'auto'\nconst itemWidth = ref<string>('100%');\nconst singleWidth = ref<string>('100%');\nwatchEffect(() => {\n const n = colCount.value;\n if (n <= 1) {\n itemWidth.value = '100%';\n singleWidth.value = '100%';\n } else {\n // subtract total horizontal gaps from 100%\n const gapPx = typeof props.gap === 'number' ? props.gap : parseFloat(String(props.gap)) || 0;\n const totalGap = (n - 1) * gapPx;\n const base = `calc((100% - ${totalGap}px) / ${n})`;\n singleWidth.value = base;\n itemWidth.value = base;\n }\n});\n\nprovide('rcDescItemWidth', itemWidth);\nprovide('rcDescSingleWidth', singleWidth);\nprovide('rcDescColCount', colCount);\nprovide('rcDescGapPx', computed(() => (typeof props.gap === 'number' ? props.gap : parseFloat(String(props.gap)) || 0)));\nconst labelWidthCss = computed(() => {\n if (props.labelWidth === '' || props.labelWidth === undefined) return '';\n return typeof props.labelWidth === 'number' ? `${props.labelWidth}px` : String(props.labelWidth);\n});\nprovide('rcDescLabelWidth', labelWidthCss);\nprovide('rcDescGap', computed(() => (typeof props.gap === 'number' ? `${props.gap}px` : String(props.gap))));\n\nconst normalizedData = computed(() => {\n const keyK = (props.keyMap?.key ?? 'label') as string;\n const keyV = (props.keyMap?.value ?? 'value') as string;\n if (!props.data?.length) return [];\n return props.data.map((it) => ({\n label: it?.[keyK],\n value: it?.[keyV],\n }));\n});\n\n</script>\n\n<style scoped>\n.rc-descriptions {\n width: 100%;\n}\n.rc-descriptions__title {\n font-weight: 600;\n font-size: 16px;\n margin: 0 0 12px 0;\n}\n.rc-description__row {\n display: contents;\n}\n.rc-descriptions__body {\n display: flex;\n flex-wrap: wrap;\n}\n\n</style>\n\n\n","import type { App } from 'vue';\r\nimport Descriptions from './index.vue';\r\nimport DescriptionsItem from './item.vue';\r\n\r\n(Descriptions as any).name = 'rc-descriptions';\r\n(DescriptionsItem as any).name = 'rc-descriptions-item';\r\n\r\nexport function install(app: App) {\r\n // 同时注册 kebab 与 PascalCase 名称,便于 <rc-descriptions>/<RcDescriptions> 使用\r\n app.component((Descriptions as any).name, Descriptions);\r\n app.component('RcDescriptions', Descriptions);\r\n app.component((DescriptionsItem as any).name, DescriptionsItem);\r\n app.component('RcDescriptionsItem', DescriptionsItem);\r\n return app;\r\n}\r\n\r\nexport const RcDescriptions = Descriptions;\r\nexport const RcDescriptionsItem = DescriptionsItem;\r\n\r\nexport default Descriptions;\r\n\r\n\r\n\r\n","<template>\n <div\n class=\"rc-card\"\n :class=\"[{ 'rc-card--bordered': bordered }]\"\n :style=\"wrapperStyle\"\n >\n <div\n v-if=\"$slots.title || title || $slots.status || status\"\n class=\"rc-card__top\"\n :style=\"{ backgroundColor: topBgColor || 'rgba(29, 133, 252, 0.05)' }\"\n >\n <div class=\"rc-card__title\">\n <slot name=\"title\">\n <span class=\"rc-card__title-text\">{{ title }}</span>\n </slot>\n </div>\n <div class=\"rc-card__status\" v-if=\"$slots.status || status\">\n <slot name=\"status\">\n <span class=\"rc-card__status-text\" :style=\"{ color: statusColor || 'var(--rc-primary)' }\">\n {{ status }}\n </span>\n </slot>\n </div>\n </div>\n\n <div class=\"rc-card__body\" :style=\"{ padding: bodyPadding, gap: bodyGap }\">\n <slot name=\"content\">\n <slot />\n </slot>\n </div>\n\n <div v-if=\"$slots.action\" class=\"rc-card__divider\" />\n\n <div v-if=\"$slots.action\" class=\"rc-card__action\">\n <slot name=\"action\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\ndefineOptions({ name: 'rc-card' });\n\ninterface Props {\n /** 卡片整体背景色,默认白色 */\n color?: string;\n /** 顶部色块背景色 */\n topBgColor?: string;\n /** 标题文本(可用 slot=\"title\" 自定义) */\n title?: string;\n /** 右侧状态文案(可用 slot=\"status\" 自定义) */\n status?: string;\n /** 状态文本颜色 */\n statusColor?: string;\n /** 圆角:数值代表 px,字符串可用百分比 */\n round?: number | string;\n /** 是否描边 */\n bordered?: boolean;\n /** 阴影强度:0/1/2/3... -> 转换为不同阴影强度 */\n elevation?: number;\n /** 内边距(CSS 值,如 '16px 12px') */\n padding?: string;\n /** 主体内容的垂直间距(px 或 CSS 字符串) */\n gap?: number | string;\n /** 宽度(px/百分比) */\n width?: string | number;\n /** 高度(px/百分比) */\n height?: string | number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n color: 'var(--rc-white)',\n topBgColor: 'rgba(29, 133, 252, 0.05)',\n title: '',\n status: '',\n statusColor: 'var(--rc-primary)',\n round: 8,\n bordered: false,\n elevation: 2,\n padding: '16px',\n gap: 12,\n width: '100%',\n height: '',\n});\n\nconst wrapperStyle = computed(() => {\n const radius =\n typeof props.round === 'boolean'\n ? props.round\n ? '12px'\n : '0'\n : typeof props.round === 'number'\n ? `${props.round}px`\n : String(props.round);\n\n return {\n backgroundColor: props.color || 'var(--rc-white)',\n borderRadius: radius,\n boxShadow: shadowByLevel(props.elevation),\n width: toCssSize(props.width),\n height: toCssSize(props.height),\n } as Record<string, string>;\n});\n\nconst bodyPadding = computed(() => props.padding || '16px');\nconst bodyGap = computed(() =>\n typeof props.gap === 'number' ? `${props.gap}px` : String(props.gap)\n);\n\nfunction toCssSize(v?: string | number) {\n if (v === undefined || v === null || v === '') return '';\n return typeof v === 'number' ? `${v}px` : String(v);\n}\n\nfunction shadowByLevel(level: number) {\n if (!level || level <= 0) return 'none';\n // 简单的多层阴影(可按需微调)\n const base = 4 * level;\n return `0 ${Math.round(base / 2)}px ${base}px rgba(0,0,0,0.06), 0 ${Math.round(\n base / 4\n )}px ${Math.round(base / 2)}px rgba(0,0,0,0.04)`;\n}\n</script>\n\n<style scoped>\n.rc-card {\n --rc-white: #ffffff;\n --rc-border: #e5e6eb;\n --rc-primary: #1677ff;\n\n display: flex;\n flex-direction: column;\n width: 100%;\n border: 1px solid transparent;\n background: var(.rc-white);\n}\n.rc-card--bordered {\n border-color: var(--rc-border);\n}\n\n.rc-card__top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-top-left-radius: inherit;\n border-top-right-radius: inherit;\n}\n.rc-card__title {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.rc-card__title-text {\n font-weight: 600;\n font-size: 16px;\n color: #1d2129;\n}\n.rc-card__status-text {\n font-size: 14px;\n}\n.rc-card__body {\n display: flex;\n flex-direction: column;\n}\n.rc-card__divider {\n height: 1px;\n background: var(--rc-border);\n}\n.rc-card__action {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n}\n</style>\n\n\n","import type { App } from 'vue';\r\nimport Card from './index.vue';\r\n\r\n// 同时注册小写与驼峰,便于 <rc-card> / <RcCard> 两种写法\r\n(Card as any).name = 'rc-card';\r\nconst PascalName = 'RcCard';\r\n\r\nexport function install(app: App) {\r\n app.component((Card as any).name, Card);\r\n app.component(PascalName, Card);\r\n return app;\r\n}\r\n\r\nexport default Card;\r\n\r\n\r\n","<template>\r\n <teleport to=\"body\">\r\n <transition name=\"rc-toast-fade\" @after-leave=\"onAfterLeave\">\r\n <div v-if=\"visible\" class=\"rc-toast\" :class=\"[`rc-toast--${type}`]\">\r\n <div v-if=\"mask\" class=\"rc-toast__mask\" />\r\n <div class=\"rc-toast__content\">\r\n <div v-if=\"type === 'loading'\" class=\"rc-toast__spinner\" />\r\n <div v-else-if=\"type === 'success'\" class=\"rc-toast__icon rc-toast__icon--success\" />\r\n <div v-else-if=\"type === 'fail'\" class=\"rc-toast__icon rc-toast__icon--fail\" />\r\n <div class=\"rc-toast__text\">{{ message }}</div>\r\n </div>\r\n </div>\r\n </transition>\r\n </teleport>\r\n <slot />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { onMounted, onUnmounted, ref, watch, defineExpose } from 'vue';\r\n\r\nexport type ToastType = 'text' | 'success' | 'fail' | 'loading';\r\nexport interface ToastProps {\r\n message?: string;\r\n type?: ToastType;\r\n duration?: number;\r\n mask?: boolean;\r\n /** 服务端关闭回调,用于卸载容器 */\r\n onAfterLeave?: () => void;\r\n}\r\n\r\nconst props = withDefaults(defineProps<ToastProps>(), {\r\n message: '',\r\n type: 'text',\r\n duration: 2000,\r\n mask: false,\r\n});\r\n\r\nconst visible = ref(true);\r\nlet timer: any;\r\n\r\nfunction clearTimer() {\r\n if (timer) {\r\n clearTimeout(timer);\r\n timer = null;\r\n }\r\n}\r\n\r\nfunction close() {\r\n clearTimer();\r\n visible.value = false;\r\n}\r\n\r\ndefineExpose({ close });\r\n\r\nonMounted(() => {\r\n if (props.duration && props.duration > 0) {\r\n timer = setTimeout(() => {\r\n close();\r\n }, props.duration);\r\n }\r\n});\r\n\r\nonUnmounted(() => {\r\n clearTimer();\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.rc-toast {\r\n position: fixed;\r\n inset: 0;\r\n z-index: 9999;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n.rc-toast__mask {\r\n position: absolute;\r\n inset: 0;\r\n background: rgba(0, 0, 0, 0.35);\r\n pointer-events: auto;\r\n backdrop-filter: blur(1px);\r\n}\r\n.rc-toast__content {\r\n position: relative;\r\n max-width: 80%;\r\n background: rgba(0, 0, 0, 0.75);\r\n color: #fff;\r\n border-radius: 12px;\r\n padding: 12px 14px;\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 8px;\r\n box-shadow: 0 6px 16px rgba(0,0,0,0.2);\r\n}\r\n.rc-toast__text {\r\n font-size: 14px;\r\n line-height: 1.4;\r\n}\r\n.rc-toast__spinner {\r\n width: 18px;\r\n height: 18px;\r\n border: 2px solid rgba(255,255,255,0.35);\r\n border-top-color: #fff;\r\n border-radius: 50%;\r\n animation: rc-toast-spin 0.8s linear infinite;\r\n}\r\n.rc-toast__icon {\r\n width: 18px;\r\n height: 18px;\r\n border-radius: 50%;\r\n position: relative;\r\n flex: 0 0 18px;\r\n}\r\n.rc-toast__icon--success::before {\r\n content: '';\r\n position: absolute;\r\n left: 3px;\r\n top: 3px;\r\n width: 10px;\r\n height: 10px;\r\n border-right: 2px solid #fff;\r\n border-bottom: 2px solid #fff;\r\n transform: rotate(45deg);\r\n}\r\n.rc-toast__icon--fail::before,\r\n.rc-toast__icon--fail::after {\r\n content: '';\r\n position: absolute;\r\n left: 3px;\r\n right: 3px;\r\n top: 8px;\r\n height: 2px;\r\n background: #fff;\r\n}\r\n.rc-toast__icon--fail::before {\r\n transform: rotate(45deg);\r\n}\r\n.rc-toast__icon--fail::after {\r\n transform: rotate(-45deg);\r\n}\r\n\r\n.rc-toast-fade-enter-active,\r\n.rc-toast-fade-leave-active {\r\n transition: opacity .2s ease;\r\n}\r\n.rc-toast-fade-enter-from,\r\n.rc-toast-fade-leave-to {\r\n opacity: 0;\r\n}\r\n@keyframes rc-toast-spin {\r\n to { transform: rotate(360deg); }\r\n}\r\n</style>\r\n\r\n\r\n","import { App, createApp } from 'vue';\r\nimport Toast, { type ToastProps } from './index.vue';\r\n\r\nexport type { ToastProps };\r\nexport interface ShowToastOptions {\r\n message?: string;\r\n type?: 'text' | 'success' | 'fail' | 'loading';\r\n duration?: number;\r\n mask?: boolean;\r\n /** 关闭时回调(仅服务方式有效) */\r\n onClose?: () => void;\r\n}\r\n\r\nlet app: App<Element> | null = null;\r\nlet host: HTMLDivElement | null = null;\r\n\r\nfunction unmount() {\r\n if (app) {\r\n app.unmount();\r\n app = null;\r\n }\r\n if (host) {\r\n document.body.removeChild(host);\r\n host = null;\r\n }\r\n}\r\n\r\nexport function showToast(options: string | ShowToastOptions) {\r\n const opt: ShowToastOptions =\r\n typeof options === 'string' ? { message: options } : (options || {});\r\n unmount();\r\n host = document.createElement('div');\r\n document.body.appendChild(host);\r\n const toastProps: ToastProps = {\r\n message: opt.message,\r\n type: (opt as any).type ?? 'text',\r\n duration: (opt as any).duration ?? 2000,\r\n mask: (opt as any).mask ?? false,\r\n onAfterLeave: () => {\r\n unmount();\r\n opt.onClose?.();\r\n },\r\n };\r\n app = createApp(Toast, toastProps as any);\r\n app.mount(host);\r\n return {\r\n close: hideToast,\r\n };\r\n}\r\n\r\nexport function hideToast() {\r\n if (!app) return;\r\n // 调用暴露的 close 方法\r\n // @ts-ignore\r\n app._instance?.exposed?.close?.();\r\n}\r\n\r\n// 组件注册(可选,提供 rc-toast 用于手动放置 Portal)\r\n(Toast as any).name = 'rc-toast';\r\nexport function install(app: App) {\r\n app.component((Toast as any).name, Toast);\r\n return app;\r\n}\r\n\r\nexport default Toast;\r\n\r\n\r\n","<template>\r\n <div class=\"rc-message\" role=\"alert\" aria-live=\"polite\">\r\n <transition-group name=\"rc-message-fade\" tag=\"div\">\r\n <div\r\n v-for=\"m in messages\"\r\n :key=\"m.id\"\r\n class=\"rc-message__item\"\r\n :class=\"`rc-message--${m.type}`\"\r\n >\r\n <span class=\"rc-message__content\">{{ m.content }}</span>\r\n </div>\r\n </transition-group>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { reactive } from 'vue';\r\n\r\nexport type MessageType = 'info' | 'success' | 'warning' | 'error' | 'loading';\r\nexport interface MessageItem {\r\n id: number;\r\n type: MessageType;\r\n content: string;\r\n duration: number; // ms; 0 = persistent (except loading default)\r\n}\r\n\r\nconst messages = reactive<MessageItem[]>([]);\r\nlet uid = 1;\r\n\r\nfunction remove(id: number) {\r\n const idx = messages.findIndex((x) => x.id === id);\r\n if (idx >= 0) messages.splice(idx, 1);\r\n}\r\n\r\nfunction add(type: MessageType, content: string, duration: number) {\r\n const id = uid++;\r\n messages.push({ id, type, content, duration });\r\n if (duration > 0) {\r\n window.setTimeout(() => remove(id), duration);\r\n }\r\n return id;\r\n}\r\n\r\ndefineExpose({ add, remove });\r\n</script>\r\n\r\n<style scoped>\r\n.rc-message {\r\n position: fixed;\r\n top: 16px;\r\n left: 0;\r\n right: 0;\r\n z-index: 10000;\r\n pointer-events: none;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n.rc-message__item {\r\n pointer-events: auto;\r\n min-width: 120px;\r\n max-width: 80%;\r\n padding: 8px 12px;\r\n border-radius: 6px;\r\n color: #fff;\r\n background: rgba(0, 0, 0, 0.78);\r\n box-shadow: 0 6px 16px rgba(0,0,0,0.2);\r\n font-size: 14px;\r\n}\r\n.rc-message--success { background: rgba(22,119,255,0.9); }\r\n.rc-message--warning { background: rgba(250,173,20,0.95); }\r\n.rc-message--error { background: rgba(245,63,63,0.95); }\r\n.rc-message--info { background: rgba(0,0,0,0.78); }\r\n.rc-message--loading { background: rgba(0,0,0,0.78); }\r\n\r\n.rc-message-fade-enter-active,\r\n.rc-message-fade-leave-active {\r\n transition: all .2s ease;\r\n}\r\n.rc-message-fade-enter-from,\r\n.rc-message-fade-leave-to {\r\n opacity: 0;\r\n transform: translateY(-6px);\r\n}\r\n</style>\r\n\r\n\r\n","import { createVNode, render, type App } from 'vue';\r\nimport MessageHost from './index.vue';\r\n\r\ntype MessageType = 'info' | 'success' | 'warning' | 'error' | 'loading';\r\n\r\nexport interface MessageOptions {\r\n content: string;\r\n duration?: number; // ms; default 2000, loading 默认 0\r\n type?: MessageType;\r\n}\r\n\r\nlet container: HTMLElement | null = null;\r\nlet hostExposed: any = null;\r\n\r\nfunction ensureHost() {\r\n if (container && hostExposed) return;\r\n container = document.createElement('div');\r\n document.body.appendChild(container);\r\n const vnode = createVNode(MessageHost, {});\r\n render(vnode, container);\r\n hostExposed = (vnode.component as any)?.exposed;\r\n}\r\n\r\nfunction open(type: MessageType, content: string, duration?: number) {\r\n ensureHost();\r\n const d = typeof duration === 'number'\r\n ? duration\r\n : (type === 'loading' ? 0 : 2000);\r\n return hostExposed?.add?.(type, content, d);\r\n}\r\n\r\nexport const message = {\r\n open(opts: MessageOptions) {\r\n return open(opts.type || 'info', opts.content, opts.duration);\r\n },\r\n info(content: string, duration?: number) {\r\n return open('info', content, duration);\r\n },\r\n success(content: string, duration?: number) {\r\n return open('success', content, duration);\r\n },\r\n warning(content: string, duration?: number) {\r\n return open('warning', content, duration);\r\n },\r\n error(content: string, duration?: number) {\r\n return open('error', content, duration);\r\n },\r\n loading(content: string, duration?: number) {\r\n return open('loading', content, duration);\r\n },\r\n destroy() {\r\n if (container) {\r\n render(null, container);\r\n container.remove();\r\n container = null;\r\n hostExposed = null;\r\n }\r\n },\r\n};\r\n\r\nexport default message;\r\n\r\n// 可选:提供 install,注入到 app.config.globalProperties 以便 this.$message 使用\r\nexport function install(app: App) {\r\n (app.config.globalProperties as any).$message = message;\r\n return app;\r\n}\r\n\r\n\r\n","<template>\r\n <i\r\n class=\"rc-icon\"\r\n :class=\"[baseClass, iconClassName, { 'rc-icon--spin': spin }]\"\r\n :style=\"iconStyle\"\r\n aria-hidden=\"true\"\r\n >\r\n <span v-if=\"char\" class=\"rc-icon__unicode\">{{ char }}</span>\r\n </i>\r\n </template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, inject, onMounted } from 'vue';\r\nimport type { RecycleUIOptions } from '../../types';\r\nimport { RECYCLE_UI_SYMBOL, defaultRecycleUIConfig } from '../../index';\r\n\r\ndefineOptions({ name: 'rc-icon' });\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 图标名,例如 'icon_a_in_store',也可直接传完整类名 */\r\n name: string;\r\n /** 尺寸,数字按 px 处理,也可传 '1.2em' 等 */\r\n size?: number | string;\r\n /** 颜色 */\r\n color?: string;\r\n /** 是否旋转(用于 loading 类图标) */\r\n spin?: boolean;\r\n /** Unicode 码点(不带 \\\\u,十六进制,如 'e609' 或 0xe609),用于无类名时渲染 */\r\n code?: string | number;\r\n}>(), {\r\n size: 16,\r\n color: '',\r\n spin: false,\r\n code: '',\r\n});\r\n\r\nconst cfg = inject<RecycleUIOptions>(RECYCLE_UI_SYMBOL, {} as RecycleUIOptions);\r\n\r\nconst baseClass = computed(() => cfg?.iconClass || 'iconfont');\r\nconst iconClassName = computed(() => props.name || '');\r\n\r\nconst sizeCss = computed(() => (typeof props.size === 'number' ? `${props.size}px` : (props.size || '16px')));\r\nconst iconStyle = computed(() => ({\r\n fontSize: sizeCss.value,\r\n color: props.color || undefined,\r\n lineHeight: 1,\r\n fontFamily: cfg?.iconClass || 'iconfont',\r\n}));\r\n\r\n// 将 code 转为字符\r\nconst char = computed(() => {\r\n const c = props.code as any;\r\n if (c === undefined || c === null || c === '' || c === 0) return '';\r\n if (typeof c === 'number') {\r\n return String.fromCharCode(c);\r\n }\r\n const hex = String(c).replace(/^0x/i, '');\r\n const num = parseInt(hex, 16);\r\n if (Number.isNaN(num)) return '';\r\n return String.fromCharCode(num);\r\n});\r\n\r\n// 兜底:若未通过 app.use 安装插件,则在组件挂载时尝试注入默认的 iconfont 样式\r\nonMounted(() => {\r\n if (typeof window === 'undefined') return;\r\n const url = (cfg && cfg.iconCssUrl) || defaultRecycleUIConfig.iconCssUrl;\r\n if (!url) return;\r\n const selector = `link[rel=\"stylesheet\"][data-rcui-icon=\"true\"][href=\"${url}\"]`;\r\n const exists = document.head.querySelector(selector);\r\n if (!exists) {\r\n const link = document.createElement('link');\r\n link.rel = 'stylesheet';\r\n link.href = url as string;\r\n link.setAttribute('data-rcui-icon', 'true');\r\n document.head.appendChild(link);\r\n }\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.rc-icon {\r\n display: inline-block;\r\n vertical-align: -0.125em;\r\n}\r\n.rc-icon__unicode {\r\n /* 让 Unicode 文本走同一字体,确保显示 */\r\n font-family: inherit;\r\n line-height: 1;\r\n}\r\n.rc-icon--spin {\r\n animation: rc-icon-rot 1s linear infinite;\r\n}\r\n@keyframes rc-icon-rot {\r\n to { transform: rotate(360deg); }\r\n}\r\n</style>\r\n\r\n\r\n","import type { App } from 'vue';\r\nimport Icon from './index.vue';\r\n\r\n(Icon as any).name = 'rc-icon';\r\n\r\nexport function install(app: App) {\r\n app.component((Icon as any).name, Icon);\r\n app.component('RcIcon', Icon);\r\n return app;\r\n}\r\n\r\nexport const RcIcon = Icon;\r\nexport default Icon;\r\n\r\n\r\n","<template>\r\n <div class=\"rc-search-area\">\r\n <!-- 筛选项按钮行 -->\r\n <div class=\"rc-search-area__bar\">\r\n <div\r\n v-for=\"(item, index) in props.items\"\r\n :key=\"index\"\r\n class=\"rc-search-area__item\"\r\n :class=\"{ \r\n 'is-active': activeIndex === index,\r\n 'has-value': getSelectedCount(item) > 0\r\n }\"\r\n @click=\"openFilter(index)\"\r\n >\r\n <span class=\"rc-search-area__item-label\">{{ getItemDisplayText(item) }}</span>\r\n <rc-icon \r\n name=\"icon_a-xiala2\" \r\n :color=\"(activeIndex !== index && getSelectedCount(item) > 0) ? '#1677ff' : '#969799'\"\r\n class=\"rc-search-area__item-arrow\" \r\n :class=\"{ 'is-up': activeIndex === index }\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 蒙层 -->\r\n <transition name=\"rc-search-area-fade\">\r\n <div \r\n v-if=\"activeIndex !== null && props.showMask\" \r\n ref=\"maskRef\"\r\n class=\"rc-search-area__mask\"\r\n :style=\"maskStyle\"\r\n @click=\"closeFilter\"\r\n ></div>\r\n </transition>\r\n\r\n <!-- 筛选面板 -->\r\n <transition name=\"rc-search-area-slide\">\r\n <div v-if=\"activeIndex !== null\" ref=\"panelRef\" class=\"rc-search-area__panel\">\r\n <div class=\"rc-search-area__panel-content\">\r\n <!-- 单选模式 -->\r\n <template v-if=\"currentFilter?.type === 'single'\">\r\n <div class=\"rc-search-area__options-grid\">\r\n <div\r\n v-for=\"(option, optIdx) in currentFilter.options\"\r\n :key=\"optIdx\"\r\n class=\"rc-search-area__option\"\r\n :class=\"{ 'is-selected': isSelected(option) }\"\r\n @click=\"selectSingle(option)\"\r\n >\r\n <span class=\"rc-search-area__option-label\">{{ getOptionLabel(option) }}</span>\r\n <rc-icon v-if=\"isSelected(option)\" name=\"icon_select\" class=\"rc-search-area__option-check\" />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- 多选模式 -->\r\n <template v-else>\r\n <div class=\"rc-search-area__options-grid\">\r\n <div\r\n v-for=\"(option, optIdx) in currentFilter?.options || []\"\r\n :key=\"optIdx\"\r\n class=\"rc-search-area__option\"\r\n :class=\"{ 'is-selected': isSelected(option) }\"\r\n @click=\"toggleOption(option)\"\r\n >\r\n <span class=\"rc-search-area__option-label\">{{ getOptionLabel(option) }}</span>\r\n <rc-icon v-if=\"isSelected(option)\" name=\"icon_select\" class=\"rc-search-area__option-check\" />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- 无结果提示 -->\r\n <div v-if=\"currentFilter?.options?.length === 0\" class=\"rc-search-area__empty\">\r\n <p>暂无选项</p>\r\n </div>\r\n </div>\r\n\r\n <div class=\"rc-search-area__panel-footer\">\r\n <rc-button \r\n block \r\n @click=\"resetCurrentFilter\"\r\n >\r\n 重置\r\n </rc-button>\r\n <rc-button \r\n type=\"primary\"\r\n block \r\n @click=\"confirmFilter\"\r\n >\r\n 确定{{ selectedCountText }}\r\n </rc-button>\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, ref, watch, nextTick, onUnmounted } from 'vue';\r\nimport RcIcon from '../icon';\r\nimport RcButton from '../button';\r\n\r\ndefineOptions({ name: 'rc-search-area' });\r\n\r\nexport interface FilterOption {\r\n label: string;\r\n value: any;\r\n [key: string]: any;\r\n}\r\n\r\nexport interface FilterItem {\r\n /** 筛选项标签 */\r\n label: string;\r\n /** 筛选项唯一标识 */\r\n key: string;\r\n /** 选项列表 */\r\n options: FilterOption[] | string[];\r\n /** 筛选类型:single 单选,multiple 多选(默认) */\r\n type?: 'single' | 'multiple';\r\n /** 多选时的列数(默认 2) */\r\n column?: number;\r\n}\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 筛选项配置 */\r\n items: FilterItem[];\r\n /** 当前筛选值(支持 v-model) */\r\n modelValue?: Record<string, any>;\r\n /** 是否显示蒙层 */\r\n showMask?: boolean;\r\n}>(), {\r\n items: () => [],\r\n modelValue: () => ({}),\r\n showMask: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n /** v-model 更新事件 */\r\n (e: 'update:modelValue', values: Record<string, any>): void;\r\n /** 筛选条件变化时触发 */\r\n (e: 'change', values: Record<string, any>, item: FilterItem): void;\r\n /** 确认筛选时触发 */\r\n (e: 'confirm', values: Record<string, any>, item: FilterItem): void;\r\n /** 重置筛选时触发 */\r\n (e: 'reset', key?: string): void;\r\n /** 某个筛选项的值被修改并确认时触发 */\r\n (e: 'item-change', key: string, value: any): void;\r\n}>();\r\n\r\n// 当前打开的筛选项索引\r\nconst activeIndex = ref<number | null>(null);\r\n\r\n// 面板和蒙层的 ref\r\nconst panelRef = ref<HTMLElement | null>(null);\r\nconst maskRef = ref<HTMLElement | null>(null);\r\n\r\n// 蒙层样式 - 从面板底部开始\r\nconst maskStyle = ref<{ top: string }>({ top: '0px' });\r\n\r\n// 计算蒙层位置\r\nconst updateMaskPosition = async () => {\r\n if (activeIndex.value === null || !panelRef.value) {\r\n return;\r\n }\r\n await nextTick();\r\n const panelRect = panelRef.value.getBoundingClientRect();\r\n const panelTop = panelRect.top;\r\n maskStyle.value = { top: `${panelTop}px` };\r\n};\r\n\r\n// 处理点击外部区域关闭面板\r\nconst handleClickOutside = (event: MouseEvent) => {\r\n if (activeIndex.value === null || !panelRef.value) {\r\n return;\r\n }\r\n \r\n const target = event.target as HTMLElement;\r\n \r\n // 检查点击的目标是否在面板内部\r\n if (panelRef.value.contains(target)) {\r\n return;\r\n }\r\n \r\n // 检查是否点击的是筛选项按钮(避免点击按钮时关闭)\r\n const searchAreaEl = panelRef.value.closest('.rc-search-area');\r\n if (searchAreaEl) {\r\n const barEl = searchAreaEl.querySelector('.rc-search-area__bar');\r\n if (barEl && barEl.contains(target)) {\r\n // 点击的是筛选项按钮,不关闭面板(由按钮的点击事件处理)\r\n return;\r\n }\r\n }\r\n \r\n // 点击的是外部区域,关闭面板\r\n closeFilter();\r\n};\r\n\r\n// 监听面板打开,更新蒙层位置和添加外部点击监听\r\nwatch(activeIndex, async (newVal) => {\r\n if (newVal !== null) {\r\n await nextTick();\r\n updateMaskPosition();\r\n // 监听窗口大小变化和滚动,更新蒙层位置\r\n window.addEventListener('resize', updateMaskPosition);\r\n window.addEventListener('scroll', updateMaskPosition, true);\r\n // 添加点击外部区域关闭面板的监听\r\n document.addEventListener('click', handleClickOutside, true);\r\n } else {\r\n window.removeEventListener('resize', updateMaskPosition);\r\n window.removeEventListener('scroll', updateMaskPosition, true);\r\n document.removeEventListener('click', handleClickOutside, true);\r\n }\r\n});\r\n\r\n// 组件卸载时清理事件监听器\r\nonUnmounted(() => {\r\n window.removeEventListener('resize', updateMaskPosition);\r\n window.removeEventListener('scroll', updateMaskPosition, true);\r\n document.removeEventListener('click', handleClickOutside, true);\r\n});\r\n\r\n// 每个筛选项的选中值(临时状态,用于模态窗内选择)\r\nconst tempSelectedValues = ref<Record<string, any>>({});\r\n\r\n// 已确认的筛选值\r\nconst confirmedValues = ref<Record<string, any>>({ ...props.modelValue });\r\n\r\n// 监听外部传入的 modelValue 变化\r\nwatch(() => props.modelValue, (newValue) => {\r\n confirmedValues.value = { ...(newValue || {}) };\r\n}, { deep: true, immediate: true });\r\n\r\n// 当前打开的筛选项\r\nconst currentFilter = computed(() => {\r\n if (activeIndex.value === null) return null;\r\n return props.items[activeIndex.value];\r\n});\r\n\r\n// 确定按钮文本\r\nconst selectedCountText = computed(() => {\r\n if (!currentFilter.value) return '';\r\n const count = getTempSelectedCount(currentFilter.value);\r\n return count > 0 ? `(${count}项)` : '';\r\n});\r\n\r\n// 获取筛选项的显示文本\r\nconst getItemDisplayText = (item: FilterItem): string => {\r\n const value = confirmedValues.value[item.key];\r\n if (value === undefined || value === null || value === '') {\r\n return item.label;\r\n }\r\n \r\n if (item.type === 'single') {\r\n const option = findOption(item, value);\r\n if (option) {\r\n return `${item.label}: ${getOptionLabel(option)}`;\r\n }\r\n } else {\r\n // 多选\r\n const values = Array.isArray(value) ? value : [value];\r\n if (values.length > 0) {\r\n const labels = values\r\n .map((val) => {\r\n const opt = findOption(item, val);\r\n return opt ? getOptionLabel(opt) : null;\r\n })\r\n .filter((label) => label !== null);\r\n \r\n if (labels.length > 0) {\r\n return `${item.label}: ${labels.join('、')}`;\r\n }\r\n }\r\n }\r\n \r\n return item.label;\r\n};\r\n\r\n// 打开筛选模态窗\r\nconst openFilter = (index: number) => {\r\n const item = props.items[index];\r\n if (!item) return;\r\n \r\n // 如果点击的是当前已打开的筛选项,则收起\r\n if (activeIndex.value === index) {\r\n activeIndex.value = null;\r\n return;\r\n }\r\n \r\n // 初始化临时选中值\r\n const currentValue = confirmedValues.value[item.key];\r\n if (item.type === 'single') {\r\n tempSelectedValues.value[item.key] = currentValue !== undefined ? currentValue : null;\r\n } else {\r\n tempSelectedValues.value[item.key] = currentValue !== undefined \r\n ? (Array.isArray(currentValue) ? [...currentValue] : [currentValue])\r\n : [];\r\n }\r\n \r\n activeIndex.value = index;\r\n};\r\n\r\n// 关闭筛选模态窗\r\nconst closeFilter = () => {\r\n activeIndex.value = null;\r\n};\r\n\r\n// 获取选项的显示文本\r\nconst getOptionLabel = (option: FilterOption | string): string => {\r\n if (typeof option === 'string') return option;\r\n return option.label || String(option.value);\r\n};\r\n\r\n// 获取选项的值\r\nconst getOptionValue = (option: FilterOption | string): any => {\r\n if (typeof option === 'string') return option;\r\n return option.value !== undefined ? option.value : option;\r\n};\r\n\r\n// 查找选项\r\nconst findOption = (item: FilterItem, value: any): FilterOption | string | null => {\r\n return item.options.find((opt) => {\r\n const optValue = getOptionValue(opt);\r\n return optValue === value || String(optValue) === String(value);\r\n }) || null;\r\n};\r\n\r\n// 判断选项是否被选中(临时状态)\r\nconst isSelected = (option: FilterOption | string): boolean => {\r\n if (!currentFilter.value) return false;\r\n const key = currentFilter.value.key;\r\n const tempValue = tempSelectedValues.value[key];\r\n const optValue = getOptionValue(option);\r\n \r\n if (currentFilter.value.type === 'single') {\r\n return tempValue !== null && tempValue !== undefined && tempValue === optValue;\r\n } else {\r\n const tempArray = Array.isArray(tempValue) ? tempValue : [];\r\n return tempArray.some((v) => v === optValue || String(v) === String(optValue));\r\n }\r\n};\r\n\r\n// 单选\r\nconst selectSingle = (option: FilterOption | string) => {\r\n if (!currentFilter.value) return;\r\n const key = currentFilter.value.key;\r\n const optValue = getOptionValue(option);\r\n \r\n // 如果已选中,则取消选中\r\n if (tempSelectedValues.value[key] === optValue) {\r\n tempSelectedValues.value[key] = null;\r\n } else {\r\n tempSelectedValues.value[key] = optValue;\r\n }\r\n};\r\n\r\n// 多选切换\r\nconst toggleOption = (option: FilterOption | string) => {\r\n if (!currentFilter.value) return;\r\n const key = currentFilter.value.key;\r\n const optValue = getOptionValue(option);\r\n const tempArray = Array.isArray(tempSelectedValues.value[key]) \r\n ? [...tempSelectedValues.value[key]] \r\n : [];\r\n \r\n const existingIndex = tempArray.findIndex(\r\n (v) => v === optValue || String(v) === String(optValue)\r\n );\r\n \r\n if (existingIndex >= 0) {\r\n tempArray.splice(existingIndex, 1);\r\n } else {\r\n tempArray.push(optValue);\r\n }\r\n \r\n tempSelectedValues.value[key] = tempArray;\r\n};\r\n\r\n// 重置当前筛选项\r\nconst resetCurrentFilter = () => {\r\n if (!currentFilter.value) return;\r\n const key = currentFilter.value.key;\r\n if (currentFilter.value.type === 'single') {\r\n tempSelectedValues.value[key] = null;\r\n } else {\r\n tempSelectedValues.value[key] = [];\r\n }\r\n};\r\n\r\n// 确认筛选\r\nconst confirmFilter = () => {\r\n if (!currentFilter.value) return;\r\n const key = currentFilter.value.key;\r\n const tempValue = tempSelectedValues.value[key];\r\n const oldValue = confirmedValues.value[key];\r\n \r\n // 更新已确认的值\r\n let newValue: any;\r\n if (currentFilter.value.type === 'single') {\r\n newValue = tempValue !== null && tempValue !== undefined ? tempValue : undefined;\r\n confirmedValues.value[key] = newValue;\r\n } else {\r\n newValue = Array.isArray(tempValue) && tempValue.length > 0 ? tempValue : undefined;\r\n confirmedValues.value[key] = newValue;\r\n }\r\n \r\n // 更新 v-model\r\n emit('update:modelValue', { ...confirmedValues.value });\r\n \r\n // 触发事件\r\n emit('change', { ...confirmedValues.value }, currentFilter.value);\r\n emit('confirm', { ...confirmedValues.value }, currentFilter.value);\r\n \r\n // 如果值发生变化,触发 item-change 事件\r\n const valueChanged = JSON.stringify(oldValue) !== JSON.stringify(newValue);\r\n if (valueChanged) {\r\n emit('item-change', key, newValue);\r\n }\r\n \r\n closeFilter();\r\n};\r\n\r\n// 获取已选中的数量(已确认的)\r\nconst getSelectedCount = (item: FilterItem): number => {\r\n const value = confirmedValues.value[item.key];\r\n if (value === undefined || value === null || value === '') return 0;\r\n \r\n if (item.type === 'single') {\r\n return 1;\r\n } else {\r\n return Array.isArray(value) ? value.length : (value ? 1 : 0);\r\n }\r\n};\r\n\r\n// 获取临时选中的数量\r\nconst getTempSelectedCount = (item: FilterItem): number => {\r\n const tempValue = tempSelectedValues.value[item.key];\r\n if (tempValue === undefined || tempValue === null || tempValue === '') return 0;\r\n \r\n if (item.type === 'single') {\r\n return 1;\r\n } else {\r\n return Array.isArray(tempValue) ? tempValue.length : 0;\r\n }\r\n};\r\n\r\n// 暴露方法供外部调用\r\ndefineExpose({\r\n /** 获取当前筛选值 */\r\n getValues: () => ({ ...confirmedValues.value }),\r\n /** 重置所有筛选 */\r\n reset: () => {\r\n confirmedValues.value = {};\r\n tempSelectedValues.value = {};\r\n emit('update:modelValue', {});\r\n emit('change', {}, null as any);\r\n emit('reset');\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-search-area {\r\n position: relative;\r\n width: 100%;\r\n\r\n &__bar {\r\n display: flex;\r\n align-items: center;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n -webkit-overflow-scrolling: touch;\r\n scrollbar-width: none;\r\n -ms-overflow-style: none;\r\n touch-action: pan-x;\r\n padding: 4px 8px;\r\n box-sizing: border-box;\r\n\r\n &::-webkit-scrollbar {\r\n display: none;\r\n }\r\n }\r\n\r\n &__item {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 4px 6px;\r\n font-size: 14px;\r\n color: #323233;\r\n cursor: pointer;\r\n user-select: none;\r\n -webkit-user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n transition: all 0.2s;\r\n white-space: nowrap;\r\n flex-shrink: 0;\r\n flex-grow: 0;\r\n background: #f0f0f0;\r\n border: 1px solid transparent;\r\n border-radius: 4px;\r\n margin-right: 8px;\r\n max-width: calc(100% - 16px);\r\n min-width: 0;\r\n\r\n &:last-child {\r\n margin-right: 0;\r\n }\r\n\r\n &.has-value {\r\n border-color: #1677ff;\r\n color: #1677ff;\r\n background: #fff;\r\n }\r\n\r\n &.is-active {\r\n background: #f0f0f0;\r\n border-color: transparent;\r\n color: #323233;\r\n\r\n &::after {\r\n content: '';\r\n border: 1px solid #f0f0f0;\r\n position: absolute;\r\n bottom: -8px;\r\n width: 100%;\r\n height: 8px;\r\n background: #f0f0f0;\r\n }\r\n }\r\n\r\n &-label {\r\n margin-right: 4px;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n min-width: 0;\r\n flex: 1;\r\n max-width: 100%;\r\n }\r\n\r\n &-count {\r\n min-width: 16px;\r\n height: 16px;\r\n padding: 0 4px;\r\n margin-right: 4px;\r\n background: #1677ff;\r\n color: #fff;\r\n border-radius: 8px;\r\n font-size: 11px;\r\n line-height: 16px;\r\n text-align: center;\r\n }\r\n\r\n &-arrow {\r\n font-size: 10px;\r\n color: #969799;\r\n transition: transform 0.2s;\r\n transform: rotate(0deg);\r\n flex-shrink: 0;\r\n\r\n &.is-up {\r\n transform: rotate(180deg);\r\n }\r\n }\r\n }\r\n\r\n &__mask {\r\n position: fixed;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background: rgba(0, 0, 0, 0.5);\r\n z-index: 999;\r\n }\r\n\r\n &__panel {\r\n position: absolute;\r\n top: 100%;\r\n left: 0;\r\n right: 0;\r\n max-height: 70vh;\r\n background: #f0f0f0;\r\n z-index: 1000;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n border-bottom-right-radius: 8px;\r\n border-bottom-left-radius: 8px;\r\n }\r\n\r\n &__panel-content {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 8px;\r\n }\r\n\r\n &__options-grid {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 12px;\r\n }\r\n\r\n &__option {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 4px 6px;\r\n background: #f7f8fa;\r\n border: 1px solid #dcdee0;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n transition: all 0.2s;\r\n white-space: nowrap;\r\n flex-shrink: 0;\r\n\r\n &:hover {\r\n border-color: #1677ff;\r\n }\r\n\r\n &.is-selected {\r\n background: #e6f4ff;\r\n border-color: #1677ff;\r\n color: #1677ff;\r\n }\r\n\r\n &-label {\r\n font-size: 14px;\r\n }\r\n\r\n &-check {\r\n color: #1677ff;\r\n }\r\n }\r\n\r\n &__empty {\r\n padding: 40px 0;\r\n text-align: center;\r\n color: #969799;\r\n font-size: 14px;\r\n }\r\n\r\n &__panel-footer {\r\n display: flex;\r\n gap: 12px;\r\n padding: 8px;\r\n border-top: 1px solid #eee;\r\n flex-shrink: 0;\r\n }\r\n}\r\n\r\n// 过渡动画\r\n.rc-search-area-fade-enter-active,\r\n.rc-search-area-fade-leave-active {\r\n transition: opacity 0.3s ease-out;\r\n}\r\n\r\n.rc-search-area-fade-enter-from,\r\n.rc-search-area-fade-leave-to {\r\n opacity: 0;\r\n}\r\n\r\n.rc-search-area-fade-enter-to,\r\n.rc-search-area-fade-leave-from {\r\n opacity: 1;\r\n}\r\n\r\n.rc-search-area-slide-enter-active,\r\n.rc-search-area-slide-leave-active {\r\n transition: max-height 0.3s ease-out, opacity 0.3s ease-out;\r\n overflow: hidden;\r\n}\r\n\r\n.rc-search-area-slide-enter-from,\r\n.rc-search-area-slide-leave-to {\r\n max-height: 0;\r\n opacity: 0;\r\n}\r\n\r\n.rc-search-area-slide-enter-to,\r\n.rc-search-area-slide-leave-from {\r\n max-height: 70vh;\r\n opacity: 1;\r\n}\r\n</style>\r\n\r\n","/**\r\n * @description 基础用法\r\n */\r\nimport type { App } from 'vue';\r\nimport RcSearchArea from './index.vue';\r\n\r\nexport { RcSearchArea };\r\nexport type { FilterItem, FilterOption } from './index.vue';\r\n\r\nexport const install = (app: App) => {\r\n app.component('RcSearchArea', RcSearchArea);\r\n app.component('rc-search-area', RcSearchArea);\r\n};\r\n\r\nexport default RcSearchArea;\r\n\r\n","// library entry\r\nimport type { App, Plugin } from 'vue';\r\nimport { install as installButton } from './components/button';\r\nimport { install as installDescriptions } from './components/descriptions';\r\nimport { install as installCard } from './components/card';\r\nimport { install as installToast } from './components/toast';\r\nimport { install as installMessage } from './components/message';\r\nimport { install as installIcon } from './components/icon/index';\r\nimport { install as installSearchArea } from './components/search-area';\r\nimport type { RecycleUIOptions } from './types';\r\n\r\nexport const RECYCLE_UI_SYMBOL = Symbol('RECYCLE_UI_CONFIG');\r\n\r\nexport const defaultRecycleUIConfig: RecycleUIOptions = {\r\n prefix: 'rc',\r\n autoRegister: true,\r\n provideKey: RECYCLE_UI_SYMBOL,\r\n // 预留主题/其他全局配置\r\n theme: {},\r\n // IconFont 默认配置(可在 app.use 时覆盖)\r\n iconCssUrl: '//at.alicdn.com/t/c/font_4252799_9vcnw0pnmkh.css',\r\n iconClass: 'iconfont',\r\n};\r\n\r\n// 统一导出所有类型的命名空间\r\nexport namespace RecycleUiTypes {\r\n // 核心配置类型\r\n export type Options = RecycleUIOptions;\r\n export type DefaultConfig = typeof defaultRecycleUIConfig;\r\n \r\n // Message 相关类型\r\n export type MessageOptions = import('./components/message').MessageOptions;\r\n export type MessageType = import('./components/message/index.vue').MessageType;\r\n export type MessageItem = import('./components/message/index.vue').MessageItem;\r\n \r\n // Toast 相关类型\r\n export type ToastProps = import('./components/toast/index.vue').ToastProps;\r\n export type ToastType = import('./components/toast/index.vue').ToastType;\r\n export type ShowToastOptions = import('./components/toast').ShowToastOptions;\r\n}\r\n\r\nfunction doAutoRegister(app: App, opts: RecycleUIOptions) {\r\n if (opts.autoRegister === false) return;\r\n if (typeof installButton === 'function') installButton(app);\r\n if (typeof installDescriptions === 'function') installDescriptions(app);\r\n if (typeof installCard === 'function') installCard(app);\r\n if (typeof installToast === 'function') installToast(app);\r\n if (typeof installIcon === 'function') installIcon(app);\r\n if (typeof installMessage === 'function') installMessage(app);\r\n if (typeof installSearchArea === 'function') installSearchArea(app);\r\n}\r\n\r\nexport const install = (app: App, options?: RecycleUIOptions) => {\r\n const cfg: RecycleUIOptions = { ...defaultRecycleUIConfig, ...(options || {}) };\r\n // 提供全局配置\r\n app.provide(cfg.provideKey ?? RECYCLE_UI_SYMBOL, cfg);\r\n // 供模板/实例访问:this.$recycleUI\r\n (app.config.globalProperties as any).$recycleUI = cfg;\r\n // 注入 IconFont 样式链接(浏览器环境)\r\n if (typeof window !== 'undefined' && cfg.iconCssUrl) {\r\n const selector = `link[rel=\"stylesheet\"][data-rcui-icon=\"true\"][href=\"${cfg.iconCssUrl}\"]`;\r\n const exists = document.head.querySelector(selector);\r\n if (!exists) {\r\n const link = document.createElement('link');\r\n link.rel = 'stylesheet';\r\n link.href = cfg.iconCssUrl;\r\n link.setAttribute('data-rcui-icon', 'true');\r\n document.head.appendChild(link);\r\n }\r\n }\r\n // 自动注册内置组件(可通过 autoRegister 关闭)\r\n doAutoRegister(app, cfg);\r\n return app;\r\n};\r\n\r\n// 默认导出为插件,支持 app.use(recycleUi, options)\r\nconst plugin: Plugin = { install };\r\nexport default plugin;\r\n\r\n// 也导出命名组件安装器与默认配置(defaultRecycleUIConfig 已在上方以常量形式导出)\r\n\r\n// 可选:工厂方法,便于创建带预设配置的插件\r\nexport function createRecycleUI(options?: RecycleUIOptions): Plugin {\r\n return {\r\n install(app: App) {\r\n install(app, options);\r\n },\r\n };\r\n}\r\n\r\n// 按需导出组件与其安装器(供文档与业务直接使用)\r\nexport { default as RcButton } from './components/button';\r\nexport { RcDescriptions, RcDescriptionsItem } from './components/descriptions';\r\nexport { install as installButton } from './components/button';\r\nexport { install as installDescriptions } from './components/descriptions';\r\nexport { default as RcCard } from './components/card';\r\nexport { install as installCard } from './components/card';\r\n// 兼容别名导出(文档示例中的 rcXxx)\r\nexport { RcDescriptions as rcDescriptions, RcDescriptionsItem as rcDescriptionsItem } from './components/descriptions';\r\n// Toast 服务导出\r\nexport { default as RcToast, showToast, hideToast } from './components/toast';\r\n// Icon 组件导出\r\nexport { default as RcIcon } from './components/icon/index';\r\nexport { install as installIcon } from './components/icon/index';\r\n// Message 服务(对标 antd 的 message)\r\nexport { default as message } from './components/message';\r\nexport { install as installMessage } from './components/message';\r\n// SearchArea 组件导出\r\nexport { default as RcSearchArea } from './components/search-area';\r\nexport { install as installSearchArea } from './components/search-area';\r\nexport type { FilterItem, FilterOption } from './components/search-area';\r\n"],"names":["props","__props","emit","__emit","onClick","ev","radius","computed","v","_createElementBlock","_normalizeClass","_openBlock","_hoisted_2","_renderSlot","_ctx","Button","install","app","inject","providedGapPx","providedColCount","providedLabelWidth","spanNum","n","max","safe","computedWidth","gapPx","k","totalGap","interGap","labelStyle","injected","w","_normalizeStyle","_createElementVNode","_hoisted_1","wrapEl","ref","gapStyle","colCount","itemWidth","singleWidth","watchEffect","base","provide","labelWidthCss","normalizedData","keyK","_a","keyV","_b","_c","it","$slots","_Fragment","_renderList","idx","_createBlock","rcDescriptionsItem","Descriptions","DescriptionsItem","RcDescriptions","RcDescriptionsItem","wrapperStyle","shadowByLevel","toCssSize","bodyPadding","bodyGap","level","_toDisplayString","_hoisted_3","_hoisted_4","_hoisted_5","Card","PascalName","visible","timer","clearTimer","close","__expose","onMounted","onUnmounted","_Teleport","_createVNode","_Transition","_hoisted_6","host","unmount","showToast","options","opt","toastProps","createApp","Toast","hideToast","messages","reactive","uid","remove","id","x","add","type","content","duration","_TransitionGroup","m","container","hostExposed","ensureHost","vnode","createVNode","MessageHost","render","open","d","message","opts","cfg","RECYCLE_UI_SYMBOL","baseClass","iconClassName","sizeCss","iconStyle","char","c","hex","num","url","defaultRecycleUIConfig","selector","link","Icon","activeIndex","panelRef","maskRef","maskStyle","updateMaskPosition","nextTick","panelTop","handleClickOutside","event","target","searchAreaEl","barEl","closeFilter","watch","newVal","tempSelectedValues","confirmedValues","newValue","currentFilter","selectedCountText","count","getTempSelectedCount","getItemDisplayText","item","value","option","findOption","getOptionLabel","values","labels","val","label","openFilter","index","currentValue","getOptionValue","optValue","isSelected","key","tempValue","selectSingle","toggleOption","tempArray","existingIndex","resetCurrentFilter","confirmFilter","oldValue","getSelectedCount","$event","_unref","RcIcon","optIdx","_hoisted_8","_hoisted_9","_hoisted_11","_d","_hoisted_12","_cache","_hoisted_13","RcButton","_createTextVNode","RcSearchArea","doAutoRegister","installButton","installDescriptions","installCard","installToast","installIcon","installMessage","installSearchArea","plugin","createRecycleUI"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/components/icon/index.vue","../src/components/button/index.vue","../src/components/button/index.ts","../src/components/descriptions/item.vue","../src/components/descriptions/index.vue","../src/components/descriptions/index.ts","../src/components/card/index.vue","../src/components/card/index.ts","../src/components/icon/index.ts","../src/components/toast/index.vue","../src/components/toast/index.ts","../src/components/message/index.vue","../src/components/message/index.ts","../src/components/popup/index.vue","../src/components/popup/index.ts","../src/components/calendar/panel-content.vue","../src/components/calendar/index.vue","../src/components/calendar/index.ts","../src/components/search-area/index.vue","../src/components/search-area/index.ts","../src/components/input/index.vue","../src/components/input/index.ts","../src/components/dropdown/menu.vue","../src/components/dropdown/index.vue","../src/components/dropdown/item.vue","../src/components/dropdown/index.ts","../src/components/form/index.vue","../src/components/form/item.vue","../src/components/form/index.ts","../src/components/radio/index.vue","../src/components/radio/group.vue","../src/components/radio/button.vue","../src/components/radio/index.ts","../src/components/checkbox/index.vue","../src/components/checkbox/group.vue","../src/components/checkbox/button.vue","../src/components/checkbox/index.ts","../src/index.ts"],"sourcesContent":["<template>\r\n <i\r\n class=\"rc-icon\"\r\n :class=\"[baseClass, iconClassName, { 'rc-icon--spin': spin }]\"\r\n :style=\"iconStyle\"\r\n aria-hidden=\"true\"\r\n >\r\n <span v-if=\"char\" class=\"rc-icon__unicode\">{{ char }}</span>\r\n </i>\r\n </template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, inject, onMounted } from 'vue';\r\nimport type { RecycleUIOptions } from '../../types';\r\nimport { RECYCLE_UI_SYMBOL, defaultRecycleUIConfig } from '../../index';\r\n\r\ndefineOptions({ name: 'rc-icon' });\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 图标名,例如 'icon_a_in_store',也可直接传完整类名 */\r\n name: string;\r\n /** 尺寸,数字按 px 处理,也可传 '1.2em' 等 */\r\n size?: number | string;\r\n /** 颜色 */\r\n color?: string;\r\n /** 是否旋转(用于 loading 类图标) */\r\n spin?: boolean;\r\n /** Unicode 码点(不带 \\\\u,十六进制,如 'e609' 或 0xe609),用于无类名时渲染 */\r\n code?: string | number;\r\n}>(), {\r\n size: 16,\r\n color: '',\r\n spin: false,\r\n code: '',\r\n});\r\n\r\nconst cfg = inject<RecycleUIOptions>(RECYCLE_UI_SYMBOL, {} as RecycleUIOptions);\r\n\r\nconst baseClass = computed(() => cfg?.iconClass || 'iconfont');\r\nconst iconClassName = computed(() => props.name || '');\r\n\r\nconst sizeCss = computed(() => (typeof props.size === 'number' ? `${props.size}px` : (props.size || '16px')));\r\nconst iconStyle = computed(() => ({\r\n fontSize: sizeCss.value,\r\n color: props.color || undefined,\r\n lineHeight: 1,\r\n fontFamily: cfg?.iconClass || 'iconfont',\r\n}));\r\n\r\n// 将 code 转为字符\r\nconst char = computed(() => {\r\n const c = props.code as any;\r\n if (c === undefined || c === null || c === '' || c === 0) return '';\r\n if (typeof c === 'number') {\r\n return String.fromCharCode(c);\r\n }\r\n const hex = String(c).replace(/^0x/i, '');\r\n const num = parseInt(hex, 16);\r\n if (Number.isNaN(num)) return '';\r\n return String.fromCharCode(num);\r\n});\r\n\r\n// 兜底:若未通过 app.use 安装插件,则在组件挂载时尝试注入默认的 iconfont 样式\r\nonMounted(() => {\r\n if (typeof window === 'undefined') return;\r\n const url = (cfg && cfg.iconCssUrl) || defaultRecycleUIConfig.iconCssUrl;\r\n if (!url) return;\r\n const selector = `link[rel=\"stylesheet\"][data-rcui-icon=\"true\"][href=\"${url}\"]`;\r\n const exists = document.head.querySelector(selector);\r\n if (!exists) {\r\n const link = document.createElement('link');\r\n link.rel = 'stylesheet';\r\n link.href = url as string;\r\n link.setAttribute('data-rcui-icon', 'true');\r\n document.head.appendChild(link);\r\n }\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.rc-icon {\r\n display: inline-block;\r\n vertical-align: -0.125em;\r\n}\r\n.rc-icon__unicode {\r\n /* 让 Unicode 文本走同一字体,确保显示 */\r\n font-family: inherit;\r\n line-height: 1;\r\n}\r\n.rc-icon--spin {\r\n animation: rc-icon-rot 1s linear infinite;\r\n}\r\n@keyframes rc-icon-rot {\r\n to { transform: rotate(360deg); }\r\n}\r\n</style>\r\n\r\n\r\n","<template>\n <button\n class=\"rc-button\"\n :class=\"[`rc-button--${type}`, `rc-button--${size}`, mode ? `rc-button--${mode}` : '', { 'is-block': block, 'is-disabled': disabled, 'is-loading': loading }]\"\n :style=\"{ borderRadius: radius, width: computedWidth }\"\n :disabled=\"disabled || loading\"\n :type=\"actualButtonType\"\n @click=\"onClick\"\n >\n <span v-if=\"loading\" class=\"rc-button__spinner\" />\n <template v-else>\n <span v-if=\"preIcon || $slots.preIcon\" class=\"rc-button__icon rc-button__icon--prefix\">\n <slot name=\"preIcon\">\n <rc-icon v-if=\"preIcon\" :name=\"preIcon\" />\n </slot>\n </span>\n </template>\n <slot>{{ label }}</slot>\n <span v-if=\"!loading && (suffixIcon || $slots.suffixIcon)\" class=\"rc-button__icon rc-button__icon--suffix\">\n <slot name=\"suffixIcon\">\n <rc-icon v-if=\"suffixIcon\" :name=\"suffixIcon\" />\n </slot>\n </span>\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject } from 'vue';\nimport RcIcon from '../icon/index.vue';\ntype ButtonType = 'default' | 'primary' | 'success' | 'warning' | 'danger';\ntype ButtonSize = 'mini' | 'small' | 'medium' | 'large';\ntype ButtonMode = 'outline' | 'text';\ntype FormType = 'submit' | 'reset' | 'button';\n\ninterface Props {\n type?: ButtonType;\n size?: ButtonSize;\n /** 按钮模式:outline 中空模式,text 文本模式 */\n mode?: ButtonMode;\n block?: boolean;\n /** 按钮文本,提供时可不写默认插槽 */\n label?: string;\n /** 圆角;number 代表 px,string 支持百分比等写法(如 '50%')。也兼容 boolean,true 表示大圆角。 */\n round?: number | string | boolean;\n disabled?: boolean;\n loading?: boolean;\n /** 前置图标名称 */\n preIcon?: string;\n /** 后置图标名称 */\n suffixIcon?: string;\n /** 表单按钮类型:submit 提交表单(支持回车提交),button 提交表单(不支持回车提交),reset 重置表单 */\n formType?: FormType;\n /** 按钮宽度;number 表示 px,string 支持百分比等(如 '100%', '200px', '50vw') */\n width?: number | string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'default',\n size: 'medium',\n mode: undefined,\n block: false,\n label: '',\n round: 6,\n disabled: false,\n loading: false,\n preIcon: '',\n suffixIcon: '',\n formType: undefined,\n width: undefined,\n});\n\nconst emit = defineEmits<{\n (e: 'click', ev: MouseEvent): void\n}>();\n\n// 获取表单上下文(如果按钮在表单内)\ninterface FormContext {\n submit: () => void;\n reset: () => void;\n}\nconst formContext = inject<FormContext | undefined>('rcFormActions', undefined);\n\n// 计算实际的 button type 属性\nconst actualButtonType = computed<'button' | 'submit' | 'reset'>(() => {\n if (props.formType === 'submit') {\n return 'submit';\n } else if (props.formType === 'reset') {\n return 'reset';\n }\n return 'button';\n});\n\nconst onClick = (ev: MouseEvent) => {\n if (props.disabled || props.loading) return;\n \n // 如果设置了 form-type,处理表单操作\n if (props.formType && formContext) {\n if (props.formType === 'submit') {\n // submit 类型:点击时阻止默认提交,使用表单的 validate 方法\n // 回车键提交会由表单的 onSubmit 处理(因为按钮 type=\"submit\")\n ev.preventDefault();\n formContext.submit();\n return; // 阻止事件继续传播,避免重复触发\n } else if (props.formType === 'button') {\n // button 类型:只支持点击提交,不支持回车\n ev.preventDefault();\n formContext.submit();\n } else if (props.formType === 'reset') {\n // reset 类型:阻止默认重置,使用表单的 reset 方法\n ev.preventDefault();\n formContext.reset();\n }\n }\n \n emit('click', ev);\n};\n\nconst radius = computed(() => {\n const v = props.round;\n if (typeof v === 'boolean') return v ? '999px' : '6px';\n if (typeof v === 'number') return `${v}px`;\n return String(v);\n});\n\nconst computedWidth = computed(() => {\n if (props.width !== undefined) {\n // 如果设置了 width 属性,使用 width 的值\n if (typeof props.width === 'number') return `${props.width}px`;\n // 如果是字符串,检查是否为纯数字字符串(如 \"150\"),如果是则添加 px\n const str = String(props.width);\n if (/^\\d+$/.test(str)) {\n return `${str}px`;\n }\n return str;\n }\n // 如果没有设置 width,但设置了 block,返回 100%(通过内联样式设置,优先级高于 CSS 类)\n if (props.block) {\n return '100%';\n }\n return undefined;\n});\n</script>\n\n<style scoped lang=\"scss\">\n.rc-button {\n --rc-primary: #1677ff;\n --rc-success: #00b578;\n --rc-warning: #ff8f1f;\n --rc-danger: #ff3141;\n --rc-text: #323233;\n --rc-border: #dcdee0;\n --rc-white: #ffffff;\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 0 16px;\n border: 1px solid var(--rc-border);\n border-radius: 6px;\n background: var(--rc-white);\n color: var(--rc-text);\n cursor: pointer;\n user-select: none;\n transition: all .2s ease;\n\n &.is-disabled { cursor: not-allowed; opacity: .6; }\n &.is-block { display: flex; width: 100%; }\n &.is-loading { opacity: .85; }\n\n &__spinner {\n width: 14px;\n height: 14px;\n margin-right: 6px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: rc-spin 0.8s linear infinite;\n }\n\n &__icon {\n display: inline-flex;\n align-items: center;\n line-height: 1;\n color: currentColor;\n\n &--prefix {\n margin-right: 6px;\n }\n\n &--suffix {\n margin-left: 6px;\n }\n }\n\n &--primary { background: var(--rc-primary); color: var(--rc-white); border-color: var(--rc-primary); }\n &--success { background: var(--rc-success); color: var(--rc-white); border-color: var(--rc-success); }\n &--warning { background: var(--rc-warning); color: var(--rc-white); border-color: var(--rc-warning); }\n &--danger { background: var(--rc-danger); color: var(--rc-white); border-color: var(--rc-danger); }\n\n // outline 模式:中空,有边框,文字和边框颜色为 type 颜色\n &--outline {\n background: transparent;\n\n &.rc-button--default { color: var(--rc-text); border-color: var(--rc-border); }\n &.rc-button--primary { color: var(--rc-primary); border-color: var(--rc-primary); }\n &.rc-button--success { color: var(--rc-success); border-color: var(--rc-success); }\n &.rc-button--warning { color: var(--rc-warning); border-color: var(--rc-warning); }\n &.rc-button--danger { color: var(--rc-danger); border-color: var(--rc-danger); }\n }\n\n // text 模式:无边框,无背景,文字颜色为 type 颜色\n &--text {\n background: transparent;\n border-color: transparent;\n\n &.rc-button--default { color: var(--rc-text); }\n &.rc-button--primary { color: var(--rc-primary); }\n &.rc-button--success { color: var(--rc-success); }\n &.rc-button--warning { color: var(--rc-warning); }\n &.rc-button--danger { color: var(--rc-danger); }\n }\n\n &--mini { height: auto; padding: 2px 3px; font-size: 12px; }\n &--small { height: auto; padding: 3px 5px; font-size: 13px; }\n &--medium { height: auto; padding: 4px 8px; font-size: 14px; }\n &--large { height: auto; padding: 6px 14px; font-size: 16px; }\n}\n\n@keyframes rc-spin { to { transform: rotate(360deg) } }\n</style>\n","import type { App } from 'vue';\r\nimport Button from './index.vue';\r\n\r\n// 组件名使用全小写,以 <rc-button> 形式在模板中使用\r\nif (Button) {\r\n (Button as any).name = 'rc-button';\r\n}\r\n\r\nexport function install(app: App) {\r\n if (Button) {\r\n app.component((Button as any).name || 'rc-button', Button);\r\n }\r\n return app;\r\n}\r\n\r\n\r\nexport default Button;\r\n","<template>\r\n <div \r\n class=\"rc-desc-item\" \r\n :class=\"{ 'rc-desc-item--label-top': labelPosition === 'top' }\"\r\n :style=\"{ width: computedWidth, flex: `0 0 ${computedWidth}` }\"\r\n >\r\n <div class=\"rc-desc-item__label\" :style=\"labelStyle\">\r\n <slot name=\"label\">\r\n {{ label }}\r\n </slot>\r\n </div>\r\n <div class=\"rc-desc-item__value\">\r\n <slot>\r\n {{ value }}\r\n </slot>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, inject, Ref } from 'vue';\r\n\r\ndefineOptions({ name: 'rc-descriptions-item' });\r\n\r\nconst props = withDefaults(defineProps<{\r\n label?: string | number;\r\n value?: any;\r\n labelWidth?: string | number;\r\n /** 跨越的列数,默认 1,可传字符串数字 */\r\n span?: number | string;\r\n /** 标签位置,left 左侧,top 顶部。优先级高于父组件的 label-position */\r\n labelPosition?: 'left' | 'top';\r\n}>(), {\r\n label: '',\r\n value: '',\r\n labelWidth: '',\r\n span: 1,\r\n labelPosition: undefined,\r\n});\r\n\r\nconst providedWidth = inject<Ref<string>>('rcDescItemWidth', undefined as unknown as Ref<string>);\r\nconst providedSingleWidth = inject<Ref<string> | string>('rcDescSingleWidth', '' as unknown as Ref<string>);\r\nconst providedGap = inject<string>('rcDescGap', '0px');\r\nconst providedGapPx = inject<Ref<number> | number>('rcDescGapPx', 0 as unknown as Ref<number>);\r\nconst providedColCount = inject<Ref<number> | number>('rcDescColCount', 1 as unknown as Ref<number>);\r\nconst providedLabelWidth = inject<Ref<string> | string>('rcDescLabelWidth', '' as unknown as Ref<string>);\r\nconst providedLabelPosition = inject<Ref<'left' | 'top'> | 'left' | 'top'>('rcDescLabelPosition', 'left' as unknown as Ref<'left' | 'top'>);\r\n\r\nconst labelPosition = computed(() => {\r\n // 优先使用 item 自身的 labelPosition 属性(优先级最高)\r\n if (props.labelPosition !== undefined) {\r\n return props.labelPosition;\r\n }\r\n // 否则使用父组件提供的 labelPosition\r\n const injectedPos = typeof (providedLabelPosition as any)?.value === 'string' \r\n ? (providedLabelPosition as any).value \r\n : (providedLabelPosition as any);\r\n return injectedPos || 'left';\r\n});\r\n\r\nconst spanNum = computed(() => {\r\n const n = typeof props.span === 'string' ? parseInt(props.span, 10) : props.span;\r\n const max = typeof (providedColCount as any)?.value === 'number' ? (providedColCount as any).value : (providedColCount as any);\r\n const safe = !Number.isNaN(n as number) && (n as number) > 0 ? (n as number) : 1;\r\n return Math.min(safe, max || 1);\r\n});\r\n\r\nconst computedWidth = computed(() => {\r\n const n = typeof (providedColCount as any)?.value === 'number' ? (providedColCount as any).value : (providedColCount as any);\r\n const gapPx = typeof (providedGapPx as any)?.value === 'number' ? (providedGapPx as any).value : (providedGapPx as any);\r\n const k = spanNum.value;\r\n if (!n || n <= 1) return '100%';\r\n if (k >= n) return '100%';\r\n // 展开为单层 calc:((100% - (n-1)*gap) * k / n + (k-1)*gap)\r\n const totalGap = (n - 1) * gapPx;\r\n const interGap = (k - 1) * gapPx;\r\n return `calc((100% - ${totalGap}px) * ${k} / ${n} + ${interGap}px)`;\r\n});\r\n\r\nconst labelStyle = computed(() => {\r\n const injected = typeof (providedLabelWidth as any)?.value === 'string'\r\n ? (providedLabelWidth as any).value\r\n : (providedLabelWidth as any);\r\n const w = props.labelWidth !== '' ? props.labelWidth : (injected || '');\r\n return w ? { width: typeof w === 'number' ? `${w}px` : String(w), flex: '0 0 auto' } : {};\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.rc-desc-item {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 8px;\r\n padding: 6px 0;\r\n flex: 0 0 auto;\r\n}\r\n\r\n.rc-desc-item--label-top {\r\n flex-direction: column;\r\n align-items: flex-start;\r\n}\r\n\r\n.rc-desc-item__label {\r\n color: #666;\r\n font-size: 14px;\r\n line-height: 22px;\r\n /* 不强制最小宽度,交由 label-width 控制 */\r\n min-width: 0;\r\n}\r\n\r\n.rc-desc-item--label-top .rc-desc-item__label {\r\n width: 100%;\r\n}\r\n\r\n.rc-desc-item__value {\r\n flex: 1 1 auto;\r\n font-size: 14px;\r\n line-height: 22px;\r\n overflow: hidden;\r\n}\r\n\r\n</style>\r\n\r\n\r\n","<template>\r\n <div class=\"rc-descriptions\">\r\n <div v-if=\"$slots.title || title\" class=\"rc-descriptions__title\">\r\n <slot name=\"title\">\r\n {{ title }}\r\n </slot>\r\n </div>\r\n <div class=\"rc-descriptions__body\" :style=\"{ gap: gapStyle }\" ref=\"wrapEl\">\r\n <template v-if=\"normalizedData.length\">\r\n <rcDescriptionsItem\r\n v-for=\"(it, idx) in normalizedData\"\r\n :key=\"idx\"\r\n :label=\"it.label\"\r\n :value=\"it.value\"\r\n :label-width=\"labelWidth\"\r\n />\r\n </template>\r\n <slot v-else />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, provide, ref, watchEffect } from 'vue';\r\nimport rcDescriptionsItem from './item.vue';\r\n\r\ndefineOptions({ name: 'rc-descriptions' });\r\n\r\ntype KeyMap = { key: string; value: string };\r\n\r\nconst props = withDefaults(defineProps<{\r\n title?: string;\r\n /** 每行展示的列数,支持数字或字符串数字 */\r\n column?: number | string;\r\n /** 列间距,支持数字(px)或字符串值,例如 '12px' */\r\n gap?: number | string;\r\n /** label 固定宽度,数字代表 px,也可直接传入 '120px' */\r\n labelWidth?: number | string | '';\r\n /** 标签位置,left 左侧,top 顶部 */\r\n labelPosition?: 'left' | 'top';\r\n /** 直接通过数据渲染 */\r\n data?: Array<Record<string, any>>;\r\n /** data 的字段映射,如 { key: 'label', value: 'value' } */\r\n keyMap?: KeyMap;\r\n}>(), {\r\n column: 2,\r\n gap: 4,\r\n labelWidth: '',\r\n labelPosition: 'left',\r\n data: () => [],\r\n});\r\n\r\nconst wrapEl = ref<HTMLElement | null>(null);\r\nconst gapStyle = computed(() => (typeof props.gap === 'number' ? `${props.gap}px` : String(props.gap)));\r\nconst colCount = computed(() => {\r\n const n = typeof props.column === 'string' ? Number.parseInt(props.column as string, 10) : (props.column ?? 1);\r\n return !Number.isNaN(n) && n > 0 ? n : 1;\r\n});\r\n\r\n// compute child item width as percentage string or 'auto'\r\nconst itemWidth = ref<string>('100%');\r\nconst singleWidth = ref<string>('100%');\r\nwatchEffect(() => {\r\n const n = colCount.value;\r\n if (n <= 1) {\r\n itemWidth.value = '100%';\r\n singleWidth.value = '100%';\r\n } else {\r\n // subtract total horizontal gaps from 100%\r\n const gapPx = typeof props.gap === 'number' ? props.gap : parseFloat(String(props.gap)) || 0;\r\n const totalGap = (n - 1) * gapPx;\r\n const base = `calc((100% - ${totalGap}px) / ${n})`;\r\n singleWidth.value = base;\r\n itemWidth.value = base;\r\n }\r\n});\r\n\r\nprovide('rcDescItemWidth', itemWidth);\r\nprovide('rcDescSingleWidth', singleWidth);\r\nprovide('rcDescColCount', colCount);\r\nprovide('rcDescGapPx', computed(() => (typeof props.gap === 'number' ? props.gap : parseFloat(String(props.gap)) || 0)));\r\nconst labelWidthCss = computed(() => {\r\n if (props.labelWidth === '' || props.labelWidth === undefined) return '';\r\n return typeof props.labelWidth === 'number' ? `${props.labelWidth}px` : String(props.labelWidth);\r\n});\r\nprovide('rcDescLabelWidth', labelWidthCss);\r\nprovide('rcDescGap', computed(() => (typeof props.gap === 'number' ? `${props.gap}px` : String(props.gap))));\r\nprovide('rcDescLabelPosition', computed(() => props.labelPosition || 'left'));\r\n\r\nconst normalizedData = computed(() => {\r\n const keyK = (props.keyMap?.key ?? 'label') as string;\r\n const keyV = (props.keyMap?.value ?? 'value') as string;\r\n if (!props.data?.length) return [];\r\n return props.data.map((it) => ({\r\n label: it?.[keyK],\r\n value: it?.[keyV],\r\n }));\r\n});\r\n\r\n</script>\r\n\r\n<style scoped>\r\n.rc-descriptions {\r\n width: 100%;\r\n}\r\n.rc-descriptions__title {\r\n font-weight: 600;\r\n font-size: 16px;\r\n margin: 0 0 12px 0;\r\n}\r\n.rc-description__row {\r\n display: contents;\r\n}\r\n.rc-descriptions__body {\r\n display: flex;\r\n flex-wrap: wrap;\r\n}\r\n\r\n</style>\r\n\r\n\r\n","import type { App } from 'vue';\nimport Descriptions from './index.vue';\nimport DescriptionsItem from './item.vue';\n\n(Descriptions as any).name = 'rc-descriptions';\n(DescriptionsItem as any).name = 'rc-descriptions-item';\n\nexport function install(app: App) {\n // 同时注册 kebab 与 PascalCase 名称,便于 <rc-descriptions>/<RcDescriptions> 使用\n app.component((Descriptions as any).name, Descriptions);\n app.component('RcDescriptions', Descriptions);\n app.component((DescriptionsItem as any).name, DescriptionsItem);\n app.component('RcDescriptionsItem', DescriptionsItem);\n return app;\n}\n\nexport const RcDescriptions = Descriptions;\nexport const RcDescriptionsItem = DescriptionsItem;\n\nexport default Descriptions;\n\n\n\n","<template>\n <div\n class=\"rc-card\"\n :class=\"[{ 'rc-card--bordered': bordered }]\"\n :style=\"wrapperStyle\"\n >\n <div\n v-if=\"$slots.title || title || $slots.status || status\"\n class=\"rc-card__top\"\n :style=\"{ backgroundColor: topBgColor || 'rgba(29, 133, 252, 0.05)' }\"\n >\n <div class=\"rc-card__title\">\n <slot name=\"title\">\n <span class=\"rc-card__title-text\">{{ title }}</span>\n </slot>\n </div>\n <div class=\"rc-card__status\" v-if=\"$slots.status || status\">\n <slot name=\"status\">\n <span class=\"rc-card__status-text\" :style=\"{ color: statusColor || 'var(--rc-primary)' }\">\n {{ status }}\n </span>\n </slot>\n </div>\n </div>\n\n <div class=\"rc-card__body\" :style=\"{ padding: bodyPadding, gap: bodyGap }\">\n <slot name=\"content\">\n <slot />\n </slot>\n </div>\n\n <div v-if=\"$slots.action\" class=\"rc-card__divider\" />\n\n <div v-if=\"$slots.action\" class=\"rc-card__action\">\n <slot name=\"action\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\ndefineOptions({ name: 'rc-card' });\n\ninterface Props {\n /** 卡片整体背景色,默认白色 */\n color?: string;\n /** 顶部色块背景色 */\n topBgColor?: string;\n /** 标题文本(可用 slot=\"title\" 自定义) */\n title?: string;\n /** 右侧状态文案(可用 slot=\"status\" 自定义) */\n status?: string;\n /** 状态文本颜色 */\n statusColor?: string;\n /** 圆角:数值代表 px,字符串可用百分比 */\n round?: number | string;\n /** 是否描边 */\n bordered?: boolean;\n /** 阴影强度:0/1/2/3... -> 转换为不同阴影强度 */\n elevation?: number;\n /** 内边距(CSS 值,如 '16px 12px') */\n padding?: string;\n /** 主体内容的垂直间距(px 或 CSS 字符串) */\n gap?: number | string;\n /** 宽度(px/百分比) */\n width?: string | number;\n /** 高度(px/百分比) */\n height?: string | number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n color: 'var(--rc-white)',\n topBgColor: 'rgba(29, 133, 252, 0.05)',\n title: '',\n status: '',\n statusColor: 'var(--rc-primary)',\n round: 8,\n bordered: false,\n elevation: 2,\n padding: '16px',\n gap: 12,\n width: '100%',\n height: '',\n});\n\nconst wrapperStyle = computed(() => {\n const radius =\n typeof props.round === 'boolean'\n ? props.round\n ? '12px'\n : '0'\n : typeof props.round === 'number'\n ? `${props.round}px`\n : String(props.round);\n\n return {\n backgroundColor: props.color || 'var(--rc-white)',\n borderRadius: radius,\n boxShadow: shadowByLevel(props.elevation),\n width: toCssSize(props.width),\n height: toCssSize(props.height),\n } as Record<string, string>;\n});\n\nconst bodyPadding = computed(() => props.padding || '16px');\nconst bodyGap = computed(() =>\n typeof props.gap === 'number' ? `${props.gap}px` : String(props.gap)\n);\n\nfunction toCssSize(v?: string | number) {\n if (v === undefined || v === null || v === '') return '';\n return typeof v === 'number' ? `${v}px` : String(v);\n}\n\nfunction shadowByLevel(level: number) {\n if (!level || level <= 0) return 'none';\n // 简单的多层阴影(可按需微调)\n const base = 4 * level;\n return `0 ${Math.round(base / 2)}px ${base}px rgba(0,0,0,0.06), 0 ${Math.round(\n base / 4\n )}px ${Math.round(base / 2)}px rgba(0,0,0,0.04)`;\n}\n</script>\n\n<style scoped>\n.rc-card {\n --rc-white: #ffffff;\n --rc-border: #e5e6eb;\n --rc-primary: #1677ff;\n\n display: flex;\n flex-direction: column;\n width: 100%;\n border: 1px solid transparent;\n background: var(.rc-white);\n}\n.rc-card--bordered {\n border-color: var(--rc-border);\n}\n\n.rc-card__top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-top-left-radius: inherit;\n border-top-right-radius: inherit;\n}\n.rc-card__title {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.rc-card__title-text {\n font-weight: 600;\n font-size: 16px;\n color: #1d2129;\n}\n.rc-card__status-text {\n font-size: 14px;\n}\n.rc-card__body {\n display: flex;\n flex-direction: column;\n}\n.rc-card__divider {\n height: 1px;\n background: var(--rc-border);\n}\n.rc-card__action {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n}\n</style>\n\n\n","import type { App } from 'vue';\nimport Card from './index.vue';\n\n// 同时注册小写与驼峰,便于 <rc-card> / <RcCard> 两种写法\n(Card as any).name = 'rc-card';\nconst PascalName = 'RcCard';\n\nexport function install(app: App) {\n app.component((Card as any).name, Card);\n app.component(PascalName, Card);\n return app;\n}\n\nexport default Card;\n\n\n","import type { App } from 'vue';\r\nimport Icon from './index.vue';\r\n\r\nexport function install(app: App) {\r\n if (Icon) {\r\n app.component('rc-icon', Icon);\r\n app.component('RcIcon', Icon);\r\n }\r\n return app;\r\n}\r\n\r\nexport const RcIcon = Icon;\r\nexport default Icon;\r\n\r\n\r\n","<template>\r\n <teleport to=\"body\">\r\n <transition name=\"rc-toast-fade\" @after-leave=\"onAfterLeave\">\r\n <div v-if=\"visible\" class=\"rc-toast\" :class=\"[`rc-toast--${type}`]\">\r\n <div v-if=\"mask\" class=\"rc-toast__mask\" />\r\n <div class=\"rc-toast__content\">\r\n <div v-if=\"type === 'loading'\" class=\"rc-toast__spinner\" />\r\n <rc-icon name=\"icon_select\" v-else-if=\"type === 'success'\" />\r\n <div v-else-if=\"type === 'fail'\" class=\"rc-toast__icon rc-toast__icon--fail\" />\r\n <div class=\"rc-toast__text\">{{ message }}</div>\r\n </div>\r\n </div>\r\n </transition>\r\n </teleport>\r\n <slot />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { onMounted, onUnmounted, ref, defineExpose } from 'vue';\r\nimport RcIcon from '../icon';\r\n\r\nexport type ToastType = 'text' | 'success' | 'fail' | 'loading';\r\nexport interface ToastProps {\r\n message?: string;\r\n type?: ToastType;\r\n duration?: number;\r\n mask?: boolean;\r\n /** 服务端关闭回调,用于卸载容器 */\r\n onAfterLeave?: () => void;\r\n}\r\n\r\nconst props = withDefaults(defineProps<ToastProps>(), {\r\n message: '',\r\n type: 'text',\r\n duration: 2000,\r\n mask: false,\r\n});\r\n\r\nconst visible = ref(true);\r\nlet timer: any;\r\n\r\nfunction clearTimer() {\r\n if (timer) {\r\n clearTimeout(timer);\r\n timer = null;\r\n }\r\n}\r\n\r\nfunction close() {\r\n clearTimer();\r\n visible.value = false;\r\n}\r\n\r\ndefineExpose({ close });\r\n\r\nonMounted(() => {\r\n if (props.duration && props.duration > 0) {\r\n timer = setTimeout(() => {\r\n close();\r\n }, props.duration);\r\n }\r\n});\r\n\r\nonUnmounted(() => {\r\n clearTimer();\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.rc-toast {\r\n position: fixed;\r\n inset: 0;\r\n z-index: 9999;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n.rc-toast__mask {\r\n position: absolute;\r\n inset: 0;\r\n background: rgba(0, 0, 0, 0.35);\r\n pointer-events: auto;\r\n backdrop-filter: blur(1px);\r\n}\r\n.rc-toast__content {\r\n position: relative;\r\n max-width: 80%;\r\n background: rgba(0, 0, 0, 0.75);\r\n color: #fff;\r\n border-radius: 12px;\r\n padding: 12px 14px;\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 8px;\r\n box-shadow: 0 6px 16px rgba(0,0,0,0.2);\r\n}\r\n.rc-toast__text {\r\n font-size: 14px;\r\n line-height: 1.4;\r\n}\r\n.rc-toast__spinner {\r\n width: 18px;\r\n height: 18px;\r\n border: 2px solid rgba(255,255,255,0.35);\r\n border-top-color: #fff;\r\n border-radius: 50%;\r\n animation: rc-toast-spin 0.8s linear infinite;\r\n}\r\n.rc-toast__icon {\r\n width: 18px;\r\n height: 18px;\r\n border-radius: 50%;\r\n position: relative;\r\n flex: 0 0 18px;\r\n}\r\n.rc-toast__icon--success::before {\r\n content: '';\r\n position: absolute;\r\n left: 3px;\r\n top: 3px;\r\n width: 10px;\r\n height: 10px;\r\n border-right: 2px solid #fff;\r\n border-bottom: 2px solid #fff;\r\n transform: rotate(45deg);\r\n}\r\n.rc-toast__icon--fail::before,\r\n.rc-toast__icon--fail::after {\r\n content: '';\r\n position: absolute;\r\n left: 3px;\r\n right: 3px;\r\n top: 8px;\r\n height: 2px;\r\n background: #fff;\r\n}\r\n.rc-toast__icon--fail::before {\r\n transform: rotate(45deg);\r\n}\r\n.rc-toast__icon--fail::after {\r\n transform: rotate(-45deg);\r\n}\r\n\r\n.rc-toast-fade-enter-active,\r\n.rc-toast-fade-leave-active {\r\n transition: opacity .2s ease;\r\n}\r\n.rc-toast-fade-enter-from,\r\n.rc-toast-fade-leave-to {\r\n opacity: 0;\r\n}\r\n@keyframes rc-toast-spin {\r\n to { transform: rotate(360deg); }\r\n}\r\n</style>\r\n\r\n\r\n","import { App, createApp } from 'vue';\nimport Toast, { type ToastProps } from './index.vue';\n\nexport type { ToastProps };\nexport interface ShowToastOptions {\n message?: string;\n type?: 'text' | 'success' | 'fail' | 'loading';\n duration?: number;\n mask?: boolean;\n /** 关闭时回调(仅服务方式有效) */\n onClose?: () => void;\n}\n\nlet app: App<Element> | null = null;\nlet host: HTMLDivElement | null = null;\n\nfunction unmount() {\n if (app) {\n app.unmount();\n app = null;\n }\n if (host) {\n document.body.removeChild(host);\n host = null;\n }\n}\n\nexport function showToast(options: string | ShowToastOptions) {\n const opt: ShowToastOptions =\n typeof options === 'string' ? { message: options } : (options || {});\n unmount();\n host = document.createElement('div');\n document.body.appendChild(host);\n const toastProps: ToastProps = {\n message: opt.message,\n type: (opt as any).type ?? 'text',\n duration: (opt as any).duration ?? 2000,\n mask: (opt as any).mask ?? false,\n onAfterLeave: () => {\n unmount();\n opt.onClose?.();\n },\n };\n app = createApp(Toast, toastProps as any);\n app.mount(host);\n return {\n close: hideToast,\n };\n}\n\nexport function hideToast() {\n if (!app) return;\n // 调用暴露的 close 方法\n // @ts-ignore\n app._instance?.exposed?.close?.();\n}\n\n// 组件注册(可选,提供 rc-toast 用于手动放置 Portal)\n(Toast as any).name = 'rc-toast';\nexport function install(app: App) {\n app.component((Toast as any).name, Toast);\n return app;\n}\n\nexport default Toast;\n\n\n","<template>\r\n <div class=\"rc-message\" role=\"alert\" aria-live=\"polite\">\r\n <transition-group name=\"rc-message-fade\" tag=\"div\">\r\n <div\r\n v-for=\"m in messages\"\r\n :key=\"m.id\"\r\n class=\"rc-message__item\"\r\n :class=\"`rc-message--${m.type}`\"\r\n >\r\n <span class=\"rc-message__content\">{{ m.content }}</span>\r\n </div>\r\n </transition-group>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { reactive } from 'vue';\r\n\r\nexport type MessageType = 'info' | 'success' | 'warning' | 'error' | 'loading';\r\nexport interface MessageItem {\r\n id: number;\r\n type: MessageType;\r\n content: string;\r\n duration: number; // ms; 0 = persistent (except loading default)\r\n}\r\n\r\nconst messages = reactive<MessageItem[]>([]);\r\nlet uid = 1;\r\n\r\nfunction remove(id: number) {\r\n const idx = messages.findIndex((x) => x.id === id);\r\n if (idx >= 0) messages.splice(idx, 1);\r\n}\r\n\r\nfunction add(type: MessageType, content: string, duration: number) {\r\n const id = uid++;\r\n messages.push({ id, type, content, duration });\r\n if (duration > 0) {\r\n window.setTimeout(() => remove(id), duration);\r\n }\r\n return id;\r\n}\r\n\r\ndefineExpose({ add, remove });\r\n</script>\r\n\r\n<style scoped>\r\n.rc-message {\r\n position: fixed;\r\n top: 16px;\r\n left: 0;\r\n right: 0;\r\n z-index: 10000;\r\n pointer-events: none;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n.rc-message__item {\r\n pointer-events: auto;\r\n min-width: 120px;\r\n max-width: 80%;\r\n padding: 8px 12px;\r\n border-radius: 6px;\r\n color: #fff;\r\n background: rgba(0, 0, 0, 0.78);\r\n box-shadow: 0 6px 16px rgba(0,0,0,0.2);\r\n font-size: 14px;\r\n}\r\n.rc-message--success { background: rgba(22,119,255,0.9); }\r\n.rc-message--warning { background: rgba(250,173,20,0.95); }\r\n.rc-message--error { background: rgba(245,63,63,0.95); }\r\n.rc-message--info { background: rgba(0,0,0,0.78); }\r\n.rc-message--loading { background: rgba(0,0,0,0.78); }\r\n\r\n.rc-message-fade-enter-active,\r\n.rc-message-fade-leave-active {\r\n transition: all .2s ease;\r\n}\r\n.rc-message-fade-enter-from,\r\n.rc-message-fade-leave-to {\r\n opacity: 0;\r\n transform: translateY(-6px);\r\n}\r\n</style>\r\n\r\n\r\n","import { createVNode, render, type App } from 'vue';\r\nimport MessageHost from './index.vue';\r\n\r\ntype MessageType = 'info' | 'success' | 'warning' | 'error' | 'loading';\r\n\r\nexport interface MessageOptions {\r\n content: string;\r\n duration?: number; // ms; default 2000, loading 默认 0\r\n type?: MessageType;\r\n}\r\n\r\nlet container: HTMLElement | null = null;\r\nlet hostExposed: any = null;\r\n\r\nfunction ensureHost() {\r\n if (container && hostExposed) return;\r\n container = document.createElement('div');\r\n document.body.appendChild(container);\r\n const vnode = createVNode(MessageHost, {});\r\n render(vnode, container);\r\n hostExposed = (vnode.component as any)?.exposed;\r\n}\r\n\r\nfunction open(type: MessageType, content: string, duration?: number) {\r\n ensureHost();\r\n const d = typeof duration === 'number'\r\n ? duration\r\n : (type === 'loading' ? 0 : 2000);\r\n return hostExposed?.add?.(type, content, d);\r\n}\r\n\r\nexport const message = {\r\n open(opts: MessageOptions) {\r\n return open(opts.type || 'info', opts.content, opts.duration);\r\n },\r\n info(content: string, duration?: number) {\r\n return open('info', content, duration);\r\n },\r\n success(content: string, duration?: number) {\r\n return open('success', content, duration);\r\n },\r\n warning(content: string, duration?: number) {\r\n return open('warning', content, duration);\r\n },\r\n error(content: string, duration?: number) {\r\n return open('error', content, duration);\r\n },\r\n loading(content: string, duration?: number) {\r\n return open('loading', content, duration);\r\n },\r\n destroy() {\r\n if (container) {\r\n render(null, container);\r\n container.remove();\r\n container = null;\r\n hostExposed = null;\r\n }\r\n },\r\n};\r\n\r\nexport default message;\r\n\r\n// 可选:提供 install,注入到 app.config.globalProperties 以便 this.$message 使用\r\nexport function install(app: App) {\r\n (app.config.globalProperties as any).$message = message;\r\n return app;\r\n}\r\n\r\n\r\n","<template>\r\n <teleport to=\"body\">\r\n <transition name=\"rc-popup-fade\">\r\n <div\r\n v-if=\"visible && props.overlay\"\r\n class=\"rc-popup__overlay\"\r\n :class=\"{ 'rc-popup__overlay--transparent': props.overlayClass === 'transparent' }\"\r\n :style=\"props.overlayStyle\"\r\n @click=\"handleOverlayClick\"\r\n ></div>\r\n </transition>\r\n\r\n <transition :name=\"transitionName\">\r\n <div\r\n v-if=\"visible\"\r\n ref=\"popupRef\"\r\n class=\"rc-popup\"\r\n :class=\"[\r\n `rc-popup--${position}`,\r\n { 'rc-popup--round': round }\r\n ]\"\r\n :style=\"popupStyle\"\r\n @click.stop\r\n >\r\n <div v-if=\"closeable\" class=\"rc-popup__close\" :class=\"`rc-popup__close--${closeIconPosition}`\" @click=\"handleClose\">\r\n <rc-icon :name=\"closeIcon\" class=\"rc-popup__close-icon\" />\r\n </div>\r\n\r\n <div class=\"rc-popup__content\">\r\n <slot />\r\n </div>\r\n </div>\r\n </transition>\r\n </teleport>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, onUnmounted } from 'vue';\r\nimport RcIcon from '../icon/index.vue';\r\n\r\ndefineOptions({ name: 'rc-popup' });\r\n\r\ntype PopupPosition = 'top' | 'bottom' | 'left' | 'right' | 'center';\r\ntype CloseIconPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\r\n\r\ninterface Props {\r\n /** 是否显示弹出层 */\r\n modelValue?: boolean;\r\n /** 弹出位置 */\r\n position?: PopupPosition;\r\n /** 是否显示遮罩层 */\r\n overlay?: boolean;\r\n /** 遮罩层样式类名 */\r\n overlayClass?: string;\r\n /** 遮罩层样式 */\r\n overlayStyle?: Record<string, string>;\r\n /** 是否显示关闭图标 */\r\n closeable?: boolean;\r\n /** 关闭图标位置 */\r\n closeIconPosition?: CloseIconPosition;\r\n /** 自定义关闭图标 */\r\n closeIcon?: string;\r\n /** 是否显示圆角 */\r\n round?: boolean;\r\n /** 弹出层样式 */\r\n popupStyle?: Record<string, string>;\r\n /** 是否点击遮罩层关闭 */\r\n closeOnClickOverlay?: boolean;\r\n /** 是否锁定背景滚动 */\r\n lockScroll?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n modelValue: false,\r\n position: 'center',\r\n overlay: true,\r\n overlayClass: '',\r\n overlayStyle: undefined,\r\n closeable: false,\r\n closeIconPosition: 'top-right',\r\n closeIcon: 'icon_close',\r\n round: false,\r\n popupStyle: undefined,\r\n closeOnClickOverlay: true,\r\n lockScroll: 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 (e: 'click-overlay'): void;\r\n}>();\r\n\r\nconst popupRef = ref<HTMLElement>();\r\nconst visible = ref(props.modelValue);\r\n\r\n// 锁定背景滚动\r\nlet scrollLocked = false;\r\nfunction lockBodyScroll() {\r\n if (scrollLocked) return;\r\n scrollLocked = true;\r\n document.body.style.overflow = 'hidden';\r\n}\r\n\r\n// 解锁背景滚动\r\nfunction unlockBodyScroll() {\r\n if (!scrollLocked) return;\r\n scrollLocked = false;\r\n document.body.style.overflow = '';\r\n}\r\n\r\n// 监听 modelValue 变化\r\nwatch(\r\n () => props.modelValue,\r\n (val) => {\r\n visible.value = val;\r\n if (val) {\r\n emit('open');\r\n if (props.lockScroll) {\r\n lockBodyScroll();\r\n }\r\n } else {\r\n emit('close');\r\n if (props.lockScroll) {\r\n unlockBodyScroll();\r\n }\r\n }\r\n },\r\n { immediate: true }\r\n);\r\n\r\n\r\n// 监听 visible 变化,同步到 modelValue\r\nwatch(visible, (val) => {\r\n if (val !== props.modelValue) {\r\n emit('update:modelValue', val);\r\n }\r\n});\r\n\r\n// 计算过渡动画名称\r\nconst transitionName = computed(() => {\r\n return `rc-popup-slide-${props.position}`;\r\n});\r\n\r\n// 计算弹出层样式\r\nconst popupStyle = computed(() => {\r\n return { ...(props.popupStyle || {}) };\r\n});\r\n\r\n// 处理遮罩层点击\r\nfunction handleOverlayClick() {\r\n emit('click-overlay');\r\n if (props.closeOnClickOverlay) {\r\n close();\r\n }\r\n}\r\n\r\n// 处理关闭\r\nfunction handleClose() {\r\n close();\r\n}\r\n\r\n// 关闭弹出层\r\nfunction close() {\r\n visible.value = false;\r\n}\r\n\r\n// 打开弹出层\r\nfunction open() {\r\n visible.value = true;\r\n}\r\n\r\nonUnmounted(() => {\r\n unlockBodyScroll();\r\n});\r\n\r\n// 暴露方法(供函数式调用使用)\r\ndefineExpose({\r\n open,\r\n close,\r\n visible,\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-popup {\r\n --rc-primary: #1677ff;\r\n --rc-text: #323233;\r\n --rc-border: #dcdee0;\r\n --rc-white: #ffffff;\r\n --rc-overlay: rgba(0, 0, 0, 0.7);\r\n\r\n position: fixed;\r\n z-index: 2000;\r\n max-height: 100%;\r\n max-width: 100%;\r\n background: var(--rc-white);\r\n overflow: auto;\r\n\r\n &--round {\r\n border-radius: 8px 8px 0 0;\r\n }\r\n\r\n &--top {\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n width: 100%;\r\n }\r\n\r\n &--bottom {\r\n bottom: 0;\r\n left: 0;\r\n right: 0;\r\n width: 100%;\r\n }\r\n\r\n &--left {\r\n top: 0;\r\n bottom: 0;\r\n left: 0;\r\n height: 100%;\r\n }\r\n\r\n &--right {\r\n top: 0;\r\n bottom: 0;\r\n right: 0;\r\n height: 100%;\r\n }\r\n\r\n &--center {\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n max-width: 90vw;\r\n max-height: 90vh;\r\n border-radius: 8px;\r\n }\r\n\r\n &__overlay {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n z-index: 1999;\r\n background: rgba(0, 0, 0, 0.7);\r\n\r\n &--transparent {\r\n background: transparent;\r\n }\r\n }\r\n\r\n &__close {\r\n position: absolute;\r\n z-index: 1;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 32px;\r\n height: 32px;\r\n cursor: pointer;\r\n transition: opacity 0.2s;\r\n\r\n &:hover {\r\n opacity: 0.8;\r\n }\r\n\r\n &--top-left {\r\n top: 8px;\r\n left: 8px;\r\n }\r\n\r\n &--top-right {\r\n top: 8px;\r\n right: 8px;\r\n }\r\n\r\n &--bottom-left {\r\n bottom: 8px;\r\n left: 8px;\r\n }\r\n\r\n &--bottom-right {\r\n bottom: 8px;\r\n right: 8px;\r\n }\r\n }\r\n\r\n &__close-icon {\r\n font-size: 18px;\r\n color: var(--rc-text);\r\n }\r\n\r\n &__content {\r\n width: 100%;\r\n height: 100%;\r\n }\r\n}\r\n\r\n// 过渡动画\r\n.rc-popup-fade-enter-active,\r\n.rc-popup-fade-leave-active {\r\n transition: opacity 0.3s;\r\n}\r\n\r\n.rc-popup-fade-enter-from,\r\n.rc-popup-fade-leave-to {\r\n opacity: 0;\r\n}\r\n\r\n.rc-popup-slide-top-enter-active,\r\n.rc-popup-slide-top-leave-active {\r\n transition: transform 0.3s;\r\n}\r\n\r\n.rc-popup-slide-top-enter-from,\r\n.rc-popup-slide-top-leave-to {\r\n transform: translateY(-100%);\r\n}\r\n\r\n.rc-popup-slide-bottom-enter-active,\r\n.rc-popup-slide-bottom-leave-active {\r\n transition: transform 0.3s;\r\n}\r\n\r\n.rc-popup-slide-bottom-enter-from,\r\n.rc-popup-slide-bottom-leave-to {\r\n transform: translateY(100%);\r\n}\r\n\r\n.rc-popup-slide-left-enter-active,\r\n.rc-popup-slide-left-leave-active {\r\n transition: transform 0.3s;\r\n}\r\n\r\n.rc-popup-slide-left-enter-from,\r\n.rc-popup-slide-left-leave-to {\r\n transform: translateX(-100%);\r\n}\r\n\r\n.rc-popup-slide-right-enter-active,\r\n.rc-popup-slide-right-leave-active {\r\n transition: transform 0.3s;\r\n}\r\n\r\n.rc-popup-slide-right-enter-from,\r\n.rc-popup-slide-right-leave-to {\r\n transform: translateX(100%);\r\n}\r\n</style>\r\n\r\n","import type { App } from 'vue';\r\nimport Popup from './index.vue';\r\n\r\n// 组件名使用全小写,以 <rc-popup> 形式在模板中使用\r\nif (Popup) {\r\n (Popup as any).name = 'rc-popup';\r\n}\r\nconst PascalName = 'RcPopup';\r\n\r\nexport function install(app: App) {\r\n if (Popup) {\r\n app.component((Popup as any).name || 'rc-popup', Popup);\r\n app.component(PascalName, Popup);\r\n }\r\n return app;\r\n}\r\n\r\nexport default Popup;\r\n\r\n","<template>\r\n <div>\r\n <!-- 标题栏 -->\r\n <div v-if=\"showTitle\" class=\"rc-calendar__header\">\r\n <div class=\"rc-calendar__header-title\">{{ title }}</div>\r\n <span\r\n class=\"rc-calendar__header-clear\"\r\n :class=\"{ 'is-disabled': !hasValue }\"\r\n @click=\"handleHeaderClear\"\r\n >\r\n 清空\r\n </span>\r\n </div>\r\n\r\n <!-- 快捷选择 -->\r\n <div v-if=\"range\" class=\"rc-calendar__shortcuts\">\r\n <div class=\"rc-calendar__shortcuts-scroll\">\r\n <div\r\n v-for=\"option in availableShortcuts\"\r\n :key=\"option.key\"\r\n class=\"rc-calendar__shortcut-item\"\r\n @click=\"handleShortcutClick(option)\"\r\n >\r\n {{ option.label }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 月份导航 -->\r\n <div class=\"rc-calendar__month-title\">\r\n <div class=\"rc-calendar__nav-button\" @click=\"prevMonth\">\r\n <rc-icon name=\"icon_caret-left\" class=\"rc-calendar__nav-icon\" />\r\n </div>\r\n <div class=\"rc-calendar__month-text\" @click=\"openMonthPicker\">\r\n {{ monthTitle }}\r\n </div>\r\n <div class=\"rc-calendar__nav-button\" @click=\"nextMonth\">\r\n <rc-icon name=\"icon_caret-right\" class=\"rc-calendar__nav-icon\" />\r\n </div>\r\n </div>\r\n\r\n <!-- 星期标题 -->\r\n <div class=\"rc-calendar__weekdays\">\r\n <div v-for=\"day in weekdays\" :key=\"day\" class=\"rc-calendar__weekday\">\r\n {{ day }}\r\n </div>\r\n </div>\r\n\r\n <!-- 日期网格 -->\r\n <div class=\"rc-calendar__days\">\r\n <div\r\n v-for=\"(day, index) in monthDays\"\r\n :key=\"index\"\r\n class=\"rc-calendar__day\"\r\n :class=\"getDayClass(day)\"\r\n @click=\"onSelectDay(day)\"\r\n >\r\n <div class=\"rc-calendar__day-content\">\r\n <span class=\"rc-calendar__day-text\">{{ day.text }}</span>\r\n <span v-if=\"day.bottomInfo\" class=\"rc-calendar__day-bottom\">{{ day.bottomInfo }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 底部操作栏(区间模式) -->\r\n <div v-if=\"range && showFooter\" class=\"rc-calendar__footer\">\r\n <rc-button type=\"default\" class=\"rc-calendar__footer-reset\" @click=\"onClear\">取消</rc-button>\r\n <rc-button\r\n type=\"primary\"\r\n class=\"rc-calendar__footer-confirm\"\r\n :disabled=\"!isRangeComplete\"\r\n @click=\"onConfirm\"\r\n >\r\n {{ isRangeComplete ? `确定(${selectedRangeCount}项)` : '确定' }}\r\n </rc-button>\r\n </div>\r\n \r\n <!-- 年月选择器 - 覆盖在日历面板上 -->\r\n <transition name=\"rc-calendar-fade\">\r\n <div v-if=\"showMonthPicker\" class=\"rc-calendar__month-picker-overlay\">\r\n <div class=\"rc-calendar__month-picker\">\r\n <div class=\"rc-calendar__month-picker-header\">\r\n <rc-button type=\"default\" mode=\"text\" size=\"small\" @click=\"onCloseMonthPicker\">取消</rc-button>\r\n <div class=\"rc-calendar__month-picker-title\">\r\n <span @click=\"onPickerModeChange('year')\">{{ tempYear }}年</span>\r\n <span v-if=\"pickerMode === 'month'\"> - </span>\r\n <span v-if=\"pickerMode === 'month'\" @click=\"onPickerModeChange('month')\">{{ tempMonth }}月</span>\r\n </div>\r\n <rc-button \r\n v-if=\"pickerMode === 'year'\"\r\n type=\"primary\" \r\n mode=\"text\" \r\n size=\"small\" \r\n @click=\"selectCurrentYear\"\r\n >\r\n 本年\r\n </rc-button>\r\n <rc-button \r\n v-if=\"pickerMode === 'month'\"\r\n type=\"primary\" \r\n mode=\"text\" \r\n size=\"small\" \r\n @click=\"selectCurrentMonth\"\r\n >\r\n 本月\r\n </rc-button>\r\n </div>\r\n \r\n <!-- 年份选择 -->\r\n <div v-if=\"pickerMode === 'year'\" class=\"rc-calendar__year-picker-content\">\r\n <div \r\n class=\"rc-calendar__year-picker-scroll\" \r\n ref=\"yearScrollRef\" \r\n @scroll=\"handleYearScroll\"\r\n >\r\n <div class=\"rc-calendar__year-picker-spacer\" :style=\"{ height: `${Math.floor((visibleYearStart - dynamicMinYear) / itemsPerRow) * itemHeight}px` }\"></div>\r\n <div class=\"rc-calendar__year-picker-grid\">\r\n <div\r\n v-for=\"year in visibleYearList\"\r\n :key=\"year\"\r\n class=\"rc-calendar__year-picker-item\"\r\n :class=\"{\r\n 'is-selected': tempYear === year,\r\n 'is-disabled': isYearDisabled(year)\r\n }\"\r\n @click=\"selectYear(year)\"\r\n >\r\n {{ year }}\r\n </div>\r\n </div>\r\n <div class=\"rc-calendar__year-picker-spacer\" :style=\"{ height: `${Math.ceil((dynamicMaxYear - visibleYearEnd) / itemsPerRow) * itemHeight}px` }\"></div>\r\n </div>\r\n </div>\r\n \r\n <!-- 月份选择 -->\r\n <div v-if=\"pickerMode === 'month'\" class=\"rc-calendar__month-picker-content\">\r\n <div\r\n v-for=\"month in 12\"\r\n :key=\"month\"\r\n class=\"rc-calendar__month-picker-item\"\r\n :class=\"{\r\n 'is-selected': tempMonth === month,\r\n 'is-disabled': isMonthDisabled(tempYear, month)\r\n }\"\r\n @click=\"selectMonth(month)\"\r\n >\r\n {{ month }}月\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick } from 'vue';\r\nimport RcIcon from '../icon';\r\nimport RcButton from '../button';\r\n\r\ninterface DayItem {\r\n date: Date;\r\n type: string;\r\n text: string;\r\n bottomInfo?: string;\r\n}\r\n\r\ninterface Props {\r\n showTitle?: boolean;\r\n title?: string;\r\n range?: boolean;\r\n selectedDate: string | null;\r\n rangeStart: string | null;\r\n rangeEnd: string | null;\r\n minDate?: string;\r\n maxDate?: string;\r\n disabledDate?: (date: Date) => boolean;\r\n formatter?: (day: DayItem) => { text?: string; bottomInfo?: string };\r\n showFooter?: boolean;\r\n maxRangeDays?: number;\r\n}\r\n\r\nconst props = defineProps<Props>();\r\n\r\nconst emit = defineEmits<{\r\n (e: 'select-day', day: DayItem): void;\r\n (e: 'clear'): void;\r\n (e: 'confirm'): void;\r\n (e: 'shortcut-select', range: [string, string]): void;\r\n}>();\r\n\r\n// 常量\r\nconst weekdays = ['日', '一', '二', '三', '四', '五', '六'];\r\nconst itemHeight = 48; // 每个年份项的高度(包括 margin)\r\nconst itemsPerRow = 3; // 每行显示的年份数\r\nconst visibleRows = 7; // 可见的行数\r\n\r\n// 解析日期字符串\r\nfunction parseDate(dateStr: string | null | undefined): Date | null {\r\n if (!dateStr) return null;\r\n const date = new Date(dateStr);\r\n return isNaN(date.getTime()) ? null : date;\r\n}\r\n\r\n// 格式化日期为 YYYY-MM-DD\r\nfunction formatDate(date: Date): string {\r\n const year = date.getFullYear();\r\n const month = String(date.getMonth() + 1).padStart(2, '0');\r\n const day = String(date.getDate()).padStart(2, '0');\r\n return `${year}-${month}-${day}`;\r\n}\r\n\r\n// 当前显示的月份\r\nconst currentDate = ref(new Date());\r\n\r\n// 根据选中的日期初始化 currentDate\r\nwatch(\r\n () => [props.selectedDate, props.rangeStart],\r\n () => {\r\n if (props.range && props.rangeStart) {\r\n const date = parseDate(props.rangeStart);\r\n if (date) {\r\n currentDate.value = date;\r\n }\r\n } else if (!props.range && props.selectedDate) {\r\n const date = parseDate(props.selectedDate);\r\n if (date) {\r\n currentDate.value = date;\r\n }\r\n }\r\n },\r\n { immediate: true }\r\n);\r\n\r\n// 判断是否是今天\r\nfunction isToday(date: Date): boolean {\r\n const today = new Date();\r\n return (\r\n date.getFullYear() === today.getFullYear() &&\r\n date.getMonth() === today.getMonth() &&\r\n date.getDate() === today.getDate()\r\n );\r\n}\r\n\r\n// 判断日期是否在区间内\r\nfunction isInRange(date: Date): boolean {\r\n if (!props.rangeStart || !props.rangeEnd) return false;\r\n const dateStr = formatDate(date);\r\n const start = props.rangeStart;\r\n const end = props.rangeEnd;\r\n return dateStr > start && dateStr < end;\r\n}\r\n\r\n// 判断日期是否被禁用\r\nfunction isDisabled(date: Date): boolean {\r\n if (props.disabledDate && props.disabledDate(date)) {\r\n return true;\r\n }\r\n \r\n const dateStr = formatDate(date);\r\n \r\n if (props.minDate && dateStr < props.minDate) {\r\n return true;\r\n }\r\n if (props.maxDate && dateStr > props.maxDate) {\r\n return true;\r\n }\r\n \r\n return false;\r\n}\r\n\r\n// 计算指定月份的日期\r\nfunction getMonthDays(year: number, month: number): DayItem[] {\r\n const firstDay = new Date(year, month, 1);\r\n const lastDay = new Date(year, month + 1, 0);\r\n const firstDayWeek = firstDay.getDay();\r\n const daysInMonth = lastDay.getDate();\r\n \r\n const days: DayItem[] = [];\r\n \r\n // 上个月的日期\r\n const prevMonthLastDay = new Date(year, month, 0).getDate();\r\n for (let i = firstDayWeek - 1; i >= 0; i--) {\r\n const date = new Date(year, month - 1, prevMonthLastDay - i);\r\n const dayItem: DayItem = {\r\n date,\r\n type: 'prev-month',\r\n text: String(prevMonthLastDay - i),\r\n };\r\n \r\n if (props.formatter) {\r\n const formatted = props.formatter(dayItem);\r\n if (formatted.text) dayItem.text = formatted.text;\r\n if (formatted.bottomInfo) dayItem.bottomInfo = formatted.bottomInfo;\r\n }\r\n \r\n days.push(dayItem);\r\n }\r\n \r\n // 当前月的日期\r\n for (let i = 1; i <= daysInMonth; i++) {\r\n const date = new Date(year, month, i);\r\n const dayItem: DayItem = {\r\n date,\r\n type: 'current-month',\r\n text: String(i),\r\n };\r\n \r\n if (props.formatter) {\r\n const formatted = props.formatter(dayItem);\r\n if (formatted.text) dayItem.text = formatted.text;\r\n if (formatted.bottomInfo) dayItem.bottomInfo = formatted.bottomInfo;\r\n }\r\n \r\n days.push(dayItem);\r\n }\r\n \r\n // 下个月的日期(补齐6行)\r\n const remaining = 42 - days.length;\r\n for (let i = 1; i <= remaining; i++) {\r\n const date = new Date(year, month + 1, i);\r\n const dayItem: DayItem = {\r\n date,\r\n type: 'next-month',\r\n text: String(i),\r\n };\r\n \r\n if (props.formatter) {\r\n const formatted = props.formatter(dayItem);\r\n if (formatted.text) dayItem.text = formatted.text;\r\n if (formatted.bottomInfo) dayItem.bottomInfo = formatted.bottomInfo;\r\n }\r\n \r\n days.push(dayItem);\r\n }\r\n \r\n return days;\r\n}\r\n\r\n// 计算当前月份的所有日期\r\nconst monthDays = computed(() => {\r\n const year = currentDate.value.getFullYear();\r\n const month = currentDate.value.getMonth();\r\n return getMonthDays(year, month);\r\n});\r\n\r\n// 月份标题\r\nconst monthTitle = computed(() => {\r\n const year = currentDate.value.getFullYear();\r\n const month = currentDate.value.getMonth() + 1;\r\n return `${year}年${month}月`;\r\n});\r\n\r\n// 获取日期单元格的类名\r\nfunction getDayClass(day: DayItem) {\r\n const classes: string[] = [];\r\n \r\n if (day.type !== 'current-month') {\r\n classes.push('is-other-month');\r\n }\r\n \r\n if (isToday(day.date)) {\r\n classes.push('is-today');\r\n }\r\n \r\n if (isDisabled(day.date)) {\r\n classes.push('is-disabled');\r\n return classes;\r\n }\r\n \r\n const dateStr = formatDate(day.date);\r\n \r\n if (props.range) {\r\n if (props.rangeStart === dateStr) {\r\n classes.push('is-start');\r\n }\r\n if (props.rangeEnd === dateStr) {\r\n classes.push('is-end');\r\n }\r\n if (isInRange(day.date)) {\r\n classes.push('is-in-range');\r\n }\r\n } else {\r\n if (props.selectedDate === dateStr) {\r\n classes.push('is-selected');\r\n }\r\n }\r\n \r\n return classes;\r\n}\r\n\r\n// 区间是否完整\r\nconst isRangeComplete = computed(() => {\r\n return !!(props.rangeStart && props.rangeEnd);\r\n});\r\n\r\n// 已选中的日期范围项数\r\nconst selectedRangeCount = computed(() => {\r\n if (props.rangeStart && props.rangeEnd) {\r\n return 2;\r\n } else if (props.rangeStart || props.rangeEnd) {\r\n return 1;\r\n }\r\n return 0;\r\n});\r\n\r\n// 判断年份是否被禁用\r\nfunction isYearDisabled(year: number): boolean {\r\n if (!props.minDate && !props.maxDate) {\r\n return false;\r\n }\r\n \r\n const min = props.minDate ? parseDate(props.minDate) : null;\r\n const max = props.maxDate ? parseDate(props.maxDate) : null;\r\n \r\n if (min && year < min.getFullYear()) {\r\n return true;\r\n }\r\n if (max && year > max.getFullYear()) {\r\n return true;\r\n }\r\n \r\n return false;\r\n}\r\n\r\n// 判断月份是否被禁用\r\nfunction isMonthDisabled(year: number, month: number): boolean {\r\n const min = props.minDate ? parseDate(props.minDate) : null;\r\n const max = props.maxDate ? parseDate(props.maxDate) : null;\r\n \r\n if (min) {\r\n const minYear = min.getFullYear();\r\n const minMonth = min.getMonth() + 1;\r\n if (year < minYear || (year === minYear && month < minMonth)) {\r\n return true;\r\n }\r\n }\r\n \r\n if (max) {\r\n const maxYear = max.getFullYear();\r\n const maxMonth = max.getMonth() + 1;\r\n if (year > maxYear || (year === maxYear && month > maxMonth)) {\r\n return true;\r\n }\r\n }\r\n \r\n return false;\r\n}\r\n\r\n// 年月选择器状态\r\nconst showMonthPicker = ref(false);\r\nconst pickerMode = ref<'year' | 'month'>('year');\r\nconst tempYear = ref(currentDate.value.getFullYear());\r\nconst tempMonth = ref(currentDate.value.getMonth() + 1);\r\n\r\n// 年份选择器虚拟滚动\r\nconst yearScrollRef = ref<HTMLElement>();\r\nconst visibleYearStart = ref(1900);\r\nconst visibleYearEnd = ref(1920);\r\nconst dynamicMinYear = ref(1900);\r\nconst dynamicMaxYear = ref(2100);\r\n\r\n// 计算可见年份列表\r\nconst visibleYearList = computed(() => {\r\n const years: number[] = [];\r\n const bufferRows = 3;\r\n const startRow = Math.floor((visibleYearStart.value - dynamicMinYear.value) / itemsPerRow) - bufferRows;\r\n const endRow = Math.ceil((visibleYearEnd.value - dynamicMinYear.value) / itemsPerRow) + bufferRows;\r\n const start = dynamicMinYear.value + Math.max(0, startRow) * itemsPerRow;\r\n const end = dynamicMinYear.value + endRow * itemsPerRow - 1;\r\n \r\n for (let i = start; i <= end; i++) {\r\n years.push(i);\r\n }\r\n return years;\r\n});\r\n\r\n// 监听currentDate变化,同步tempYear和tempMonth\r\nwatch(() => currentDate.value, (date) => {\r\n tempYear.value = date.getFullYear();\r\n tempMonth.value = date.getMonth() + 1;\r\n}, { immediate: true });\r\n\r\n// 处理年份滚动\r\nfunction handleYearScroll() {\r\n if (!yearScrollRef.value) return;\r\n const scrollTop = yearScrollRef.value.scrollTop;\r\n const rowHeight = itemHeight;\r\n const startRow = Math.max(0, Math.floor(scrollTop / rowHeight));\r\n const newStart = dynamicMinYear.value + startRow * itemsPerRow;\r\n const newEnd = newStart + visibleRows * itemsPerRow - 1;\r\n \r\n // 动态扩展年份范围\r\n if (newStart < dynamicMinYear.value) {\r\n dynamicMinYear.value = newStart - 100;\r\n } else if (newEnd > dynamicMaxYear.value) {\r\n dynamicMaxYear.value = newEnd + 100;\r\n }\r\n \r\n if (newStart !== visibleYearStart.value || newEnd !== visibleYearEnd.value) {\r\n visibleYearStart.value = newStart;\r\n visibleYearEnd.value = newEnd;\r\n }\r\n}\r\n\r\n// 打开年月选择器\r\nfunction openMonthPicker() {\r\n tempYear.value = currentDate.value.getFullYear();\r\n tempMonth.value = currentDate.value.getMonth() + 1;\r\n pickerMode.value = 'year';\r\n showMonthPicker.value = true;\r\n \r\n // 动态调整年份范围\r\n const currentYear = tempYear.value;\r\n if (currentYear < dynamicMinYear.value) {\r\n dynamicMinYear.value = Math.floor(currentYear / 100) * 100;\r\n } else if (currentYear > dynamicMaxYear.value) {\r\n dynamicMaxYear.value = Math.ceil(currentYear / 100) * 100 + 99;\r\n }\r\n \r\n // 初始化可见年份范围\r\n nextTick(() => {\r\n if (yearScrollRef.value) {\r\n const rowIndex = Math.floor((currentYear - dynamicMinYear.value) / itemsPerRow);\r\n const startRow = Math.max(0, rowIndex - 2);\r\n visibleYearStart.value = dynamicMinYear.value + startRow * itemsPerRow;\r\n visibleYearEnd.value = visibleYearStart.value + visibleRows * itemsPerRow - 1;\r\n scrollToYear(currentYear);\r\n }\r\n });\r\n}\r\n\r\n// 滚动到指定年份\r\nfunction scrollToYear(year: number) {\r\n if (!yearScrollRef.value) return;\r\n \r\n if (year < dynamicMinYear.value) {\r\n dynamicMinYear.value = Math.floor(year / 100) * 100;\r\n } else if (year > dynamicMaxYear.value) {\r\n dynamicMaxYear.value = Math.ceil(year / 100) * 100 + 99;\r\n }\r\n \r\n const rowIndex = Math.floor((year - dynamicMinYear.value) / itemsPerRow);\r\n const scrollTop = rowIndex * itemHeight;\r\n yearScrollRef.value.scrollTop = scrollTop;\r\n const startRow = Math.max(0, rowIndex - 2);\r\n visibleYearStart.value = dynamicMinYear.value + startRow * itemsPerRow;\r\n visibleYearEnd.value = visibleYearStart.value + visibleRows * itemsPerRow - 1;\r\n}\r\n\r\n// 上一个月\r\nfunction prevMonth() {\r\n const date = new Date(currentDate.value);\r\n date.setMonth(date.getMonth() - 1);\r\n currentDate.value = date;\r\n}\r\n\r\n// 下一个月\r\nfunction nextMonth() {\r\n const date = new Date(currentDate.value);\r\n date.setMonth(date.getMonth() + 1);\r\n currentDate.value = date;\r\n}\r\n\r\n// 选择年份\r\nfunction selectYear(year: number) {\r\n if (isYearDisabled(year)) return;\r\n tempYear.value = year;\r\n pickerMode.value = 'month';\r\n}\r\n\r\n// 选择月份\r\nfunction selectMonth(month: number) {\r\n if (isMonthDisabled(tempYear.value, month)) return;\r\n tempMonth.value = month;\r\n // 直接确认并关闭\r\n confirmMonth();\r\n}\r\n\r\n// 确认年月选择\r\nfunction confirmMonth() {\r\n const date = new Date(currentDate.value);\r\n date.setFullYear(tempYear.value);\r\n date.setMonth(tempMonth.value - 1);\r\n currentDate.value = date;\r\n showMonthPicker.value = false;\r\n pickerMode.value = 'year';\r\n}\r\n\r\nfunction onSelectDay(day: DayItem) {\r\n emit('select-day', day);\r\n}\r\n\r\nfunction onClear() {\r\n emit('clear');\r\n}\r\n\r\n// 处理标题栏清空按钮点击\r\nfunction handleHeaderClear() {\r\n if (!hasValue.value) return;\r\n onClear();\r\n}\r\n\r\nfunction onConfirm() {\r\n emit('confirm');\r\n}\r\n\r\nfunction onCloseMonthPicker() {\r\n showMonthPicker.value = false;\r\n}\r\n\r\nfunction onPickerModeChange(mode: 'year' | 'month') {\r\n pickerMode.value = mode;\r\n}\r\n\r\n// 选择本年(年份选择模式下)\r\nfunction selectCurrentYear() {\r\n const today = new Date();\r\n const currentYear = today.getFullYear();\r\n if (isYearDisabled(currentYear)) return;\r\n tempYear.value = currentYear;\r\n // 选择年后切换到月份选择\r\n pickerMode.value = 'month';\r\n}\r\n\r\n// 选择本月(月份选择模式下)\r\nfunction selectCurrentMonth() {\r\n const today = new Date();\r\n const currentMonth = today.getMonth() + 1;\r\n if (isMonthDisabled(tempYear.value, currentMonth)) return;\r\n tempMonth.value = currentMonth;\r\n // 选择月后直接确认并关闭\r\n confirmMonth();\r\n}\r\n\r\n// 是否有值(用于显示清空按钮)\r\nconst hasValue = computed(() => {\r\n if (props.range) {\r\n return !!(props.rangeStart || props.rangeEnd);\r\n } else {\r\n return !!props.selectedDate;\r\n }\r\n});\r\n\r\n// 快捷选项定义\r\ninterface ShortcutOption {\r\n key: string;\r\n label: string;\r\n getRange: () => [string, string] | null;\r\n days?: number; // 该选项对应的天数\r\n disabled?: boolean;\r\n}\r\n\r\n// 计算两个日期之间的天数差\r\nfunction getDaysBetween(start: string, end: string): number {\r\n const startDate = parseDate(start);\r\n const endDate = parseDate(end);\r\n if (!startDate || !endDate) return 0;\r\n const diffTime = Math.abs(endDate.getTime() - startDate.getTime());\r\n return Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1; // +1 因为包含开始和结束日期\r\n}\r\n\r\n// 获取今天的日期字符串\r\nfunction getTodayStr(): string {\r\n return formatDate(new Date());\r\n}\r\n\r\n// 获取本周的开始日期(周一)\r\nfunction getWeekStart(): Date {\r\n const today = new Date();\r\n const day = today.getDay();\r\n const diff = today.getDate() - day + (day === 0 ? -6 : 1); // 调整为周一\r\n return new Date(today.getFullYear(), today.getMonth(), diff);\r\n}\r\n\r\n// 获取本周的结束日期(周日)\r\nfunction getWeekEnd(): Date {\r\n const weekStart = getWeekStart();\r\n const weekEnd = new Date(weekStart);\r\n weekEnd.setDate(weekStart.getDate() + 6); // 周日是周一+6天\r\n return weekEnd;\r\n}\r\n\r\n// 获取本月的开始日期\r\nfunction getMonthStart(): Date {\r\n const today = new Date();\r\n return new Date(today.getFullYear(), today.getMonth(), 1);\r\n}\r\n\r\n// 获取本月的结束日期\r\nfunction getMonthEnd(): Date {\r\n const today = new Date();\r\n return new Date(today.getFullYear(), today.getMonth() + 1, 0); // 下个月的第0天就是本月的最后一天\r\n}\r\n\r\n// 获取近三个月的开始日期\r\nfunction getThreeMonthsAgo(): Date {\r\n const today = new Date();\r\n return new Date(today.getFullYear(), today.getMonth() - 2, 1);\r\n}\r\n\r\n// 获取本年的开始日期\r\nfunction getYearStart(): Date {\r\n const today = new Date();\r\n return new Date(today.getFullYear(), 0, 1);\r\n}\r\n\r\n// 获取本年的结束日期\r\nfunction getYearEnd(): Date {\r\n const today = new Date();\r\n return new Date(today.getFullYear(), 11, 31); // 12月的第31天\r\n}\r\n\r\n// 所有快捷选项\r\nconst allShortcuts: ShortcutOption[] = [\r\n {\r\n key: 'today',\r\n label: '本日',\r\n days: 1,\r\n getRange: () => {\r\n const today = getTodayStr();\r\n return [today, today];\r\n },\r\n },\r\n {\r\n key: 'week',\r\n label: '本周',\r\n days: 7,\r\n getRange: () => {\r\n const start = formatDate(getWeekStart());\r\n const end = formatDate(getWeekEnd());\r\n return [start, end];\r\n },\r\n },\r\n {\r\n key: 'month',\r\n label: '本月',\r\n getRange: () => {\r\n const start = formatDate(getMonthStart());\r\n const end = formatDate(getMonthEnd());\r\n return [start, end];\r\n },\r\n },\r\n {\r\n key: 'threeMonths',\r\n label: '近三月',\r\n getRange: () => {\r\n const start = formatDate(getThreeMonthsAgo());\r\n const end = formatDate(getMonthEnd()); // 到本月结束\r\n return [start, end];\r\n },\r\n },\r\n {\r\n key: 'year',\r\n label: '本年',\r\n getRange: () => {\r\n const start = formatDate(getYearStart());\r\n const end = formatDate(getYearEnd());\r\n return [start, end];\r\n },\r\n },\r\n {\r\n key: 'last7Days',\r\n label: '近7天',\r\n days: 7,\r\n getRange: () => {\r\n const today = new Date();\r\n const startDate = new Date(today);\r\n startDate.setDate(today.getDate() - 6); // 包含今天,所以是 -6\r\n return [formatDate(startDate), getTodayStr()];\r\n },\r\n },\r\n {\r\n key: 'last30Days',\r\n label: '近30天',\r\n days: 30,\r\n getRange: () => {\r\n const today = new Date();\r\n const startDate = new Date(today);\r\n startDate.setDate(today.getDate() - 29); // 包含今天,所以是 -29\r\n return [formatDate(startDate), getTodayStr()];\r\n },\r\n },\r\n];\r\n\r\n// 根据 range 过滤可用的快捷选项(不可选的直接隐藏)\r\nconst availableShortcuts = computed(() => {\r\n return allShortcuts.filter(option => {\r\n // 如果设置了最大天数限制,检查该选项是否符合\r\n if (props.maxRangeDays !== undefined) {\r\n if (option.days !== undefined) {\r\n // 如果选项有明确的天数,直接比较\r\n return option.days <= props.maxRangeDays;\r\n } else {\r\n // 如果选项没有明确的天数,计算实际天数\r\n const range = option.getRange();\r\n if (range) {\r\n const days = getDaysBetween(range[0], range[1]);\r\n return days <= props.maxRangeDays;\r\n }\r\n }\r\n }\r\n \r\n // 没有限制时,所有选项都可用\r\n return true;\r\n });\r\n});\r\n\r\n// 处理快捷选项点击\r\nfunction handleShortcutClick(option: ShortcutOption) {\r\n const range = option.getRange();\r\n if (range) {\r\n // 检查日期范围是否在 minDate 和 maxDate 范围内\r\n if (props.minDate && range[0] < props.minDate) {\r\n return;\r\n }\r\n if (props.maxDate && range[1] > props.maxDate) {\r\n return;\r\n }\r\n \r\n // 触发选择日期事件(通过模拟点击日期来实现)\r\n // 这里需要直接设置 rangeStart 和 rangeEnd,但它们是 props,不能直接修改\r\n // 所以需要通过 emit 来通知父组件\r\n emit('shortcut-select', range);\r\n }\r\n}\r\n\r\ndefineExpose({\r\n yearScrollRef\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-calendar {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n margin-bottom: 16px;\r\n padding-bottom: 12px;\r\n border-bottom: 1px solid var(--rc-border);\r\n }\r\n\r\n &__header-title {\r\n font-size: 16px;\r\n font-weight: 600;\r\n color: var(--rc-text);\r\n }\r\n\r\n &__header-clear {\r\n color: var(--rc-primary);\r\n font-size: 14px;\r\n cursor: pointer;\r\n transition: all 0.2s;\r\n\r\n &:hover:not(.is-disabled) {\r\n opacity: 0.8;\r\n }\r\n\r\n &.is-disabled {\r\n color: var(--rc-disabled);\r\n cursor: not-allowed;\r\n }\r\n }\r\n\r\n &__shortcuts {\r\n margin-bottom: 16px;\r\n overflow: hidden;\r\n }\r\n\r\n &__shortcuts-scroll {\r\n display: flex;\r\n gap: 8px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n -webkit-overflow-scrolling: touch;\r\n scrollbar-width: none; /* Firefox */\r\n -ms-overflow-style: none; /* IE and Edge */\r\n \r\n &::-webkit-scrollbar {\r\n display: none; /* Chrome, Safari, Opera */\r\n }\r\n }\r\n\r\n &__shortcut-item {\r\n flex-shrink: 0;\r\n padding: 6px 16px;\r\n border: 1px solid var(--rc-border);\r\n border-radius: 16px;\r\n background: var(--rc-white);\r\n font-size: 14px;\r\n color: var(--rc-text);\r\n cursor: pointer;\r\n transition: all 0.2s;\r\n white-space: nowrap;\r\n\r\n &:hover {\r\n border-color: var(--rc-primary);\r\n color: var(--rc-primary);\r\n }\r\n }\r\n\r\n &__month-title {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n margin-bottom: 16px;\r\n }\r\n\r\n &__month-text {\r\n font-size: 16px;\r\n font-weight: 600;\r\n color: var(--rc-text);\r\n cursor: pointer;\r\n user-select: none;\r\n }\r\n\r\n &__nav-button {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n background: rgba(22, 119, 255, 0.1);\r\n cursor: pointer;\r\n transition: all 0.2s;\r\n\r\n &:hover {\r\n background: rgba(22, 119, 255, 0.2);\r\n }\r\n\r\n &:active {\r\n background: rgba(22, 119, 255, 0.3);\r\n }\r\n }\r\n\r\n &__nav-icon {\r\n color: var(--rc-primary);\r\n font-size: 16px;\r\n }\r\n\r\n &__weekdays {\r\n display: grid;\r\n grid-template-columns: repeat(7, 1fr);\r\n margin-bottom: 8px;\r\n }\r\n\r\n &__weekday {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 32px;\r\n font-size: 14px;\r\n font-weight: 500;\r\n color: var(--rc-text);\r\n }\r\n\r\n &__days {\r\n display: grid;\r\n grid-template-columns: repeat(7, 1fr);\r\n gap: 4px;\r\n }\r\n\r\n &__day {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n min-height: 30px;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n transition: all 0.2s;\r\n\r\n &.is-other-month {\r\n opacity: 0.3;\r\n cursor: default;\r\n }\r\n\r\n &.is-disabled {\r\n opacity: 0.3;\r\n cursor: not-allowed;\r\n }\r\n\r\n &.is-in-range:not(.is-start):not(.is-end) {\r\n background: rgba(22, 119, 255, 0.1);\r\n }\r\n\r\n &.is-today {\r\n .rc-calendar__day-text {\r\n color: var(--rc-primary);\r\n font-weight: 600;\r\n }\r\n }\r\n\r\n &.is-start,\r\n &.is-end {\r\n background: var(--rc-primary);\r\n color: var(--rc-white);\r\n\r\n .rc-calendar__day-text {\r\n color: var(--rc-white);\r\n font-weight: 600;\r\n }\r\n }\r\n\r\n &.is-selected {\r\n background: var(--rc-primary);\r\n color: var(--rc-white);\r\n\r\n .rc-calendar__day-text {\r\n color: var(--rc-white);\r\n font-weight: 600;\r\n }\r\n }\r\n\r\n &:hover:not(.is-disabled):not(.is-other-month):not(.is-start):not(.is-end):not(.is-selected) {\r\n background: var(--rc-bg);\r\n }\r\n }\r\n\r\n &__day-content {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 2px;\r\n }\r\n\r\n &__day-text {\r\n font-size: 14px;\r\n color: var(--rc-text);\r\n }\r\n\r\n &__day-bottom {\r\n font-size: 10px;\r\n color: var(--rc-text);\r\n opacity: 0.7;\r\n }\r\n\r\n &__footer {\r\n display: flex;\r\n justify-content: space-between;\r\n gap: 12px;\r\n margin-top: 16px;\r\n padding-top: 16px;\r\n border-top: 1px solid var(--rc-border);\r\n\r\n &-reset {\r\n flex: 1;\r\n background: var(--rc-white);\r\n color: var(--rc-text);\r\n border-color: var(--rc-border);\r\n }\r\n\r\n &-confirm {\r\n flex: 1;\r\n }\r\n }\r\n\r\n &__month-picker-overlay {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n z-index: 10;\r\n background: var(--rc-white);\r\n border-radius: 8px;\r\n }\r\n\r\n &__month-picker {\r\n position: relative;\r\n height: 100%;\r\n background: var(--rc-white);\r\n border-radius: 8px;\r\n display: flex;\r\n flex-direction: column;\r\n }\r\n\r\n &__month-picker-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 0 16px 16px;\r\n flex-shrink: 0;\r\n }\r\n\r\n &__month-picker-title {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n font-size: 16px;\r\n font-weight: 600;\r\n color: var(--rc-text);\r\n \r\n span {\r\n cursor: pointer;\r\n transition: color 0.2s;\r\n \r\n &:hover {\r\n color: var(--rc-primary);\r\n }\r\n }\r\n }\r\n\r\n &__year-picker-content {\r\n flex: 1;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n min-height: 0;\r\n }\r\n\r\n &__year-picker-scroll {\r\n flex: 1;\r\n overflow-y: auto;\r\n -webkit-overflow-scrolling: touch;\r\n min-height: 0;\r\n }\r\n\r\n &__year-picker-spacer {\r\n width: 100%;\r\n }\r\n\r\n &__year-picker-grid {\r\n display: grid;\r\n grid-template-columns: repeat(3, 1fr);\r\n gap: 8px;\r\n padding: 8px 16px;\r\n }\r\n\r\n &__year-picker-item {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 40px;\r\n border: 1px solid var(--rc-border);\r\n border-radius: 6px;\r\n background: var(--rc-bg);\r\n font-size: 14px;\r\n color: var(--rc-text);\r\n cursor: pointer;\r\n transition: all 0.2s;\r\n\r\n &:hover:not(.is-selected):not(.is-disabled) {\r\n border-color: var(--rc-primary);\r\n color: var(--rc-primary);\r\n }\r\n\r\n &.is-selected {\r\n background: var(--rc-primary);\r\n border-color: var(--rc-primary);\r\n color: var(--rc-white);\r\n }\r\n\r\n &.is-disabled {\r\n opacity: 0.3;\r\n cursor: not-allowed;\r\n }\r\n }\r\n\r\n &__month-picker-content {\r\n display: grid;\r\n grid-template-columns: repeat(3, 1fr);\r\n gap: 8px;\r\n padding: 0 16px 16px;\r\n }\r\n\r\n &__month-picker-item {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 40px;\r\n border: 1px solid var(--rc-border);\r\n border-radius: 6px;\r\n background: var(--rc-white);\r\n font-size: 14px;\r\n color: var(--rc-text);\r\n cursor: pointer;\r\n transition: all 0.2s;\r\n\r\n &:hover:not(.is-selected):not(.is-disabled) {\r\n border-color: var(--rc-primary);\r\n color: var(--rc-primary);\r\n }\r\n\r\n &.is-selected {\r\n background: var(--rc-primary);\r\n border-color: var(--rc-primary);\r\n color: var(--rc-white);\r\n }\r\n\r\n &.is-disabled {\r\n opacity: 0.3;\r\n cursor: not-allowed;\r\n }\r\n }\r\n}\r\n\r\n// 过渡动画\r\n.rc-calendar-fade-enter-active,\r\n.rc-calendar-fade-leave-active {\r\n transition: opacity 0.3s;\r\n}\r\n\r\n.rc-calendar-fade-enter-from,\r\n.rc-calendar-fade-leave-to {\r\n opacity: 0;\r\n}\r\n</style>\r\n\r\n","<template>\r\n <div class=\"rc-calendar\">\r\n <!-- 输入框模式 -->\r\n <div v-if=\"mode === 'popup'\" class=\"rc-calendar__input\" @click=\"open\">\r\n <input\r\n ref=\"inputRef\"\r\n v-model=\"inputText\"\r\n type=\"text\"\r\n class=\"rc-calendar__input-field\"\r\n :placeholder=\"placeholder\"\r\n readonly\r\n @focus=\"handleInputFocus\"\r\n @blur=\"handleInputBlur\"\r\n @input=\"handleInput\"\r\n />\r\n <div class=\"rc-calendar__input-actions\">\r\n <rc-icon name=\"icon_a-rili\" class=\"rc-calendar__input-icon\" />\r\n </div>\r\n </div>\r\n\r\n <!-- 日历面板 - 直接展示模式 -->\r\n <div \r\n v-if=\"mode === 'default'\"\r\n class=\"rc-calendar__panel\"\r\n >\r\n <CalendarPanelContent\r\n :show-title=\"showTitle\"\r\n :title=\"title\"\r\n :range=\"isRangeMode\"\r\n :selected-date=\"selectedDate\"\r\n :range-start=\"rangeStart\"\r\n :range-end=\"rangeEnd\"\r\n :min-date=\"minDate\"\r\n :max-date=\"maxDate\"\r\n :disabled-date=\"mergedDisabledDate\"\r\n :formatter=\"formatter\"\r\n :show-footer=\"false\"\r\n :max-range-days=\"maxRangeDays\"\r\n @select-day=\"onSelectDay\"\r\n @clear=\"onClear\"\r\n @confirm=\"onConfirm\"\r\n @shortcut-select=\"onShortcutSelect\"\r\n />\r\n </div>\r\n\r\n <!-- 日历面板 - Popup 模式 -->\r\n <rc-popup\r\n v-if=\"mode === 'popup'\"\r\n v-model=\"visible\"\r\n position=\"bottom\"\r\n :overlay=\"true\"\r\n :round=\"true\"\r\n :close-on-click-overlay=\"true\"\r\n :lock-scroll=\"true\"\r\n @update:modelValue=\"handlePopupClose\"\r\n >\r\n <div \r\n ref=\"popupPanelRef\"\r\n class=\"rc-calendar__panel\"\r\n >\r\n <CalendarPanelContent\r\n :show-title=\"showTitle\"\r\n :title=\"title\"\r\n :range=\"isRangeMode\"\r\n :selected-date=\"selectedDate\"\r\n :range-start=\"rangeStart\"\r\n :range-end=\"rangeEnd\"\r\n :min-date=\"minDate\"\r\n :max-date=\"maxDate\"\r\n :disabled-date=\"mergedDisabledDate\"\r\n :formatter=\"formatter\"\r\n :show-footer=\"showFooter\"\r\n :max-range-days=\"maxRangeDays\"\r\n @select-day=\"onSelectDay\"\r\n @clear=\"onClear\"\r\n @confirm=\"onConfirm\"\r\n @shortcut-select=\"onShortcutSelect\"\r\n />\r\n </div>\r\n </rc-popup>\r\n \r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue';\r\nimport RcIcon from '../icon';\r\nimport RcButton from '../button';\r\nimport RcPopup from '../popup';\r\nimport CalendarPanelContent from './panel-content.vue';\r\n\r\ndefineOptions({ name: 'rc-calendar' });\r\n\r\ntype CalendarValue = string | [string, string] | null;\r\n\r\ninterface DayItem {\r\n date: Date;\r\n type: string;\r\n text: string;\r\n bottomInfo?: string;\r\n}\r\n\r\ntype CalendarMode = 'default' | 'popup';\r\n\r\ninterface Props {\r\n /** 当前选中的日期,格式为 YYYY-MM-DD */\r\n modelValue?: CalendarValue;\r\n /** 是否支持区间选择:true/false 或数字(表示区间可选的最大天数) */\r\n range?: boolean | number;\r\n /** 显示模式:default 直接展示,popup 输入框模式(点击后弹出日历) */\r\n mode?: CalendarMode;\r\n /** 输入框占位符 */\r\n placeholder?: string;\r\n /** 是否显示标题栏 */\r\n showTitle?: boolean;\r\n /** 标题栏文字 */\r\n title?: string;\r\n /** 最小可选日期 */\r\n minDate?: string;\r\n /** 最大可选日期 */\r\n maxDate?: string;\r\n /** 禁用日期函数 */\r\n disabledDate?: (date: Date) => boolean;\r\n /** 日期格式化函数 */\r\n formatter?: (day: DayItem) => { text?: string; bottomInfo?: string };\r\n /** 区间模式下是否显示底部按钮(确定/取消),为 false 时区间完整后自动确认 */\r\n showFooter?: boolean;\r\n /** 区间模式下,结束日期是否自动加一天(选中日期为结束日期时,实际返回的结束日期会加一天) */\r\n endDateOffset?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n modelValue: null,\r\n range: false,\r\n mode: 'default',\r\n placeholder: '请选择日期',\r\n showTitle: true,\r\n title: '选择日期',\r\n minDate: undefined,\r\n maxDate: undefined,\r\n disabledDate: undefined,\r\n formatter: undefined,\r\n showFooter: true,\r\n endDateOffset: false,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: CalendarValue): void;\r\n (e: 'change', value: CalendarValue): void;\r\n (e: 'confirm', value: CalendarValue): void;\r\n}>();\r\n\r\nconst inputRef = ref<HTMLInputElement>();\r\nconst popupPanelRef = ref<HTMLElement>();\r\nconst visible = ref(false);\r\nconst inputText = ref('');\r\n\r\n// 判断是否是区间模式\r\nconst isRangeMode = computed(() => {\r\n return props.range === true || typeof props.range === 'number';\r\n});\r\n\r\n// 最大区间天数(如果是数字模式)\r\nconst maxRangeDays = computed(() => {\r\n return typeof props.range === 'number' ? props.range : undefined;\r\n});\r\n\r\n// 合并禁用日期函数(包括天数限制)\r\nconst mergedDisabledDate = computed(() => {\r\n return (date: Date): boolean => {\r\n // 先检查用户自定义的禁用函数\r\n if (props.disabledDate && props.disabledDate(date)) {\r\n return true;\r\n }\r\n \r\n // 如果设置了最大天数限制且已选择开始日期,禁用超出范围的日期\r\n if (maxRangeDays.value !== undefined && rangeStart.value && !rangeEnd.value) {\r\n const dateStr = formatDate(date);\r\n const startDate = parseDate(rangeStart.value);\r\n if (startDate) {\r\n const days = getDaysBetween(rangeStart.value, dateStr);\r\n // 如果日期超出最大天数范围(包括开始日期之前的日期),则禁用\r\n if (days > maxRangeDays.value) {\r\n return true;\r\n }\r\n }\r\n }\r\n \r\n return false;\r\n };\r\n});\r\n\r\n// 单日期模式:选中的日期\r\nconst selectedDate = ref<string | null>(null);\r\n// 区间模式:选中的开始和结束日期\r\nconst rangeStart = ref<string | null>(null);\r\nconst rangeEnd = ref<string | null>(null);\r\n\r\n// 初始化选中值\r\nwatch(\r\n () => props.modelValue,\r\n (val) => {\r\n if (isRangeMode.value) {\r\n if (Array.isArray(val) && val.length === 2) {\r\n rangeStart.value = val[0];\r\n // 如果启用了 endDateOffset,从外部传入的结束日期需要减一天来显示\r\n rangeEnd.value = getDisplayEndDate(val[1]);\r\n } else {\r\n rangeStart.value = null;\r\n rangeEnd.value = null;\r\n }\r\n } else {\r\n selectedDate.value = typeof val === 'string' ? val : null;\r\n }\r\n updateInputText();\r\n },\r\n { immediate: true }\r\n);\r\n\r\n// 更新输入框文本\r\nfunction updateInputText() {\r\n if (props.mode !== 'popup') return;\r\n \r\n if (isRangeMode.value) {\r\n if (rangeStart.value && rangeEnd.value) {\r\n // 显示时使用用户实际选择的日期(rangeEnd 存储的就是用户选择的日期)\r\n inputText.value = `${rangeStart.value} ~ ${rangeEnd.value}`;\r\n } else if (rangeStart.value) {\r\n inputText.value = `${rangeStart.value} ~ `;\r\n } else {\r\n inputText.value = '';\r\n }\r\n } else {\r\n inputText.value = selectedDate.value || '';\r\n }\r\n}\r\n\r\n\r\n// 解析日期字符串\r\nfunction parseDate(dateStr: string | null | undefined): Date | null {\r\n if (!dateStr) return null;\r\n const date = new Date(dateStr);\r\n return isNaN(date.getTime()) ? null : date;\r\n}\r\n\r\n// 格式化日期为 YYYY-MM-DD\r\nfunction formatDate(date: Date): string {\r\n const year = date.getFullYear();\r\n const month = String(date.getMonth() + 1).padStart(2, '0');\r\n const day = String(date.getDate()).padStart(2, '0');\r\n return `${year}-${month}-${day}`;\r\n}\r\n\r\n\r\n\r\n// 计算两个日期之间的天数差\r\nfunction getDaysBetween(start: string, end: string): number {\r\n const startDate = parseDate(start);\r\n const endDate = parseDate(end);\r\n if (!startDate || !endDate) return 0;\r\n const diffTime = Math.abs(endDate.getTime() - startDate.getTime());\r\n return Math.ceil(diffTime / (1000 * 60 * 60 * 24));\r\n}\r\n\r\n// 给日期加一天\r\nfunction addOneDay(dateStr: string): string {\r\n const date = parseDate(dateStr);\r\n if (!date) return dateStr;\r\n date.setDate(date.getDate() + 1);\r\n return formatDate(date);\r\n}\r\n\r\n// 给日期减一天\r\nfunction subtractOneDay(dateStr: string): string {\r\n const date = parseDate(dateStr);\r\n if (!date) return dateStr;\r\n date.setDate(date.getDate() - 1);\r\n return formatDate(date);\r\n}\r\n\r\n// 获取实际的结束日期(如果启用了 endDateOffset,则加一天)\r\nfunction getActualEndDate(endDate: string): string {\r\n if (props.endDateOffset && isRangeMode.value) {\r\n return addOneDay(endDate);\r\n }\r\n return endDate;\r\n}\r\n\r\n// 获取显示的结束日期(如果启用了 endDateOffset,从外部传入的值需要减一天来显示)\r\nfunction getDisplayEndDate(endDate: string): string {\r\n if (props.endDateOffset && isRangeMode.value) {\r\n return subtractOneDay(endDate);\r\n }\r\n return endDate;\r\n}\r\n\r\n// 选择日期\r\nfunction onSelectDay(day: DayItem) {\r\n if (day.type !== 'current-month') {\r\n return;\r\n }\r\n \r\n // 检查是否被禁用\r\n if (props.disabledDate && props.disabledDate(day.date)) {\r\n return;\r\n }\r\n \r\n const dateStr = formatDate(day.date);\r\n if (props.minDate && dateStr < props.minDate) {\r\n return;\r\n }\r\n if (props.maxDate && dateStr > props.maxDate) {\r\n return;\r\n }\r\n \r\n if (isRangeMode.value) {\r\n if (!rangeStart.value || (rangeStart.value && rangeEnd.value)) {\r\n // 重新开始选择\r\n rangeStart.value = dateStr;\r\n rangeEnd.value = null;\r\n } else {\r\n // 选择结束日期\r\n let start = rangeStart.value;\r\n let end = dateStr;\r\n \r\n if (dateStr < rangeStart.value!) {\r\n // 如果结束日期早于开始日期,交换\r\n end = rangeStart.value;\r\n start = dateStr;\r\n }\r\n \r\n rangeStart.value = start;\r\n rangeEnd.value = end;\r\n \r\n // 区间模式下,选择完成后立即触发 change\r\n if (rangeStart.value && rangeEnd.value) {\r\n const actualEnd = getActualEndDate(rangeEnd.value);\r\n const value: [string, string] = [rangeStart.value, actualEnd];\r\n emit('update:modelValue', value);\r\n emit('change', value);\r\n \r\n // 如果隐藏了底部按钮,区间完整后自动确认\r\n if (!props.showFooter) {\r\n onConfirm();\r\n }\r\n }\r\n }\r\n } else {\r\n selectedDate.value = dateStr;\r\n const value = dateStr;\r\n emit('update:modelValue', value);\r\n emit('change', value);\r\n \r\n // 单日期模式下,选择后自动关闭(输入框模式或弹窗模式)\r\n if (props.mode) {\r\n close();\r\n }\r\n }\r\n \r\n updateInputText();\r\n}\r\n\r\n// 确认选择(区间模式)\r\nfunction onConfirm() {\r\n if (rangeStart.value && rangeEnd.value) {\r\n const actualEnd = getActualEndDate(rangeEnd.value);\r\n const value: [string, string] = [rangeStart.value, actualEnd];\r\n emit('update:modelValue', value);\r\n emit('change', value);\r\n emit('confirm', value);\r\n close();\r\n }\r\n}\r\n\r\n// 清除选择\r\nfunction onClear() {\r\n if (isRangeMode.value) {\r\n rangeStart.value = null;\r\n rangeEnd.value = null;\r\n } else {\r\n selectedDate.value = null;\r\n }\r\n const value = null;\r\n emit('update:modelValue', value);\r\n emit('change', value);\r\n updateInputText();\r\n}\r\n\r\n// 处理快捷选项选择\r\nfunction onShortcutSelect(range: [string, string]) {\r\n rangeStart.value = range[0];\r\n rangeEnd.value = range[1];\r\n const actualEnd = getActualEndDate(range[1]);\r\n const value: [string, string] = [range[0], actualEnd];\r\n emit('update:modelValue', value);\r\n emit('change', value);\r\n \r\n // 如果隐藏了底部按钮,区间完整后自动确认\r\n if (!props.showFooter) {\r\n onConfirm();\r\n } else {\r\n updateInputText();\r\n }\r\n}\r\n\r\n\r\n\r\n\r\n// 打开日历\r\nfunction open() {\r\n visible.value = true;\r\n}\r\n\r\n// 关闭日历\r\nfunction close() {\r\n visible.value = false;\r\n}\r\n\r\n// Popup 关闭处理\r\nfunction handlePopupClose(value: boolean) {\r\n visible.value = value;\r\n}\r\n\r\n// 处理输入框焦点\r\nfunction handleInputFocus() {\r\n open();\r\n}\r\n\r\n// 处理输入框失焦\r\nfunction handleInputBlur() {\r\n if (props.mode === 'popup') {\r\n parseInputText();\r\n }\r\n}\r\n\r\n// 处理输入框输入\r\nfunction handleInput() {\r\n if (!visible.value) {\r\n open();\r\n }\r\n}\r\n\r\n// 解析输入文本\r\nfunction parseInputText() {\r\n const text = inputText.value.trim();\r\n \r\n if (isRangeMode.value) {\r\n // 区间模式:支持 \"YYYY-MM-DD ~ YYYY-MM-DD\" 格式\r\n const parts = text.split('~').map(s => s.trim());\r\n if (parts.length === 2 && parts[0] && parts[1]) {\r\n const start = parseDate(parts[0]);\r\n const end = parseDate(parts[1]);\r\n if (start && end && !isNaN(start.getTime()) && !isNaN(end.getTime())) {\r\n rangeStart.value = formatDate(start);\r\n // 解析输入文本时,如果启用了 endDateOffset,需要将输入的结束日期减一天来存储\r\n const endStr = formatDate(end);\r\n rangeEnd.value = getDisplayEndDate(endStr);\r\n const actualEnd = getActualEndDate(rangeEnd.value);\r\n const value: [string, string] = [rangeStart.value, actualEnd];\r\n emit('update:modelValue', value);\r\n emit('change', value);\r\n return;\r\n }\r\n }\r\n } else {\r\n // 单日期模式\r\n const date = parseDate(text);\r\n if (date && !isNaN(date.getTime())) {\r\n selectedDate.value = formatDate(date);\r\n emit('update:modelValue', selectedDate.value);\r\n emit('change', selectedDate.value);\r\n return;\r\n }\r\n }\r\n \r\n // 解析失败,恢复显示值\r\n updateInputText();\r\n}\r\n\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-calendar {\r\n --rc-primary: #1677ff;\r\n --rc-text: #323233;\r\n --rc-border: #dcdee0;\r\n --rc-white: #ffffff;\r\n --rc-bg: #f7f8fa;\r\n --rc-disabled: #c8c9cc;\r\n\r\n position: relative;\r\n width: 100%;\r\n\r\n &__input {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n width: 100%;\r\n padding: 8px 12px;\r\n border: 1px solid var(--rc-border);\r\n border-radius: 6px;\r\n background: var(--rc-white);\r\n cursor: pointer;\r\n }\r\n\r\n &__input-field {\r\n flex: 1;\r\n border: none;\r\n outline: none;\r\n background: transparent;\r\n font-size: 14px;\r\n color: var(--rc-text);\r\n\r\n &::placeholder {\r\n color: var(--rc-disabled);\r\n }\r\n }\r\n\r\n &__input-actions {\r\n display: flex;\r\n align-items: center;\r\n }\r\n\r\n &__input-icon {\r\n color: var(--rc-disabled);\r\n font-size: 18px;\r\n }\r\n\r\n &__panel {\r\n position: relative;\r\n padding: 16px;\r\n background: var(--rc-white);\r\n border-radius: 8px;\r\n display: flex;\r\n flex-direction: column;\r\n }\r\n}\r\n</style>\r\n","import type { App } from 'vue';\r\nimport Calendar from './index.vue';\r\n\r\n// 组件名使用全小写,以 <rc-calendar> 形式在模板中使用\r\nif (Calendar) {\r\n (Calendar as any).name = 'rc-calendar';\r\n}\r\nconst PascalName = 'RcCalendar';\r\n\r\nexport function install(app: App) {\r\n if (Calendar) {\r\n app.component((Calendar as any).name || 'rc-calendar', Calendar);\r\n app.component(PascalName, Calendar);\r\n }\r\n return app;\r\n}\r\n\r\nexport default Calendar;\r\n\r\n","<template>\r\n <div class=\"rc-search-area\">\r\n <!-- 筛选项按钮行 -->\r\n <div class=\"rc-search-area__bar\">\r\n <div\r\n v-for=\"(item, index) in props.items\"\r\n :key=\"index\"\r\n class=\"rc-search-area__item\"\r\n :class=\"{ \r\n 'is-active': activeIndex === index,\r\n 'has-value': getSelectedCount(item) > 0\r\n }\"\r\n @click=\"openFilter(index)\"\r\n >\r\n <span class=\"rc-search-area__item-label\">{{ getItemDisplayText(item) }}</span>\r\n <rc-icon \r\n name=\"icon_a-xiala2\" \r\n :color=\"(activeIndex !== index && getSelectedCount(item) > 0) ? '#1677ff' : '#969799'\"\r\n class=\"rc-search-area__item-arrow\" \r\n :class=\"{ 'is-up': activeIndex === index }\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 蒙层 -->\r\n <transition name=\"rc-search-area-fade\">\r\n <div \r\n v-if=\"activeIndex !== null && props.showMask\" \r\n ref=\"maskRef\"\r\n class=\"rc-search-area__mask\"\r\n :style=\"maskStyle\"\r\n @click=\"closeFilter\"\r\n ></div>\r\n </transition>\r\n\r\n <!-- 筛选面板 -->\r\n <transition name=\"rc-search-area-slide\">\r\n <div v-if=\"activeIndex !== null\" ref=\"panelRef\" class=\"rc-search-area__panel\">\r\n <div class=\"rc-search-area__panel-content\">\r\n <!-- 插槽模式 -->\r\n <template v-if=\"currentFilter?.slot && $slots[currentFilter.key]\">\r\n <slot \r\n :name=\"currentFilter.key\" \r\n :value=\"getSlotValue(currentFilter)\"\r\n :update:value=\"(val: any) => updateSlotValue(currentFilter, val)\"\r\n />\r\n </template>\r\n\r\n <!-- 输入框模式 -->\r\n <template v-else-if=\"currentFilter?.type === 'input'\">\r\n <div class=\"rc-search-area__input-wrapper\">\r\n <input\r\n v-model=\"tempInputValue\"\r\n type=\"text\"\r\n class=\"rc-search-area__input\"\r\n :placeholder=\"currentFilter.placeholder || '请输入'\"\r\n @input=\"handleInputChange\"\r\n />\r\n </div> \r\n </template>\r\n\r\n <!-- 日期选择器模式 -->\r\n <template v-else-if=\"currentFilter?.type === 'calendar'\">\r\n <div class=\"rc-search-area__calendar-wrapper\">\r\n <rc-calendar\r\n v-model=\"tempCalendarValue\"\r\n :range=\"currentFilter.calendarConfig?.range || false\"\r\n mode=\"default\"\r\n :min-date=\"currentFilter.calendarConfig?.minDate\"\r\n :max-date=\"currentFilter.calendarConfig?.maxDate\"\r\n :disabled-date=\"currentFilter.calendarConfig?.disabledDate\"\r\n :formatter=\"currentFilter.calendarConfig?.formatter\"\r\n :end-date-offset=\"currentFilter.calendarConfig?.endDateOffset || false\"\r\n @change=\"handleCalendarChange\"\r\n />\r\n </div>\r\n </template>\r\n\r\n <!-- 树形单选模式 -->\r\n <template v-else-if=\"currentFilter?.type === 'tree-single'\">\r\n <div class=\"rc-search-area__tree-container\">\r\n <div\r\n v-for=\"(group, groupIdx) in getTreeGroups(currentFilter)\"\r\n :key=\"groupIdx\"\r\n class=\"rc-search-area__tree-group\"\r\n >\r\n <div class=\"rc-search-area__tree-group-title\">\r\n {{ getOptionLabel(group, currentFilter || undefined) }}\r\n </div>\r\n <div class=\"rc-search-area__tree-group-options\">\r\n <div\r\n v-for=\"(option, optIdx) in getTreeGroupChildren(group, currentFilter)\"\r\n :key=\"optIdx\"\r\n class=\"rc-search-area__option\"\r\n :class=\"{ 'is-selected': isSelected(option) }\"\r\n @click=\"selectSingle(option)\"\r\n >\r\n <span class=\"rc-search-area__option-label\">{{ getOptionLabel(option, currentFilter || undefined) }}</span>\r\n <rc-icon v-if=\"isSelected(option)\" name=\"icon_check\" class=\"rc-search-area__option-check\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- 树形多选模式 -->\r\n <template v-else-if=\"currentFilter?.type === 'tree-multiple'\">\r\n <div class=\"rc-search-area__tree-container\">\r\n <div\r\n v-for=\"(group, groupIdx) in getTreeGroups(currentFilter)\"\r\n :key=\"groupIdx\"\r\n class=\"rc-search-area__tree-group\"\r\n >\r\n <div class=\"rc-search-area__tree-group-title\">\r\n {{ getOptionLabel(group, currentFilter || undefined) }}\r\n </div>\r\n <div class=\"rc-search-area__tree-group-options\">\r\n <div\r\n v-for=\"(option, optIdx) in getTreeGroupChildren(group, currentFilter)\"\r\n :key=\"optIdx\"\r\n class=\"rc-search-area__option\"\r\n :class=\"{ 'is-selected': isSelected(option) }\"\r\n @click=\"toggleOption(option)\"\r\n >\r\n <span class=\"rc-search-area__option-label\">{{ getOptionLabel(option, currentFilter || undefined) }}</span>\r\n <rc-icon v-if=\"isSelected(option)\" name=\"icon_check\" class=\"rc-search-area__option-check\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- 普通单选模式 -->\r\n <template v-else-if=\"currentFilter?.type === 'single'\">\r\n <div class=\"rc-search-area__options-grid\">\r\n <div\r\n v-for=\"(option, optIdx) in getDisplayOptions(currentFilter)\"\r\n :key=\"optIdx\"\r\n class=\"rc-search-area__option\"\r\n :class=\"{ 'is-selected': isSelected(option) }\"\r\n @click=\"selectSingle(option)\"\r\n >\r\n <span class=\"rc-search-area__option-label\">{{ getOptionLabel(option, currentFilter || undefined) }}</span>\r\n <rc-icon v-if=\"isSelected(option)\" name=\"icon_check\" class=\"rc-search-area__option-check\" />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- 普通多选模式 -->\r\n <template v-else>\r\n <div class=\"rc-search-area__options-grid\">\r\n <div\r\n v-for=\"(option, optIdx) in getDisplayOptions(currentFilter)\"\r\n :key=\"optIdx\"\r\n class=\"rc-search-area__option\"\r\n :class=\"{ 'is-selected': isSelected(option) }\"\r\n @click=\"toggleOption(option)\"\r\n >\r\n <span class=\"rc-search-area__option-label\">{{ getOptionLabel(option, currentFilter || undefined) }}</span>\r\n <rc-icon v-if=\"isSelected(option)\" name=\"icon_check\" class=\"rc-search-area__option-check\" />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- 无结果提示 -->\r\n <div v-if=\"currentFilter?.type !== 'input' && currentFilter?.type !== 'calendar' && !currentFilter?.slot && currentFilter?.options?.length === 0\" class=\"rc-search-area__empty\">\r\n <p>暂无选项</p>\r\n </div>\r\n </div>\r\n\r\n <div v-if=\"!props.autoConfirm && currentFilter?.type !== 'single' && currentFilter?.type !== 'tree-single'\" class=\"rc-search-area__panel-footer\">\r\n <rc-button \r\n block \r\n @click=\"resetCurrentFilter\"\r\n >\r\n 重置\r\n </rc-button>\r\n <rc-button \r\n type=\"primary\"\r\n block \r\n @click=\"confirmFilter\"\r\n >\r\n 确定{{ selectedCountText }}\r\n </rc-button>\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, ref, watch, nextTick, onUnmounted } from 'vue';\r\nimport RcIcon from '../icon';\r\nimport RcButton from '../button';\r\nimport RcCalendar from '../calendar';\r\n\r\ndefineOptions({ name: 'rc-search-area' });\r\n\r\nexport interface FilterOption {\r\n label: string;\r\n value: any;\r\n [key: string]: any;\r\n}\r\n\r\nexport interface FilterItem {\r\n /** 筛选项标签 */\r\n label: string;\r\n /** 筛选项唯一标识 */\r\n key: string;\r\n /** 筛选类型:single 单选,multiple 多选,tree-single 树形单选,tree-multiple 树形多选,input 输入框,calendar 日期选择器(默认 multiple) */\r\n type: 'single' | 'multiple' | 'tree-single' | 'tree-multiple' | 'input' | 'calendar';\r\n /** 选项列表 */\r\n options?: FilterOption[] | string[];\r\n /** 多选时的列数(默认 2) */\r\n column?: number;\r\n /** 格式化 value,默认返回原始数据。为 string 时,会作为 key 从原始数据中获取值,相当于 (d) => d[format]。为函数时,以函数返回结果作为 value */\r\n format?: ((data: FilterOption) => any) | string;\r\n /** 渲染选项内容。为 string 时,返回 d[string]。为 function 时,返回函数结果 */\r\n renderItem?: ((data: FilterOption) => any) | string;\r\n /** 选中后在结果中显示的内容,默认和 renderItem 相同 */\r\n renderResult?: ((data: FilterOption) => any) | string;\r\n /** 树形数据下,指定子数据的属性名,有值时可以展示树形结构 */\r\n childrenKey?: string;\r\n /** 输入框类型的占位符(仅 type='input' 时有效) */\r\n placeholder?: string;\r\n /** 是否使用插槽自定义渲染,为 true 时使用名为 key 的插槽 */\r\n slot?: boolean;\r\n /** 日期选择器相关配置(仅 type='calendar' 时有效) */\r\n calendarConfig?: {\r\n /** 是否支持区间选择:true/false 或数字(表示区间可选的最大天数) */\r\n range?: boolean | number;\r\n /** 最小可选日期,格式为 YYYY-MM-DD */\r\n minDate?: string;\r\n /** 最大可选日期,格式为 YYYY-MM-DD */\r\n maxDate?: string;\r\n /** 禁用日期函数 */\r\n disabledDate?: (date: Date) => boolean;\r\n /** 日期格式化函数 */\r\n formatter?: (day: any) => { text?: string; bottomInfo?: string };\r\n /** 区间模式下,结束日期是否自动加一天(选中日期为结束日期时,实际返回的结束日期会加一天) */\r\n endDateOffset?: boolean;\r\n };\r\n}\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 筛选项配置 */\r\n items: FilterItem[];\r\n /** 当前筛选值(支持 v-model) */\r\n modelValue?: Record<string, any>;\r\n /** 是否显示蒙层 */\r\n showMask?: boolean;\r\n /** 是否自动确认:为 true 时,每次修改立即触发 change 事件并关闭弹窗,不显示确定和重置按钮 */\r\n autoConfirm?: boolean;\r\n}>(), {\r\n items: () => [],\r\n modelValue: () => ({}),\r\n showMask: true,\r\n autoConfirm: false,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n /** v-model 更新事件 */\r\n (e: 'update:modelValue', values: Record<string, any>): void;\r\n /** 筛选条件变化时触发 */\r\n (e: 'change', values: Record<string, any>, item: FilterItem): void;\r\n}>();\r\n\r\n/** 当前打开的筛选项索引 */\r\nconst activeIndex = ref<number | null>(null);\r\n\r\n/** 面板和蒙层的 ref */\r\nconst panelRef = ref<HTMLElement | null>(null);\r\nconst maskRef = ref<HTMLElement | null>(null);\r\n\r\n/** 蒙层样式 - 从面板底部开始 */\r\nconst maskStyle = ref<{ top: string }>({ top: '0px' });\r\n\r\n/** 计算蒙层位置 */\r\nconst updateMaskPosition = async () => {\r\n if (activeIndex.value === null || !panelRef.value) {\r\n return;\r\n }\r\n await nextTick();\r\n const panelRect = panelRef.value.getBoundingClientRect();\r\n const panelTop = panelRect.top;\r\n maskStyle.value = { top: `${panelTop}px` };\r\n};\r\n\r\n/**\r\n * 处理点击外部区域关闭面板\r\n * @param event 鼠标事件\r\n */\r\nconst handleClickOutside = (event: MouseEvent) => {\r\n if (activeIndex.value === null || !panelRef.value) {\r\n return;\r\n }\r\n \r\n const target = event.target as HTMLElement;\r\n \r\n // 检查点击的目标是否在面板内部\r\n if (panelRef.value.contains(target)) {\r\n return;\r\n }\r\n \r\n // 检查是否点击的是筛选项按钮(避免点击按钮时关闭)\r\n const searchAreaEl = panelRef.value.closest('.rc-search-area');\r\n if (searchAreaEl) {\r\n const barEl = searchAreaEl.querySelector('.rc-search-area__bar');\r\n if (barEl && barEl.contains(target)) {\r\n // 点击的是筛选项按钮,不关闭面板(由按钮的点击事件处理)\r\n return;\r\n }\r\n }\r\n \r\n // 点击的是外部区域,关闭面板\r\n closeFilter();\r\n};\r\n\r\n/** 监听面板打开,更新蒙层位置和添加外部点击监听 */\r\nwatch(activeIndex, async (newVal) => {\r\n if (newVal !== null) {\r\n await nextTick();\r\n updateMaskPosition();\r\n // 监听窗口大小变化和滚动,更新蒙层位置\r\n window.addEventListener('resize', updateMaskPosition);\r\n window.addEventListener('scroll', updateMaskPosition, true);\r\n // 添加点击外部区域关闭面板的监听\r\n document.addEventListener('click', handleClickOutside, true);\r\n } else {\r\n window.removeEventListener('resize', updateMaskPosition);\r\n window.removeEventListener('scroll', updateMaskPosition, true);\r\n document.removeEventListener('click', handleClickOutside, true);\r\n }\r\n});\r\n\r\n/** 组件卸载时清理事件监听器 */\r\nonUnmounted(() => {\r\n window.removeEventListener('resize', updateMaskPosition);\r\n window.removeEventListener('scroll', updateMaskPosition, true);\r\n document.removeEventListener('click', handleClickOutside, true);\r\n});\r\n\r\n/** 每个筛选项的选中值(临时状态,用于模态窗内选择) */\r\nconst tempSelectedValues = ref<Record<string, any>>({});\r\n\r\n/** 输入框的临时值 */\r\nconst tempInputValue = ref<string>('');\r\n\r\n/** 日历的临时值 */\r\nconst tempCalendarValue = ref<string | [string, string] | null>(null);\r\n\r\n/** 插槽的临时值 */\r\nconst tempSlotValues = ref<Record<string, any>>({});\r\n\r\n/** 已确认的筛选值 */\r\nconst confirmedValues = ref<Record<string, any>>({ ...props.modelValue });\r\n\r\n/** 监听外部传入的 modelValue 变化 */\r\nwatch(() => props.modelValue, (newValue) => {\r\n confirmedValues.value = { ...(newValue || {}) };\r\n}, { deep: true, immediate: true });\r\n\r\n/** 当前打开的筛选项 */\r\nconst currentFilter = computed(() => {\r\n if (activeIndex.value === null) return null;\r\n return props.items[activeIndex.value];\r\n});\r\n\r\n/** 确定按钮文本 */\r\nconst selectedCountText = computed(() => {\r\n if (!currentFilter.value) return '';\r\n const count = getTempSelectedCount(currentFilter.value);\r\n return count > 0 ? `(${count}项)` : '';\r\n});\r\n\r\n/**\r\n * 获取筛选项的显示文本\r\n * @param item 筛选项配置\r\n * @returns 显示文本\r\n */\r\nconst getItemDisplayText = (item: FilterItem): string => {\r\n const value = confirmedValues.value[item.key];\r\n if (value === undefined || value === null || value === '') {\r\n return item.label;\r\n }\r\n \r\n if (item.slot) {\r\n // 插槽类型:显示标签,具体显示内容由插槽决定\r\n return item.label;\r\n } else if (item.type === 'input') {\r\n // 输入框类型\r\n if (value && String(value).trim()) {\r\n return `${item.label}: ${value}`;\r\n }\r\n } else if (item.type === 'calendar') {\r\n // 日历类型\r\n if (value) {\r\n if (Array.isArray(value) && value.length === 2) {\r\n return `${item.label}: ${value[0]} ~ ${value[1]}`;\r\n } else if (typeof value === 'string') {\r\n return `${item.label}: ${value}`;\r\n }\r\n }\r\n } else if (item.type === 'single' || item.type === 'tree-single') {\r\n // 单选类型\r\n const option = findOption(item, value);\r\n if (option) {\r\n return `${item.label}: ${getResultLabel(option, item)}`;\r\n }\r\n } else {\r\n // 多选类型(包括 tree-multiple)\r\n const values = Array.isArray(value) ? value : [value];\r\n if (values.length > 0) {\r\n const labels = values\r\n .map((val) => {\r\n const opt = findOption(item, val);\r\n return opt ? getResultLabel(opt, item) : null;\r\n })\r\n .filter((label) => label !== null);\r\n \r\n if (labels.length > 0) {\r\n return `${item.label}: ${labels.join('、')}`;\r\n }\r\n }\r\n }\r\n \r\n return item.label;\r\n};\r\n\r\n/**\r\n * 打开筛选模态窗\r\n * @param index 筛选项索引\r\n */\r\nconst openFilter = (index: number) => {\r\n const item = props.items[index];\r\n if (!item) return;\r\n \r\n // 如果点击的是当前已打开的筛选项,则收起\r\n if (activeIndex.value === index) {\r\n activeIndex.value = null;\r\n return;\r\n }\r\n \r\n // 初始化临时选中值\r\n const currentValue = confirmedValues.value[item.key];\r\n if (item.slot) {\r\n // 插槽类型:初始化插槽值(保持原始数据类型,不做转换)\r\n if (currentValue !== undefined && currentValue !== null) {\r\n if (Array.isArray(currentValue)) {\r\n // 数组类型:使用数组复制\r\n tempSlotValues.value[item.key] = [...currentValue];\r\n } else if (typeof currentValue === 'object') {\r\n // 对象类型:使用对象展开\r\n tempSlotValues.value[item.key] = { ...currentValue };\r\n } else {\r\n // 其他类型:直接赋值\r\n tempSlotValues.value[item.key] = currentValue;\r\n }\r\n } else {\r\n tempSlotValues.value[item.key] = undefined;\r\n }\r\n } else if (item.type === 'input') {\r\n // 输入框类型\r\n tempInputValue.value = currentValue !== undefined && currentValue !== null ? String(currentValue) : '';\r\n } else if (item.type === 'calendar') {\r\n // 日历类型\r\n tempCalendarValue.value = currentValue !== undefined && currentValue !== null ? currentValue : null;\r\n } else if (item.type === 'single' || item.type === 'tree-single') {\r\n // 单选类型\r\n tempSelectedValues.value[item.key] = currentValue !== undefined ? currentValue : null;\r\n } else {\r\n // 多选类型(包括 tree-multiple)\r\n tempSelectedValues.value[item.key] = currentValue !== undefined \r\n ? (Array.isArray(currentValue) ? [...currentValue] : [currentValue])\r\n : [];\r\n }\r\n \r\n activeIndex.value = index;\r\n};\r\n\r\n/** 关闭筛选模态窗 */\r\nconst closeFilter = () => {\r\n activeIndex.value = null;\r\n};\r\n\r\n/**\r\n * 获取选项的显示文本\r\n * @param option 选项数据\r\n * @param item 筛选项配置(可选)\r\n * @returns 显示文本\r\n */\r\nconst getOptionLabel = (option: FilterOption | string, item?: FilterItem): string => {\r\n if (!item) {\r\n if (typeof option === 'string') return option;\r\n return option.label || String(option.value);\r\n }\r\n\r\n const data: any = typeof option === 'string' ? option : option;\r\n \r\n // 使用 renderItem\r\n if (item.renderItem) {\r\n if (typeof item.renderItem === 'string') {\r\n // 字符串模式:从数据中获取属性\r\n if (typeof data === 'object' && data !== null) {\r\n return String(data[item.renderItem] ?? '');\r\n }\r\n return String(data);\r\n } else {\r\n // 函数模式\r\n const result = item.renderItem(data);\r\n return result !== undefined && result !== null ? String(result) : '';\r\n }\r\n }\r\n \r\n // 默认行为\r\n if (typeof option === 'string') return option;\r\n return option.label || String(option.value);\r\n};\r\n\r\n/**\r\n * 获取选项的值\r\n * @param option 选项数据\r\n * @param item 筛选项配置(可选)\r\n * @returns 选项的值\r\n */\r\nconst getOptionValue = (option: FilterOption | string, item?: FilterItem): any => {\r\n if (!item) {\r\n if (typeof option === 'string') return option;\r\n return option.value !== undefined ? option.value : option;\r\n }\r\n\r\n const data: any = typeof option === 'string' ? option : option;\r\n \r\n // 使用 format\r\n if (item.format) {\r\n if (typeof item.format === 'string') {\r\n // 字符串模式:从数据中获取属性\r\n if (typeof data === 'object' && data !== null) {\r\n return data[item.format];\r\n }\r\n return data;\r\n } else {\r\n // 函数模式\r\n return item.format(data);\r\n }\r\n }\r\n \r\n // 默认行为\r\n if (typeof option === 'string') return option;\r\n return option.value !== undefined ? option.value : option;\r\n};\r\n\r\n/**\r\n * 获取结果中显示的文本\r\n * @param option 选项数据\r\n * @param item 筛选项配置\r\n * @returns 结果文本\r\n */\r\nconst getResultLabel = (option: FilterOption | string, item: FilterItem): string => {\r\n const data: any = typeof option === 'string' ? option : option;\r\n \r\n // 使用 renderResult,如果没有则使用 renderItem\r\n const render = item.renderResult || item.renderItem;\r\n \r\n if (render) {\r\n if (typeof render === 'string') {\r\n // 字符串模式:从数据中获取属性\r\n if (typeof data === 'object' && data !== null) {\r\n return String(data[render] ?? '');\r\n }\r\n return String(data);\r\n } else {\r\n // 函数模式\r\n const result = render(data);\r\n return result !== undefined && result !== null ? String(result) : '';\r\n }\r\n }\r\n \r\n // 默认行为\r\n return getOptionLabel(option, item);\r\n};\r\n\r\n/**\r\n * 查找选项(支持树形结构)\r\n * @param item 筛选项配置\r\n * @param value 要查找的值\r\n * @param options 选项列表(可选,用于递归查找)\r\n * @returns 找到的选项或 null\r\n */\r\nconst findOption = (item: FilterItem, value: any, options?: FilterOption[] | string[]): FilterOption | string | null => {\r\n const opts = options || item.options;\r\n if (!opts) return null;\r\n const childrenKey = item.childrenKey || 'children';\r\n \r\n for (const opt of opts) {\r\n const optValue = getOptionValue(opt, item);\r\n if (optValue === value || String(optValue) === String(value)) {\r\n return opt;\r\n }\r\n \r\n // 如果是树形结构,递归查找子节点\r\n if (typeof opt === 'object' && opt !== null) {\r\n const children = (opt as any)[childrenKey];\r\n if (Array.isArray(children) && children.length > 0) {\r\n const found = findOption(item, value, children);\r\n if (found) return found;\r\n }\r\n }\r\n }\r\n \r\n return null;\r\n};\r\n\r\n/**\r\n * 扁平化选项列表(用于树形结构)\r\n * @param item 筛选项配置\r\n * @param options 选项列表(可选,用于递归)\r\n * @returns 扁平化后的选项列表\r\n */\r\nconst flattenOptions = (item: FilterItem, options?: FilterOption[] | string[]): (FilterOption | string)[] => {\r\n const opts = options || item.options;\r\n if (!opts) return [];\r\n const childrenKey = item.childrenKey || 'children';\r\n const result: (FilterOption | string)[] = [];\r\n \r\n for (const opt of opts) {\r\n result.push(opt);\r\n \r\n // 如果有子节点,递归添加\r\n if (typeof opt === 'object' && opt !== null) {\r\n const children = (opt as any)[childrenKey];\r\n if (Array.isArray(children) && children.length > 0) {\r\n result.push(...flattenOptions(item, children));\r\n }\r\n }\r\n }\r\n \r\n return result;\r\n};\r\n\r\n/**\r\n * 判断选项是否被选中(临时状态)\r\n * @param option 选项数据\r\n * @returns 是否选中\r\n */\r\nconst isSelected = (option: FilterOption | string): boolean => {\r\n if (!currentFilter.value) return false;\r\n const key = currentFilter.value.key;\r\n const tempValue = tempSelectedValues.value[key];\r\n const optValue = getOptionValue(option, currentFilter.value);\r\n \r\n if (currentFilter.value.type === 'single' || currentFilter.value.type === 'tree-single') {\r\n return tempValue !== null && tempValue !== undefined && tempValue === optValue;\r\n } else {\r\n const tempArray = Array.isArray(tempValue) ? tempValue : [];\r\n return tempArray.some((v) => v === optValue || String(v) === String(optValue));\r\n }\r\n};\r\n\r\n/**\r\n * 获取显示的选项列表(普通模式)\r\n * @param item 筛选项配置\r\n * @returns 选项列表\r\n */\r\nconst getDisplayOptions = (item: FilterItem | null): (FilterOption | string)[] => {\r\n if (!item) return [];\r\n // 如果有 childrenKey,扁平化选项;否则直接返回\r\n return item.childrenKey ? flattenOptions(item) : (item.options || []);\r\n};\r\n\r\n/**\r\n * 获取树形结构的一级分组(仅返回一级选项,作为分组标题)\r\n * @param item 筛选项配置\r\n * @returns 一级选项列表\r\n */\r\nconst getTreeGroups = (item: FilterItem | null): (FilterOption | string)[] => {\r\n if (!item) return [];\r\n const childrenKey = item.childrenKey || 'children';\r\n // 只返回一级选项(有子节点的选项)\r\n return (item.options || []).filter((opt) => {\r\n if (typeof opt === 'string') return false;\r\n const children = (opt as any)[childrenKey];\r\n return Array.isArray(children) && children.length > 0;\r\n });\r\n};\r\n\r\n/**\r\n * 获取树形结构分组下的子选项\r\n * @param group 分组选项\r\n * @param item 筛选项配置\r\n * @returns 子选项列表\r\n */\r\nconst getTreeGroupChildren = (group: FilterOption | string, item: FilterItem | null): (FilterOption | string)[] => {\r\n if (!item || typeof group === 'string') return [];\r\n const childrenKey = item.childrenKey || 'children';\r\n const children = (group as any)[childrenKey];\r\n return Array.isArray(children) ? children : [];\r\n};\r\n\r\n/**\r\n * 获取插槽的当前值\r\n * @param item 筛选项配置\r\n * @returns 插槽的当前值\r\n */\r\nconst getSlotValue = (item: FilterItem | null): any => {\r\n if (!item) return undefined;\r\n return tempSlotValues.value[item.key] !== undefined ? tempSlotValues.value[item.key] : confirmedValues.value[item.key];\r\n};\r\n\r\n/**\r\n * 更新插槽的值\r\n * @param item 筛选项配置\r\n * @param value 新值\r\n */\r\nconst updateSlotValue = (item: FilterItem | null, value: any) => {\r\n if (!item) return;\r\n tempSlotValues.value[item.key] = value;\r\n \r\n // 如果启用了自动确认,立即确认并关闭\r\n if (props.autoConfirm) {\r\n const key = item.key;\r\n confirmedValues.value[key] = value;\r\n emit('update:modelValue', { ...confirmedValues.value });\r\n emit('change', { ...confirmedValues.value }, item);\r\n closeFilter();\r\n }\r\n};\r\n\r\n/**\r\n * 判断选项是否有子节点\r\n * @param option 选项数据\r\n * @param item 筛选项配置\r\n * @returns 是否有子节点\r\n */\r\nconst hasChildren = (option: FilterOption | string, item: FilterItem | null): boolean => {\r\n if (!item || !item.childrenKey) return false;\r\n if (typeof option === 'string') return false;\r\n const children = (option as any)[item.childrenKey];\r\n return Array.isArray(children) && children.length > 0;\r\n};\r\n\r\n/**\r\n * 单选(支持树形结构)- 点击后直接确认并关闭\r\n * @param option 选项数据\r\n */\r\nconst selectSingle = (option: FilterOption | string) => {\r\n if (!currentFilter.value) return;\r\n const key = currentFilter.value.key;\r\n const optValue = getOptionValue(option, currentFilter.value);\r\n const oldValue = confirmedValues.value[key];\r\n \r\n // 如果已选中,则取消选中;否则选中\r\n let newValue: any;\r\n if (tempSelectedValues.value[key] === optValue) {\r\n newValue = undefined;\r\n } else {\r\n newValue = optValue;\r\n }\r\n \r\n // 直接更新已确认的值\r\n confirmedValues.value[key] = newValue;\r\n \r\n // 更新 v-model\r\n emit('update:modelValue', { ...confirmedValues.value });\r\n \r\n // 触发 change 事件\r\n emit('change', { ...confirmedValues.value }, currentFilter.value);\r\n \r\n // 直接关闭面板\r\n closeFilter();\r\n};\r\n\r\n/**\r\n * 多选切换\r\n * @param option 选项数据\r\n */\r\nconst toggleOption = (option: FilterOption | string) => {\r\n if (!currentFilter.value) return;\r\n const key = currentFilter.value.key;\r\n const optValue = getOptionValue(option, currentFilter.value);\r\n const tempArray = Array.isArray(tempSelectedValues.value[key]) \r\n ? [...tempSelectedValues.value[key]] \r\n : [];\r\n \r\n const existingIndex = tempArray.findIndex(\r\n (v) => v === optValue || String(v) === String(optValue)\r\n );\r\n \r\n if (existingIndex >= 0) {\r\n tempArray.splice(existingIndex, 1);\r\n } else {\r\n tempArray.push(optValue);\r\n }\r\n \r\n tempSelectedValues.value[key] = tempArray;\r\n \r\n // 如果启用了自动确认,立即确认并关闭\r\n if (props.autoConfirm) {\r\n const newValue = tempArray.length > 0 ? tempArray : undefined;\r\n confirmedValues.value[key] = newValue;\r\n emit('update:modelValue', { ...confirmedValues.value });\r\n emit('change', { ...confirmedValues.value }, currentFilter.value);\r\n closeFilter();\r\n }\r\n};\r\n\r\n/** 重置当前筛选项 */\r\nconst resetCurrentFilter = () => {\r\n if (!currentFilter.value) return;\r\n const key = currentFilter.value.key;\r\n if (currentFilter.value.slot) {\r\n tempSlotValues.value[key] = undefined;\r\n } else if (currentFilter.value.type === 'input') {\r\n tempInputValue.value = '';\r\n } else if (currentFilter.value.type === 'calendar') {\r\n tempCalendarValue.value = null;\r\n } else if (currentFilter.value.type === 'single' || currentFilter.value.type === 'tree-single') {\r\n tempSelectedValues.value[key] = null;\r\n } else {\r\n tempSelectedValues.value[key] = [];\r\n }\r\n};\r\n\r\n/** 处理输入框变化 */\r\nconst handleInputChange = () => {\r\n // 如果启用了自动确认,立即确认并关闭\r\n if (props.autoConfirm && currentFilter.value) {\r\n const key = currentFilter.value.key;\r\n const newValue = tempInputValue.value.trim() || undefined;\r\n confirmedValues.value[key] = newValue;\r\n emit('update:modelValue', { ...confirmedValues.value });\r\n emit('change', { ...confirmedValues.value }, currentFilter.value);\r\n closeFilter();\r\n }\r\n};\r\n\r\n/** 处理日历变化 */\r\nconst handleCalendarChange = (value: string | [string, string] | null) => {\r\n tempCalendarValue.value = value;\r\n \r\n // 如果启用了自动确认,立即确认并关闭\r\n if (props.autoConfirm && currentFilter.value) {\r\n const key = currentFilter.value.key;\r\n const newValue = value !== null && value !== undefined ? value : undefined;\r\n confirmedValues.value[key] = newValue;\r\n emit('update:modelValue', { ...confirmedValues.value });\r\n emit('change', { ...confirmedValues.value }, currentFilter.value);\r\n closeFilter();\r\n }\r\n};\r\n\r\n/** 确认筛选 */\r\nconst confirmFilter = () => {\r\n if (!currentFilter.value) return;\r\n const key = currentFilter.value.key;\r\n const oldValue = confirmedValues.value[key];\r\n \r\n // 更新已确认的值\r\n let newValue: any;\r\n if (currentFilter.value.slot) {\r\n // 插槽类型\r\n newValue = tempSlotValues.value[key];\r\n confirmedValues.value[key] = newValue;\r\n } else if (currentFilter.value.type === 'input') {\r\n // 输入框类型\r\n newValue = tempInputValue.value.trim() || undefined;\r\n confirmedValues.value[key] = newValue;\r\n } else if (currentFilter.value.type === 'calendar') {\r\n // 日历类型\r\n newValue = tempCalendarValue.value !== null && tempCalendarValue.value !== undefined ? tempCalendarValue.value : undefined;\r\n confirmedValues.value[key] = newValue;\r\n } else if (currentFilter.value.type === 'single' || currentFilter.value.type === 'tree-single') {\r\n // 单选类型\r\n const tempValue = tempSelectedValues.value[key];\r\n newValue = tempValue !== null && tempValue !== undefined ? tempValue : undefined;\r\n confirmedValues.value[key] = newValue;\r\n } else {\r\n // 多选类型(包括 tree-multiple)\r\n const tempValue = tempSelectedValues.value[key];\r\n newValue = Array.isArray(tempValue) && tempValue.length > 0 ? tempValue : undefined;\r\n confirmedValues.value[key] = newValue;\r\n }\r\n \r\n // 更新 v-model\r\n emit('update:modelValue', { ...confirmedValues.value });\r\n \r\n // 触发 change 事件\r\n emit('change', { ...confirmedValues.value }, currentFilter.value);\r\n \r\n closeFilter();\r\n};\r\n\r\n/**\r\n * 获取已选中的数量(已确认的)\r\n * @param item 筛选项配置\r\n * @returns 选中数量\r\n */\r\nconst getSelectedCount = (item: FilterItem): number => {\r\n const value = confirmedValues.value[item.key];\r\n if (value === undefined || value === null || value === '') return 0;\r\n \r\n if (item.slot) {\r\n // 插槽类型:有值就返回1\r\n return 1;\r\n } else if (item.type === 'input') {\r\n return String(value).trim() ? 1 : 0;\r\n } else if (item.type === 'single' || item.type === 'tree-single') {\r\n return 1;\r\n } else {\r\n return Array.isArray(value) ? value.length : (value ? 1 : 0);\r\n }\r\n};\r\n\r\n/**\r\n * 获取临时选中的数量\r\n * @param item 筛选项配置\r\n * @returns 临时选中数量\r\n */\r\nconst getTempSelectedCount = (item: FilterItem): number => {\r\n if (item.slot) {\r\n // 插槽类型:有值就返回1\r\n const slotValue = tempSlotValues.value[item.key];\r\n return slotValue !== undefined && slotValue !== null && slotValue !== '' ? 1 : 0;\r\n } else if (item.type === 'input') {\r\n return tempInputValue.value.trim() ? 1 : 0;\r\n } else if (item.type === 'calendar') {\r\n return tempCalendarValue.value !== null && tempCalendarValue.value !== undefined ? 1 : 0;\r\n }\r\n \r\n const tempValue = tempSelectedValues.value[item.key];\r\n if (tempValue === undefined || tempValue === null || tempValue === '') return 0;\r\n \r\n if (item.type === 'single' || item.type === 'tree-single') {\r\n return 1;\r\n } else {\r\n return Array.isArray(tempValue) ? tempValue.length : 0;\r\n }\r\n};\r\n\r\n// 暴露方法供外部调用\r\ndefineExpose({\r\n /** 获取当前筛选值 */\r\n getValues: () => ({ ...confirmedValues.value }),\r\n /** 重置所有筛选 */\r\n reset: () => {\r\n confirmedValues.value = {};\r\n tempSelectedValues.value = {};\r\n tempSlotValues.value = {};\r\n emit('update:modelValue', {});\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-search-area {\r\n position: relative;\r\n width: 100%;\r\n\r\n &__bar {\r\n display: flex;\r\n align-items: center;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n -webkit-overflow-scrolling: touch;\r\n scrollbar-width: none;\r\n -ms-overflow-style: none;\r\n touch-action: pan-x;\r\n padding: 4px 8px;\r\n box-sizing: border-box;\r\n\r\n &::-webkit-scrollbar {\r\n display: none;\r\n }\r\n }\r\n\r\n &__item {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 4px 6px;\r\n font-size: 14px;\r\n color: #323233;\r\n cursor: pointer;\r\n user-select: none;\r\n -webkit-user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n transition: all 0.2s;\r\n white-space: nowrap;\r\n flex-shrink: 0;\r\n flex-grow: 0;\r\n background: #F9F9F9;\r\n border: 1px solid transparent;\r\n border-radius: 4px;\r\n margin-right: 8px;\r\n max-width: calc(100% - 16px);\r\n min-width: 0;\r\n\r\n &:last-child {\r\n margin-right: 0;\r\n }\r\n\r\n &.has-value {\r\n border-color: #1677ff;\r\n color: #1677ff;\r\n background: #fff;\r\n }\r\n\r\n &.is-active {\r\n background: #F9F9F9;\r\n border-color: transparent;\r\n color: #323233;\r\n\r\n &::after {\r\n content: '';\r\n border: 1px solid #F9F9F9;\r\n position: absolute;\r\n bottom: -8px;\r\n width: 100%;\r\n height: 8px;\r\n background: #F9F9F9;\r\n }\r\n }\r\n\r\n &-label {\r\n margin-right: 4px;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n min-width: 0;\r\n flex: 1;\r\n max-width: 100%;\r\n }\r\n\r\n &-count {\r\n min-width: 16px;\r\n height: 16px;\r\n padding: 0 4px;\r\n margin-right: 4px;\r\n background: #1677ff;\r\n color: #fff;\r\n border-radius: 8px;\r\n font-size: 11px;\r\n line-height: 16px;\r\n text-align: center;\r\n }\r\n\r\n &-arrow {\r\n font-size: 10px;\r\n color: #969799;\r\n transition: transform 0.2s;\r\n transform: rotate(0deg);\r\n flex-shrink: 0;\r\n\r\n &.is-up {\r\n transform: rotate(180deg);\r\n }\r\n }\r\n }\r\n\r\n &__mask {\r\n position: fixed;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background: rgba(0, 0, 0, 0.5);\r\n z-index: 999;\r\n }\r\n\r\n &__panel {\r\n position: absolute;\r\n top: 100%;\r\n left: 0;\r\n right: 0;\r\n max-height: 70vh;\r\n background: #F9F9F9;\r\n z-index: 1000;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n border-bottom-right-radius: 8px;\r\n border-bottom-left-radius: 8px;\r\n }\r\n\r\n &__panel-content {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 8px;\r\n }\r\n\r\n &__options-grid {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 12px;\r\n }\r\n\r\n &__tree-container {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 16px;\r\n }\r\n\r\n &__tree-group {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n }\r\n\r\n &__tree-group-title {\r\n padding: 8px 12px;\r\n font-size: 14px;\r\n font-weight: 500;\r\n color: #323233;\r\n background: #f7f8fa;\r\n border-radius: 6px;\r\n user-select: none;\r\n cursor: default;\r\n }\r\n\r\n &__tree-group-options {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 12px;\r\n padding-left: 12px;\r\n }\r\n\r\n &__option {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 4px 6px;\r\n background: #f7f8fa;\r\n border: 1px solid #dcdee0;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n transition: all 0.2s;\r\n white-space: nowrap;\r\n flex-shrink: 0;\r\n\r\n &:hover {\r\n border-color: #1677ff;\r\n }\r\n\r\n &.is-selected {\r\n background: #e6f4ff;\r\n border-color: #1677ff;\r\n color: #1677ff;\r\n }\r\n\r\n &-label {\r\n font-size: 14px;\r\n }\r\n\r\n &-check {\r\n color: #1677ff;\r\n }\r\n }\r\n\r\n &__input-wrapper {\r\n padding: 8px;\r\n }\r\n\r\n &__calendar-wrapper {\r\n padding: 8px;\r\n }\r\n\r\n &__input {\r\n width: 100%;\r\n height: 40px;\r\n padding: 0 12px;\r\n font-size: 14px;\r\n color: #323233;\r\n background: #fff;\r\n border: 1px solid #dcdee0;\r\n border-radius: 8px;\r\n outline: none;\r\n box-sizing: border-box;\r\n transition: border-color 0.2s;\r\n\r\n &:focus {\r\n border-color: #1677ff;\r\n }\r\n\r\n &::placeholder {\r\n color: #969799;\r\n }\r\n }\r\n\r\n &__empty {\r\n padding: 40px 0;\r\n text-align: center;\r\n color: #969799;\r\n font-size: 14px;\r\n }\r\n\r\n &__panel-footer {\r\n display: flex;\r\n gap: 12px;\r\n padding: 8px;\r\n border-top: 1px solid #eee;\r\n flex-shrink: 0;\r\n }\r\n}\r\n\r\n// 过渡动画\r\n.rc-search-area-fade-enter-active,\r\n.rc-search-area-fade-leave-active {\r\n transition: opacity 0.3s ease-out;\r\n}\r\n\r\n.rc-search-area-fade-enter-from,\r\n.rc-search-area-fade-leave-to {\r\n opacity: 0;\r\n}\r\n\r\n.rc-search-area-fade-enter-to,\r\n.rc-search-area-fade-leave-from {\r\n opacity: 1;\r\n}\r\n\r\n.rc-search-area-slide-enter-active,\r\n.rc-search-area-slide-leave-active {\r\n transition: max-height 0.3s ease-out, opacity 0.3s ease-out;\r\n overflow: hidden;\r\n}\r\n\r\n.rc-search-area-slide-enter-from,\r\n.rc-search-area-slide-leave-to {\r\n max-height: 0;\r\n opacity: 0;\r\n}\r\n\r\n.rc-search-area-slide-enter-to,\r\n.rc-search-area-slide-leave-from {\r\n max-height: 70vh;\r\n opacity: 1;\r\n}\r\n</style>\r\n\r\n","/**\n * @description 基础用法\n */\nimport type { App } from 'vue';\nimport RcSearchArea from './index.vue';\n\nexport { RcSearchArea };\nexport type { FilterItem, FilterOption } from './index.vue';\n\nexport const install = (app: App) => {\n app.component('RcSearchArea', RcSearchArea);\n app.component('rc-search-area', RcSearchArea);\n};\n\nexport default RcSearchArea;\n\n","<template>\n <div class=\"rc-input\" :class=\"[\n `rc-input--${size}`,\n {\n 'is-disabled': disabled,\n 'is-focused': focused,\n 'is-readonly': readonly,\n 'rc-input--textarea': type === 'textarea',\n 'has-prepend': $slots.prepend || (isNumberMode && controls),\n 'has-append': $slots.append || (isNumberMode && controls),\n }\n ]\" @click=\"handleWrapperClick\">\n <!-- 数字输入模式:减少按钮(左侧) -->\n <button\n v-if=\"isNumberMode && controls\"\n type=\"button\"\n class=\"rc-input__number-btn rc-input__number-btn--decrease rc-input__number-btn--prepend\"\n :disabled=\"props.disabled || props.readonly || isMin\"\n @click.stop=\"handleStepDown\"\n >\n <span class=\"rc-input__number-text\">-</span>\n </button>\n\n <!-- 前置元素 -->\n <div v-if=\"$slots.prepend\" class=\"rc-input__prepend\">\n <slot name=\"prepend\" />\n </div>\n\n <div class=\"rc-input__wrapper\">\n <!-- 前缀图标或插槽 -->\n <div v-if=\"prefixIcon || $slots.prefix\" class=\"rc-input__prefix\">\n <slot name=\"prefix\">\n <rc-icon v-if=\"prefixIcon\" :name=\"prefixIcon\" class=\"rc-input__prefix-icon\" />\n </slot>\n </div>\n\n <!-- 输入框或文本域 -->\n <div v-if=\"type === 'textarea'\" class=\"rc-input__textarea-wrapper\">\n <component :is=\"'textarea'\" ref=\"inputRef\" :value=\"displayValue\"\n class=\"rc-input__field rc-input__field--textarea\"\n :placeholder=\"placeholder\" :disabled=\"disabled\" :readonly=\"readonly\" :maxlength=\"maxlength\"\n :minlength=\"minlength\" :rows=\"rows\" :autocomplete=\"autocomplete\" :name=\"name\" :autofocus=\"autofocus\"\n :form=\"form\" :tabindex=\"tabindex\" :style=\"textareaStyle\" @input=\"onInput\" @focus=\"onFocus\" @blur=\"onBlur\"\n @keydown=\"onKeydown\" @mouseenter=\"onMouseEnter\" @mouseleave=\"onMouseLeave\"\n @compositionstart=\"onCompositionStart\" @compositionupdate=\"onCompositionUpdate\"\n @compositionend=\"onCompositionEnd\" />\n <!-- 文本域清空按钮(在文本域内部) -->\n <button v-if=\"showClearButton && type === 'textarea'\" type=\"button\" class=\"rc-input__clear rc-input__clear--textarea\"\n :class=\"{ 'rc-input__clear--mobile': actualDeviceType === 'mobile' }\"\n @click.stop=\"onClear\">\n <rc-icon name=\"icon_close_circle\" class=\"rc-input__clear-icon\" />\n </button>\n </div>\n <component v-else :is=\"'input'\" ref=\"inputRef\" :value=\"displayValue\"\n :type=\"actualType\" class=\"rc-input__field\"\n :class=\"{ 'rc-input__field--number': isNumberMode }\"\n :placeholder=\"placeholder\" :disabled=\"disabled\" :readonly=\"readonly\" :maxlength=\"maxlength\"\n :minlength=\"minlength\" :autocomplete=\"autocomplete\" :name=\"name\" :autofocus=\"autofocus\"\n :form=\"form\" :tabindex=\"tabindex\" :min=\"isNumberMode ? min : undefined\" :max=\"isNumberMode ? max : undefined\"\n :step=\"isNumberMode ? step : undefined\" @input=\"onInput\" @focus=\"onFocus\" @blur=\"onBlur\"\n @keydown=\"onKeydown\" @mouseenter=\"onMouseEnter\" @mouseleave=\"onMouseLeave\"\n @compositionstart=\"onCompositionStart\" @compositionupdate=\"onCompositionUpdate\"\n @compositionend=\"onCompositionEnd\" />\n\n <!-- 后缀操作区 -->\n <div v-if=\"hasSuffix\" class=\"rc-input__suffix\">\n <div v-if=\"$slots.suffix\" class=\"rc-input__suffix-inner\">\n <slot name=\"suffix\" />\n </div>\n <!-- 密码显示/隐藏切换 -->\n <button v-if=\"showPassword && type === 'password' && hasValue\" type=\"button\" class=\"rc-input__password-toggle\"\n @click.stop=\"togglePassword\">\n <rc-icon :color=\"passwordVisible ? '#1677ff' : '#999'\"\n :name=\"passwordVisible ? 'icon_view' : 'icon_view-off'\" />\n </button>\n <!-- 清空按钮(普通输入框始终显示,数字模式下:mobile 设备始终显示,PC 设备仅在带控制按钮时显示) -->\n <button v-if=\"showClearButton && type !== 'textarea' && (!isNumberMode || (isNumberMode && (actualDeviceType === 'mobile' || controls)))\" type=\"button\" class=\"rc-input__clear\"\n :class=\"{ 'rc-input__clear--mobile': actualDeviceType === 'mobile' }\"\n @click.stop=\"onClear\">\n <rc-icon name=\"icon_close_circle\" class=\"rc-input__clear-icon\" />\n </button>\n <!-- 后缀图标 -->\n <rc-icon v-if=\"suffixIcon && !clearable && !showPassword && !isNumberMode\" :name=\"suffixIcon\" class=\"rc-input__suffix-icon\" />\n </div>\n\n <!-- 字符计数 -->\n <span v-if=\"showWordLimit && maxlength\" class=\"rc-input__count\">\n {{ wordCount }} / {{ maxlength }}\n </span>\n </div>\n\n <!-- 后置元素 -->\n <div v-if=\"$slots.append\" class=\"rc-input__append\">\n <slot name=\"append\" />\n </div>\n\n <!-- 数字输入模式:增加按钮(右侧) -->\n <button\n v-if=\"isNumberMode && controls\"\n type=\"button\"\n class=\"rc-input__number-btn rc-input__number-btn--increase rc-input__number-btn--append\"\n :disabled=\"props.disabled || props.readonly || isMax\"\n @click.stop=\"handleStepUp\"\n >\n <span class=\"rc-input__number-text\">+</span>\n </button>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, computed, nextTick, onMounted, useSlots, inject } from 'vue';\nimport RcIcon from '../icon';\nimport type { RecycleUIOptions } from '../../types';\nimport { RECYCLE_UI_SYMBOL, defaultRecycleUIConfig } from '../../index';\n\ntype InputValue = string | number | null | undefined;\ntype InputSize = 'large' | 'default' | 'small';\ntype InputType = 'text' | 'textarea' | 'password' | 'number';\ntype AutosizeConfig = boolean | { minRows?: number; maxRows?: number };\ntype DeviceType = 'pc' | 'mobile';\n\ninterface Props {\n /** 双向绑定值 */\n modelValue?: InputValue;\n /** 输入框类型:'text' 文本输入(默认)、'textarea' 文本域、'password' 密码输入、'number' 数字输入 */\n type?: InputType;\n /** 尺寸 */\n size?: InputSize;\n /** 占位符 */\n placeholder?: string;\n /** 是否禁用 */\n disabled?: boolean;\n /** 是否显示清空按钮 */\n clearable?: boolean;\n /** 是否显示密码切换按钮 */\n showPassword?: boolean;\n /** 是否只读 */\n readonly?: boolean;\n /** 最大输入长度 */\n maxlength?: number;\n /** 最小输入长度 */\n minlength?: number;\n /** 是否显示字数统计,只在 type 为 'text' 或 'textarea' 时生效 */\n showWordLimit?: boolean;\n /** 文本域行数 */\n rows?: number;\n /** 文本域自适应内容高度 */\n autosize?: AutosizeConfig;\n /** 文本域是否可以缩放 */\n resize?: 'none' | 'both' | 'horizontal' | 'vertical';\n /** 前缀图标 */\n prefixIcon?: string;\n /** 后缀图标 */\n suffixIcon?: string;\n /** 原生 autocomplete 属性 */\n autocomplete?: string;\n /** 原生 name 属性 */\n name?: string;\n /** 原生 autofocus 属性 */\n autofocus?: boolean;\n /** 原生 form 属性 */\n form?: string;\n /** tabindex */\n tabindex?: string | number;\n /** 格式化函数 */\n formatter?: (value: string) => string;\n /** 解析函数 */\n parser?: (value: string) => string;\n /** 设备类型,'pc' | 'mobile',默认从全局配置读取,全局配置默认为 'pc' */\n deviceType?: DeviceType;\n /** 数字输入模式:最小值 */\n min?: number;\n /** 数字输入模式:最大值 */\n max?: number;\n /** 数字输入模式:步进值 */\n step?: number;\n /** 数字输入模式:精度(小数位数) */\n precision?: number;\n /** 数字输入模式:是否显示控制按钮 */\n controls?: boolean;\n /** 数字输入模式:是否使用千分位分隔符 */\n useGrouping?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: '',\n type: 'text',\n size: 'default',\n placeholder: '请输入',\n disabled: false,\n clearable: true,\n showPassword: false,\n readonly: false,\n maxlength: undefined,\n minlength: undefined,\n showWordLimit: false,\n rows: 2,\n autosize: false,\n resize: undefined,\n prefixIcon: '',\n suffixIcon: '',\n autocomplete: 'off',\n name: undefined,\n autofocus: false,\n form: undefined,\n tabindex: undefined,\n formatter: undefined,\n parser: undefined,\n deviceType: undefined,\n min: undefined,\n max: undefined,\n step: 1,\n precision: undefined,\n controls: false,\n useGrouping: false,\n});\n\n// 获取全局配置\nconst cfg = inject<RecycleUIOptions>(RECYCLE_UI_SYMBOL, {} as RecycleUIOptions);\n\n// 注入 formItem 的验证方法\ninterface FormItemContext {\n onBlur?: () => void;\n onChange?: () => void;\n}\nconst formItemContext = inject<FormItemContext | undefined>('rcFormItem', undefined);\n\n// 计算实际设备类型:优先使用prop,其次使用全局配置,最后使用默认值\nconst actualDeviceType = computed<DeviceType>(() => {\n return props.deviceType || cfg?.inputDeviceType || defaultRecycleUIConfig.inputDeviceType || 'pc';\n});\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: InputValue): void;\n (e: 'input', value: InputValue): void;\n (e: 'change', value: InputValue): void;\n (e: 'focus', event: FocusEvent): void;\n (e: 'blur', event: FocusEvent): void;\n (e: 'clear'): void;\n (e: 'keydown', event: KeyboardEvent): void;\n (e: 'mouseenter', event: MouseEvent): void;\n (e: 'mouseleave', event: MouseEvent): void;\n (e: 'compositionstart', event: CompositionEvent): void;\n (e: 'compositionupdate', event: CompositionEvent): void;\n (e: 'compositionend', event: CompositionEvent): void;\n}>();\n\nconst inputRef = ref<HTMLInputElement | HTMLTextAreaElement>();\nconst innerValue = ref<InputValue>(props.modelValue ?? '');\nconst focused = ref(false);\nconst passwordVisible = ref(false);\nconst isComposing = ref(false);\n\nwatch(\n () => props.modelValue,\n (val) => {\n innerValue.value = val ?? '';\n }\n);\n\n// 是否为数字输入模式\nconst isNumberMode = computed(() => {\n return props.type === 'number';\n});\n\n// 实际输入类型(密码框切换时)\nconst actualType = computed(() => {\n if (props.type === 'password') {\n return passwordVisible.value ? 'text' : 'password';\n }\n if (isNumberMode.value) {\n return 'text'; // 使用 text 类型以便更好地控制输入\n }\n return props.type;\n});\n\n// 显示值(格式化后)\nconst displayValue = computed(() => {\n if (isNumberMode.value) {\n // 如果 innerValue 是字符串且以小数点结尾(如 \"12.\"),直接返回以支持部分输入\n if (typeof innerValue.value === 'string' && innerValue.value.endsWith('.') && !innerValue.value.includes('e') && !innerValue.value.includes('E')) {\n return innerValue.value;\n }\n \n const numValue = getNumberValue(innerValue.value);\n if (numValue === null || numValue === undefined) {\n // 如果 innerValue 是字符串(可能是部分输入如 \"-\"),返回字符串\n if (typeof innerValue.value === 'string' && (innerValue.value === '-' || innerValue.value === '')) {\n return innerValue.value;\n }\n return '';\n }\n let formatted = String(numValue);\n // 应用精度\n if (props.precision !== undefined) {\n formatted = numValue.toFixed(props.precision);\n }\n // 应用千分位分隔符\n if (props.useGrouping && !isComposing.value) {\n formatted = formatNumberWithGrouping(formatted);\n }\n return formatted;\n }\n const value = String(innerValue.value ?? '');\n if (props.formatter && !isComposing.value) {\n return props.formatter(value);\n }\n return value;\n});\n\n// 是否有值\nconst hasValue = computed(() => {\n const value = innerValue.value;\n return value !== '' && value !== null && value !== undefined;\n});\n\n// 字符计数\nconst wordCount = computed(() => {\n return String(innerValue.value ?? '').length;\n});\n\n// 是否显示清空按钮(根据设备类型)\nconst showClearButton = computed(() => {\n if (!props.clearable || !hasValue.value || props.disabled || props.readonly) {\n return false;\n }\n // mobile模式:有值就显示\n if (actualDeviceType.value === 'mobile') {\n return true;\n }\n // pc模式:悬浮时显示(通过CSS控制)\n return true;\n});\n\n// 是否有后缀内容(文本域的清空按钮不在suffix区域)\nconst slots = useSlots();\nconst hasSuffix = computed(() => {\n if (isNumberMode.value && props.controls) {\n // 数字模式下,控制按钮单独显示,不占用 suffix 区域\n // 但清空按钮仍然在 suffix 区域显示\n return !!(\n props.suffixIcon ||\n (showClearButton.value && (actualDeviceType.value === 'mobile' || props.controls)) ||\n slots.suffix\n );\n }\n return !!(\n props.suffixIcon ||\n (props.showPassword && props.type === 'password') ||\n (showClearButton.value && props.type !== 'textarea' && (!isNumberMode.value || (isNumberMode.value && (actualDeviceType.value === 'mobile' || props.controls)))) ||\n slots.suffix\n );\n});\n\n// 文本域样式(resize 应用到 textarea 元素)\nconst textareaStyle = computed(() => {\n if (props.type !== 'textarea') return {};\n const style: Record<string, string> = {};\n\n // 如果设置了 autosize,禁止 resize\n if (props.autosize) {\n style.resize = 'none';\n } else if (props.resize !== undefined) {\n // 如果明确设置了 resize,使用设置的值\n style.resize = props.resize;\n } else {\n // 默认允许垂直方向调整大小\n style.resize = 'vertical';\n }\n\n return style;\n});\n\n// 获取数字值\nfunction getNumberValue(value: InputValue): number | null {\n if (value === null || value === undefined || value === '') {\n return null;\n }\n if (typeof value === 'number') {\n return isNaN(value) ? null : value;\n }\n const num = Number(String(value).replace(/,/g, ''));\n return isNaN(num) ? null : num;\n}\n\n// 格式化数字(千分位分隔符)\nfunction formatNumberWithGrouping(value: string): string {\n const parts = value.split('.');\n parts[0] = parts[0].replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n return parts.join('.');\n}\n\n// 验证并限制数字值\nfunction validateNumber(value: number | null): number | null {\n if (value === null) return null;\n \n let num = value;\n \n // 应用最小值限制\n if (props.min !== undefined && num < props.min) {\n num = props.min;\n }\n \n // 应用最大值限制\n if (props.max !== undefined && num > props.max) {\n num = props.max;\n }\n \n // 应用精度(在限制之后应用,确保精度正确)\n if (props.precision !== undefined) {\n num = Number(num.toFixed(props.precision));\n }\n \n return num;\n}\n\n// 是否达到最大值\nconst isMax = computed(() => {\n if (!isNumberMode.value || props.max === undefined) return false;\n const numValue = getNumberValue(innerValue.value);\n return numValue !== null && numValue >= props.max;\n});\n\n// 是否达到最小值\nconst isMin = computed(() => {\n if (!isNumberMode.value || props.min === undefined) return false;\n const numValue = getNumberValue(innerValue.value);\n return numValue !== null && numValue <= props.min;\n});\n\n// 输入处理\nfunction onInput(event: Event) {\n const target = event.target as HTMLInputElement | HTMLTextAreaElement;\n let value = target.value;\n\n // 数字模式:移除千分位分隔符\n if (isNumberMode.value) {\n value = value.replace(/,/g, '');\n }\n\n // 解析函数\n if (props.parser && !isComposing.value) {\n value = props.parser(value);\n }\n\n // 数字模式:验证并转换\n if (isNumberMode.value) {\n // 允许空值、负号、小数点\n if (value === '' || value === '-' || value === '.') {\n innerValue.value = value === '' ? undefined : value;\n emit('update:modelValue', value === '' ? undefined : value);\n emit('input', value === '' ? undefined : value);\n formItemContext?.onChange?.();\n return;\n }\n \n // 检查是否为有效的数字输入(包括部分输入,如 \"12.\"、\"12-\"、\"12.3\" 等)\n // 允许:纯数字、负号开头、小数点、科学计数法(e/E)\n const isValidNumberInput = /^-?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/.test(value);\n \n if (isValidNumberInput) {\n // 尝试解析为数字\n const numValue = getNumberValue(value);\n if (numValue !== null) {\n // 如果输入值以小数点结尾(如 \"12.\"),保持原输入值以便用户继续输入小数部分\n // 否则,验证并更新为数字值\n if (value.endsWith('.') && !value.includes('e') && !value.includes('E')) {\n // 部分输入(如 \"12.\"),保持当前输入值\n innerValue.value = value;\n emit('update:modelValue', value);\n emit('input', value);\n } else {\n // 完整的数字输入,验证并更新\n const validated = validateNumber(numValue);\n innerValue.value = validated;\n emit('update:modelValue', validated);\n emit('input', validated);\n }\n } else {\n // 可能是部分输入(如 \"12.\"),保持当前输入值\n innerValue.value = value;\n emit('update:modelValue', value);\n emit('input', value);\n }\n } else {\n // 无效输入(包含非数字字符),保持原值不变\n // 不更新 innerValue,也不触发事件\n // 需要手动恢复输入框的值\n nextTick(() => {\n if (inputRef.value) {\n const currentValue = displayValue.value;\n inputRef.value.value = currentValue;\n }\n });\n return;\n }\n formItemContext?.onChange?.();\n return;\n }\n\n // 空字符串转换为undefined\n const normalizedValue = value === '' ? undefined : value;\n\n innerValue.value = normalizedValue;\n emit('update:modelValue', normalizedValue);\n emit('input', normalizedValue);\n // 触发 formItem 的 change 验证\n formItemContext?.onChange?.();\n\n // change 事件在失焦或回车时触发\n if (props.type === 'textarea' && props.autosize) {\n nextTick(() => {\n resizeTextarea();\n });\n }\n}\n\n// 聚焦\nfunction onFocus(event: FocusEvent) {\n focused.value = true;\n emit('focus', event);\n}\n\n// 失焦\nfunction onBlur(event: FocusEvent) {\n focused.value = false;\n \n // 数字模式:验证并规范化值\n if (isNumberMode.value) {\n const numValue = getNumberValue(innerValue.value);\n if (numValue !== null) {\n const validated = validateNumber(numValue);\n innerValue.value = validated;\n emit('update:modelValue', validated);\n emit('change', validated);\n } else {\n // 空值或无效值\n innerValue.value = undefined;\n emit('update:modelValue', undefined);\n emit('change', undefined);\n }\n } else {\n const value = innerValue.value;\n // 空字符串转换为undefined\n const normalizedValue = value === '' ? undefined : value;\n emit('change', normalizedValue);\n }\n \n emit('blur', event);\n // 触发 formItem 的 blur 验证\n formItemContext?.onBlur?.();\n}\n\n// 清空\nfunction onClear() {\n innerValue.value = undefined;\n emit('update:modelValue', undefined);\n emit('input', undefined);\n emit('change', undefined);\n emit('clear');\n nextTick(() => {\n inputRef.value?.focus();\n });\n}\n\n// 切换密码显示\nfunction togglePassword() {\n passwordVisible.value = !passwordVisible.value;\n}\n\n// 步进增加\nfunction handleStepUp() {\n if (props.disabled || props.readonly || isMax.value) return;\n const current = getNumberValue(innerValue.value);\n const step = props.step ?? 1;\n let newValue: number;\n if (current === null) {\n // 空值时,从最小值开始\n newValue = validateNumber(props.min ?? 0) ?? 0;\n } else {\n newValue = validateNumber(current + step) ?? current;\n }\n innerValue.value = newValue;\n emit('update:modelValue', newValue);\n emit('input', newValue);\n emit('change', newValue);\n formItemContext?.onChange?.();\n}\n\n// 步进减少\nfunction handleStepDown() {\n if (props.disabled || props.readonly || isMin.value) return;\n const current = getNumberValue(innerValue.value);\n const step = props.step ?? 1;\n let newValue: number;\n if (current === null) {\n // 空值时,从最大值开始\n newValue = validateNumber(props.max ?? 0) ?? 0;\n } else {\n newValue = validateNumber(current - step) ?? current;\n }\n innerValue.value = newValue;\n emit('update:modelValue', newValue);\n emit('input', newValue);\n emit('change', newValue);\n formItemContext?.onChange?.();\n}\n\n// 键盘按下\nfunction onKeydown(event: KeyboardEvent) {\n emit('keydown', event);\n \n // 数字模式:处理上下箭头和 PageUp/PageDown\n if (isNumberMode.value && !props.disabled && !props.readonly) {\n const step = props.step ?? 1;\n const current = getNumberValue(innerValue.value);\n \n if (event.key === 'ArrowUp') {\n event.preventDefault();\n handleStepUp();\n return;\n }\n \n if (event.key === 'ArrowDown') {\n event.preventDefault();\n handleStepDown();\n return;\n }\n \n if (event.key === 'PageUp') {\n event.preventDefault();\n if (current !== null) {\n const newValue = validateNumber(current + step * 10);\n innerValue.value = newValue;\n emit('update:modelValue', newValue);\n emit('input', newValue);\n emit('change', newValue);\n }\n return;\n }\n \n if (event.key === 'PageDown') {\n event.preventDefault();\n if (current !== null) {\n const newValue = validateNumber(current - step * 10);\n innerValue.value = newValue;\n emit('update:modelValue', newValue);\n emit('input', newValue);\n emit('change', newValue);\n }\n return;\n }\n }\n \n if (event.key === 'Enter' && props.type !== 'textarea') {\n const value = innerValue.value;\n // 空字符串转换为undefined\n const normalizedValue = value === '' ? undefined : value;\n emit('change', normalizedValue);\n }\n}\n\n// 鼠标进入\nfunction onMouseEnter(event: MouseEvent) {\n emit('mouseenter', event);\n}\n\n// 鼠标离开\nfunction onMouseLeave(event: MouseEvent) {\n emit('mouseleave', event);\n}\n\n// 输入法开始\nfunction onCompositionStart(event: CompositionEvent) {\n isComposing.value = true;\n emit('compositionstart', event);\n}\n\n// 输入法更新\nfunction onCompositionUpdate(event: CompositionEvent) {\n emit('compositionupdate', event);\n}\n\n// 输入法结束\nfunction onCompositionEnd(event: CompositionEvent) {\n isComposing.value = false;\n emit('compositionend', event);\n // 输入法结束后触发 input\n const target = event.target as HTMLInputElement | HTMLTextAreaElement;\n if (target) {\n onInput(event as any);\n }\n}\n\n// 包装器点击\nfunction handleWrapperClick() {\n if (props.disabled || props.readonly) return;\n inputRef.value?.focus();\n}\n\n// 调整文本域高度\nfunction resizeTextarea() {\n if (props.type !== 'textarea' || !inputRef.value) return;\n\n const textarea = inputRef.value as HTMLTextAreaElement;\n\n if (props.autosize) {\n textarea.style.height = 'auto';\n const scrollHeight = textarea.scrollHeight;\n\n if (typeof props.autosize === 'object') {\n const { minRows = 2, maxRows } = props.autosize;\n const lineHeight = parseInt(getComputedStyle(textarea).lineHeight) || 20;\n const minHeight = minRows * lineHeight;\n const maxHeight = maxRows ? maxRows * lineHeight : Infinity;\n\n textarea.style.height = `${Math.min(Math.max(scrollHeight, minHeight), maxHeight)}px`;\n } else {\n textarea.style.height = `${scrollHeight}px`;\n }\n }\n}\n\n// 暴露方法\nfunction focus() {\n inputRef.value?.focus();\n}\n\nfunction blur() {\n inputRef.value?.blur();\n}\n\nfunction select() {\n if (inputRef.value && 'select' in inputRef.value) {\n (inputRef.value as HTMLInputElement).select();\n }\n}\n\nfunction clear() {\n onClear();\n}\n\nonMounted(() => {\n if (props.type === 'textarea' && props.autosize) {\n resizeTextarea();\n }\n});\n\ndefineExpose({\n focus,\n blur,\n select,\n clear,\n resizeTextarea,\n inputRef,\n});\n</script>\n\n<style scoped lang=\"scss\">\n.rc-input {\n --rc-primary: #1677ff;\n --rc-text: #323233;\n --rc-border: #dcdee0;\n --rc-white: #ffffff;\n --rc-bg: #f7f8fa;\n --rc-disabled: #c8c9cc;\n\n position: relative;\n display: inline-flex;\n align-items: stretch;\n width: 100%;\n font-size: 14px;\n line-height: 1.5;\n\n &--small {\n font-size: 12px;\n }\n\n &--large {\n font-size: 16px;\n }\n\n &--textarea {\n display: flex;\n flex-direction: column;\n }\n\n &__prepend,\n &__append {\n display: flex;\n align-items: center;\n padding: 0 12px;\n background: var(--rc-bg);\n border: 1px solid var(--rc-border);\n white-space: nowrap;\n }\n\n &__prepend {\n border-right: none;\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n\n &__append {\n border-left: none;\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n\n &__wrapper {\n position: relative;\n display: inline-flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n padding: 8px 12px;\n border: 1px solid var(--rc-border);\n border-radius: 6px;\n background: var(--rc-white);\n transition: border-color 0.2s, box-shadow 0.2s;\n box-sizing: border-box;\n\n .rc-input--small & {\n padding: 4px 8px;\n }\n\n .rc-input--large & {\n padding: 12px 16px;\n }\n\n .rc-input--textarea & {\n padding: 0;\n align-items: stretch;\n }\n\n .rc-input.has-prepend & {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n\n .rc-input.has-append & {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n }\n\n &.is-focused &__wrapper {\n border-color: var(--rc-primary);\n box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.12);\n z-index: 1;\n }\n\n // 数字模式下,聚焦时整个组件(包括按钮)统一显示聚焦效果\n &.is-focused:has(.rc-input__number-btn) {\n // 移除 wrapper 的 box-shadow,改为在容器上统一显示\n .rc-input__wrapper {\n box-shadow: none;\n }\n // 在容器上显示统一的聚焦阴影\n box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.12);\n border-radius: 6px;\n }\n\n // 数字模式下,聚焦时按钮和输入框边框颜色统一\n &.is-focused:has(.rc-input__number-btn--prepend) .rc-input__number-btn--prepend:not(:disabled),\n &.is-focused:has(.rc-input__number-btn--append) .rc-input__number-btn--append:not(:disabled),\n &.is-focused:has(.rc-input__number-btn) .rc-input__wrapper {\n border-color: var(--rc-primary);\n }\n\n &.is-disabled &__wrapper {\n background: var(--rc-bg);\n cursor: not-allowed;\n border-color: var(--rc-border);\n }\n\n // 数字模式下,禁用时按钮和输入框样式完全统一\n &.is-disabled &__number-btn {\n background: var(--rc-bg) !important;\n border-color: var(--rc-border) !important;\n color: var(--rc-disabled) !important;\n opacity: 1;\n }\n\n // 数字模式下,禁用时输入框字段颜色统一\n &.is-disabled &__field--number {\n background: var(--rc-bg);\n color: var(--rc-disabled);\n }\n\n // 数字模式下,禁用时确保分割线消失\n &.is-disabled:has(.rc-input__number-btn--prepend) .rc-input__wrapper {\n border-left: none;\n }\n\n &.is-disabled:has(.rc-input__number-btn--append) .rc-input__wrapper {\n border-right: none;\n }\n\n // 数字模式下,聚焦时确保分割线消失\n &.is-focused:has(.rc-input__number-btn--prepend) .rc-input__wrapper {\n border-left: none;\n }\n\n &.is-focused:has(.rc-input__number-btn--append) .rc-input__wrapper {\n border-right: none;\n }\n\n &.is-readonly &__wrapper {\n background: var(--rc-bg);\n }\n\n &__prefix {\n display: flex;\n align-items: center;\n margin-right: 8px;\n color: var(--rc-text);\n }\n\n &__prefix-icon {\n font-size: 16px;\n }\n\n &__textarea-wrapper {\n position: relative;\n flex: 1;\n display: flex;\n align-items: stretch;\n overflow: hidden;\n }\n\n &__field {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n font-size: inherit;\n color: var(--rc-text);\n min-width: 0;\n padding: 0;\n\n &::placeholder {\n color: var(--rc-disabled);\n }\n\n &--textarea {\n min-height: 32px;\n line-height: 1.5;\n padding: 8px 30px 8px 12px;\n width: 100%;\n }\n }\n\n &--small &__field--textarea {\n padding: 4px 8px;\n }\n\n &--large &__field--textarea {\n padding: 12px 16px;\n }\n\n &__suffix {\n display: flex;\n align-items: center;\n margin-left: 8px;\n gap: 4px;\n\n &:empty {\n display: none;\n }\n }\n\n &__suffix-inner {\n display: flex;\n align-items: center;\n color: var(--rc-text);\n }\n\n &__suffix-icon {\n font-size: 16px;\n color: var(--rc-text);\n }\n\n &__clear {\n border: none;\n background: transparent;\n cursor: pointer;\n padding: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n transform: rotate(-90deg);\n transition: opacity 0.2s, transform 0.2s;\n color: var(--rc-disabled);\n font-size: 16px;\n\n &:hover {\n color: var(--rc-text);\n }\n\n // mobile模式:始终显示,无动画\n &--mobile {\n opacity: 1;\n transform: rotate(0deg);\n }\n\n // 文本域内的清空按钮\n &--textarea {\n position: absolute;\n top: 8px;\n right: 16px;\n z-index: 1;\n }\n }\n\n &__password-toggle {\n border: none;\n background: transparent;\n cursor: pointer;\n padding: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--rc-disabled);\n font-size: 16px;\n opacity: 1;\n\n &:hover {\n color: var(--rc-text);\n }\n }\n\n // 普通输入框悬浮时显示清空按钮(带动画)\n &:hover &__clear:not(:disabled):not(.rc-input__clear--textarea) {\n opacity: 1;\n transform: rotate(0deg);\n }\n\n // 文本域悬浮时显示清空按钮(带动画)\n &:hover &__clear--textarea:not(:disabled) {\n opacity: 1;\n transform: rotate(0deg);\n }\n\n &__count {\n position: absolute;\n right: 8px;\n bottom: 4px;\n font-size: 12px;\n color: var(--rc-disabled);\n line-height: 1;\n }\n\n &--textarea &__count {\n bottom: 8px;\n right: 12px;\n }\n\n &.is-disabled {\n .rc-input__field {\n color: var(--rc-disabled);\n cursor: not-allowed;\n }\n }\n\n // 数字输入模式\n &__field--number {\n text-align: left;\n }\n\n &__number-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n align-self: stretch;\n border: 1px solid var(--rc-border);\n background: var(--rc-white);\n cursor: pointer;\n padding: 0;\n color: var(--rc-text);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n flex-shrink: 0;\n position: relative;\n outline: none;\n box-sizing: border-box;\n\n &:hover:not(:disabled) {\n background: var(--rc-bg);\n color: var(--rc-primary);\n border-color: var(--rc-primary);\n z-index: 1;\n }\n\n &:active:not(:disabled) {\n background: var(--rc-border);\n transform: scale(0.98);\n }\n\n &:focus:not(:disabled) {\n outline: none;\n }\n\n &:disabled {\n cursor: not-allowed;\n color: var(--rc-disabled) !important;\n background: var(--rc-bg) !important;\n border-color: var(--rc-border) !important;\n opacity: 1;\n }\n\n &--prepend {\n border-right: none;\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n margin-right: -1px;\n z-index: 1;\n }\n\n &--append {\n border-left: none;\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n margin-left: -1px;\n z-index: 1;\n }\n }\n\n &__number-text {\n font-size: 16px;\n font-weight: 600;\n line-height: 1;\n user-select: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n\n // 数字模式下,当有控制按钮时,调整 wrapper 的边框\n &:has(.rc-input__number-btn--prepend) .rc-input__wrapper {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n border-left: none;\n }\n\n &:has(.rc-input__number-btn--append) .rc-input__wrapper {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n border-right: none;\n }\n\n // 数字模式下,确保按钮与输入框在同一层级\n &__number-btn--prepend,\n &__number-btn--append {\n z-index: 0;\n }\n\n // 数字模式下,聚焦时按钮和输入框边框颜色统一,并提升层级\n &.is-focused &__number-btn--prepend:not(:disabled),\n &.is-focused &__number-btn--append:not(:disabled) {\n z-index: 2;\n border-color: var(--rc-primary);\n }\n}\n</style>\n","import type { App } from 'vue';\r\nimport Input from './index.vue';\r\n\r\nif (Input) {\r\n (Input as any).name = 'rc-input';\r\n}\r\n\r\nexport function install(app: App) {\r\n if (Input) {\r\n app.component((Input as any).name || 'rc-input', Input);\r\n }\r\n return app;\r\n}\r\n\r\nexport default Input;\r\n\r\n","<template>\r\n <teleport v-if=\"hasTeleport\" to=\"body\">\r\n <transition name=\"rc-dropdown-fade\">\r\n <ul\r\n v-if=\"shouldShow\"\r\n ref=\"menuRef\"\r\n class=\"rc-dropdown-menu\"\r\n :class=\"[`rc-dropdown-menu--${effect}`]\"\r\n :style=\"menuStyle\"\r\n @click.stop\r\n @mouseenter=\"$emit('mouseenter', $event)\"\r\n @mouseleave=\"$emit('mouseleave', $event)\"\r\n >\r\n <slot />\r\n </ul>\r\n </transition>\r\n </teleport>\r\n <ul\r\n v-else\r\n ref=\"menuRef\"\r\n class=\"rc-dropdown-menu rc-dropdown-menu--nested\"\r\n :class=\"[`rc-dropdown-menu--${effect}`]\"\r\n :style=\"menuStyle\"\r\n @click.stop\r\n @mouseenter=\"$emit('mouseenter', $event)\"\r\n @mouseleave=\"$emit('mouseleave', $event)\"\r\n >\r\n <slot />\r\n </ul>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed } from 'vue';\r\n\r\ndefineOptions({ name: 'rc-dropdown-menu' });\r\n\r\ninterface Props {\r\n visible?: boolean;\r\n effect?: 'dark' | 'light';\r\n maxHeight?: string | number;\r\n}\r\n\r\nconst emit = defineEmits<{\r\n (e: 'mouseenter', event: MouseEvent): void;\r\n (e: 'mouseleave', event: MouseEvent): void;\r\n}>();\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n visible: undefined,\r\n effect: 'light',\r\n maxHeight: '',\r\n});\r\n\r\nconst menuRef = ref<HTMLElement>();\r\n\r\n// 如果 visible 未定义,说明是嵌套使用的内层菜单,应该始终显示\r\n// 如果 visible 已定义,则根据其值决定是否显示\r\nconst shouldShow = computed(() => {\r\n return props.visible === undefined ? true : props.visible;\r\n});\r\n\r\n// 只有外层菜单(有 visible prop)才使用 teleport\r\nconst hasTeleport = computed(() => {\r\n return props.visible !== undefined;\r\n});\r\n\r\nconst menuStyle = computed(() => {\r\n const style: Record<string, string> = {};\r\n if (props.maxHeight) {\r\n style.maxHeight = typeof props.maxHeight === 'number' ? `${props.maxHeight}px` : props.maxHeight;\r\n style.overflowY = 'auto';\r\n }\r\n return style;\r\n});\r\n\r\ndefineExpose({\r\n menuRef,\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-dropdown-menu {\r\n --rc-primary: #1677ff;\r\n --rc-text: #323233;\r\n --rc-border: #dcdee0;\r\n --rc-white: #ffffff;\r\n --rc-bg: #f7f8fa;\r\n\r\n position: fixed;\r\n z-index: 2000;\r\n min-width: 120px;\r\n padding: 4px 0;\r\n margin: 0;\r\n background: var(--rc-white);\r\n border: 1px solid var(--rc-border);\r\n border-radius: 6px;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n list-style: none;\r\n\r\n &--dark {\r\n background: #1d1e1f;\r\n border-color: #1d1e1f;\r\n color: var(--rc-white);\r\n }\r\n\r\n &--light {\r\n background: var(--rc-white);\r\n border-color: var(--rc-border);\r\n color: var(--rc-text);\r\n }\r\n\r\n &--nested {\r\n position: static;\r\n top: auto;\r\n left: auto;\r\n box-shadow: none;\r\n border: none;\r\n padding: 0;\r\n }\r\n}\r\n\r\n.rc-dropdown-fade-enter-active,\r\n.rc-dropdown-fade-leave-active {\r\n transition: opacity 0.15s, transform 0.15s;\r\n}\r\n\r\n.rc-dropdown-fade-enter-from,\r\n.rc-dropdown-fade-leave-to {\r\n opacity: 0;\r\n transform: scale(0.95);\r\n}\r\n</style>\r\n\r\n\r\n\r\n","<template>\r\n <div\r\n ref=\"dropdownRef\"\r\n class=\"rc-dropdown\"\r\n :class=\"{ 'is-disabled': disabled }\"\r\n @mouseenter=\"handleMouseEnter\"\r\n @mouseleave=\"handleMouseLeave\"\r\n @click=\"handleClick\"\r\n >\r\n <slot />\r\n\r\n <rc-dropdown-menu\r\n ref=\"menuRef\"\r\n :visible=\"visible\"\r\n :effect=\"effect\"\r\n :max-height=\"maxHeight\"\r\n @mouseenter=\"handleMenuMouseEnter\"\r\n @mouseleave=\"handleMenuMouseLeave\"\r\n >\r\n <slot name=\"dropdown\" />\r\n </rc-dropdown-menu>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, provide, watch, computed, onMounted, onUnmounted, nextTick } from 'vue';\r\nimport RcDropdownMenu from './menu.vue';\r\nimport type { DropdownPlacement } from './types';\r\n\r\ndefineOptions({ name: 'rc-dropdown' });\r\n\r\ninterface Props {\r\n placement?: DropdownPlacement;\r\n trigger?: 'hover' | 'click';\r\n disabled?: boolean;\r\n effect?: 'dark' | 'light';\r\n maxHeight?: string | number;\r\n hideOnClick?: boolean;\r\n showTimeout?: number;\r\n hideTimeout?: number;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n placement: 'bottom',\r\n trigger: 'hover',\r\n disabled: false,\r\n effect: 'light',\r\n maxHeight: '',\r\n hideOnClick: true,\r\n showTimeout: 150,\r\n hideTimeout: 150,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n (e: 'command', command: string | number | object): void;\r\n (e: 'visible-change', visible: boolean): void;\r\n}>();\r\n\r\nconst dropdownRef = ref<HTMLElement>();\r\nconst menuRef = ref<InstanceType<typeof RcDropdownMenu>>();\r\nconst visible = ref(false);\r\nlet showTimer: ReturnType<typeof setTimeout> | null = null;\r\nlet hideTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n// 处理菜单项点击\r\nfunction handleItemClick(command?: string | number | object) {\r\n if (props.hideOnClick) {\r\n visible.value = false;\r\n }\r\n if (command !== undefined) {\r\n emit('command', command);\r\n }\r\n}\r\n\r\nprovide('handleItemClick', handleItemClick);\r\n\r\n// 显示菜单\r\nfunction show() {\r\n if (props.disabled) return;\r\n if (showTimer) {\r\n clearTimeout(showTimer);\r\n showTimer = null;\r\n }\r\n if (hideTimer) {\r\n clearTimeout(hideTimer);\r\n hideTimer = null;\r\n }\r\n showTimer = setTimeout(() => {\r\n visible.value = true;\r\n // 使用 requestAnimationFrame 确保 DOM 已更新\r\n requestAnimationFrame(() => {\r\n nextTick(() => {\r\n updatePosition();\r\n });\r\n });\r\n }, props.showTimeout);\r\n}\r\n\r\n// 隐藏菜单\r\nfunction hide() {\r\n if (props.trigger === 'hover' && isMenuHovered.value) {\r\n return;\r\n }\r\n if (hideTimer) {\r\n clearTimeout(hideTimer);\r\n hideTimer = null;\r\n }\r\n if (showTimer) {\r\n clearTimeout(showTimer);\r\n showTimer = null;\r\n }\r\n hideTimer = setTimeout(() => {\r\n visible.value = false;\r\n isMenuHovered.value = false;\r\n }, props.hideTimeout);\r\n}\r\n\r\n// 切换菜单显示状态\r\nfunction toggle() {\r\n if (props.disabled) return;\r\n if (visible.value) {\r\n hide();\r\n } else {\r\n show();\r\n }\r\n}\r\n\r\n// 鼠标进入\r\nfunction handleMouseEnter() {\r\n if (props.trigger === 'hover' && !props.disabled) {\r\n show();\r\n }\r\n}\r\n\r\n// 鼠标离开\r\nfunction handleMouseLeave() {\r\n if (props.trigger === 'hover') {\r\n // 延迟隐藏,给菜单鼠标进入的时间\r\n setTimeout(() => {\r\n if (!isMenuHovered.value) {\r\n hide();\r\n }\r\n }, 50);\r\n }\r\n}\r\n\r\nconst isMenuHovered = ref(false);\r\n\r\n// 菜单鼠标进入\r\nfunction handleMenuMouseEnter() {\r\n if (props.trigger === 'hover') {\r\n isMenuHovered.value = true;\r\n if (showTimer) {\r\n clearTimeout(showTimer);\r\n showTimer = null;\r\n }\r\n if (hideTimer) {\r\n clearTimeout(hideTimer);\r\n hideTimer = null;\r\n }\r\n }\r\n}\r\n\r\n// 菜单鼠标离开\r\nfunction handleMenuMouseLeave() {\r\n if (props.trigger === 'hover') {\r\n isMenuHovered.value = false;\r\n hide();\r\n }\r\n}\r\n\r\n// 点击\r\nfunction handleClick(event: MouseEvent) {\r\n if (props.trigger === 'click' && !props.disabled) {\r\n event.stopPropagation();\r\n toggle();\r\n }\r\n}\r\n\r\n// 更新菜单位置\r\nfunction updatePosition() {\r\n if (!dropdownRef.value || !menuRef.value?.menuRef) return;\r\n \r\n const triggerEl = dropdownRef.value;\r\n const menuEl = menuRef.value.menuRef as HTMLElement;\r\n \r\n if (!triggerEl || !menuEl) return;\r\n\r\n const triggerRect = triggerEl.getBoundingClientRect();\r\n \r\n // 确保菜单已经渲染完成,如果尺寸为0则等待\r\n const menuRect = menuEl.getBoundingClientRect();\r\n if (menuRect.width === 0 || menuRect.height === 0) {\r\n // 如果菜单还没有尺寸,延迟重试\r\n setTimeout(() => {\r\n if (visible.value) {\r\n updatePosition();\r\n }\r\n }, 10);\r\n return;\r\n }\r\n \r\n // 使用 fixed 定位,直接使用 getBoundingClientRect 的坐标(相对于视口)\r\n let top = 0;\r\n let left = 0;\r\n\r\n switch (props.placement) {\r\n case 'top':\r\n top = triggerRect.top - menuRect.height;\r\n left = triggerRect.left;\r\n break;\r\n case 'top-start':\r\n top = triggerRect.top - menuRect.height;\r\n left = triggerRect.left;\r\n break;\r\n case 'top-end':\r\n top = triggerRect.top - menuRect.height;\r\n left = triggerRect.left + triggerRect.width - menuRect.width;\r\n break;\r\n case 'bottom':\r\n top = triggerRect.bottom;\r\n left = triggerRect.left + (triggerRect.width - menuRect.width) / 2;\r\n break;\r\n case 'bottom-start':\r\n top = triggerRect.bottom;\r\n left = triggerRect.left;\r\n break;\r\n case 'bottom-end':\r\n top = triggerRect.bottom;\r\n left = triggerRect.left + triggerRect.width - menuRect.width;\r\n break;\r\n case 'left':\r\n top = triggerRect.top + (triggerRect.height - menuRect.height) / 2;\r\n left = triggerRect.left - menuRect.width;\r\n break;\r\n case 'left-start':\r\n top = triggerRect.top;\r\n left = triggerRect.left - menuRect.width;\r\n break;\r\n case 'left-end':\r\n top = triggerRect.top + triggerRect.height - menuRect.height;\r\n left = triggerRect.left - menuRect.width;\r\n break;\r\n case 'right':\r\n top = triggerRect.top + (triggerRect.height - menuRect.height) / 2;\r\n left = triggerRect.right;\r\n break;\r\n case 'right-start':\r\n top = triggerRect.top;\r\n left = triggerRect.right;\r\n break;\r\n case 'right-end':\r\n top = triggerRect.top + triggerRect.height - menuRect.height;\r\n left = triggerRect.right;\r\n break;\r\n }\r\n\r\n // 边界检测和调整(fixed 定位相对于视口)\r\n const viewportWidth = window.innerWidth;\r\n const viewportHeight = window.innerHeight;\r\n\r\n if (left < 0) left = 8;\r\n if (left + menuRect.width > viewportWidth) {\r\n left = viewportWidth - menuRect.width - 8;\r\n }\r\n if (top < 0) top = 8;\r\n if (top + menuRect.height > viewportHeight) {\r\n top = viewportHeight - menuRect.height - 8;\r\n }\r\n\r\n menuEl.style.top = `${top}px`;\r\n menuEl.style.left = `${left}px`;\r\n menuEl.style.position = 'fixed';\r\n menuEl.style.visibility = 'visible';\r\n menuEl.style.display = 'block';\r\n}\r\n\r\n// 监听 visible 变化\r\nwatch(visible, (val) => {\r\n emit('visible-change', val);\r\n if (val) {\r\n // 使用 requestAnimationFrame 确保 DOM 已更新\r\n requestAnimationFrame(() => {\r\n nextTick(() => {\r\n updatePosition();\r\n });\r\n });\r\n document.addEventListener('click', handleDocumentClick);\r\n } else {\r\n document.removeEventListener('click', handleDocumentClick);\r\n }\r\n});\r\n\r\n// 处理文档点击\r\nfunction handleDocumentClick(event: MouseEvent) {\r\n if (props.trigger === 'click' && !props.disabled) {\r\n const target = event.target as HTMLElement;\r\n if (dropdownRef.value && !dropdownRef.value.contains(target)) {\r\n hide();\r\n }\r\n }\r\n}\r\n\r\n// 监听窗口大小变化\r\nfunction handleResize() {\r\n if (visible.value) {\r\n updatePosition();\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n window.addEventListener('resize', handleResize);\r\n window.addEventListener('scroll', handleResize, true);\r\n});\r\n\r\nonUnmounted(() => {\r\n if (showTimer) clearTimeout(showTimer);\r\n if (hideTimer) clearTimeout(hideTimer);\r\n document.removeEventListener('click', handleDocumentClick);\r\n window.removeEventListener('resize', handleResize);\r\n window.removeEventListener('scroll', handleResize, true);\r\n});\r\n\r\n// 暴露方法\r\ndefineExpose({\r\n show,\r\n hide,\r\n toggle,\r\n visible,\r\n});\r\n</script>\r\n\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-dropdown {\r\n position: relative;\r\n display: inline-block;\r\n\r\n &.is-disabled {\r\n cursor: not-allowed;\r\n opacity: 0.6;\r\n }\r\n}\r\n</style>\r\n","<template>\r\n <li\r\n class=\"rc-dropdown-item\"\r\n :class=\"{\r\n 'is-disabled': disabled,\r\n 'is-divided': divided,\r\n }\"\r\n @click=\"handleClick\"\r\n >\r\n <rc-icon v-if=\"icon\" :name=\"icon\" class=\"rc-dropdown-item__icon\" />\r\n <span class=\"rc-dropdown-item__text\">\r\n <slot />\r\n </span>\r\n </li>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject } from 'vue';\r\nimport RcIcon from '../icon/index.vue';\r\n\r\ndefineOptions({ name: 'rc-dropdown-item' });\r\n\r\ninterface Props {\r\n command?: string | number | object;\r\n disabled?: boolean;\r\n divided?: boolean;\r\n icon?: string;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n command: undefined,\r\n disabled: false,\r\n divided: false,\r\n icon: '',\r\n});\r\n\r\nconst handleItemClick = inject<(command?: string | number | object) => void>('handleItemClick', () => {});\r\n\r\nfunction handleClick(event: MouseEvent) {\r\n if (props.disabled) {\r\n event.stopPropagation();\r\n return;\r\n }\r\n handleItemClick(props.command);\r\n}\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-dropdown-item {\r\n --rc-primary: #1677ff;\r\n --rc-text: #323233;\r\n --rc-disabled: #c8c9cc;\r\n --rc-hover: #f5f5f5;\r\n --rc-border: #dcdee0;\r\n\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n padding: 8px 16px;\r\n margin: 0;\r\n font-size: 14px;\r\n line-height: 22px;\r\n color: var(--rc-text);\r\n cursor: pointer;\r\n transition: background-color 0.2s;\r\n list-style: none;\r\n\r\n &:hover:not(.is-disabled) {\r\n background-color: var(--rc-hover);\r\n }\r\n\r\n &.is-disabled {\r\n color: var(--rc-disabled);\r\n cursor: not-allowed;\r\n }\r\n\r\n &.is-divided {\r\n border-top: 1px solid #dcdee0;\r\n margin-top: 4px;\r\n padding-top: 8px;\r\n }\r\n\r\n &__icon {\r\n margin-right: 8px;\r\n font-size: 14px;\r\n }\r\n\r\n &__text {\r\n flex: 1;\r\n }\r\n}\r\n\r\n:deep(.rc-dropdown-menu--dark) .rc-dropdown-item {\r\n color: rgba(255, 255, 255, 0.9);\r\n\r\n &:hover:not(.is-disabled) {\r\n background-color: rgba(255, 255, 255, 0.1);\r\n }\r\n\r\n &.is-disabled {\r\n color: rgba(255, 255, 255, 0.4);\r\n }\r\n\r\n &.is-divided {\r\n border-top-color: rgba(255, 255, 255, 0.1);\r\n }\r\n}\r\n</style>\r\n\r\n\r\n\r\n","import type { App } from 'vue';\nimport Dropdown from './index.vue';\nimport DropdownMenu from './menu.vue';\nimport DropdownItem from './item.vue';\n\nif (Dropdown) {\n (Dropdown as any).name = 'rc-dropdown';\n}\nif (DropdownMenu) {\n (DropdownMenu as any).name = 'rc-dropdown-menu';\n}\nif (DropdownItem) {\n (DropdownItem as any).name = 'rc-dropdown-item';\n}\n\nexport function install(app: App) {\n if (Dropdown) {\n app.component((Dropdown as any).name || 'rc-dropdown', Dropdown);\n app.component('RcDropdown', Dropdown);\n }\n if (DropdownMenu) {\n app.component((DropdownMenu as any).name || 'rc-dropdown-menu', DropdownMenu);\n app.component('RcDropdownMenu', DropdownMenu);\n }\n if (DropdownItem) {\n app.component((DropdownItem as any).name || 'rc-dropdown-item', DropdownItem);\n app.component('RcDropdownItem', DropdownItem);\n }\n return app;\n}\n\nexport { DropdownMenu, DropdownItem };\nexport default Dropdown;\n\n","<template>\r\n <form\r\n ref=\"formRef\"\r\n class=\"rc-form\"\r\n :class=\"[\r\n `rc-form--${labelPosition}`,\r\n {\r\n 'rc-form--inline': inline,\r\n }\r\n ]\"\r\n @submit.prevent=\"onSubmit\"\r\n >\r\n <slot />\r\n </form>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, provide, reactive, watch, nextTick, onMounted } from 'vue';\r\n\r\nexport interface FormRules {\r\n [key: string]: FormRule | FormRule[];\r\n}\r\n\r\nexport interface FormRule {\r\n required?: boolean;\r\n message?: string;\r\n trigger?: 'blur' | 'change' | 'submit';\r\n min?: number;\r\n max?: number;\r\n type?: 'string' | 'number' | 'boolean' | 'method' | 'regexp' | 'integer' | 'float' | 'array' | 'object' | 'enum' | 'date' | 'url' | 'hex' | 'email';\r\n pattern?: RegExp | string;\r\n validator?: (rule: FormRule, value: any, callback: (error?: Error) => void) => void | Promise<void>;\r\n transform?: (value: any) => any;\r\n}\r\n\r\nexport interface ValidateCallback {\r\n (isValid: boolean, invalidFields?: Record<string, string[]>): void;\r\n}\r\n\r\nexport interface ValidateFieldCallback {\r\n (errorMessage?: string): void;\r\n}\r\n\r\ninterface Props {\r\n /** 表单数据对象 */\r\n model?: Record<string, any>;\r\n /** 表单验证规则 */\r\n rules?: FormRules;\r\n /** 表单域标签的宽度,例如 '50px'。作为 Form 直接子元素的 FormItem 会继承该值。支持 auto。 */\r\n labelWidth?: string | number;\r\n /** 表单域标签的位置,如果值为 left 时,则需要设置 label-width */\r\n labelPosition?: 'left' | 'top';\r\n /** 行内表单模式 */\r\n inline?: boolean;\r\n /** 用于控制该表单内组件的尺寸 */\r\n size?: 'large' | 'default' | 'small';\r\n /** 是否禁用该表单内的所有组件。若设置为 true,则表单内组件上的 disabled 属性不再生效 */\r\n disabled?: boolean;\r\n /** 是否在 rules 属性改变后立即触发一次验证 */\r\n validateOnRuleChange?: boolean;\r\n /** 是否显示必填字段的标签旁边的红色星号 */\r\n hideRequiredAsterisk?: boolean;\r\n /** 是否显示校验错误信息 */\r\n showMessage?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n model: () => ({}),\r\n rules: () => ({}),\r\n labelWidth: undefined,\r\n labelPosition: 'left',\r\n inline: false,\r\n size: 'default',\r\n disabled: false,\r\n validateOnRuleChange: true,\r\n hideRequiredAsterisk: false,\r\n showMessage: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n (e: 'validate', prop: string, isValid: boolean, message: string): void;\r\n}>();\r\n\r\nconst formRef = ref<HTMLFormElement>();\r\n\r\n// 存储所有 FormItem 实例\r\nconst formItems = ref<Map<string, any>>(new Map());\r\n\r\n// 保存表单初始值,用于重置\r\nconst initialModel = ref<Record<string, any>>({});\r\n\r\n// 深拷贝对象\r\nconst deepClone = (obj: any): any => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n if (obj instanceof Date) {\r\n return new Date(obj.getTime());\r\n }\r\n if (obj instanceof Array) {\r\n return obj.map(item => deepClone(item));\r\n }\r\n if (typeof obj === 'object') {\r\n const cloned: Record<string, any> = {};\r\n for (const key in obj) {\r\n if (obj.hasOwnProperty(key)) {\r\n cloned[key] = deepClone(obj[key]);\r\n }\r\n }\r\n return cloned;\r\n }\r\n return obj;\r\n};\r\n\r\n// 保存初始值\r\nconst saveInitialValues = () => {\r\n if (props.model) {\r\n initialModel.value = deepClone(props.model);\r\n }\r\n};\r\n\r\n// 注册 FormItem\r\nconst registerFormItem = (prop: string, formItem: any) => {\r\n formItems.value.set(prop, formItem);\r\n};\r\n\r\n// 注销 FormItem\r\nconst unregisterFormItem = (prop: string) => {\r\n formItems.value.delete(prop);\r\n};\r\n\r\n// 提供表单上下文给子组件\r\nprovide('rcForm', {\r\n model: props.model,\r\n rules: props.rules,\r\n labelWidth: props.labelWidth,\r\n labelPosition: props.labelPosition,\r\n size: props.size,\r\n disabled: props.disabled,\r\n hideRequiredAsterisk: props.hideRequiredAsterisk,\r\n showMessage: props.showMessage,\r\n registerFormItem,\r\n unregisterFormItem,\r\n validateField: (prop: string, callback?: ValidateFieldCallback) => {\r\n const formItem = formItems.value.get(prop);\r\n if (formItem) {\r\n return formItem.validate(callback);\r\n }\r\n return Promise.resolve();\r\n },\r\n});\r\n\r\n// 提交标志,防止重复提交\r\nlet isSubmitting = false;\r\n\r\n// 提供表单操作方法给 Button 组件\r\nconst submitForm = () => {\r\n if (isSubmitting) return;\r\n isSubmitting = true;\r\n \r\n validate((isValid) => {\r\n isSubmitting = false;\r\n if (isValid) {\r\n // 表单验证通过,可以在这里处理提交逻辑\r\n console.log('表单验证通过', props.model);\r\n } else {\r\n // 表单验证失败\r\n console.log('表单验证失败');\r\n }\r\n }).catch(() => {\r\n // 捕获验证过程中的错误,避免未处理的 rejection\r\n isSubmitting = false;\r\n });\r\n};\r\n\r\nconst resetForm = () => {\r\n resetFields();\r\n};\r\n\r\nprovide('rcFormActions', {\r\n submit: submitForm,\r\n reset: resetForm,\r\n});\r\n\r\n// 监听 model 变化,保存初始值(仅在首次设置时)\r\nlet isInitialValueSaved = false;\r\nwatch(\r\n () => props.model,\r\n () => {\r\n if (!isInitialValueSaved && props.model) {\r\n saveInitialValues();\r\n isInitialValueSaved = true;\r\n }\r\n },\r\n { immediate: true, deep: true }\r\n);\r\n\r\n// 组件挂载时保存初始值\r\nonMounted(() => {\r\n if (!isInitialValueSaved && props.model) {\r\n saveInitialValues();\r\n isInitialValueSaved = true;\r\n }\r\n});\r\n\r\n// 监听 rules 变化,触发验证\r\nwatch(\r\n () => props.rules,\r\n () => {\r\n if (props.validateOnRuleChange) {\r\n nextTick(() => {\r\n validate().catch(() => {\r\n // 静默处理验证错误,错误信息已通过表单字段显示\r\n });\r\n });\r\n }\r\n },\r\n { deep: true }\r\n);\r\n\r\n// 验证整个表单\r\nconst validate = (callback?: ValidateCallback): Promise<boolean> => {\r\n return new Promise((resolve) => {\r\n const promises: Promise<void>[] = [];\r\n const invalidFields: Record<string, string[]> = {};\r\n\r\n formItems.value.forEach((formItem, prop) => {\r\n const promise = formItem.validate().then(() => {\r\n // 验证通过\r\n emit('validate', prop, true, '');\r\n }).catch((error: string) => {\r\n // 验证失败\r\n if (error) {\r\n invalidFields[prop] = [error];\r\n emit('validate', prop, false, error);\r\n }\r\n });\r\n promises.push(promise);\r\n });\r\n\r\n Promise.all(promises).then(() => {\r\n const isValid = Object.keys(invalidFields).length === 0;\r\n if (callback) {\r\n callback(isValid, isValid ? undefined : invalidFields);\r\n }\r\n resolve(isValid);\r\n }).catch(() => {\r\n // 捕获可能的错误,避免未处理的 rejection\r\n const isValid = Object.keys(invalidFields).length === 0;\r\n if (callback) {\r\n callback(isValid, isValid ? undefined : invalidFields);\r\n }\r\n resolve(isValid);\r\n });\r\n });\r\n};\r\n\r\n// 验证指定字段\r\nconst validateField = (prop: string, callback?: ValidateFieldCallback): Promise<void> => {\r\n const formItem = formItems.value.get(prop);\r\n if (formItem) {\r\n return formItem.validate(callback);\r\n }\r\n return Promise.resolve();\r\n};\r\n\r\n// 重置表单\r\nconst resetFields = () => {\r\n // 重置所有字段的验证状态\r\n formItems.value.forEach((formItem) => {\r\n formItem.resetField();\r\n });\r\n \r\n // 恢复表单数据为初始值\r\n if (props.model && initialModel.value) {\r\n // 先清空所有现有字段\r\n Object.keys(props.model).forEach((key) => {\r\n delete props.model[key];\r\n });\r\n // 然后恢复初始值\r\n Object.keys(initialModel.value).forEach((key) => {\r\n props.model[key] = deepClone(initialModel.value[key]);\r\n });\r\n }\r\n};\r\n\r\n// 清除验证\r\nconst clearValidate = (props?: string | string[]) => {\r\n const propsToClear = props ? (Array.isArray(props) ? props : [props]) : undefined;\r\n \r\n formItems.value.forEach((formItem, prop) => {\r\n if (!propsToClear || propsToClear.includes(prop)) {\r\n formItem.clearValidate();\r\n }\r\n });\r\n};\r\n\r\n// 提交表单\r\nconst onSubmit = (event: Event) => {\r\n event.preventDefault();\r\n submitForm();\r\n};\r\n\r\n// 暴露方法\r\ndefineExpose({\r\n validate,\r\n validateField,\r\n resetFields,\r\n clearValidate,\r\n formRef,\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-form {\r\n --rc-primary: #1677ff;\r\n --rc-text: #323233;\r\n --rc-border: #dcdee0;\r\n --rc-error: #ff3141;\r\n --rc-disabled: #c8c9cc;\r\n --rc-bg: #f7f8fa;\r\n\r\n &--inline {\r\n .rc-form-item {\r\n display: inline-flex;\r\n margin-right: 18px;\r\n vertical-align: top;\r\n }\r\n }\r\n\r\n &--left {\r\n .rc-form-item__label {\r\n text-align: left;\r\n }\r\n }\r\n\r\n &--top {\r\n .rc-form-item {\r\n flex-direction: column;\r\n }\r\n\r\n .rc-form-item__label {\r\n padding: 0 0 8px 0;\r\n line-height: 1.5;\r\n width: 100% !important;\r\n }\r\n }\r\n}\r\n</style>\r\n\r\n\r\n","<template>\r\n <div\r\n class=\"rc-form-item\"\r\n :class=\"[\r\n {\r\n 'is-error': validateState === 'error',\r\n 'is-validating': validateState === 'validating',\r\n 'is-required': isRequired,\r\n 'is-no-asterisk': hideRequiredAsterisk,\r\n 'is-label-top': labelPosition === 'top',\r\n }\r\n ]\"\r\n >\r\n <label\r\n v-if=\"label || $slots.label\"\r\n class=\"rc-form-item__label\"\r\n :style=\"labelStyle\"\r\n :for=\"labelFor\"\r\n >\r\n <slot name=\"label\">\r\n <span v-if=\"label\">{{ label }}</span>\r\n </slot>\r\n </label>\r\n <div class=\"rc-form-item__content\">\r\n <div class=\"rc-form-item__control\">\r\n <slot />\r\n </div>\r\n <transition name=\"rc-form-item-error-fade\">\r\n <div v-if=\"validateState === 'error' && showMessage && validateMessage\" class=\"rc-form-item__error\">\r\n {{ validateMessage }}\r\n </div>\r\n </transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, inject, provide, watch, onMounted, onUnmounted } from 'vue';\r\nimport type { FormRules, FormRule, ValidateFieldCallback } from './index.vue';\r\n\r\ninterface FormContext {\r\n model: Record<string, any>;\r\n rules: FormRules;\r\n labelWidth?: string | number;\r\n labelPosition?: 'left' | 'top';\r\n size?: 'large' | 'default' | 'small';\r\n disabled?: boolean;\r\n hideRequiredAsterisk?: boolean;\r\n showMessage?: boolean;\r\n registerFormItem: (prop: string, formItem: any) => void;\r\n unregisterFormItem: (prop: string) => void;\r\n validateField: (prop: string, callback?: ValidateFieldCallback) => Promise<void>;\r\n}\r\n\r\ninterface Props {\r\n /** 表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的 */\r\n prop?: string;\r\n /** 标签文本 */\r\n label?: string;\r\n /** 表单域标签的的宽度,例如 '50px'。支持 auto。 */\r\n labelWidth?: string | number;\r\n /** 是否必填,如不设置,则会根据校验规则自动生成 */\r\n required?: boolean;\r\n /** 表单验证规则 */\r\n rules?: FormRule | FormRule[];\r\n /** 是否显示校验错误信息 */\r\n showMessage?: boolean;\r\n /** 以行内形式展示校验信息 */\r\n inlineMessage?: boolean;\r\n /** 自定义错误提示信息,设置该值会使表单验证状态变为 error,并显示该错误信息 */\r\n error?: string;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n prop: '',\r\n label: '',\r\n labelWidth: undefined,\r\n required: undefined,\r\n rules: undefined,\r\n showMessage: undefined,\r\n inlineMessage: false,\r\n error: '',\r\n});\r\n\r\nconst formContext = inject<FormContext | undefined>('rcForm', undefined);\r\n\r\nconst validateState = ref<'success' | 'error' | 'validating' | ''>('');\r\nconst validateMessage = ref('');\r\n\r\n// 计算标签样式\r\nconst labelStyle = computed(() => {\r\n const width = props.labelWidth ?? formContext?.labelWidth;\r\n if (width) {\r\n return {\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n };\r\n }\r\n return {};\r\n});\r\n\r\n// label 的 for 属性(暂时不实现)\r\nconst labelFor = computed(() => {\r\n return undefined;\r\n});\r\n\r\n// 是否显示错误信息\r\nconst showMessage = computed(() => {\r\n return props.showMessage ?? formContext?.showMessage ?? true;\r\n});\r\n\r\n// 是否隐藏必填星号\r\nconst hideRequiredAsterisk = computed(() => {\r\n return formContext?.hideRequiredAsterisk ?? false;\r\n});\r\n\r\n// 标签位置\r\nconst labelPosition = computed(() => {\r\n return formContext?.labelPosition ?? 'left';\r\n});\r\n\r\n// 计算是否必填\r\nconst isRequired = computed(() => {\r\n if (props.required !== undefined) {\r\n return props.required;\r\n }\r\n \r\n if (!props.prop || !formContext) {\r\n return false;\r\n }\r\n\r\n const rules = getRules();\r\n if (rules && rules.length > 0) {\r\n return rules.some((rule) => rule.required);\r\n }\r\n \r\n return false;\r\n});\r\n\r\n// 获取验证规则\r\nconst getRules = (): FormRule[] => {\r\n if (props.rules) {\r\n return Array.isArray(props.rules) ? props.rules : [props.rules];\r\n }\r\n \r\n if (!props.prop || !formContext) {\r\n return [];\r\n }\r\n\r\n const formRules = formContext.rules[props.prop];\r\n if (formRules) {\r\n return Array.isArray(formRules) ? formRules : [formRules];\r\n }\r\n \r\n return [];\r\n};\r\n\r\n// 获取字段值\r\nconst getFieldValue = (): any => {\r\n if (!props.prop || !formContext) {\r\n return undefined;\r\n }\r\n return formContext.model[props.prop];\r\n};\r\n\r\n// 设置字段值\r\nconst setFieldValue = (value: any) => {\r\n if (!props.prop || !formContext) {\r\n return;\r\n }\r\n formContext.model[props.prop] = value;\r\n};\r\n\r\n// 验证单个规则\r\nconst validateRule = (rule: FormRule, value: any): Promise<string | null> => {\r\n return new Promise((resolve) => {\r\n // 转换值\r\n let transformedValue = value;\r\n if (rule.transform) {\r\n transformedValue = rule.transform(value);\r\n }\r\n\r\n // 必填验证\r\n if (rule.required) {\r\n if (transformedValue === undefined || transformedValue === null || transformedValue === '') {\r\n const message = rule.message || `${props.label || props.prop} 是必填项`;\r\n resolve(message);\r\n return;\r\n }\r\n }\r\n\r\n // 类型验证\r\n if (rule.type && transformedValue !== undefined && transformedValue !== null && transformedValue !== '') {\r\n const typeValid = validateType(transformedValue, rule.type);\r\n if (!typeValid) {\r\n const message = rule.message || `${props.label || props.prop} 格式不正确`;\r\n resolve(message);\r\n return;\r\n }\r\n }\r\n\r\n // 最小长度/值验证\r\n if (rule.min !== undefined && transformedValue !== undefined && transformedValue !== null && transformedValue !== '') {\r\n const length = Array.isArray(transformedValue) || typeof transformedValue === 'string' \r\n ? transformedValue.length \r\n : transformedValue;\r\n if (length < rule.min) {\r\n const message = rule.message || `${props.label || props.prop} 不能少于 ${rule.min} 个字符`;\r\n resolve(message);\r\n return;\r\n }\r\n }\r\n\r\n // 最大长度/值验证\r\n if (rule.max !== undefined && transformedValue !== undefined && transformedValue !== null && transformedValue !== '') {\r\n const length = Array.isArray(transformedValue) || typeof transformedValue === 'string' \r\n ? transformedValue.length \r\n : transformedValue;\r\n if (length > rule.max) {\r\n const message = rule.message || `${props.label || props.prop} 不能超过 ${rule.max} 个字符`;\r\n resolve(message);\r\n return;\r\n }\r\n }\r\n\r\n // 正则验证\r\n if (rule.pattern) {\r\n const pattern = typeof rule.pattern === 'string' ? new RegExp(rule.pattern) : rule.pattern;\r\n if (transformedValue !== undefined && transformedValue !== null && transformedValue !== '' && !pattern.test(String(transformedValue))) {\r\n const message = rule.message || `${props.label || props.prop} 格式不正确`;\r\n resolve(message);\r\n return;\r\n }\r\n }\r\n\r\n // 自定义验证器\r\n if (rule.validator) {\r\n const result = rule.validator(rule, transformedValue, (error?: Error) => {\r\n if (error) {\r\n resolve(error.message || rule.message || `${props.label || props.prop} 验证失败`);\r\n } else {\r\n resolve(null);\r\n }\r\n });\r\n \r\n // 如果返回 Promise\r\n if (result instanceof Promise) {\r\n result.then(() => {\r\n resolve(null);\r\n }).catch((error) => {\r\n resolve(error?.message || rule.message || `${props.label || props.prop} 验证失败`);\r\n });\r\n return;\r\n }\r\n }\r\n\r\n resolve(null);\r\n });\r\n};\r\n\r\n// 类型验证\r\nconst validateType = (value: any, type: string): boolean => {\r\n switch (type) {\r\n case 'string':\r\n return typeof value === 'string';\r\n case 'number':\r\n return typeof value === 'number' && !isNaN(value);\r\n case 'boolean':\r\n return typeof value === 'boolean';\r\n case 'integer':\r\n return Number.isInteger(value);\r\n case 'float':\r\n return typeof value === 'number' && !isNaN(value) && !Number.isInteger(value);\r\n case 'array':\r\n return Array.isArray(value);\r\n case 'object':\r\n return typeof value === 'object' && value !== null && !Array.isArray(value);\r\n case 'email':\r\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(String(value));\r\n case 'url':\r\n try {\r\n new URL(String(value));\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n case 'date':\r\n return value instanceof Date || !isNaN(Date.parse(String(value)));\r\n default:\r\n return true;\r\n }\r\n};\r\n\r\n// 验证字段\r\nconst validate = (trigger?: 'blur' | 'change' | 'submit', callback?: ValidateFieldCallback): Promise<void> => {\r\n return new Promise((resolve, reject) => {\r\n // 如果有自定义错误信息,直接显示\r\n if (props.error) {\r\n validateState.value = 'error';\r\n validateMessage.value = props.error;\r\n if (callback) callback(props.error);\r\n reject(new Error(props.error));\r\n return;\r\n }\r\n\r\n if (!props.prop) {\r\n resolve();\r\n return;\r\n }\r\n\r\n const rules = getRules();\r\n if (rules.length === 0) {\r\n validateState.value = '';\r\n validateMessage.value = '';\r\n resolve();\r\n return;\r\n }\r\n\r\n // 如果指定了trigger,根据trigger过滤规则\r\n // submit 或未指定:验证所有规则(提交时)\r\n // blur/change:只验证对应trigger的规则(失焦/值变化时)\r\n let rulesToValidate: FormRule[];\r\n if (!trigger || trigger === 'submit') {\r\n // 提交时验证所有规则\r\n rulesToValidate = rules;\r\n } else {\r\n // blur 或 change 时,只验证对应 trigger 的规则\r\n // 注意:未设置 trigger 的规则默认是 'submit',在 blur/change 时不验证\r\n rulesToValidate = rules.filter((rule) => rule.trigger === trigger);\r\n }\r\n\r\n if (rulesToValidate.length === 0) {\r\n // 如果没有需要验证的规则,直接resolve\r\n resolve();\r\n return;\r\n }\r\n\r\n validateState.value = 'validating';\r\n validateMessage.value = '';\r\n\r\n const value = getFieldValue();\r\n const promises = rulesToValidate.map((rule) => validateRule(rule, value));\r\n\r\n Promise.all(promises).then((errors) => {\r\n const error = errors.find((e) => e !== null);\r\n if (error) {\r\n validateState.value = 'error';\r\n validateMessage.value = error;\r\n if (callback) callback(error);\r\n reject(new Error(error));\r\n } else {\r\n // 如果当前验证通过,但还有其他未验证的规则,保持当前状态\r\n // 否则设置为success\r\n if (!trigger || rulesToValidate.length === rules.length) {\r\n validateState.value = 'success';\r\n validateMessage.value = '';\r\n }\r\n if (callback) callback();\r\n resolve();\r\n }\r\n }).catch((err) => {\r\n // 捕获 Promise.all 可能的错误,避免未处理的 rejection\r\n const errorMessage = err?.message || '验证失败';\r\n validateState.value = 'error';\r\n validateMessage.value = errorMessage;\r\n if (callback) callback(errorMessage);\r\n reject(err);\r\n });\r\n });\r\n};\r\n\r\n// 重置字段\r\nconst resetField = () => {\r\n validateState.value = '';\r\n validateMessage.value = '';\r\n // 数据重置由表单组件统一处理\r\n};\r\n\r\n// 清除验证\r\nconst clearValidate = () => {\r\n validateState.value = '';\r\n validateMessage.value = '';\r\n};\r\n\r\n// 监听字段值变化(仅在trigger为change时验证)\r\nwatch(\r\n () => getFieldValue(),\r\n () => {\r\n const rules = getRules();\r\n const hasChangeRule = rules.some((rule) => rule.trigger === 'change');\r\n const hasBlurRule = rules.some((rule) => rule.trigger === 'blur');\r\n \r\n // 只有在有change规则时才在值变化时验证\r\n if (hasChangeRule) {\r\n validate('change').catch(() => {\r\n // 静默处理验证错误,错误信息已通过 validateState 和 validateMessage 显示\r\n });\r\n } else if (hasBlurRule && validateState.value === 'error') {\r\n // 如果trigger是blur且已有错误,值变化时不清除错误,保持错误状态直到下次blur验证\r\n // 这样可以避免用户输入时错误信息闪烁\r\n }\r\n }\r\n);\r\n\r\n// 监听自定义错误\r\nwatch(\r\n () => props.error,\r\n (error) => {\r\n if (error) {\r\n validateState.value = 'error';\r\n validateMessage.value = error;\r\n } else if (validateState.value === 'error' && !props.prop) {\r\n clearValidate();\r\n }\r\n }\r\n);\r\n\r\n// 提供form-item的验证函数给子组件(用于blur/change事件)\r\nprovide('rcFormItem', {\r\n onBlur: () => {\r\n const rules = getRules();\r\n const hasBlurRule = rules.some((rule) => rule.trigger === 'blur');\r\n if (hasBlurRule) {\r\n validate('blur').catch(() => {\r\n // 静默处理验证错误\r\n });\r\n }\r\n },\r\n onChange: () => {\r\n const rules = getRules();\r\n const hasChangeRule = rules.some((rule) => rule.trigger === 'change');\r\n if (hasChangeRule) {\r\n validate('change').catch(() => {\r\n // 静默处理验证错误\r\n });\r\n }\r\n },\r\n});\r\n\r\n// 注册到父表单\r\nonMounted(() => {\r\n if (props.prop && formContext) {\r\n formContext.registerFormItem(props.prop, {\r\n validate,\r\n resetField,\r\n clearValidate,\r\n });\r\n }\r\n});\r\n\r\n// 注销\r\nonUnmounted(() => {\r\n if (props.prop && formContext) {\r\n formContext.unregisterFormItem(props.prop);\r\n }\r\n});\r\n\r\n// 暴露方法\r\ndefineExpose({\r\n validate,\r\n resetField,\r\n clearValidate,\r\n validateState,\r\n validateMessage,\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-form-item {\r\n display: flex;\r\n margin-bottom: 18px;\r\n\r\n &__label {\r\n padding: 0 12px 0 0;\r\n line-height: 32px;\r\n color: var(--rc-text, #323233);\r\n font-size: 14px;\r\n box-sizing: border-box;\r\n flex-shrink: 0;\r\n }\r\n\r\n &__content {\r\n display: flex;\r\n flex-direction: column;\r\n flex: 1;\r\n min-width: 0;\r\n }\r\n\r\n &__control {\r\n width: 100%;\r\n }\r\n\r\n &__error {\r\n color: var(--rc-error, #ff3141);\r\n font-size: 12px;\r\n line-height: 1.5;\r\n padding-top: 4px;\r\n width: 100%;\r\n }\r\n\r\n // 标签在顶部时的布局\r\n &.is-label-top {\r\n flex-direction: column;\r\n\r\n .rc-form-item__label {\r\n padding: 0 0 8px 0;\r\n line-height: 1.5;\r\n width: 100% !important;\r\n }\r\n }\r\n\r\n &.is-required:not(.is-no-asterisk) {\r\n .rc-form-item__label::before {\r\n content: '*';\r\n color: var(--rc-error, #ff3141);\r\n margin-right: 4px;\r\n }\r\n }\r\n\r\n &.is-error {\r\n .rc-input__wrapper,\r\n .rc-input__field {\r\n border-color: var(--rc-error, #ff3141);\r\n }\r\n }\r\n}\r\n\r\n// 错误信息淡入淡出动画\r\n.rc-form-item-error-fade-enter-active,\r\n.rc-form-item-error-fade-leave-active {\r\n transition: opacity 0.3s;\r\n}\r\n\r\n.rc-form-item-error-fade-enter-from,\r\n.rc-form-item-error-fade-leave-to {\r\n opacity: 0;\r\n}\r\n</style>\r\n\r\n\r\n","import type { App } from 'vue';\r\nimport Form from './index.vue';\r\nimport FormItem from './item.vue';\r\n\r\n// 组件名使用全小写,以 <rc-form> 形式在模板中使用\r\nif (Form) {\r\n (Form as any).name = 'rc-form';\r\n}\r\nif (FormItem) {\r\n (FormItem as any).name = 'rc-form-item';\r\n}\r\n\r\nexport function install(app: App) {\r\n if (Form) {\r\n app.component((Form as any).name || 'rc-form', Form);\r\n }\r\n if (FormItem) {\r\n app.component((FormItem as any).name || 'rc-form-item', FormItem);\r\n }\r\n return app;\r\n}\r\n\r\nexport default Form;\r\nexport { FormItem };\r\nexport type { FormRules, FormRule, ValidateCallback, ValidateFieldCallback } from './index.vue';\r\n\r\n\r\n","<template>\r\n <label\r\n class=\"rc-radio\"\r\n :class=\"[\r\n {\r\n 'is-checked': isChecked,\r\n 'is-disabled': isDisabled,\r\n 'is-border': border,\r\n [`rc-radio--${size}`]: size,\r\n }\r\n ]\"\r\n >\r\n <span class=\"rc-radio__input\" :class=\"{ 'is-checked': isChecked, 'is-disabled': isDisabled }\">\r\n <span class=\"rc-radio__inner\"></span>\r\n <input\r\n ref=\"radioRef\"\r\n v-model=\"model\"\r\n :value=\"label\"\r\n class=\"rc-radio__original\"\r\n :name=\"name\"\r\n :disabled=\"isDisabled\"\r\n type=\"radio\"\r\n @change=\"handleChange\"\r\n @focus=\"handleFocus\"\r\n @blur=\"handleBlur\"\r\n />\r\n </span>\r\n <span class=\"rc-radio__label\">\r\n <slot>\r\n <template v-if=\"label !== undefined\">{{ label }}</template>\r\n </slot>\r\n </span>\r\n </label>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, inject, ref, unref } from 'vue';\r\n\r\ndefineOptions({ name: 'rc-radio' });\r\n\r\ninterface RadioGroupContext {\r\n modelValue: string | number | boolean;\r\n changeEvent: (value: string | number | boolean) => void;\r\n size?: 'large' | 'default' | 'small';\r\n disabled?: boolean;\r\n name?: string;\r\n fill?: string;\r\n textColor?: string;\r\n}\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 绑定值,使用 RadioGroup 时不需要单独设置 */\r\n modelValue?: string | number | boolean;\r\n /** Radio 的 value */\r\n label?: string | number | boolean;\r\n /** 是否禁用 */\r\n disabled?: boolean;\r\n /** 是否显示边框 */\r\n border?: boolean;\r\n /** Radio 的尺寸,仅在 border 为真时有效 */\r\n size?: 'large' | 'default' | 'small';\r\n /** 原生 name 属性 */\r\n name?: string;\r\n}>(), {\r\n modelValue: undefined,\r\n label: undefined,\r\n disabled: false,\r\n border: false,\r\n size: 'default',\r\n name: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: string | number | boolean): void;\r\n (e: 'change', value: string | number | boolean): void;\r\n (e: 'focus', event: FocusEvent): void;\r\n (e: 'blur', event: FocusEvent): void;\r\n}>();\r\n\r\nconst radioRef = ref<HTMLInputElement>();\r\nconst radioGroup = inject<RadioGroupContext | undefined>('RadioGroup', undefined);\r\n\r\n// 是否在 RadioGroup 中\r\nconst isGroup = computed(() => !!radioGroup);\r\n\r\n// 当前值(优先使用 RadioGroup 的值)\r\nconst model = computed({\r\n get() {\r\n return isGroup.value ? unref(radioGroup!.modelValue) : props.modelValue;\r\n },\r\n set(val: string | number | boolean) {\r\n if (isGroup.value) {\r\n radioGroup!.changeEvent(val);\r\n } else {\r\n emit('update:modelValue', val);\r\n }\r\n },\r\n});\r\n\r\n// 是否选中\r\nconst isChecked = computed(() => {\r\n const value = model.value;\r\n const label = props.label;\r\n return value === label;\r\n});\r\n\r\n// 是否禁用(优先使用 RadioGroup 的设置)\r\nconst isDisabled = computed(() => {\r\n return props.disabled || radioGroup?.disabled || false;\r\n});\r\n\r\n// 实际尺寸(优先使用 RadioGroup 的设置)\r\nconst actualSize = computed(() => {\r\n return radioGroup?.size || props.size;\r\n});\r\n\r\n// 注入 formItem 的验证方法\r\ninterface FormItemContext {\r\n onBlur?: () => void;\r\n onChange?: () => void;\r\n}\r\nconst formItemContext = inject<FormItemContext | undefined>('rcFormItem', undefined);\r\n\r\nconst handleChange = (event: Event) => {\r\n const target = event.target as HTMLInputElement;\r\n if (target.checked) {\r\n emit('change', props.label!);\r\n formItemContext?.onChange?.();\r\n }\r\n};\r\n\r\nconst handleFocus = (event: FocusEvent) => {\r\n emit('focus', event);\r\n};\r\n\r\nconst handleBlur = (event: FocusEvent) => {\r\n emit('blur', event);\r\n formItemContext?.onBlur?.();\r\n};\r\n\r\ndefineExpose({\r\n radioRef,\r\n focus: () => {\r\n radioRef.value?.focus();\r\n },\r\n blur: () => {\r\n radioRef.value?.blur();\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-radio {\r\n color: var(--rc-text, #333333);\r\n font-weight: 500;\r\n cursor: pointer;\r\n display: inline-flex;\r\n align-items: center;\r\n white-space: nowrap;\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n height: 32px;\r\n margin-right: 30px;\r\n\r\n &:last-child {\r\n margin-right: 0;\r\n }\r\n\r\n &:hover:not(.is-disabled) {\r\n .rc-radio__inner {\r\n border-color: var(--rc-primary, #1d85fc);\r\n }\r\n }\r\n\r\n &.is-disabled {\r\n cursor: not-allowed;\r\n color: var(--rc-disabled, #c0c4cc);\r\n\r\n .rc-radio__input {\r\n cursor: not-allowed;\r\n }\r\n\r\n .rc-radio__inner {\r\n background-color: var(--rc-bg, #f5f7fa);\r\n border-color: var(--rc-border, #e4e7ed);\r\n cursor: not-allowed;\r\n\r\n &::after {\r\n cursor: not-allowed;\r\n background-color: var(--rc-disabled, #c0c4cc);\r\n }\r\n }\r\n }\r\n\r\n &.is-checked {\r\n .rc-radio__inner {\r\n border-color: var(--rc-primary, #1d85fc);\r\n background: var(--rc-primary, #1d85fc);\r\n\r\n &::after {\r\n transform: translate(-50%, -50%) scale(1);\r\n }\r\n }\r\n\r\n .rc-radio__label {\r\n color: var(--rc-primary, #1d85fc);\r\n }\r\n }\r\n\r\n &.is-border {\r\n padding: 12px 20px 12px 10px;\r\n border-radius: 4px;\r\n border: 1px solid var(--rc-border, #dcdfe6);\r\n box-sizing: border-box;\r\n height: auto;\r\n margin-right: 0;\r\n margin-bottom: 0;\r\n\r\n &.is-checked {\r\n border-color: var(--rc-primary, #1d85fc);\r\n }\r\n\r\n &.is-disabled {\r\n background-color: var(--rc-bg, #f5f7fa);\r\n border-color: var(--rc-border, #e4e7ed);\r\n cursor: not-allowed;\r\n color: var(--rc-disabled, #c0c4cc);\r\n }\r\n\r\n &.rc-radio--large {\r\n padding: 14px 20px 14px 10px;\r\n font-size: 14px;\r\n\r\n .rc-radio__inner {\r\n width: 20px;\r\n height: 20px;\r\n }\r\n }\r\n\r\n &.rc-radio--small {\r\n padding: 8px 15px 8px 10px;\r\n font-size: 12px;\r\n\r\n .rc-radio__inner {\r\n width: 18px;\r\n height: 18px;\r\n }\r\n }\r\n }\r\n}\r\n\r\n.rc-radio__input {\r\n white-space: nowrap;\r\n cursor: pointer;\r\n outline: none;\r\n display: inline-flex;\r\n position: relative;\r\n vertical-align: middle;\r\n\r\n &.is-checked {\r\n .rc-radio__inner {\r\n border-color: var(--rc-primary, #1d85fc);\r\n background: var(--rc-primary, #1d85fc);\r\n\r\n &::after {\r\n transform: translate(-50%, -50%) scale(1);\r\n }\r\n }\r\n }\r\n\r\n &.is-disabled {\r\n .rc-radio__inner {\r\n background-color: var(--rc-bg, #f5f7fa);\r\n border-color: var(--rc-border, #e4e7ed);\r\n cursor: not-allowed;\r\n\r\n &::after {\r\n cursor: not-allowed;\r\n background-color: var(--rc-disabled, #c0c4cc);\r\n }\r\n }\r\n }\r\n}\r\n\r\n.rc-radio__inner {\r\n border: 1px solid var(--rc-border, #dcdfe6);\r\n border-radius: 100%;\r\n width: 18px;\r\n height: 18px;\r\n background-color: var(--rc-white, #ffffff);\r\n position: relative;\r\n cursor: pointer;\r\n display: inline-block;\r\n box-sizing: border-box;\r\n\r\n &:hover {\r\n border-color: var(--rc-primary, #1d85fc);\r\n }\r\n\r\n &::after {\r\n width: 8px;\r\n height: 8px;\r\n border-radius: 100%;\r\n background-color: var(--rc-white, #ffffff);\r\n content: \"\";\r\n position: absolute;\r\n left: 50%;\r\n top: 50%;\r\n transform: translate(-50%, -50%) scale(0);\r\n transition: transform 0.15s ease-in;\r\n }\r\n}\r\n\r\n.rc-radio__original {\r\n opacity: 0;\r\n outline: none;\r\n position: absolute;\r\n z-index: -1;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n margin: 0;\r\n}\r\n\r\n.rc-radio__label {\r\n font-size: 14px;\r\n padding-left: 8px;\r\n}\r\n</style>\r\n\r\n","<template>\r\n <div class=\"rc-radio-group\" :class=\"[{ 'is-disabled': disabled }]\">\r\n <slot />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { provide, computed, watch, inject, type ComputedRef } from 'vue';\r\n\r\ndefineOptions({ name: 'rc-radio-group' });\r\n\r\nexport interface RadioGroupContext {\r\n modelValue: ComputedRef<string | number | boolean>;\r\n changeEvent: (value: string | number | boolean) => void;\r\n size?: 'large' | 'default' | 'small';\r\n disabled?: boolean;\r\n name?: string;\r\n fill?: string;\r\n textColor?: string;\r\n}\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 绑定值 */\r\n modelValue?: string | number | boolean;\r\n /** Radio 按钮组尺寸,仅对按钮样式的 Radio 有效 */\r\n size?: 'large' | 'default' | 'small';\r\n /** 是否禁用 */\r\n disabled?: boolean;\r\n /** 按钮形式的 Radio 激活时的文本颜色 */\r\n textColor?: string;\r\n /** 按钮形式的 Radio 激活时的填充色和边框色 */\r\n fill?: string;\r\n /** 原生 name 属性 */\r\n name?: string;\r\n}>(), {\r\n modelValue: undefined,\r\n size: 'default',\r\n disabled: false,\r\n textColor: undefined,\r\n fill: undefined,\r\n name: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: string | number | boolean): void;\r\n (e: 'change', value: string | number | boolean): void;\r\n}>();\r\n\r\nconst changeEvent = (value: string | number | boolean) => {\r\n emit('update:modelValue', value);\r\n emit('change', value);\r\n};\r\n\r\n// 注入 formItem 的验证方法\r\ninterface FormItemContext {\r\n onChange?: () => void;\r\n}\r\nconst formItemContext = inject<FormItemContext | undefined>('rcFormItem', undefined);\r\n\r\nwatch(() => props.modelValue, () => {\r\n formItemContext?.onChange?.();\r\n});\r\n\r\nprovide<RadioGroupContext>('RadioGroup', {\r\n modelValue: computed(() => props.modelValue!),\r\n changeEvent,\r\n size: props.size,\r\n disabled: props.disabled,\r\n name: props.name,\r\n fill: props.fill,\r\n textColor: props.textColor,\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-radio-group {\r\n display: inline-flex;\r\n flex-wrap: wrap;\r\n font-size: 0;\r\n\r\n &.is-disabled {\r\n cursor: not-allowed;\r\n }\r\n}\r\n</style>\r\n","<template>\r\n <label\r\n class=\"rc-radio-button\"\r\n :class=\"[\r\n {\r\n 'is-active': isChecked,\r\n 'is-disabled': isDisabled,\r\n 'is-focus': focused,\r\n [`rc-radio-button--${actualSize}`]: actualSize,\r\n }\r\n ]\"\r\n :style=\"buttonStyle\"\r\n >\r\n <input\r\n ref=\"radioRef\"\r\n v-model=\"model\"\r\n :value=\"label\"\r\n class=\"rc-radio-button__original\"\r\n :name=\"name\"\r\n :disabled=\"isDisabled\"\r\n type=\"radio\"\r\n @change=\"handleChange\"\r\n @focus=\"handleFocus\"\r\n @blur=\"handleBlur\"\r\n />\r\n <span class=\"rc-radio-button__inner\">\r\n <slot>\r\n <template v-if=\"label !== undefined\">{{ label }}</template>\r\n </slot>\r\n </span>\r\n </label>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, inject, ref, unref } from 'vue';\r\nimport type { RadioGroupContext } from './group.vue';\r\n\r\ndefineOptions({ name: 'rc-radio-button' });\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 绑定值,使用 RadioGroup 时不需要单独设置 */\r\n modelValue?: string | number | boolean;\r\n /** Radio 的 value */\r\n label?: string | number | boolean;\r\n /** 是否禁用 */\r\n disabled?: boolean;\r\n /** 原生 name 属性 */\r\n name?: string;\r\n}>(), {\r\n modelValue: undefined,\r\n label: undefined,\r\n disabled: false,\r\n name: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: string | number | boolean): void;\r\n (e: 'change', value: string | number | boolean): void;\r\n (e: 'focus', event: FocusEvent): void;\r\n (e: 'blur', event: FocusEvent): void;\r\n}>();\r\n\r\nconst radioRef = ref<HTMLInputElement>();\r\nconst focused = ref(false);\r\nconst radioGroup = inject<RadioGroupContext | undefined>('RadioGroup', undefined);\r\n\r\n// 是否在 RadioGroup 中\r\nconst isGroup = computed(() => !!radioGroup);\r\n\r\n// 当前值(优先使用 RadioGroup 的值)\r\nconst model = computed({\r\n get() {\r\n return isGroup.value ? unref(radioGroup!.modelValue) : props.modelValue;\r\n },\r\n set(val: string | number | boolean) {\r\n if (isGroup.value) {\r\n radioGroup!.changeEvent(val);\r\n } else {\r\n emit('update:modelValue', val);\r\n }\r\n },\r\n});\r\n\r\n// 是否选中\r\nconst isChecked = computed(() => {\r\n const value = model.value;\r\n const label = props.label;\r\n return value === label;\r\n});\r\n\r\n// 是否禁用(优先使用 RadioGroup 的设置)\r\nconst isDisabled = computed(() => {\r\n return props.disabled || radioGroup?.disabled || false;\r\n});\r\n\r\n// 实际尺寸(优先使用 RadioGroup 的设置)\r\nconst actualSize = computed(() => {\r\n return radioGroup?.size || 'default';\r\n});\r\n\r\n// 按钮样式(使用 RadioGroup 的颜色配置)\r\nconst buttonStyle = computed(() => {\r\n if (!isChecked.value || !radioGroup) {\r\n return {};\r\n }\r\n const style: Record<string, string> = {};\r\n if (radioGroup.fill) {\r\n style.backgroundColor = radioGroup.fill;\r\n style.borderColor = radioGroup.fill;\r\n }\r\n if (radioGroup.textColor) {\r\n style.color = radioGroup.textColor;\r\n }\r\n return style;\r\n});\r\n\r\n// 注入 formItem 的验证方法\r\ninterface FormItemContext {\r\n onBlur?: () => void;\r\n onChange?: () => void;\r\n}\r\nconst formItemContext = inject<FormItemContext | undefined>('rcFormItem', undefined);\r\n\r\nconst handleChange = (event: Event) => {\r\n const target = event.target as HTMLInputElement;\r\n if (target.checked) {\r\n emit('change', props.label!);\r\n formItemContext?.onChange?.();\r\n }\r\n};\r\n\r\nconst handleFocus = (event: FocusEvent) => {\r\n focused.value = true;\r\n emit('focus', event);\r\n};\r\n\r\nconst handleBlur = (event: FocusEvent) => {\r\n focused.value = false;\r\n emit('blur', event);\r\n formItemContext?.onBlur?.();\r\n};\r\n\r\ndefineExpose({\r\n radioRef,\r\n focus: () => {\r\n radioRef.value?.focus();\r\n },\r\n blur: () => {\r\n radioRef.value?.blur();\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-radio-button {\r\n position: relative;\r\n display: inline-block;\r\n outline: none;\r\n cursor: pointer;\r\n user-select: none;\r\n vertical-align: middle;\r\n\r\n &__original {\r\n opacity: 0;\r\n outline: none;\r\n position: absolute;\r\n z-index: -1;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n margin: 0;\r\n }\r\n\r\n &__inner {\r\n display: inline-block;\r\n line-height: 1;\r\n white-space: nowrap;\r\n vertical-align: middle;\r\n background: var(--rc-white, #ffffff);\r\n border: 1px solid var(--rc-border, #dcdfe6);\r\n font-weight: 500;\r\n border-left: 0;\r\n color: var(--rc-text, #606266);\r\n text-align: center;\r\n box-sizing: border-box;\r\n margin: 0;\r\n padding: 12px 20px;\r\n font-size: 14px;\r\n border-radius: 0;\r\n transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);\r\n cursor: pointer;\r\n }\r\n\r\n &:first-child {\r\n .rc-radio-button__inner {\r\n border-left: 1px solid var(--rc-border, #dcdfe6);\r\n border-radius: 4px 0 0 4px;\r\n box-shadow: none !important;\r\n }\r\n }\r\n\r\n &:last-child {\r\n .rc-radio-button__inner {\r\n border-radius: 0 4px 4px 0;\r\n }\r\n }\r\n\r\n &:first-child:last-child {\r\n .rc-radio-button__inner {\r\n border-radius: 4px;\r\n }\r\n }\r\n\r\n &:hover:not(.is-disabled) {\r\n .rc-radio-button__inner {\r\n color: var(--rc-primary, #1d85fc);\r\n }\r\n }\r\n\r\n &.is-active {\r\n .rc-radio-button__inner {\r\n color: var(--rc-white, #ffffff);\r\n background-color: var(--rc-primary, #1d85fc);\r\n border-color: var(--rc-primary, #1d85fc);\r\n box-shadow: -1px 0 0 0 var(--rc-primary, #1d85fc);\r\n }\r\n\r\n &:first-child {\r\n .rc-radio-button__inner {\r\n border-left-color: var(--rc-primary, #1d85fc);\r\n }\r\n }\r\n }\r\n\r\n &.is-disabled {\r\n cursor: not-allowed;\r\n\r\n .rc-radio-button__inner {\r\n color: var(--rc-disabled, #c0c4cc);\r\n cursor: not-allowed;\r\n background-image: none;\r\n background-color: var(--rc-white, #ffffff);\r\n border-color: var(--rc-border, #e4e7ed);\r\n box-shadow: none;\r\n }\r\n\r\n &:first-child {\r\n .rc-radio-button__inner {\r\n border-left-color: var(--rc-border, #e4e7ed);\r\n }\r\n }\r\n }\r\n\r\n &.is-focus {\r\n .rc-radio-button__inner {\r\n border-color: var(--rc-primary, #1d85fc);\r\n }\r\n }\r\n\r\n &--large {\r\n .rc-radio-button__inner {\r\n padding: 14px 20px;\r\n font-size: 14px;\r\n border-radius: 0;\r\n }\r\n\r\n &:first-child {\r\n .rc-radio-button__inner {\r\n border-radius: 4px 0 0 4px;\r\n }\r\n }\r\n\r\n &:last-child {\r\n .rc-radio-button__inner {\r\n border-radius: 0 4px 4px 0;\r\n }\r\n }\r\n }\r\n\r\n &--small {\r\n .rc-radio-button__inner {\r\n padding: 8px 15px;\r\n font-size: 12px;\r\n border-radius: 0;\r\n }\r\n\r\n &:first-child {\r\n .rc-radio-button__inner {\r\n border-radius: 3px 0 0 3px;\r\n }\r\n }\r\n\r\n &:last-child {\r\n .rc-radio-button__inner {\r\n border-radius: 0 3px 3px 0;\r\n }\r\n }\r\n }\r\n}\r\n\r\n.rc-radio-group {\r\n .rc-radio-button {\r\n &:not(:first-child) {\r\n margin-left: -1px;\r\n }\r\n }\r\n}\r\n</style>\r\n\r\n","import type { App } from 'vue';\r\nimport Radio from './index.vue';\r\nimport RadioGroup from './group.vue';\r\nimport RadioButton from './button.vue';\r\n\r\n(Radio as any).name = 'rc-radio';\r\n(RadioGroup as any).name = 'rc-radio-group';\r\n(RadioButton as any).name = 'rc-radio-button';\r\n\r\nexport function install(app: App) {\r\n app.component((Radio as any).name, Radio);\r\n app.component('RcRadio', Radio);\r\n app.component((RadioGroup as any).name, RadioGroup);\r\n app.component('RcRadioGroup', RadioGroup);\r\n app.component((RadioButton as any).name, RadioButton);\r\n app.component('RcRadioButton', RadioButton);\r\n return app;\r\n}\r\n\r\nexport { RadioGroup, RadioButton };\r\nexport default Radio;\r\n","<template>\r\n <label\r\n class=\"rc-checkbox\"\r\n :class=\"[\r\n {\r\n 'is-checked': isChecked,\r\n 'is-disabled': isDisabled,\r\n 'is-indeterminate': indeterminate,\r\n 'is-border': border,\r\n [`rc-checkbox--${size}`]: size,\r\n }\r\n ]\"\r\n >\r\n <span class=\"rc-checkbox__input\" :class=\"{ 'is-checked': isChecked, 'is-disabled': isDisabled, 'is-indeterminate': indeterminate }\">\r\n <span class=\"rc-checkbox__inner\">\r\n <rc-icon v-if=\"isChecked && !indeterminate\" name=\"icon_select\" class=\"rc-checkbox__icon\" :size=\"14\" />\r\n </span>\r\n <input\r\n ref=\"checkboxRef\"\r\n :checked=\"isGroup ? isChecked : !!model\"\r\n :value=\"label\"\r\n :true-value=\"trueLabel\"\r\n :false-value=\"falseLabel\"\r\n class=\"rc-checkbox__original\"\r\n :name=\"name\"\r\n :disabled=\"isDisabled\"\r\n type=\"checkbox\"\r\n @change=\"handleChange\"\r\n @focus=\"handleFocus\"\r\n @blur=\"handleBlur\"\r\n />\r\n </span>\r\n <span class=\"rc-checkbox__label\">\r\n <slot>\r\n <template v-if=\"label !== undefined && typeof label !== 'boolean'\">{{ label }}</template>\r\n </slot>\r\n </span>\r\n </label>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, inject, ref, watch, unref } from 'vue';\r\nimport RcIcon from '../icon/index.vue';\r\n\r\ndefineOptions({ name: 'rc-checkbox' });\r\n\r\ninterface CheckboxGroupContext {\r\n modelValue: (string | number | boolean)[];\r\n changeEvent: (value: (string | number | boolean)[]) => void;\r\n size?: 'large' | 'default' | 'small';\r\n disabled?: boolean;\r\n name?: string;\r\n fill?: string;\r\n textColor?: string;\r\n min?: number;\r\n max?: number;\r\n}\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 绑定值,使用 CheckboxGroup 时不需要单独设置 */\r\n modelValue?: string | number | boolean;\r\n /** Checkbox 的 value */\r\n label?: string | number | boolean;\r\n /** 是否禁用 */\r\n disabled?: boolean;\r\n /** 是否显示边框 */\r\n border?: boolean;\r\n /** Checkbox 的尺寸,仅在 border 为真时有效 */\r\n size?: 'large' | 'default' | 'small';\r\n /** 原生 name 属性 */\r\n name?: string;\r\n /** 设置 indeterminate 状态,只负责样式控制 */\r\n indeterminate?: boolean;\r\n /** 是否默认选中 */\r\n checked?: boolean;\r\n /** 选中时的值 */\r\n trueLabel?: string | number;\r\n /** 没有选中时的值 */\r\n falseLabel?: string | number;\r\n}>(), {\r\n modelValue: undefined,\r\n label: undefined,\r\n disabled: false,\r\n border: false,\r\n size: 'default',\r\n name: undefined,\r\n indeterminate: false,\r\n checked: false,\r\n trueLabel: undefined,\r\n falseLabel: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: string | number | boolean): void;\r\n (e: 'change', value: string | number | boolean): void;\r\n (e: 'focus', event: FocusEvent): void;\r\n (e: 'blur', event: FocusEvent): void;\r\n}>();\r\n\r\nconst checkboxRef = ref<HTMLInputElement>();\r\nconst checkboxGroup = inject<CheckboxGroupContext | undefined>('CheckboxGroup', undefined);\r\n\r\n// 是否在 CheckboxGroup 中\r\nconst isGroup = computed(() => !!checkboxGroup);\r\n\r\n// 获取 CheckboxGroup 的实际值(处理 computed ref)\r\nconst getGroupValue = () => {\r\n if (!checkboxGroup) return [];\r\n // 使用 unref 来获取 computed ref 的值\r\n const rawValue = unref(checkboxGroup.modelValue);\r\n return Array.isArray(rawValue) ? rawValue : [];\r\n};\r\n\r\n// 当前值(优先使用 CheckboxGroup 的值)\r\nconst model = computed({\r\n get() {\r\n if (isGroup.value) {\r\n const groupValue = getGroupValue();\r\n return groupValue.includes(props.label!);\r\n } else {\r\n return props.modelValue ?? props.checked;\r\n }\r\n },\r\n set(val: boolean) {\r\n if (isGroup.value) {\r\n const groupValue = [...getGroupValue()];\r\n if (val) {\r\n if (!groupValue.includes(props.label!)) {\r\n groupValue.push(props.label!);\r\n }\r\n } else {\r\n const index = groupValue.indexOf(props.label!);\r\n if (index > -1) {\r\n groupValue.splice(index, 1);\r\n }\r\n }\r\n checkboxGroup!.changeEvent(groupValue);\r\n } else {\r\n const actualValue = val ? (props.trueLabel ?? true) : (props.falseLabel ?? false);\r\n emit('update:modelValue', actualValue);\r\n }\r\n },\r\n});\r\n\r\n// 是否选中\r\nconst isChecked = computed(() => {\r\n if (isGroup.value) {\r\n const groupValue = getGroupValue();\r\n return groupValue.includes(props.label!);\r\n } else {\r\n if (props.trueLabel !== undefined || props.falseLabel !== undefined) {\r\n return props.modelValue === props.trueLabel;\r\n } else {\r\n return !!props.modelValue || props.checked;\r\n }\r\n }\r\n});\r\n\r\n// 是否禁用(优先使用 CheckboxGroup 的设置)\r\nconst isDisabled = computed(() => {\r\n if (props.disabled || checkboxGroup?.disabled) {\r\n return true;\r\n }\r\n // 检查 min/max 限制\r\n if (isGroup.value && checkboxGroup) {\r\n const groupValue = getGroupValue();\r\n if (isChecked.value) {\r\n // 已选中,检查是否达到最小值\r\n if (checkboxGroup.min !== undefined && groupValue.length <= checkboxGroup.min) {\r\n return true;\r\n }\r\n } else {\r\n // 未选中,检查是否达到最大值\r\n if (checkboxGroup.max !== undefined && groupValue.length >= checkboxGroup.max) {\r\n return true;\r\n }\r\n }\r\n }\r\n return false;\r\n});\r\n\r\n// 注入 formItem 的验证方法\r\ninterface FormItemContext {\r\n onBlur?: () => void;\r\n onChange?: () => void;\r\n}\r\nconst formItemContext = inject<FormItemContext | undefined>('rcFormItem', undefined);\r\n\r\nconst handleChange = (event: Event) => {\r\n const target = event.target as HTMLInputElement;\r\n if (isGroup.value) {\r\n // 在 CheckboxGroup 中,手动更新值\r\n const groupValue = [...getGroupValue()];\r\n if (target.checked) {\r\n if (!groupValue.includes(props.label!)) {\r\n groupValue.push(props.label!);\r\n }\r\n } else {\r\n const index = groupValue.indexOf(props.label!);\r\n if (index > -1) {\r\n groupValue.splice(index, 1);\r\n }\r\n }\r\n checkboxGroup!.changeEvent(groupValue);\r\n emit('change', props.label!);\r\n formItemContext?.onChange?.();\r\n } else {\r\n // 单独使用时,手动更新值\r\n const actualValue = target.checked ? (props.trueLabel ?? true) : (props.falseLabel ?? false);\r\n emit('update:modelValue', actualValue);\r\n emit('change', actualValue);\r\n formItemContext?.onChange?.();\r\n }\r\n};\r\n\r\nconst handleFocus = (event: FocusEvent) => {\r\n emit('focus', event);\r\n};\r\n\r\nconst handleBlur = (event: FocusEvent) => {\r\n emit('blur', event);\r\n formItemContext?.onBlur?.();\r\n};\r\n\r\ndefineExpose({\r\n checkboxRef,\r\n focus: () => {\r\n checkboxRef.value?.focus();\r\n },\r\n blur: () => {\r\n checkboxRef.value?.blur();\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-checkbox {\r\n color: var(--rc-text, #333333);\r\n font-weight: 500;\r\n cursor: pointer;\r\n display: inline-flex;\r\n align-items: center;\r\n white-space: nowrap;\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n height: 32px;\r\n margin-right: 30px;\r\n\r\n &:last-child {\r\n margin-right: 0;\r\n }\r\n\r\n &:hover:not(.is-disabled) {\r\n .rc-checkbox__inner {\r\n border-color: var(--rc-primary, #1d85fc);\r\n }\r\n }\r\n\r\n &.is-disabled {\r\n cursor: not-allowed;\r\n color: var(--rc-disabled, #c0c4cc);\r\n\r\n .rc-checkbox__input {\r\n cursor: not-allowed;\r\n }\r\n\r\n .rc-checkbox__inner {\r\n background-color: var(--rc-bg, #f5f7fa);\r\n border-color: var(--rc-border, #e4e7ed);\r\n cursor: not-allowed;\r\n\r\n &::after {\r\n cursor: not-allowed;\r\n border-color: var(--rc-disabled, #c0c4cc);\r\n }\r\n }\r\n }\r\n\r\n &.is-checked {\r\n .rc-checkbox__inner {\r\n background-color: var(--rc-primary, #1d85fc);\r\n border-color: var(--rc-primary, #1d85fc);\r\n\r\n &::after {\r\n transform: translate(-50%, -50%) rotate(45deg) scaleY(1);\r\n }\r\n }\r\n\r\n .rc-checkbox__label {\r\n color: var(--rc-primary, #1d85fc);\r\n }\r\n }\r\n\r\n &.is-indeterminate {\r\n .rc-checkbox__inner {\r\n background-color: var(--rc-primary, #1d85fc);\r\n border-color: var(--rc-primary, #1d85fc);\r\n\r\n &::before {\r\n content: \"\";\r\n position: absolute;\r\n display: block;\r\n background-color: var(--rc-white, #ffffff);\r\n height: 2px;\r\n transform: scale(0.5);\r\n left: 0;\r\n right: 0;\r\n top: 50%;\r\n transform: translateY(-50%) scale(0.5);\r\n }\r\n\r\n &::after {\r\n display: none;\r\n }\r\n }\r\n }\r\n\r\n &.is-border {\r\n padding: 12px 20px 12px 10px;\r\n border-radius: 4px;\r\n border: 1px solid var(--rc-border, #dcdfe6);\r\n box-sizing: border-box;\r\n height: auto;\r\n margin-right: 0;\r\n margin-bottom: 0;\r\n\r\n &.is-checked {\r\n border-color: var(--rc-primary, #1d85fc);\r\n }\r\n\r\n &.is-disabled {\r\n background-color: var(--rc-bg, #f5f7fa);\r\n border-color: var(--rc-border, #e4e7ed);\r\n cursor: not-allowed;\r\n color: var(--rc-disabled, #c0c4cc);\r\n }\r\n\r\n &.rc-checkbox--large {\r\n padding: 14px 20px 14px 10px;\r\n font-size: 14px;\r\n\r\n .rc-checkbox__inner {\r\n width: 20px;\r\n height: 20px;\r\n }\r\n }\r\n\r\n &.rc-checkbox--small {\r\n padding: 8px 15px 8px 10px;\r\n font-size: 12px;\r\n\r\n .rc-checkbox__inner {\r\n width: 18px;\r\n height: 18px;\r\n }\r\n }\r\n }\r\n}\r\n\r\n.rc-checkbox__input {\r\n white-space: nowrap;\r\n cursor: pointer;\r\n outline: none;\r\n display: inline-flex;\r\n position: relative;\r\n vertical-align: middle;\r\n\r\n &.is-checked {\r\n .rc-checkbox__inner {\r\n background-color: var(--rc-primary, #1d85fc);\r\n border-color: var(--rc-primary, #1d85fc);\r\n }\r\n }\r\n\r\n &.is-indeterminate {\r\n .rc-checkbox__inner {\r\n background-color: var(--rc-primary, #1d85fc);\r\n border-color: var(--rc-primary, #1d85fc);\r\n\r\n &::before {\r\n content: \"\";\r\n position: absolute;\r\n display: block;\r\n background-color: var(--rc-white, #ffffff);\r\n height: 2px;\r\n left: 0;\r\n right: 0;\r\n top: 50%;\r\n transform: translateY(-50%) scale(0.5);\r\n }\r\n\r\n .rc-checkbox__icon {\r\n display: none;\r\n }\r\n }\r\n }\r\n\r\n &.is-disabled {\r\n .rc-checkbox__inner {\r\n background-color: var(--rc-bg, #f5f7fa);\r\n border-color: var(--rc-border, #e4e7ed);\r\n cursor: not-allowed;\r\n\r\n .rc-checkbox__icon {\r\n color: var(--rc-disabled, #c0c4cc);\r\n }\r\n }\r\n }\r\n}\r\n\r\n.rc-checkbox__inner {\r\n display: inline-block;\r\n position: relative;\r\n border: 1px solid var(--rc-border, #dcdfe6);\r\n border-radius: 4px;\r\n box-sizing: border-box;\r\n width: 18px;\r\n height: 18px;\r\n background-color: var(--rc-white, #ffffff);\r\n z-index: 1;\r\n transition: border-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46), background-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46);\r\n\r\n &:hover {\r\n border-color: var(--rc-primary, #1d85fc);\r\n }\r\n\r\n}\r\n\r\n.rc-checkbox__icon {\r\n position: absolute;\r\n left: 50%;\r\n top: 50%;\r\n transform: translate(-50%, -50%);\r\n color: var(--rc-white, #ffffff) !important;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n transition: opacity 0.15s ease-in 0.05s, transform 0.15s ease-in 0.05s;\r\n opacity: 0;\r\n transform: translate(-50%, -50%) scale(0);\r\n pointer-events: none;\r\n}\r\n\r\n.rc-checkbox__input.is-checked .rc-checkbox__icon {\r\n opacity: 1;\r\n transform: translate(-50%, -50%) scale(1);\r\n}\r\n\r\n.rc-checkbox__input.is-disabled .rc-checkbox__icon {\r\n color: var(--rc-disabled, #c0c4cc) !important;\r\n}\r\n\r\n.rc-checkbox__original {\r\n opacity: 0;\r\n outline: none;\r\n position: absolute;\r\n margin: 0;\r\n width: 0;\r\n height: 0;\r\n z-index: -1;\r\n}\r\n\r\n.rc-checkbox__label {\r\n font-size: 14px;\r\n padding-left: 8px;\r\n line-height: 1;\r\n}\r\n</style>\r\n","<template>\r\n <div class=\"rc-checkbox-group\" :class=\"[{ 'is-disabled': disabled }]\">\r\n <slot />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { provide, computed, watch, inject, type ComputedRef } from 'vue';\r\n\r\ndefineOptions({ name: 'rc-checkbox-group' });\r\n\r\nexport interface CheckboxGroupContext {\r\n modelValue: ComputedRef<(string | number | boolean)[]>;\r\n changeEvent: (value: (string | number | boolean)[]) => void;\r\n size?: 'large' | 'default' | 'small';\r\n disabled?: boolean;\r\n name?: string;\r\n fill?: string;\r\n textColor?: string;\r\n min?: number;\r\n max?: number;\r\n}\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 绑定值 */\r\n modelValue?: (string | number | boolean)[];\r\n /** Checkbox 按钮组尺寸,仅对按钮样式的 Checkbox 有效 */\r\n size?: 'large' | 'default' | 'small';\r\n /** 是否禁用 */\r\n disabled?: boolean;\r\n /** 按钮形式的 Checkbox 激活时的文本颜色 */\r\n textColor?: string;\r\n /** 按钮形式的 Checkbox 激活时的填充色和边框色 */\r\n fill?: string;\r\n /** 原生 name 属性 */\r\n name?: string;\r\n /** 可被勾选的 checkbox 的最小数量 */\r\n min?: number;\r\n /** 可被勾选的 checkbox 的最大数量 */\r\n max?: number;\r\n}>(), {\r\n modelValue: () => [],\r\n size: 'default',\r\n disabled: false,\r\n textColor: undefined,\r\n fill: undefined,\r\n name: undefined,\r\n min: undefined,\r\n max: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: (string | number | boolean)[]): void;\r\n (e: 'change', value: (string | number | boolean)[]): void;\r\n}>();\r\n\r\nconst changeEvent = (value: (string | number | boolean)[]) => {\r\n emit('update:modelValue', value);\r\n emit('change', value);\r\n};\r\n\r\n// 注入 formItem 的验证方法\r\ninterface FormItemContext {\r\n onChange?: () => void;\r\n}\r\nconst formItemContext = inject<FormItemContext | undefined>('rcFormItem', undefined);\r\n\r\nwatch(() => props.modelValue, () => {\r\n formItemContext?.onChange?.();\r\n});\r\n\r\nprovide<CheckboxGroupContext>('CheckboxGroup', {\r\n modelValue: computed(() => props.modelValue || []),\r\n changeEvent,\r\n size: props.size,\r\n disabled: props.disabled,\r\n name: props.name,\r\n fill: props.fill,\r\n textColor: props.textColor,\r\n min: props.min,\r\n max: props.max,\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-checkbox-group {\r\n display: inline-flex;\r\n flex-wrap: wrap;\r\n font-size: 0;\r\n\r\n &.is-disabled {\r\n cursor: not-allowed;\r\n }\r\n}\r\n</style>\r\n","<template>\r\n <label\r\n class=\"rc-checkbox-button\"\r\n :class=\"[\r\n {\r\n 'is-checked': isChecked,\r\n 'is-disabled': isDisabled,\r\n 'is-focus': focused,\r\n [`rc-checkbox-button--${actualSize}`]: actualSize,\r\n }\r\n ]\"\r\n :style=\"buttonStyle\"\r\n >\r\n <input\r\n ref=\"checkboxRef\"\r\n :checked=\"isGroup ? isChecked : !!model\"\r\n :value=\"label\"\r\n class=\"rc-checkbox-button__original\"\r\n :name=\"name\"\r\n :disabled=\"isDisabled\"\r\n type=\"checkbox\"\r\n @change=\"handleChange\"\r\n @focus=\"handleFocus\"\r\n @blur=\"handleBlur\"\r\n />\r\n <span class=\"rc-checkbox-button__inner\">\r\n <slot>\r\n <template v-if=\"label !== undefined && typeof label !== 'boolean'\">{{ label }}</template>\r\n </slot>\r\n </span>\r\n </label>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, inject, ref, unref } from 'vue';\r\nimport type { CheckboxGroupContext } from './group.vue';\r\n\r\ndefineOptions({ name: 'rc-checkbox-button' });\r\n\r\nconst props = withDefaults(defineProps<{\r\n /** 绑定值,使用 CheckboxGroup 时不需要单独设置 */\r\n modelValue?: string | number | boolean;\r\n /** Checkbox 的 value */\r\n label?: string | number | boolean;\r\n /** 是否禁用 */\r\n disabled?: boolean;\r\n /** 原生 name 属性 */\r\n name?: string;\r\n /** 是否默认选中 */\r\n checked?: boolean;\r\n /** 选中时的值 */\r\n trueLabel?: string | number;\r\n /** 没有选中时的值 */\r\n falseLabel?: string | number;\r\n}>(), {\r\n modelValue: undefined,\r\n label: undefined,\r\n disabled: false,\r\n name: undefined,\r\n checked: false,\r\n trueLabel: undefined,\r\n falseLabel: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: string | number | boolean): void;\r\n (e: 'change', value: string | number | boolean): void;\r\n (e: 'focus', event: FocusEvent): void;\r\n (e: 'blur', event: FocusEvent): void;\r\n}>();\r\n\r\nconst checkboxRef = ref<HTMLInputElement>();\r\nconst focused = ref(false);\r\nconst checkboxGroup = inject<CheckboxGroupContext | undefined>('CheckboxGroup', undefined);\r\n\r\n// 是否在 CheckboxGroup 中\r\nconst isGroup = computed(() => !!checkboxGroup);\r\n\r\n// 获取 CheckboxGroup 的实际值(处理 computed ref)\r\nconst getGroupValue = () => {\r\n if (!checkboxGroup) return [];\r\n // 使用 unref 来获取 computed ref 的值\r\n const rawValue = unref(checkboxGroup.modelValue);\r\n return Array.isArray(rawValue) ? rawValue : [];\r\n};\r\n\r\n// 当前值(优先使用 CheckboxGroup 的值)\r\nconst model = computed({\r\n get() {\r\n if (isGroup.value) {\r\n const groupValue = getGroupValue();\r\n return groupValue.includes(props.label!);\r\n } else {\r\n if (props.trueLabel !== undefined || props.falseLabel !== undefined) {\r\n return props.modelValue === props.trueLabel;\r\n } else {\r\n return !!props.modelValue || props.checked;\r\n }\r\n }\r\n },\r\n set(val: boolean) {\r\n if (isGroup.value) {\r\n const groupValue = [...getGroupValue()];\r\n if (val) {\r\n if (!groupValue.includes(props.label!)) {\r\n groupValue.push(props.label!);\r\n }\r\n } else {\r\n const index = groupValue.indexOf(props.label!);\r\n if (index > -1) {\r\n groupValue.splice(index, 1);\r\n }\r\n }\r\n checkboxGroup!.changeEvent(groupValue);\r\n } else {\r\n const actualValue = val ? (props.trueLabel ?? true) : (props.falseLabel ?? false);\r\n emit('update:modelValue', actualValue);\r\n }\r\n },\r\n});\r\n\r\n// 是否选中\r\nconst isChecked = computed(() => {\r\n if (isGroup.value) {\r\n const groupValue = getGroupValue();\r\n return groupValue.includes(props.label!);\r\n } else {\r\n if (props.trueLabel !== undefined || props.falseLabel !== undefined) {\r\n return props.modelValue === props.trueLabel;\r\n } else {\r\n return !!props.modelValue || props.checked;\r\n }\r\n }\r\n});\r\n\r\n// 是否禁用(优先使用 CheckboxGroup 的设置)\r\nconst isDisabled = computed(() => {\r\n if (props.disabled || checkboxGroup?.disabled) {\r\n return true;\r\n }\r\n // 检查 min/max 限制\r\n if (isGroup.value && checkboxGroup) {\r\n const groupValue = getGroupValue();\r\n if (isChecked.value) {\r\n // 已选中,检查是否达到最小值\r\n if (checkboxGroup.min !== undefined && groupValue.length <= checkboxGroup.min) {\r\n return true;\r\n }\r\n } else {\r\n // 未选中,检查是否达到最大值\r\n if (checkboxGroup.max !== undefined && groupValue.length >= checkboxGroup.max) {\r\n return true;\r\n }\r\n }\r\n }\r\n return false;\r\n});\r\n\r\n// 实际尺寸(优先使用 CheckboxGroup 的设置)\r\nconst actualSize = computed(() => {\r\n return checkboxGroup?.size || 'default';\r\n});\r\n\r\n// 按钮样式(使用 CheckboxGroup 的颜色配置)\r\nconst buttonStyle = computed(() => {\r\n if (!isChecked.value || !checkboxGroup) {\r\n return {};\r\n }\r\n const style: Record<string, string> = {};\r\n if (checkboxGroup.fill) {\r\n style.backgroundColor = checkboxGroup.fill;\r\n style.borderColor = checkboxGroup.fill;\r\n }\r\n if (checkboxGroup.textColor) {\r\n style.color = checkboxGroup.textColor;\r\n }\r\n return style;\r\n});\r\n\r\n// 注入 formItem 的验证方法\r\ninterface FormItemContext {\r\n onBlur?: () => void;\r\n onChange?: () => void;\r\n}\r\nconst formItemContext = inject<FormItemContext | undefined>('rcFormItem', undefined);\r\n\r\nconst handleChange = (event: Event) => {\r\n const target = event.target as HTMLInputElement;\r\n if (isGroup.value) {\r\n // 在 CheckboxGroup 中,手动更新值\r\n const groupValue = [...getGroupValue()];\r\n if (target.checked) {\r\n if (!groupValue.includes(props.label!)) {\r\n groupValue.push(props.label!);\r\n }\r\n } else {\r\n const index = groupValue.indexOf(props.label!);\r\n if (index > -1) {\r\n groupValue.splice(index, 1);\r\n }\r\n }\r\n checkboxGroup!.changeEvent(groupValue);\r\n emit('change', props.label!);\r\n formItemContext?.onChange?.();\r\n } else {\r\n // 单独使用时,手动更新值\r\n const actualValue = target.checked ? (props.trueLabel ?? true) : (props.falseLabel ?? false);\r\n emit('update:modelValue', actualValue);\r\n emit('change', actualValue);\r\n formItemContext?.onChange?.();\r\n }\r\n};\r\n\r\nconst handleFocus = (event: FocusEvent) => {\r\n focused.value = true;\r\n emit('focus', event);\r\n};\r\n\r\nconst handleBlur = (event: FocusEvent) => {\r\n focused.value = false;\r\n emit('blur', event);\r\n formItemContext?.onBlur?.();\r\n};\r\n\r\ndefineExpose({\r\n checkboxRef,\r\n focus: () => {\r\n checkboxRef.value?.focus();\r\n },\r\n blur: () => {\r\n checkboxRef.value?.blur();\r\n },\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.rc-checkbox-button {\r\n position: relative;\r\n display: inline-block;\r\n outline: none;\r\n cursor: pointer;\r\n user-select: none;\r\n vertical-align: middle;\r\n\r\n &__original {\r\n opacity: 0;\r\n outline: none;\r\n position: absolute;\r\n z-index: -1;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n margin: 0;\r\n }\r\n\r\n &__inner {\r\n display: inline-block;\r\n line-height: 1;\r\n white-space: nowrap;\r\n vertical-align: middle;\r\n background: var(--rc-white, #ffffff);\r\n border: 1px solid var(--rc-border, #dcdfe6);\r\n font-weight: 500;\r\n border-left: 0;\r\n color: var(--rc-text, #606266);\r\n text-align: center;\r\n box-sizing: border-box;\r\n margin: 0;\r\n padding: 12px 20px;\r\n font-size: 14px;\r\n border-radius: 0;\r\n transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);\r\n cursor: pointer;\r\n }\r\n\r\n &:first-child {\r\n .rc-checkbox-button__inner {\r\n border-left: 1px solid var(--rc-border, #dcdfe6);\r\n border-radius: 4px 0 0 4px;\r\n box-shadow: none !important;\r\n }\r\n }\r\n\r\n &:last-child {\r\n .rc-checkbox-button__inner {\r\n border-radius: 0 4px 4px 0;\r\n }\r\n }\r\n\r\n &:first-child:last-child {\r\n .rc-checkbox-button__inner {\r\n border-radius: 4px;\r\n }\r\n }\r\n\r\n &:hover:not(.is-disabled):not(.is-checked) {\r\n .rc-checkbox-button__inner {\r\n color: var(--rc-primary, #1d85fc);\r\n border-color: var(--rc-border, #dcdfe6);\r\n }\r\n }\r\n\r\n &.is-checked {\r\n .rc-checkbox-button__inner {\r\n color: var(--rc-white, #ffffff);\r\n background-color: var(--rc-primary, #1d85fc);\r\n border-color: var(--rc-primary, #1d85fc);\r\n box-shadow: -1px 0 0 0 var(--rc-white, #ffffff);\r\n }\r\n\r\n &:first-child {\r\n .rc-checkbox-button__inner {\r\n border-left-color: var(--rc-primary, #1d85fc);\r\n box-shadow: none;\r\n }\r\n }\r\n }\r\n\r\n &.is-disabled {\r\n cursor: not-allowed;\r\n\r\n .rc-checkbox-button__inner {\r\n color: var(--rc-disabled, #c0c4cc);\r\n cursor: not-allowed;\r\n background-image: none;\r\n background-color: var(--rc-white, #ffffff);\r\n border-color: var(--rc-border, #e4e7ed);\r\n box-shadow: none;\r\n }\r\n\r\n &:first-child {\r\n .rc-checkbox-button__inner {\r\n border-left-color: var(--rc-border, #e4e7ed);\r\n }\r\n }\r\n }\r\n\r\n &.is-focus {\r\n .rc-checkbox-button__inner {\r\n border-color: var(--rc-primary, #1d85fc);\r\n }\r\n }\r\n\r\n &--large {\r\n .rc-checkbox-button__inner {\r\n padding: 14px 20px;\r\n font-size: 14px;\r\n border-radius: 0;\r\n }\r\n\r\n &:first-child {\r\n .rc-checkbox-button__inner {\r\n border-radius: 4px 0 0 4px;\r\n }\r\n }\r\n\r\n &:last-child {\r\n .rc-checkbox-button__inner {\r\n border-radius: 0 4px 4px 0;\r\n }\r\n }\r\n }\r\n\r\n &--small {\r\n .rc-checkbox-button__inner {\r\n padding: 8px 15px;\r\n font-size: 12px;\r\n border-radius: 0;\r\n }\r\n\r\n &:first-child {\r\n .rc-checkbox-button__inner {\r\n border-radius: 3px 0 0 3px;\r\n }\r\n }\r\n\r\n &:last-child {\r\n .rc-checkbox-button__inner {\r\n border-radius: 0 3px 3px 0;\r\n }\r\n }\r\n }\r\n}\r\n\r\n.rc-checkbox-group {\r\n .rc-checkbox-button {\r\n &:not(:first-child) {\r\n margin-left: -1px;\r\n }\r\n }\r\n}\r\n</style>\r\n","import type { App } from 'vue';\r\nimport Checkbox from './index.vue';\r\nimport CheckboxGroup from './group.vue';\r\nimport CheckboxButton from './button.vue';\r\n\r\n(Checkbox as any).name = 'rc-checkbox';\r\n(CheckboxGroup as any).name = 'rc-checkbox-group';\r\n(CheckboxButton as any).name = 'rc-checkbox-button';\r\n\r\nexport function install(app: App) {\r\n app.component((Checkbox as any).name, Checkbox);\r\n app.component('RcCheckbox', Checkbox);\r\n app.component((CheckboxGroup as any).name, CheckboxGroup);\r\n app.component('RcCheckboxGroup', CheckboxGroup);\r\n app.component((CheckboxButton as any).name, CheckboxButton);\r\n app.component('RcCheckboxButton', CheckboxButton);\r\n return app;\r\n}\r\n\r\nexport { CheckboxGroup, CheckboxButton };\r\nexport default Checkbox;\r\n","// library entry\r\nimport type { App, Plugin } from 'vue';\r\nimport { install as installButton } from './components/button';\r\nimport { install as installDescriptions } from './components/descriptions';\r\nimport { install as installCard } from './components/card';\r\nimport { install as installToast } from './components/toast';\r\nimport { install as installMessage } from './components/message';\r\nimport { install as installIcon } from './components/icon/index';\r\nimport { install as installSearchArea } from './components/search-area';\r\nimport { install as installCalendar } from './components/calendar';\r\nimport { install as installPopup } from './components/popup';\r\nimport { install as installInput } from './components/input';\r\nimport { install as installDropdown } from './components/dropdown';\r\nimport { install as installForm } from './components/form';\r\nimport { install as installRadio } from './components/radio';\r\nimport { install as installCheckbox } from './components/checkbox';\r\nimport type { RecycleUIOptions } from './types';\r\n\r\nexport const RECYCLE_UI_SYMBOL = Symbol('RECYCLE_UI_CONFIG');\r\n\r\nexport const defaultRecycleUIConfig: RecycleUIOptions = {\r\n prefix: 'rc',\r\n autoRegister: true,\r\n provideKey: RECYCLE_UI_SYMBOL,\r\n // 预留主题/其他全局配置\r\n theme: {},\r\n // IconFont 默认配置(可在 app.use 时覆盖)\r\n iconCssUrl: '//at.alicdn.com/t/c/font_4252799_2vm5jrrzfvq.css',\r\n iconClass: 'iconfont',\r\n // 输入框设备类型默认配置\r\n inputDeviceType: 'pc',\r\n};\r\n\r\n// 统一导出所有类型的命名空间\r\nexport namespace RecycleUiTypes {\r\n // 核心配置类型\r\n export type Options = RecycleUIOptions;\r\n export type DefaultConfig = typeof defaultRecycleUIConfig;\r\n \r\n // Message 相关类型\r\n export type MessageOptions = import('./components/message').MessageOptions;\r\n export type MessageType = import('./components/message/index.vue').MessageType;\r\n export type MessageItem = import('./components/message/index.vue').MessageItem;\r\n \r\n // Toast 相关类型\r\n export type ToastProps = import('./components/toast/index.vue').ToastProps;\r\n export type ToastType = import('./components/toast/index.vue').ToastType;\r\n export type ShowToastOptions = import('./components/toast').ShowToastOptions;\r\n}\r\n\r\nfunction doAutoRegister(app: App, opts: RecycleUIOptions) {\r\n if (opts.autoRegister === false) return;\r\n if (typeof installButton === 'function') installButton(app);\r\n if (typeof installDescriptions === 'function') installDescriptions(app);\r\n if (typeof installCard === 'function') installCard(app);\r\n if (typeof installToast === 'function') installToast(app);\r\n if (typeof installIcon === 'function') installIcon(app);\r\n if (typeof installMessage === 'function') installMessage(app);\r\n if (typeof installSearchArea === 'function') installSearchArea(app);\r\n if (typeof installCalendar === 'function') installCalendar(app);\r\n if (typeof installPopup === 'function') installPopup(app);\r\n if (typeof installInput === 'function') installInput(app);\r\n if (typeof installDropdown === 'function') installDropdown(app);\r\n if (typeof installForm === 'function') installForm(app);\r\n if (typeof installRadio === 'function') installRadio(app);\r\n if (typeof installCheckbox === 'function') installCheckbox(app);\r\n}\r\n\r\nexport const install = (app: App, options?: RecycleUIOptions) => {\r\n const cfg: RecycleUIOptions = { ...defaultRecycleUIConfig, ...(options || {}) };\r\n // 提供全局配置\r\n app.provide(cfg.provideKey ?? RECYCLE_UI_SYMBOL, cfg);\r\n // 供模板/实例访问:this.$recycleUI\r\n (app.config.globalProperties as any).$recycleUI = cfg;\r\n // 注入 IconFont 样式链接(浏览器环境)\r\n if (typeof window !== 'undefined' && cfg.iconCssUrl) {\r\n const selector = `link[rel=\"stylesheet\"][data-rcui-icon=\"true\"][href=\"${cfg.iconCssUrl}\"]`;\r\n const exists = document.head.querySelector(selector);\r\n if (!exists) {\r\n const link = document.createElement('link');\r\n link.rel = 'stylesheet';\r\n link.href = cfg.iconCssUrl;\r\n link.setAttribute('data-rcui-icon', 'true');\r\n document.head.appendChild(link);\r\n }\r\n }\r\n // 自动注册内置组件(可通过 autoRegister 关闭)\r\n doAutoRegister(app, cfg);\r\n return app;\r\n};\r\n\r\n// 默认导出为插件,支持 app.use(recycleUi, options)\r\nconst plugin: Plugin = { install };\r\nexport default plugin;\r\n\r\n// 也导出命名组件安装器与默认配置(defaultRecycleUIConfig 已在上方以常量形式导出)\r\n\r\n// 可选:工厂方法,便于创建带预设配置的插件\r\nexport function createRecycleUI(options?: RecycleUIOptions): Plugin {\r\n return {\r\n install(app: App) {\r\n install(app, options);\r\n },\r\n };\r\n}\r\n\r\n// 按需导出组件与其安装器(供文档与业务直接使用)\r\nexport { default as RcButton } from './components/button';\r\nexport { RcDescriptions, RcDescriptionsItem } from './components/descriptions';\r\nexport { install as installButton } from './components/button';\r\nexport { install as installDescriptions } from './components/descriptions';\r\nexport { default as RcCard } from './components/card';\r\nexport { install as installCard } from './components/card';\r\n// 兼容别名导出(文档示例中的 rcXxx)\r\nexport { RcDescriptions as rcDescriptions, RcDescriptionsItem as rcDescriptionsItem } from './components/descriptions';\r\n// Toast 服务导出\r\nexport { default as RcToast, showToast, hideToast } from './components/toast';\r\n// Icon 组件导出\r\nexport { default as RcIcon } from './components/icon/index';\r\nexport { install as installIcon } from './components/icon/index';\r\n// Message 服务(对标 antd 的 message)\r\nexport { default as message } from './components/message';\r\nexport { install as installMessage } from './components/message';\r\n// SearchArea 组件导出\r\nexport { default as RcSearchArea } from './components/search-area';\r\nexport { install as installSearchArea } from './components/search-area';\r\nexport type { FilterItem, FilterOption } from './components/search-area';\r\n// Calendar 组件导出\r\nexport { default as RcCalendar } from './components/calendar';\r\nexport { install as installCalendar } from './components/calendar';\r\n// Popup 组件导出\r\nexport { default as RcPopup } from './components/popup';\r\nexport { install as installPopup } from './components/popup';\r\n// Input 组件导出\r\nexport { default as RcInput } from './components/input';\r\nexport { install as installInput } from './components/input';\r\n// Dropdown 组件导出\r\nexport { default as RcDropdown, DropdownMenu as RcDropdownMenu, DropdownItem as RcDropdownItem } from './components/dropdown';\r\nexport { install as installDropdown } from './components/dropdown';\r\nexport type { DropdownPlacement } from './components/dropdown/types';\r\n// Form 组件导出\r\nexport { default as RcForm, FormItem as RcFormItem } from './components/form';\r\nexport { install as installForm } from './components/form';\r\nexport type { FormRules, FormRule, ValidateCallback, ValidateFieldCallback } from './components/form';\r\n// Radio 组件导出\r\nexport { default as RcRadio, RadioGroup as RcRadioGroup, RadioButton as RcRadioButton } from './components/radio';\r\nexport { install as installRadio } from './components/radio';\r\n// Checkbox 组件导出\r\nexport { default as RcCheckbox, CheckboxGroup as RcCheckboxGroup, CheckboxButton as RcCheckboxButton } from './components/checkbox';\r\nexport { install as installCheckbox } from './components/checkbox';\r\n"],"names":["props","__props","cfg","inject","RECYCLE_UI_SYMBOL","baseClass","computed","iconClassName","sizeCss","iconStyle","char","c","hex","num","onMounted","url","defaultRecycleUIConfig","selector","link","_createElementBlock","_hoisted_1","_toDisplayString","emit","__emit","formContext","actualButtonType","onClick","ev","radius","v","computedWidth","str","_normalizeClass","_normalizeStyle","_openBlock","_hoisted_2","_Fragment","$slots","_hoisted_3","_renderSlot","_ctx","_createBlock","RcIcon","_hoisted_4","Button","install","app","providedGapPx","providedColCount","providedLabelWidth","providedLabelPosition","labelPosition","spanNum","n","max","safe","gapPx","totalGap","interGap","labelStyle","injected","w","_createElementVNode","wrapEl","ref","gapStyle","colCount","itemWidth","singleWidth","watchEffect","base","provide","labelWidthCss","normalizedData","keyK","_a","keyV","_b","_c","it","_renderList","idx","rcDescriptionsItem","Descriptions","DescriptionsItem","RcDescriptions","RcDescriptionsItem","wrapperStyle","shadowByLevel","toCssSize","bodyPadding","bodyGap","level","_hoisted_5","Card","PascalName","Icon","visible","timer","clearTimer","close","__expose","onUnmounted","_Teleport","_createVNode","_Transition","_unref","host","unmount","showToast","options","opt","toastProps","createApp","Toast","hideToast","messages","reactive","uid","remove","id","x","add","type","content","duration","_TransitionGroup","m","container","hostExposed","ensureHost","vnode","createVNode","MessageHost","render","open","d","message","opts","popupRef","scrollLocked","lockBodyScroll","unlockBodyScroll","watch","val","transitionName","popupStyle","handleOverlayClick","handleClose","Popup","itemHeight","itemsPerRow","visibleRows","weekdays","parseDate","dateStr","date","formatDate","year","month","day","currentDate","isToday","today","isInRange","start","end","isDisabled","getMonthDays","firstDay","lastDay","firstDayWeek","daysInMonth","days","prevMonthLastDay","i","dayItem","formatted","remaining","monthDays","monthTitle","getDayClass","classes","isRangeComplete","selectedRangeCount","isYearDisabled","min","isMonthDisabled","minYear","minMonth","maxYear","maxMonth","showMonthPicker","pickerMode","tempYear","tempMonth","yearScrollRef","visibleYearStart","visibleYearEnd","dynamicMinYear","dynamicMaxYear","visibleYearList","years","startRow","endRow","handleYearScroll","scrollTop","newStart","newEnd","openMonthPicker","currentYear","nextTick","rowIndex","scrollToYear","prevMonth","nextMonth","selectYear","selectMonth","confirmMonth","onSelectDay","onClear","handleHeaderClear","hasValue","onConfirm","onCloseMonthPicker","onPickerModeChange","mode","selectCurrentYear","selectCurrentMonth","currentMonth","getDaysBetween","startDate","endDate","diffTime","getTodayStr","getWeekStart","diff","getWeekEnd","weekStart","weekEnd","getMonthStart","getMonthEnd","getThreeMonthsAgo","getYearStart","getYearEnd","allShortcuts","availableShortcuts","option","range","handleShortcutClick","$event","_hoisted_6","_hoisted_7","_hoisted_8","index","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","RcButton","_cache","_createTextVNode","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","inputRef","popupPanelRef","inputText","isRangeMode","maxRangeDays","mergedDisabledDate","rangeStart","rangeEnd","selectedDate","getDisplayEndDate","updateInputText","addOneDay","subtractOneDay","getActualEndDate","actualEnd","value","onShortcutSelect","handlePopupClose","handleInputFocus","handleInputBlur","parseInputText","handleInput","text","parts","s","endStr","CalendarPanelContent","RcPopup","Calendar","activeIndex","panelRef","maskRef","maskStyle","updateMaskPosition","panelTop","handleClickOutside","event","target","searchAreaEl","barEl","closeFilter","newVal","tempSelectedValues","tempInputValue","tempCalendarValue","tempSlotValues","confirmedValues","newValue","currentFilter","selectedCountText","count","getTempSelectedCount","getItemDisplayText","item","findOption","getResultLabel","values","labels","label","openFilter","currentValue","getOptionLabel","data","result","getOptionValue","childrenKey","optValue","children","found","flattenOptions","isSelected","key","tempValue","getDisplayOptions","getTreeGroups","getTreeGroupChildren","group","getSlotValue","updateSlotValue","selectSingle","toggleOption","tempArray","existingIndex","resetCurrentFilter","handleInputChange","handleCalendarChange","confirmFilter","getSelectedCount","slotValue","RcCalendar","_d","_e","_f","_g","_h","_i","_j","_hoisted_9","groupIdx","optIdx","_k","_hoisted_18","_l","_hoisted_24","_m","_n","_o","_q","_p","_hoisted_25","_r","_s","_hoisted_26","RcSearchArea","formItemContext","actualDeviceType","innerValue","focused","passwordVisible","isComposing","isNumberMode","actualType","displayValue","numValue","getNumberValue","formatNumberWithGrouping","wordCount","showClearButton","slots","useSlots","hasSuffix","textareaStyle","style","validateNumber","isMax","isMin","onInput","validated","normalizedValue","resizeTextarea","onFocus","onBlur","togglePassword","handleStepUp","current","step","handleStepDown","onKeydown","onMouseEnter","onMouseLeave","onCompositionStart","onCompositionUpdate","onCompositionEnd","handleWrapperClick","textarea","scrollHeight","minRows","maxRows","lineHeight","minHeight","maxHeight","focus","blur","select","clear","_resolveDynamicComponent","Input","menuRef","shouldShow","hasTeleport","menuStyle","$emit","dropdownRef","showTimer","hideTimer","handleItemClick","command","show","updatePosition","hide","isMenuHovered","toggle","handleMouseEnter","handleMouseLeave","handleMenuMouseEnter","handleMenuMouseLeave","handleClick","triggerEl","menuEl","triggerRect","menuRect","top","left","viewportWidth","viewportHeight","handleDocumentClick","handleResize","RcDropdownMenu","Dropdown","DropdownMenu","DropdownItem","formRef","formItems","initialModel","deepClone","obj","cloned","saveInitialValues","registerFormItem","prop","formItem","unregisterFormItem","callback","isSubmitting","submitForm","validate","isValid","resetForm","resetFields","isInitialValueSaved","resolve","promises","invalidFields","promise","error","validateField","clearValidate","propsToClear","onSubmit","validateState","validateMessage","width","labelFor","showMessage","hideRequiredAsterisk","isRequired","rules","getRules","rule","formRules","getFieldValue","validateRule","transformedValue","validateType","pattern","trigger","reject","rulesToValidate","errors","e","err","errorMessage","resetField","hasChangeRule","hasBlurRule","Form","FormItem","radioRef","radioGroup","isGroup","model","unref","isChecked","handleChange","handleFocus","handleBlur","changeEvent","actualSize","buttonStyle","Radio","RadioGroup","RadioButton","checkboxRef","checkboxGroup","getGroupValue","rawValue","groupValue","actualValue","Checkbox","CheckboxGroup","CheckboxButton","doAutoRegister","installButton","installDescriptions","installCard","installToast","installIcon","installMessage","installSearchArea","installCalendar","installPopup","installInput","installDropdown","installForm","installRadio","installCheckbox","plugin","createRecycleUI"],"mappings":"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"}
|