@vela-studio/ui 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +152 -0
  2. package/dist/index.d.ts +696 -0
  3. package/dist/index.js +10 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.mjs +11786 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/dist/index.umd.js +10 -0
  8. package/dist/index.umd.js.map +1 -0
  9. package/dist/style.css +1 -0
  10. package/index.ts +150 -0
  11. package/package.json +73 -0
  12. package/src/components/advanced/scripting/Scripting.vue +189 -0
  13. package/src/components/advanced/state/State.vue +231 -0
  14. package/src/components/advanced/trigger/Trigger.vue +256 -0
  15. package/src/components/basic/button/Button.vue +120 -0
  16. package/src/components/basic/container/Container.vue +22 -0
  17. package/src/components/chart/barChart/barChart.vue +176 -0
  18. package/src/components/chart/doughnutChart/doughnutChart.vue +128 -0
  19. package/src/components/chart/funnelChart/funnelChart.vue +128 -0
  20. package/src/components/chart/gaugeChart/gaugeChart.vue +144 -0
  21. package/src/components/chart/lineChart/lineChart.vue +188 -0
  22. package/src/components/chart/pieChart/pieChart.vue +114 -0
  23. package/src/components/chart/radarChart/radarChart.vue +115 -0
  24. package/src/components/chart/sankeyChart/sankeyChart.vue +144 -0
  25. package/src/components/chart/scatterChart/scatterChart.vue +162 -0
  26. package/src/components/chart/stackedBarChart/stackedBarChart.vue +184 -0
  27. package/src/components/content/html/Html.vue +104 -0
  28. package/src/components/content/iframe/Iframe.vue +111 -0
  29. package/src/components/content/markdown/Markdown.vue +174 -0
  30. package/src/components/controls/breadcrumb/Breadcrumb.vue +79 -0
  31. package/src/components/controls/buttonGroup/ButtonGroup.vue +93 -0
  32. package/src/components/controls/checkboxGroup/CheckboxGroup.vue +147 -0
  33. package/src/components/controls/dateRange/DateRange.vue +174 -0
  34. package/src/components/controls/multiSelect/MultiSelect.vue +155 -0
  35. package/src/components/controls/navButton/NavButton.vue +97 -0
  36. package/src/components/controls/pagination/Pagination.vue +94 -0
  37. package/src/components/controls/searchBox/SearchBox.vue +170 -0
  38. package/src/components/controls/select/Select.vue +134 -0
  39. package/src/components/controls/slider/Slider.vue +167 -0
  40. package/src/components/controls/switch/Switch.vue +107 -0
  41. package/src/components/data/cardGrid/CardGrid.vue +318 -0
  42. package/src/components/data/list/List.vue +282 -0
  43. package/src/components/data/pivot/Pivot.vue +270 -0
  44. package/src/components/data/table/Table.vue +150 -0
  45. package/src/components/data/timeline/Timeline.vue +315 -0
  46. package/src/components/group/Group.vue +75 -0
  47. package/src/components/kpi/box/Box.vue +98 -0
  48. package/src/components/kpi/countUp/CountUp.vue +193 -0
  49. package/src/components/kpi/progress/Progress.vue +159 -0
  50. package/src/components/kpi/stat/Stat.vue +205 -0
  51. package/src/components/kpi/text/Text.vue +74 -0
  52. package/src/components/layout/badge/Badge.vue +105 -0
  53. package/src/components/layout/col/Col.vue +114 -0
  54. package/src/components/layout/flex/Flex.vue +105 -0
  55. package/src/components/layout/grid/Grid.vue +89 -0
  56. package/src/components/layout/modal/Modal.vue +118 -0
  57. package/src/components/layout/panel/Panel.vue +162 -0
  58. package/src/components/layout/row/Row.vue +99 -0
  59. package/src/components/layout/tabs/Tabs.vue +117 -0
  60. package/src/components/media/image/Image.vue +132 -0
  61. package/src/components/media/video/Video.vue +115 -0
  62. package/src/components/v2/basic/BaseButton.vue +179 -0
  63. package/src/components/v2/kpi/KpiCard.vue +215 -0
  64. package/src/components/v2/layout/GridBox.vue +55 -0
  65. package/src/hooks/useDataSource.ts +123 -0
  66. package/src/types/gis.ts +251 -0
  67. package/src/utils/chartUtils.ts +349 -0
  68. package/src/utils/dataUtils.ts +403 -0
@@ -0,0 +1,174 @@
1
+ <template>
2
+ <div :style="containerStyle" class="markdown-body" v-html="renderedHtml"></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import { computed } from 'vue'
7
+ import type { CSSProperties } from 'vue'
8
+ import { marked } from 'marked'
9
+ import DOMPurify from 'dompurify'
10
+
11
+ const props = withDefaults(
12
+ defineProps<{
13
+ content?: string
14
+ padding?: number
15
+ backgroundColor?: string
16
+ textColor?: string
17
+ fontSize?: number
18
+ lineHeight?: number | string
19
+ borderRadius?: number
20
+ border?: string
21
+ fontFamily?: string
22
+ }>(),
23
+ {
24
+ content: '# Markdown 内容\n\n请输入 Markdown 文本...',
25
+ padding: 16,
26
+ backgroundColor: '#ffffff',
27
+ textColor: '#333333',
28
+ fontSize: 14,
29
+ lineHeight: 1.6,
30
+ borderRadius: 0,
31
+ border: 'none',
32
+ fontFamily: 'inherit',
33
+ },
34
+ )
35
+
36
+ // 渲染的 HTML
37
+ const renderedHtml = computed(() => {
38
+ try {
39
+ const html = marked(props.content)
40
+ // 使用 DOMPurify 清理 HTML,防止 XSS 攻击
41
+ return DOMPurify.sanitize(String(html))
42
+ } catch (error) {
43
+ console.error('Markdown 渲染失败:', error)
44
+ return '<p>Markdown 渲染失败</p>'
45
+ }
46
+ })
47
+
48
+ // 样式
49
+ const containerStyle = computed<CSSProperties>(() => ({
50
+ width: '100%',
51
+ height: '100%',
52
+ padding: `${props.padding}px`,
53
+ backgroundColor: props.backgroundColor,
54
+ color: props.textColor,
55
+ fontSize: `${props.fontSize}px`,
56
+ lineHeight: String(props.lineHeight),
57
+ borderRadius: `${props.borderRadius}px`,
58
+ border: props.border,
59
+ overflow: 'auto',
60
+ fontFamily: props.fontFamily,
61
+ }))
62
+ </script>
63
+
64
+ <style scoped>
65
+ .markdown-body {
66
+ box-sizing: border-box;
67
+ }
68
+
69
+ .markdown-body :deep(h1),
70
+ .markdown-body :deep(h2),
71
+ .markdown-body :deep(h3),
72
+ .markdown-body :deep(h4),
73
+ .markdown-body :deep(h5),
74
+ .markdown-body :deep(h6) {
75
+ margin-top: 24px;
76
+ margin-bottom: 16px;
77
+ font-weight: 600;
78
+ line-height: 1.25;
79
+ }
80
+
81
+ .markdown-body :deep(h1) {
82
+ font-size: 2em;
83
+ border-bottom: 1px solid #eaecef;
84
+ padding-bottom: 0.3em;
85
+ }
86
+
87
+ .markdown-body :deep(h2) {
88
+ font-size: 1.5em;
89
+ border-bottom: 1px solid #eaecef;
90
+ padding-bottom: 0.3em;
91
+ }
92
+
93
+ .markdown-body :deep(h3) {
94
+ font-size: 1.25em;
95
+ }
96
+
97
+ .markdown-body :deep(p) {
98
+ margin-top: 0;
99
+ margin-bottom: 16px;
100
+ }
101
+
102
+ .markdown-body :deep(ul),
103
+ .markdown-body :deep(ol) {
104
+ padding-left: 2em;
105
+ margin-top: 0;
106
+ margin-bottom: 16px;
107
+ }
108
+
109
+ .markdown-body :deep(li) {
110
+ margin-bottom: 4px;
111
+ }
112
+
113
+ .markdown-body :deep(code) {
114
+ padding: 0.2em 0.4em;
115
+ margin: 0;
116
+ font-size: 85%;
117
+ background-color: rgba(175, 184, 193, 0.2);
118
+ border-radius: 6px;
119
+ font-family: monospace;
120
+ }
121
+
122
+ .markdown-body :deep(pre) {
123
+ padding: 16px;
124
+ overflow: auto;
125
+ font-size: 85%;
126
+ line-height: 1.45;
127
+ background-color: #f6f8fa;
128
+ border-radius: 6px;
129
+ margin-bottom: 16px;
130
+ }
131
+
132
+ .markdown-body :deep(pre code) {
133
+ background-color: transparent;
134
+ padding: 0;
135
+ }
136
+
137
+ .markdown-body :deep(blockquote) {
138
+ padding: 0 1em;
139
+ color: #6a737d;
140
+ border-left: 0.25em solid #dfe2e5;
141
+ margin: 0 0 16px 0;
142
+ }
143
+
144
+ .markdown-body :deep(table) {
145
+ border-collapse: collapse;
146
+ width: 100%;
147
+ margin-bottom: 16px;
148
+ }
149
+
150
+ .markdown-body :deep(table th),
151
+ .markdown-body :deep(table td) {
152
+ padding: 6px 13px;
153
+ border: 1px solid #dfe2e5;
154
+ }
155
+
156
+ .markdown-body :deep(table th) {
157
+ font-weight: 600;
158
+ background-color: #f6f8fa;
159
+ }
160
+
161
+ .markdown-body :deep(img) {
162
+ max-width: 100%;
163
+ box-sizing: content-box;
164
+ }
165
+
166
+ .markdown-body :deep(a) {
167
+ color: #0366d6;
168
+ text-decoration: none;
169
+ }
170
+
171
+ .markdown-body :deep(a:hover) {
172
+ text-decoration: underline;
173
+ }
174
+ </style>
@@ -0,0 +1,79 @@
1
+ <template>
2
+ <el-breadcrumb :separator="separator" class="custom-breadcrumb" :style="containerStyle">
3
+ <el-breadcrumb-item v-for="(item, index) in displayItems" :key="index">
4
+ <span v-if="index === displayItems.length - 1" class="current">{{ item.label }}</span>
5
+ <a v-else class="link" @click="handleItemClick(item)">{{ item.label }}</a>
6
+ </el-breadcrumb-item>
7
+ </el-breadcrumb>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { computed } from 'vue'
12
+ import type { CSSProperties } from 'vue'
13
+ import { ElBreadcrumb, ElBreadcrumbItem } from 'element-plus'
14
+
15
+ export interface BreadcrumbItem {
16
+ label: string
17
+ pageId?: string
18
+ url?: string
19
+ }
20
+
21
+ export interface BreadcrumbProps {
22
+ items?: BreadcrumbItem[]
23
+ separator?: string
24
+ fontSize?: number
25
+ color?: string
26
+ activeColor?: string
27
+ linkColor?: string
28
+ }
29
+
30
+ const props = withDefaults(defineProps<BreadcrumbProps>(), {
31
+ items: () => [],
32
+ separator: '/',
33
+ fontSize: 14,
34
+ color: '#606266',
35
+ activeColor: '#909399',
36
+ linkColor: '#409eff',
37
+ })
38
+
39
+ const emit = defineEmits<{
40
+ itemClick: [item: BreadcrumbItem]
41
+ }>()
42
+
43
+ // 默认显示项
44
+ const defaultItems: BreadcrumbItem[] = [{ label: '首页', pageId: 'home' }, { label: '当前页面' }]
45
+
46
+ const displayItems = computed(() => {
47
+ return props.items.length > 0 ? props.items : defaultItems
48
+ })
49
+
50
+ const containerStyle = computed<CSSProperties>(() => ({
51
+ fontSize: `${props.fontSize}px`,
52
+ '--breadcrumb-color': props.color,
53
+ '--breadcrumb-active-color': props.activeColor,
54
+ '--breadcrumb-link-color': props.linkColor,
55
+ }))
56
+
57
+ function handleItemClick(item: BreadcrumbItem) {
58
+ emit('itemClick', item)
59
+ }
60
+ </script>
61
+
62
+ <style scoped>
63
+ .custom-breadcrumb {
64
+ padding: 8px 16px;
65
+ }
66
+
67
+ .link {
68
+ cursor: pointer;
69
+ color: var(--breadcrumb-link-color, #409eff);
70
+ }
71
+
72
+ .link:hover {
73
+ text-decoration: underline;
74
+ }
75
+
76
+ .current {
77
+ color: var(--breadcrumb-active-color, #909399);
78
+ }
79
+ </style>
@@ -0,0 +1,93 @@
1
+ <template>
2
+ <div :style="containerStyle">
3
+ <el-button-group>
4
+ <el-button
5
+ v-for="button in displayButtons"
6
+ :key="button.value"
7
+ :type="button.type || type"
8
+ :size="size"
9
+ :disabled="button.disabled || disabled"
10
+ :plain="plain"
11
+ :round="round"
12
+ :circle="circle"
13
+ :icon="button.icon"
14
+ @click="handleClick(button)"
15
+ >
16
+ {{ button.label }}
17
+ </el-button>
18
+ </el-button-group>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { computed } from 'vue'
24
+ import type { CSSProperties } from 'vue'
25
+ import { ElButtonGroup, ElButton } from 'element-plus'
26
+
27
+ // 按钮接口
28
+ export interface ButtonItem {
29
+ label: string
30
+ value: string | number
31
+ type?: 'default' | 'primary' | 'success' | 'warning' | 'info' | 'danger'
32
+ icon?: string
33
+ disabled?: boolean
34
+ }
35
+
36
+ const props = withDefaults(
37
+ defineProps<{
38
+ buttons?: ButtonItem[]
39
+ type?: 'default' | 'primary' | 'success' | 'warning' | 'info' | 'danger'
40
+ size?: 'large' | 'default' | 'small'
41
+ disabled?: boolean
42
+ plain?: boolean
43
+ round?: boolean
44
+ circle?: boolean
45
+ padding?: number
46
+ backgroundColor?: string
47
+ }>(),
48
+ {
49
+ buttons: () => [],
50
+ type: 'default',
51
+ size: 'default',
52
+ disabled: false,
53
+ plain: false,
54
+ round: false,
55
+ circle: false,
56
+ padding: 16,
57
+ backgroundColor: 'transparent',
58
+ },
59
+ )
60
+
61
+ const emit = defineEmits<{
62
+ click: [button: ButtonItem]
63
+ }>()
64
+
65
+ // 默认按钮数据
66
+ const defaultButtons: ButtonItem[] = [
67
+ { label: '按钮 1', value: '1' },
68
+ { label: '按钮 2', value: '2' },
69
+ { label: '按钮 3', value: '3' },
70
+ ]
71
+
72
+ // 显示的按钮
73
+ const displayButtons = computed(() => {
74
+ return props.buttons.length > 0 ? props.buttons : defaultButtons
75
+ })
76
+
77
+ // 容器样式
78
+ const containerStyle = computed<CSSProperties>(() => ({
79
+ padding: `${props.padding}px`,
80
+ backgroundColor: props.backgroundColor,
81
+ }))
82
+
83
+ // 事件处理
84
+ const handleClick = (button: ButtonItem) => {
85
+ emit('click', button)
86
+ }
87
+ </script>
88
+
89
+ <style scoped>
90
+ :deep(.el-button-group) {
91
+ display: flex;
92
+ }
93
+ </style>
@@ -0,0 +1,147 @@
1
+ <template>
2
+ <div :style="containerStyle">
3
+ <el-checkbox-group
4
+ v-model="internalValue"
5
+ :size="size"
6
+ :disabled="disabled"
7
+ :min="min"
8
+ :max="max"
9
+ @change="handleChange"
10
+ >
11
+ <component
12
+ :is="layout === 'button' ? 'el-checkbox-button' : 'el-checkbox'"
13
+ v-for="option in displayOptions"
14
+ :key="option.value"
15
+ :label="option.value"
16
+ :disabled="option.disabled"
17
+ :border="showBorder && layout !== 'button'"
18
+ >
19
+ {{ option.label }}
20
+ </component>
21
+ </el-checkbox-group>
22
+ </div>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ import { computed, ref, watch } from 'vue'
27
+ import type { CSSProperties } from 'vue'
28
+ import { ElCheckboxGroup, ElCheckbox, ElCheckboxButton } from 'element-plus'
29
+
30
+ // 选项接口
31
+ export interface CheckboxOption {
32
+ label: string
33
+ value: string | number
34
+ disabled?: boolean
35
+ }
36
+
37
+ const props = withDefaults(
38
+ defineProps<{
39
+ modelValue?: (string | number)[]
40
+ options?: CheckboxOption[]
41
+ size?: 'large' | 'default' | 'small'
42
+ disabled?: boolean
43
+ min?: number
44
+ max?: number
45
+ layout?: 'default' | 'button'
46
+ showBorder?: boolean
47
+ direction?: 'horizontal' | 'vertical'
48
+ gap?: number
49
+ padding?: number
50
+ backgroundColor?: string
51
+ checkedColor?: string
52
+ borderColor?: string
53
+ textColor?: string
54
+ }>(),
55
+ {
56
+ modelValue: () => [],
57
+ options: () => [],
58
+ size: 'default',
59
+ disabled: false,
60
+ min: undefined,
61
+ max: undefined,
62
+ layout: 'default',
63
+ showBorder: false,
64
+ direction: 'horizontal',
65
+ gap: 12,
66
+ padding: 16,
67
+ backgroundColor: 'transparent',
68
+ checkedColor: '#409eff',
69
+ borderColor: '#dcdfe6',
70
+ textColor: '#606266',
71
+ },
72
+ )
73
+
74
+ const emit = defineEmits<{
75
+ 'update:modelValue': [value: (string | number)[]]
76
+ change: [value: (string | number)[]]
77
+ }>()
78
+
79
+ // 默认选项
80
+ const defaultOptions: CheckboxOption[] = [
81
+ { label: '选项 A', value: 'a' },
82
+ { label: '选项 B', value: 'b' },
83
+ { label: '选项 C', value: 'c' },
84
+ ]
85
+
86
+ // 显示的选项
87
+ const displayOptions = computed(() => {
88
+ return props.options.length > 0 ? props.options : defaultOptions
89
+ })
90
+
91
+ // 内部值
92
+ const internalValue = ref<(string | number)[]>([...props.modelValue])
93
+
94
+ // 监听外部值变化
95
+ watch(
96
+ () => props.modelValue,
97
+ (newVal) => {
98
+ internalValue.value = [...newVal]
99
+ },
100
+ )
101
+
102
+ // 容器样式
103
+ const containerStyle = computed<CSSProperties>(
104
+ () =>
105
+ ({
106
+ padding: `${props.padding}px`,
107
+ backgroundColor: props.backgroundColor,
108
+ display: 'flex',
109
+ flexDirection: props.direction === 'vertical' ? 'column' : 'row',
110
+ gap: `${props.gap}px`,
111
+ '--el-checkbox-checked-bg-color': props.checkedColor,
112
+ '--el-checkbox-checked-input-border-color': props.checkedColor,
113
+ '--el-checkbox-input-border-color': props.borderColor,
114
+ '--el-checkbox-text-color': props.textColor,
115
+ }) as CSSProperties,
116
+ )
117
+
118
+ // 事件处理
119
+ const handleChange = (value: (string | number)[]) => {
120
+ emit('update:modelValue', value)
121
+ emit('change', value)
122
+ }
123
+ </script>
124
+
125
+ <style scoped>
126
+ :deep(.el-checkbox-group) {
127
+ display: flex;
128
+ flex-direction: v-bind('containerStyle.flexDirection');
129
+ gap: v-bind('containerStyle.gap');
130
+ }
131
+
132
+ :deep(.el-checkbox) {
133
+ --el-checkbox-checked-bg-color: v-bind('containerStyle["--el-checkbox-checked-bg-color"]');
134
+ --el-checkbox-checked-input-border-color: v-bind(
135
+ 'containerStyle["--el-checkbox-checked-input-border-color"]'
136
+ );
137
+ --el-checkbox-input-border-color: v-bind('containerStyle["--el-checkbox-input-border-color"]');
138
+ --el-checkbox-text-color: v-bind('containerStyle["--el-checkbox-text-color"]');
139
+ }
140
+
141
+ :deep(.el-checkbox-button) {
142
+ --el-checkbox-button-checked-bg-color: v-bind('containerStyle["--el-checkbox-checked-bg-color"]');
143
+ --el-checkbox-button-checked-border-color: v-bind(
144
+ 'containerStyle["--el-checkbox-checked-input-border-color"]'
145
+ );
146
+ }
147
+ </style>
@@ -0,0 +1,174 @@
1
+ <template>
2
+ <div class="date-range-container" :style="containerStyle">
3
+ <el-date-picker
4
+ v-model="internalValue"
5
+ type="daterange"
6
+ :range-separator="rangeSeparator"
7
+ :start-placeholder="startPlaceholder"
8
+ :end-placeholder="endPlaceholder"
9
+ :format="format"
10
+ :value-format="valueFormat"
11
+ :disabled="disabled"
12
+ :clearable="clearable"
13
+ :size="size"
14
+ :editable="editable"
15
+ :shortcuts="computedShortcuts"
16
+ :style="pickerStyle"
17
+ @change="handleChange"
18
+ />
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { computed, ref, watch } from 'vue'
24
+ import type { CSSProperties } from 'vue'
25
+ import { ElDatePicker } from 'element-plus'
26
+
27
+ const props = withDefaults(
28
+ defineProps<{
29
+ modelValue?: [Date, Date] | null
30
+ rangeSeparator?: string
31
+ startPlaceholder?: string
32
+ endPlaceholder?: string
33
+ format?: string
34
+ valueFormat?: string
35
+ disabled?: boolean
36
+ clearable?: boolean
37
+ size?: 'large' | 'default' | 'small'
38
+ editable?: boolean
39
+ enableShortcuts?: boolean
40
+ padding?: number
41
+ backgroundColor?: string
42
+ borderRadius?: number
43
+ opacity?: number
44
+ pickerWidth?: number
45
+ borderColor?: string
46
+ focusBorderColor?: string
47
+ hoverBorderColor?: string
48
+ }>(),
49
+ {
50
+ modelValue: null,
51
+ rangeSeparator: '至',
52
+ startPlaceholder: '开始日期',
53
+ endPlaceholder: '结束日期',
54
+ format: 'YYYY-MM-DD',
55
+ valueFormat: 'YYYY-MM-DD',
56
+ disabled: false,
57
+ clearable: true,
58
+ size: 'default',
59
+ editable: false,
60
+ enableShortcuts: true,
61
+ padding: 8,
62
+ backgroundColor: 'transparent',
63
+ borderRadius: 4,
64
+ opacity: 100,
65
+ pickerWidth: 100,
66
+ borderColor: '#dcdfe6',
67
+ focusBorderColor: '#409eff',
68
+ hoverBorderColor: '#c0c4cc',
69
+ },
70
+ )
71
+
72
+ const emit = defineEmits<{
73
+ 'update:modelValue': [value: [Date, Date] | null]
74
+ change: [value: [Date, Date] | null]
75
+ }>()
76
+
77
+ // 内部值
78
+ const internalValue = ref<[Date, Date] | null>(props.modelValue)
79
+
80
+ // 监听外部值变化
81
+ watch(
82
+ () => props.modelValue,
83
+ (newVal) => {
84
+ internalValue.value = newVal
85
+ },
86
+ )
87
+
88
+ // 快捷选项
89
+ const computedShortcuts = computed(() => {
90
+ if (!props.enableShortcuts) return []
91
+
92
+ return [
93
+ {
94
+ text: '最近一周',
95
+ value: () => {
96
+ const end = new Date()
97
+ const start = new Date()
98
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
99
+ return [start, end]
100
+ },
101
+ },
102
+ {
103
+ text: '最近一个月',
104
+ value: () => {
105
+ const end = new Date()
106
+ const start = new Date()
107
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
108
+ return [start, end]
109
+ },
110
+ },
111
+ {
112
+ text: '最近三个月',
113
+ value: () => {
114
+ const end = new Date()
115
+ const start = new Date()
116
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
117
+ return [start, end]
118
+ },
119
+ },
120
+ {
121
+ text: '本月',
122
+ value: () => {
123
+ const now = new Date()
124
+ const start = new Date(now.getFullYear(), now.getMonth(), 1)
125
+ const end = new Date(now.getFullYear(), now.getMonth() + 1, 0)
126
+ return [start, end]
127
+ },
128
+ },
129
+ {
130
+ text: '本年',
131
+ value: () => {
132
+ const now = new Date()
133
+ const start = new Date(now.getFullYear(), 0, 1)
134
+ const end = new Date(now.getFullYear(), 11, 31)
135
+ return [start, end]
136
+ },
137
+ },
138
+ ]
139
+ })
140
+
141
+ // 样式
142
+ const containerStyle = computed<CSSProperties>(() => ({
143
+ opacity: props.opacity / 100,
144
+ display: 'flex',
145
+ alignItems: 'center',
146
+ width: '100%',
147
+ height: '100%',
148
+ padding: `${props.padding}px`,
149
+ backgroundColor: props.backgroundColor,
150
+ borderRadius: `${props.borderRadius}px`,
151
+ }))
152
+
153
+ const pickerStyle = computed<CSSProperties>(
154
+ () =>
155
+ ({
156
+ width: `${props.pickerWidth}%`,
157
+ '--el-input-border-color': props.borderColor,
158
+ '--el-input-focus-border-color': props.focusBorderColor,
159
+ '--el-input-hover-border-color': props.hoverBorderColor,
160
+ }) as CSSProperties,
161
+ )
162
+
163
+ // 事件
164
+ function handleChange(value: [Date, Date] | null) {
165
+ emit('update:modelValue', value)
166
+ emit('change', value)
167
+ }
168
+ </script>
169
+
170
+ <style scoped>
171
+ .date-range-container {
172
+ box-sizing: border-box;
173
+ }
174
+ </style>