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,303 @@
1
+ <template>
2
+ <div class="aui-multi-select">
3
+ <view
4
+ class="aui-multi-select-flex"
5
+ @click="togglePopup"
6
+ :style="`height:${height};line-height:${height}`"
7
+ >
8
+ <view class="text">
9
+ {{ selectedItems.length > 0
10
+ ? selectedItems.map(item => item.label || item).join(', ')
11
+ : placeholder }}
12
+ </view>
13
+ <view class="icon">
14
+ <aui-icon name="right" style="margin-top: -12px;"/>
15
+ </view>
16
+ </view>
17
+ <view
18
+ v-if="isPopupOpen"
19
+ class="aui-multi-select-popup-content"
20
+ :class="{ 'animate-popup': isPopupOpen }"
21
+ >
22
+ <view class="aui-multi-select-title">{{ placeholder }}</view>
23
+ <view
24
+ v-for="(category, index) in dataSource"
25
+ :key="index"
26
+ >
27
+ <view class="aui-multi-select-type">{{ category.type }}</view>
28
+ <view class="aui-multi-select-data">
29
+ <view
30
+ v-for="(item, itemIndex) in category.data"
31
+ :key="itemIndex"
32
+ class="aui-multi-select-data-item"
33
+ :class="{ 'selected': isSelected(item) }"
34
+ @click="toggleSelection(item)"
35
+ >
36
+ <input
37
+ type="checkbox"
38
+ :checked="isSelected(item)"
39
+ @change="toggleSelection(item)"
40
+ style="display: none;"
41
+ />
42
+ <view class=font>{{ item.label || item }}</view>
43
+ </view>
44
+ <!-- 根据 customerData 控制自定义按钮的显示 -->
45
+ <view
46
+ v-if="itemIndex === category.data.length - 1 && customerData"
47
+ class="custom-button"
48
+ @click="showEditInput(index)"
49
+ >
50
+ +
51
+ </view>
52
+ <input
53
+ v-if="editIndex === index && editInputVisible"
54
+ v-model="editInputValue"
55
+ type="text"
56
+ placeholder="请输入自定义数据"
57
+ />
58
+ <view
59
+ v-if="editIndex === index && editInputVisible"
60
+ class="confirm-button"
61
+ @click="addCustomData(index)"
62
+ >
63
+ 确认
64
+ </view>
65
+ </view>
66
+ </view>
67
+ <view class="aui-multi-select-foot">
68
+ <view class="close" @click="closePopup">取消</view>
69
+ <view class="confirm" @click="closePopup">确定</view>
70
+ </view>
71
+ </view>
72
+ </div>
73
+ </template>
74
+
75
+ <script setup>
76
+ import { defineProps, defineEmits, ref, computed, watch } from 'vue';
77
+ import AuiIcon from './AuiIcon.vue';
78
+
79
+ const __name = 'AuiMultiSelect';
80
+ // 这里的 defineOptions 可能不是 Vue 内置方法,暂时注释掉
81
+ defineOptions({
82
+ name: __name
83
+ })
84
+ const props = defineProps({
85
+ modelValue: {
86
+ type: Array,
87
+ default: () => []
88
+ },
89
+ dataSource: {
90
+ type: Array,
91
+ default: () => []
92
+ },
93
+ placeholder: {
94
+ type: String,
95
+ default: '请选择'
96
+ },
97
+ height: {
98
+ type: String,
99
+ default: '44px'
100
+ },
101
+ // 新增 props 用于控制自定义按钮的显示
102
+ customerData: {
103
+ type: Boolean,
104
+ default: true
105
+ }
106
+ });
107
+
108
+ const emits = defineEmits(['update:modelValue']);
109
+
110
+ const isPopupOpen = ref(false);
111
+ const selectedItems = ref(props.modelValue);
112
+ const editInputVisible = ref(false);
113
+ const editIndex = ref(-1);
114
+ const editInputValue = ref('');
115
+
116
+ // 监听 modelValue 的变化,更新 selectedItems
117
+ watch(() => props.modelValue, (newValue) => {
118
+ selectedItems.value = [...newValue];
119
+ }, { deep: true });
120
+
121
+ const togglePopup = () => {
122
+ isPopupOpen.value =!isPopupOpen.value;
123
+ };
124
+
125
+ const toggleSelection = (item) => {
126
+ const index = selectedItems.value.findIndex(selected => {
127
+ return item.id? selected.id === item.id : selected === item;
128
+ });
129
+ if (index > -1) {
130
+ selectedItems.value.splice(index, 1);
131
+ } else {
132
+ selectedItems.value.push(item);
133
+ }
134
+ emits('update:modelValue', selectedItems.value);
135
+ };
136
+
137
+ const isSelected = (item) => {
138
+ return selectedItems.value.some(selected => {
139
+ return item.id? selected.id === item.id : selected === item;
140
+ });
141
+ };
142
+
143
+ const closePopup = () => {
144
+ isPopupOpen.value = false;
145
+ emits('update:modelValue', selectedItems.value);
146
+ };
147
+
148
+ const showEditInput = (index) => {
149
+ editInputVisible.value = true;
150
+ editIndex.value = index;
151
+ editInputValue.value = '';
152
+ };
153
+
154
+ const addCustomData = (index) => {
155
+ if (editInputValue.value.trim()!== '') {
156
+ const newItem = {
157
+ label: editInputValue.value
158
+ };
159
+ props.dataSource[index].data.push(newItem);
160
+ editInputVisible.value = false;
161
+ editIndex.value = -1;
162
+ editInputValue.value = '';
163
+ emits('update:modelValue', selectedItems.value);
164
+ }
165
+ };
166
+ </script>
167
+
168
+ <style scoped lang="scss">
169
+ @import '../style.scss';
170
+
171
+ .aui-multi-select {
172
+ position: relative;
173
+ flex: 1;
174
+ border-radius: 8px;
175
+ border: 1px solid $aui-border-color;
176
+ padding: 0 20px;
177
+ }
178
+
179
+ .aui-multi-select-popup-content {
180
+ position: fixed;
181
+ bottom: 0;
182
+ left: 0;
183
+ right: 0;
184
+ background-color: white;
185
+ border-top: 1px solid #ccc;
186
+ padding: 16px;
187
+ z-index: 100;
188
+ overflow-y: auto;
189
+ height: 100%; /* 可根据需求调整 */
190
+ animation: slide-up 0.3s ease;
191
+ box-sizing: border-box;
192
+ padding-top: 10%;
193
+ }
194
+
195
+ .animate-popup {
196
+ animation: slide-up 0.3s ease;
197
+ }
198
+
199
+ @keyframes slide-up {
200
+ from {
201
+ bottom: -100%;
202
+ }
203
+ to {
204
+ bottom: 0;
205
+ }
206
+ }
207
+
208
+ .aui-multi-select view {
209
+ cursor: pointer;
210
+ font-size: $aui-font-size;
211
+ color: $aui-text-color;
212
+ }
213
+
214
+ .aui-multi-select-type {
215
+ font-size: $aui-font-min-size;
216
+ color: #999;
217
+ margin-bottom: 8px;
218
+ }
219
+
220
+ .aui-multi-select-data {
221
+ margin-bottom: 16px;
222
+ display: block;
223
+ }
224
+
225
+ .aui-multi-select-data-item {
226
+ border-radius: 3px;
227
+ align-items: center;
228
+ display: inline-block;
229
+ margin-bottom: 8px;
230
+ padding: 8px 15px;
231
+ font-size: $aui-font-size;;
232
+ cursor: pointer;
233
+ margin-right: 10px;
234
+ background-color: #F3F4F6;
235
+ }
236
+
237
+ .aui-multi-select-data-item.selected {
238
+ background-color: $aui-primary-color !important;
239
+ }
240
+ .aui-multi-select-data-item.selected .font{
241
+ color: #FFFFFF;
242
+ }
243
+
244
+ .aui-multi-select-popup-content button {
245
+ padding: 8px 16px;
246
+ background-color: $aui-primary-color;
247
+ color: white;
248
+ border: none;
249
+ border-radius: 4px;
250
+ cursor: pointer;
251
+ }
252
+
253
+ .aui-multi-select-foot {
254
+ display: flex;
255
+ }
256
+
257
+ .aui-multi-select-foot > view {
258
+ width: 40%;
259
+ height: 40px;
260
+ line-height: 40px;
261
+ background: $aui-primary-color;
262
+ color: #FFFFFF;
263
+ text-align: center;
264
+ font-size: $aui-font-size;
265
+ margin: 0 5%;
266
+ border-radius: 3px;
267
+ cursor: pointer;
268
+ }
269
+
270
+ .aui-multi-select-foot >.close {
271
+ background: $aui-danger-color;
272
+ }
273
+
274
+ .custom-button {
275
+ display: inline-block;
276
+ width: 20px;
277
+ height: 20px;
278
+ line-height: 20px;
279
+ text-align: center;
280
+ background-color: #f0f0f0;
281
+ border-radius: 3px;
282
+ cursor: pointer;
283
+ }
284
+
285
+ .confirm-button {
286
+ display: inline-block;
287
+ padding: 4px 8px;
288
+ background-color: $aui-primary-color;
289
+ color: white;
290
+ border: none;
291
+ border-radius: 3px;
292
+ cursor: pointer;
293
+ }
294
+ .aui-multi-select-title{font-size: 16px;color:#000000;margin-bottom: 20px;}
295
+ .aui-multi-select-flex{display: flex;}
296
+ .aui-multi-select-flex .text{ flex: 1;
297
+ white-space: nowrap; /* 禁止换行 */
298
+ overflow: hidden; /* 超出内容隐藏 */
299
+ text-overflow: ellipsis; /* 超出部分显示为省略号 */
300
+ max-width: 100%; /* 确保不超出父容器 */}
301
+ .aui-multi-select-flex .icon{margin-right: -10px;align-items: center;
302
+ justify-content: center; /* 使子元素在水平方向上居中,可按需添加 */}
303
+ </style>
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <view class="aui-notice-bar">
3
+ <view class="aui-notice-bar_icon" v-if="icon != 'none'">
4
+ <aui-icon :color="iconColor" :name="icon" size="20px" />
5
+ </view>
6
+ <view class="aui-notice-bar_content">
7
+ <view>{{ dataSource }}</view>
8
+ </view>
9
+ </view>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { defineProps } from 'vue';
14
+ const __name = 'AuiNoticeBar';
15
+
16
+ import AuiIcon from './AuiIcon.vue';
17
+ defineOptions({
18
+ name: __name
19
+ })
20
+
21
+ const props = defineProps({
22
+ dataSource: {
23
+ type: [String, Array],
24
+ default: '欢迎使用AstraUI...'
25
+ },
26
+ icon: {
27
+ type: String,
28
+ default: 'remind',
29
+ validator: (value) => ['none', 'remind', 'speaker'].includes(value)
30
+ },
31
+ iconColor: {
32
+ type: String,
33
+ default: '#2B6BE6'
34
+ }
35
+ });
36
+ </script>
37
+
38
+ <style scoped lang="scss">
39
+ @import '../style.scss';
40
+
41
+ .aui-notice-bar {
42
+ display: flex;
43
+ align-items: center;
44
+ background-color: #FFF;
45
+ border-radius: 6px;
46
+ padding: 10px;
47
+ font-size: $aui-font-min-size;
48
+ color: $aui-text-color;
49
+ position: relative;
50
+ }
51
+
52
+ .aui-notice-bar_icon {
53
+ /* 根据需要设置图标相关样式 */
54
+ margin-right: 6px;
55
+ /* 调整图标与内容之间的间距 */
56
+ }
57
+
58
+ .aui-notice-bar_content {
59
+ flex: 1;
60
+ /* 当有图标时,内容占剩余空间;无图标时,占全部宽度 */
61
+ }
62
+ </style>
@@ -0,0 +1,282 @@
1
+ <template>
2
+ <view class="aui-number-box">
3
+ <button
4
+ class="aui-number-box__btn aui-number-box__btn--decrease"
5
+ :disabled="currentValue <= min"
6
+ @click="decrease"
7
+ >
8
+ {{ minusIcon }}
9
+ </button>
10
+ <input
11
+ class="aui-number-box__input"
12
+ type="number"
13
+ :value="currentValue"
14
+ :disabled="disabled"
15
+ :placeholder="placeholder"
16
+ @change="handleChange"
17
+ @blur="handleBlur"
18
+ @focus="handleFocus"
19
+ />
20
+ <button
21
+ class="aui-number-box__btn aui-number-box__btn--increase"
22
+ :disabled="currentValue >= max"
23
+ @click="increase"
24
+ >
25
+ {{ plusIcon }}
26
+ </button>
27
+ </view>
28
+ </template>
29
+
30
+ <script setup>
31
+ import { ref, computed, watch, defineProps, defineEmits } from 'vue';
32
+
33
+ const _name="AuiNumberBox";
34
+ defineOptions({name:_name})
35
+ /**
36
+ * @param {number|string} modelValue - 绑定值
37
+ * @param {number} min - 最小值
38
+ * @param {number} max - 最大值
39
+ * @param {number} step - 步长
40
+ * @param {boolean} disabled - 是否禁用
41
+ * @param {string} placeholder - 输入框占位文本
42
+ * @param {string} minusIcon - 减号图标
43
+ * @param {string} plusIcon - 加号图标
44
+ * @param {boolean} integer - 是否只能输入整数
45
+ * @param {number|null} decimalLength - 小数点位数,为 null 时不限制
46
+ * @param {string|number} inputWidth - 输入框宽度
47
+ * @param {string|number} buttonSize - 按钮大小
48
+ * @param {string} disabledColor - 禁用状态颜色
49
+ * @param {string} color - 数值颜色
50
+ * @param {string} borderColor - 边框颜色
51
+ * @event update:modelValue - 绑定值变化时触发
52
+ * @event change - 数值变化时触发
53
+ * @event blur - 输入框失去焦点时触发
54
+ * @event focus - 输入框获得焦点时触发
55
+ */
56
+ const props = defineProps({
57
+ // 绑定值
58
+ modelValue: {
59
+ type: [Number, String],
60
+ default: 0
61
+ },
62
+ // 最小值
63
+ min: {
64
+ type: Number,
65
+ default: 0
66
+ },
67
+ // 最大值
68
+ max: {
69
+ type: Number,
70
+ default: Infinity
71
+ },
72
+ // 步长
73
+ step: {
74
+ type: Number,
75
+ default: 1
76
+ },
77
+ // 是否禁用
78
+ disabled: {
79
+ type: Boolean,
80
+ default: false
81
+ },
82
+ // 输入框占位文本
83
+ placeholder: {
84
+ type: String,
85
+ default: ''
86
+ },
87
+ // 减号图标
88
+ minusIcon: {
89
+ type: String,
90
+ default: '-'
91
+ },
92
+ // 加号图标
93
+ plusIcon: {
94
+ type: String,
95
+ default: '+'
96
+ },
97
+ // 是否只能输入整数
98
+ integer: {
99
+ type: Boolean,
100
+ default: false
101
+ },
102
+ // 小数点位数
103
+ decimalLength: {
104
+ type: Number,
105
+ default: null
106
+ },
107
+ // 输入框宽度
108
+ inputWidth: {
109
+ type: [String, Number],
110
+ default: 50
111
+ },
112
+ // 按钮大小
113
+ buttonSize: {
114
+ type: [String, Number],
115
+ default: 32
116
+ },
117
+ // 禁用状态颜色
118
+ disabledColor: {
119
+ type: String,
120
+ default: '#c0c4cc'
121
+ },
122
+ // 数值颜色
123
+ color: {
124
+ type: String,
125
+ default: '#303133'
126
+ },
127
+ // 边框颜色
128
+ borderColor: {
129
+ type: String,
130
+ default: '#ebeef5'
131
+ }
132
+ });
133
+
134
+ const emits = defineEmits([
135
+ 'update:modelValue',
136
+ 'change',
137
+ 'blur',
138
+ 'focus'
139
+ ]);
140
+
141
+ // 计算当前值
142
+ const currentValue = computed({
143
+ get() {
144
+ return formatValue(props.modelValue);
145
+ },
146
+ set(value) {
147
+ const formattedValue = formatValue(value);
148
+ emits('update:modelValue', formattedValue);
149
+ emits('change', formattedValue);
150
+ }
151
+ });
152
+
153
+ // 格式化数值
154
+ const formatValue = (value) => {
155
+ let val = parseFloat(value);
156
+
157
+ // 处理NaN情况
158
+ if (isNaN(val)) {
159
+ return props.min;
160
+ }
161
+
162
+ // 处理整数限制
163
+ if (props.integer) {
164
+ val = Math.round(val);
165
+ }
166
+
167
+ // 处理小数点位数
168
+ if (props.decimalLength !== null) {
169
+ val = parseFloat(val.toFixed(props.decimalLength));
170
+ }
171
+
172
+ // 限制在最小值和最大值之间
173
+ val = Math.max(props.min, Math.min(props.max, val));
174
+
175
+ return val;
176
+ };
177
+
178
+ // 增加数值
179
+ const increase = () => {
180
+ if (props.disabled || currentValue.value >= props.max) return;
181
+ currentValue.value = currentValue.value + props.step;
182
+ };
183
+
184
+ // 减少数值
185
+ const decrease = () => {
186
+ if (props.disabled || currentValue.value <= props.min) return;
187
+ currentValue.value = currentValue.value - props.step;
188
+ };
189
+
190
+ // 处理输入框变化
191
+ const handleChange = (e) => {
192
+ currentValue.value = e.target.value;
193
+ };
194
+
195
+ // 处理失焦事件
196
+ const handleBlur = (e) => {
197
+ // 失焦时格式化值
198
+ currentValue.value = e.target.value;
199
+ emits('blur', e);
200
+ };
201
+
202
+ // 处理聚焦事件
203
+ const handleFocus = (e) => {
204
+ emits('focus', e);
205
+ };
206
+
207
+ // 监听props变化
208
+ watch(() => props.modelValue, (newVal) => {
209
+ currentValue.value = formatValue(newVal);
210
+ });
211
+ </script>
212
+
213
+ <style scoped lang="scss">
214
+ .aui-number-box {
215
+ display: inline-flex;
216
+ align-items: center;
217
+ border: 1px solid var(--border-color, #ebeef5);
218
+ border-radius: 4px;
219
+ overflow: hidden;
220
+
221
+ .aui-number-box__btn {
222
+ display: flex;
223
+ align-items: center;
224
+ justify-content: center;
225
+ width: var(--button-size, 32px);
226
+ height: var(--button-size, 32px);
227
+ padding: 0;
228
+ background-color: #f5f7fa;
229
+ border: none;
230
+ color: var(--color, #303133);
231
+ font-size: 14px;
232
+ cursor: pointer;
233
+ transition: background-color 0.2s;
234
+
235
+ &:hover:not(:disabled) {
236
+ background-color: #e4e7ed;
237
+ }
238
+
239
+ &:disabled {
240
+ color: var(--disabled-color, #c0c4cc);
241
+ cursor: not-allowed;
242
+ background-color: #f5f7fa;
243
+ }
244
+
245
+ &--decrease {
246
+ border-right: 1px solid var(--border-color, #ebeef5);
247
+ }
248
+
249
+ &--increase {
250
+ border-left: 1px solid var(--border-color, #ebeef5);
251
+ }
252
+ }
253
+
254
+ .aui-number-box__input {
255
+ width: var(--input-width, 50px);
256
+ height: var(--button-size, 32px);
257
+ padding: 0 5px;
258
+ text-align: center;
259
+ border: none;
260
+ outline: none;
261
+ font-size: 14px;
262
+ color: var(--color, #303133);
263
+ background-color: #fff;
264
+
265
+ &:disabled {
266
+ background-color: #f5f7fa;
267
+ color: var(--disabled-color, #c0c4cc);
268
+ }
269
+
270
+ // 去除浏览器默认样式
271
+ &::-webkit-outer-spin-button,
272
+ &::-webkit-inner-spin-button {
273
+ -webkit-appearance: none;
274
+ margin: 0;
275
+ }
276
+
277
+ &[type="number"] {
278
+ -moz-appearance: textfield;
279
+ }
280
+ }
281
+ }
282
+ </style>