tang-ui-x 1.1.1 → 1.1.3
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.
- package/README.md +1003 -0
- package/components/TActionSheet/index.uvue +15 -2
- package/components/TCheckboxGroup/index.uvue +30 -11
- package/components/TCheckboxGroup/type.uts +10 -0
- package/components/TCollapse/index.uvue +1 -1
- package/components/TCollapse/type.uts +3 -1
- package/components/TCollapseItem/index.uvue +22 -26
- package/components/TDialog/index.uvue +19 -4
- package/components/TEmpty/index.uvue +28 -14
- package/components/TForm/index.uvue +394 -392
- package/components/TForm/type.uts +90 -80
- package/components/TInput/index.uvue +24 -5
- package/components/TInput/type.uts +10 -0
- package/components/TPicker/index.uvue +26 -6
- package/components/TRadioGroup/index.uvue +32 -12
- package/components/TRadioGroup/type.uts +7 -0
- package/components/TSearchBar/index.uvue +19 -4
- package/composables/i18n/error.uts +82 -0
- package/composables/i18n/index.uts +188 -0
- package/composables/i18n/manager-demo.uts +104 -0
- package/composables/i18n/manager.test.uts +182 -0
- package/composables/i18n/manager.uts +531 -0
- package/composables/i18n/register-demo.uts +125 -0
- package/composables/i18n/task22-verification.uts +198 -0
- package/composables/i18n/task23-verification.uts +343 -0
- package/composables/i18n/task8-demo.uts +93 -0
- package/composables/i18n/task8-verification.uts +98 -0
- package/composables/i18n/test-task23.uts +9 -0
- package/composables/i18n/types.uts +46 -0
- package/composables/i18n/useI18n-verification.uts +105 -0
- package/composables/i18n/validation-demo.uts +45 -0
- package/composables/i18n/validation-test.uts +106 -0
- package/composables/useI18n.uts +77 -0
- package/index.uts +23 -0
- package/locales/cross-platform-verification.uts +510 -0
- package/locales/en-US/actionSheet.json +3 -0
- package/locales/en-US/common.json +17 -0
- package/locales/en-US/dialog.json +5 -0
- package/locales/en-US/empty.json +6 -0
- package/locales/en-US/errorState.json +5 -0
- package/locales/en-US/examplePages.json +1236 -0
- package/locales/en-US/examples.json +218 -0
- package/locales/en-US/form.json +18 -0
- package/locales/en-US/input.json +3 -0
- package/locales/en-US/list.json +5 -0
- package/locales/en-US/loading.json +3 -0
- package/locales/en-US/navBar.json +4 -0
- package/locales/en-US/noticeBar.json +3 -0
- package/locales/en-US/picker.json +5 -0
- package/locales/en-US/searchBar.json +4 -0
- package/locales/en-US/textarea.json +3 -0
- package/locales/en-US/toast.json +6 -0
- package/locales/index.uts +79 -0
- package/locales/init-verification.uts +101 -0
- package/locales/loader.uts +251 -0
- package/locales/run-verification.uts +16 -0
- package/locales/zh-CN/actionSheet.json +3 -0
- package/locales/zh-CN/common.json +17 -0
- package/locales/zh-CN/dialog.json +5 -0
- package/locales/zh-CN/empty.json +6 -0
- package/locales/zh-CN/errorState.json +5 -0
- package/locales/zh-CN/examplePages.json +1236 -0
- package/locales/zh-CN/examples.json +218 -0
- package/locales/zh-CN/form.json +18 -0
- package/locales/zh-CN/input.json +3 -0
- package/locales/zh-CN/list.json +5 -0
- package/locales/zh-CN/loading.json +3 -0
- package/locales/zh-CN/navBar.json +4 -0
- package/locales/zh-CN/noticeBar.json +3 -0
- package/locales/zh-CN/picker.json +5 -0
- package/locales/zh-CN/searchBar.json +4 -0
- package/locales/zh-CN/textarea.json +3 -0
- package/locales/zh-CN/toast.json +6 -0
- package/locales/zh-TW/actionSheet.json +3 -0
- package/locales/zh-TW/common.json +15 -0
- package/locales/zh-TW/dialog.json +5 -0
- package/locales/zh-TW/empty.json +6 -0
- package/locales/zh-TW/errorState.json +5 -0
- package/locales/zh-TW/examplePages.json +705 -0
- package/locales/zh-TW/examples.json +218 -0
- package/locales/zh-TW/form.json +18 -0
- package/locales/zh-TW/input.json +3 -0
- package/locales/zh-TW/list.json +5 -0
- package/locales/zh-TW/loading.json +3 -0
- package/locales/zh-TW/navBar.json +4 -0
- package/locales/zh-TW/noticeBar.json +3 -0
- package/locales/zh-TW/picker.json +5 -0
- package/locales/zh-TW/searchBar.json +4 -0
- package/locales/zh-TW/textarea.json +3 -0
- package/locales/zh-TW/toast.json +6 -0
- package/package.json +3 -2
|
@@ -1,80 +1,90 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 表单选项类型
|
|
3
|
-
*/
|
|
4
|
-
export type FormOption = {
|
|
5
|
-
label: string
|
|
6
|
-
value: string | number
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 组件通用属性
|
|
11
|
-
*/
|
|
12
|
-
export type ComponentProps = {
|
|
13
|
-
/** 占位符 */
|
|
14
|
-
placeholder?: string
|
|
15
|
-
/** 是否禁用 */
|
|
16
|
-
disabled?: boolean
|
|
17
|
-
/** 选项列表(用于 select、radio、checkbox) */
|
|
18
|
-
options?: FormOption[]
|
|
19
|
-
/** 输入类型(用于 input) */
|
|
20
|
-
type?: string
|
|
21
|
-
/** 最大长度(用于 input、textarea) */
|
|
22
|
-
maxlength?: number
|
|
23
|
-
/** 最小值(用于 number、slider) */
|
|
24
|
-
min?: number
|
|
25
|
-
/** 最大值(用于 number、slider、rate) */
|
|
26
|
-
max?: number
|
|
27
|
-
/** 步长(用于 slider) */
|
|
28
|
-
step?: number
|
|
29
|
-
/** 是否自动聚焦(用于 input、textarea) */
|
|
30
|
-
focus?: boolean
|
|
31
|
-
/** 确认按钮文字(用于 input) */
|
|
32
|
-
confirmType?: string
|
|
33
|
-
/** 是否自动高度(用于 textarea) */
|
|
34
|
-
autoHeight?: boolean
|
|
35
|
-
/** 是否显示确认栏(用于 textarea) */
|
|
36
|
-
showConfirmBar?: boolean
|
|
37
|
-
/** 开始日期(用于 date) */
|
|
38
|
-
start?: string
|
|
39
|
-
/** 结束日期(用于 date) */
|
|
40
|
-
end?: string
|
|
41
|
-
/** 激活颜色(用于 switch) */
|
|
42
|
-
color?: string
|
|
43
|
-
/** 是否允许半星(用于 rate) */
|
|
44
|
-
allowHalf?: boolean
|
|
45
|
-
/** 是否显示值(用于 slider) */
|
|
46
|
-
showValue?: boolean
|
|
47
|
-
/** 其他扩展属性 */
|
|
48
|
-
[key: string]: any
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* 表单字段配置
|
|
53
|
-
*/
|
|
54
|
-
export type FormSchema = {
|
|
55
|
-
/** 字段名 */
|
|
56
|
-
field: string
|
|
57
|
-
/** 标签文本 */
|
|
58
|
-
label: string
|
|
59
|
-
/** 组件类型 */
|
|
60
|
-
component: 'Input' | 'Textarea' | 'Select' | 'Date' | 'Time' | 'Radio' | 'Checkbox' | 'Switch' | 'Rate' | 'Slider' | 'InputNumber'
|
|
61
|
-
/** 是否必填 */
|
|
62
|
-
required?: boolean
|
|
63
|
-
/** 组件属性 */
|
|
64
|
-
componentProps?: ComponentProps
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 表单选项类型
|
|
3
|
+
*/
|
|
4
|
+
export type FormOption = {
|
|
5
|
+
label: string
|
|
6
|
+
value: string | number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 组件通用属性
|
|
11
|
+
*/
|
|
12
|
+
export type ComponentProps = {
|
|
13
|
+
/** 占位符 */
|
|
14
|
+
placeholder?: string
|
|
15
|
+
/** 是否禁用 */
|
|
16
|
+
disabled?: boolean
|
|
17
|
+
/** 选项列表(用于 select、radio、checkbox) */
|
|
18
|
+
options?: FormOption[]
|
|
19
|
+
/** 输入类型(用于 input) */
|
|
20
|
+
type?: string
|
|
21
|
+
/** 最大长度(用于 input、textarea) */
|
|
22
|
+
maxlength?: number
|
|
23
|
+
/** 最小值(用于 number、slider) */
|
|
24
|
+
min?: number
|
|
25
|
+
/** 最大值(用于 number、slider、rate) */
|
|
26
|
+
max?: number
|
|
27
|
+
/** 步长(用于 slider) */
|
|
28
|
+
step?: number
|
|
29
|
+
/** 是否自动聚焦(用于 input、textarea) */
|
|
30
|
+
focus?: boolean
|
|
31
|
+
/** 确认按钮文字(用于 input) */
|
|
32
|
+
confirmType?: string
|
|
33
|
+
/** 是否自动高度(用于 textarea) */
|
|
34
|
+
autoHeight?: boolean
|
|
35
|
+
/** 是否显示确认栏(用于 textarea) */
|
|
36
|
+
showConfirmBar?: boolean
|
|
37
|
+
/** 开始日期(用于 date) */
|
|
38
|
+
start?: string
|
|
39
|
+
/** 结束日期(用于 date) */
|
|
40
|
+
end?: string
|
|
41
|
+
/** 激活颜色(用于 switch) */
|
|
42
|
+
color?: string
|
|
43
|
+
/** 是否允许半星(用于 rate) */
|
|
44
|
+
allowHalf?: boolean
|
|
45
|
+
/** 是否显示值(用于 slider) */
|
|
46
|
+
showValue?: boolean
|
|
47
|
+
/** 其他扩展属性 */
|
|
48
|
+
[key: string]: any
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 表单字段配置
|
|
53
|
+
*/
|
|
54
|
+
export type FormSchema = {
|
|
55
|
+
/** 字段名 */
|
|
56
|
+
field: string
|
|
57
|
+
/** 标签文本 */
|
|
58
|
+
label: string
|
|
59
|
+
/** 组件类型 */
|
|
60
|
+
component: 'Input' | 'Textarea' | 'Select' | 'Date' | 'Time' | 'Radio' | 'Checkbox' | 'Switch' | 'Rate' | 'Slider' | 'InputNumber'
|
|
61
|
+
/** 是否必填 */
|
|
62
|
+
required?: boolean
|
|
63
|
+
/** 组件属性 */
|
|
64
|
+
componentProps?: ComponentProps
|
|
65
|
+
/** 单个配置项的布局方向(优先级高于整体 layout) */
|
|
66
|
+
layout?: 'horizontal' | 'vertical'
|
|
67
|
+
/** 单个配置项的标签宽度(优先级高于整体 labelWidth) */
|
|
68
|
+
labelWidth?: string
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 表单组件属性
|
|
73
|
+
*/
|
|
74
|
+
export type TFormProps = {
|
|
75
|
+
/** 表单配置 */
|
|
76
|
+
schemas: FormSchema[]
|
|
77
|
+
/** 标签宽度 */
|
|
78
|
+
labelWidth?: string
|
|
79
|
+
/** 表单项布局方向 */
|
|
80
|
+
layout?: 'horizontal' | 'vertical'
|
|
81
|
+
/** 是否隐藏默认按钮 */
|
|
82
|
+
hideButtons?: boolean
|
|
83
|
+
/** 提交按钮文本 */
|
|
84
|
+
submitText?: string
|
|
85
|
+
/** 重置按钮文本 */
|
|
86
|
+
resetText?: string
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 导出所有类型
|
|
90
|
+
export { FormOption, ComponentProps, FormSchema, TFormProps }
|
|
@@ -16,6 +16,8 @@ const props = withDefaults(defineProps<TInputProps>(), {
|
|
|
16
16
|
clearable: false,
|
|
17
17
|
showCount: false,
|
|
18
18
|
maxlength: -1,
|
|
19
|
+
prefix: '',
|
|
20
|
+
suffix: '',
|
|
19
21
|
prefixIcon: '',
|
|
20
22
|
suffixIcon: '',
|
|
21
23
|
rows: 3,
|
|
@@ -70,13 +72,13 @@ const inputWrapperClasses = computed((): string => {
|
|
|
70
72
|
classes.push('t-input--focused')
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
//
|
|
74
|
-
if (props.prefixIcon) {
|
|
75
|
+
// 前缀文本或图标
|
|
76
|
+
if (props.prefix || props.prefixIcon) {
|
|
75
77
|
classes.push('t-input--prefix')
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
//
|
|
79
|
-
if (props.suffixIcon || props.clearable) {
|
|
80
|
+
// 后缀文本、图标或清除按钮
|
|
81
|
+
if (props.suffix || props.suffixIcon || props.clearable) {
|
|
80
82
|
classes.push('t-input--suffix')
|
|
81
83
|
}
|
|
82
84
|
|
|
@@ -142,8 +144,13 @@ const handleConfirm = () => {
|
|
|
142
144
|
|
|
143
145
|
<template>
|
|
144
146
|
<view class="t-input" :class="inputWrapperClasses" :style="customStyle">
|
|
147
|
+
<!-- 前缀文本 -->
|
|
148
|
+
<view v-if="prefix" class="t-input__prefix">
|
|
149
|
+
<text class="t-input__prefix-text">{{ prefix }}</text>
|
|
150
|
+
</view>
|
|
151
|
+
|
|
145
152
|
<!-- 前缀图标 -->
|
|
146
|
-
<view v-if="prefixIcon" class="t-input__prefix">
|
|
153
|
+
<view v-else-if="prefixIcon" class="t-input__prefix">
|
|
147
154
|
<text class="t-input__icon">{{ prefixIcon }}</text>
|
|
148
155
|
</view>
|
|
149
156
|
|
|
@@ -189,6 +196,11 @@ const handleConfirm = () => {
|
|
|
189
196
|
<text class="t-input__icon">✕</text>
|
|
190
197
|
</view>
|
|
191
198
|
|
|
199
|
+
<!-- 后缀文本 -->
|
|
200
|
+
<view v-else-if="suffix" class="t-input__suffix">
|
|
201
|
+
<text class="t-input__suffix-text">{{ suffix }}</text>
|
|
202
|
+
</view>
|
|
203
|
+
|
|
192
204
|
<!-- 后缀图标 -->
|
|
193
205
|
<view v-else-if="suffixIcon" class="t-input__suffix">
|
|
194
206
|
<text class="t-input__icon">{{ suffixIcon }}</text>
|
|
@@ -242,6 +254,13 @@ const handleConfirm = () => {
|
|
|
242
254
|
font-size: 16px;
|
|
243
255
|
}
|
|
244
256
|
|
|
257
|
+
&__prefix-text,
|
|
258
|
+
&__suffix-text {
|
|
259
|
+
font-size: 14px;
|
|
260
|
+
color: #606266;
|
|
261
|
+
white-space: nowrap;
|
|
262
|
+
}
|
|
263
|
+
|
|
245
264
|
&__inner,
|
|
246
265
|
&__textarea {
|
|
247
266
|
flex: 1;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="uts">
|
|
2
2
|
import { computed, ref, watch } from 'vue'
|
|
3
3
|
import type { TPickerProps, TPickerOption } from './type.uts'
|
|
4
|
+
import { useI18n } from '../../composables/useI18n.uts'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* TPicker 通用选择器组件
|
|
@@ -11,11 +12,8 @@ import type { TPickerProps, TPickerOption } from './type.uts'
|
|
|
11
12
|
type Props = Omit<TPickerProps, 'visible'>
|
|
12
13
|
|
|
13
14
|
const props = withDefaults(defineProps<Props>(), {
|
|
14
|
-
title: '请选择',
|
|
15
15
|
options: () => [] as TPickerOption[],
|
|
16
16
|
columns: () => [] as TPickerOption[][],
|
|
17
|
-
confirmText: '确定',
|
|
18
|
-
cancelText: '取消',
|
|
19
17
|
itemHeight: '44px',
|
|
20
18
|
visibleItemCount: 5,
|
|
21
19
|
showToolbar: true
|
|
@@ -34,6 +32,28 @@ const emit = defineEmits<{
|
|
|
34
32
|
change: [value: any, index: number | number[], columnIndex: number]
|
|
35
33
|
}>()
|
|
36
34
|
|
|
35
|
+
// 使用 i18n
|
|
36
|
+
const { $t } = useI18n()
|
|
37
|
+
|
|
38
|
+
// 优先使用用户传入的值,否则使用翻译
|
|
39
|
+
const displayTitle = computed(() => {
|
|
40
|
+
return props.title !== undefined && props.title !== ''
|
|
41
|
+
? props.title
|
|
42
|
+
: $t('picker.title')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const displayConfirmText = computed(() => {
|
|
46
|
+
return props.confirmText !== undefined && props.confirmText !== ''
|
|
47
|
+
? props.confirmText
|
|
48
|
+
: $t('picker.confirmText')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const displayCancelText = computed(() => {
|
|
52
|
+
return props.cancelText !== undefined && props.cancelText !== ''
|
|
53
|
+
? props.cancelText
|
|
54
|
+
: $t('picker.cancelText')
|
|
55
|
+
})
|
|
56
|
+
|
|
37
57
|
// 当前选中的索引(单列为 number,多列为 number[])
|
|
38
58
|
const selectedIndex = ref<number[]>([0])
|
|
39
59
|
|
|
@@ -154,13 +174,13 @@ const handleChange = (e: any): void => {
|
|
|
154
174
|
<!-- 工具栏 -->
|
|
155
175
|
<view v-if="showToolbar" class="t-picker__toolbar">
|
|
156
176
|
<view class="t-picker__btn t-picker__btn--cancel" @click="handleCancel">
|
|
157
|
-
<text class="t-picker__btn-text">{{
|
|
177
|
+
<text class="t-picker__btn-text">{{ displayCancelText }}</text>
|
|
158
178
|
</view>
|
|
159
179
|
<view class="t-picker__title">
|
|
160
|
-
<text class="t-picker__title-text">{{
|
|
180
|
+
<text class="t-picker__title-text">{{ displayTitle }}</text>
|
|
161
181
|
</view>
|
|
162
182
|
<view class="t-picker__btn t-picker__btn--confirm" @click="handleConfirm">
|
|
163
|
-
<text class="t-picker__btn-text t-picker__btn-text--primary">{{
|
|
183
|
+
<text class="t-picker__btn-text t-picker__btn-text--primary">{{ displayConfirmText }}</text>
|
|
164
184
|
</view>
|
|
165
185
|
</view>
|
|
166
186
|
|
|
@@ -12,6 +12,9 @@ type Props = Omit<TRadioGroupProps, 'modelValue'>
|
|
|
12
12
|
const props = withDefaults(defineProps<Props>(), {
|
|
13
13
|
options: () => [] as RadioOption[],
|
|
14
14
|
direction: 'vertical',
|
|
15
|
+
size: 'medium',
|
|
16
|
+
activeColor: '#00bba7',
|
|
17
|
+
inactiveColor: '#c8c9cc',
|
|
15
18
|
disabled: false,
|
|
16
19
|
customClass: '',
|
|
17
20
|
customStyle: ''
|
|
@@ -34,20 +37,37 @@ const handleChange = (option: RadioOption): void => {
|
|
|
34
37
|
const isChecked = (option: RadioOption): boolean => {
|
|
35
38
|
return modelValue.value === option.value
|
|
36
39
|
}
|
|
40
|
+
|
|
41
|
+
// 尺寸映射
|
|
42
|
+
const sizeMap = {
|
|
43
|
+
small: { icon: 28, dot: 14, fontSize: 24 },
|
|
44
|
+
medium: { icon: 36, dot: 20, fontSize: 28 },
|
|
45
|
+
large: { icon: 44, dot: 26, fontSize: 32 }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const currentSize = computed(() => sizeMap[props.size])
|
|
49
|
+
|
|
50
|
+
const cssVars = computed(() => ({
|
|
51
|
+
'--icon-size': `${currentSize.value.icon}rpx`,
|
|
52
|
+
'--dot-size': `${currentSize.value.dot}rpx`,
|
|
53
|
+
'--font-size': `${currentSize.value.fontSize}rpx`,
|
|
54
|
+
'--active-color': props.activeColor,
|
|
55
|
+
'--inactive-color': props.inactiveColor
|
|
56
|
+
}))
|
|
37
57
|
</script>
|
|
38
58
|
|
|
39
59
|
<template>
|
|
40
60
|
<view
|
|
41
61
|
class="t-radio-group"
|
|
42
62
|
:class="[`t-radio-group--${direction}`, customClass]"
|
|
43
|
-
:style="customStyle"
|
|
63
|
+
:style="[customStyle, cssVars]"
|
|
44
64
|
>
|
|
45
65
|
<view
|
|
46
66
|
v-for="(option, index) in options"
|
|
47
67
|
:key="index"
|
|
48
68
|
class="t-radio-group__item"
|
|
49
69
|
:class="{ 't-radio-group__item--disabled': disabled || option.disabled }"
|
|
50
|
-
@click="
|
|
70
|
+
@click="handleChange(option)"
|
|
51
71
|
>
|
|
52
72
|
<view class="t-radio-group__icon" :class="{ 't-radio-group__icon--checked': isChecked(option) }">
|
|
53
73
|
<view v-if="isChecked(option)" class="t-radio-group__dot"></view>
|
|
@@ -73,7 +93,7 @@ const isChecked = (option: RadioOption): boolean => {
|
|
|
73
93
|
|
|
74
94
|
.t-radio-group__item {
|
|
75
95
|
display: flex;
|
|
76
|
-
|
|
96
|
+
flex-direction: row;
|
|
77
97
|
padding: 12px 0;
|
|
78
98
|
cursor: pointer;
|
|
79
99
|
|
|
@@ -88,30 +108,30 @@ const isChecked = (option: RadioOption): boolean => {
|
|
|
88
108
|
}
|
|
89
109
|
|
|
90
110
|
.t-radio-group__icon {
|
|
91
|
-
width:
|
|
92
|
-
height:
|
|
93
|
-
border:
|
|
111
|
+
width: var(--icon-size);
|
|
112
|
+
height: var(--icon-size);
|
|
113
|
+
border: 2rpx solid var(--inactive-color);
|
|
94
114
|
border-radius: 50%;
|
|
95
|
-
margin-right:
|
|
115
|
+
margin-right: 16rpx;
|
|
96
116
|
display: flex;
|
|
97
117
|
align-items: center;
|
|
98
118
|
justify-content: center;
|
|
99
119
|
transition: all 0.3s;
|
|
100
120
|
|
|
101
121
|
&--checked {
|
|
102
|
-
border-color:
|
|
122
|
+
border-color: var(--active-color);
|
|
103
123
|
}
|
|
104
124
|
}
|
|
105
125
|
|
|
106
126
|
.t-radio-group__dot {
|
|
107
|
-
width:
|
|
108
|
-
height:
|
|
109
|
-
background-color:
|
|
127
|
+
width: var(--dot-size);
|
|
128
|
+
height: var(--dot-size);
|
|
129
|
+
background-color: var(--active-color);
|
|
110
130
|
border-radius: 50%;
|
|
111
131
|
}
|
|
112
132
|
|
|
113
133
|
.t-radio-group__label {
|
|
114
|
-
font-size:
|
|
134
|
+
font-size: var(--font-size);
|
|
115
135
|
color: #323233;
|
|
116
136
|
}
|
|
117
137
|
</style>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export type RadioDirection = 'horizontal' | 'vertical'
|
|
6
|
+
export type RadioSize = 'small' | 'medium' | 'large'
|
|
6
7
|
|
|
7
8
|
export interface RadioOption {
|
|
8
9
|
label: string
|
|
@@ -14,6 +15,12 @@ export interface TRadioGroupProps {
|
|
|
14
15
|
modelValue?: string | number
|
|
15
16
|
options?: RadioOption[]
|
|
16
17
|
direction?: RadioDirection
|
|
18
|
+
/** 按钮尺寸 */
|
|
19
|
+
size?: RadioSize
|
|
20
|
+
/** 活动状态颜色 */
|
|
21
|
+
activeColor?: string
|
|
22
|
+
/** 非活动状态颜色 */
|
|
23
|
+
inactiveColor?: string
|
|
17
24
|
disabled?: boolean
|
|
18
25
|
customClass?: string
|
|
19
26
|
customStyle?: string
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="uts">
|
|
2
2
|
import { ref, computed } from 'vue'
|
|
3
3
|
import type { TSearchBarProps } from './type.uts'
|
|
4
|
+
import { useI18n } from '../../composables/useI18n.uts'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* TSearchBar 搜索框组件
|
|
@@ -11,13 +12,11 @@ import type { TSearchBarProps } from './type.uts'
|
|
|
11
12
|
type Props = Omit<TSearchBarProps, 'modelValue'>
|
|
12
13
|
|
|
13
14
|
const props = withDefaults(defineProps<Props>(), {
|
|
14
|
-
placeholder: '请输入搜索关键词',
|
|
15
15
|
shape: 'square',
|
|
16
16
|
background: '#f5f5f5',
|
|
17
17
|
maxlength: -1,
|
|
18
18
|
clearable: true,
|
|
19
19
|
showCancel: false,
|
|
20
|
-
cancelText: '取消',
|
|
21
20
|
disabled: false,
|
|
22
21
|
readonly: false,
|
|
23
22
|
autoFocus: false,
|
|
@@ -40,6 +39,22 @@ const emit = defineEmits<{
|
|
|
40
39
|
blur: [event: Event]
|
|
41
40
|
}>()
|
|
42
41
|
|
|
42
|
+
// 使用 i18n
|
|
43
|
+
const { $t } = useI18n()
|
|
44
|
+
|
|
45
|
+
// 优先使用用户传入的值,否则使用翻译
|
|
46
|
+
const displayPlaceholder = computed(() => {
|
|
47
|
+
return props.placeholder !== undefined && props.placeholder !== ''
|
|
48
|
+
? props.placeholder
|
|
49
|
+
: $t('searchBar.placeholder')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const displayCancelText = computed(() => {
|
|
53
|
+
return props.cancelText !== undefined && props.cancelText !== ''
|
|
54
|
+
? props.cancelText
|
|
55
|
+
: $t('searchBar.cancelText')
|
|
56
|
+
})
|
|
57
|
+
|
|
43
58
|
// 状态管理
|
|
44
59
|
const isFocused = ref<boolean>(false)
|
|
45
60
|
let debounceTimer: number | null = null
|
|
@@ -149,7 +164,7 @@ const handleCancel = (): void => {
|
|
|
149
164
|
class="t-search-bar__input"
|
|
150
165
|
type="text"
|
|
151
166
|
:value="modelValue"
|
|
152
|
-
:placeholder="
|
|
167
|
+
:placeholder="displayPlaceholder"
|
|
153
168
|
:maxlength="maxlength"
|
|
154
169
|
:disabled="disabled"
|
|
155
170
|
:focus="autoFocus"
|
|
@@ -175,7 +190,7 @@ const handleCancel = (): void => {
|
|
|
175
190
|
class="t-search-bar__cancel"
|
|
176
191
|
@click="handleCancel"
|
|
177
192
|
>
|
|
178
|
-
{{
|
|
193
|
+
{{ displayCancelText }}
|
|
179
194
|
</text>
|
|
180
195
|
</view>
|
|
181
196
|
</template>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n 错误处理工具类
|
|
3
|
+
* 提供统一的错误和警告输出
|
|
4
|
+
*/
|
|
5
|
+
export class I18nError {
|
|
6
|
+
/**
|
|
7
|
+
* 警告:语言代码不存在
|
|
8
|
+
* @param locale 语言代码
|
|
9
|
+
*/
|
|
10
|
+
static warnLocaleNotFound(locale: string): void {
|
|
11
|
+
console.warn(`[Tang UI I18n] Locale "${locale}" not found, using fallback locale`)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 警告:翻译键不存在
|
|
16
|
+
* @param key 翻译键
|
|
17
|
+
* @param locale 语言代码
|
|
18
|
+
*/
|
|
19
|
+
static warnKeyNotFound(key: string, locale: string): void {
|
|
20
|
+
// 仅在开发环境输出警告
|
|
21
|
+
if (process.env.NODE_ENV === 'development') {
|
|
22
|
+
console.warn(`[Tang UI I18n] Translation key "${key}" not found in locale "${locale}"`)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 错误:语言包格式无效
|
|
28
|
+
* @param locale 语言代码
|
|
29
|
+
*/
|
|
30
|
+
static errorInvalidMessages(locale: string): void {
|
|
31
|
+
console.error(`[Tang UI I18n] Invalid messages format for locale "${locale}"`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 警告:参数缺失
|
|
36
|
+
* @param key 翻译键
|
|
37
|
+
* @param param 参数名
|
|
38
|
+
*/
|
|
39
|
+
static warnMissingParam(key: string, param: string): void {
|
|
40
|
+
// 仅在开发环境输出警告
|
|
41
|
+
if (process.env.NODE_ENV === 'development') {
|
|
42
|
+
console.warn(`[Tang UI I18n] Missing parameter "${param}" for key "${key}"`)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 警告:翻译键格式无效
|
|
48
|
+
* @param key 翻译键
|
|
49
|
+
*/
|
|
50
|
+
static warnInvalidKey(key: string): void {
|
|
51
|
+
if (process.env.NODE_ENV === 'development') {
|
|
52
|
+
console.warn(`[Tang UI I18n] Invalid translation key format: "${key}". Expected format: "moduleName.key"`)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 错误:语言包不是有效的对象
|
|
58
|
+
* @param locale 语言代码
|
|
59
|
+
*/
|
|
60
|
+
static errorMessagesNotObject(locale: string): void {
|
|
61
|
+
console.error(`[Tang UI I18n] Messages for locale "${locale}" must be a valid object`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 错误:模块不是有效的对象
|
|
66
|
+
* @param locale 语言代码
|
|
67
|
+
* @param moduleName 模块名
|
|
68
|
+
*/
|
|
69
|
+
static errorModuleNotObject(locale: string, moduleName: string): void {
|
|
70
|
+
console.error(`[Tang UI I18n] Module "${moduleName}" in locale "${locale}" must be a valid object`)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 错误:键值不是字符串
|
|
75
|
+
* @param locale 语言代码
|
|
76
|
+
* @param moduleName 模块名
|
|
77
|
+
* @param key 键名
|
|
78
|
+
*/
|
|
79
|
+
static errorValueNotString(locale: string, moduleName: string, key: string): void {
|
|
80
|
+
console.error(`[Tang UI I18n] Value for key "${key}" in module "${moduleName}" of locale "${locale}" must be a string`)
|
|
81
|
+
}
|
|
82
|
+
}
|