@ecolovo/uniapp-components 1.0.9 → 2.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 (117) hide show
  1. package/README.md +83 -51
  2. package/components/aspect/aspect.vue +24 -15
  3. package/components/badge/badge.scss +20 -0
  4. package/components/badge/badge.vue +49 -40
  5. package/components/button/button.scss +15 -0
  6. package/components/button/button.vue +125 -181
  7. package/components/checkbox/checkbox.scss +10 -0
  8. package/components/checkbox/checkbox.vue +118 -146
  9. package/components/checkbox-group/checkbox-group.vue +79 -81
  10. package/components/checkbox-group2/checkbox-group2.vue +111 -107
  11. package/components/checkbox-group2/checkbox2.vue +104 -0
  12. package/components/data-list/data-list.scss +9 -0
  13. package/components/data-list/data-list.vue +70 -79
  14. package/components/date-picker/date-picker-view.vue +125 -124
  15. package/components/date-picker/date-picker.vue +145 -146
  16. package/components/dialog/dialog-content.vue +39 -47
  17. package/components/dialog/dialog.scss +11 -0
  18. package/components/dialog/dialog.vue +125 -138
  19. package/components/dropdown/dropdown.scss +11 -0
  20. package/components/dropdown/dropdown.vue +55 -97
  21. package/components/empty/empty.scss +14 -0
  22. package/components/empty/empty.vue +42 -41
  23. package/components/flex/flex.vue +45 -54
  24. package/components/form/form.vue +29 -24
  25. package/components/form-item/form-item.scss +11 -0
  26. package/components/form-item/form-item.vue +43 -40
  27. package/components/icon/icon.vue +70 -85
  28. package/components/image/image.vue +35 -38
  29. package/components/input/input.vue +65 -79
  30. package/components/input/password-input.vue +34 -42
  31. package/components/list-page/list-page.vue +73 -99
  32. package/components/load-more/load-more.scss +12 -0
  33. package/components/load-more/load-more.vue +29 -29
  34. package/components/loading/animations/loading-animation1.vue +8 -8
  35. package/components/loading/animations/loading-animation2.vue +8 -9
  36. package/components/loading/animations/loading-animation3.vue +11 -11
  37. package/components/loading/animations/loading-animation4.vue +8 -8
  38. package/components/loading/loading.vue +19 -20
  39. package/components/message-box/message-box.vue +59 -41
  40. package/components/number-dialog/number-dialog.scss +9 -0
  41. package/components/number-dialog/number-dialog.vue +209 -204
  42. package/components/number-input/number-input.scss +9 -0
  43. package/components/number-input/number-input.vue +233 -232
  44. package/components/numpad/numpad.scss +9 -0
  45. package/components/numpad/numpad.vue +133 -150
  46. package/components/page/page-body.scss +15 -0
  47. package/components/page/page-body.vue +137 -119
  48. package/components/page/page-footer.scss +13 -0
  49. package/components/page/page-footer.vue +31 -33
  50. package/components/page/page-header.scss +17 -0
  51. package/components/page/page-header.vue +89 -94
  52. package/components/page/page.scss +9 -0
  53. package/components/page/page.vue +105 -81
  54. package/components/picker/picker-popup.vue +218 -209
  55. package/components/picker/picker.vue +99 -104
  56. package/components/popover/popover-content.vue +54 -63
  57. package/components/popover/popover-mask.vue +63 -63
  58. package/components/popover/popover.scss +28 -0
  59. package/components/popover/popover.vue +49 -47
  60. package/components/popup/popup-content.vue +49 -53
  61. package/components/popup/popup.scss +11 -0
  62. package/components/popup/popup.vue +117 -132
  63. package/components/price/price.scss +20 -0
  64. package/components/price/price.vue +31 -42
  65. package/components/search/search.scss +12 -0
  66. package/components/search/search.vue +93 -117
  67. package/components/searching/searching.vue +33 -40
  68. package/components/selector/selector.vue +43 -48
  69. package/components/switch/switch.scss +12 -0
  70. package/components/switch/switch.vue +99 -96
  71. package/components/tab/tab.scss +19 -0
  72. package/components/tab/tab.vue +151 -145
  73. package/components/textarea/textarea.vue +104 -101
  74. package/composable/component-name.ts +10 -0
  75. package/configs/index.ts +82 -0
  76. package/{easyCom.js → easyCom.ts} +1 -1
  77. package/index.ts +1 -0
  78. package/init.ts +34 -0
  79. package/package.json +12 -4
  80. package/styles/utils/css-var.scss +12 -15
  81. package/styles/utils/ellipsis.scss +0 -7
  82. package/styles/utils/z-index.scss +1 -1
  83. package/styles/var/component.scss +21 -245
  84. package/utils/{date.js → date.ts} +44 -42
  85. package/utils/freezeDeep.ts +9 -0
  86. package/utils/price.ts +57 -0
  87. package/utils/round.ts +11 -0
  88. package/utils/{windowInfo.js → windowInfo.ts} +12 -35
  89. package/components/checkbox-group2/checkbox.vue +0 -109
  90. package/components/datetime-picker/datetime-picker-view.vue +0 -209
  91. package/components/datetime-picker/datetime-picker.vue +0 -235
  92. package/components/form/mixin.js +0 -13
  93. package/components/list-page/list-page.js +0 -10
  94. package/components/table/table.vue +0 -112
  95. package/components/time-picker/time-picker-view.vue +0 -127
  96. package/components/time-picker/time-picker.vue +0 -140
  97. package/components/uploader/download.js +0 -81
  98. package/components/uploader/file-uploader.vue +0 -52
  99. package/components/uploader/files.js +0 -225
  100. package/components/uploader/media-uploader.vue +0 -179
  101. package/components/uploader/mixin.js +0 -171
  102. package/components/uploader/uni.js +0 -38
  103. package/components/uploader/upload-button.vue +0 -29
  104. package/components/uploader/uploader copy.vue +0 -547
  105. package/components/uploader/uploader.vue +0 -117
  106. package/configs/index.d.ts +0 -22
  107. package/configs/index.js +0 -68
  108. package/init.d.ts +0 -19
  109. package/init.js +0 -20
  110. package/mixins/componentName.js +0 -32
  111. package/mixins/listPage.js +0 -1
  112. package/mixins/windowInfo.js +0 -1
  113. package/utils/fileSize.js +0 -39
  114. package/utils/floor.js +0 -20
  115. package/utils/freezeDeep.js +0 -19
  116. package/utils/price.js +0 -32
  117. package/utils/round.js +0 -22
@@ -1,12 +1,12 @@
1
1
  <template>
2
- <view :class="componentClassNames">
2
+ <view :class="classNames">
3
3
  <popover-mask-cpn
4
- ref="mask"
5
- :value="value"
4
+ ref="maskRef"
5
+ :model-value="modelValue"
6
6
  :modal="modal || isLoading"
7
- @input="$emit('input', $event)"
8
- @close="$emit('close')"
9
- @closed="$emit('closed')"
7
+ @update:model-value="emit('update:modelValue', $event)"
8
+ @close="emit('close')"
9
+ @closed="emit('closed')"
10
10
  >
11
11
  <slot name="content">
12
12
  <dialog-content-cpn
@@ -27,148 +27,135 @@
27
27
  </view>
28
28
  </template>
29
29
 
30
- <script>
31
- import componentName from '../../mixins/componentName';
30
+ <script lang="ts" setup>
31
+ import { ref, computed } from 'vue';
32
+ import useClassNames from '../../composable/component-name';
32
33
  import PopoverMaskCpn from '../popover/popover-mask.vue';
33
34
  import DialogContentCpn from './dialog-content.vue';
34
35
 
35
- export default {
36
- name: 'Dialog',
36
+ defineOptions({
37
37
  options: {
38
38
  virtualHost: true,
39
39
  styleIsolation: 'shared',
40
40
  },
41
- components: { PopoverMaskCpn, DialogContentCpn },
42
- mixins: [componentName],
43
- props: {
44
- /** v-model 绑定值,控制对话框是否可见 */
45
- value: {
46
- type: Boolean,
47
- default: false,
48
- },
49
- /** 是否模态框 */
50
- modal: {
51
- type: Boolean,
52
- default: false,
53
- },
54
- /** 是否显示 loading 动画 */
55
- loading: {
56
- type: Boolean,
57
- default: false,
58
- },
59
- /** 标题 */
60
- title: {
61
- type: String,
62
- default: '',
63
- },
64
- /** 是否居中标题 */
65
- centerTitle: {
66
- type: Boolean,
67
- default: false,
68
- },
69
- /** 是否显示关闭按钮 */
70
- showClose: {
71
- type: Boolean,
72
- default: false,
73
- },
74
- /** 取消按钮文本,为 falsy 时( false 或 '' )不显示 */
75
- cancel: {
76
- type: [String, Boolean],
77
- default: '取消',
78
- },
79
- /** 点击确认按钮时是否自动关闭对话框 */
80
- closeOnCancel: {
81
- type: Boolean,
82
- default: true,
83
- },
84
- /** 确认按钮文本,为 falsy 时( false 或 '' )不显示 */
85
- confirm: {
86
- type: [String, Boolean],
87
- default: '确认',
88
- },
89
- /** 点击确认按钮时是否自动关闭对话框 */
90
- closeOnConfirm: {
91
- type: Boolean,
92
- default: true,
93
- },
94
- /** 是否异步关闭,使用内部 loading 属性,需手动调用 close 方法关闭 */
95
- async: {
96
- type: Boolean,
97
- default: false,
98
- },
99
- },
100
- data() {
101
- return {
102
- isAsyncLoading: false,
103
- };
104
- },
105
- computed: {
106
- /** 按钮 loading */
107
- isLoading() {
108
- return this.loading || this.isAsyncLoading;
109
- },
110
- },
111
- methods: {
112
- close() {
113
- this.$refs.mask.close();
114
- },
115
- /** 隐藏 */
116
- onClose() {
117
- if (this.isLoading) return;
118
-
119
- this.close();
120
- },
121
- onCancel() {
122
- this.onButton('cancel', this.closeOnCancel);
123
- },
124
- onConfirm() {
125
- this.onButton('confirm', this.closeOnConfirm);
126
- },
127
- /** 点击取消或确认按钮
128
- * @param {'cancel' | 'confirm'} btnType 按钮类型
129
- * @param {boolean} shouldClose 是否自动关闭对话框
130
- */
131
- onButton(btnType, shouldClose) {
132
- if (this.isLoading) return;
133
-
134
- if (btnType === 'confirm' && this.async) {
135
- this.isAsyncLoading = true;
136
- const { promise, resolve, reject } = Promise.withResolvers();
137
- promise
138
- .then((willClose = true) => {
139
- if (willClose === false) {
140
- this.isAsyncLoading = false;
141
- return;
142
- }
143
- this.close();
144
- })
145
- .catch((err) => {
146
- if (process.env.NODE_ENV === 'development') {
147
- // eslint-disable-next-line no-console
148
- console.warn(`${this.componentClass} unresolved error:`, err);
149
- }
150
- this.isAsyncLoading = false;
151
- });
152
- this.$emit(btnType, { resolve, reject });
153
- return;
154
- }
155
-
156
- if (shouldClose) {
157
- this.$emit(btnType);
158
- this.close();
159
- return;
160
- }
161
-
162
- this.$emit(btnType, this.$refs.mask.close.bind(this.$refs.mask));
163
- },
164
- },
41
+ });
42
+
43
+ const classNames = useClassNames('dialog');
44
+
45
+ type _Props = {
46
+ /** v-model 绑定值,控制对话框是否可见 */
47
+ modelValue?: boolean;
48
+ /** 是否模态框 */
49
+ modal?: boolean;
50
+ /** 是否显示 loading 动画 */
51
+ loading?: boolean;
52
+ /** 标题 */
53
+ title?: string;
54
+ /** 是否居中标题 */
55
+ centerTitle?: boolean;
56
+ /** 是否显示关闭按钮 */
57
+ showClose?: boolean;
58
+ /** 取消按钮文本,为 falsy 时( false 或 '' )不显示 */
59
+ cancel?: string | boolean;
60
+ /** 点击取消按钮时是否自动关闭对话框 */
61
+ closeOnCancel?: boolean;
62
+ /** 确认按钮文本,为 falsy 时( false 或 '' )不显示 */
63
+ confirm?: string | boolean;
64
+ /** 点击确认按钮时是否自动关闭对话框 */
65
+ closeOnConfirm?: boolean;
66
+ /** 是否异步关闭,使用内部 loading 属性,需手动调用 close 方法关闭 */
67
+ async?: boolean;
165
68
  };
69
+
70
+ const props = withDefaults(defineProps<_Props>(), {
71
+ modelValue: false,
72
+ modal: false,
73
+ loading: false,
74
+ title: '',
75
+ centerTitle: false,
76
+ showClose: false,
77
+ cancel: '取消',
78
+ closeOnCancel: true,
79
+ confirm: '确认',
80
+ closeOnConfirm: true,
81
+ async: false,
82
+ });
83
+
84
+ const emit = defineEmits<{
85
+ (e: 'update:modelValue', val: boolean): void;
86
+ (e: 'close'): void;
87
+ (e: 'closed'): void;
88
+ (e: 'cancel', closeFn?: VoidFunction): void;
89
+ (e: 'confirm', payload?: Omit<PromiseWithResolvers<unknown>, 'promise'> | VoidFunction): void;
90
+ }>();
91
+
92
+ const isAsyncLoading = ref(false);
93
+ const maskRef = ref<InstanceType<typeof PopoverMaskCpn>>();
94
+
95
+ /** 按钮 loading */
96
+ const isLoading = computed(() => props.loading || isAsyncLoading.value);
97
+
98
+ const close = () => {
99
+ maskRef.value?.close();
100
+ };
101
+
102
+ /** 隐藏 */
103
+ const onClose = () => {
104
+ if (isLoading.value) return;
105
+ close();
106
+ };
107
+
108
+ const onCancel = () => {
109
+ onButton('cancel', props.closeOnCancel);
110
+ };
111
+
112
+ const onConfirm = () => {
113
+ onButton('confirm', props.closeOnConfirm);
114
+ };
115
+
116
+ /** 点击取消或确认按钮
117
+ * @param {'cancel' | 'confirm'} btnType 按钮类型
118
+ * @param {boolean} shouldClose 是否自动关闭对话框
119
+ */
120
+ const onButton = (btnType: 'cancel' | 'confirm', shouldClose: boolean) => {
121
+ if (isLoading.value) return;
122
+
123
+ if (btnType === 'confirm' && props.async) {
124
+ isAsyncLoading.value = true;
125
+ const { promise, resolve, reject } = Promise.withResolvers();
126
+ promise
127
+ .then((willClose = true) => {
128
+ if (willClose === false) {
129
+ isAsyncLoading.value = false;
130
+ return;
131
+ }
132
+ close();
133
+ })
134
+ .catch((err) => {
135
+ if (import.meta.env.DEV) {
136
+ // eslint-disable-next-line no-console
137
+ console.warn(`${classNames[0]} unresolved error:`, err);
138
+ }
139
+ isAsyncLoading.value = false;
140
+ });
141
+ emit(btnType, { resolve, reject });
142
+ return;
143
+ }
144
+
145
+ if (shouldClose) {
146
+ // @ts-expect-error 这里语法是正确的
147
+ emit(btnType);
148
+ close();
149
+ return;
150
+ }
151
+
152
+ // @ts-expect-error 这里语法是正确的
153
+ emit(btnType, maskRef.value?.close.bind(maskRef.value));
154
+ };
155
+
156
+ defineExpose({ close });
166
157
  </script>
167
158
 
168
159
  <style lang="scss" module>
169
160
  @use '../../styles/index' as *;
170
-
171
- :host {
172
- display: block;
173
- }
174
161
  </style>
@@ -0,0 +1,11 @@
1
+ @use 'sass:map';
2
+
3
+ $dropdown: () !default;
4
+ $dropdown-default: (
5
+ input-background: #fff,
6
+ dropdown-background: #fff,
7
+ input-radius: 12rpx,
8
+ dropdown-item-height: 64rpx,
9
+ font-size: 28rpx,
10
+ );
11
+ $dropdown: map.merge($dropdown-default, $dropdown);
@@ -1,12 +1,12 @@
1
1
  <template>
2
- <view :class="componentClassNames">
2
+ <view :class="[...classNames, $style['Dropdown']]">
3
3
  <view
4
4
  :class="[
5
5
  $style['Dropdown--input'],
6
6
  { [$style['Dropdown--placeholder']]: !hasValue, [$style['Dropdown--multiple']]: hasValue },
7
7
  ]"
8
8
  >
9
- <view class="ellipsis" :class="{ 'flex-1': align !== 'center' }">
9
+ <view :class="['ellipsis', { 'flex-1': align !== 'center' }]">
10
10
  {{ showValue }}
11
11
  </view>
12
12
  <icon-cpn icon="triangle-down" :class="$style['Dropdown--icon']"></icon-cpn>
@@ -14,132 +14,90 @@
14
14
  </view>
15
15
  </template>
16
16
 
17
- <script>
18
- import componentName from '../../mixins/componentName';
19
- import IconCpn from '../../icon/icon.vue';
17
+ <script lang="ts" setup>
18
+ import { computed } from 'vue';
19
+ import useClassNames from '../../composable/component-name';
20
+ import IconCpn from '../icon/icon.vue';
20
21
 
21
- export default {
22
- name: 'Dropdown',
22
+ defineOptions({
23
23
  options: {
24
24
  virtualHost: true,
25
25
  styleIsolation: 'shared',
26
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
- },
27
+ });
28
+
29
+ const classNames = useClassNames('dropdown');
30
+
31
+ type _Props = {
32
+ /** 当前选择的值 */
33
+ modelValue?: string | number | unknown[] | Record<string, unknown> | null;
34
+ /** 未选中时的提示语 */
35
+ placeholder?: string;
36
+ /** 文本对齐方式 */
37
+ align?: string;
38
+ /** 是否多选 */
39
+ multiple?: boolean;
40
+ /** 展示值格式化函数 */
41
+ formatter?: ((val: unknown) => string) | null;
73
42
  };
43
+
44
+ const props = withDefaults(defineProps<_Props>(), {
45
+ modelValue: null,
46
+ placeholder: '',
47
+ align: '',
48
+ multiple: true,
49
+ formatter: null,
50
+ });
51
+
52
+ /** 是否选择了值 */
53
+ const hasValue = computed(() => {
54
+ return props.modelValue !== null && (!Array.isArray(props.modelValue) || props.modelValue.length > 0);
55
+ });
56
+
57
+ /** 展示值 */
58
+ const showValue = computed(() => {
59
+ if (!hasValue.value) return props.placeholder;
60
+ return props.formatter
61
+ ? props.formatter(props.modelValue)
62
+ : props.multiple && Array.isArray(props.modelValue) && props.modelValue.length > 1
63
+ ? `+${props.modelValue.length}`
64
+ : props.modelValue;
65
+ });
74
66
  </script>
75
67
 
76
68
  <style lang="scss" module>
77
- @use '../../styles/index' as *;
69
+ @use '../../styles/utils' as *;
70
+ @use './dropdown' as *;
78
71
 
79
- // 自定义样式变量前缀,与组件名称一致
80
- $component-prefix: '#{$ec-component-prefix}-dropdown';
81
- // 自定义样式变量
82
72
  %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
- );
73
+ @include UTILS__DEFINE_COMPONENT_VARS($dropdown, 'dropdown');
89
74
  }
90
75
 
91
76
  .Dropdown {
92
77
  @extend %external-vars;
93
78
  position: relative;
94
79
  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
- }
80
+ font-size: UTILS__LOCAL_VAR(font-size);
109
81
  }
110
82
  .Dropdown--input {
111
83
  position: relative;
112
84
  height: 100%;
113
- padding: 0 get-value('size-m');
85
+ padding: 0 30rpx;
114
86
  display: flex;
115
87
  justify-content: center;
116
88
  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
- }
89
+ background: UTILS__LOCAL_VAR(input-background);
90
+ border-radius: UTILS__LOCAL_VAR(input-radius);
122
91
  }
123
92
  .Dropdown--placeholder {
124
93
  color: UTILS__GLOBAL_VAR(color, placeholder);
125
94
  }
126
95
  .Dropdown--multiple {
127
- color: get-value('color-primary');
96
+ color: UTILS__GLOBAL_VAR(theme, primary);
128
97
  }
129
98
  .Dropdown--icon {
130
99
  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;
100
+ font-size: 24rpx;
101
+ margin-left: 12rpx;
144
102
  }
145
103
  </style>
@@ -0,0 +1,14 @@
1
+ @use 'sass:map';
2
+ @use '../../styles/utils' as *;
3
+
4
+ // 可配置的变量
5
+ $empty: () !default;
6
+ $empty-default: (
7
+ image-size: 300rpx,
8
+ image-width: UTILS__LOCAL_VAR(image-size),
9
+ image-height: UTILS__LOCAL_VAR(image-size),
10
+ space: 20rpx,
11
+ color: #ccc,
12
+ font-size: UTILS__GLOBAL_VAR(font-size, normal),
13
+ );
14
+ $empty: map.merge($empty-default, $empty);
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <view :class="componentClassNames">
2
+ <view :class="[...classNames, $style['Empty']]">
3
3
  <template v-if="loading">
4
4
  <image v-if="loadingImage" :src="loadingImage" :class="$style['Empty--image']" />
5
5
  <view v-else :class="$style['Empty--loading-icon-wrapper']">
@@ -11,7 +11,7 @@
11
11
  </template>
12
12
  <template v-else>
13
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']" />
14
+ <image v-else :src="emptyImage" :class="$style['Empty--image']" />
15
15
  <view :class="$style['Empty--text']">
16
16
  <slot>{{ text }}</slot>
17
17
  </view>
@@ -19,56 +19,49 @@
19
19
  </view>
20
20
  </template>
21
21
 
22
- <script>
23
- import componentName from '../../mixins/componentName';
22
+ <script lang="ts" setup>
23
+ import useClassNames from '../../composable/component-name';
24
24
  import IconCpn from '../icon/icon.vue';
25
+ import emptyImage from '../../resources/image/empty.svg';
25
26
 
26
- export default {
27
- name: 'Empty',
27
+ defineOptions({
28
28
  options: {
29
29
  virtualHost: true,
30
30
  styleIsolation: 'shared',
31
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
- },
32
+ });
33
+
34
+ const classNames = useClassNames('empty');
35
+
36
+ type _Props = {
37
+ /** 图片 */
38
+ image?: string;
39
+ /** 文本 */
40
+ text?: string;
41
+ /** 数据加载中 */
42
+ loading?: boolean;
43
+ /** 数据加载中显示图片 */
44
+ loadingImage?: string;
45
+ /** 加载中文本 */
46
+ loadingText?: string;
61
47
  };
48
+
49
+ withDefaults(defineProps<_Props>(), {
50
+ image: '',
51
+ text: '暂无数据',
52
+ loading: false,
53
+ loadingImage: '',
54
+ loadingText: '数据加载中',
55
+ });
62
56
  </script>
63
57
 
64
58
  <style lang="scss" module>
65
- @use '../../styles/index' as *;
59
+ @use '../../styles/utils' as *;
60
+ @use './empty' as *;
66
61
 
67
62
  // 定义外部变量
68
- $component-name: 'empty';
69
- $component-vars: $empty;
70
63
  %external-vars {
71
- @include UTILS__DEFINE_COMPONENT_VARS();
64
+ @include UTILS__DEFINE_COMPONENT_VARS($empty, 'empty');
72
65
  }
73
66
 
74
67
  .Empty {
@@ -91,12 +84,20 @@ $component-vars: $empty;
91
84
  width: 100rpx;
92
85
  height: 100rpx;
93
86
  transform-origin: center center;
94
- animation: circle 1.5s infinite linear;
87
+ animation: Empty--circle 1.5s infinite linear;
95
88
  }
96
89
  .Empty--loading-icon {
97
90
  position: absolute;
98
91
  font-size: 60rpx;
99
92
  color: UTILS__LOCAL_VAR(color);
100
- animation: circle 1.5s linear infinite reverse;
93
+ animation: Empty--circle 1.5s linear infinite reverse;
94
+ }
95
+ @keyframes Empty--circle {
96
+ 0% {
97
+ rotate: 0deg;
98
+ }
99
+ 100% {
100
+ rotate: 360deg;
101
+ }
101
102
  }
102
103
  </style>