@ecolovo/uniapp-components 1.0.0

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 (97) hide show
  1. package/components/aspect/aspect.vue +43 -0
  2. package/components/badge/badge.vue +88 -0
  3. package/components/button/button.vue +409 -0
  4. package/components/checkbox/checkbox.vue +183 -0
  5. package/components/checkbox-group/checkbox-group.vue +101 -0
  6. package/components/checkbox-group2/checkbox-group2.vue +138 -0
  7. package/components/checkbox-group2/checkbox.vue +103 -0
  8. package/components/data-list/data-list.vue +130 -0
  9. package/components/date-picker/date-picker-view.vue +181 -0
  10. package/components/date-picker/date-picker.vue +237 -0
  11. package/components/datetime-picker/datetime-picker-view.vue +209 -0
  12. package/components/datetime-picker/datetime-picker.vue +235 -0
  13. package/components/dialog/dialog-content.vue +162 -0
  14. package/components/dialog/dialog.vue +166 -0
  15. package/components/dropdown/dropdown.vue +145 -0
  16. package/components/empty/empty.vue +102 -0
  17. package/components/flex/flex.vue +76 -0
  18. package/components/form/form.vue +43 -0
  19. package/components/form/mixin.js +13 -0
  20. package/components/form-item/form-item.vue +141 -0
  21. package/components/icon/icon.vue +114 -0
  22. package/components/image/image.vue +61 -0
  23. package/components/input/input.vue +154 -0
  24. package/components/input/password-input.vue +95 -0
  25. package/components/list-page/list-page.js +10 -0
  26. package/components/list-page/list-page.vue +150 -0
  27. package/components/load-more/load-more.vue +97 -0
  28. package/components/loading/animations/loading-animation1.vue +92 -0
  29. package/components/loading/animations/loading-animation2.vue +28 -0
  30. package/components/loading/animations/loading-animation3.vue +81 -0
  31. package/components/loading/animations/loading-animation4.vue +74 -0
  32. package/components/loading/loading.vue +91 -0
  33. package/components/message-box/message-box.vue +60 -0
  34. package/components/number-dialog/number-dialog.vue +360 -0
  35. package/components/number-input/number-input.vue +352 -0
  36. package/components/numpad/numpad.vue +224 -0
  37. package/components/page/page-body.vue +227 -0
  38. package/components/page/page-footer.vue +75 -0
  39. package/components/page/page-header.vue +222 -0
  40. package/components/page/page.vue +128 -0
  41. package/components/picker/picker-popup.vue +295 -0
  42. package/components/picker/picker.vue +151 -0
  43. package/components/popover/popover-content.vue +255 -0
  44. package/components/popover/popover-mask.vue +113 -0
  45. package/components/popover/popover.vue +84 -0
  46. package/components/popup/popup-content.vue +162 -0
  47. package/components/popup/popup.vue +168 -0
  48. package/components/price/price.vue +104 -0
  49. package/components/search/search.vue +220 -0
  50. package/components/searching/searching.vue +86 -0
  51. package/components/selector/selector.vue +86 -0
  52. package/components/switch/switch.vue +180 -0
  53. package/components/tab/tab.vue +235 -0
  54. package/components/table/table.vue +112 -0
  55. package/components/textarea/textarea.vue +192 -0
  56. package/components/time-picker/time-picker-view.vue +127 -0
  57. package/components/time-picker/time-picker.vue +140 -0
  58. package/components/uploader/download.js +81 -0
  59. package/components/uploader/file-uploader.vue +52 -0
  60. package/components/uploader/files.js +225 -0
  61. package/components/uploader/media-uploader.vue +133 -0
  62. package/components/uploader/mixin.js +106 -0
  63. package/components/uploader/uni.js +38 -0
  64. package/components/uploader/upload-button.vue +29 -0
  65. package/components/uploader/uploader copy.vue +547 -0
  66. package/components/uploader/uploader.vue +117 -0
  67. package/configs/index.js +41 -0
  68. package/easyCom.js +25 -0
  69. package/init.js +17 -0
  70. package/mixins/componentName.js +32 -0
  71. package/mixins/listPage.js +1 -0
  72. package/mixins/windowInfo.js +1 -0
  73. package/package.json +12 -0
  74. package/resources/iconfont/uniapp_ui_icon/demo.css +539 -0
  75. package/resources/iconfont/uniapp_ui_icon/demo_index.html +555 -0
  76. package/resources/iconfont/uniapp_ui_icon/iconfont.css +78 -0
  77. package/resources/iconfont/uniapp_ui_icon/iconfont.js +1 -0
  78. package/resources/iconfont/uniapp_ui_icon/iconfont.json +121 -0
  79. package/resources/iconfont/uniapp_ui_icon/iconfont.woff2 +0 -0
  80. package/resources/image/empty.svg +13 -0
  81. package/styles/global.scss +24 -0
  82. package/styles/index.scss +2 -0
  83. package/styles/utils/css-var.scss +87 -0
  84. package/styles/utils/ellipsis.scss +26 -0
  85. package/styles/utils/global-var.scss +11 -0
  86. package/styles/utils/index.scss +5 -0
  87. package/styles/utils/selector.scss +5 -0
  88. package/styles/utils/z-index.scss +10 -0
  89. package/styles/var/component.scss +242 -0
  90. package/styles/var/index.scss +2 -0
  91. package/styles/var/theme.scss +40 -0
  92. package/utils/date.js +151 -0
  93. package/utils/floor.js +20 -0
  94. package/utils/freezeDeep.js +19 -0
  95. package/utils/price.js +32 -0
  96. package/utils/round.js +22 -0
  97. package/utils/windowInfo.js +77 -0
@@ -0,0 +1,162 @@
1
+ <template>
2
+ <view :class="componentClassNames">
3
+ <popover-content-cpn position="center" :loading="loading">
4
+ <!-- 内容上方标题 -->
5
+ <template #header>
6
+ <slot v-if="$slots.header" name="header"></slot>
7
+ <view v-else-if="title || showClose" :class="$style['DialogContent--header']">
8
+ <view
9
+ :class="[
10
+ $style['DialogContent--title'],
11
+ { [$style['DialogContent--title-center']]: centerTitle },
12
+ ]"
13
+ >
14
+ <slot name="title">
15
+ <text>{{ title }}</text>
16
+ </slot>
17
+ </view>
18
+ <view v-if="showClose" :class="$style['DialogContent--close']" @click="$emit('close')">
19
+ <icon-cpn icon="close" tap-size="80rpx" />
20
+ </view>
21
+ </view>
22
+ </template>
23
+
24
+ <!-- 内容区域 -->
25
+ <slot></slot>
26
+
27
+ <!-- 内容下方操作按钮 -->
28
+ <template #footer>
29
+ <slot v-if="$slots.footer" name="footer"></slot>
30
+ <view v-else-if="cancel || confirm" :class="$style['DialogContent--footer']">
31
+ <view v-if="cancel" :class="$style['DialogContent--button']">
32
+ <button-cpn plain @click="$emit('cancel')">
33
+ {{ cancel }}
34
+ </button-cpn>
35
+ </view>
36
+ <view v-if="confirm" :class="$style['DialogContent--button']">
37
+ <button-cpn @click="$emit('confirm')">
38
+ {{ confirm }}
39
+ </button-cpn>
40
+ </view>
41
+ </view>
42
+ </template>
43
+ </popover-content-cpn>
44
+ </view>
45
+ </template>
46
+
47
+ <script>
48
+ import componentName from '../../mixins/componentName';
49
+ import ButtonCpn from '../button/button.vue';
50
+ import IconCpn from '../icon/icon.vue';
51
+ import PopoverContentCpn from '../popover/popover-content.vue';
52
+
53
+ export default {
54
+ name: 'AppDialogContent',
55
+ options: {
56
+ virtualHost: true,
57
+ styleIsolation: 'shared',
58
+ },
59
+ components: { ButtonCpn, IconCpn, PopoverContentCpn },
60
+ mixins: [componentName],
61
+ props: {
62
+ /** 是否显示 loading 动画 */
63
+ loading: {
64
+ type: Boolean,
65
+ default: false,
66
+ },
67
+ /** 标题 */
68
+ title: {
69
+ type: String,
70
+ default: '',
71
+ },
72
+ /** 是否居中标题 */
73
+ centerTitle: {
74
+ type: Boolean,
75
+ default: false,
76
+ },
77
+ /** 是否显示关闭按钮 */
78
+ showClose: {
79
+ type: Boolean,
80
+ default: false,
81
+ },
82
+ /** 取消按钮文本,为 falsy 时( false 或 '' )不显示 */
83
+ cancel: {
84
+ type: [String, Boolean],
85
+ default: '取消',
86
+ },
87
+ /** 确认按钮文本,为 falsy 时( false 或 '' )不显示 */
88
+ confirm: {
89
+ type: [String, Boolean],
90
+ default: '确认',
91
+ },
92
+ },
93
+ };
94
+ </script>
95
+
96
+ <style lang="scss" module>
97
+ @use '../../styles/index' as *;
98
+
99
+ // 定义外部变量
100
+ $component-name: 'dialog';
101
+ $component-vars: $dialog;
102
+ %external-vars {
103
+ @include UTILS__DEFINE_COMPONENT_VARS();
104
+ }
105
+
106
+ :host {
107
+ display: block;
108
+ }
109
+
110
+ .DialogContent {
111
+ @extend %external-vars;
112
+ #{UTILS__VAR_NAME(header-height, popover)}: #{UTILS__LOCAL_VAR(header-height)};
113
+ #{UTILS__VAR_NAME(footer-height, popover)}: #{UTILS__LOCAL_VAR(footer-height)};
114
+ #{UTILS__VAR_NAME(padding, popover)}: 20rpx 30rpx;
115
+
116
+ .DialogContent--header {
117
+ position: relative;
118
+ box-sizing: border-box;
119
+ height: UTILS__LOCAL_VAR(header-height);
120
+ padding: 20rpx 30rpx 0rpx;
121
+ display: flex;
122
+ align-items: center;
123
+ }
124
+ .DialogContent--title {
125
+ flex: 1;
126
+ font-size: UTILS__GLOBAL_VAR(font-size, large);
127
+ font-weight: 600;
128
+ &.DialogContent--title-center {
129
+ text-align: center;
130
+ }
131
+ }
132
+ .DialogContent--close {
133
+ position: absolute;
134
+ top: 0;
135
+ right: 20rpx;
136
+ margin-top: 20rpx;
137
+ width: calc(#{UTILS__LOCAL_VAR(header-height)} - 20rpx);
138
+ height: calc(#{UTILS__LOCAL_VAR(header-height)} - 20rpx);
139
+ font-size: 48rpx;
140
+ color: #999;
141
+ display: flex;
142
+ justify-content: center;
143
+ align-items: center;
144
+ }
145
+
146
+ .DialogContent--footer {
147
+ box-sizing: border-box;
148
+ height: UTILS__LOCAL_VAR(footer-height);
149
+ padding: 10rpx 30rpx 30rpx;
150
+ display: flex;
151
+ align-items: center;
152
+ }
153
+ .DialogContent--button {
154
+ flex: 1;
155
+ #{UTILS__VAR_NAME(height, button)}: 84rpx;
156
+ #{UTILS__VAR_NAME(border-radius, button)}: 20rpx;
157
+ & + #{UTILS__LAST_SELECTOR(&)} {
158
+ margin-left: 20rpx;
159
+ }
160
+ }
161
+ }
162
+ </style>
@@ -0,0 +1,166 @@
1
+ <template>
2
+ <view :class="componentClassNames">
3
+ <popover-mask-cpn
4
+ ref="mask"
5
+ :value="value"
6
+ :modal="modal || isLoading"
7
+ @input="$emit('input', $event)"
8
+ @close="$emit('close')"
9
+ @closed="$emit('closed')"
10
+ >
11
+ <dialog-content-cpn
12
+ :loading="isLoading"
13
+ :title="title"
14
+ :center-title="centerTitle"
15
+ :show-close="showClose"
16
+ :cancel="cancel"
17
+ :confirm="confirm"
18
+ @close="onClose()"
19
+ @cancel="onButton('cancel', closeOnCancel)"
20
+ @confirm="onButton('confirm', closeOnConfirm)"
21
+ >
22
+ <slot></slot>
23
+ </dialog-content-cpn>
24
+ </popover-mask-cpn>
25
+ </view>
26
+ </template>
27
+
28
+ <script>
29
+ import componentName from '../../mixins/componentName';
30
+ import PopoverMaskCpn from '../popover/popover-mask.vue';
31
+ import DialogContentCpn from './dialog-content.vue';
32
+
33
+ export default {
34
+ name: 'AppDialog',
35
+ options: {
36
+ virtualHost: true,
37
+ styleIsolation: 'shared',
38
+ },
39
+ components: { PopoverMaskCpn, DialogContentCpn },
40
+ mixins: [componentName],
41
+ props: {
42
+ /** v-model 绑定值,控制对话框是否可见 */
43
+ value: {
44
+ type: Boolean,
45
+ default: false,
46
+ },
47
+ /** 是否模态框 */
48
+ modal: {
49
+ type: Boolean,
50
+ default: false,
51
+ },
52
+ /** 是否显示 loading 动画 */
53
+ loading: {
54
+ type: Boolean,
55
+ default: false,
56
+ },
57
+ /** 标题 */
58
+ title: {
59
+ type: String,
60
+ default: '',
61
+ },
62
+ /** 是否居中标题 */
63
+ centerTitle: {
64
+ type: Boolean,
65
+ default: false,
66
+ },
67
+ /** 是否显示关闭按钮 */
68
+ showClose: {
69
+ type: Boolean,
70
+ default: false,
71
+ },
72
+ /** 取消按钮文本,为 falsy 时( false 或 '' )不显示 */
73
+ cancel: {
74
+ type: [String, Boolean],
75
+ default: '取消',
76
+ },
77
+ /** 点击确认按钮时是否自动关闭对话框 */
78
+ closeOnCancel: {
79
+ type: Boolean,
80
+ default: true,
81
+ },
82
+ /** 确认按钮文本,为 falsy 时( false 或 '' )不显示 */
83
+ confirm: {
84
+ type: [String, Boolean],
85
+ default: '确认',
86
+ },
87
+ /** 点击确认按钮时是否自动关闭对话框 */
88
+ closeOnConfirm: {
89
+ type: Boolean,
90
+ default: true,
91
+ },
92
+ /** 是否异步关闭,使用内部 loading 属性,需手动调用 close 方法关闭 */
93
+ async: {
94
+ type: Boolean,
95
+ default: false,
96
+ },
97
+ },
98
+ data() {
99
+ return {
100
+ isAsyncLoading: false,
101
+ };
102
+ },
103
+ computed: {
104
+ /** 按钮 loading */
105
+ isLoading() {
106
+ return this.loading || this.isAsyncLoading;
107
+ },
108
+ },
109
+ methods: {
110
+ close() {
111
+ this.$refs.mask.close();
112
+ },
113
+ /** 隐藏 */
114
+ onClose() {
115
+ if (this.isLoading) return;
116
+
117
+ this.close();
118
+ },
119
+ /** 点击取消或确认按钮
120
+ * @param {'cancel' | 'confirm'} btnType 按钮类型
121
+ * @param {boolean} shouldClose 是否自动关闭对话框
122
+ */
123
+ onButton(btnType, shouldClose) {
124
+ if (this.isLoading) return;
125
+
126
+ if (btnType === 'confirm' && this.async) {
127
+ this.isAsyncLoading = true;
128
+ const { promise, resolve, reject } = Promise.withResolvers();
129
+ promise
130
+ .then((willClose = true) => {
131
+ if (willClose === false) {
132
+ this.isAsyncLoading = false;
133
+ return;
134
+ }
135
+ this.close();
136
+ })
137
+ .catch((err) => {
138
+ if (process.env.NODE_ENV === 'development') {
139
+ // eslint-disable-next-line no-console
140
+ console.warn(`${this.componentClass} unresolved error:`, err);
141
+ }
142
+ this.isAsyncLoading = false;
143
+ });
144
+ this.$emit(btnType, { resolve, reject });
145
+ return;
146
+ }
147
+
148
+ if (shouldClose) {
149
+ this.$emit(btnType);
150
+ this.close();
151
+ return;
152
+ }
153
+
154
+ this.$emit(btnType, this.$refs.mask.close.bind(this.$refs.mask));
155
+ },
156
+ },
157
+ };
158
+ </script>
159
+
160
+ <style lang="scss" module>
161
+ @use '../../styles/index' as *;
162
+
163
+ :host {
164
+ display: block;
165
+ }
166
+ </style>
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <view :class="componentClassNames">
3
+ <view
4
+ :class="[
5
+ $style['Dropdown--input'],
6
+ { [$style['Dropdown--placeholder']]: !hasValue, [$style['Dropdown--multiple']]: hasValue },
7
+ ]"
8
+ >
9
+ <view class="ellipsis" :class="{ 'flex-1': align !== 'center' }">
10
+ {{ showValue }}
11
+ </view>
12
+ <icon-cpn icon="triangle-down" :class="$style['Dropdown--icon']"></icon-cpn>
13
+ </view>
14
+ </view>
15
+ </template>
16
+
17
+ <script>
18
+ import componentName from '../../mixins/componentName';
19
+ import IconCpn from '../../icon/icon.vue';
20
+
21
+ export default {
22
+ name: 'AppDropdown',
23
+ options: {
24
+ virtualHost: true,
25
+ styleIsolation: 'shared',
26
+ },
27
+ components: { IconCpn },
28
+ mixins: [componentName],
29
+ props: {
30
+ /** 当前选择的值 */
31
+ value: {
32
+ type: [String, Number, Array, Object],
33
+ default: null,
34
+ },
35
+ /** 未选中时的提示语 */
36
+ placeholder: {
37
+ type: String,
38
+ default: '',
39
+ },
40
+ /** 文本对齐方式 */
41
+ align: {
42
+ type: String,
43
+ default: '',
44
+ },
45
+ /** 是否多选 */
46
+ multiple: {
47
+ type: Boolean,
48
+ default: true,
49
+ },
50
+ /** 展示值格式化函数 */
51
+ formatter: {
52
+ type: Function,
53
+ default: null,
54
+ },
55
+ },
56
+ computed: {
57
+ /** 是否选择了值 */
58
+ hasValue() {
59
+ return this.value !== null && (!Array.isArray(this.value) || this.value.length > 0);
60
+ },
61
+ /** 展示值 */
62
+ showValue() {
63
+ if (!this.hasValue) {
64
+ return this.placeholder;
65
+ }
66
+ return this.formatter
67
+ ? this.formatter(this.value)
68
+ : this.multiple && this.value.length > 1
69
+ ? `+${this.value.length}`
70
+ : this.value;
71
+ },
72
+ },
73
+ };
74
+ </script>
75
+
76
+ <style lang="scss" module>
77
+ @use '../../styles/index' as *;
78
+
79
+ // 自定义样式变量前缀,与组件名称一致
80
+ $component-prefix: '#{$ec-component-prefix}-dropdown';
81
+ // 自定义样式变量
82
+ %external-vars {
83
+ @include define-component-vars(
84
+ $input-background: get-value('color-white'),
85
+ $dropdown-background: get-value('color-white'),
86
+ $input-radius: get-value('size-radius-xs'),
87
+ $dropdown-item-height: 64rpx
88
+ );
89
+ }
90
+
91
+ .Dropdown {
92
+ @extend %external-vars;
93
+ position: relative;
94
+ height: 100%;
95
+ font-size: get-value('size-font-s');
96
+ }
97
+ .Dropdown--modal {
98
+ position: fixed;
99
+ @include absolute-size();
100
+ background-color: #000000;
101
+ opacity: 0;
102
+ scale: 0;
103
+ transition: opacity 0.3s;
104
+ z-index: UTILS__z-index();
105
+ .Dropdown--visible & {
106
+ opacity: 0.5;
107
+ scale: 1;
108
+ }
109
+ }
110
+ .Dropdown--input {
111
+ position: relative;
112
+ height: 100%;
113
+ padding: 0 get-value('size-m');
114
+ display: flex;
115
+ justify-content: center;
116
+ align-items: center;
117
+ background: var(--input-background);
118
+ border-radius: var(--input-radius);
119
+ .Dropdown--visible & {
120
+ z-index: UTILS__z-index() + 1;
121
+ }
122
+ }
123
+ .Dropdown--placeholder {
124
+ color: UTILS__GLOBAL_VAR(color, placeholder);
125
+ }
126
+ .Dropdown--multiple {
127
+ color: get-value('color-primary');
128
+ }
129
+ .Dropdown--icon {
130
+ flex: none;
131
+ font-size: get-value('size-font-xxs');
132
+ margin-left: get-value('size-xxs');
133
+ }
134
+ .Dropdown--dropdown {
135
+ position: absolute;
136
+ top: calc(100% + #{get-value('size-xxs')});
137
+ left: 0;
138
+ width: 100%;
139
+ min-height: var(--dropdown-item-height);
140
+ max-height: calc(var(--dropdown-item-height) * 6);
141
+ background: var(--dropdown-background);
142
+ border-radius: get-value('size-radius-xs');
143
+ z-index: UTILS__z-index() + 1;
144
+ }
145
+ </style>
@@ -0,0 +1,102 @@
1
+ <template>
2
+ <view :class="componentClassNames">
3
+ <template v-if="loading">
4
+ <image v-if="loadingImage" :src="loadingImage" :class="$style['Empty--image']" />
5
+ <view v-else :class="$style['Empty--loading-icon-wrapper']">
6
+ <icon-cpn icon="search" :class="$style['Empty--loading-icon']" />
7
+ </view>
8
+ <view :class="$style['Empty--text']">
9
+ <slot>{{ loadingText }}</slot>
10
+ </view>
11
+ </template>
12
+ <template v-else>
13
+ <image v-if="image" :src="image" :class="$style['Empty--image']" />
14
+ <image v-else :src="require('../../resources/image/empty.svg')" :class="$style['Empty--image']" />
15
+ <view :class="$style['Empty--text']">
16
+ <slot>{{ text }}</slot>
17
+ </view>
18
+ </template>
19
+ </view>
20
+ </template>
21
+
22
+ <script>
23
+ import componentName from '../../mixins/componentName';
24
+ import IconCpn from '../icon/icon.vue';
25
+
26
+ export default {
27
+ name: 'AppEmpty',
28
+ options: {
29
+ virtualHost: true,
30
+ styleIsolation: 'shared',
31
+ },
32
+ components: { IconCpn },
33
+ mixins: [componentName],
34
+ props: {
35
+ /** 图片 */
36
+ image: {
37
+ type: String,
38
+ default: '',
39
+ },
40
+ /** 文本 */
41
+ text: {
42
+ type: String,
43
+ default: '暂无数据',
44
+ },
45
+ /** 数据加载中 */
46
+ loading: {
47
+ type: Boolean,
48
+ default: false,
49
+ },
50
+ /** 数据加载中显示图片 */
51
+ loadingImage: {
52
+ type: String,
53
+ default: '',
54
+ },
55
+ /** 文本 */
56
+ loadingText: {
57
+ type: String,
58
+ default: '数据加载中',
59
+ },
60
+ },
61
+ };
62
+ </script>
63
+
64
+ <style lang="scss" module>
65
+ @use '../../styles/index' as *;
66
+
67
+ // 定义外部变量
68
+ $component-name: 'empty';
69
+ $component-vars: $empty;
70
+ %external-vars {
71
+ @include UTILS__DEFINE_COMPONENT_VARS();
72
+ }
73
+
74
+ .Empty {
75
+ @extend %external-vars;
76
+ display: flex;
77
+ flex-direction: column;
78
+ justify-content: center;
79
+ align-items: center;
80
+ }
81
+ .Empty--image {
82
+ width: UTILS__LOCAL_VAR(image-width);
83
+ height: UTILS__LOCAL_VAR(image-height);
84
+ }
85
+ .Empty--text {
86
+ margin-top: UTILS__LOCAL_VAR(space);
87
+ color: UTILS__LOCAL_VAR(color);
88
+ font-size: UTILS__LOCAL_VAR(font-size);
89
+ }
90
+ .Empty--loading-icon-wrapper {
91
+ width: 100rpx;
92
+ height: 100rpx;
93
+ transform-origin: center center;
94
+ animation: circle 1.5s infinite linear;
95
+ }
96
+ .Empty--loading-icon {
97
+ position: absolute;
98
+ font-size: 60rpx;
99
+ color: UTILS__LOCAL_VAR(color);
100
+ animation: circle 1.5s linear infinite reverse;
101
+ }
102
+ </style>
@@ -0,0 +1,76 @@
1
+ <template>
2
+ <view :class="componentClassNames" :style="styleStr">
3
+ <slot></slot>
4
+ </view>
5
+ </template>
6
+
7
+ <script>
8
+ import componentName from '../../mixins/componentName';
9
+
10
+ export default {
11
+ name: 'AppFlex',
12
+ options: {
13
+ virtualHost: true,
14
+ styleIsolation: 'shared',
15
+ },
16
+ mixins: [componentName],
17
+ props: {
18
+ /** 排版方向 */
19
+ direction: {
20
+ type: String,
21
+ Validator: (value) => ['row', 'row-reverse', 'column', 'column-reverse'].includes(value),
22
+ default: 'row',
23
+ },
24
+ /** 当前轴对齐方式 */
25
+ justify: {
26
+ type: String,
27
+ Validator: (value) =>
28
+ ['start', 'center', 'end', 'space-between', 'space-around', 'space-evenly'].includes(value),
29
+ default: 'start',
30
+ },
31
+ /** 交叉轴对齐方式 */
32
+ align: {
33
+ type: String,
34
+ Validator: (value) => ['start', 'center', 'end', 'baseline', 'stretch'].includes(value),
35
+ default: 'center',
36
+ },
37
+ /** 是否换行 */
38
+ wrap: {
39
+ type: Boolean,
40
+ default: false,
41
+ },
42
+ /** 间距 */
43
+ gap: {
44
+ type: [String, Number, Array],
45
+ default: '0px',
46
+ },
47
+ },
48
+ computed: {
49
+ gapValue() {
50
+ if (Array.isArray(this.gap)) {
51
+ return this.gap.map((item) => (typeof item === 'number' ? uni.upx2px(item) + 'px' : item)).join(' ');
52
+ }
53
+ return typeof this.gap === 'number' ? uni.upx2px(this.gap) + 'px' : this.gap;
54
+ },
55
+ styleStr() {
56
+ return [
57
+ `flex-direction: ${this.direction};`,
58
+ `justify-content: ${this.justify};`,
59
+ `align-items: ${this.align};`,
60
+ `flex-wrap: ${this.wrap ? 'wrap' : 'nowrap'};`,
61
+ `gap: ${this.gapValue};`,
62
+ ].join(' ');
63
+ },
64
+ },
65
+ };
66
+ </script>
67
+
68
+ <style lang="scss" module>
69
+ @use '../../styles/index' as *;
70
+
71
+ .Flex {
72
+ width: 100%;
73
+ height: 100%;
74
+ display: flex;
75
+ }
76
+ </style>
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <view :class="componentClassNames">
3
+ <slot></slot>
4
+ </view>
5
+ </template>
6
+
7
+ <script>
8
+ import componentName from '../../mixins/componentName';
9
+
10
+ export default {
11
+ name: 'AppForm',
12
+ options: {
13
+ virtualHost: true,
14
+ styleIsolation: 'shared',
15
+ },
16
+ mixins: [componentName],
17
+ provide() {
18
+ return {
19
+ formProps: this.$props,
20
+ };
21
+ },
22
+ props: {
23
+ readonly: {
24
+ type: Boolean,
25
+ default: false,
26
+ },
27
+ /** 显示类型 */
28
+ type: {
29
+ type: String,
30
+ validator: (val) => !val || ['line', 'next', 'block'].includes(val),
31
+ default: 'line',
32
+ },
33
+ },
34
+ };
35
+ </script>
36
+
37
+ <style lang="scss" module>
38
+ .Form {
39
+ background: #fff;
40
+ padding: 20rpx;
41
+ border-radius: 20rpx;
42
+ }
43
+ </style>
@@ -0,0 +1,13 @@
1
+ export const isFormReadonly = {
2
+ inject: {
3
+ formProps: {
4
+ from: 'formProps',
5
+ default: {},
6
+ },
7
+ },
8
+ computed: {
9
+ isFormReadonly() {
10
+ return this.formProps.readonly;
11
+ },
12
+ },
13
+ };