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,178 @@
1
+ <template>
2
+ <view class="v-dialog-overlay" v-if="visible">
3
+ <view :class="['v-dialog', `v-dialog--${size}`]" :style="dialogStyle">
4
+ <view class="v-dialog-header">
5
+ <slot name="header">
6
+ <text class="v-dialog-title">{{ title }}</text>
7
+ <button class="v-dialog-close" @click="handleClose">×</button>
8
+ </slot>
9
+ </view>
10
+
11
+ <view class="v-dialog-body">
12
+ <slot></slot>
13
+ </view>
14
+ <view class="v-dialog-footer">
15
+ <slot name="footer">
16
+ <view class="v-dialog-buttons">
17
+ <v-button type="info" @click="handleClose">取消</v-button>
18
+ <v-button @click="handleSubmit">确定</v-button>
19
+ </view>
20
+ </slot>
21
+ </view>
22
+ </view>
23
+ </view>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { ref, computed, watch,inject } from 'vue';
28
+
29
+ /**
30
+ * v-dialog 对话框
31
+ * value 是否显示
32
+ * title 标题
33
+ * size 大小
34
+ * width 宽度
35
+ * height 长度
36
+ * isCover 是否需要遮罩层 默认值:true 可选值:false不需要 true需要
37
+ *
38
+ * 相关事件close、submit
39
+ */
40
+ const props = defineProps({
41
+ value: {
42
+ type: Boolean,
43
+ default: false
44
+ },
45
+ title: {
46
+ type: String,
47
+ default: ''
48
+ },
49
+ size: {
50
+ type: String,
51
+ default: 'medium',
52
+ validator: (value: string) => {
53
+ return ['small', 'medium', 'large'].includes(value);
54
+ }
55
+ },
56
+ width: {
57
+ type: [String, Number],
58
+ default: ''
59
+ },
60
+ height: {
61
+ type: [String, Number],
62
+ default: ''
63
+ },
64
+ isCover: {
65
+ type: Boolean,
66
+ default: true
67
+ }
68
+ });
69
+
70
+ const emit = defineEmits(['update:value', 'close', 'submit']);
71
+
72
+ const config = inject<any>('config');
73
+ const visible = ref(props.value);
74
+
75
+ watch(
76
+ () => props.value,
77
+ (newVal) => {
78
+ visible.value = newVal;
79
+ }
80
+ );
81
+
82
+ const dialogStyle = computed(() => {
83
+ const style: Record<string, string | number> = {};
84
+ if (props.width) style.width = `${props.width}`;
85
+ if (props.height) style.height = `${props.height}`;
86
+ return style;
87
+ });
88
+
89
+ const handleClose = () => {
90
+ visible.value = false;
91
+ emit('update:value', false);
92
+ emit('close');
93
+ };
94
+
95
+ const handleSubmit = () => {
96
+ visible.value = false;
97
+ emit('update:value', false);
98
+ emit('submit');
99
+ };
100
+ const overlay = props.isCover ? `rgba(0,0,0,${config.opacity.mask})` : 'transparent';
101
+ </script>
102
+
103
+ <style lang="scss" scoped>
104
+ .v-dialog-overlay {
105
+ position: fixed;
106
+ top: 0;
107
+ left: 0;
108
+ right: 0;
109
+ bottom: 0;
110
+ background-color: v-bind("overlay");
111
+ display: flex;
112
+ justify-content: center;
113
+ align-items: center;
114
+ z-index: 1000;
115
+ }
116
+
117
+ .v-dialog {
118
+ width: 600rpx;
119
+ background-color: v-bind("config.backgroundColor.reversal");
120
+ overflow: hidden;
121
+
122
+ &--small {
123
+ width: 500rpx;
124
+ }
125
+
126
+ &--medium {
127
+ width: 600rpx;
128
+ }
129
+
130
+ &--large {
131
+ width: 700rpx;
132
+ }
133
+
134
+ .v-dialog-header {
135
+ display: flex;
136
+ justify-content: space-between;
137
+ align-items: center;
138
+ padding: 16rpx;
139
+ border-bottom: 1rpx solid v-bind("config.border.color");
140
+ }
141
+
142
+ .v-dialog-title {
143
+ font-size: v-bind("config.fontSize.smallTitle");
144
+ font-weight: bold;
145
+ color: v-bind("config.fontColor.mianTitle");
146
+ }
147
+
148
+ .v-dialog-close {
149
+ background: none;
150
+ border: none;
151
+ font-size: v-bind("config.fontSize.mediumText");
152
+ cursor: pointer;
153
+ color: v-bind("config.fontColor.text");
154
+ margin: 0;
155
+ }
156
+
157
+ .v-dialog-body {
158
+ padding: 16rpx;
159
+ overflow-y: auto;
160
+ }
161
+
162
+ .v-dialog-footer {
163
+ padding: 16rpx;
164
+ border-top: 1rpx solid v-bind("config.border.color");
165
+ text-align: right;
166
+ .v-dialog-buttons {
167
+ display: flex;
168
+ justify-content: right;
169
+ width: 100%;
170
+ height: 100%;
171
+
172
+ .v-button {
173
+ margin: 0 10rpx;
174
+ }
175
+ }
176
+ }
177
+ }
178
+ </style>
@@ -0,0 +1,83 @@
1
+ <template>
2
+ <v-popup v-model:value="isPopupVisible" :title="title" :scrollHeight="400" model="square" @close="handleClose">
3
+ <view class="drum-select-container">
4
+ <view class="drum-select-content">
5
+ <v-scroll-list :options="options" v-model="selectedValue" :scroll-height="scrollHeight" :item-height="itemHeight" @update:value="handleValueUpdate" />
6
+ </view>
7
+ </view>
8
+ </v-popup>
9
+ </template>
10
+
11
+ <script lang="ts" setup>
12
+ import { ref, watch, inject } from 'vue';
13
+
14
+ interface DrumSelectPicker {
15
+ value: any;
16
+ label: string;
17
+ }
18
+
19
+ const props = defineProps({
20
+ title: {
21
+ type: String,
22
+ default: '选择选项'
23
+ },
24
+ scrollHeight: {
25
+ type: Number,
26
+ default: 300
27
+ },
28
+ options: {
29
+ type: Array,
30
+ default: () => [],
31
+ required: true
32
+ },
33
+ value: {
34
+ type: [String, Number],
35
+ default: ''
36
+ },
37
+ show: {
38
+ type: Boolean,
39
+ default: false
40
+ },
41
+ itemHeight: {
42
+ type: Number,
43
+ default: 80
44
+ }
45
+ });
46
+
47
+ const emit = defineEmits(['update:value', 'close']);
48
+
49
+ const isPopupVisible = ref(props.show);
50
+ const selectedValue = ref(props.value);
51
+ const config = inject<any>('config');
52
+
53
+ watch(
54
+ () => props.value,
55
+ (newVal) => {
56
+ selectedValue.value = newVal;
57
+ }
58
+ );
59
+
60
+ function openPopup() {
61
+ isPopupVisible.value = true;
62
+ }
63
+
64
+ function handleClose() {
65
+ isPopupVisible.value = false;
66
+ emit('close');
67
+ }
68
+
69
+ function handleValueUpdate(value: any) {
70
+ emit('update:value', value);
71
+ }
72
+ </script>
73
+
74
+ <style lang="scss" scoped>
75
+ .drum-select-container {
76
+ padding: 20rpx;
77
+ }
78
+
79
+ .drum-select-content {
80
+ max-height: 500rpx;
81
+ overflow: hidden;
82
+ }
83
+ </style>
@@ -0,0 +1,226 @@
1
+ <template>
2
+ <view class="v-form" :class="[layout]">
3
+ <slot></slot>
4
+ <slot name="operate" :handleSubmit="handleSubmit" :handleRest="handleRest" :buttonDisabled="submitting" :buttonSize="buttonSize">
5
+ <view class="form-actions">
6
+ <v-button :disabled="submitting" @click="handleSubmit" :size="buttonSize">
7
+ <text v-if="!submitting">{{ submitText }}</text>
8
+ <text v-else>提交中...</text>
9
+ </v-button>
10
+ <v-button type="info" @click="handleRest" :size="buttonSize" v-if="showRest">重置</v-button>
11
+ </view>
12
+ </slot>
13
+ </view>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import { ref, provide, reactive, watchEffect, inject } from 'vue';
18
+
19
+ type FormItem = {
20
+ validate: () => Promise<boolean>;
21
+ resetField: () => void;
22
+ };
23
+
24
+ interface Rules {
25
+ required?: boolean;
26
+ message?: string;
27
+ pattern?: RegExp;
28
+ minLength?: number;
29
+ maxLength?: number;
30
+ validator?: (value: any) => boolean | Promise<boolean>;
31
+ compareWith?: string;
32
+ min?: number;
33
+ max?: number;
34
+ type?: 'email' | 'mobile' | 'number' | 'integer';
35
+ }
36
+
37
+ /**
38
+ * v-form 表单
39
+ * model 表单数据对象
40
+ * rules 验证规则 { field: [{ required: true, message: '提示' }]}
41
+ * submitText 提交按钮文字
42
+ * layout 表单布局方式 默认值: vertical 可选值: vertical垂直排列 | horizontal水平排列
43
+ * labelLayout 标签对齐方式 默认值: top 可选值:
44
+ * labelPosition标签垂直方式 默认值: normal 可选值:center
45
+ * buttonSize 按钮大小 默认值: medium 可选值:small小medium中large大
46
+ * showRest 是否显示重置按钮 默认值true 可选值:true显示 false不显示
47
+ * disabled 是否禁用表单 默认值false 可选值:true禁用 false不禁用
48
+ * 相关事件:validate 校验、submit提交、rest重置
49
+ */
50
+
51
+ const props = defineProps({
52
+ model: {
53
+ type: Object,
54
+ required: true,
55
+ default: () => ({})
56
+ },
57
+ rules: {
58
+ type: Object as () => Rules,
59
+ default: () => ({})
60
+ },
61
+ submitText: {
62
+ type: String,
63
+ default: '提交'
64
+ },
65
+ layout: {
66
+ type: String,
67
+ default: 'vertical',
68
+ validator: (v: string) => ['vertical', 'horizontal'].includes(v)
69
+ },
70
+ buttonSize: {
71
+ type: String,
72
+ default: 'medium',
73
+ validator: (v: string) => ['small', 'medium', 'large'].includes(v)
74
+ },
75
+ showRest: {
76
+ type: Boolean,
77
+ default: true
78
+ },
79
+ disabled: {
80
+ type: Boolean,
81
+ default: false
82
+ },
83
+ labelWidth: {
84
+ type: String,
85
+ default: '180'
86
+ },
87
+ labelLayout: {
88
+ type: String,
89
+ default: 'top'
90
+ },
91
+ labelLast: {
92
+ type: String,
93
+ default: 'auto'
94
+ },
95
+ labelPosition: {
96
+ type: String,
97
+ default: 'normal'
98
+ },
99
+ labelSpacing: {
100
+ type: Number,
101
+ default: 0
102
+ }
103
+ });
104
+
105
+ const emit = defineEmits(['submit', 'validate', 'rest']);
106
+
107
+ const formHasError = ref(false);
108
+ const config = inject<any>('config');
109
+ const formItems = new Map<string, FormItem>();
110
+ const submitting = ref(false);
111
+ const formData = reactive({ ...props.model });
112
+
113
+ provide('form', {
114
+ rules: props.rules || {},
115
+ formData,
116
+ register: (name: string, item: FormItem) => {
117
+ formItems.set(name, item);
118
+ },
119
+ unregister: (name: string) => {
120
+ formItems.delete(name);
121
+ },
122
+ formHasError:formHasError
123
+ });
124
+
125
+ const handleSubmit = async () => {
126
+ submitting.value = true;
127
+ formHasError.value = false;
128
+ try {
129
+ const results = await Promise.all(Array.from(formItems.values()).map((item) => item.validate()));
130
+ const isValid = results.every((valid) => valid);
131
+
132
+ emit('validate', isValid);
133
+ if (isValid) {
134
+ emit('submit', formData);
135
+ } else {
136
+ formHasError.value = true;
137
+ }
138
+ } finally {
139
+ submitting.value = false;
140
+ }
141
+ };
142
+
143
+ const handleRest = () => {
144
+ emit('rest', formData);
145
+ };
146
+
147
+ const resetForm = () => {
148
+ formItems.forEach((item) => item.resetField());
149
+ };
150
+
151
+ defineExpose({
152
+ resetForm,
153
+ validate: handleSubmit
154
+ });
155
+
156
+ watchEffect(() => {
157
+ Object.assign(formData, props.model);
158
+ });
159
+ </script>
160
+
161
+ <style lang="scss">
162
+ .v-form {
163
+ $gap: 20rpx;
164
+ $error-color: v-bind('config.fontColor.delete');
165
+
166
+ &.horizontal {
167
+ :deep(.form-item) {
168
+ display: flex;
169
+ flex-direction: row;
170
+
171
+ .label {
172
+ margin-right: $gap;
173
+ }
174
+ }
175
+ }
176
+
177
+ :deep(.form-item) {
178
+ margin-bottom: $gap;
179
+ .title {
180
+ width: v-bind("props.labelWidth + 'rpx'");
181
+ display: flex;
182
+ align-items: v-bind('props.labelPosition');
183
+
184
+ .label {
185
+ width: 80%;
186
+ font-size: v-bind('config.fontSize.largeText');
187
+ color: v-bind('config.fontColor.subTitle');
188
+ text-align: v-bind('props.labelLayout');
189
+ text-align-last: v-bind('props.labelLast');
190
+ letter-spacing: v-bind("props.labelSpacing + 'rpx'");
191
+ }
192
+ .required {
193
+ width: 20%;
194
+ height: 100%;
195
+ .v-text {
196
+ color: $error-color;
197
+ margin-left: 8rpx;
198
+ height: 100%;
199
+ display: flex !important;
200
+ align-items: v-bind('props.labelPosition');
201
+ }
202
+ }
203
+ }
204
+ .control {
205
+ min-width: 50%;
206
+ }
207
+
208
+ .error-message {
209
+ width: 100%;
210
+ height: 40rpx;
211
+ margin-top: 8rpx;
212
+ .v-text {
213
+ color: $error-color;
214
+ font-size: v-bind('config.fontSize.mediumText');
215
+ }
216
+ }
217
+ }
218
+
219
+ .form-actions {
220
+ margin-top: 40rpx;
221
+ .v-button {
222
+ width: 100%;
223
+ }
224
+ }
225
+ }
226
+ </style>