xt-element-ui 2.0.2 → 2.0.4

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.
@@ -0,0 +1,261 @@
1
+ <template>
2
+ <div class="xt-scroll-arrow" :class="[`xt-scroll-arrow--${direction}`]" :style="containerStyle">
3
+ <div
4
+ v-if="showLeftArrow"
5
+ class="xt-scroll-arrow__btn xt-scroll-arrow__btn--left"
6
+ @click="scrollLeft"
7
+ >
8
+ <i class="el-icon-arrow-left"></i>
9
+ </div>
10
+
11
+ <div ref="scrollContainer" class="xt-scroll-arrow__content" @scroll="handleScroll" @click="handleClick">
12
+ <slot></slot>
13
+ </div>
14
+
15
+ <div
16
+ v-if="showRightArrow"
17
+ class="xt-scroll-arrow__btn xt-scroll-arrow__btn--right"
18
+ @click="scrollRight"
19
+ >
20
+ <i class="el-icon-arrow-right"></i>
21
+ </div>
22
+
23
+ <div
24
+ v-if="showTopArrow && direction === 'vertical'"
25
+ class="xt-scroll-arrow__btn xt-scroll-arrow__btn--top"
26
+ @click="scrollTop"
27
+ >
28
+ <i class="el-icon-arrow-up"></i>
29
+ </div>
30
+
31
+ <div
32
+ v-if="showBottomArrow && direction === 'vertical'"
33
+ class="xt-scroll-arrow__btn xt-scroll-arrow__btn--bottom"
34
+ @click="scrollBottom"
35
+ >
36
+ <i class="el-icon-arrow-down"></i>
37
+ </div>
38
+ </div>
39
+ </template>
40
+
41
+ <script>
42
+ export default {
43
+ name: 'XtScrollArrow',
44
+ props: {
45
+ direction: {
46
+ type: String,
47
+ default: 'horizontal',
48
+ validator: (val) => ['horizontal', 'vertical'].includes(val)
49
+ },
50
+ scrollStep: {
51
+ type: Number,
52
+ default: 100
53
+ },
54
+ autoHide: {
55
+ type: Boolean,
56
+ default: true
57
+ },
58
+ height: {
59
+ type: [String, Number],
60
+ default: ''
61
+ },
62
+ width: {
63
+ type: [String, Number],
64
+ default: ''
65
+ },
66
+ appendMode: {
67
+ type: Boolean,
68
+ default: false
69
+ },
70
+ clickMode: {
71
+ type: Boolean,
72
+ default: false
73
+ }
74
+ },
75
+ data() {
76
+ return {
77
+ showLeftArrow: false,
78
+ showRightArrow: false,
79
+ showTopArrow: false,
80
+ showBottomArrow: false
81
+ }
82
+ },
83
+ computed: {
84
+ containerStyle() {
85
+ const style = {}
86
+ if (this.height) {
87
+ style.height = typeof this.height === 'number' ? `${this.height}px` : this.height
88
+ }
89
+ if (this.width) {
90
+ style.width = typeof this.width === 'number' ? `${this.width}px` : this.width
91
+ }
92
+ return style
93
+ }
94
+ },
95
+ watch: {
96
+ direction() {
97
+ this.$nextTick(() => {
98
+ this.checkScroll()
99
+ })
100
+ }
101
+ },
102
+ mounted() {
103
+ this.$nextTick(() => {
104
+ this.checkScroll()
105
+ })
106
+ this.addResizeObserver()
107
+ this.addMutationObserver()
108
+ },
109
+ beforeDestroy() {
110
+ this.removeResizeObserver()
111
+ this.removeMutationObserver()
112
+ },
113
+ methods: {
114
+ addResizeObserver() {
115
+ if (typeof ResizeObserver !== 'undefined') {
116
+ this.resizeObserver = new ResizeObserver(() => {
117
+ this.$nextTick(() => {
118
+ this.checkScroll()
119
+ })
120
+ })
121
+ const container = this.$refs.scrollContainer
122
+ if (container) {
123
+ this.resizeObserver.observe(container)
124
+ }
125
+ }
126
+ },
127
+ removeResizeObserver() {
128
+ if (this.resizeObserver) {
129
+ this.resizeObserver.disconnect()
130
+ }
131
+ },
132
+ addMutationObserver() {
133
+ if (typeof MutationObserver !== 'undefined') {
134
+ this.mutationObserver = new MutationObserver(() => {
135
+ this.$nextTick(() => {
136
+ this.checkScroll()
137
+ if (this.appendMode) {
138
+ this.scrollToEnd()
139
+ }
140
+ })
141
+ })
142
+ const container = this.$refs.scrollContainer
143
+ if (container) {
144
+ this.mutationObserver.observe(container, {
145
+ childList: true,
146
+ subtree: true
147
+ })
148
+ }
149
+ }
150
+ },
151
+ removeMutationObserver() {
152
+ if (this.mutationObserver) {
153
+ this.mutationObserver.disconnect()
154
+ }
155
+ },
156
+ checkScroll() {
157
+ const container = this.$refs.scrollContainer
158
+ if (!container) return
159
+
160
+ if (this.direction === 'horizontal') {
161
+ const scrollLeft = container.scrollLeft
162
+ const scrollWidth = container.scrollWidth
163
+ const clientWidth = container.clientWidth
164
+ const maxScroll = scrollWidth - clientWidth
165
+
166
+ this.showTopArrow = false
167
+ this.showBottomArrow = false
168
+
169
+ if (this.autoHide) {
170
+ this.showLeftArrow = scrollLeft > 0
171
+ this.showRightArrow = maxScroll > 0 && scrollLeft < maxScroll
172
+ } else {
173
+ this.showLeftArrow = maxScroll > 0
174
+ this.showRightArrow = maxScroll > 0
175
+ }
176
+ } else {
177
+ const scrollTop = container.scrollTop
178
+ const scrollHeight = container.scrollHeight
179
+ const clientHeight = container.clientHeight
180
+ const maxScroll = scrollHeight - clientHeight
181
+
182
+ this.showLeftArrow = false
183
+ this.showRightArrow = false
184
+
185
+ if (this.autoHide) {
186
+ this.showTopArrow = scrollTop > 0
187
+ this.showBottomArrow = maxScroll > 0 && scrollTop < maxScroll
188
+ } else {
189
+ this.showTopArrow = maxScroll > 0
190
+ this.showBottomArrow = maxScroll > 0
191
+ }
192
+ }
193
+ },
194
+ handleScroll() {
195
+ this.checkScroll()
196
+ this.$emit('scroll', this.$refs.scrollContainer)
197
+ },
198
+ handleClick(e) {
199
+ if (!this.clickMode) return
200
+ const container = this.$refs.scrollContainer
201
+ if (!container) return
202
+
203
+ const target = e.target
204
+ if (!target || target === container) return
205
+
206
+ const containerRect = container.getBoundingClientRect()
207
+ const targetRect = target.getBoundingClientRect()
208
+
209
+ const isVisible = (
210
+ targetRect.left >= containerRect.left &&
211
+ targetRect.right <= containerRect.right &&
212
+ targetRect.top >= containerRect.top &&
213
+ targetRect.bottom <= containerRect.bottom
214
+ )
215
+
216
+ if (!isVisible) {
217
+ if (this.direction === 'horizontal') {
218
+ const scrollLeft = target.offsetLeft - (container.clientWidth - targetRect.width) / 2
219
+ container.scrollTo({ left: scrollLeft, behavior: 'smooth' })
220
+ } else {
221
+ const scrollTop = target.offsetTop - (container.clientHeight - targetRect.height) / 2
222
+ container.scrollTo({ top: scrollTop, behavior: 'smooth' })
223
+ }
224
+ }
225
+ },
226
+ scrollLeft() {
227
+ const container = this.$refs.scrollContainer
228
+ if (container) {
229
+ container.scrollBy({ left: -this.scrollStep, behavior: 'smooth' })
230
+ }
231
+ },
232
+ scrollRight() {
233
+ const container = this.$refs.scrollContainer
234
+ if (container) {
235
+ container.scrollBy({ left: this.scrollStep, behavior: 'smooth' })
236
+ }
237
+ },
238
+ scrollTop() {
239
+ const container = this.$refs.scrollContainer
240
+ if (container) {
241
+ container.scrollBy({ top: -this.scrollStep, behavior: 'smooth' })
242
+ }
243
+ },
244
+ scrollBottom() {
245
+ const container = this.$refs.scrollContainer
246
+ if (container) {
247
+ container.scrollBy({ top: this.scrollStep, behavior: 'smooth' })
248
+ }
249
+ },
250
+ scrollToEnd() {
251
+ const container = this.$refs.scrollContainer
252
+ if (!container) return
253
+ if (this.direction === 'horizontal') {
254
+ container.scrollTo({ left: container.scrollWidth, behavior: 'smooth' })
255
+ } else {
256
+ container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' })
257
+ }
258
+ }
259
+ }
260
+ }
261
+ </script>
@@ -0,0 +1,89 @@
1
+ @import '../../../styles/variables.scss';
2
+
3
+ .xt-scroll-arrow {
4
+ position: relative;
5
+ display: flex;
6
+ align-items: center;
7
+ overflow: hidden;
8
+
9
+ &--horizontal {
10
+ flex-direction: row;
11
+ }
12
+
13
+ &--vertical {
14
+ flex-direction: column;
15
+ }
16
+
17
+ &__content {
18
+ flex: 1;
19
+ overflow: auto;
20
+ scrollbar-width: none;
21
+ -ms-overflow-style: none;
22
+
23
+ &::-webkit-scrollbar {
24
+ display: none;
25
+ }
26
+ }
27
+
28
+ &__btn {
29
+ position: absolute;
30
+ z-index: 10;
31
+ width: 32px;
32
+ height: 32px;
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ background: rgba(255, 255, 255, 0.9);
37
+ border-radius: 50%;
38
+ cursor: pointer;
39
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
40
+ transition: all 0.3s ease;
41
+ border: none;
42
+ padding: 0;
43
+
44
+ &:hover {
45
+ background: rgba(255, 255, 255, 1);
46
+ transform: scale(1.1);
47
+ }
48
+
49
+ &:active {
50
+ transform: scale(0.95);
51
+ }
52
+
53
+ &--left {
54
+ left: 8px;
55
+ }
56
+
57
+ &--right {
58
+ right: 8px;
59
+ }
60
+
61
+ &--top {
62
+ top: 8px;
63
+ left: 50%;
64
+ transform: translateX(-50%);
65
+
66
+ &:hover {
67
+ transform: translateX(-50%) scale(1.1);
68
+ }
69
+
70
+ &:active {
71
+ transform: translateX(-50%) scale(0.95);
72
+ }
73
+ }
74
+
75
+ &--bottom {
76
+ bottom: 8px;
77
+ left: 50%;
78
+ transform: translateX(-50%);
79
+
80
+ &:hover {
81
+ transform: translateX(-50%) scale(1.1);
82
+ }
83
+
84
+ &:active {
85
+ transform: translateX(-50%) scale(0.95);
86
+ }
87
+ }
88
+ }
89
+ }
@@ -331,9 +331,6 @@ export default {
331
331
  }
332
332
  .el-input{
333
333
  &:hover:not(.is-disabled) {
334
- .el-input__inner{
335
- @include border_color("borderColor");
336
- }
337
334
  &.is-selected.isclearable{
338
335
  .el-input__icon{
339
336
  &.close{
@@ -349,9 +346,6 @@ export default {
349
346
  .el-input__icon-arrow-down{
350
347
  transition: rotate(-180deg);
351
348
  }
352
- .el-input__inner{
353
- @include border_color("$subMenuActiveText");
354
- }
355
349
  }
356
350
  }
357
351
  }
@@ -380,7 +374,6 @@ export default {
380
374
  }
381
375
  .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content{
382
376
  color: #409EFF;
383
- @include font_color("primaryColor");
384
377
  font-weight: bold;
385
378
  }
386
379
  </style>
@@ -33,6 +33,7 @@
33
33
  :right-bracket="rightBracket"
34
34
  :field-keys="fieldKeys"
35
35
  :disabled="disabled"
36
+ :allow-negative="allowNegative"
36
37
  @input="(val) => onItemInput(val, idx)"
37
38
  @max-change="onMaxChange"
38
39
  @min-change="onMinChange"
@@ -100,6 +101,7 @@ export default {
100
101
  // 阶梯增量:新增/校正时,下一条阶梯的 min = 当前 max = 当前 min + step(默认 1)
101
102
  step: { type: Number, default: 10 },
102
103
  disabled: { type: Boolean, default: false },
104
+ allowNegative: { type: Boolean, default: false },
103
105
  tip: {
104
106
  type: String,
105
107
  default: '区间左闭右闭 [min, max],最后一级为 [min, +∞),保证连续且不重叠。'
@@ -217,7 +219,7 @@ export default {
217
219
  message: `第${i + 1}${this.stepName}价格不能为空`,
218
220
  type: 'error'
219
221
  })
220
- } else if (price < 0) {
222
+ } else if (price < 0 && !this.allowNegative) {
221
223
  errors.push({
222
224
  field: `stepPrice[${i}].price`,
223
225
  message: `第${i + 1}${this.stepName}价格不能为负数`,
@@ -231,7 +233,7 @@ export default {
231
233
  message: `第${i + 1}${this.stepName}下限不能为空`,
232
234
  type: 'error'
233
235
  })
234
- } else if (min < 0) {
236
+ } else if (min < 0 && !this.allowNegative) {
235
237
  errors.push({
236
238
  field: `stepPrice[${i}].min`,
237
239
  message: `第${i + 1}${this.stepName}下限不能为负数`,
@@ -67,6 +67,7 @@ export default {
67
67
  itemsLength: { type: Number, default: 1 },
68
68
  removable: { type: Boolean, default: true },
69
69
  disabled: { type: Boolean, default: false },
70
+ allowNegative: { type: Boolean, default: false },
70
71
  minLocked: { type: Boolean, default: false },
71
72
  unit: { type: String, default: '元' },
72
73
  precision: { type: Number, default: 2 },
@@ -187,7 +188,7 @@ export default {
187
188
  return
188
189
  }
189
190
  let v = this.safeNumber(rawVal, 0)
190
- if (v < 0) v = 0
191
+ if (v < 0 && !this.allowNegative) v = 0
191
192
  v = Number(v.toFixed(this.precision))
192
193
  this.priceInput = v
193
194
  this.emitChange({ [this.keyPrice]: v })
@@ -37,8 +37,8 @@
37
37
  </template>
38
38
  <script>
39
39
  import ImageViewer from "./preview.vue";
40
- import { getToken } from "@/utils/auth";
41
40
  export default {
41
+ name: "XtUpload",
42
42
  components: {
43
43
  ImageViewer
44
44
  },
@@ -58,6 +58,10 @@ export default {
58
58
  default: "",
59
59
  required: true
60
60
  },
61
+ accessToken: {
62
+ type: String,
63
+ default: ""
64
+ },
61
65
  autoUpload: {
62
66
  type: Boolean,
63
67
  default: true
@@ -111,14 +115,7 @@ export default {
111
115
  },
112
116
  data() {
113
117
  return {
114
- accessToken: getToken(),
115
118
  YSSQP: this.baseUrl,
116
- // upload: {
117
- // data: { accessToken: getToken() },
118
- // limit: 5,
119
- // accept: ".jpg,.png,.pdf",
120
- // multiple: false
121
- // },
122
119
  previewVisible: false,
123
120
  uploading: false,
124
121
  imageUrl: "",
package/src/index.js CHANGED
@@ -37,6 +37,14 @@ import XtDatePicker from './components/xt-date-picker'
37
37
  import XtChart from './components/xt-chart' // XtChart 组件(基于 ECharts 封装)
38
38
  import XtIcon from './components/xt-icon' // XtIcon 组件(支持 el-icon / svg / 自定义字体)
39
39
  import XtTable from './components/xt-table' // XtTable 组件(基于 ElementUI Table 封装)
40
+ import XtScrollArrow from './components/xt-scroll-arrow'
41
+ import XtBar from './components/xt-chart/XtBar.vue'
42
+ import XtLine from './components/xt-chart/XtLine.vue'
43
+ import XtPie from './components/xt-chart/XtPie.vue'
44
+ import XtMulti from './components/xt-chart/XtMulti.vue'
45
+ import XtPage from './components/xt-page'
46
+ import XtSelectTree from './components/xt-select-tree'
47
+ import XtUpload from './components/xt-upload'
40
48
 
41
49
 
42
50
  const components = [
@@ -60,7 +68,15 @@ const components = [
60
68
  XtDatePicker,
61
69
  XtChart,
62
70
  XtIcon,
63
- XtTable
71
+ XtTable,
72
+ XtScrollArrow,
73
+ XtBar,
74
+ XtLine,
75
+ XtPie,
76
+ XtMulti,
77
+ XtPage,
78
+ XtSelectTree,
79
+ XtUpload
64
80
  ]
65
81
 
66
82
  const install = function (Vue, options = {}) {
@@ -129,7 +145,15 @@ export default {
129
145
  XtBadge,
130
146
  XtDatePicker,
131
147
  XtIcon,
132
- XtTable
148
+ XtTable,
149
+ XtScrollArrow,
150
+ XtBar,
151
+ XtLine,
152
+ XtPie,
153
+ XtMulti,
154
+ XtPage,
155
+ XtSelectTree,
156
+ XtUpload
133
157
  }
134
158
 
135
159
  // XtChart 组件按需导出(使用时需自行安装 echarts 依赖)
@@ -1,93 +0,0 @@
1
- <template>
2
- <FlexBox
3
- v-if="iconType=='border'"
4
- class="xt-card-item is-border"
5
- :class="[iconType=='border'?`is-${type}`:'']"
6
- :style="cardItemStyle"
7
- content="between"
8
- >
9
- <span class="item__label" v-if="title">
10
- <slot name="label">{{ label }}</slot>
11
- </span>
12
- <span class="item__value">
13
- <slot name="value">{{ value }}</slot>
14
- </span>
15
- <span class="item__unit">
16
- <slot name="unit">{{ unit }}</slot>
17
- </span>
18
- </FlexBox>
19
- <FlexBox
20
- v-else
21
- class="xt-card-item"
22
- :direction="direction"
23
- :content="contentAlign"
24
- >
25
- <slot name="icon">
26
- <el-button :type="type" :circle="circle" :round="round" plain :icon="icon"></el-button>
27
- </slot>
28
- <div class="item__value">
29
- <span class="value" :style="valueStyle">
30
- <slot name="value">{{ label }}</slot>
31
- </span>
32
- <div class="unit">{{ value }}</div>
33
- </div>
34
- </FlexBox>
35
- </template>
36
- <script>
37
- import FlexBox from '../xt-flex-box/index.vue'
38
- export default {
39
- name: "XtCardItem",
40
- components: {
41
- FlexBox
42
- },
43
- props: {
44
- iconType: { default: "border" },
45
- type: { default: "primary" },
46
- label: {},
47
- value: {},
48
- unit: {},
49
- icon: {},
50
- iconAt: { default: "right" },
51
- color: {
52
- type: String,
53
- default: ''
54
- }
55
- },
56
- data() {
57
- return {
58
- circle: false,
59
- round: false
60
- }
61
- },
62
- computed: {
63
- contentAlign() {
64
- return this.iconAt == 'center' ? 'center' : 'start'
65
- },
66
- direction() {
67
- const iconAtMap = {
68
- left: 'row',
69
- right: 'row-reverse',
70
- top: 'column',
71
- bottom: 'column-reverse'
72
- }
73
- return iconAtMap[this.iconAt]
74
- },
75
- cardItemStyle() {
76
- if (this.iconType === 'border' && this.type === 'primary' && this.color) {
77
- return {
78
- '--xt-card-item-color': this.color
79
- }
80
- }
81
- return {}
82
- },
83
- valueStyle() {
84
- if (this.iconType !== 'border' && this.type === 'primary' && this.color) {
85
- return {
86
- color: this.color
87
- }
88
- }
89
- return {}
90
- }
91
- }
92
- }
93
- </script>