xt-element-ui 1.1.0 → 1.1.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.
- package/lib/css/2.3f7aa432.css +1 -0
- package/lib/css/3.ffcc175d.css +1 -0
- package/lib/css/4.9abd1f2b.css +1 -0
- package/lib/css/5.1a31ed8a.css +1 -0
- package/lib/css/6.c2d0d77e.css +1 -0
- package/lib/index.common.0.js +120208 -0
- package/lib/index.common.2.js +1053 -0
- package/lib/index.common.3.js +996 -0
- package/lib/index.common.4.js +1108 -0
- package/lib/index.common.5.js +1009 -0
- package/lib/index.common.6.js +973 -0
- package/lib/index.common.js +8003 -211
- package/lib/index.css +1 -1
- package/lib/index.umd.0.js +120208 -0
- package/lib/index.umd.2.js +1053 -0
- package/lib/index.umd.3.js +996 -0
- package/lib/index.umd.4.js +1108 -0
- package/lib/index.umd.5.js +1009 -0
- package/lib/index.umd.6.js +973 -0
- package/lib/index.umd.js +8003 -211
- package/lib/index.umd.min.0.js +34 -0
- package/lib/index.umd.min.2.js +1 -0
- package/lib/index.umd.min.3.js +1 -0
- package/lib/index.umd.min.4.js +1 -0
- package/lib/index.umd.min.5.js +1 -0
- package/lib/index.umd.min.6.js +1 -0
- package/lib/index.umd.min.js +1 -1
- package/package.json +6 -2
- package/src/components/button/index.vue +5 -5
- package/src/components/button/style/index.scss +743 -90
- package/src/components/chart/ExBar.vue +203 -0
- package/src/components/chart/ExLine.vue +146 -0
- package/src/components/chart/ExMulti.vue +257 -0
- package/src/components/chart/ExPie.vue +159 -0
- package/src/components/chart/ExTrend.vue +121 -0
- package/src/components/chart/index.js +2 -0
- package/src/components/chart/index.vue +51 -0
- package/src/components/chart/pieList.vue +110 -0
- package/src/components/chart/theme/blue.js +91 -0
- package/src/components/chart/theme/dark.js +91 -0
- package/src/components/chart/theme/orange.js +92 -0
- package/src/components/chart/theme/starry.js +106 -0
- package/src/components/chart/theme/white.js +110 -0
- package/src/components/chart/utils.js +273 -0
- package/src/components/config-provider/index.vue +150 -51
- package/src/components/config-provider/style/index.scss +2 -2
- package/src/components/date-picker/SearchDate.vue +45 -0
- package/src/components/date-picker/index.js +2 -0
- package/src/components/date-picker/index.vue +131 -0
- package/src/components/date-picker/quarter.vue +152 -0
- package/src/components/grid-box/index.js +2 -0
- package/src/components/grid-box/index.vue +42 -0
- package/src/components/layout/BaseCollapse.vue +48 -0
- package/src/components/layout/ExFieldset.vue +204 -0
- package/src/components/page/index.js +0 -0
- package/src/components/page/index.vue +109 -0
- package/src/components/select-tree/index.js +0 -0
- package/src/components/select-tree/index.vue +386 -0
- package/src/components/table/ExCell.vue +27 -0
- package/src/components/table/ExColumn.vue +36 -0
- package/src/components/table/index.js +2 -0
- package/src/components/table/index.vue +731 -0
- package/src/components/table/processor.js +380 -0
- package/src/components/text/index.vue +79 -2
- package/src/components/text/style/index.scss +28 -6
- package/src/components/upload/index.js +2 -0
- package/src/components/upload/index.vue +225 -0
- package/src/components/upload/preview.vue +333 -0
- package/src/index.js +11 -2
- package/src/styles/css-variables.scss +238 -148
- package/src/styles/theme/background.scss +1 -1
- package/src/styles/theme/colors.scss +90 -1
- package/src/styles/variables.scss +1 -1
- package/src/components/button/style/index copy.scss +0 -221
|
@@ -1,23 +1,50 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<!-- 根据 tag 属性选择渲染的标签 -->
|
|
3
|
-
<component
|
|
4
|
-
:is="tag"
|
|
5
|
-
:style="mergedStyle"
|
|
6
|
-
:class="computedClass"
|
|
7
|
-
v-bind="customAttrs"
|
|
8
|
-
>
|
|
9
|
-
<slot></slot>
|
|
10
|
-
</component>
|
|
11
|
-
</template>
|
|
12
|
-
|
|
13
1
|
<script>
|
|
14
2
|
export default {
|
|
15
3
|
name: 'XtConfigProvider',
|
|
16
4
|
inheritAttrs: false,
|
|
5
|
+
render(h) {
|
|
6
|
+
// Vue 2 不支持 Fragment,当 tag="template" 时需要特殊处理
|
|
7
|
+
// 如果设置了 proxyElement,则不渲染包裹元素,只渲染 slot 内容
|
|
8
|
+
if (this.tag === 'template' || this.proxyElement) {
|
|
9
|
+
// 渲染 slot 内容,如果只有一个元素则直接返回,否则包裹一个 div
|
|
10
|
+
const slotContent = this.$slots.default
|
|
11
|
+
|
|
12
|
+
if (!slotContent || slotContent.length === 0) {
|
|
13
|
+
return h('div')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 如果 slot 只有一个元素,直接返回该元素
|
|
17
|
+
if (slotContent.length === 1) {
|
|
18
|
+
return slotContent[0]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Vue 2 不支持多根节点,需要包裹一个 div
|
|
22
|
+
// 使用普通的 div 包裹,避免 display: contents 的兼容性问题
|
|
23
|
+
return h('div', {
|
|
24
|
+
class: 'xt-config-provider-wrapper',
|
|
25
|
+
attrs: {
|
|
26
|
+
'data-theme': this.theme
|
|
27
|
+
}
|
|
28
|
+
}, slotContent)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 正常渲染包裹元素
|
|
32
|
+
return h(this.tag, {
|
|
33
|
+
style: this.mergedStyle,
|
|
34
|
+
class: this.computedClass,
|
|
35
|
+
attrs: {
|
|
36
|
+
...this.customAttrs,
|
|
37
|
+
'data-theme': this.theme
|
|
38
|
+
}
|
|
39
|
+
}, this.$slots.default)
|
|
40
|
+
},
|
|
17
41
|
props: {
|
|
18
42
|
theme: {
|
|
19
43
|
type: String,
|
|
20
|
-
default: '
|
|
44
|
+
default: 'light',
|
|
45
|
+
validator: (value) => {
|
|
46
|
+
return ['light', 'dark', 'auto'].includes(value)
|
|
47
|
+
}
|
|
21
48
|
},
|
|
22
49
|
size: {
|
|
23
50
|
type: String,
|
|
@@ -25,7 +52,7 @@ export default {
|
|
|
25
52
|
},
|
|
26
53
|
primaryColor: {
|
|
27
54
|
type: String,
|
|
28
|
-
default: '#
|
|
55
|
+
default: '#1890ff'
|
|
29
56
|
},
|
|
30
57
|
vars: {
|
|
31
58
|
type: Object,
|
|
@@ -45,6 +72,11 @@ export default {
|
|
|
45
72
|
injectColor: {
|
|
46
73
|
type: Boolean,
|
|
47
74
|
default: false
|
|
75
|
+
},
|
|
76
|
+
proxyElement: {
|
|
77
|
+
type: [HTMLElement, String, Object],
|
|
78
|
+
default: null,
|
|
79
|
+
description: '代理元素,将样式应用到该元素上。支持 HTMLElement、CSS选择器字符串或 ref 对象'
|
|
48
80
|
}
|
|
49
81
|
},
|
|
50
82
|
computed: {
|
|
@@ -54,11 +86,14 @@ export default {
|
|
|
54
86
|
if (this.primaryColor) {
|
|
55
87
|
const color = this.normalizeColor(this.primaryColor)
|
|
56
88
|
result['--xt-color-primary'] = color
|
|
89
|
+
// 浅色系列(与 css-variables.scss 保持一致)
|
|
57
90
|
result['--xt-color-primary-light-3'] = this.lightenColor(color, 30)
|
|
58
91
|
result['--xt-color-primary-light-5'] = this.lightenColor(color, 50)
|
|
59
92
|
result['--xt-color-primary-light-7'] = this.lightenColor(color, 70)
|
|
60
93
|
result['--xt-color-primary-light-8'] = this.lightenColor(color, 80)
|
|
61
94
|
result['--xt-color-primary-light-9'] = this.lightenColor(color, 90)
|
|
95
|
+
// 深色系列
|
|
96
|
+
result['--xt-color-primary-dark-2'] = this.darkenColor(color, 20)
|
|
62
97
|
}
|
|
63
98
|
|
|
64
99
|
const sizeMap = {
|
|
@@ -71,37 +106,19 @@ export default {
|
|
|
71
106
|
}
|
|
72
107
|
|
|
73
108
|
if (this.theme === 'dark') {
|
|
74
|
-
result['--xt-color-text-primary'] = 'rgba(255, 255, 255, 0.95)'
|
|
75
|
-
result['--xt-color-text-regular'] = 'rgba(255, 255, 255, 0.8)'
|
|
76
|
-
result['--xt-color-text-secondary'] = 'rgba(255, 255, 255, 0.6)'
|
|
77
|
-
result['--xt-color-bg-primary'] = '#1f1f1f'
|
|
78
|
-
result['--xt-color-bg-secondary'] = '#2d2d2d'
|
|
79
|
-
result['--xt-color-bg-container'] = '#1f1f1f'
|
|
80
|
-
result['--xt-color-border'] = '#434343'
|
|
81
|
-
result['--xt-color-border-light'] = '#3d3d3d'
|
|
82
|
-
|
|
83
109
|
if (this.injectBackground) {
|
|
84
|
-
result.backgroundColor = result['--xt-color-bg-primary']
|
|
110
|
+
result.backgroundColor = result['--xt-color-bg-primary'] || '#141414'
|
|
85
111
|
}
|
|
86
112
|
if (this.injectColor) {
|
|
87
|
-
result.color = result['--xt-color-text-primary']
|
|
113
|
+
result.color = result['--xt-color-text-primary'] || '#E5EAF3'
|
|
88
114
|
}
|
|
89
115
|
} else {
|
|
90
|
-
// 恢复默认主题颜色(
|
|
91
|
-
result['--xt-color-text-primary'] = '#303133'
|
|
92
|
-
result['--xt-color-text-regular'] = '#606266'
|
|
93
|
-
result['--xt-color-text-secondary'] = '#909399'
|
|
94
|
-
result['--xt-color-bg-primary'] = '#ffffff'
|
|
95
|
-
result['--xt-color-bg-secondary'] = '#f5f7fa'
|
|
96
|
-
result['--xt-color-bg-container'] = '#f5f7fa'
|
|
97
|
-
result['--xt-color-border'] = '#DCDFE6'
|
|
98
|
-
result['--xt-color-border-light'] = '#E4E7ED'
|
|
99
|
-
|
|
116
|
+
// 恢复默认主题颜色(light 主题)
|
|
100
117
|
if (this.injectBackground) {
|
|
101
|
-
result.backgroundColor = result['--xt-color-bg-primary']
|
|
118
|
+
result.backgroundColor = result['--xt-color-bg-primary'] || '#ffffff'
|
|
102
119
|
}
|
|
103
120
|
if (this.injectColor) {
|
|
104
|
-
result.color = result['--xt-color-text-primary']
|
|
121
|
+
result.color = result['--xt-color-text-primary'] || '#2c3e50'
|
|
105
122
|
}
|
|
106
123
|
}
|
|
107
124
|
|
|
@@ -112,30 +129,35 @@ export default {
|
|
|
112
129
|
|
|
113
130
|
if (this.tag !== 'template') {
|
|
114
131
|
classes.push('xt-config-provider')
|
|
115
|
-
|
|
116
|
-
if (this.theme === 'dark') {
|
|
117
|
-
classes.push('xt-config-provider--dark')
|
|
118
|
-
}
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
return classes
|
|
122
135
|
},
|
|
123
136
|
customAttrs() {
|
|
124
|
-
const props = ['theme', 'size', 'primaryColor', 'vars', 'tag', 'injectBackground', 'injectColor']
|
|
137
|
+
const props = ['theme', 'size', 'primaryColor', 'vars', 'tag', 'injectBackground', 'injectColor', 'proxyElement']
|
|
125
138
|
const attrs = {}
|
|
126
|
-
|
|
139
|
+
|
|
127
140
|
for (const key in this.$attrs) {
|
|
128
141
|
if (!props.includes(key)) {
|
|
129
142
|
attrs[key] = this.$attrs[key]
|
|
130
143
|
}
|
|
131
144
|
}
|
|
132
|
-
|
|
145
|
+
|
|
133
146
|
return attrs
|
|
134
147
|
}
|
|
135
148
|
},
|
|
149
|
+
mounted() {
|
|
150
|
+
this.applyProxyElementStyle()
|
|
151
|
+
},
|
|
152
|
+
updated() {
|
|
153
|
+
this.applyProxyElementStyle()
|
|
154
|
+
},
|
|
155
|
+
beforeUnmount() {
|
|
156
|
+
this.clearProxyElementStyle()
|
|
157
|
+
},
|
|
136
158
|
methods: {
|
|
137
159
|
normalizeColor(color) {
|
|
138
|
-
if (!color) return '#
|
|
160
|
+
if (!color) return '#1890ff'
|
|
139
161
|
|
|
140
162
|
if (/^#[0-9A-Fa-f]{6}$/.test(color)) {
|
|
141
163
|
return color
|
|
@@ -158,7 +180,7 @@ export default {
|
|
|
158
180
|
}
|
|
159
181
|
|
|
160
182
|
console.warn('[XtConfigProvider] 无法识别的颜色格式:', color)
|
|
161
|
-
return '#
|
|
183
|
+
return '#1890ff'
|
|
162
184
|
},
|
|
163
185
|
|
|
164
186
|
hexToRgb(hex) {
|
|
@@ -181,13 +203,90 @@ export default {
|
|
|
181
203
|
const rgb = this.hexToRgb(hex)
|
|
182
204
|
if (!rgb) return hex
|
|
183
205
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
const
|
|
206
|
+
// 使用与 Element Plus 一致的算法:将颜色与白色按比例混合
|
|
207
|
+
// percent 表示混合白色的比例(0-100),即 (1 - percent/100) 是原色比例
|
|
208
|
+
const ratio = percent / 100
|
|
209
|
+
const r = Math.round(rgb.r * (1 - ratio) + 255 * ratio)
|
|
210
|
+
const g = Math.round(rgb.g * (1 - ratio) + 255 * ratio)
|
|
211
|
+
const b = Math.round(rgb.b * (1 - ratio) + 255 * ratio)
|
|
188
212
|
|
|
189
213
|
return this.rgbToHex(r, g, b)
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
darkenColor(hex, percent) {
|
|
217
|
+
const rgb = this.hexToRgb(hex)
|
|
218
|
+
if (!rgb) return hex
|
|
219
|
+
|
|
220
|
+
// 使用按比例混合黑色的方式变暗
|
|
221
|
+
// percent 表示混合黑色的比例(0-100)
|
|
222
|
+
const ratio = percent / 100
|
|
223
|
+
const r = Math.max(0, Math.round(rgb.r * (1 - ratio)))
|
|
224
|
+
const g = Math.max(0, Math.round(rgb.g * (1 - ratio)))
|
|
225
|
+
const b = Math.max(0, Math.round(rgb.b * (1 - ratio)))
|
|
226
|
+
|
|
227
|
+
return this.rgbToHex(r, g, b)
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
getProxyElement() {
|
|
231
|
+
const { proxyElement } = this
|
|
232
|
+
|
|
233
|
+
if (!proxyElement) return null
|
|
234
|
+
|
|
235
|
+
if (proxyElement instanceof HTMLElement) {
|
|
236
|
+
return proxyElement
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (typeof proxyElement === 'string') {
|
|
240
|
+
return document.querySelector(proxyElement)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (proxyElement.$el) {
|
|
244
|
+
return proxyElement.$el
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (proxyElement.value && proxyElement.value instanceof HTMLElement) {
|
|
248
|
+
return proxyElement.value
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
console.warn('[XtConfigProvider] 无法解析 proxyElement:', proxyElement)
|
|
252
|
+
return null
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
applyProxyElementStyle() {
|
|
256
|
+
const element = this.getProxyElement()
|
|
257
|
+
if (!element) return
|
|
258
|
+
|
|
259
|
+
const style = this.mergedStyle
|
|
260
|
+
|
|
261
|
+
for (const key in style) {
|
|
262
|
+
element.style.setProperty(key, style[key])
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// 设置 data-theme 属性
|
|
266
|
+
element.setAttribute('data-theme', this.theme)
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
clearProxyElementStyle() {
|
|
270
|
+
const element = this.getProxyElement()
|
|
271
|
+
if (!element) return
|
|
272
|
+
|
|
273
|
+
const style = this.mergedStyle
|
|
274
|
+
|
|
275
|
+
for (const key in style) {
|
|
276
|
+
element.style.removeProperty(key)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// 移除 data-theme 属性
|
|
280
|
+
element.removeAttribute('data-theme')
|
|
190
281
|
}
|
|
191
282
|
}
|
|
192
283
|
}
|
|
193
|
-
</script>
|
|
284
|
+
</script>
|
|
285
|
+
|
|
286
|
+
<style scoped>
|
|
287
|
+
/* 包裹容器样式 - 最小化影响布局 */
|
|
288
|
+
.xt-config-provider-wrapper {
|
|
289
|
+
width: 100%;
|
|
290
|
+
height: 100%;
|
|
291
|
+
}
|
|
292
|
+
</style>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
.xt-config-provider--dark {
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
.xt-config-provider--dark
|
|
10
|
-
background-color: var(--xt-color-bg-primary, #
|
|
9
|
+
.xt-config-provider--dark {
|
|
10
|
+
background-color: var(--xt-color-bg-primary, #0b141d);
|
|
11
11
|
color: var(--xt-color-text-primary, rgba(255, 255, 255, 0.95));
|
|
12
12
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-form-item label="日期类型">
|
|
3
|
+
<el-select v-model="params.SearchCondition" style="width:120px;">
|
|
4
|
+
<el-option label="建档日期" value="建档日期"></el-option>
|
|
5
|
+
<el-option label="更新日期" value="更新日期"></el-option>
|
|
6
|
+
</el-select>
|
|
7
|
+
<el-select v-model="params.SearchType" style="width:120px;">
|
|
8
|
+
<el-option v-for="item in searchList" :key="item.value" :label="item.name" :value="item.value"></el-option>
|
|
9
|
+
</el-select>
|
|
10
|
+
<el-date-picker v-model="params.SearchValue" :style="'width:'+txtInputWidth+'px;'" value-format="yyyy-MM-dd" placeholder=""></el-date-picker>
|
|
11
|
+
</el-form-item>
|
|
12
|
+
</template>
|
|
13
|
+
<script>
|
|
14
|
+
export default {
|
|
15
|
+
name: "SearchDate",
|
|
16
|
+
props: {
|
|
17
|
+
searchList: {
|
|
18
|
+
type: Array,
|
|
19
|
+
default() {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
params: {
|
|
24
|
+
type: Object,
|
|
25
|
+
default() {
|
|
26
|
+
return {
|
|
27
|
+
SearchType: "",
|
|
28
|
+
SearchCondition: "建档日期",
|
|
29
|
+
SearchValue: ""
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
/** 查询文本输入框宽度 */
|
|
34
|
+
txtInputWidth: {
|
|
35
|
+
type: Number,
|
|
36
|
+
default: 130
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
created() {
|
|
40
|
+
if (this.searchList.length > 0 && !this.params.SearchType) {
|
|
41
|
+
this.params.SearchType = this.searchList[0].value;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
</script>
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div style="display:inline-block">
|
|
3
|
+
<FlexBox v-if="dateType=='quarter'" type="inline-flex" class="xt-date-picker" :class="{focus: isfocus}" :style="width?{width: `${width}px`}:{}">
|
|
4
|
+
<Quarter v-model="timeStart" :format="format" placeholder="开始时间" quarter-type="quarter-start" clearable></Quarter>
|
|
5
|
+
<span class="separator">{{ separator }}</span>
|
|
6
|
+
<Quarter v-model="timeEnd" :format="format" placeholder="结束时间" quarter-type="quarter-end" clearable></Quarter>
|
|
7
|
+
</FlexBox>
|
|
8
|
+
<FlexBox v-else type="inline-flex" class="xt-date" :class="{focus: isfocus}" :style="width?{width: `${width}px`}:{}">
|
|
9
|
+
<el-date-picker ref="timeStart" key="startSelect" v-model="timeStart" size="small" :disabled="disabled" append-to-body :picker-options="startTimeRange" :format="format" :type="dateType" placeholder="开始时间" clearable @blur="$emit('blur')" @focus="$emit('focus')"></el-date-picker>
|
|
10
|
+
<span class="separator">{{ separator }}</span>
|
|
11
|
+
<el-date-picker ref="timeEnd" key="endSelect" v-model="timeEnd" size="small" :disabled="disabled" append-to-body :picker-options="endTimeRange" :format="format" :type="dateType" placeholder="结束时间" clearable @blur="$emit('blur')" @focus="$emit('focus')"></el-date-picker>
|
|
12
|
+
</FlexBox>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
<script>
|
|
16
|
+
const typeFormatEnum = {
|
|
17
|
+
datetime: "yyyy-MM-dd HH:mm", month: "yyyy-MM", year: "yyyy", date: "yyyy-MM-dd", quarter: "yyyy-Qq", week: "yyyy-WW"
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
import FlexBox from '../flex-box/index.vue'
|
|
21
|
+
import Quarter from "./quarter.vue";
|
|
22
|
+
export default {
|
|
23
|
+
name: "XtDatePicker",
|
|
24
|
+
components: {
|
|
25
|
+
FlexBox,
|
|
26
|
+
Quarter
|
|
27
|
+
},
|
|
28
|
+
model: {
|
|
29
|
+
prop: "value",
|
|
30
|
+
event: "change"
|
|
31
|
+
},
|
|
32
|
+
props: {
|
|
33
|
+
value: {},
|
|
34
|
+
dateType: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: "date"
|
|
37
|
+
},
|
|
38
|
+
separator: {
|
|
39
|
+
type: String,
|
|
40
|
+
default: "至"
|
|
41
|
+
},
|
|
42
|
+
disabled: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: false
|
|
45
|
+
},
|
|
46
|
+
immediate: { // 是否直接初始化 参数
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: true
|
|
49
|
+
},
|
|
50
|
+
placeholder: {},
|
|
51
|
+
width: {
|
|
52
|
+
type: Number,
|
|
53
|
+
default: 280
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
data() {
|
|
57
|
+
return {
|
|
58
|
+
isfocus: false
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
computed: {
|
|
62
|
+
format() {
|
|
63
|
+
return typeFormatEnum[this.dateType] || "yyyy-MM-dd";
|
|
64
|
+
},
|
|
65
|
+
timeStart: {
|
|
66
|
+
get() {
|
|
67
|
+
return this.value && this.value[0];
|
|
68
|
+
},
|
|
69
|
+
set(v) {
|
|
70
|
+
this.$emit("update:value", [v, this.timeEnd]);
|
|
71
|
+
this.$emit("change", [v, this.timeEnd]);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
timeEnd: {
|
|
75
|
+
get() {
|
|
76
|
+
return this.value && this.value[1];
|
|
77
|
+
},
|
|
78
|
+
set(v) {
|
|
79
|
+
this.$emit("update:value", [this.timeStart, v]);
|
|
80
|
+
this.$emit("change", [this.timeStart, v]);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
startTimeRange() {
|
|
84
|
+
if (!this.timeEnd) return {};
|
|
85
|
+
const endTime = this.timeEnd.getTime();
|
|
86
|
+
return {
|
|
87
|
+
disabledDate: (time) => {
|
|
88
|
+
return time.getTime() > (endTime);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
endTimeRange() {
|
|
93
|
+
if (!this.timeStart) return {};
|
|
94
|
+
const startTime = this.timeStart.getTime();
|
|
95
|
+
return {
|
|
96
|
+
disabledDate: (time) => {
|
|
97
|
+
return time.getTime() < (startTime);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
methods: {
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
</script>
|
|
106
|
+
<style lang="scss" scoped>
|
|
107
|
+
.xt-date-picker{
|
|
108
|
+
width: 100%;
|
|
109
|
+
border-radius: 4px;
|
|
110
|
+
border: 1px solid #DCDFE6;
|
|
111
|
+
|
|
112
|
+
&.focus{
|
|
113
|
+
border-color: #1890FF;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
::v-deep .el-picker-panel{
|
|
117
|
+
position: absolute;
|
|
118
|
+
z-index: 401;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
::v-deep .el-input__inner{
|
|
122
|
+
border: none;
|
|
123
|
+
padding: 0;
|
|
124
|
+
text-align: center;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
::v-deep .el-input__prefix{
|
|
128
|
+
display: none;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
</style>
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-popover v-model="popoverVisible" trigger="click" :disabled="disabled" transition="el-zoom-in-top" :placement="placement" :width="popoverWidth" @hide="handleBlur">
|
|
3
|
+
<div class="quarter-wrapper">
|
|
4
|
+
<BaseFlexBox content="between">
|
|
5
|
+
<i class="el-icon-d-arrow-left" @click="prev"></i>
|
|
6
|
+
<span>{{ selectYear }}</span>
|
|
7
|
+
<i class="el-icon-d-arrow-right" @click="after"></i>
|
|
8
|
+
</BaseFlexBox>
|
|
9
|
+
<BaseFlexBox content="between" style="margin-top: 10px">
|
|
10
|
+
<el-button v-for="item in quarterList" :key="item.value" :disabled="getDisable(item)" :type="currentyear==selectYear&&item.value == currentQuarter ?'primary':''" size="mini" round @click="setCurrent(item)">{{ item.label }}</el-button>
|
|
11
|
+
</BaseFlexBox>
|
|
12
|
+
</div>
|
|
13
|
+
<el-input slot="reference" ref="reference" size="small" :value="quarterLabel" readonly :title="value" :placeholder="placeholder" prefix-icon="el-icon-date" clearable />
|
|
14
|
+
</el-popover>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
import BaseFlexBox from "../flex-box/index.vue";
|
|
19
|
+
import dateFns from "date-fns";
|
|
20
|
+
export default {
|
|
21
|
+
name: "DateQuarter",
|
|
22
|
+
components: {
|
|
23
|
+
BaseFlexBox
|
|
24
|
+
},
|
|
25
|
+
model: {
|
|
26
|
+
props: "value",
|
|
27
|
+
event: "change"
|
|
28
|
+
},
|
|
29
|
+
props: {
|
|
30
|
+
value: {},
|
|
31
|
+
quarterType: { // value绑定值类型 1.quarter为时返回当前时间 2.quarter-start时返回季的开始时间 3. quarter-end时返回季的结束时间
|
|
32
|
+
type: String,
|
|
33
|
+
default: "quarter"
|
|
34
|
+
},
|
|
35
|
+
placement: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: "bottom-start"
|
|
38
|
+
},
|
|
39
|
+
// valueFormat: {
|
|
40
|
+
// type: String,
|
|
41
|
+
// default: "yyyy-Qq"
|
|
42
|
+
// },
|
|
43
|
+
format: { // 同时支持字符串 "yyyy-Qq" 使用小写q进行格式化数据
|
|
44
|
+
type: String,
|
|
45
|
+
default: "yy-Qq"
|
|
46
|
+
},
|
|
47
|
+
popoverWidth: Number,
|
|
48
|
+
placeholder: {},
|
|
49
|
+
pickerOptions: {
|
|
50
|
+
type: Object,
|
|
51
|
+
default: () => {
|
|
52
|
+
return {
|
|
53
|
+
disabledDate: () => {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
disabled: {}
|
|
60
|
+
},
|
|
61
|
+
data() {
|
|
62
|
+
const dateVal = this.getQuarterDate(this.value);
|
|
63
|
+
const currentyear = dateVal ? dateVal.getFullYear() : "";
|
|
64
|
+
const month = dateVal ? dateVal.getMonth() : "";
|
|
65
|
+
const selectYear = dateVal ? dateVal.getFullYear() : new Date().getFullYear();
|
|
66
|
+
return {
|
|
67
|
+
dateVal: dateVal,
|
|
68
|
+
currentyear: currentyear,
|
|
69
|
+
currentQuarter: dateFns.getQuarter(dateVal),
|
|
70
|
+
selectYear: selectYear,
|
|
71
|
+
currentMonth: month,
|
|
72
|
+
popoverVisible: false,
|
|
73
|
+
quarterList: [
|
|
74
|
+
{ label: "Q1", value: 1 },
|
|
75
|
+
{ label: "Q2", value: 2 },
|
|
76
|
+
{ label: "Q3", value: 3 },
|
|
77
|
+
{ label: "Q4", value: 4 }
|
|
78
|
+
]
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
computed: {
|
|
82
|
+
diffQuarter() {
|
|
83
|
+
return (this.selectYear - this.currentyear) * 4 - this.currentQuarter;
|
|
84
|
+
},
|
|
85
|
+
quarterLabel: {
|
|
86
|
+
get() {
|
|
87
|
+
if (!this.currentyear || !this.currentQuarter) {
|
|
88
|
+
return "";
|
|
89
|
+
}
|
|
90
|
+
return this.getFormatVal();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
methods: {
|
|
95
|
+
getQuarterDate(val) {
|
|
96
|
+
if (!val) return null;
|
|
97
|
+
if (this.quarterType == "quarter-start") {
|
|
98
|
+
return dateFns.startOfQuarter(val);
|
|
99
|
+
} else if (this.quarterType == "quarter-end") {
|
|
100
|
+
return dateFns.endOfQuarter(val);
|
|
101
|
+
} else {
|
|
102
|
+
const currentQuarter = dateFns.getQuarter(val);
|
|
103
|
+
return dateFns.setQuarter(this.value, currentQuarter);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
getDisable(it) {
|
|
107
|
+
},
|
|
108
|
+
handleChangeVal(v) {
|
|
109
|
+
},
|
|
110
|
+
getFormatVal() {
|
|
111
|
+
if (!this.format) {
|
|
112
|
+
return `${this.currentyear}-Q${this.currentQuarter}`;
|
|
113
|
+
}
|
|
114
|
+
const formatMap = {
|
|
115
|
+
y: this.currentyear,
|
|
116
|
+
q: this.currentQuarter
|
|
117
|
+
};
|
|
118
|
+
const val = this.format.replace(/(y|q)+/g, (result, key) => {
|
|
119
|
+
const value = formatMap[key];
|
|
120
|
+
return value || "";
|
|
121
|
+
});
|
|
122
|
+
return val;
|
|
123
|
+
},
|
|
124
|
+
setCurrent(item) {
|
|
125
|
+
if (!this.dateVal) {
|
|
126
|
+
this.dateVal = new Date();
|
|
127
|
+
}
|
|
128
|
+
this.dateVal.setFullYear(this.selectYear);
|
|
129
|
+
this.dateVal = dateFns.setQuarter(this.dateVal, item.value);
|
|
130
|
+
this.$emit("change", this.dateVal);
|
|
131
|
+
this.currentQuarter = item.value;
|
|
132
|
+
this.currentyear = this.selectYear;
|
|
133
|
+
this.popoverVisible = false;
|
|
134
|
+
},
|
|
135
|
+
after() {
|
|
136
|
+
this.dateVal.setFullYear(this.dateVal.getFullYear() + 1);
|
|
137
|
+
this.selectYear = this.dateVal.getFullYear();
|
|
138
|
+
},
|
|
139
|
+
prev() {
|
|
140
|
+
this.dateVal.setFullYear(this.dateVal.getFullYear() - 1);
|
|
141
|
+
this.selectYear = this.dateVal.getFullYear();
|
|
142
|
+
},
|
|
143
|
+
handleBlur() {
|
|
144
|
+
this.$refs.reference.blur();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
</script>
|
|
149
|
+
|
|
150
|
+
<style>
|
|
151
|
+
|
|
152
|
+
</style>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ex-grid-box" :style="styleAttrs">
|
|
3
|
+
<slot></slot>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
name: "XtGridBox",
|
|
10
|
+
props: {
|
|
11
|
+
columns: {
|
|
12
|
+
type: [String, Array], // ["1fr","2fr", "20%"]
|
|
13
|
+
default: "1fr"
|
|
14
|
+
},
|
|
15
|
+
rows: { // 1
|
|
16
|
+
type: [String, Array], // ["1fr","2fr", "20%"]
|
|
17
|
+
default: "1fr"
|
|
18
|
+
},
|
|
19
|
+
gap: { type: String, default: "" }
|
|
20
|
+
},
|
|
21
|
+
computed: {
|
|
22
|
+
styleAttrs() {
|
|
23
|
+
const gridTemplateRows = (typeof this.rows !== "string") ? this.rows.join(" ") : this.rows;
|
|
24
|
+
const gridTemplateColumns = (typeof this.columns !== "string") ? this.columns.join(" ") : this.columns;
|
|
25
|
+
return this.gap ? {
|
|
26
|
+
gridTemplateColumns,
|
|
27
|
+
gridTemplateRows,
|
|
28
|
+
gap: this.gap.toString().split(" ").map(_getGap).join(" ")
|
|
29
|
+
} : {
|
|
30
|
+
gridTemplateColumns,
|
|
31
|
+
gridTemplateRows
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<style lang="scss">
|
|
39
|
+
.ex-grid-box{
|
|
40
|
+
display: grid;
|
|
41
|
+
}
|
|
42
|
+
</style>
|