rrj-astra-ui 1.0.2

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 (38) hide show
  1. package/README.en.md +36 -0
  2. package/README.md +37 -0
  3. package/components/AuiBadge.vue +50 -0
  4. package/components/AuiBlockBox.vue +85 -0
  5. package/components/AuiButton.vue +210 -0
  6. package/components/AuiCustomerForm.vue +304 -0
  7. package/components/AuiDivider.vue +66 -0
  8. package/components/AuiFold.vue +40 -0
  9. package/components/AuiFoldItem.vue +173 -0
  10. package/components/AuiForm.vue +76 -0
  11. package/components/AuiFormItem.vue +88 -0
  12. package/components/AuiGrid.vue +26 -0
  13. package/components/AuiGridItem.vue +20 -0
  14. package/components/AuiIcon.vue +145 -0
  15. package/components/AuiImage.vue +152 -0
  16. package/components/AuiInput.vue +176 -0
  17. package/components/AuiLamp.vue +254 -0
  18. package/components/AuiLineProgress.vue +169 -0
  19. package/components/AuiList.vue +18 -0
  20. package/components/AuiListItem.vue +142 -0
  21. package/components/AuiMultiSelect.vue +303 -0
  22. package/components/AuiNoticeBar.vue +62 -0
  23. package/components/AuiNumberBox.vue +282 -0
  24. package/components/AuiPicker.vue +619 -0
  25. package/components/AuiPopup.vue +57 -0
  26. package/components/AuiSelectGroup.vue +312 -0
  27. package/components/AuiTab.vue +173 -0
  28. package/components/AuiTabItem.vue +43 -0
  29. package/components/AuiTable.vue +357 -0
  30. package/components/AuiTag.vue +112 -0
  31. package/components/AuiText.vue +81 -0
  32. package/components/AuiTextarea.vue +203 -0
  33. package/components/AuiToast.vue +96 -0
  34. package/components/AuiUpdate.vue +271 -0
  35. package/components/AuiUpload.vue +524 -0
  36. package/index.js +93 -0
  37. package/package.json +36 -0
  38. package/style.scss +30 -0
@@ -0,0 +1,254 @@
1
+ <template>
2
+ <div class="aui-lamp-container">
3
+ <!-- 左侧呼吸灯 -->
4
+ <div
5
+ ref="leftLamp"
6
+ class="aui-lamp-left"
7
+ :style="{ backgroundColor: lampColor, opacity: leftLampOpacity }"
8
+ ></div>
9
+
10
+ <!-- 右侧呼吸灯 -->
11
+ <div
12
+ ref="rightLamp"
13
+ class="aui-lamp-right"
14
+ :style="{ backgroundColor: lampColor, opacity: rightLampOpacity }"
15
+ ></div>
16
+ </div>
17
+ </template>
18
+
19
+ <script setup>
20
+ import { ref, onMounted, onUnmounted, watch, nextTick, computed } from 'vue';
21
+
22
+ const __name = 'AuiLamp';
23
+ defineOptions({ name: __name });
24
+
25
+ // 定义组件属性
26
+ const props = defineProps({
27
+ // 呼吸灯颜色
28
+ color: {
29
+ type: String,
30
+ default: '#EF4444' // 错误红色作为默认值
31
+ },
32
+ // 自动关闭时间(毫秒),0表示不自动关闭
33
+ autoCloseTime: {
34
+ type: Number,
35
+ default: 3000 // 默认3秒后关闭
36
+ },
37
+ // 是否显示呼吸灯
38
+ visible: {
39
+ type: Boolean,
40
+ default: false
41
+ },
42
+ // 主题
43
+ theme: {
44
+ type: String,
45
+ default: 'normal',
46
+ validator: (value) => ['normal', 'flat', 'grey', 'white', 'none'].includes(value)
47
+ }
48
+ });
49
+
50
+ // 定义组件事件
51
+ const emits = defineEmits(['update:visible', 'closed', 'update:color', 'update:autoCloseTime']);
52
+
53
+ // 左侧灯透明度
54
+ const leftLampOpacity = ref(0);
55
+ // 右侧灯透明度
56
+ const rightLampOpacity = ref(0);
57
+ // 动画定时器
58
+ let animationTimer = null;
59
+ // 关闭定时器
60
+ let closeTimer = null;
61
+ // 呼吸灯元素引用
62
+ const leftLamp = ref(null);
63
+ const rightLamp = ref(null);
64
+ // 动画状态
65
+ const isAnimating = ref(false);
66
+
67
+ // 计算属性:灯的颜色
68
+ const lampColor = computed(() => {
69
+ // 根据主题调整颜色(保持与AUI主题一致)
70
+ if (props.theme === 'flat' || props.theme === 'grey') {
71
+ return props.color;
72
+ } else if (props.theme === 'white') {
73
+ return props.color;
74
+ } else {
75
+ return props.color;
76
+ }
77
+ });
78
+
79
+ // 启动呼吸动画
80
+ const startAnimation = () => {
81
+ if (isAnimating.value) return;
82
+
83
+ isAnimating.value = true;
84
+ let opacity = 0.3;
85
+ let direction = 1; // 1表示增加,-1表示减少
86
+
87
+ animationTimer = setInterval(() => {
88
+ if (!props.visible) {
89
+ stopAnimation();
90
+ return;
91
+ }
92
+
93
+ opacity += 0.05 * direction;
94
+
95
+ if (opacity >= 1) {
96
+ opacity = 1;
97
+ direction = -1;
98
+ } else if (opacity <= 0.3) {
99
+ opacity = 0.3;
100
+ direction = 1;
101
+ }
102
+
103
+ leftLampOpacity.value = opacity;
104
+ rightLampOpacity.value = opacity;
105
+
106
+ }, 100);
107
+ };
108
+
109
+ // 停止呼吸动画
110
+ const stopAnimation = () => {
111
+ if (animationTimer) {
112
+ clearInterval(animationTimer);
113
+ animationTimer = null;
114
+ isAnimating.value = false;
115
+ }
116
+ };
117
+
118
+ // 启动自动关闭
119
+ const startAutoClose = () => {
120
+ stopAutoClose(); // 先清除已有的定时器
121
+
122
+ if (props.autoCloseTime > 0) {
123
+ closeTimer = setTimeout(() => {
124
+ hideLamp();
125
+ }, props.autoCloseTime);
126
+ }
127
+ };
128
+
129
+ // 停止自动关闭
130
+ const stopAutoClose = () => {
131
+ if (closeTimer) {
132
+ clearTimeout(closeTimer);
133
+ closeTimer = null;
134
+ }
135
+ };
136
+
137
+ // 显示呼吸灯
138
+ const showLamp = () => {
139
+ if (!props.visible) {
140
+ emits('update:visible', true);
141
+
142
+ nextTick(() => {
143
+ leftLampOpacity.value = 0.3;
144
+ rightLampOpacity.value = 0.3;
145
+ startAnimation();
146
+ startAutoClose();
147
+ });
148
+ }
149
+ };
150
+
151
+ // 隐藏呼吸灯
152
+ const hideLamp = () => {
153
+ if (props.visible) {
154
+ emits('update:visible', false);
155
+ stopAnimation();
156
+ stopAutoClose();
157
+ leftLampOpacity.value = 0;
158
+ rightLampOpacity.value = 0;
159
+ emits('closed');
160
+ }
161
+ };
162
+
163
+ // 监听visible属性变化
164
+ watch(() => props.visible, (newValue, oldValue) => {
165
+ // 防止初始渲染时触发
166
+ if (oldValue !== undefined) {
167
+ if (newValue) {
168
+ showLamp();
169
+ } else {
170
+ hideLamp();
171
+ }
172
+ }
173
+ });
174
+
175
+ // 监听颜色变化
176
+ watch(() => props.color, (newColor) => {
177
+ // 如果灯正在显示,更新颜色
178
+ if (props.visible && leftLamp.value && rightLamp.value) {
179
+ leftLamp.value.style.backgroundColor = newColor;
180
+ rightLamp.value.style.backgroundColor = newColor;
181
+ }
182
+ });
183
+
184
+ // 组件挂载时初始化
185
+ onMounted(() => {
186
+ // 设置灯带样式
187
+ if (leftLamp.value && rightLamp.value) {
188
+ leftLamp.value.style.cssText = `
189
+ position: fixed;
190
+ left: 0;
191
+ top: 0;
192
+ height: 100vh;
193
+ width: 10px;
194
+ z-index: 9999;
195
+ pointer-events: none;
196
+ transition: opacity 0.3s ease;
197
+ `;
198
+
199
+ rightLamp.value.style.cssText = `
200
+ position: fixed;
201
+ right: 0;
202
+ top: 0;
203
+ height: 100vh;
204
+ width: 10px;
205
+ z-index: 9999;
206
+ pointer-events: none;
207
+ transition: opacity 0.3s ease;
208
+ `;
209
+
210
+ // 如果初始visible为true,则启动动画
211
+ if (props.visible) {
212
+ nextTick(() => {
213
+ startAnimation();
214
+ startAutoClose();
215
+ });
216
+ }
217
+ }
218
+ });
219
+
220
+ // 组件卸载时清理
221
+ onUnmounted(() => {
222
+ stopAnimation();
223
+ stopAutoClose();
224
+ });
225
+
226
+ // 暴露公共方法
227
+ const api = {
228
+ show: showLamp,
229
+ hide: hideLamp,
230
+ setColor: (color) => {
231
+ emits('update:color', color);
232
+ },
233
+ setAutoCloseTime: (time) => {
234
+ emits('update:autoCloseTime', time);
235
+ }
236
+ };
237
+
238
+ // 导出组件方法
239
+ defineExpose(api);
240
+ </script>
241
+
242
+ <style scoped lang="scss">
243
+ @import '../style.scss';
244
+
245
+ .aui-lamp-container {
246
+ position: relative;
247
+ width: 100%;
248
+ height: 100%;
249
+ }
250
+
251
+ .aui-lamp-left, .aui-lamp-right {
252
+ will-change: opacity;
253
+ }
254
+ </style>
@@ -0,0 +1,169 @@
1
+ <template>
2
+ <div class="aui-line-progress" :class="classes">
3
+ <div class="progress-bar" :style="barStyle">
4
+ <div class="progress-text" v-if="showText">
5
+ {{ formatText }}
6
+ </div>
7
+ </div>
8
+ </div>
9
+ </template>
10
+
11
+ <script setup>
12
+ import { computed, defineProps, ref, watch } from 'vue'
13
+
14
+ const _name="AuiLineProgress";
15
+ defineOptions({
16
+ name:_name
17
+ })
18
+ const props = defineProps({
19
+ // 进度百分比
20
+ percentage: {
21
+ type: Number,
22
+ default: 0,
23
+ validator: (val) => val >= 0 && val <= 100
24
+ },
25
+ // 进度条高度(px)
26
+ height: {
27
+ type: Number,
28
+ default: 8
29
+ },
30
+ // 是否显示进度文字
31
+ showText: {
32
+ type: Boolean,
33
+ default: true
34
+ },
35
+ // 进度条颜色
36
+ color: {
37
+ type: String,
38
+ default: '#165DFF'
39
+ },
40
+ // 进度条背景色
41
+ backgroundColor: {
42
+ type: String,
43
+ default: '#E5E6EB'
44
+ },
45
+ // 文字显示类型
46
+ textType: {
47
+ type: String,
48
+ default: 'percentage',
49
+ validator: (val) => ['percentage', 'number', 'none'].includes(val)
50
+ },
51
+ // 是否为条纹进度条
52
+ striped: {
53
+ type: Boolean,
54
+ default: false
55
+ },
56
+ // 是否为动画条纹
57
+ stripedAnimation: {
58
+ type: Boolean,
59
+ default: false
60
+ },
61
+ // 进度条状态
62
+ status: {
63
+ type: String,
64
+ default: '',
65
+ validator: (val) => ['success', 'warning', 'error', ''].includes(val)
66
+ },
67
+ // 自定义文字内容
68
+ customText: {
69
+ type: String,
70
+ default: ''
71
+ }
72
+ })
73
+
74
+ // 计算进度条样式
75
+ const barStyle = computed(() => {
76
+ const style = {
77
+ width: `${props.percentage}%`,
78
+ height: `${props.height}px`,
79
+ backgroundColor: getStatusColor()
80
+ }
81
+
82
+ if (props.striped || props.stripedAnimation) {
83
+ style.backgroundImage = 'linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)'
84
+ style.backgroundSize = '40px 40px'
85
+ }
86
+
87
+ if (props.stripedAnimation) {
88
+ style.animation = 'aui-progress-bar-stripes 1s linear infinite'
89
+ }
90
+
91
+ return style
92
+ })
93
+
94
+ // 获取状态颜色
95
+ const getStatusColor = () => {
96
+ if (props.status === 'success') return '#00B42A'
97
+ if (props.status === 'warning') return '#FF7D00'
98
+ if (props.status === 'error') return '#F53F3F'
99
+ return props.color
100
+ }
101
+
102
+ // 计算组件类
103
+ const classes = computed(() => {
104
+ const cls = ['aui-line-progress']
105
+ if (props.status) cls.push(`status-${props.status}`)
106
+ return cls
107
+ })
108
+
109
+ // 格式化显示文本
110
+ const formatText = computed(() => {
111
+ if (props.textType === 'none') return ''
112
+ if (props.customText) return props.customText
113
+
114
+ if (props.textType === 'percentage') {
115
+ return `${props.percentage}%`
116
+ }
117
+
118
+ return props.percentage
119
+ })
120
+ </script>
121
+
122
+ <style scoped>
123
+ .aui-line-progress {
124
+ width: 100%;
125
+ background-color: var(--background-color, #E5E6EB);
126
+ border-radius: 100px;
127
+ overflow: hidden;
128
+ position: relative;
129
+ }
130
+
131
+ .progress-bar {
132
+ transition: width 0.6s ease;
133
+ border-radius: 100px;
134
+ position: relative;
135
+ height: 100%;
136
+ }
137
+
138
+ .progress-text {
139
+ position: absolute;
140
+ right: 0;
141
+ top: 50%;
142
+ transform: translateY(-50%);
143
+ font-size: 8px;
144
+ color: #FFFFFF;
145
+ padding: 0 5px;
146
+ white-space: nowrap;
147
+ }
148
+
149
+ .status-success .progress-bar {
150
+ background-color: #00B42A;
151
+ }
152
+
153
+ .status-warning .progress-bar {
154
+ background-color: #FF7D00;
155
+ }
156
+
157
+ .status-error .progress-bar {
158
+ background-color: #F53F3F;
159
+ }
160
+
161
+ @keyframes aui-progress-bar-stripes {
162
+ from {
163
+ background-position: 40px 0;
164
+ }
165
+ to {
166
+ background-position: 0 0;
167
+ }
168
+ }
169
+ </style>
@@ -0,0 +1,18 @@
1
+ <template>
2
+ <view class="aui-list">
3
+ <slot></slot>
4
+ </view>
5
+ </template>
6
+ <script setup>
7
+
8
+ import { defineProps } from 'vue';
9
+ const __name = 'AuiList';
10
+
11
+ defineOptions({
12
+ name: __name
13
+ })
14
+
15
+ const props = defineProps({
16
+
17
+ });
18
+ </script>
@@ -0,0 +1,142 @@
1
+ <template>
2
+ <view class="aui-list-item">
3
+ <view class="aui-list-item-content-wrapper" :style="{ transform: `translateX(${offsetX}px)` }" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd">
4
+ <view class="aui-list-item_befor">
5
+ <slot name="befor"></slot>
6
+ </view>
7
+ <view class="aui-list-item_content">
8
+ <view class="aui-list-item_content_text">
9
+ <view class="titleBefor">
10
+ <slot name="titleBefor"></slot>
11
+ </view>
12
+ {{ text }}
13
+ <view class="aui-list-item_content_tip" v-if="tip">{{ tip }}</view>
14
+ </view>
15
+ <view class="aui-list-item_content_desc">{{ desc }}</view>
16
+ <slot></slot>
17
+ </view>
18
+ <view class="aui-list-item_after">
19
+ <slot name="after"></slot>
20
+ </view>
21
+ </view>
22
+ <view class="aui-list-item-slide-content" v-if="isSliding">
23
+ <slot name="slide"></slot>
24
+ </view>
25
+ </view>
26
+ </template>
27
+
28
+ <script setup>
29
+ import { defineProps, ref } from 'vue';
30
+ const __name = 'AuiListItem';
31
+
32
+ // defineOptions 可能不是 Vue 内置方法,这里注释掉
33
+ defineOptions({
34
+ name: __name
35
+ })
36
+
37
+ const props = defineProps({
38
+ text: {
39
+ type: String,
40
+ default: ''
41
+ },
42
+ tip:{
43
+ type: String,
44
+ default: ''
45
+ },
46
+ desc: {
47
+ type: String,
48
+ default: ''
49
+ },
50
+ allowSlide: {
51
+ type: Boolean,
52
+ default: true
53
+ }
54
+ });
55
+
56
+ const startX = ref(0);
57
+ const offsetX = ref(0);
58
+ const isSliding = ref(false);
59
+ const SLIDE_THRESHOLD = -50; // 滑动阈值
60
+
61
+ const onTouchStart = (e) => {
62
+ if (!props.allowSlide) return;
63
+ startX.value = e.touches[0].clientX;
64
+ offsetX.value = 0;
65
+ isSliding.value = false;
66
+ };
67
+
68
+ const onTouchMove = (e) => {
69
+ if (!props.allowSlide) return;
70
+ const currentX = e.touches[0].clientX;
71
+ const diffX = currentX - startX.value;
72
+ if (diffX < 0) {
73
+ offsetX.value = diffX;
74
+ if (diffX < SLIDE_THRESHOLD) {
75
+ isSliding.value = true;
76
+ }
77
+ }
78
+ };
79
+
80
+ const onTouchEnd = () => {
81
+ if (!props.allowSlide) return;
82
+ if (offsetX.value < SLIDE_THRESHOLD) {
83
+ offsetX.value = -150; // 自定义内容宽度
84
+ } else {
85
+ offsetX.value = 0;
86
+ isSliding.value = false;
87
+ }
88
+ };
89
+ </script>
90
+
91
+ <style scoped lang="scss">
92
+ @import '../style.scss';
93
+ .aui-list-item {
94
+ display: flex;
95
+ align-items: center;
96
+ padding: 10px 0;
97
+ border-bottom: 1px solid #F3F4F6;
98
+ position: relative;
99
+ overflow: hidden;
100
+ }
101
+ .aui-list-item-content-wrapper {
102
+ display: flex;
103
+ // align-items: center;
104
+ width: 100%;
105
+ transition: transform 0.3s;
106
+ }
107
+ .aui-list-item_befor {
108
+ margin:0 10px;
109
+ }
110
+ .aui-list-item_content {
111
+ flex: 1;
112
+ }
113
+ .aui-list-item_content_text {
114
+ font-size: 16px;
115
+ color: $aui-default-color;
116
+ }
117
+ .aui-list-item_content_tip {
118
+ float: right;
119
+ font-size: 12px;
120
+ color: $aui-text-color;
121
+ }
122
+ .aui-list-item_content_desc {
123
+ margin-top: 5px;
124
+ font-size: $aui-font-min-size;
125
+ color: $aui-text-color;
126
+ }
127
+ .aui-list-item_after {
128
+ margin-left: 10px;
129
+ }
130
+ .aui-list-item-slide-content {
131
+ position: absolute;
132
+ right: 0;
133
+ top: 0;
134
+ bottom: 0;
135
+ width: 150px; /* 自定义内容宽度 */
136
+ background-color: #f0f0f0;
137
+ display: flex;
138
+ align-items: center;
139
+ justify-content: center;
140
+ z-index: 999;
141
+ }
142
+ </style>