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,88 @@
1
+ <template>
2
+ <view :class="['aui-form-item', `aui-form-item--${labelPosition}`, { 'aui-form-item--error': errorMessage }]" :style="formItemStyle">
3
+ <view v-if="label" :class="['aui-form-item__label', { 'aui-form-item__label--required': required }]">
4
+ {{ label }}
5
+ </view>
6
+ <view class="aui-form-item__content">
7
+ <slot></slot>
8
+ <span v-if="errorMessage" class="aui-form-item__error">{{ errorMessage }}</span>
9
+ </view>
10
+ </view>
11
+ </template>
12
+
13
+ <script setup>
14
+ import { inject, defineProps } from 'vue';
15
+ const __name = 'AuiFormItem';
16
+
17
+ defineOptions({
18
+ name: __name
19
+ })
20
+ const props = defineProps({
21
+ label: {
22
+ type: String,
23
+ default: ''
24
+ },
25
+ labelPosition: {
26
+ type: String,
27
+ default: 'left',
28
+ validator: (value) => ['top', 'left'].includes(value)
29
+ },
30
+ required: {
31
+ type: Boolean,
32
+ default: false
33
+ },
34
+ errorMessage: {
35
+ type: String,
36
+ default: ''
37
+ }
38
+ });
39
+ const formItemStyle = inject('formItemStyle', {});
40
+ </script>
41
+
42
+ <style scoped lang="scss">
43
+ @import '../style.scss';
44
+
45
+ .aui-form-item {
46
+ display: flex;
47
+ gap: 5px;
48
+ }
49
+
50
+ .aui-form-item--top {
51
+ flex-direction: column;
52
+ }
53
+
54
+ .aui-form-item--left {
55
+ flex-direction: row;
56
+ align-items: center;
57
+ }
58
+
59
+ .aui-form-item__label {
60
+ display: flex;
61
+ font-size: $aui-font-size;
62
+ color: $aui-text-color;
63
+ align-items: center;
64
+ margin-right: 10px;
65
+ min-width: 60px;
66
+ }
67
+
68
+ .aui-form-item--top .aui-form-item__label {
69
+ margin-top: 10px;
70
+ }
71
+ .aui-form-item__label--required::after {
72
+ content: '*';
73
+ color: $aui-danger-color;
74
+ margin-left: 3px;
75
+ }
76
+
77
+ .aui-form-item__content {
78
+ flex: 1;
79
+ display: flex;
80
+ flex-direction: column;
81
+ gap: 5px;
82
+ }
83
+
84
+ .aui-form-item__error {
85
+ font-size: 12px;
86
+ color: $aui-danger-color;
87
+ }
88
+ </style>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <view class="aui-grid" :style="{gridTemplateColumns:`repeat(${colNum},1fr)`}">
3
+ <slot></slot>
4
+ </view>
5
+ </template>
6
+ <script setup>
7
+ import { defineProps } from 'vue';
8
+ const __name = 'AuiGrid';
9
+
10
+ defineOptions({
11
+ name: __name
12
+ })
13
+ const props = defineProps({
14
+ colNum: {
15
+ type: Number,
16
+ default: 3,
17
+ validator: (value) => [1, 2, 3, 4, 6].includes(value)
18
+ },
19
+ });
20
+ </script>
21
+ <style scoped>
22
+ .aui-grid {
23
+ display: grid;
24
+ gap:10px;
25
+ }
26
+ </style>
@@ -0,0 +1,20 @@
1
+ <template>
2
+ <view class="aui-grid-item">
3
+ <slot></slot>
4
+ </view>
5
+ </template>
6
+ <script setup>
7
+ import { defineProps } from 'vue';
8
+ const __name = 'AuiGridItem';
9
+
10
+ defineOptions({
11
+ name: __name
12
+ })
13
+ </script>
14
+ <style scoped>
15
+ .aui-grid-item {
16
+ padding: 10px;
17
+ text-align: center;
18
+ cursor: pointer;
19
+ }
20
+ </style>
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <view :class="classes" :style="auiStyle">
3
+ <view v-html="svgContent" :style="style"></view>
4
+ </view>
5
+ </template>
6
+
7
+ <script setup>
8
+ import { ref, computed } from 'vue';
9
+ import { camelize } from '@vue/shared';
10
+ import * as svgFiles from '../icons/index.js';
11
+ import { DOMParser, XMLSerializer } from '@xmldom/xmldom';
12
+
13
+ const __name = 'AuiIcon';
14
+
15
+ defineOptions({
16
+ name: __name
17
+ })
18
+
19
+ const props = defineProps({
20
+ name: {
21
+ type: String,
22
+ required: true
23
+ },
24
+ size: {
25
+ type: [String, Number],
26
+ default: '1em'
27
+ },
28
+ color: {
29
+ type: String,
30
+ default: 'currentColor'
31
+ },
32
+ class: {
33
+ type: [String, Array, Object],
34
+ default: ''
35
+ },
36
+ auiStyle: {
37
+ type: String,
38
+ default: ''
39
+ },
40
+ rotate: {
41
+ type: [String, Number],
42
+ default: 0,
43
+ validator: (value) => {
44
+ // 允许数值角度或预设值
45
+ return !isNaN(Number(value)) || ['90', '180', '270', 'clockwise', 'counter-clockwise'].includes(value);
46
+ }
47
+ }
48
+ });
49
+
50
+ const svgContent = ref('');
51
+
52
+ const loadSvg = () => {
53
+ const svg = svgFiles[props.name];
54
+ if (svg) {
55
+ let parser = new DOMParser();
56
+ let doc = parser.parseFromString(svg, 'image/svg+xml');
57
+ let svgElement = doc.getElementsByTagName('svg')[0];
58
+ if (svgElement) {
59
+ // 移除 SVG 根元素的 width、height、fill 和 stroke 属性
60
+ svgElement.removeAttribute('width');
61
+ svgElement.removeAttribute('height');
62
+ svgElement.removeAttribute('stroke');
63
+ svgElement.setAttribute('stroke', props.color);
64
+
65
+ // 递归设置所有子元素的 stroke 属性
66
+ function setStrokeAttributes(element) {
67
+ if (element.hasAttribute('stroke')) {
68
+ element.removeAttribute('stroke');
69
+ element.setAttribute('stroke', props.color);
70
+ } else {
71
+ element.setAttribute('stroke', 'none');
72
+ }
73
+ const children = element.childNodes;
74
+ for (let i = 0; i < children.length; i++) {
75
+ if (children[i].nodeType === 1) {
76
+ setStrokeAttributes(children[i]);
77
+ }
78
+ }
79
+ }
80
+ setStrokeAttributes(svgElement);
81
+ }
82
+ let serializer = new XMLSerializer();
83
+ let processedSvg = serializer.serializeToString(doc);
84
+ svgContent.value = processedSvg;
85
+ } else {
86
+ console.error(`Icon not found: ${props.name}`);
87
+ }
88
+ };
89
+
90
+ loadSvg();
91
+
92
+ const style = computed(() => {
93
+ const width = typeof props.size === 'number' ? `${props.size}px` : props.size;
94
+ const height = typeof props.size === 'number' ? `${props.size}px` : props.size;
95
+
96
+ // 处理旋转逻辑
97
+ let rotation = '0deg';
98
+
99
+ if (!isNaN(Number(props.rotate))) {
100
+ // 直接使用数值角度
101
+ rotation = `${Number(props.rotate)}deg`;
102
+ } else {
103
+ // 处理预设值
104
+ switch (props.rotate) {
105
+ case '90':
106
+ case 'clockwise':
107
+ rotation = '90deg';
108
+ break;
109
+ case '180':
110
+ rotation = '180deg';
111
+ break;
112
+ case '270':
113
+ case 'counter-clockwise':
114
+ rotation = '270deg';
115
+ break;
116
+ }
117
+ }
118
+
119
+ return {
120
+ width,
121
+ height,
122
+ display: 'inline-block',
123
+ verticalAlign: 'middle',
124
+ transform: `rotate(${rotation})`,
125
+ transition: 'transform 0.3s ease'
126
+ };
127
+ });
128
+
129
+ const classes = computed(() => {
130
+ const baseClass = `icon-${camelize(props.name)}`;
131
+ if (typeof props.class === 'string') {
132
+ return [baseClass, props.class];
133
+ }
134
+ if (Array.isArray(props.class)) {
135
+ return [baseClass, ...props.class];
136
+ }
137
+ if (typeof props.class === 'object') {
138
+ return [baseClass, ...Object.keys(props.class).filter((key) => props.class[key])];
139
+ }
140
+ return [baseClass];
141
+ });
142
+ </script>
143
+
144
+ <style scoped>
145
+ </style>
@@ -0,0 +1,152 @@
1
+ <template>
2
+ <div class="aui-image-container" @click="handleClick">
3
+ <img
4
+ :src="src"
5
+ :alt="alt"
6
+ :class="['aui-image']"
7
+ :style="{ width: width ? (isNumber(width) ? width + 'px' : width) : '',borderRadius:borderRadius}"
8
+ @load="handleLoad"
9
+ @error="handleError"
10
+ />
11
+ <transition name="scale">
12
+ <div v-if="showModal" class="aui-image-modal" @click.self="closeModal">
13
+ <img :src="src" class="aui-image-modal-content" />
14
+ </div>
15
+ </transition>
16
+ </div>
17
+ </template>
18
+
19
+ <script setup>
20
+ import { ref, defineProps, defineEmits, nextTick, watch } from 'vue';
21
+
22
+ const _name="AuiImage";
23
+ defineOptions({name:_name})
24
+ /**
25
+ * @param {string} src - 图片地址
26
+ * @param {string} alt - 图片描述
27
+ * @param {string} mode - 图片模式,可选值为 'widthFix' 或 'heightFix',默认为 'widthFix'
28
+ * @param {string|number} width - 图片宽度,默认为 ''
29
+ * @param {boolean} zoomable - 是否可缩放,默认为 true
30
+ * @event load - 图片加载完成时触发
31
+ * @event error - 图片加载失败时触发
32
+ * @event click - 图片点击时触发
33
+ */
34
+ const props = defineProps({
35
+ src: {
36
+ type: String,
37
+ required: true
38
+ },
39
+ alt: {
40
+ type: String,
41
+ default: ''
42
+ },
43
+ mode: {
44
+ type: String,
45
+ default: 'widthFix'
46
+ },
47
+ width: {
48
+ type: [String, Number],
49
+ default: ''
50
+ },
51
+ zoomable: {
52
+ type: Boolean,
53
+ default: false
54
+ },
55
+ borderRadius:{
56
+ type: [String, Number],
57
+ default: '0px'
58
+ },
59
+ preview:{
60
+ type:Boolean,
61
+ default:true
62
+ }
63
+ });
64
+
65
+ const emits = defineEmits(['load', 'error', 'click']);
66
+
67
+ const showModal = ref(false);
68
+ const imgNaturalWidth = ref(0);
69
+ const imgNaturalHeight = ref(0);
70
+
71
+ const isNumber = (val) => typeof val === 'number';
72
+
73
+ const handleClick = (e) => {
74
+ if (props.zoomable) {
75
+ showModal.value = true;
76
+ emits('click', e);
77
+ }
78
+ if(props.preview){
79
+ uni.previewImage({
80
+ urls: [props.src]
81
+ });
82
+ }
83
+ };
84
+
85
+ const closeModal = () => {
86
+ showModal.value = false;
87
+ };
88
+
89
+ const handleLoad = (e) => {
90
+ imgNaturalWidth.value = e.target.naturalWidth;
91
+ imgNaturalHeight.value = e.target.naturalHeight;
92
+ emits('load', e);
93
+ };
94
+
95
+ const handleError = (e) => {
96
+ emits('error', e);
97
+ };
98
+ </script>
99
+
100
+ <style scoped lang="scss">
101
+ @import '../style.scss';
102
+
103
+ .aui-image-container {
104
+ display: inline-block;
105
+ overflow: hidden;
106
+ position: relative;
107
+ cursor: pointer;
108
+
109
+ .aui-image {
110
+ display: block;
111
+ max-width: 100%;
112
+ transition: transform 0.3s ease;
113
+
114
+ &:hover {
115
+ transform: scale(1.03);
116
+ }
117
+ }
118
+ }
119
+
120
+ .aui-image-modal {
121
+ position: fixed;
122
+ top: 0;
123
+ left: 0;
124
+ width: 100%;
125
+ height: 100%;
126
+ background-color: rgba(0, 0, 0, 0.8);
127
+ display: flex;
128
+ justify-content: center;
129
+ align-items: center;
130
+ z-index: 9999;
131
+ opacity: 0;
132
+ transition: opacity 0.3s ease;
133
+
134
+ &.scale-enter-active,
135
+ &.scale-leave-active {
136
+ opacity: 1;
137
+ }
138
+
139
+ .aui-image-modal-content {
140
+ max-width: 90%;
141
+ max-height: 90%;
142
+ object-fit: contain;
143
+ transform: scale(0.95);
144
+ transition: transform 0.3s ease;
145
+
146
+ .scale-enter-active &,
147
+ .scale-leave-active & {
148
+ transform: scale(1);
149
+ }
150
+ }
151
+ }
152
+ </style>
@@ -0,0 +1,176 @@
1
+ <template>
2
+ <view :class="['aui-input-item',`aui-theme-${theme}`]">
3
+ <view class="aui-input-befor">
4
+ <slot name="befor"></slot>
5
+ </view>
6
+ <view class="aui-input-content">
7
+ <input
8
+ :type="type"
9
+ :placeholder="placeholder"
10
+ v-model="inputValue"
11
+ :class="['aui-input', `aui-input-${size}`,`aui-input-align-${textAlign}`]"
12
+ :readonly="readonly"
13
+ :disabled="disabled"
14
+ @input="handleInput"
15
+ :style="`height:${height};line-height:${height}`"
16
+ @blur="handleBlur"
17
+ />
18
+ </view>
19
+ <view class="aui-input-after">
20
+ <slot name="after"></slot>
21
+ </view>
22
+ </view>
23
+ </template>
24
+
25
+ <script setup>
26
+ import { defineProps, defineEmits, ref, watch } from 'vue';
27
+ const __name = 'AuiInput';
28
+
29
+ // 这里的 defineOptions 可能不是 Vue 内置方法,暂时注释掉
30
+ defineOptions({
31
+ name: __name
32
+ })
33
+
34
+ const props = defineProps({
35
+ type: {
36
+ type: String,
37
+ default: 'text'
38
+ },
39
+ placeholder: {
40
+ type: String,
41
+ default: ''
42
+ },
43
+ size: {
44
+ type: String,
45
+ default: 'normal',
46
+ validator: (value) => ['normal', 'small', 'large'].includes(value)
47
+ },
48
+ disabled: {
49
+ type: Boolean,
50
+ default: false
51
+ },
52
+ modelValue: {
53
+ type: [String, Number],
54
+ default: ''
55
+ },
56
+ theme: {
57
+ type: String,
58
+ default: 'normal',
59
+ validator: (value) => ['normal', 'flat', 'grey', 'write', 'none'].includes(value)
60
+ },
61
+ height: {
62
+ type: String,
63
+ default: '44px',
64
+ },
65
+ textAlign: {
66
+ type: String,
67
+ default: 'left',
68
+ validator: (value) => ['left', 'center', 'right'].includes(value)
69
+ },
70
+ readonly: {
71
+ type: Boolean,
72
+ default: false,
73
+ }
74
+ });
75
+
76
+ const emits = defineEmits(['input', 'update:modelValue', 'blur']);
77
+
78
+ const inputValue = ref(props.modelValue);
79
+
80
+ // 监听 props.modelValue 的变化
81
+ watch(() => props.modelValue, (newValue) => {
82
+ console.log('props.modelValue 变化,新值:', newValue);
83
+ inputValue.value = newValue;
84
+ });
85
+
86
+ const handleInput = (e) => {
87
+ let newValue;
88
+ if (e.detail && typeof e.detail.value !== 'undefined') {
89
+ newValue = e.detail.value;
90
+ } else {
91
+ newValue = e.target ? e.target.value : undefined;
92
+ }
93
+ if (newValue) {
94
+ inputValue.value = newValue;
95
+ console.log('输入事件触发,新值:', newValue);
96
+ emits('input', newValue);
97
+ emits('update:modelValue', newValue);
98
+ }
99
+ };
100
+
101
+ const handleBlur = (e) => {
102
+ emits('blur', e);
103
+ };
104
+ </script>
105
+
106
+ <style scoped lang="scss">
107
+ @import '../style.scss';
108
+
109
+ .aui-input-item {
110
+ display: flex;
111
+ align-items: center;
112
+ border: 1px solid $aui-border-color;
113
+ border-radius: 8px;
114
+ padding: 0 10px;
115
+ }
116
+ .aui-input-befor {
117
+ margin-right: 10px;
118
+ margin-top: -5px;
119
+ }
120
+ .aui-input-after {
121
+ margin-left: 10px;
122
+ margin-top: -5px;
123
+ }
124
+ .aui-input-content {
125
+ flex: 1;
126
+ }
127
+ .aui-input {
128
+ font-size: $aui-font-size;
129
+ outline: none;
130
+ transition: border-color 0.3s;
131
+ height: 36px;
132
+ line-height: 36px;
133
+ &:focus {
134
+ border-color: $aui-primary-color;
135
+ }
136
+ }
137
+ .aui-theme-flat{
138
+ background-color: #F5F5F5;
139
+ border: none;
140
+ border-radius: 10px;
141
+ }
142
+ .aui-theme-flat input{border:none;}
143
+ .aui-theme-write{
144
+ background-color: #FFFFFF;
145
+ border: 1px solid #E5E7EB;
146
+ border-radius: 10px;
147
+ }
148
+ .aui-theme-write input{border:none}
149
+ .aui-theme-none{
150
+ background-color: #FFFFFF;
151
+ border:none;
152
+ }
153
+ .aui-theme-none input{border:none;height: 20px;line-height: 20px;}
154
+ .aui-theme-grey{
155
+ background-color: #F5F5F5;
156
+ border: none;
157
+ border-radius: 10px;
158
+ }
159
+ .aui-theme-grey input{border:none;}
160
+ .aui-input-small {
161
+ font-size: 12px;
162
+ }
163
+
164
+ .aui-input-large {
165
+ font-size: 18px;
166
+ }
167
+ .aui-input-align-left {
168
+ text-align: left;
169
+ }
170
+ .aui-input-align-center {
171
+ text-align: center;
172
+ }
173
+ .aui-input-align-right {
174
+ text-align: right;
175
+ }
176
+ </style>