xt-element-ui 1.3.4 → 1.4.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xt-element-ui",
3
- "version": "1.3.4",
3
+ "version": "1.4.0",
4
4
  "description": "基于 Vue 2.7 + ElementUI 的企业级组件库,提供丰富的自定义组件和扩展组件",
5
5
  "main": "lib/index.common.js",
6
6
  "module": "lib/index.esm.js",
@@ -14,6 +14,9 @@ export default {
14
14
  color: "#ffffff"
15
15
  }
16
16
  },
17
+ axisLabel: {
18
+ color: "#ffffff"
19
+ },
17
20
  line: {
18
21
  itemStyle: {
19
22
  },
@@ -24,7 +27,7 @@ export default {
24
27
  bar: {
25
28
  itemStyle: {
26
29
  borderRadius: 4
27
- }
30
+ },
28
31
  },
29
32
  pie: {
30
33
  roseType: "radius",
@@ -37,4 +37,13 @@
37
37
  @import './xt-grid-box/style/index.scss';
38
38
 
39
39
  // ExIcon 组件样式
40
- @import './ex-icon/style/index.scss';
40
+ @import './ex-icon/style/index.scss';
41
+
42
+ // Progress 组件样式
43
+ @import './xt-progress/style/index.scss';
44
+
45
+ // Tabs 组件样式
46
+ @import './xt-tabs/style/index.scss';
47
+
48
+ // Badge 组件样式
49
+ @import './xt-badge/style/index.scss';
@@ -0,0 +1,7 @@
1
+ import XtBadge from './index.vue'
2
+
3
+ XtBadge.install = function(Vue) {
4
+ Vue.component(XtBadge.name, XtBadge)
5
+ }
6
+
7
+ export default XtBadge
@@ -0,0 +1,71 @@
1
+ <template>
2
+ <span class="xt-badge" :class="[
3
+ `xt-badge--${type}`,
4
+ { 'xt-badge--dot': isDot },
5
+ { 'xt-badge--hidden': hidden },
6
+ { 'xt-badge--fixed': fixed }
7
+ ]">
8
+ <span class="xt-badge__content">
9
+ <slot></slot>
10
+ </span>
11
+ <span
12
+ v-if="!hidden && (value || isDot)"
13
+ class="xt-badge__badge"
14
+ :style="badgeStyle"
15
+ >
16
+ <template v-if="isDot"></template>
17
+ <template v-else-if="showOverflow && value > max">{{ max }}+</template>
18
+ <template v-else>{{ value }}</template>
19
+ </span>
20
+ </span>
21
+ </template>
22
+
23
+ <script>
24
+ export default {
25
+ name: 'XtBadge',
26
+ props: {
27
+ value: {
28
+ type: [Number, String],
29
+ default: ''
30
+ },
31
+ type: {
32
+ type: String,
33
+ default: 'primary',
34
+ validator: (val) => ['primary', 'success', 'warning', 'danger', 'info'].includes(val)
35
+ },
36
+ max: {
37
+ type: Number,
38
+ default: 99
39
+ },
40
+ isDot: {
41
+ type: Boolean,
42
+ default: false
43
+ },
44
+ hidden: {
45
+ type: Boolean,
46
+ default: false
47
+ },
48
+ showOverflow: {
49
+ type: Boolean,
50
+ default: true
51
+ },
52
+ fixed: {
53
+ type: Boolean,
54
+ default: false
55
+ },
56
+ color: {
57
+ type: String,
58
+ default: ''
59
+ }
60
+ },
61
+ computed: {
62
+ badgeStyle() {
63
+ const style = {}
64
+ if (this.color) {
65
+ style.backgroundColor = this.color
66
+ }
67
+ return style
68
+ }
69
+ }
70
+ }
71
+ </script>
@@ -0,0 +1,88 @@
1
+ @import '../../../styles/variables.scss';
2
+
3
+ .xt-badge {
4
+ position: relative;
5
+ display: inline-flex;
6
+ align-items: center;
7
+ }
8
+
9
+ .xt-badge__content {
10
+ display: inline-flex;
11
+ align-items: center;
12
+ }
13
+
14
+ .xt-badge__badge {
15
+ position: absolute;
16
+ top: -6px;
17
+ right: -8px;
18
+ min-width: 18px;
19
+ height: 18px;
20
+ padding: 0 5px;
21
+ border-radius: 9px;
22
+ font-size: 12px;
23
+ font-weight: 500;
24
+ line-height: 18px;
25
+ color: #ffffff;
26
+ text-align: center;
27
+ white-space: nowrap;
28
+ background: $xt-color-danger;
29
+ }
30
+
31
+ .xt-badge--dot .xt-badge__badge {
32
+ min-width: 8px;
33
+ width: 8px;
34
+ height: 8px;
35
+ padding: 0;
36
+ border-radius: 50%;
37
+ }
38
+
39
+ .xt-badge--fixed .xt-badge__badge {
40
+ top: -4px;
41
+ right: -4px;
42
+ }
43
+
44
+ .xt-badge--primary .xt-badge__badge {
45
+ background: $xt-color-primary;
46
+ }
47
+
48
+ .xt-badge--success .xt-badge__badge {
49
+ background: $xt-color-success;
50
+ }
51
+
52
+ .xt-badge--warning .xt-badge__badge {
53
+ background: $xt-color-warning;
54
+ }
55
+
56
+ .xt-badge--danger .xt-badge__badge {
57
+ background: $xt-color-danger;
58
+ }
59
+
60
+ .xt-badge--info .xt-badge__badge {
61
+ background: $xt-color-info;
62
+ }
63
+
64
+ .xt-badge--hidden {
65
+ display: none;
66
+ }
67
+
68
+ [data-theme='dark'], html.dark {
69
+ .xt-badge--primary .xt-badge__badge {
70
+ background: $xt-dark-color-primary;
71
+ }
72
+
73
+ .xt-badge--success .xt-badge__badge {
74
+ background: $xt-dark-color-success;
75
+ }
76
+
77
+ .xt-badge--warning .xt-badge__badge {
78
+ background: $xt-dark-color-warning;
79
+ }
80
+
81
+ .xt-badge--danger .xt-badge__badge {
82
+ background: $xt-dark-color-danger;
83
+ }
84
+
85
+ .xt-badge--info .xt-badge__badge {
86
+ background: $xt-dark-color-info;
87
+ }
88
+ }
@@ -1,17 +1,17 @@
1
1
  <template>
2
2
  <ex-card class="xt-card-item" :bordered="false" :class="{ [`is-${type}`]: type ? true : false}">
3
- <xt-text bold size="medium">{{ title }}</xt-text>
4
- <xt-flex-box>
5
- <div style="width: 50%;margin-bottom: 5px;">
3
+ <xt-flex-box content="between">
4
+ <div >
5
+ <div><xt-text bold size="extra-large">{{ title }}</xt-text></div>
6
6
  <xt-text bold size="large" v-model="value" format="thousand" :type="type" :decimals="0"></xt-text>
7
7
  <div style="margin: 5px 0;">
8
8
  <xt-text size="small">较昨日</xt-text>
9
9
  <xt-text v-model="change" format="normal" :type="diff > 0 ? 'success' : 'danger'" :suffix="diff > 0 ? '↑' : '↓'"></xt-text>
10
10
  </div>
11
11
  </div>
12
- <div style="flex: 1; height: 100%;">
12
+ <div style="height: 100%;">
13
13
  <slot name="icon">
14
- <xt-text size="extra-large" :type="type"><i class="el-icon-user"></i></xt-text>
14
+ <xt-text size="extra-large" :type="type"><ex-icon name="el-icon-user" :size="48" ></ex-icon></xt-text>
15
15
  </slot>
16
16
  </div>
17
17
  </xt-flex-box>
@@ -0,0 +1,7 @@
1
+ import XtProgress from './index.vue'
2
+
3
+ XtProgress.install = function(Vue) {
4
+ Vue.component(XtProgress.name, XtProgress)
5
+ }
6
+
7
+ export default XtProgress
@@ -0,0 +1,103 @@
1
+ <template>
2
+ <div class="xt-progress" :class="[
3
+ `xt-progress--${type}`,
4
+ `xt-progress--${size}`
5
+ ]">
6
+ <div v-if="type === 'line'" class="xt-progress__bar">
7
+ <div
8
+ class="xt-progress__bar-inner"
9
+ :style="{ width: `${percentage}%`, backgroundColor: color }"
10
+ >
11
+ <transition name="xt-progress-fade">
12
+ <div v-if="showText" class="xt-progress__bar-text">{{ percentage }}%</div>
13
+ </transition>
14
+ </div>
15
+ </div>
16
+
17
+ <div v-else-if="type === 'circle'" class="xt-progress__circle">
18
+ <svg :width="circleSize" :height="circleSize" class="xt-progress__circle-svg">
19
+ <circle
20
+ class="xt-progress__circle-bg"
21
+ :cx="circleSize / 2"
22
+ :cy="circleSize / 2"
23
+ :r="circleRadius"
24
+ fill="none"
25
+ :stroke="bgColor"
26
+ :stroke-width="strokeWidth"
27
+ />
28
+ <circle
29
+ class="xt-progress__circle-bar"
30
+ :cx="circleSize / 2"
31
+ :cy="circleSize / 2"
32
+ :r="circleRadius"
33
+ fill="none"
34
+ :stroke="color"
35
+ :stroke-width="strokeWidth"
36
+ :stroke-dasharray="circleLength"
37
+ :stroke-dashoffset="circleOffset"
38
+ stroke-linecap="round"
39
+ transform="rotate(-90 ${circleSize / 2} ${circleSize / 2})"
40
+ />
41
+ </svg>
42
+ <div v-if="showText" class="xt-progress__circle-text">
43
+ <span class="xt-progress__circle-percent">{{ percentage }}%</span>
44
+ </div>
45
+ </div>
46
+
47
+ <div v-if="showText && type === 'line'" class="xt-progress__text">{{ percentage }}%</div>
48
+ </div>
49
+ </template>
50
+
51
+ <script>
52
+ export default {
53
+ name: 'XtProgress',
54
+ props: {
55
+ percentage: {
56
+ type: Number,
57
+ default: 0,
58
+ validator: (val) => val >= 0 && val <= 100
59
+ },
60
+ type: {
61
+ type: String,
62
+ default: 'line',
63
+ validator: (val) => ['line', 'circle'].includes(val)
64
+ },
65
+ size: {
66
+ type: String,
67
+ default: 'medium',
68
+ validator: (val) => ['small', 'medium', 'large'].includes(val)
69
+ },
70
+ color: {
71
+ type: String,
72
+ default: '#1890ff'
73
+ },
74
+ bgColor: {
75
+ type: String,
76
+ default: '#ebeef5'
77
+ },
78
+ showText: {
79
+ type: Boolean,
80
+ default: true
81
+ },
82
+ strokeWidth: {
83
+ type: Number,
84
+ default: 6
85
+ },
86
+ circleSize: {
87
+ type: Number,
88
+ default: 120
89
+ }
90
+ },
91
+ computed: {
92
+ circleRadius() {
93
+ return (this.circleSize - this.strokeWidth) / 2
94
+ },
95
+ circleLength() {
96
+ return 2 * Math.PI * this.circleRadius
97
+ },
98
+ circleOffset() {
99
+ return this.circleLength * (1 - this.percentage / 100)
100
+ }
101
+ }
102
+ }
103
+ </script>
@@ -0,0 +1,119 @@
1
+ @import '../../../styles/variables.scss';
2
+
3
+ .xt-progress {
4
+ display: inline-flex;
5
+ align-items: center;
6
+ }
7
+
8
+ .xt-progress__bar {
9
+ flex: 1;
10
+ height: 6px;
11
+ background: $xt-color-border-light;
12
+ border-radius: 3px;
13
+ overflow: hidden;
14
+ position: relative;
15
+ }
16
+
17
+ .xt-progress--small .xt-progress__bar {
18
+ height: 4px;
19
+ }
20
+
21
+ .xt-progress--large .xt-progress__bar {
22
+ height: 8px;
23
+ }
24
+
25
+ .xt-progress__bar-inner {
26
+ height: 100%;
27
+ border-radius: 3px;
28
+ transition: width 0.3s ease;
29
+ position: relative;
30
+ }
31
+
32
+ .xt-progress__bar-text {
33
+ position: absolute;
34
+ right: -30px;
35
+ top: 50%;
36
+ transform: translateY(-50%);
37
+ font-size: 12px;
38
+ color: $xt-color-text-secondary;
39
+ }
40
+
41
+ .xt-progress__text {
42
+ margin-left: 10px;
43
+ font-size: 14px;
44
+ color: $xt-color-text-secondary;
45
+ }
46
+
47
+ .xt-progress--small .xt-progress__text {
48
+ font-size: 12px;
49
+ }
50
+
51
+ .xt-progress--large .xt-progress__text {
52
+ font-size: 16px;
53
+ }
54
+
55
+ .xt-progress__circle {
56
+ position: relative;
57
+ display: inline-flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ }
61
+
62
+ .xt-progress__circle-svg {
63
+ transform: rotate(-90deg);
64
+ }
65
+
66
+ .xt-progress__circle-bg {
67
+ transition: stroke 0.3s ease;
68
+ }
69
+
70
+ .xt-progress__circle-bar {
71
+ transition: stroke-dashoffset 0.6s ease;
72
+ }
73
+
74
+ .xt-progress__circle-text {
75
+ position: absolute;
76
+ display: flex;
77
+ flex-direction: column;
78
+ align-items: center;
79
+ justify-content: center;
80
+ }
81
+
82
+ .xt-progress__circle-percent {
83
+ font-size: 16px;
84
+ font-weight: 500;
85
+ color: $xt-color-text-primary;
86
+ }
87
+
88
+ .xt-progress--small .xt-progress__circle-percent {
89
+ font-size: 12px;
90
+ }
91
+
92
+ .xt-progress--large .xt-progress__circle-percent {
93
+ font-size: 20px;
94
+ }
95
+
96
+ .xt-progress-fade-enter-active,
97
+ .xt-progress-fade-leave-active {
98
+ transition: opacity 0.3s ease;
99
+ }
100
+
101
+ .xt-progress-fade-enter,
102
+ .xt-progress-fade-leave-to {
103
+ opacity: 0;
104
+ }
105
+
106
+ [data-theme='dark'], html.dark {
107
+ .xt-progress__bar {
108
+ background: $xt-dark-color-border;
109
+ }
110
+
111
+ .xt-progress__bar-text,
112
+ .xt-progress__text {
113
+ color: $xt-dark-color-text-secondary;
114
+ }
115
+
116
+ .xt-progress__circle-percent {
117
+ color: $xt-dark-color-text-primary;
118
+ }
119
+ }
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <div v-show="isActive" class="xt-tab-pane">
3
+ <slot></slot>
4
+ </div>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ name: 'XtTabPane',
10
+ props: {
11
+ name: {
12
+ type: [String, Number],
13
+ required: true
14
+ },
15
+ label: {
16
+ type: String,
17
+ default: ''
18
+ }
19
+ },
20
+ computed: {
21
+ isActive() {
22
+ return this.$parent && this.$parent.activeName === this.name
23
+ }
24
+ },
25
+ mounted() {
26
+ if (this.$parent && typeof this.$parent.addPane === 'function') {
27
+ this.$parent.addPane({ name: this.name, label: this.label })
28
+ }
29
+ },
30
+ beforeDestroy() {
31
+ if (this.$parent && typeof this.$parent.removePane === 'function') {
32
+ this.$parent.removePane(this.name)
33
+ }
34
+ }
35
+ }
36
+ </script>
@@ -0,0 +1,10 @@
1
+ import XtTabs from './index.vue'
2
+ import XtTabPane from './TabPane.vue'
3
+
4
+ XtTabs.install = function(Vue) {
5
+ Vue.component(XtTabs.name, XtTabs)
6
+ Vue.component(XtTabPane.name, XtTabPane)
7
+ }
8
+
9
+ export default XtTabs
10
+ export { XtTabPane }
@@ -0,0 +1,113 @@
1
+ <template>
2
+ <div class="xt-tabs" :class="[
3
+ `xt-tabs--${position}`,
4
+ { 'xt-tabs--card': type === 'card' }
5
+ ]">
6
+ <div class="xt-tabs__header">
7
+ <div class="xt-tabs__nav">
8
+ <div
9
+ v-for="(pane, index) in panes"
10
+ :key="pane.name"
11
+ class="xt-tabs__nav-item"
12
+ :class="{ 'xt-tabs__nav-item--active': activeName === pane.name }"
13
+ @click="handleTabClick(pane.name)"
14
+ >
15
+ <span class="xt-tabs__nav-link">{{ pane.label }}</span>
16
+ </div>
17
+ </div>
18
+ <div class="xt-tabs__nav-indicator" :style="indicatorStyle"></div>
19
+ </div>
20
+
21
+ <div class="xt-tabs__content">
22
+ <transition name="xt-tabs-fade" mode="out-in">
23
+ <div
24
+ v-for="(pane, index) in panes"
25
+ :key="pane.name"
26
+ class="xt-tabs__pane"
27
+ v-show="activeName === pane.name"
28
+ >
29
+ <slot :name="pane.name"></slot>
30
+ </div>
31
+ </transition>
32
+ </div>
33
+ </div>
34
+ </template>
35
+
36
+ <script>
37
+ export default {
38
+ name: 'XtTabs',
39
+ props: {
40
+ value: {
41
+ type: [String, Number],
42
+ default: ''
43
+ },
44
+ type: {
45
+ type: String,
46
+ default: 'default',
47
+ validator: (val) => ['default', 'card'].includes(val)
48
+ },
49
+ position: {
50
+ type: String,
51
+ default: 'top',
52
+ validator: (val) => ['top', 'bottom', 'left', 'right'].includes(val)
53
+ }
54
+ },
55
+ data() {
56
+ return {
57
+ panes: [],
58
+ activeName: this.value
59
+ }
60
+ },
61
+ watch: {
62
+ value(val) {
63
+ this.activeName = val
64
+ },
65
+ activeName(val) {
66
+ this.$emit('input', val)
67
+ this.$emit('change', val)
68
+ }
69
+ },
70
+ computed: {
71
+ indicatorStyle() {
72
+ const activeIndex = this.panes.findIndex(p => p.name === this.activeName)
73
+ if (activeIndex === -1) return { display: 'none' }
74
+
75
+ const navItems = this.$el && this.$el.querySelectorAll('.xt-tabs__nav-item')
76
+ if (!navItems || navItems.length === 0) return { display: 'none' }
77
+
78
+ const activeItem = navItems[activeIndex]
79
+ return {
80
+ left: `${activeItem.offsetLeft}px`,
81
+ width: `${activeItem.offsetWidth}px`,
82
+ display: 'block'
83
+ }
84
+ }
85
+ },
86
+ methods: {
87
+ handleTabClick(name) {
88
+ this.activeName = name
89
+ },
90
+ addPane(pane) {
91
+ if (!this.panes.find(p => p.name === pane.name)) {
92
+ this.panes.push(pane)
93
+ if (!this.activeName && this.panes.length === 1) {
94
+ this.activeName = pane.name
95
+ }
96
+ }
97
+ },
98
+ removePane(name) {
99
+ const index = this.panes.findIndex(p => p.name === name)
100
+ if (index > -1) {
101
+ this.panes.splice(index, 1)
102
+ }
103
+ }
104
+ },
105
+ mounted() {
106
+ this.$children.forEach(child => {
107
+ if (child.$options.name === 'XtTabPane') {
108
+ this.addPane({ name: child.name, label: child.label })
109
+ }
110
+ })
111
+ }
112
+ }
113
+ </script>