v-uni-app-ui 1.0.0 → 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 (61) hide show
  1. package/components/config.js +123 -0
  2. package/components/layout/v-card/v-card.vue +108 -0
  3. package/components/layout/v-grid/v-grid.vue +162 -0
  4. package/components/layout/v-icon-grid/v-icon-grid.vue +195 -0
  5. package/components/layout/v-infinite-scroll/v-infinite-scroll.vue +172 -0
  6. package/components/layout/v-list/v-list.vue +43 -0
  7. package/components/layout/v-row/v-row.vue +142 -0
  8. package/components/layout/v-waterfall/v-waterfall.vue +79 -0
  9. package/components/model/compound/v-checkbox-group/v-checkbox-group.vue +96 -0
  10. package/components/model/compound/v-console/v-console.js +20 -0
  11. package/components/model/compound/v-console/v-console.vue +299 -0
  12. package/components/model/compound/v-date-time/v-date-time.vue +261 -0
  13. package/components/model/compound/v-dialog/v-dialog.vue +178 -0
  14. package/components/model/compound/v-drum-select-picker/v-drum-select-picker.vue +83 -0
  15. package/components/model/compound/v-form/v-form.vue +226 -0
  16. package/components/model/compound/v-form-item/v-form-item.vue +255 -0
  17. package/components/model/compound/v-image/v-image.vue +357 -0
  18. package/components/model/compound/v-input-desensitize/v-input-desensitize.vue +101 -0
  19. package/components/model/compound/v-page/v-page.vue +11 -0
  20. package/components/model/compound/v-pages/v-pages.vue +141 -0
  21. package/components/model/compound/v-picker-list/v-picker-list.vue +109 -0
  22. package/components/model/compound/v-popup/v-popup.vue +151 -0
  23. package/components/model/compound/v-radio-group/v-radio-group.vue +86 -0
  24. package/components/model/compound/v-select-picker/v-select-picker.vue +202 -0
  25. package/components/model/compound/v-series-picker-list/v-series-picker-list.vue +221 -0
  26. package/components/model/compound/v-series-select-picker/v-series-select-picker.vue +203 -0
  27. package/components/model/compound/v-switch/v-switch.vue +136 -0
  28. package/components/model/compound/v-tabs-page/v-tabs-page.vue +138 -0
  29. package/components/model/native/v-badge/v-badge.vue +143 -0
  30. package/components/model/native/v-button/v-button.vue +273 -0
  31. package/components/model/native/v-carousel/v-carousel.vue +138 -0
  32. package/components/model/native/v-checkbox/v-checkbox.vue +215 -0
  33. package/components/model/native/v-collapse/v-collapse.vue +190 -0
  34. package/components/model/native/v-header-navigation-bar/v-header-navigation-bar.vue +92 -0
  35. package/components/model/native/v-input/v-input.vue +352 -0
  36. package/components/model/native/v-input-code/v-input-code.vue +146 -0
  37. package/components/model/native/v-loading/v-loading.vue +206 -0
  38. package/components/model/native/v-menu/v-menu.vue +222 -0
  39. package/components/model/native/v-menu-slide/v-menu-slide.vue +364 -0
  40. package/components/model/native/v-min-loading/v-min-loading.vue +80 -0
  41. package/components/model/native/v-null/v-null.vue +97 -0
  42. package/components/model/native/v-overlay/v-overlay.vue +96 -0
  43. package/components/model/native/v-pull-up-refresh/v-pull-up-refresh.vue +157 -0
  44. package/components/model/native/v-radio/v-radio.vue +138 -0
  45. package/components/model/native/v-scroll-list/v-scroll-list.vue +169 -0
  46. package/components/model/native/v-steps/v-steps.vue +253 -0
  47. package/components/model/native/v-table/v-table.vue +203 -0
  48. package/components/model/native/v-tabs/v-tabs.vue +235 -0
  49. package/components/model/native/v-tag/v-tag.vue +206 -0
  50. package/components/model/native/v-text/v-text.vue +187 -0
  51. package/components/model/native/v-text-button/v-text-button.vue +139 -0
  52. package/components/model/native/v-textarea/v-textarea.vue +178 -0
  53. package/components/model/native/v-title/v-title.vue +91 -0
  54. package/components/model/native/v-toast/info.png +0 -0
  55. package/components/model/native/v-toast/success.png +0 -0
  56. package/components/model/native/v-toast/v-toast.vue +198 -0
  57. package/components/model/native/v-toast/warn.png +0 -0
  58. package/components/model/native/v-upload-file-button/v-upload-file-button.vue +296 -0
  59. package/components/model/native/v-video/v-video.vue +175 -0
  60. package/components/model/native/v-window/v-window.vue +158 -0
  61. package/package.json +18 -94
@@ -0,0 +1,123 @@
1
+ export const config = {
2
+ //背景颜色
3
+ backgroundColor: {
4
+ default: '#307fff',
5
+ delete: '#ff5e5e',
6
+ succeed: '#31d283',
7
+ info: '#888888',
8
+ warn: '#fba000',
9
+ reversal: '#ffffff',
10
+ disabled: '#f5f5f5'
11
+ },
12
+ //字体颜色
13
+ fontColor: {
14
+ default: '#307fff',
15
+ delete: '#ff5e5e',
16
+ succeed: '#31d283',
17
+ info: '#888888',
18
+ warn: '#fba000',
19
+ mianTitle: '#222222',
20
+ subTitle: '#666666',
21
+ mainText: '#333333',
22
+ text: '#969696',
23
+ hintText: '#cccccc',
24
+ reversal: '#ffffff'
25
+ },
26
+ //字体大小
27
+ fontSize: {
28
+ largeTitle: '42.5rpx',
29
+ mediumTitle: '34.5rpx',
30
+ smallTitle: '31.5rpx',
31
+ largeText: '29.5rpx',
32
+ mediumText: '25.5rpx',
33
+ smallText: '22.5rpx',
34
+ messageText: '20.5rpx',
35
+ hintText: '18.5rpx'
36
+ },
37
+ //字体其他
38
+ fontOther: {
39
+ fontFamily: "'Noto Sans CJK'"
40
+ },
41
+ //文字间距
42
+ letterSpacing: {},
43
+ //边框
44
+ border: {
45
+ default: '#307fff',
46
+ delete: '#ff5e5e',
47
+ succeed: '#31d283',
48
+ info: '#888888',
49
+ warn: '#fba000',
50
+ color: '#e0e0e0'
51
+ },
52
+ borderRadius: {
53
+ semicircle: '8rpx',
54
+ square: '0',
55
+ circle: '35rpx'
56
+ },
57
+ //透明度
58
+ opacity: {
59
+ //悬浮
60
+ hover: 0.9,
61
+ //点击
62
+ click: 0.8,
63
+ //禁用
64
+ disabled: 0.7,
65
+ //消息提示
66
+ toast: 0.7,
67
+ //遮罩层
68
+ mask: 0.4,
69
+ //边框
70
+ border: 0.3
71
+ },
72
+ //暗黑模式
73
+ darkMode: {
74
+ backgroundColor: '#333333',
75
+ fontColor: '#ffffff',
76
+ border: '#e0e0e0'
77
+ },
78
+ //图片
79
+ VImage: {
80
+ prefix: '/21cqttttttttttttttttttttttttttt/ldxyb/static/images/'
81
+ },
82
+ //文本框
83
+ VInput: {
84
+ boxShadow: '0 0 0 4rpx rgba(24, 144, 255, 0.2)'
85
+ },
86
+ //表单
87
+ VTable: {
88
+ backgroundColor: '#f5f5f5'
89
+ },
90
+ //上传图片按钮
91
+ VUploadFileButton: {
92
+ backgroundColor: '#f5f5f5'
93
+ },
94
+ //菜单
95
+ VMenu: {
96
+ backgroundColor: '#f5f5f5',
97
+ highlightBackgroundColor: '#e0e0e0'
98
+ },
99
+ //步骤条
100
+ VSteps: {
101
+ lineBackgroundColor: '#e0e0e0'
102
+ },
103
+ //下拉框
104
+ VSelectPicker: {
105
+ backgroundColor: '#f5f5f5'
106
+ },
107
+ //时间选择器
108
+ VDateTime: {
109
+ backgroundColor: '#f5f5f5'
110
+ },
111
+ //表单行
112
+ VFormItem: {
113
+ borderColor: '#e0e0e0'
114
+ },
115
+ //开关
116
+ VSwitch: {
117
+ backgroundColor: '#f5f5f5'
118
+ },
119
+ //宫格布局
120
+ VGrid:{
121
+ backgroundColor: '#f5f5f5'
122
+ }
123
+ };
@@ -0,0 +1,108 @@
1
+ <template>
2
+ <view class="v-card" :class="{ 'v-card-elevated': elevated }" :style="{ width, padding, borderRadius }">
3
+ <view class="v-card-header" v-if="title || $slots.header">
4
+ <slot name="header">
5
+ <text class="v-card-title">{{ title }}</text>
6
+ </slot>
7
+ </view>
8
+ <view class="v-card-content">
9
+ <slot>
10
+ <text v-if="content">{{ content }}</text>
11
+ </slot>
12
+ </view>
13
+ <view class="v-card-actions" v-if="$slots.actions">
14
+ <slot name="actions"></slot>
15
+ </view>
16
+ </view>
17
+ </template>
18
+
19
+ <script lang="ts" setup>
20
+ import { computed,inject } from 'vue';
21
+
22
+ interface CardItem {
23
+ title?: string;
24
+ content?: string;
25
+ actions?: any;
26
+ }
27
+
28
+ /**
29
+ * v-card
30
+ * title 卡片标题
31
+ * content 卡片内容
32
+ * width 卡片宽度,默认为100%
33
+ * padding 内边距,默认为none
34
+ * borderRadius 圆角大小,默认为8px
35
+ * elevated 是否启用阴影效果,默认为false
36
+ */
37
+ const props = defineProps({
38
+ title: {
39
+ type: String,
40
+ default: ''
41
+ },
42
+ content: {
43
+ type: String,
44
+ default: ''
45
+ },
46
+ width: {
47
+ type: String,
48
+ default: '100%'
49
+ },
50
+ padding: {
51
+ type: String,
52
+ default: 'none'
53
+ },
54
+ borderRadius: {
55
+ type: String,
56
+ default: '8px'
57
+ },
58
+ elevated: {
59
+ type: Boolean,
60
+ default: false
61
+ }
62
+ });
63
+
64
+ const config = inject<any>('config');
65
+ // 计算样式
66
+ const style = computed(() => ({
67
+ width: props.width,
68
+ padding: props.padding,
69
+ borderRadius: props.borderRadius
70
+ }));
71
+ </script>
72
+
73
+ <style lang="scss" scoped>
74
+ .v-card {
75
+ background-color: v-bind('config.backgroundColor.reversal');
76
+ border: 1rpx solid v-bind('config.border.color');
77
+ box-sizing: border-box;
78
+ overflow: hidden;
79
+ transition: box-shadow 0.3s ease;
80
+
81
+ &-elevated {
82
+ box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
83
+ }
84
+
85
+ &-header {
86
+ padding: 16rpx;
87
+ border-bottom: 1rpx solid v-bind('config.border.color');
88
+ }
89
+
90
+ &-title {
91
+ font-size: v-bind('config.fontSize.mediumText');
92
+ font-weight: bold;
93
+ color: v-bind('config.fontColor.mainText');
94
+ }
95
+
96
+ &-content {
97
+ padding: 16rpx;
98
+ color: v-bind('config.fontColor.subTitle');
99
+ }
100
+
101
+ &-actions {
102
+ padding: 16rpx;
103
+ border-top: 1rpx solid v-bind('config.border.color');
104
+ display: flex;
105
+ justify-content: flex-end;
106
+ }
107
+ }
108
+ </style>
@@ -0,0 +1,162 @@
1
+ <template>
2
+ <view class="v-grid" :style="gridStyle">
3
+ <view v-for="(item, index) in items" :key="index" class="grid-item" :style="itemStyle" @click="handleItemClick(item)">
4
+ <slot name="item" :item="item" :index="index">
5
+ <view class="default-item">
6
+ <view class="image-container" v-if="item.image">
7
+ <img :src="item.image" :mode="imageMode" :lazy-load="lazyLoad" @error="handleImageError(item)" class="grid-image" :style="imageStyle" />
8
+ <view v-if="item.loading">
9
+ <slot name="loading">
10
+
11
+ </slot>
12
+ </view>
13
+ </view>
14
+ <view class="content">
15
+ <slot name="content" :item="item" :index="index"></slot>
16
+ </view>
17
+ </view>
18
+ </slot>
19
+ </view>
20
+ </view>
21
+ </template>
22
+
23
+ <script lang="ts" setup>
24
+ import { computed, ref,inject } from 'vue';
25
+
26
+ interface GridItem {
27
+ id?: string | number;
28
+ image?: string;
29
+ title: string;
30
+ desc?: string;
31
+ price?: number;
32
+ loading?: boolean;
33
+ [key: string]: any;
34
+ }
35
+
36
+ /**
37
+ * v-grid
38
+ * items 数据
39
+ * cols 列数 (支持响应式对象)
40
+ * gap 间距 rpx
41
+ * imageMode 图片模式
42
+ * lazyLoad 是否懒加载
43
+ * imageHeight 图片高度 rpx
44
+ */
45
+ const props = defineProps({
46
+ items: {
47
+ type: Array as () => GridItem[],
48
+ default: () => []
49
+ },
50
+ cols: {
51
+ type: [Number, Object],
52
+ default: 3
53
+ },
54
+ gap: {
55
+ type: [Number, String],
56
+ default: 20
57
+ },
58
+ imageMode: {
59
+ type: String,
60
+ default: 'aspectFill'
61
+ },
62
+ lazyLoad: Boolean,
63
+ imageHeight: {
64
+ type: [Number, String],
65
+ default: 300
66
+ }
67
+ });
68
+
69
+ const emit = defineEmits(['item-click', 'image-error']);
70
+
71
+ const config = inject<any>('config');
72
+ const currentCols = ref(3);
73
+ const updateColumns = () => {
74
+ const screenWidth = uni.getSystemInfoSync().screenWidth;
75
+ if (typeof props.cols === 'object') {
76
+ currentCols.value =
77
+ screenWidth >= 1200
78
+ ? props.cols.xl || 4
79
+ : screenWidth >= 992
80
+ ? props.cols.lg || 3
81
+ : screenWidth >= 768
82
+ ? props.cols.md || 2
83
+ : screenWidth >= 576
84
+ ? props.cols.sm || 2
85
+ : props.cols.xs || 1;
86
+ } else {
87
+ currentCols.value = props.cols;
88
+ }
89
+ };
90
+
91
+ updateColumns();
92
+ uni.onWindowResize(() => updateColumns());
93
+
94
+ const gridStyle = computed(() => {
95
+ const gap = uni.upx2px(Number(props.gap));
96
+ return {
97
+ marginLeft: `-${gap / 2}px`,
98
+ marginRight: `-${gap / 2}px`
99
+ };
100
+ });
101
+
102
+ const itemStyle = computed(() => {
103
+ const gap = uni.upx2px(Number(props.gap));
104
+ const width = `calc(${100 / currentCols.value}% - ${gap}px)`;
105
+ return {
106
+ width,
107
+ marginLeft: `${gap / 2}px`,
108
+ marginRight: `${gap / 2}px`,
109
+ marginBottom: `${gap}px`
110
+ };
111
+ });
112
+
113
+ const imageStyle = computed(() => ({
114
+ height: uni.upx2px(Number(props.imageHeight)) + 'px'
115
+ }));
116
+
117
+
118
+ const handleItemClick = (item: GridItem) => {
119
+ emit('item-click', item);
120
+ };
121
+
122
+ const handleImageError = (item: GridItem) => {
123
+ emit('image-error', item);
124
+ item.loading = false;
125
+ };
126
+ </script>
127
+
128
+ <style lang="scss" scoped>
129
+ .v-grid {
130
+ display: flex;
131
+ flex-wrap: wrap;
132
+ box-sizing: border-box;
133
+
134
+ .grid-item {
135
+ box-sizing: border-box;
136
+ background: v-bind("config.backgroundColor.reversal");
137
+ border-radius: 8rpx;
138
+ overflow: hidden;
139
+ transition: all 0.3s ease;
140
+
141
+ &:active {
142
+ transform: scale(0.98);
143
+ }
144
+
145
+ .default-item {
146
+ .image-container {
147
+ position: relative;
148
+ background-color: v-bind("config.VGrid.backgroundColor");
149
+
150
+ .grid-image {
151
+ width: 100%;
152
+ display: block;
153
+ }
154
+ }
155
+
156
+ .content {
157
+ padding: 20rpx;
158
+ }
159
+ }
160
+ }
161
+ }
162
+ </style>
@@ -0,0 +1,195 @@
1
+ <template>
2
+ <view class="v-icon-grid">
3
+ <scroll-view class="scroll-container" :scroll-x="scrollable" :show-scrollbar="false" :scroll-with-animation="true">
4
+ <view class="icon-grid" :style="{ 'grid-template-columns': `repeat(${columns}, 1fr)` }">
5
+ <view
6
+ v-for="(icon, index) in icons"
7
+ :key="index"
8
+ class="icon-item"
9
+ :class="{ 'icon-item-active': activeIndex === index }"
10
+ @click="handleIconClick(index)"
11
+ :style="{
12
+ width: typeof itemWidth === 'string' ? itemWidth : `${itemWidth}px`,
13
+ margin: typeof gutter === 'string' ? `calc(${gutter} / 2)` : `${gutter / 2}px`
14
+ }"
15
+ >
16
+ <view class="icon-wrapper">
17
+ <view class="icon" :style="{ 'font-size': fontSize }">
18
+ <text v-if="useIcon" :class="icon.icon"></text>
19
+ <v-image v-else :src="icon.image" :style="{ width: iconSize, height: iconSize }" />
20
+ </view>
21
+ </view>
22
+ <view
23
+ class="icon-text"
24
+ :style="{
25
+ color: textColor,
26
+ ...textStyle
27
+ }"
28
+ >
29
+ {{ icon.title }}
30
+ </view>
31
+ </view>
32
+ </view>
33
+ </scroll-view>
34
+ </view>
35
+ </template>
36
+
37
+ <script lang="ts" setup>
38
+ import { ref, computed, inject } from 'vue';
39
+
40
+ interface IconItem {
41
+ title: string;
42
+ icon?: string;
43
+ image?: string;
44
+ }
45
+ /**
46
+ * v-icon-grid 图标排版
47
+ * icons : 图标数组 title标题 icon图标类名 image图片路径
48
+ * iconSize 图标大小
49
+ * textColor 文本颜色
50
+ * activeColor 活动图标颜色
51
+ * itemWidth 每个图标项的宽度
52
+ * gutter 图标项之间的间距
53
+ * scrollable 是否可滚动 默认值:true滚动 可选值:true滚动 false不滚动
54
+ * useIcon 图标还是图片 默认值:true图标 可选值:true图标 false图片
55
+ * rows 图片排数 默认值:1
56
+ */
57
+ const props = defineProps({
58
+ icons: {
59
+ type: Array as () => IconItem[],
60
+ default: () => []
61
+ },
62
+ iconSize: {
63
+ type: String,
64
+ default: '50rpx'
65
+ },
66
+ fontSize: {
67
+ type: String,
68
+ default: '25rpx'
69
+ },
70
+ textColor: {
71
+ type: String,
72
+ default: '#333333'
73
+ },
74
+ activeColor: {
75
+ type: String,
76
+ default: 'transparent'
77
+ },
78
+ itemWidth: {
79
+ type: [Number, String],
80
+ default: 80
81
+ },
82
+ gutter: {
83
+ type: [Number, String],
84
+ default: 10
85
+ },
86
+ scrollable: {
87
+ type: Boolean,
88
+ default: true
89
+ },
90
+ useIcon: {
91
+ type: Boolean,
92
+ default: true
93
+ },
94
+ rows: {
95
+ type: Number,
96
+ default: 1
97
+ },
98
+ iconTextModel: {
99
+ type: String as () => 'normal' | 'wrap' | 'ellipsis',
100
+ default: 'normal'
101
+ }
102
+ });
103
+
104
+ const emits = defineEmits(['select']);
105
+ const config = inject<any>('config');
106
+
107
+ const activeIndex = ref(0);
108
+ const columns = computed(() => {
109
+ const totalIcons = props.icons.length;
110
+ const maxIconsPerRow = Math.ceil(totalIcons / props.rows);
111
+ return maxIconsPerRow;
112
+ });
113
+ const textStyle = computed(() => {
114
+ switch (props.iconTextModel) {
115
+ case 'wrap':
116
+ return {
117
+ whiteSpace: 'normal',
118
+ overflow: 'visible',
119
+ textOverflow: 'clip'
120
+ };
121
+ case 'ellipsis':
122
+ return {
123
+ whiteSpace: 'nowrap',
124
+ overflow: 'hidden',
125
+ textOverflow: 'ellipsis'
126
+ };
127
+ default: // normal
128
+ return {
129
+ whiteSpace: 'normal',
130
+ overflow: 'visible',
131
+ textOverflow: 'clip'
132
+ };
133
+ }
134
+ });
135
+
136
+ const handleIconClick = (index: number) => {
137
+ activeIndex.value = index;
138
+ emits('select', index, props.icons[index]);
139
+ };
140
+ </script>
141
+
142
+ <style lang="scss" scoped>
143
+ .v-icon-grid {
144
+ width: 100%;
145
+ position: relative;
146
+ }
147
+
148
+ .scroll-container {
149
+ width: 100%;
150
+ white-space: nowrap;
151
+ overflow: hidden;
152
+ flex: 1;
153
+ }
154
+
155
+ .icon-grid {
156
+ display: grid;
157
+ gap: 10rpx;
158
+ }
159
+
160
+ .icon-item {
161
+ display: flex;
162
+ flex-direction: column;
163
+ align-items: center;
164
+ justify-content: center;
165
+ border-radius: 10rpx;
166
+ transition: all 0.3s ease;
167
+ box-sizing: border-box;
168
+ }
169
+
170
+ .icon-item-active {
171
+ background-color: v-bind('props.activeColor');
172
+ }
173
+
174
+ .icon-wrapper {
175
+ display: flex;
176
+ justify-content: center;
177
+ align-items: center;
178
+ width: v-bind('props.iconSize');
179
+ height: v-bind('props.iconSize');
180
+ margin-bottom: 5rpx;
181
+ }
182
+
183
+ .icon {
184
+ display: flex;
185
+ justify-content: center;
186
+ align-items: center;
187
+ width: 100%;
188
+ height: 100%;
189
+ }
190
+
191
+ .icon-text {
192
+ font-size: v-bind('config.fontSize.mediumText');
193
+ text-align: center;
194
+ }
195
+ </style>