mirror of
https://gitee.com/wot-design-uni/wot-design-uni.git
synced 2025-12-06 17:18:40 +08:00
feat: ✨ 支持国际化 (#168)
* feat: ✨ 支持国际化 * feat: ✨ 支持国际化 * fix: 🐛 支持国际化 * docs: ✏️ 文档中增加国际化的介绍 * feat: ✨ 支持越南语 * docs: ✏️ 文档中增加支持国际化的版本 * refactor: ♻️ 调整防抖函数的实现 * docs: ✏️ 文档中增加vite.config.ts国际化相关的配置 * docs: ✏️ 增加支持越南文 --------- Co-authored-by: xuqingkai <xuqingkai@hd123.com>
This commit is contained in:
parent
38465905e7
commit
ce9f19244e
@ -48,7 +48,7 @@
|
||||
- 🚀 支持 APP、H5、微信小程序 等平台.
|
||||
- 🚀 60+ 个高质量组件,覆盖移动端主流场景.
|
||||
- 💪 使用 Typescript 构建,提供良好的组件类型系统.
|
||||
- 💪 采用 Vue3 最新特性,提升组件性能.
|
||||
- 🌍 支持国际化,内置 6 种语言包.
|
||||
- 📖 提供丰富的文档和组件示例.
|
||||
- 🎨 支持修改 CSS 变量实现主题定制.
|
||||
- 🍭 支持暗黑模式
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-07-27 10:26:09
|
||||
* @LastEditTime: 2024-01-06 22:20:13
|
||||
* @LastEditTime: 2024-01-26 13:32:22
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: /wot-design-uni/docs/.vitepress/config.ts
|
||||
* @FilePath: \wot-design-uni\docs\.vitepress\config.ts
|
||||
* 记得注释
|
||||
*/
|
||||
import { defineConfig } from 'vitepress';
|
||||
|
||||
export default defineConfig({
|
||||
title: `Wot Design Uni`,
|
||||
description: '一个参照Wot-design打造的uni-app组件库',
|
||||
description: '一个参照wot-design打造的uni-app组件库',
|
||||
head: [
|
||||
['link', { rel: 'icon', href: '/favicon.ico' }],
|
||||
['script', {}, `
|
||||
@ -69,15 +69,17 @@ export default defineConfig({
|
||||
{
|
||||
text: '字体',
|
||||
link: '/guide/typography',
|
||||
}, {
|
||||
text: '常见问题',
|
||||
link: '/guide/common-problems',
|
||||
},
|
||||
{
|
||||
text: '国际化',
|
||||
link: '/guide/locale',
|
||||
}, {
|
||||
text: '更新日志',
|
||||
link: '/guide/changelog',
|
||||
},
|
||||
{
|
||||
text: '常见问题',
|
||||
link: '/guide/common-problems',
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -133,13 +135,17 @@ export default defineConfig({
|
||||
link: '/guide/typography',
|
||||
},
|
||||
{
|
||||
text: '更新日志',
|
||||
link: '/guide/changelog',
|
||||
text: '国际化',
|
||||
link: '/guide/locale',
|
||||
},
|
||||
{
|
||||
text: '常见问题',
|
||||
link: '/guide/common-problems',
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '更新日志',
|
||||
link: '/guide/changelog',
|
||||
},
|
||||
],
|
||||
'/reward/': [
|
||||
{
|
||||
@ -151,7 +157,7 @@ export default defineConfig({
|
||||
link: '/reward/donor',
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
'/component/': [
|
||||
{
|
||||
text: '基础',
|
||||
@ -184,7 +190,7 @@ export default defineConfig({
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
|
||||
text: "导航",
|
||||
items: [{
|
||||
link: "/component/pagination",
|
||||
@ -209,7 +215,7 @@ export default defineConfig({
|
||||
text: "Sidebar 侧边栏"
|
||||
}]
|
||||
}, {
|
||||
|
||||
|
||||
text: "数据输入",
|
||||
items: [{
|
||||
link: "/component/calendar",
|
||||
@ -324,7 +330,7 @@ export default defineConfig({
|
||||
text: "NumberKeyboard 数字键盘"
|
||||
}]
|
||||
}, {
|
||||
|
||||
|
||||
text: "数据展示",
|
||||
items: [{
|
||||
link: "/component/badge",
|
||||
@ -384,7 +390,7 @@ export default defineConfig({
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
})
|
||||
@ -87,7 +87,7 @@ const columns = ref([
|
||||
|
||||
传入 `column-change` 属性,其类型为 `function`,接收 pickerView 实例、选中项、当前修改列的下标、resolve 作为入参,根据选中项和列下标进行判断,通过 pickerView 实例暴露出来的 `setColumnData` 方法修改其他列的数据源,当修改完成后需要执行 `resolve()` 告知组件修改完成以继续执行,如果 `column-change` 包含异步操作,也可以使组件按照异步顺序进行执行。
|
||||
|
||||
> resolve 参数为 1.4.0 添加,每次修改完后都需要调用 resolve() 通知组件。
|
||||
> 每次修改完后都需要调用 resolve() 通知组件。
|
||||
|
||||
```html
|
||||
<wd-picker
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
- 🚀 支持 APP、H5、微信小程序 等平台.
|
||||
- 🚀 60+ 个高质量组件,覆盖移动端主流场景.
|
||||
- 💪 使用 Typescript 构建,提供良好的组件类型系统.
|
||||
- 💪 采用 Vue3 最新特性,提升组件性能.
|
||||
- 🌍 支持国际化,内置 6 种语言包.
|
||||
- 📖 提供丰富的文档和组件示例.
|
||||
- 🎨 支持修改 CSS 变量实现主题定制.
|
||||
- 🍭 支持暗黑模式
|
||||
|
||||
67
docs/guide/locale.md
Normal file
67
docs/guide/locale.md
Normal file
@ -0,0 +1,67 @@
|
||||
# 国际化<el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">0.2.20</el-tag>
|
||||
|
||||
Wot Design Uni 默认使用中文语言,同时支持多语言切换,如果你希望使用其他语言,你可以参考下面的方案。
|
||||
|
||||
:::warning 注意点
|
||||
目前组件库发布到 npm 上的包是未经编译的`vue`与`ts`,而 Vite 会将[预构建](https://cn.vitejs.dev/guide/dep-pre-bundling.html)的依赖项缓存到 `node_modules/.vite`,组件库的国际化的实现是基于`reactive`实现的数据共享,在`dev`阶段就会出现页面使用预构建产物中的国际化数据,而组件库使用组件库内部的国际化数据,所以在非`uni_modules`模式引入时,需要在`vite.config.ts`中增加以下配置:
|
||||
|
||||
```ts
|
||||
import { defineConfig } from 'vite'
|
||||
import uni from '@dcloudio/vite-plugin-uni'
|
||||
|
||||
export default defineConfig({
|
||||
...
|
||||
optimizeDeps: {
|
||||
exclude: process.env.UNI_PLATFORM === 'h5' && process.env.NODE_ENV === 'development' ? ['wot-design-uni'] : []
|
||||
}
|
||||
...
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
使用[optimizeDeps.exclude](https://cn.vitejs.dev/config/dep-optimization-options.html#optimizedeps-exclude)在预构建中强制排除`wot-design-uni`模块,在`uni_modules`模式下,不需要做任何处理。
|
||||
|
||||
:::
|
||||
|
||||
## 使用其他语言
|
||||
|
||||
我们通过 **Locale** 组件实现多语言支持,使用 **Locale.use** 方法可以切换当前使用的语言。
|
||||
|
||||
```typescript
|
||||
import { Locale } from 'wot-design-uni'
|
||||
// 引入英文语言包
|
||||
import enUS from 'wot-design-uni/locale/lang/en-US'
|
||||
|
||||
Locale.use('en-US', enUS)
|
||||
```
|
||||
|
||||
## 覆盖语言包
|
||||
|
||||
通过 **Locale.add** 方法可以实现文案的修改和扩展,示例如下:
|
||||
|
||||
```typescript
|
||||
import { Locale } from 'wot-design-uni'
|
||||
|
||||
const messages = {
|
||||
'zh-CN': {
|
||||
calendar: {
|
||||
title: '请选择日期' // 将'选择日期'修改为'请选择日期'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Locale.add(messages)
|
||||
```
|
||||
|
||||
## 支持的语言
|
||||
|
||||
| 语言 | 文件名 | 版本 |
|
||||
| ---------------- | --------- | --------- |
|
||||
| 简体中文 | zh-CN | `v0.2.20` |
|
||||
| 繁体中文(台湾) | zh-TW | `v0.2.20` |
|
||||
| 繁体中文(香港) | zh-HK | `v0.2.20` |
|
||||
| 英文 | en-US | `v0.2.20` |
|
||||
| 泰文 | th-TH | `v0.2.20` |
|
||||
| 越南文 | vi-VN | `v0.2.20` |
|
||||
|
||||
如果你需要使用其他的语言,欢迎贡献 [PR](https://github.com/Moonofweisheng/wot-design-uni/pulls),只需在[这里](https://github.com/Moonofweisheng/wot-design-uni/tree/master/src/uni_modules/wot-design-uni/locale/lang)添加一个语言配置文件即可。
|
||||
@ -2,12 +2,12 @@
|
||||
layout: home
|
||||
|
||||
title: Wot Design Uni
|
||||
titleTemplate: 一个参照Wot-design打造的uni-app组件库
|
||||
titleTemplate: 基于Vue3+TS开发的uni-app组件库
|
||||
|
||||
hero:
|
||||
name: Wot Design Uni
|
||||
text:
|
||||
tagline: 一个参照Wot-design打造的uni-app组件库
|
||||
tagline: 基于Vue3+TS开发的uni-app组件库
|
||||
image:
|
||||
src: /wot-design.png
|
||||
alt: Wot Design
|
||||
@ -30,17 +30,17 @@ features:
|
||||
title: 60+ 组件
|
||||
details: 超过 60 个高质量组件,覆盖移动端主流场景。
|
||||
- icon: 💪
|
||||
title: 支持 TypeScript
|
||||
title: TypeScript 支持
|
||||
details: 使用 Typescript 构建,提供良好的组件类型系统。
|
||||
- icon: 💪
|
||||
title: 支持 Vue3
|
||||
details: 采用 Vue3 最新特性,提升组件性能。
|
||||
- icon: 🌍
|
||||
title: 支持国际化
|
||||
details: 支持国际化,内置 6 种语言包。
|
||||
- icon: 📖
|
||||
title: 提供丰富的文档和组件示例
|
||||
details: 文档和组件示例为开发者提供稳定的后勤保障。
|
||||
- icon: 🍭
|
||||
title: 支持暗黑模式和主题定制
|
||||
details: 可以定制scss变量以及组件的样式自定义。
|
||||
details: 可以定制css变量以及组件的样式自定义。
|
||||
|
||||
footer: false
|
||||
---
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-03-09 19:23:03
|
||||
* @LastEditTime: 2023-08-22 23:02:46
|
||||
* @LastEditTime: 2024-01-26 14:08:43
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\main.ts
|
||||
|
||||
@ -1,206 +0,0 @@
|
||||
import isObject from './isObject'
|
||||
import root from './internal/root'
|
||||
|
||||
/**
|
||||
* Creates a debounced function that delays invoking `func` until after `wait`
|
||||
* milliseconds have elapsed since the last time the debounced function was
|
||||
* invoked, or until the next browser frame is drawn. The debounced function
|
||||
* comes with a `cancel` method to cancel delayed `func` invocations and a
|
||||
* `flush` method to immediately invoke them. Provide `options` to indicate
|
||||
* whether `func` should be invoked on the leading and/or trailing edge of the
|
||||
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
||||
* debounced function. Subsequent calls to the debounced function return the
|
||||
* result of the last `func` invocation.
|
||||
*
|
||||
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
||||
* invoked on the trailing edge of the timeout only if the debounced function
|
||||
* is invoked more than once during the `wait` timeout.
|
||||
*
|
||||
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
||||
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
||||
*
|
||||
* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
|
||||
* invocation will be deferred until the next frame is drawn (typically about
|
||||
* 16ms).
|
||||
*
|
||||
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
||||
* for details over the differences between `debounce` and `throttle`.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @category Function
|
||||
* @param {Function} func The function to debounce.
|
||||
* @param {number} [wait=0]
|
||||
* The number of milliseconds to delay; if omitted, `requestAnimationFrame` is
|
||||
* used (if available).
|
||||
* @param {Object} [options={}] The options object.
|
||||
* @param {boolean} [options.leading=false]
|
||||
* Specify invoking on the leading edge of the timeout.
|
||||
* @param {number} [options.maxWait]
|
||||
* The maximum time `func` is allowed to be delayed before it's invoked.
|
||||
* @param {boolean} [options.trailing=true]
|
||||
* Specify invoking on the trailing edge of the timeout.
|
||||
* @returns {Function} Returns the new debounced function.
|
||||
* @example
|
||||
*
|
||||
* // Avoid costly calculations while the window size is in flux.
|
||||
* jQuery(window).on('resize', debounce(calculateLayout, 150))
|
||||
*
|
||||
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
|
||||
* jQuery(element).on('click', debounce(sendMail, 300, {
|
||||
* 'leading': true,
|
||||
* 'trailing': false
|
||||
* }))
|
||||
*
|
||||
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
|
||||
* const debounced = debounce(batchLog, 250, { 'maxWait': 1000 })
|
||||
* const source = new EventSource('/stream')
|
||||
* jQuery(source).on('message', debounced)
|
||||
*
|
||||
* // Cancel the trailing debounced invocation.
|
||||
* jQuery(window).on('popstate', debounced.cancel)
|
||||
*
|
||||
* // Check for pending invocations.
|
||||
* const status = debounced.pending() ? "Pending..." : "Ready"
|
||||
*/
|
||||
function debounce(func, wait, options?) {
|
||||
let lastArgs, lastThis, maxWait, result, timerId, lastCallTime
|
||||
|
||||
let lastInvokeTime = 0
|
||||
let leading = false
|
||||
let maxing = false
|
||||
let trailing = true
|
||||
|
||||
// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
|
||||
const useRAF = !wait && wait !== 0 && typeof root.requestAnimationFrame === 'function'
|
||||
|
||||
if (typeof func !== 'function') {
|
||||
throw new TypeError('Expected a function')
|
||||
}
|
||||
wait = +wait || 0
|
||||
if (isObject(options)) {
|
||||
leading = !!options.leading
|
||||
maxing = 'maxWait' in options
|
||||
maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait
|
||||
trailing = 'trailing' in options ? !!options.trailing : trailing
|
||||
}
|
||||
|
||||
function invokeFunc(time) {
|
||||
const args = lastArgs
|
||||
const thisArg = lastThis
|
||||
|
||||
lastArgs = lastThis = undefined
|
||||
lastInvokeTime = time
|
||||
result = func.apply(thisArg, args)
|
||||
return result
|
||||
}
|
||||
|
||||
function startTimer(pendingFunc, wait) {
|
||||
if (useRAF) {
|
||||
root.cancelAnimationFrame(timerId)
|
||||
return root.requestAnimationFrame(pendingFunc)
|
||||
}
|
||||
return setTimeout(pendingFunc, wait)
|
||||
}
|
||||
|
||||
function cancelTimer(id) {
|
||||
if (useRAF) {
|
||||
return root.cancelAnimationFrame(id)
|
||||
}
|
||||
clearTimeout(id)
|
||||
}
|
||||
|
||||
function leadingEdge(time) {
|
||||
// Reset any `maxWait` timer.
|
||||
lastInvokeTime = time
|
||||
// Start the timer for the trailing edge.
|
||||
timerId = startTimer(timerExpired, wait)
|
||||
// Invoke the leading edge.
|
||||
return leading ? invokeFunc(time) : result
|
||||
}
|
||||
|
||||
function remainingWait(time) {
|
||||
const timeSinceLastCall = time - lastCallTime
|
||||
const timeSinceLastInvoke = time - lastInvokeTime
|
||||
const timeWaiting = wait - timeSinceLastCall
|
||||
|
||||
return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting
|
||||
}
|
||||
|
||||
function shouldInvoke(time) {
|
||||
const timeSinceLastCall = time - lastCallTime
|
||||
const timeSinceLastInvoke = time - lastInvokeTime
|
||||
|
||||
// Either this is the first call, activity has stopped and we're at the
|
||||
// trailing edge, the system time has gone backwards and we're treating
|
||||
// it as the trailing edge, or we've hit the `maxWait` limit.
|
||||
return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || (maxing && timeSinceLastInvoke >= maxWait)
|
||||
}
|
||||
|
||||
function timerExpired() {
|
||||
const time = Date.now()
|
||||
if (shouldInvoke(time)) {
|
||||
return trailingEdge(time)
|
||||
}
|
||||
// Restart the timer.
|
||||
timerId = startTimer(timerExpired, remainingWait(time))
|
||||
}
|
||||
|
||||
function trailingEdge(time) {
|
||||
timerId = undefined
|
||||
|
||||
// Only invoke if we have `lastArgs` which means `func` has been
|
||||
// debounced at least once.
|
||||
if (trailing && lastArgs) {
|
||||
return invokeFunc(time)
|
||||
}
|
||||
lastArgs = lastThis = undefined
|
||||
return result
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
if (timerId !== undefined) {
|
||||
cancelTimer(timerId)
|
||||
}
|
||||
lastInvokeTime = 0
|
||||
lastArgs = lastCallTime = lastThis = timerId = undefined
|
||||
}
|
||||
|
||||
function flush() {
|
||||
return timerId === undefined ? result : trailingEdge(Date.now())
|
||||
}
|
||||
|
||||
function pending() {
|
||||
return timerId !== undefined
|
||||
}
|
||||
|
||||
function debounced(this: any, ...args) {
|
||||
const time = Date.now()
|
||||
const isInvoking = shouldInvoke(time)
|
||||
|
||||
lastArgs = args
|
||||
lastThis = this
|
||||
lastCallTime = time
|
||||
|
||||
if (isInvoking) {
|
||||
if (timerId === undefined) {
|
||||
return leadingEdge(lastCallTime)
|
||||
}
|
||||
if (maxing) {
|
||||
// Handle invocations in a tight loop.
|
||||
timerId = startTimer(timerExpired, wait)
|
||||
return invokeFunc(lastCallTime)
|
||||
}
|
||||
}
|
||||
if (timerId === undefined) {
|
||||
timerId = startTimer(timerExpired, wait)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
debounced.cancel = cancel
|
||||
debounced.flush = flush
|
||||
debounced.pending = pending
|
||||
return debounced
|
||||
}
|
||||
|
||||
export default debounce
|
||||
@ -1,4 +0,0 @@
|
||||
/** Detect free variable `global` from Node.js. */
|
||||
const freeGlobal = typeof global === 'object' && global !== null && global.Object === Object && global
|
||||
|
||||
export default freeGlobal
|
||||
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-09-01 21:42:32
|
||||
* @LastEditTime: 2023-09-03 11:43:06
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\common\lodash\internal\root.ts
|
||||
* 记得注释
|
||||
*/
|
||||
import freeGlobal from './freeGlobal'
|
||||
|
||||
/** Detect free variable `globalThis` */
|
||||
// eslint-disable-next-line eqeqeq
|
||||
const freeGlobalThis = typeof globalThis === 'object' && globalThis !== null && globalThis.Object == Object && globalThis
|
||||
|
||||
/** Detect free variable `self`. */
|
||||
const freeSelf = typeof self === 'object' && self !== null && self.Object === Object && self
|
||||
|
||||
/** Used as a reference to the global object. */
|
||||
// eslint-disable-next-line no-new-func
|
||||
const root = freeGlobalThis || freeGlobal || freeSelf || Function('return this')()
|
||||
|
||||
export default root
|
||||
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Checks if `value` is the
|
||||
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
||||
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @category Lang
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
||||
* @example
|
||||
*
|
||||
* isObject({})
|
||||
* // => true
|
||||
*
|
||||
* isObject([1, 2, 3])
|
||||
* // => true
|
||||
*
|
||||
* isObject(Function)
|
||||
* // => true
|
||||
*
|
||||
* isObject(null)
|
||||
* // => false
|
||||
*/
|
||||
function isObject(value) {
|
||||
const type = typeof value
|
||||
return value != null && (type === 'object' || type === 'function')
|
||||
}
|
||||
|
||||
export default isObject
|
||||
@ -1,6 +1,3 @@
|
||||
/* eslint-disable no-prototype-builtins */
|
||||
import debounce from './lodash/debounce'
|
||||
|
||||
/**
|
||||
* 生成uuid
|
||||
* @returns string
|
||||
@ -78,8 +75,6 @@ export const defaultFunction = <T>(value: T): T => value
|
||||
*/
|
||||
export const isDef = <T>(value: T): value is NonNullable<T> => value !== undefined && value !== null
|
||||
|
||||
export { debounce }
|
||||
|
||||
/**
|
||||
* @description 防止数字小于零
|
||||
* @param {number} num
|
||||
@ -275,6 +270,15 @@ export function kebabCase(word: string): string {
|
||||
return newWord
|
||||
}
|
||||
|
||||
/**
|
||||
* 将短横线链接转换为驼峰命名
|
||||
* @param word 需要转换的短横线链接
|
||||
* @returns 转换后的驼峰命名字符串
|
||||
*/
|
||||
export function camelCase(word: string): string {
|
||||
return word.replace(/-(\w)/g, (_, c) => c.toUpperCase())
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定值是否为数组。
|
||||
* @param {any} value 要检查的值
|
||||
@ -482,6 +486,7 @@ export function deepMerge<T extends Record<string, any>>(target: T, source: Reco
|
||||
|
||||
// 遍历源对象的属性
|
||||
for (const prop in source) {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!source.hasOwnProperty(prop))
|
||||
continue
|
||||
// 使用类型断言,告诉 TypeScript 这是有效的属性
|
||||
@ -491,6 +496,25 @@ export function deepMerge<T extends Record<string, any>>(target: T, source: Reco
|
||||
return target
|
||||
}
|
||||
|
||||
/**
|
||||
* 深度合并两个对象。
|
||||
* @param target
|
||||
* @param source
|
||||
* @returns
|
||||
*/
|
||||
export function deepAssign(target: Record<string, any>, source: Record<string, any>): Record<string, any> {
|
||||
Object.keys(source).forEach((key) => {
|
||||
const targetValue = target[key]
|
||||
const newObjValue = source[key]
|
||||
if (isObj(targetValue) && isObj(newObjValue)) {
|
||||
deepAssign(targetValue, newObjValue)
|
||||
} else {
|
||||
target[key] = newObjValue
|
||||
}
|
||||
})
|
||||
return target
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建带参数的URL
|
||||
* @param baseUrl 基础URL
|
||||
@ -510,10 +534,66 @@ export function buildUrlWithParams(baseUrl: string, params: Record<string, strin
|
||||
return `${baseUrl}${separator}${queryString}`
|
||||
}
|
||||
|
||||
type DebounceOptions = {
|
||||
leading?: boolean // 是否在延迟时间开始时调用函数
|
||||
trailing?: boolean // 是否在延迟时间结束时调用函数
|
||||
}
|
||||
|
||||
export function debounce<T extends (...args: any[]) => any>(func: T, wait: number, options: DebounceOptions = {}): T {
|
||||
let timeoutId: ReturnType<typeof setTimeout> | null = null
|
||||
let lastArgs: any[] | undefined
|
||||
let lastThis: any
|
||||
let result: ReturnType<T> | undefined
|
||||
const leading = options.leading ?? false
|
||||
const trailing = options.trailing ?? true
|
||||
|
||||
function invokeFunc() {
|
||||
if (lastArgs !== undefined) {
|
||||
result = func.apply(lastThis, lastArgs)
|
||||
lastArgs = undefined
|
||||
}
|
||||
}
|
||||
|
||||
function startTimer() {
|
||||
timeoutId = setTimeout(() => {
|
||||
timeoutId = null
|
||||
if (trailing) {
|
||||
invokeFunc()
|
||||
}
|
||||
}, wait)
|
||||
}
|
||||
|
||||
function cancelTimer() {
|
||||
if (timeoutId !== null) {
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = null
|
||||
}
|
||||
}
|
||||
|
||||
function debounced(this: any, ...args: Parameters<T>): ReturnType<T> | undefined {
|
||||
lastArgs = args
|
||||
lastThis = this
|
||||
|
||||
if (timeoutId === null) {
|
||||
if (leading) {
|
||||
invokeFunc()
|
||||
}
|
||||
startTimer()
|
||||
} else if (trailing) {
|
||||
cancelTimer()
|
||||
startTimer()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
return debounced as T
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function throttle(func: Function, wait: number): Function {
|
||||
let timeout: NodeJS.Timeout | null
|
||||
let previous = 0
|
||||
let timeout: ReturnType<typeof setTimeout> | null = null
|
||||
let previous: number = 0
|
||||
|
||||
const throttled = function (this: any, ...args: any[]) {
|
||||
const now = Date.now()
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2024-01-25 23:06:48
|
||||
* @LastEditTime: 2024-01-26 14:00:48
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\composables\useTranslate.ts
|
||||
* 记得注释
|
||||
*/
|
||||
import { camelCase, getPropByPath, isFunction } from '../common/util'
|
||||
import Locale from '../../locale'
|
||||
|
||||
export const useTranslate = (name?: string) => {
|
||||
const prefix = name ? camelCase(name) + '.' : ''
|
||||
const translate = (key: string, ...args: unknown[]) => {
|
||||
const currentMessages = Locale.messages()
|
||||
const message = getPropByPath(currentMessages, prefix + key)
|
||||
return isFunction(message) ? message(...args) : message
|
||||
}
|
||||
|
||||
return { translate }
|
||||
}
|
||||
@ -51,6 +51,7 @@ import {
|
||||
} from '../utils'
|
||||
import { useToast } from '../../wd-toast'
|
||||
import { deepClone, getType, isArray } from '../../common/util'
|
||||
import { useTranslate } from '../../composables/useTranslate'
|
||||
|
||||
interface Props {
|
||||
type: string
|
||||
@ -70,6 +71,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
allowSameDay: false
|
||||
})
|
||||
|
||||
const { translate } = useTranslate('calendar-view')
|
||||
|
||||
const days = ref<Array<Record<string, any>>>([])
|
||||
|
||||
const itemClass = computed(() => {
|
||||
@ -295,7 +298,7 @@ function handleDateRangeChange(date) {
|
||||
const maxEndDate = getDayByOffset(startDate, props.maxRange - 1)
|
||||
value = [startDate, getDate(maxEndDate, true)]
|
||||
toast.show({
|
||||
msg: props.rangePrompt || `选择天数不能超过${props.maxRange}天`
|
||||
msg: props.rangePrompt || translate('rangePrompt', props.maxRange)
|
||||
})
|
||||
} else {
|
||||
value = [startDate, getDate(date.date, true)]
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
</scroll-view>
|
||||
<view v-if="timeType" class="wd-month-panel__time">
|
||||
<view v-if="type === 'datetimerange'" class="wd-month-panel__time-label">
|
||||
<view class="wd-month-panel__time-text">{{ timeType === 'start' ? '开始' : '结束' }}</view>
|
||||
<view class="wd-month-panel__time-text">{{ timeType === 'start' ? translate('startTime') : translate('endTime') }}</view>
|
||||
</view>
|
||||
<view class="wd-month-panel__time-picker">
|
||||
<wd-picker-view
|
||||
@ -65,6 +65,7 @@ import { debounce, getType, isEqual } from '../../common/util'
|
||||
import { compareMonth, formatMonthTitle, getMonthEndDay, getMonths, getTimeData, getWeekLabel } from '../utils'
|
||||
import Month from '../month/month.vue'
|
||||
import type { MonthInfo } from './type'
|
||||
import { useTranslate } from '../../composables/useTranslate'
|
||||
|
||||
interface Props {
|
||||
type: string
|
||||
@ -89,6 +90,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
showPanelTitle: false,
|
||||
hideSecond: false
|
||||
})
|
||||
const { translate } = useTranslate('calendar-view')
|
||||
|
||||
const title = ref<string>('')
|
||||
const scrollTop = ref<number>(0) // 滚动位置
|
||||
|
||||
@ -1,6 +1,17 @@
|
||||
import { dayjs } from '../common/dayjs'
|
||||
import { getType, padZero } from '../common/util'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
const { translate } = useTranslate('calendar-view')
|
||||
|
||||
const weeks: string[] = ['日', '一', '二', '三', '四', '五', '六']
|
||||
const weeks: string[] = [
|
||||
translate('weeks.sun'),
|
||||
translate('weeks.mon'),
|
||||
translate('weeks.tue'),
|
||||
translate('weeks.wed'),
|
||||
translate('weeks.thu'),
|
||||
translate('weeks.fri'),
|
||||
translate('weeks.sat')
|
||||
]
|
||||
|
||||
/**
|
||||
* 比较两个时间的日期是否相等
|
||||
@ -86,12 +97,7 @@ export function getMonthEndDay(year, month) {
|
||||
* @param {timestamp} date
|
||||
*/
|
||||
export function formatMonthTitle(date) {
|
||||
date = new Date(date)
|
||||
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth() + 1
|
||||
|
||||
return year + '年' + month + '月'
|
||||
return dayjs(date).format(translate('monthTitle'))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,9 +135,7 @@ export function getFirstDayStyle(index: number, date: number, firstDayOfWeek: nu
|
||||
* @param {timestamp} date
|
||||
*/
|
||||
export function formatYearTitle(date: number) {
|
||||
const year = new Date(date).getFullYear()
|
||||
|
||||
return year + '年'
|
||||
return dayjs(date).format(translate('yearTitle'))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -350,14 +354,14 @@ export function getTimeData({ date, minDate, maxDate, isHideSecond, filter } = {
|
||||
let columns: any[] = []
|
||||
let hours = times(24, (index) => {
|
||||
return {
|
||||
label: `${padZero(index)}时`,
|
||||
label: translate('hour', padZero(index)),
|
||||
value: index,
|
||||
disabled: index < minHour || index > maxHour
|
||||
}
|
||||
})
|
||||
let minutes = times(60, (index) => {
|
||||
return {
|
||||
label: `${padZero(index)}分`,
|
||||
label: translate('minute', padZero(index)),
|
||||
value: index,
|
||||
disabled: index < minMinute || index > maxMinute
|
||||
}
|
||||
@ -377,7 +381,7 @@ export function getTimeData({ date, minDate, maxDate, isHideSecond, filter } = {
|
||||
if (!isHideSecond) {
|
||||
seconds = times(60, (index) => {
|
||||
return {
|
||||
label: `${padZero(index)}秒`,
|
||||
label: translate('second', padZero(index)),
|
||||
value: index,
|
||||
disabled: index < minSecond || index > maxSecond
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
@click="handleDateClick(index)"
|
||||
>
|
||||
<view class="wd-year__month-top">{{ item.topInfo }}</view>
|
||||
<view class="wd-year__month-text">{{ item.text }}月</view>
|
||||
<view class="wd-year__month-text">{{ getMonthLabel(item.date) }}</view>
|
||||
<view class="wd-year__month-bottom">{{ item.bottomInfo }}</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -29,9 +29,11 @@ export default {
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { deepClone, getType } from '../../common/util'
|
||||
import { deepClone, getType, padZero } from '../../common/util'
|
||||
import { compareMonth, formatYearTitle, getDateByDefaultTime, getItemClass, getMonthByOffset, getMonthOffset } from '../utils'
|
||||
import { useToast } from '../../wd-toast'
|
||||
import { useTranslate } from '../../composables/useTranslate'
|
||||
import { dayjs } from '../../common/dayjs'
|
||||
|
||||
interface Props {
|
||||
type: string
|
||||
@ -50,6 +52,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
allowSameDay: false
|
||||
})
|
||||
const toast = useToast('wd-year')
|
||||
const { translate } = useTranslate('calendar-view')
|
||||
|
||||
const months = ref<Record<string, any>[]>([])
|
||||
|
||||
@ -78,6 +81,10 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
function getMonthLabel(date) {
|
||||
return dayjs(date).format(translate('month', date))
|
||||
}
|
||||
|
||||
function setMonths() {
|
||||
const monthList: Record<string, any>[] = []
|
||||
const date = new Date(props.date)
|
||||
@ -166,7 +173,7 @@ function handleMonthRangeChange(date) {
|
||||
const maxEndDate = getMonthByOffset(startDate, props.maxRange - 1)
|
||||
value = [startDate, getDate(maxEndDate)]
|
||||
toast.show({
|
||||
msg: props.rangePrompt || `选择月份不能超过${props.maxRange}个月`
|
||||
msg: props.rangePrompt || translate('rangePromptMonth', props.maxRange)
|
||||
})
|
||||
} else {
|
||||
value = [startDate, getDate(date.date)]
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
<view
|
||||
:class="`wd-calendar__value ${ellipsis ? 'is-ellipsis' : ''} ${customValueClass} ${showValue ? '' : 'wd-calendar__value--placeholder'}`"
|
||||
>
|
||||
{{ showValue || placeholder || '请选择' }}
|
||||
{{ showValue || placeholder || translate('placeholder') }}
|
||||
</view>
|
||||
<wd-icon v-if="!disabled && !readonly" custom-class="wd-calendar__arrow" name="arrow-right" />
|
||||
</view>
|
||||
@ -38,12 +38,12 @@
|
||||
@close="close"
|
||||
>
|
||||
<view class="wd-calendar__header">
|
||||
<view v-if="!showTypeSwitch && shortcuts.length === 0" class="wd-calendar__title">{{ title || '选择日期' }}</view>
|
||||
<view v-if="!showTypeSwitch && shortcuts.length === 0" class="wd-calendar__title">{{ title || translate('title') }}</view>
|
||||
<view v-if="showTypeSwitch" class="wd-calendar__tabs">
|
||||
<wd-tabs ref="calendarTabs" v-model="currentTab" @change="handleTypeChange">
|
||||
<wd-tab title="日" name="日" />
|
||||
<wd-tab title="周" name="周" />
|
||||
<wd-tab title="月" name="月" />
|
||||
<wd-tab :title="translate('day')" :name="translate('day')" />
|
||||
<wd-tab :title="translate('week')" :name="translate('week')" />
|
||||
<wd-tab :title="translate('month')" :name="translate('month')" />
|
||||
</wd-tabs>
|
||||
</view>
|
||||
<view v-if="shortcuts.length > 0" class="wd-calendar__shortcuts">
|
||||
@ -94,7 +94,7 @@
|
||||
/>
|
||||
</view>
|
||||
<view v-if="showConfirm" class="wd-calendar__confirm">
|
||||
<wd-button block :disabled="confirmBtnDisabled" @click="handleConfirm">{{ confirmText || '确定' }}</wd-button>
|
||||
<wd-button block :disabled="confirmBtnDisabled" @click="handleConfirm">{{ confirmText || translate('confirm') }}</wd-button>
|
||||
</view>
|
||||
</wd-action-sheet>
|
||||
</view>
|
||||
@ -119,6 +119,8 @@ import { getWeekNumber, isRange } from '../wd-calendar-view/utils'
|
||||
import { useCell } from '../composables/useCell'
|
||||
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
|
||||
import { useParent } from '../composables/useParent'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
const { translate } = useTranslate('calendar')
|
||||
|
||||
const defaultDisplayFormat = (value, type) => {
|
||||
switch (type) {
|
||||
@ -131,29 +133,35 @@ const defaultDisplayFormat = (value, type) => {
|
||||
})
|
||||
.join(', ')
|
||||
case 'daterange':
|
||||
return `${value[0] ? dayjs(value[0]).format('YYYY-MM-DD') : '开始时间'} 至 ${value[1] ? dayjs(value[1]).format('YYYY-MM-DD') : '结束时间'}`
|
||||
return `${value[0] ? dayjs(value[0]).format('YYYY-MM-DD') : translate('startTime')} ${translate('to')} ${
|
||||
value[1] ? dayjs(value[1]).format('YYYY-MM-DD') : translate('endTime')
|
||||
}`
|
||||
case 'datetime':
|
||||
return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
|
||||
case 'datetimerange':
|
||||
return `${value[0] ? dayjs(value[0]).format('YY年MM月DD日 HH:mm:ss') : '开始时间'} 至\n${
|
||||
value[1] ? dayjs(value[1]).format('YY年MM月DD日 HH:mm:ss') : '结束时间'
|
||||
return `${value[0] ? dayjs(value[0]).format(translate('timeFormat')) : translate('startTime')} ${translate('to')}\n${
|
||||
value[1] ? dayjs(value[1]).format(translate('timeFormat')) : translate('endTime')
|
||||
}`
|
||||
case 'week': {
|
||||
const year = new Date(value).getFullYear()
|
||||
const week = getWeekNumber(value)
|
||||
return `${year} 第 ${padZero(week)} 周`
|
||||
return translate('weekFormat', year, padZero(week))
|
||||
}
|
||||
case 'weekrange': {
|
||||
const year1 = new Date(value[0]).getFullYear()
|
||||
const week1 = getWeekNumber(value[0])
|
||||
const year2 = new Date(value[1]).getFullYear()
|
||||
const week2 = getWeekNumber(value[1])
|
||||
return `${value[0] ? `${year1} 第 ${padZero(week1)} 周` : '开始周'} - ${value[1] ? `${year2} 第 ${padZero(week2)} 周` : '结束周'}`
|
||||
return `${value[0] ? translate('weekFormat', year1, padZero(week1)) : translate('startWeek')} - ${
|
||||
value[1] ? translate('weekFormat', year2, padZero(week2)) : translate('endWeek')
|
||||
}`
|
||||
}
|
||||
case 'month':
|
||||
return dayjs(value).format('YYYY / MM')
|
||||
case 'monthrange':
|
||||
return `${value[0] ? dayjs(value[0]).format('YYYY / MM') : '开始月'} 至 ${value[1] ? dayjs(value[1]).format('YYYY / MM') : '结束月'}`
|
||||
return `${value[0] ? dayjs(value[0]).format('YYYY / MM') : translate('startMonth')} ${translate('to')} ${
|
||||
value[1] ? dayjs(value[1]).format('YYYY / MM') : translate('endMonth')
|
||||
}`
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,28 +169,28 @@ const formatRange = (value, rangeType, type) => {
|
||||
switch (type) {
|
||||
case 'daterange':
|
||||
if (!value) {
|
||||
return rangeType === 'end' ? '结束时间' : '开始时间'
|
||||
return rangeType === 'end' ? translate('endTime') : translate('startTime')
|
||||
}
|
||||
return dayjs(value).format('YYYY年MM月DD日')
|
||||
return dayjs(value).format(translate('dateFormat'))
|
||||
case 'datetimerange':
|
||||
if (!value) {
|
||||
return rangeType === 'end' ? '结束时间' : '开始时间'
|
||||
return rangeType === 'end' ? translate('endTime') : translate('startTime')
|
||||
}
|
||||
return dayjs(value).format('YY年MM月DD日 HH:mm:ss')
|
||||
return dayjs(value).format(translate('timeFormat'))
|
||||
case 'weekrange': {
|
||||
if (!value) {
|
||||
return rangeType === 'end' ? '结束周' : '开始周'
|
||||
return rangeType === 'end' ? translate('endWeek') : translate('startWeek')
|
||||
}
|
||||
const date = new Date(value)
|
||||
const year = date.getFullYear()
|
||||
const week = getWeekNumber(value)
|
||||
return year + '年第' + week + '周'
|
||||
return translate('weekFormat', year, padZero(week))
|
||||
}
|
||||
case 'monthrange':
|
||||
if (!value) {
|
||||
return rangeType === 'end' ? '结束月' : '开始月'
|
||||
return rangeType === 'end' ? translate('endMonth') : translate('startMonth')
|
||||
}
|
||||
return dayjs(value).format('YYYY年MM月')
|
||||
return dayjs(value).format(translate('monthFormat'))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
<view
|
||||
:class="`wd-col-picker__value ${ellipsis && 'is-ellipsis'} ${customValueClass} ${showValue ? '' : 'wd-col-picker__value--placeholder'}`"
|
||||
>
|
||||
{{ showValue || placeholder || '请选择' }}
|
||||
{{ showValue || placeholder || translate('placeholder') }}
|
||||
</view>
|
||||
<wd-icon v-if="!disabled && !readonly" custom-class="wd-col-picker__arrow" name="arrow-right" />
|
||||
</view>
|
||||
@ -32,7 +32,7 @@
|
||||
<wd-action-sheet
|
||||
v-model="pickerShow"
|
||||
:duration="250"
|
||||
:title="title || '请选择'"
|
||||
:title="title || translate('title')"
|
||||
:close-on-click-modal="closeOnClickModal"
|
||||
:z-index="zIndex"
|
||||
:safe-area-inset-bottom="safeAreaInsetBottom"
|
||||
@ -48,7 +48,7 @@
|
||||
:class="`wd-col-picker__selected-item ${colIndex === currentCol && 'is-selected'}`"
|
||||
@click="handleColClick(colIndex)"
|
||||
>
|
||||
{{ selectShowList[colIndex] || '请选择' }}
|
||||
{{ selectShowList[colIndex] || translate('select') }}
|
||||
</view>
|
||||
<view class="wd-col-picker__selected-line" :style="lineStyle"></view>
|
||||
</view>
|
||||
@ -100,6 +100,9 @@ import { debounce, getRect, getType } from '../common/util'
|
||||
import { useCell } from '../composables/useCell'
|
||||
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
|
||||
import { useParent } from '../composables/useParent'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
const { translate } = useTranslate('col-picker')
|
||||
|
||||
const $container = '.wd-col-picker__selected-container'
|
||||
const $item = '.wd-col-picker__selected-item'
|
||||
@ -154,7 +157,6 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
useDefaultSlot: false,
|
||||
disabled: false,
|
||||
readonly: false,
|
||||
placeholder: '请选择',
|
||||
alignRight: false,
|
||||
error: false,
|
||||
required: false,
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
<!--
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-06-13 11:34:35
|
||||
* @LastEditTime: 2024-01-03 21:59:39
|
||||
* @LastEditTime: 2024-01-26 11:53:06
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: /wot-design-uni/src/uni_modules/wot-design-uni/components/wd-col/wd-col.vue
|
||||
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-col\wd-col.vue
|
||||
* 记得注释
|
||||
-->
|
||||
<template>
|
||||
@ -25,7 +25,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, provide, watch } from 'vue'
|
||||
import { computed, watch } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import { useParent } from '../composables/useParent'
|
||||
import { ROW_KEY } from '../wd-row/types'
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
</view>
|
||||
<!-- 显示展开或折叠按钮 -->
|
||||
<block v-else>
|
||||
<span class="wd-collapse__more-txt">{{ !modelValue ? '展开' : '折叠' }}</span>
|
||||
<span class="wd-collapse__more-txt">{{ !modelValue ? translate('expand') : translate('retract') }}</span>
|
||||
<view :class="`wd-collapse__arrow ${modelValue ? 'is-retract' : ''}`">
|
||||
<wd-icon name="arrow-down"></wd-icon>
|
||||
</view>
|
||||
@ -45,6 +45,7 @@ import { onBeforeMount, ref, watch } from 'vue'
|
||||
import { COLLAPSE_KEY, type CollapseToggleAllOptions } from './types'
|
||||
import { useChildren } from '../composables/useChildren'
|
||||
import { isArray, isDef } from '../common/util'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
interface Props {
|
||||
customClass?: string
|
||||
@ -65,6 +66,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
lineNum: 2
|
||||
})
|
||||
|
||||
const { translate } = useTranslate('collapse')
|
||||
const contentLineNum = ref<number>(0) // 查看更多的折叠面板,收起时的显示行数
|
||||
|
||||
const { linkChildren, children } = useChildren(COLLAPSE_KEY)
|
||||
|
||||
@ -21,11 +21,11 @@
|
||||
<view :class="`wd-picker__value ${customValueClass}`">
|
||||
<view v-if="region">
|
||||
<text :class="showValue[0] ? '' : 'wd-picker__placeholder'">{{ showValue[0] ? showValue[0] : placeholder }}</text>
|
||||
至
|
||||
{{ translate('to') }}
|
||||
<text :class="showValue[1] ? '' : 'wd-picker__placeholder'">{{ showValue[1] ? showValue[1] : placeholder }}</text>
|
||||
</view>
|
||||
<view v-else :class="showValue ? '' : 'wd-picker__placeholder'">
|
||||
{{ showValue ? showValue : placeholder }}
|
||||
{{ showValue ? showValue : placeholder || translate('placeholder') }}
|
||||
</view>
|
||||
</view>
|
||||
<wd-icon v-if="!disabled && !readonly" custom-class="wd-picker__arrow" name="arrow-right" />
|
||||
@ -50,23 +50,23 @@
|
||||
<view class="wd-picker__toolbar" @touchmove="noop">
|
||||
<!--取消按钮-->
|
||||
<view class="wd-picker__action wd-picker__action--cancel" @click="onCancel">
|
||||
{{ cancelButtonText }}
|
||||
{{ cancelButtonText || translate('cancel') }}
|
||||
</view>
|
||||
<!--标题-->
|
||||
<view v-if="title" class="wd-picker__title">{{ title }}</view>
|
||||
<!--确定按钮-->
|
||||
<view :class="`wd-picker__action ${loading || isLoading ? 'is-loading' : ''}`" @click="onConfirm">
|
||||
{{ confirmButtonText }}
|
||||
{{ confirmButtonText || translate('confirm') }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 区域选择tab展示 -->
|
||||
<view v-if="region" class="wd-picker__region-tabs">
|
||||
<view :class="`wd-picker__region ${showStart ? 'is-active' : ''} `" @click="tabChange">
|
||||
<view>开始时间</view>
|
||||
<view>{{ translate('start') }}</view>
|
||||
<view class="wd-picker__region-time">{{ showTabLabel[0] }}</view>
|
||||
</view>
|
||||
<view :class="`wd-picker__region ${showStart ? '' : 'is-active'}`" @click="tabChange">
|
||||
<view>结束时间</view>
|
||||
<view>{{ translate('end') }}</view>
|
||||
<view class="wd-picker__region-time">{{ showTabLabel[1] }}</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -146,6 +146,7 @@ import { useCell } from '../composables/useCell'
|
||||
import { type DateTimeType, getPickerValue } from '../wd-datetime-picker-view/type'
|
||||
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
|
||||
import { useParent } from '../composables/useParent'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
interface Props {
|
||||
customClass?: string
|
||||
customViewClass?: string
|
||||
@ -227,19 +228,13 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
customViewClass: '',
|
||||
customLabelClass: '',
|
||||
customValueClass: '',
|
||||
// 选择器占位符
|
||||
placeholder: '请选择',
|
||||
// 禁用
|
||||
disabled: false,
|
||||
// 只读
|
||||
readonly: false,
|
||||
loading: false,
|
||||
loadingColor: '#4D80F0',
|
||||
/* popup */
|
||||
// 取消按钮文案
|
||||
cancelButtonText: '取消',
|
||||
// 确认按钮文案
|
||||
confirmButtonText: '完成',
|
||||
|
||||
// 是否必填
|
||||
required: false,
|
||||
labelWidth: '33%',
|
||||
@ -274,6 +269,9 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
zIndex: 15,
|
||||
rules: () => []
|
||||
})
|
||||
|
||||
const { translate } = useTranslate('datetime-picker')
|
||||
|
||||
const datetimePickerView = ref()
|
||||
const datetimePickerView1 = ref()
|
||||
|
||||
|
||||
@ -58,8 +58,8 @@
|
||||
<view class="wd-img-cropper__footer">
|
||||
<wd-icon v-if="!disabledRotate" name="rotate" size="24px" color="#fff" data-eventsync="true" @click="handleRotate"></wd-icon>
|
||||
<view class="wd-img-cropper__footer--button">
|
||||
<view class="is-cancel" @click="handleCancel">{{ cancelButtonText }}</view>
|
||||
<wd-button size="small" :custom-style="buttonStyle" @click="handleConfirm">{{ confirmButtonText }}</wd-button>
|
||||
<view class="is-cancel" @click="handleCancel">{{ cancelButtonText || translate('cancel') }}</view>
|
||||
<wd-button size="small" :custom-style="buttonStyle" @click="handleConfirm">{{ confirmButtonText || translate('confirm') }}</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -79,6 +79,7 @@ export default {
|
||||
<script lang="ts" setup>
|
||||
import { computed, getCurrentInstance, ref, watch } from 'vue'
|
||||
import { addUnit, objToStyle } from '../common/util'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
// 延时动画设置
|
||||
let CHANGE_TIME: any | null = null
|
||||
@ -118,11 +119,11 @@ interface Props {
|
||||
maxScale?: number
|
||||
}
|
||||
|
||||
const { translate } = useTranslate('img-cropper')
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customClass: '',
|
||||
modelValue: false,
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonText: '完成',
|
||||
// 是否禁用旋转
|
||||
disabledRotate: false,
|
||||
/** canvas绘图参数 start **/
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
:type="type"
|
||||
:password="showPassword && !isPwdVisible"
|
||||
v-model="inputValue"
|
||||
:placeholder="placeholder"
|
||||
:placeholder="placeholder || translate('placeholder')"
|
||||
:disabled="disabled"
|
||||
:maxlength="maxlength"
|
||||
:focus="isFocus"
|
||||
@ -90,6 +90,7 @@ import { objToStyle, requestAnimationFrame } from '../common/util'
|
||||
import { useCell } from '../composables/useCell'
|
||||
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
|
||||
import { useParent } from '../composables/useParent'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
interface Props {
|
||||
customInputClass?: string
|
||||
@ -136,6 +137,8 @@ interface Props {
|
||||
rules?: FormItemRule[]
|
||||
}
|
||||
|
||||
const { translate } = useTranslate('input')
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customInputClass: '',
|
||||
customLabelClass: '',
|
||||
@ -144,7 +147,6 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
type: 'text',
|
||||
maxlength: -1,
|
||||
modelValue: '',
|
||||
placeholder: '请输入...',
|
||||
clearable: false,
|
||||
showPassword: false,
|
||||
disabled: false,
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
<template>
|
||||
<view :class="['wd-loadmore', customClass]" @click="reload">
|
||||
<wd-divider v-if="state === 'finished'">{{ finishedText }}</wd-divider>
|
||||
<wd-divider v-if="state === 'finished'">{{ finishedText || translate('finished') }}</wd-divider>
|
||||
<block v-if="state === 'error'">
|
||||
<block v-if="errorText">
|
||||
{{ errorText }}
|
||||
</block>
|
||||
<block v-else>
|
||||
<text class="wd-loadmore__text">加载失败</text>
|
||||
<text class="wd-loadmore__text is-light">点击重试</text>
|
||||
<text class="wd-loadmore__text">{{ translate('error') }}</text>
|
||||
<text class="wd-loadmore__text is-light">{{ translate('retry') }}</text>
|
||||
<wd-icon name="refresh" size="16px" custom-class="wd-loadmore__refresh" />
|
||||
</block>
|
||||
</block>
|
||||
<block v-if="state === 'loading'">
|
||||
<wd-loading size="16px" custom-class="wd-loadmore__loading" />
|
||||
<text class="wd-loadmore__text">{{ loadingText }}</text>
|
||||
<text class="wd-loadmore__text">{{ loadingText || translate('loading') }}</text>
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
@ -30,7 +30,8 @@ export default {
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
type LoadMoreState = 'loading' | 'error' | 'finished'
|
||||
|
||||
@ -44,36 +45,12 @@ interface Props {
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customClass: '',
|
||||
loadingText: '正在努力加载中...',
|
||||
finishedText: '已加载完毕',
|
||||
errorText: ''
|
||||
})
|
||||
|
||||
const showText = ref<string>('')
|
||||
const currentState = ref<LoadMoreState | null>(null)
|
||||
const { translate } = useTranslate('loadmore')
|
||||
|
||||
watch(
|
||||
() => props.state,
|
||||
(newValue) => {
|
||||
if (!newValue) return
|
||||
const state = ['loading', 'error', 'finished']
|
||||
if (state.indexOf(newValue) === -1) console.error(`state must be one of ${state.toString()}`)
|
||||
switch (newValue) {
|
||||
case 'loading':
|
||||
showText.value = props.loadingText
|
||||
break
|
||||
case 'error':
|
||||
showText.value = props.errorText
|
||||
break
|
||||
case 'finished':
|
||||
showText.value = props.finishedText
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
const currentState = ref<LoadMoreState | null>(null)
|
||||
|
||||
const emit = defineEmits(['reload'])
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2022-12-14 17:33:21
|
||||
* @LastEditTime: 2023-09-07 00:29:51
|
||||
* @LastEditTime: 2024-01-26 11:19:42
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-message-box\index.ts
|
||||
@ -10,6 +10,9 @@
|
||||
import { provide, ref } from 'vue'
|
||||
import type { Message, MessageOptions, MessageResult, MessageType } from './types'
|
||||
import { deepMerge } from '../common/util'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
const { translate } = useTranslate('message-box')
|
||||
|
||||
/**
|
||||
* useMessage 用到的key
|
||||
@ -24,13 +27,13 @@ export const defaultOptions: MessageOptions = {
|
||||
showCancelButton: false,
|
||||
show: false,
|
||||
closeOnClickModal: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonText: translate('confirm'),
|
||||
cancelButtonText: translate('cancel'),
|
||||
msg: '',
|
||||
type: 'alert',
|
||||
inputType: 'text',
|
||||
inputValue: '',
|
||||
inputPlaceholder: '请输入',
|
||||
inputPlaceholder: translate('inputPlaceholder'),
|
||||
inputValidate: null,
|
||||
showErr: false,
|
||||
zIndex: 99,
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
<wd-input v-model="inputValue" :type="inputType" size="large" :placeholder="inputPlaceholder || '请输入'" @input="inputValChange" />
|
||||
<!--错误提示-->
|
||||
<view v-if="showErr" class="wd-message-box__input-error">
|
||||
{{ inputError || '输入的数据不合法' }}
|
||||
{{ inputError || translate('inputNoValidate') }}
|
||||
</view>
|
||||
</block>
|
||||
<!--使用插槽-->
|
||||
@ -37,10 +37,10 @@
|
||||
<!--action按钮组合-->
|
||||
<view :class="`wd-message-box__actions ${showCancelButton ? 'wd-message-box__flex' : 'wd-message-box__block'}`">
|
||||
<wd-button type="info" block v-if="showCancelButton" custom-style="margin-right: 16px;" @click="toggleModal('cancel')">
|
||||
{{ cancelButtonText || '取消' }}
|
||||
{{ cancelButtonText || translate('cancel') }}
|
||||
</wd-button>
|
||||
<wd-button block @click="toggleModal('confirm')">
|
||||
{{ confirmButtonText || '确定' }}
|
||||
{{ confirmButtonText || translate('confirm') }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
@ -63,6 +63,7 @@ import { computed, inject, ref, watch } from 'vue'
|
||||
import type { MessageOptions, MessageType } from './types'
|
||||
import { defaultOptions, messageDefaultOptionKey } from '.'
|
||||
import { isDef } from '../common/util'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
interface Props {
|
||||
useSlot?: boolean
|
||||
@ -76,6 +77,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
selector: ''
|
||||
})
|
||||
|
||||
const { translate } = useTranslate('message-box')
|
||||
|
||||
const rootClass = computed(() => {
|
||||
return `wd-message-box__container ${props.customClass}`
|
||||
})
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<view :class="`wd-pager ${customClass}`" v-if="!(hideIfOnePage && totalPageNum === 1)">
|
||||
<view class="wd-pager__content">
|
||||
<wd-button :plain="modelValue > 1" type="info" size="small" :disabled="modelValue <= 1" custom-class="wd-pager__nav" @click="sub">
|
||||
<text v-if="!showIcon">{{ prevText }}</text>
|
||||
<text v-if="!showIcon">{{ prevText || translate('prev') }}</text>
|
||||
<wd-icon
|
||||
v-else
|
||||
size="14px"
|
||||
@ -23,7 +23,7 @@
|
||||
custom-class="wd-pager__nav"
|
||||
@click="add"
|
||||
>
|
||||
<text v-if="!showIcon">{{ nextText }}</text>
|
||||
<text v-if="!showIcon">{{ nextText || translate('next') }}</text>
|
||||
<wd-icon
|
||||
v-else
|
||||
size="14px"
|
||||
@ -33,9 +33,9 @@
|
||||
</wd-button>
|
||||
</view>
|
||||
<view class="wd-pager__message" v-if="showMessage">
|
||||
<text>当前页:{{ modelValue }},</text>
|
||||
<text v-if="total">当前数据:{{ total }},</text>
|
||||
<text>分页大小:{{ pageSize }}</text>
|
||||
<text>{{ translate('page', modelValue) }},</text>
|
||||
<text v-if="total">{{ translate('total', total) }},</text>
|
||||
<text>{{ translate('size', pageSize) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@ -53,6 +53,9 @@ export default {
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
const { translate } = useTranslate('pagination')
|
||||
|
||||
interface Props {
|
||||
customClass?: string
|
||||
@ -74,8 +77,6 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
showMessage: false,
|
||||
total: 0,
|
||||
pageSize: 10, // 分页大小
|
||||
prevText: '上一页',
|
||||
nextText: '下一页',
|
||||
hideIfOnePage: true
|
||||
})
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
<view class="wd-picker__body">
|
||||
<view class="wd-picker__value-wraper">
|
||||
<view :class="`wd-picker__value ${ellipsis && 'is-ellipsis'} ${customValueClass} ${showValue ? '' : 'wd-picker__placeholder'}`">
|
||||
{{ showValue ? showValue : placeholder }}
|
||||
{{ showValue ? showValue : placeholder || translate('placeholder') }}
|
||||
</view>
|
||||
<wd-icon v-if="!disabled && !readonly" custom-class="wd-picker__arrow" name="arrow-right" />
|
||||
</view>
|
||||
@ -43,13 +43,13 @@
|
||||
<view class="wd-picker__toolbar" @touchmove="noop">
|
||||
<!--取消按钮-->
|
||||
<view class="wd-picker__action wd-picker__action--cancel" @click="onCancel">
|
||||
{{ cancelButtonText }}
|
||||
{{ cancelButtonText || translate('cancel') }}
|
||||
</view>
|
||||
<!--标题-->
|
||||
<view v-if="title" class="wd-picker__title">{{ title }}</view>
|
||||
<!--确定按钮-->
|
||||
<view :class="`wd-picker__action ${isLoading ? 'is-loading' : ''}`" @click="onConfirm">
|
||||
{{ confirmButtonText }}
|
||||
{{ confirmButtonText || translate('done') }}
|
||||
</view>
|
||||
</view>
|
||||
<!--pickerView-->
|
||||
@ -91,6 +91,8 @@ import { useCell } from '../composables/useCell'
|
||||
import { type ColumnItem, formatArray } from '../wd-picker-view/type'
|
||||
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
|
||||
import { useParent } from '../composables/useParent'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
const { translate } = useTranslate('picker')
|
||||
|
||||
interface Props {
|
||||
customClass?: string
|
||||
@ -157,17 +159,12 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
customLabelClass: '',
|
||||
customValueClass: '',
|
||||
// 选择器占位符
|
||||
placeholder: '请选择',
|
||||
// 禁用
|
||||
disabled: false,
|
||||
// 只读
|
||||
readonly: false,
|
||||
loading: false,
|
||||
loadingColor: '#4D80F0',
|
||||
// 取消按钮文案
|
||||
cancelButtonText: '取消',
|
||||
// 确认按钮文案
|
||||
confirmButtonText: '完成',
|
||||
// 是否必填
|
||||
required: false,
|
||||
useDefaultSlot: false,
|
||||
|
||||
@ -7,14 +7,14 @@
|
||||
<view class="wd-search__field">
|
||||
<view v-if="!placeholderLeft" :style="coverStyle" class="wd-search__cover" @click="closeCover">
|
||||
<wd-icon name="search" size="18px" custom-class="wd-search__search-icon"></wd-icon>
|
||||
<text class="wd-search__placeholder-txt">{{ placeholder || '搜索' }}</text>
|
||||
<text class="wd-search__placeholder-txt">{{ placeholder || translate('search') }}</text>
|
||||
</view>
|
||||
<!--icon:search-->
|
||||
<wd-icon v-if="showInput || str || placeholderLeft" name="search" size="18px" custom-class="wd-search__search-left-icon"></wd-icon>
|
||||
<!--搜索框-->
|
||||
<input
|
||||
v-if="showInput || str || placeholderLeft"
|
||||
:placeholder="placeholder || '搜索'"
|
||||
:placeholder="placeholder || translate('search')"
|
||||
placeholder-class="wd-search__placeholder-txt"
|
||||
confirm-type="search"
|
||||
v-model="str"
|
||||
@ -37,7 +37,7 @@
|
||||
<slot v-if="userSuffixSlot" name="suffix"></slot>
|
||||
<!--默认button-->
|
||||
<view v-else class="wd-search__cancel" @click="handleCancel">
|
||||
{{ cancelTxt || '取消' }}
|
||||
{{ cancelTxt || translate('cancel') }}
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
@ -57,6 +57,7 @@ export default {
|
||||
<script lang="ts" setup>
|
||||
import { type CSSProperties, computed, onMounted, ref, watch } from 'vue'
|
||||
import { objToStyle, requestAnimationFrame } from '../common/util'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
interface Props {
|
||||
userSuffixSlot?: boolean
|
||||
@ -74,13 +75,13 @@ interface Props {
|
||||
customStyle?: string
|
||||
}
|
||||
|
||||
const { translate } = useTranslate('search')
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
modelValue: '',
|
||||
customClass: '',
|
||||
customStyle: '',
|
||||
userSuffixSlot: false,
|
||||
placeholder: '搜索',
|
||||
cancelTxt: '取消',
|
||||
light: false,
|
||||
focus: false,
|
||||
focusWhenClear: false,
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
showValue ? '' : 'wd-select-picker__value--placeholder'
|
||||
}`"
|
||||
>
|
||||
{{ showValue || placeholder || '请选择' }}
|
||||
{{ showValue || placeholder || translate('placeholder') }}
|
||||
</view>
|
||||
<wd-icon v-if="!disabled && !readonly" custom-class="wd-select-picker__arrow" name="arrow-right" />
|
||||
</view>
|
||||
@ -35,7 +35,7 @@
|
||||
<wd-action-sheet
|
||||
v-model="pickerShow"
|
||||
:duration="250"
|
||||
:title="title || '请选择'"
|
||||
:title="title || translate('title')"
|
||||
:close-on-click-modal="closeOnClickModal"
|
||||
:z-index="zIndex"
|
||||
:safe-area-inset-bottom="safeAreaInsetBottom"
|
||||
@ -43,7 +43,14 @@
|
||||
@opened="scrollIntoView ? setScrollIntoView() : ''"
|
||||
custom-header-class="wd-select-picker__header"
|
||||
>
|
||||
<wd-search v-if="filterable" v-model="filterVal" :placeholder="filterPlaceholder" hide-cancel placeholder-left @change="handleFilterChange" />
|
||||
<wd-search
|
||||
v-if="filterable"
|
||||
v-model="filterVal"
|
||||
:placeholder="filterPlaceholder || translate('filterPlaceholder')"
|
||||
hide-cancel
|
||||
placeholder-left
|
||||
@change="handleFilterChange"
|
||||
/>
|
||||
<scroll-view
|
||||
:class="`wd-select-picker__wrapper ${filterable ? 'is-filterable' : ''} ${loading ? 'is-loading' : ''} ${customContentClass}`"
|
||||
:scroll-y="!loading"
|
||||
@ -91,7 +98,7 @@
|
||||
</scroll-view>
|
||||
<!-- 确认按钮 -->
|
||||
<view class="wd-select-picker__footer">
|
||||
<wd-button block size="large" @click="onConfirm" :disabled="loading">{{ confirmButtonText }}</wd-button>
|
||||
<wd-button block size="large" @click="onConfirm" :disabled="loading">{{ confirmButtonText || translate('confirm') }}</wd-button>
|
||||
</view>
|
||||
</wd-action-sheet>
|
||||
</view>
|
||||
@ -113,9 +120,12 @@ import { useCell } from '../composables/useCell'
|
||||
import { getRect, getType, isArray, isDef, requestAnimationFrame } from '../common/util'
|
||||
import { useParent } from '../composables/useParent'
|
||||
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
type SelectPickerType = 'checkbox' | 'radio'
|
||||
|
||||
const { translate } = useTranslate('select-picker')
|
||||
|
||||
interface Props {
|
||||
customClass?: string
|
||||
customContentClass?: string
|
||||
@ -170,12 +180,10 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
type: 'checkbox',
|
||||
valueKey: 'value',
|
||||
labelKey: 'label',
|
||||
placeholder: '请选择',
|
||||
disabled: false,
|
||||
loading: false,
|
||||
loadingColor: '#4D80F0',
|
||||
readonly: false,
|
||||
confirmButtonText: '确认',
|
||||
labelWidth: '33%',
|
||||
error: false,
|
||||
required: false,
|
||||
@ -188,7 +196,6 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
zIndex: 15,
|
||||
safeAreaInsetBottom: true,
|
||||
filterable: false,
|
||||
filterPlaceholder: '搜索',
|
||||
ellipsis: false,
|
||||
scrollIntoView: true,
|
||||
rules: () => []
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<!--
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-06-12 10:04:19
|
||||
* @LastEditTime: 2023-09-02 15:12:03
|
||||
* @LastEditTime: 2024-01-26 12:42:13
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-status-tip\wd-status-tip.vue
|
||||
@ -26,7 +26,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { computed, ref, watch, type CSSProperties } from 'vue'
|
||||
import { addUnit, objToStyle } from '../common/util'
|
||||
|
||||
interface Props {
|
||||
@ -59,7 +59,7 @@ watch(
|
||||
)
|
||||
|
||||
const imgStyle = computed(() => {
|
||||
let style: Record<string, string> = {}
|
||||
let style: CSSProperties = {}
|
||||
if (props.imageSize) {
|
||||
style = {
|
||||
height: addUnit(props.imageSize),
|
||||
|
||||
@ -46,6 +46,7 @@ import { computed } from 'vue'
|
||||
import { useParent } from '../composables/useParent'
|
||||
import { STEPS_KEY } from '../wd-steps/types'
|
||||
import { isDef } from '../common/util'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
type StepStatus = 'finished' | 'process' | 'error'
|
||||
|
||||
@ -71,6 +72,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
|
||||
const { parent: steps, index } = useParent(STEPS_KEY)
|
||||
|
||||
const { translate } = useTranslate('steps')
|
||||
|
||||
const currentStatus = computed(() => {
|
||||
return getCurrentStatus(index.value)
|
||||
})
|
||||
@ -149,14 +152,14 @@ function getCurrentTitle(currentStatus: string) {
|
||||
|
||||
switch (currentStatus) {
|
||||
case 'finished':
|
||||
return '已完成'
|
||||
return translate('finished')
|
||||
case 'error':
|
||||
return '失败'
|
||||
return translate('failed')
|
||||
case 'process':
|
||||
return '进行中'
|
||||
return translate('process')
|
||||
case 'wait':
|
||||
default:
|
||||
return '未开始'
|
||||
return translate('wait')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -32,7 +32,9 @@
|
||||
<wd-icon name="arrow-down" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="wd-tabs__map-header" :style="`${mapShow ? '' : 'display:none;'} ${animating ? 'opacity:1;' : ''}`">全部</view>
|
||||
<view class="wd-tabs__map-header" :style="`${mapShow ? '' : 'display:none;'} ${animating ? 'opacity:1;' : ''}`">
|
||||
{{ translate('all') }}
|
||||
</view>
|
||||
<view :class="`wd-tabs__map-body ${animating ? 'is-open' : ''}`" :style="mapShow ? '' : 'display:none'">
|
||||
<view class="wd-tabs__map-nav-item" v-for="(item, index) in items" :key="index" @click="handleSelect(index)">
|
||||
<view
|
||||
@ -97,7 +99,9 @@
|
||||
<wd-icon name="arrow-down" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="wd-tabs__map-header" :style="`${mapShow ? '' : 'display:none;'} ${animating ? 'opacity:1;' : ''}`">全部</view>
|
||||
<view class="wd-tabs__map-header" :style="`${mapShow ? '' : 'display:none;'} ${animating ? 'opacity:1;' : ''}`">
|
||||
{{ translate('all') }}
|
||||
</view>
|
||||
<view :class="`wd-tabs__map-body ${animating ? 'is-open' : ''}`" :style="mapShow ? '' : 'display:none'">
|
||||
<view class="wd-tabs__map-nav-item" v-for="(item, index) in items" :key="index" @click="handleSelect(index)">
|
||||
<view :class="`wd-tabs__map-nav-btn ${state.activeIndex === index ? 'is-active' : ''} ${item.disabled ? 'is-disabled' : ''}`">
|
||||
@ -136,6 +140,7 @@ import { checkNumRange, debounce, getRect, getType, isDef, isNumber, isString, o
|
||||
import { useTouch } from '../composables/useTouch'
|
||||
import { TABS_KEY } from './types'
|
||||
import { useChildren } from '../composables/useChildren'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
const $item = '.wd-tabs__nav-item'
|
||||
const $container = '.wd-tabs__nav-container'
|
||||
@ -180,6 +185,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
duration: 300
|
||||
})
|
||||
|
||||
const { translate } = useTranslate('tabs')
|
||||
|
||||
// 选中值的索引,默认第一个
|
||||
const state = reactive({ activeIndex: 0 })
|
||||
// navBar的下划线样式
|
||||
@ -227,7 +234,7 @@ const bodyStyle = computed(() => {
|
||||
* @param {Boolean } init - 是否伴随初始化操作
|
||||
*/
|
||||
const setActive = debounce(
|
||||
function (value: number = 0, init: boolean = false, setScroll: boolean = true) {
|
||||
function (value: number | string = 0, init: boolean = false, setScroll: boolean = true) {
|
||||
// 没有tab子元素,不执行任何操作
|
||||
if (items.value.length === 0) return
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
<input
|
||||
v-if="dynamicInput && dynamic"
|
||||
class="wd-tag__add-text"
|
||||
placeholder="请输入"
|
||||
:placeholder="translate('placeholder')"
|
||||
type="text"
|
||||
focus="true"
|
||||
v-model="dynamicValue"
|
||||
@ -22,7 +22,7 @@
|
||||
<slot name="add" v-if="$slots.add"></slot>
|
||||
<template v-else>
|
||||
<wd-icon name="add" custom-class="wd-tag__add wd-tag__icon" />
|
||||
<text>新增标签</text>
|
||||
<text>{{ translate('add') }}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
@ -41,6 +41,7 @@ export default {
|
||||
<script lang="ts" setup>
|
||||
import { objToStyle } from '../common/util'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
type TagType = 'default' | 'primary' | 'success' | 'warning' | 'danger'
|
||||
|
||||
@ -69,6 +70,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
mark: false
|
||||
})
|
||||
|
||||
const { translate } = useTranslate('tag')
|
||||
|
||||
const tagClass = ref<string>('')
|
||||
const dynamicValue = ref<string>('')
|
||||
const dynamicInput = ref<boolean>(false)
|
||||
@ -86,7 +89,7 @@ watch(
|
||||
(newValue) => {
|
||||
if (!newValue) return
|
||||
// type: 'primary', 'danger', 'warning', 'success'
|
||||
const type = ['primary', 'danger', 'warning', 'success']
|
||||
const type = ['primary', 'danger', 'warning', 'success', 'default']
|
||||
if (type.indexOf(newValue) === -1) console.error(`type must be one of ${type.toString()}`)
|
||||
computeTagClass()
|
||||
},
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
:class="`wd-textarea__inner ${showClear ? 'is-suffix' : ''} ${customTextareaClass}`"
|
||||
v-model="inputValue"
|
||||
:show-count="false"
|
||||
:placeholder="placeholder"
|
||||
:placeholder="placeholder || translate('placeholder')"
|
||||
:disabled="disabled"
|
||||
:maxlength="maxlength"
|
||||
:focus="isFocus"
|
||||
@ -80,8 +80,11 @@ import { objToStyle, requestAnimationFrame } from '../common/util'
|
||||
import { useCell } from '../composables/useCell'
|
||||
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
|
||||
import { useParent } from '../composables/useParent'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
type ConfirmType = 'send' | 'search' | 'next' | 'go' | 'done'
|
||||
|
||||
const { translate } = useTranslate('textarea')
|
||||
|
||||
interface Props {
|
||||
// 原生属性
|
||||
placeholder?: string
|
||||
@ -136,7 +139,6 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
customStyle: '',
|
||||
maxlength: -1,
|
||||
modelValue: '',
|
||||
placeholder: '请输入...',
|
||||
autoHeight: false,
|
||||
clearable: false,
|
||||
showPassword: false,
|
||||
|
||||
@ -25,7 +25,7 @@ export const defaultOptions: ToastOptions = {
|
||||
}
|
||||
|
||||
export function useToast(selector: string = ''): Toast {
|
||||
let timer: NodeJS.Timeout | null = null
|
||||
let timer: ReturnType<typeof setTimeout> | null = null
|
||||
const toastOption = ref<ToastOptions>(defaultOptions) // Toast选项
|
||||
const toastOptionKey = selector ? toastDefaultOptionKey + selector : toastDefaultOptionKey
|
||||
provide(toastOptionKey, toastOption)
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
<!-- 失败时展示失败图标以及失败信息 -->
|
||||
<view v-if="file.status === 'fail'" class="wd-upload__status-content">
|
||||
<wd-icon name="close-outline" custom-class="wd-upload__icon"></wd-icon>
|
||||
<text class="wd-upload__progress-txt">{{ file.error || '上传失败' }}</text>
|
||||
<text class="wd-upload__progress-txt">{{ file.error || translate('error') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 上传状态为上传中时不展示移除按钮 -->
|
||||
@ -54,6 +54,7 @@ export default {
|
||||
import { ref, watch } from 'vue'
|
||||
import { context, getType, isDef, isEqual } from '../common/util'
|
||||
import { chooseFile } from './utils'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
|
||||
interface Props {
|
||||
customClass?: string
|
||||
@ -122,6 +123,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
maxSize: Number.MAX_VALUE
|
||||
})
|
||||
|
||||
const { translate } = useTranslate('upload')
|
||||
|
||||
const uploadFiles = ref<Record<string, any>[]>([])
|
||||
|
||||
watch(
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2021-12-21 14:22:03
|
||||
* @LastEditTime: 2023-10-31 22:20:14
|
||||
* @LastEditTime: 2024-01-26 13:46:52
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\index.ts
|
||||
@ -24,3 +24,5 @@ export { dayjs } from './components/common/dayjs'
|
||||
export * as CommonUtil from './components/common/util'
|
||||
|
||||
export * as clickOut from './components/common/clickoutside'
|
||||
|
||||
export * from './locale'
|
||||
|
||||
39
src/uni_modules/wot-design-uni/locale/index.ts
Normal file
39
src/uni_modules/wot-design-uni/locale/index.ts
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2024-01-25 23:06:48
|
||||
* @LastEditTime: 2024-01-26 17:30:21
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\locale\index.ts
|
||||
* 记得注释
|
||||
*/
|
||||
import { reactive, ref } from 'vue'
|
||||
import zhCN from './lang/zh-CN'
|
||||
import { deepAssign } from '../components/common/util'
|
||||
|
||||
type Message = Record<string, any>
|
||||
type Messages = Record<string, Message>
|
||||
|
||||
const lang = ref<string>('zh-CN')
|
||||
const messages = reactive<Messages>({
|
||||
'zh-CN': zhCN
|
||||
})
|
||||
|
||||
export const Locale = {
|
||||
messages(): Message {
|
||||
return messages[lang.value]
|
||||
},
|
||||
|
||||
use(newLang: string, newMessages?: Message) {
|
||||
lang.value = newLang
|
||||
this.add({ [newLang]: newMessages })
|
||||
},
|
||||
|
||||
add(newMessages: Message = {}) {
|
||||
deepAssign(messages, newMessages)
|
||||
}
|
||||
}
|
||||
|
||||
export const useCurrentLang = () => lang
|
||||
|
||||
export default Locale
|
||||
124
src/uni_modules/wot-design-uni/locale/lang/en-US.ts
Normal file
124
src/uni_modules/wot-design-uni/locale/lang/en-US.ts
Normal file
@ -0,0 +1,124 @@
|
||||
export default {
|
||||
calendar: {
|
||||
placeholder: 'Select',
|
||||
title: 'Select Date',
|
||||
day: 'Date',
|
||||
week: 'Week',
|
||||
month: 'Month',
|
||||
confirm: 'OK',
|
||||
startTime: 'Start Date',
|
||||
endTime: 'End Date',
|
||||
to: 'To',
|
||||
timeFormat: 'YY-MM-DD HH:mm:ss',
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
weekFormat: (year: number, week: number) => `${year} W${week}`,
|
||||
startWeek: 'Start Week',
|
||||
endWeek: 'End Week',
|
||||
startMonth: 'Start Month',
|
||||
endMonth: 'End Month',
|
||||
monthFormat: 'YYYY-MM'
|
||||
},
|
||||
calendarView: {
|
||||
startTime: 'Start Time',
|
||||
endTime: 'End Time',
|
||||
weeks: {
|
||||
sun: 'Sun',
|
||||
mon: 'Mon',
|
||||
tue: 'Tue',
|
||||
wed: 'Wed',
|
||||
thu: 'Thu',
|
||||
fri: 'Fri',
|
||||
sat: 'Sat'
|
||||
},
|
||||
rangePrompt: (maxRange: number) => `The number of selected days cannot exceed ${maxRange} days`,
|
||||
rangePromptWeek: (maxRange: number) => `The number of weeks selected cannot exceed ${maxRange} weeks`,
|
||||
rangePromptMonth: (maxRange: number) => `The selected month cannot exceed ${maxRange} months`,
|
||||
monthTitle: 'YYYY-MM',
|
||||
yearTitle: 'YYYY',
|
||||
month: 'MM',
|
||||
hour: (value: number) => `${value}`,
|
||||
minute: (value: number) => `${value}`,
|
||||
second: (value: number) => `${value}`
|
||||
},
|
||||
datetimePicker: {
|
||||
start: 'From',
|
||||
end: 'To',
|
||||
to: 'To',
|
||||
placeholder: 'Select',
|
||||
confirm: 'OK',
|
||||
cancel: 'Cancel'
|
||||
},
|
||||
collapse: {
|
||||
expand: 'Expand',
|
||||
retract: 'Fold'
|
||||
},
|
||||
colPicker: {
|
||||
title: 'Select',
|
||||
placeholder: 'Select',
|
||||
select: 'Select'
|
||||
},
|
||||
loadmore: {
|
||||
loading: 'Loading...',
|
||||
finished: 'Finished loading',
|
||||
error: 'Failed to load...',
|
||||
retry: 'Refresh'
|
||||
},
|
||||
imgCropper: {
|
||||
confirm: 'OK',
|
||||
cancel: 'Cancel'
|
||||
},
|
||||
messageBox: {
|
||||
inputPlaceholder: 'Please input information',
|
||||
confirm: 'OK',
|
||||
cancel: 'Cancel',
|
||||
inputNoValidate: 'Please ensure you input correct information'
|
||||
},
|
||||
numberKeyboard: {
|
||||
confirm: 'done'
|
||||
},
|
||||
pagination: {
|
||||
prev: 'Previous',
|
||||
next: 'Next',
|
||||
page: (value: number) => `Page:${value}`,
|
||||
total: (total: number) => `Total:${total}`,
|
||||
size: (size: number) => `${size}/page`
|
||||
},
|
||||
picker: {
|
||||
cancel: 'Cancel',
|
||||
done: 'Done',
|
||||
placeholder: 'Select'
|
||||
},
|
||||
search: {
|
||||
search: 'Search',
|
||||
cancel: 'Cancel'
|
||||
},
|
||||
steps: {
|
||||
wait: 'Not Started',
|
||||
finished: 'Expired',
|
||||
process: 'In Progress',
|
||||
failed: 'Failed'
|
||||
},
|
||||
tabs: {
|
||||
all: 'All'
|
||||
},
|
||||
upload: {
|
||||
error: 'Failed to upload'
|
||||
},
|
||||
input: {
|
||||
placeholder: 'Please input information...'
|
||||
},
|
||||
selectPicker: {
|
||||
title: 'Select',
|
||||
placeholder: 'Select',
|
||||
select: 'Select',
|
||||
confirm: 'Ok',
|
||||
filterPlaceholder: 'Search'
|
||||
},
|
||||
tag: {
|
||||
placeholder: 'Enter',
|
||||
add: 'Add Tag'
|
||||
},
|
||||
textarea: {
|
||||
placeholder: 'Please input information...'
|
||||
}
|
||||
}
|
||||
124
src/uni_modules/wot-design-uni/locale/lang/th-TH.ts
Normal file
124
src/uni_modules/wot-design-uni/locale/lang/th-TH.ts
Normal file
@ -0,0 +1,124 @@
|
||||
export default {
|
||||
calendar: {
|
||||
placeholder: 'เลือก',
|
||||
title: 'เลือกวันที่',
|
||||
day: 'วันที่',
|
||||
week: 'สัปดาห์',
|
||||
month: 'เดือน',
|
||||
confirm: 'ยืนยัน',
|
||||
startTime: 'วันที่เริ่มต้น',
|
||||
endTime: 'วันที่สิ้นสุด',
|
||||
to: 'ถึง',
|
||||
timeFormat: 'YY-MM-DD HH:mm:ss',
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
weekFormat: (year: number, week: number) => `${year} W${week}`,
|
||||
startWeek: 'เริ่มต้นสัปดาห์',
|
||||
endWeek: 'สิ้นสุดสัปดาห์',
|
||||
startMonth: 'เดือนเริ่มต้น',
|
||||
endMonth: 'สิ้นเดือน',
|
||||
monthFormat: 'YYYY-MM'
|
||||
},
|
||||
calendarView: {
|
||||
startTime: 'เวลาเริ่มต้น',
|
||||
endTime: 'เวลาสิ้นสุด',
|
||||
weeks: {
|
||||
sun: 'อา',
|
||||
mon: 'จ',
|
||||
tue: 'อ',
|
||||
wed: 'พ',
|
||||
thu: 'พฤ',
|
||||
fri: 'ศ',
|
||||
sat: 'ส'
|
||||
},
|
||||
rangePrompt: (maxRange: number) => `จำนวนวันที่เลือกต้องไม่เกิน ${maxRange} วัน`,
|
||||
rangePromptWeek: (maxRange: number) => `จำนวนสัปดาห์ที่เลือกต้องไม่เกิน ${maxRange} สัปดาห์`,
|
||||
rangePromptMonth: (maxRange: number) => `เดือนที่เลือกต้องไม่เกิน ${maxRange} เดือน`,
|
||||
monthTitle: 'YYYY-MM',
|
||||
yearTitle: 'YYYY',
|
||||
month: 'MM',
|
||||
hour: (value: number) => `${value}`,
|
||||
minute: (value: number) => `${value}`,
|
||||
second: (value: number) => `${value}`
|
||||
},
|
||||
collapse: {
|
||||
expand: 'ดูเพิ่มเติม',
|
||||
retract: 'ย่อ'
|
||||
},
|
||||
colPicker: {
|
||||
title: 'เลือก',
|
||||
placeholder: 'เลือก',
|
||||
select: 'เลือก'
|
||||
},
|
||||
datetimePicker: {
|
||||
start: 'จาก',
|
||||
end: 'ถึง',
|
||||
to: 'ถึง',
|
||||
placeholder: 'เลือก',
|
||||
confirm: 'ยืนยัน',
|
||||
cancel: 'ยกเลิก'
|
||||
},
|
||||
loadmore: {
|
||||
loading: 'กำลังโหลด.. รอสักครู่..',
|
||||
finished: 'โหลดสำเร็จ',
|
||||
error: 'โหลดไม่สำเร็จ',
|
||||
retry: 'รีเฟรช'
|
||||
},
|
||||
imgCropper: {
|
||||
confirm: 'ยืนยัน',
|
||||
cancel: 'ยกเลิก'
|
||||
},
|
||||
messageBox: {
|
||||
inputPlaceholder: 'กรุณาใส่ข้อมูล',
|
||||
confirm: 'ยืนยัน',
|
||||
cancel: 'ยกเลิก',
|
||||
inputNoValidate: 'กรุณาตรวจสอบว่าคุณได้ใส่ข้อมูลที่ถูกต้อง'
|
||||
},
|
||||
numberKeyboard: {
|
||||
confir: 'ตกลง'
|
||||
},
|
||||
pagination: {
|
||||
prev: 'ก่อนหน้า',
|
||||
next: 'หน้าต่อไป',
|
||||
page: (value: number) => `หน้า: ${value}`,
|
||||
total: (total: number) => `ทั้งหมด: ${total} หน้า`,
|
||||
size: (size: number) => `${size}/ ต่อหน้า`
|
||||
},
|
||||
picker: {
|
||||
cancel: 'ยกเลิก',
|
||||
done: 'ตกลง',
|
||||
placeholder: 'เลือก'
|
||||
},
|
||||
search: {
|
||||
search: 'ค้นหา',
|
||||
cancel: 'ยกเลิก'
|
||||
},
|
||||
steps: {
|
||||
wait: 'ยังไม่เริ่ม',
|
||||
finished: 'เสร็จสิ้น',
|
||||
process: 'กำลังดำเนินการ',
|
||||
failed: 'ไม่ผ่าน'
|
||||
},
|
||||
tabs: {
|
||||
all: 'ทั้งหมด'
|
||||
},
|
||||
upload: {
|
||||
error: 'อัปโหลดไม่สำเร็จ'
|
||||
},
|
||||
input: {
|
||||
placeholder: 'กรุณาใส่ข้อมูล...'
|
||||
},
|
||||
selectPicker: {
|
||||
title: 'เลือก',
|
||||
placeholder: 'เลือก',
|
||||
select: 'เลือก',
|
||||
confirm: 'ยืนยัน',
|
||||
filterPlaceholder: 'ค้นหา'
|
||||
},
|
||||
tag: {
|
||||
placeholder: 'กรุณาใส่',
|
||||
add: 'ป้ายใหม่'
|
||||
},
|
||||
textarea: {
|
||||
placeholder: 'กรุณาใส่ข้อมูล...'
|
||||
}
|
||||
}
|
||||
65
src/uni_modules/wot-design-uni/locale/lang/vi-VN.ts
Normal file
65
src/uni_modules/wot-design-uni/locale/lang/vi-VN.ts
Normal file
@ -0,0 +1,65 @@
|
||||
export default {
|
||||
calendar: {
|
||||
placeholder: 'Vui lòng chọn',
|
||||
title: 'Chọn ngày',
|
||||
day: 'Ngày',
|
||||
week: 'Tuần',
|
||||
month: 'Tháng',
|
||||
confirm: 'Xác nhận',
|
||||
startTime: 'Thời gian bắt đầu',
|
||||
endTime: 'Thời gian kết thúc',
|
||||
to: 'đến',
|
||||
timeFormat: 'YY-MM-DD HH:mm:ss',
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
weekFormat: (year: number, week: number) => `Tuần thứ ${week} năm ${year}`,
|
||||
startWeek: 'Tuần bắt đầu',
|
||||
endWeek: 'Tuần kết thúc',
|
||||
startMonth: 'Tháng bắt đầu',
|
||||
endMonth: 'Tháng kết thúc',
|
||||
monthFormat: 'Tháng YYYY MM'
|
||||
},
|
||||
calendarView: {
|
||||
startTime: 'Bắt đầu',
|
||||
endTime: 'Kết thúc',
|
||||
weeks: { sun: 'CN', mon: 'T2', tue: 'T3', wed: 'T4', thu: 'T5', fri: 'T6', sat: 'T7' },
|
||||
rangePrompt: (maxRange: number) => `Không thể chọn quá ${maxRange} ngày`,
|
||||
rangePromptWeek: (maxRange: number) => `Không thể chọn quá ${maxRange} tuần`,
|
||||
rangePromptMonth: (maxRange: number) => `Không thể chọn quá ${maxRange} tháng`,
|
||||
monthTitle: 'Tháng YYYY M',
|
||||
yearTitle: 'Năm YYYY',
|
||||
month: 'MM',
|
||||
hour: (value: number) => `${value} giờ`,
|
||||
minute: (value: number) => `${value} phút`,
|
||||
second: (value: number) => `${value} giây`
|
||||
},
|
||||
collapse: { expand: 'Mở rộng', retract: 'Thu gọn' },
|
||||
colPicker: { title: 'Vui lòng chọn', placeholder: 'Vui lòng chọn', select: 'Vui lòng chọn' },
|
||||
datetimePicker: {
|
||||
start: 'Thời gian bắt đầu',
|
||||
end: 'Thời gian kết thúc',
|
||||
to: 'đến',
|
||||
placeholder: 'Vui lòng chọn',
|
||||
confirm: 'Hoàn thành',
|
||||
cancel: 'Hủy bỏ'
|
||||
},
|
||||
loadmore: { loading: 'Đang tải...', finished: 'Đã tải xong', error: 'Tải thất bại', retry: 'Nhấp để thử lại' },
|
||||
messageBox: { inputPlaceholder: 'Vui lòng nhập', confirm: 'Xác nhận', cancel: 'Hủy bỏ', inputNoValidate: 'Dữ liệu không hợp lệ' },
|
||||
numberKeyboard: { confirm: 'Hoàn thành' },
|
||||
pagination: {
|
||||
prev: 'Trang trước',
|
||||
next: 'Trang sau',
|
||||
page: (value: number) => `Trang hiện tại: ${value}`,
|
||||
total: (total: number) => `Tổng số dữ liệu: ${total}`,
|
||||
size: (size: number) => `Kích thước trang: ${size}`
|
||||
},
|
||||
picker: { cancel: 'Hủy bỏ', done: 'Hoàn thành', placeholder: 'Vui lòng chọn' },
|
||||
imgCropper: { confirm: 'Hoàn thành', cancel: 'Hủy bỏ' },
|
||||
search: { search: 'Tìm kiếm', cancel: 'Hủy bỏ' },
|
||||
steps: { wait: 'Chưa bắt đầu', finished: 'Đã hoàn thành', process: 'Đang tiến hành', failed: 'Thất bại' },
|
||||
tabs: { all: 'Tất cả' },
|
||||
upload: { error: 'Tải lên thất bại' },
|
||||
input: { placeholder: 'Vui lòng nhập...' },
|
||||
selectPicker: { title: 'Vui lòng chọn', placeholder: 'Vui lòng chọn', select: 'Xác nhận', confirm: 'Xác nhận', filterPlaceholder: 'Tìm kiếm' },
|
||||
tag: { placeholder: 'Vui lòng nhập', add: 'thêm' },
|
||||
textarea: { placeholder: 'Vui lòng nhập...' }
|
||||
}
|
||||
124
src/uni_modules/wot-design-uni/locale/lang/zh-CN.ts
Normal file
124
src/uni_modules/wot-design-uni/locale/lang/zh-CN.ts
Normal file
@ -0,0 +1,124 @@
|
||||
export default {
|
||||
calendar: {
|
||||
placeholder: '请选择',
|
||||
title: '选择日期',
|
||||
day: '日',
|
||||
week: '周',
|
||||
month: '月',
|
||||
confirm: '确定',
|
||||
startTime: '开始时间',
|
||||
endTime: '结束时间',
|
||||
to: '至',
|
||||
timeFormat: 'YY年MM月DD日 HH:mm:ss',
|
||||
dateFormat: 'YYYY年MM月DD日',
|
||||
weekFormat: (year: number, week: number) => `${year} 第 ${week} 周`,
|
||||
startWeek: '开始周',
|
||||
endWeek: '结束周',
|
||||
startMonth: '开始月',
|
||||
endMonth: '结束月',
|
||||
monthFormat: 'YYYY年MM月'
|
||||
},
|
||||
calendarView: {
|
||||
startTime: '开始',
|
||||
endTime: '结束',
|
||||
weeks: {
|
||||
sun: '日',
|
||||
mon: '一',
|
||||
tue: '二',
|
||||
wed: '三',
|
||||
thu: '四',
|
||||
fri: '五',
|
||||
sat: '六'
|
||||
},
|
||||
rangePrompt: (maxRange: number) => `选择天数不能超过${maxRange}天`,
|
||||
rangePromptWeek: (maxRange: number) => `选择周数不能超过${maxRange}周`,
|
||||
rangePromptMonth: (maxRange: number) => `选择月份不能超过${maxRange}个月`,
|
||||
monthTitle: 'YYYY年M月',
|
||||
yearTitle: 'YYYY年',
|
||||
month: 'M月',
|
||||
hour: (value: number) => `${value}时`,
|
||||
minute: (value: number) => `${value}分`,
|
||||
second: (value: number) => `${value}秒`
|
||||
},
|
||||
collapse: {
|
||||
expand: '展开',
|
||||
retract: '收起'
|
||||
},
|
||||
colPicker: {
|
||||
title: '请选择',
|
||||
placeholder: '请选择',
|
||||
select: '请选择'
|
||||
},
|
||||
datetimePicker: {
|
||||
start: '开始时间',
|
||||
end: '结束时间',
|
||||
to: '至',
|
||||
placeholder: '请选择',
|
||||
confirm: '完成',
|
||||
cancel: '取消'
|
||||
},
|
||||
loadmore: {
|
||||
loading: '正在努力加载中...',
|
||||
finished: '已加载完毕',
|
||||
error: '加载失败',
|
||||
retry: '点击重试'
|
||||
},
|
||||
messageBox: {
|
||||
inputPlaceholder: '请输入',
|
||||
confirm: '确定',
|
||||
cancel: '取消',
|
||||
inputNoValidate: '输入的数据不合法'
|
||||
},
|
||||
numberKeyboard: {
|
||||
confirm: '完成'
|
||||
},
|
||||
pagination: {
|
||||
prev: '上一页',
|
||||
next: '下一页',
|
||||
page: (value: number) => `当前页:${value}`,
|
||||
total: (total: number) => `当前数据:${total}条`,
|
||||
size: (size: number) => `分页大小:${size}`
|
||||
},
|
||||
picker: {
|
||||
cancel: '取消',
|
||||
done: '完成',
|
||||
placeholder: '请选择'
|
||||
},
|
||||
imgCropper: {
|
||||
confirm: '完成',
|
||||
cancel: '取消'
|
||||
},
|
||||
search: {
|
||||
search: '搜索',
|
||||
cancel: '取消'
|
||||
},
|
||||
steps: {
|
||||
wait: '未开始',
|
||||
finished: '已完成',
|
||||
process: '进行中',
|
||||
failed: '失败'
|
||||
},
|
||||
tabs: {
|
||||
all: '全部'
|
||||
},
|
||||
upload: {
|
||||
error: '上传失败'
|
||||
},
|
||||
input: {
|
||||
placeholder: '请输入...'
|
||||
},
|
||||
selectPicker: {
|
||||
title: '请选择',
|
||||
placeholder: '请选择',
|
||||
select: '请选择',
|
||||
confirm: '确认',
|
||||
filterPlaceholder: '搜索'
|
||||
},
|
||||
tag: {
|
||||
placeholder: '请输入',
|
||||
add: '新增标签'
|
||||
},
|
||||
textarea: {
|
||||
placeholder: '请输入...'
|
||||
}
|
||||
}
|
||||
58
src/uni_modules/wot-design-uni/locale/lang/zh-HK.ts
Normal file
58
src/uni_modules/wot-design-uni/locale/lang/zh-HK.ts
Normal file
@ -0,0 +1,58 @@
|
||||
export default {
|
||||
calendar: {
|
||||
placeholder: '請選擇',
|
||||
title: '選擇日期',
|
||||
day: '日',
|
||||
week: '週',
|
||||
month: '月',
|
||||
confirm: '確定',
|
||||
startTime: '開始時間',
|
||||
endTime: '結束時間',
|
||||
to: '至',
|
||||
timeFormat: 'YY年MM月DD日 HH:mm:ss',
|
||||
dateFormat: 'YYYY年MM月DD日',
|
||||
weekFormat: (year: number, week: number) => `${year} 第 ${week} 週`,
|
||||
startWeek: '開始週',
|
||||
endWeek: '結束週',
|
||||
startMonth: '開始月',
|
||||
endMonth: '結束月',
|
||||
monthFormat: 'YYYY年MM月'
|
||||
},
|
||||
calendarView: {
|
||||
startTime: '開始',
|
||||
endTime: '結束',
|
||||
weeks: { sun: '日', mon: '一', tue: '二', wed: '三', thu: '四', fri: '五', sat: '六' },
|
||||
rangePrompt: (maxRange: number) => `選擇天數不能超過${maxRange}天`,
|
||||
rangePromptWeek: (maxRange: number) => `選擇週數不能超過${maxRange}週`,
|
||||
rangePromptMonth: (maxRange: number) => `選擇月份不能超過${maxRange}個月`,
|
||||
monthTitle: 'YYYY年M月',
|
||||
yearTitle: 'YYYY年',
|
||||
month: 'M月',
|
||||
hour: (value: number) => `${value}時`,
|
||||
minute: (value: number) => `${value}分`,
|
||||
second: (value: number) => `${value}秒`
|
||||
},
|
||||
collapse: { expand: '展開', retract: '收起' },
|
||||
colPicker: { title: '請選擇', placeholder: '請選擇', select: '請選擇' },
|
||||
datetimePicker: { start: '開始時間', end: '結束時間', to: '至', placeholder: '請選擇', confirm: '完成', cancel: '取消' },
|
||||
loadmore: { loading: '正在努力加載中...', finished: '已加載完畢', error: '加載失敗', retry: '點擊重試' },
|
||||
messageBox: { inputPlaceholder: '請輸入', confirm: '確定', cancel: '取消', inputNoValidate: '輸入的數據不合法' },
|
||||
numberKeyboard: { confirm: '完成' },
|
||||
pagination: {
|
||||
prev: '上一頁',
|
||||
next: '下一頁',
|
||||
page: (value: number) => `當前頁:${value}`,
|
||||
total: (total: number) => `當前數據:${total}條`,
|
||||
size: (size: number) => `分頁大小:${size}`
|
||||
},
|
||||
picker: { cancel: '取消', done: '完成', placeholder: '請選擇' },
|
||||
imgCropper: { confirm: '完成', cancel: '取消' },
|
||||
search: { search: '搜索', cancel: '取消' },
|
||||
steps: { wait: '未開始', finished: '已完成', process: '進行中', failed: '失敗' },
|
||||
tabs: { all: '全部' },
|
||||
upload: { error: '上傳失敗' },
|
||||
input: { placeholder: '請輸入...' },
|
||||
selectPicker: { title: '請選擇', placeholder: '請選擇', select: '確認', confirm: '確認', filterPlaceholder: '搜索' },
|
||||
tag: { placeholder: '請輸入', add: '新增標籤' },
|
||||
textarea: { placeholder: '請輸入...' }
|
||||
}
|
||||
58
src/uni_modules/wot-design-uni/locale/lang/zh-TW.ts
Normal file
58
src/uni_modules/wot-design-uni/locale/lang/zh-TW.ts
Normal file
@ -0,0 +1,58 @@
|
||||
export default {
|
||||
calendar: {
|
||||
placeholder: '請選擇',
|
||||
title: '選擇日期',
|
||||
day: '日',
|
||||
week: '週',
|
||||
month: '月',
|
||||
confirm: '確定',
|
||||
startTime: '開始時間',
|
||||
endTime: '結束時間',
|
||||
to: '至',
|
||||
timeFormat: 'YY年MM月DD日 HH:mm:ss',
|
||||
dateFormat: 'YYYY年MM月DD日',
|
||||
weekFormat: (year: number, week: number) => `${year} 第 ${week} 週`,
|
||||
startWeek: '開始週',
|
||||
endWeek: '結束週',
|
||||
startMonth: '開始月',
|
||||
endMonth: '結束月',
|
||||
monthFormat: 'YYYY年MM月'
|
||||
},
|
||||
calendarView: {
|
||||
startTime: '開始',
|
||||
endTime: '結束',
|
||||
weeks: { sun: '日', mon: '一', tue: '二', wed: '三', thu: '四', fri: '五', sat: '六' },
|
||||
rangePrompt: (maxRange: number) => `選擇天數不能超過${maxRange} 天`,
|
||||
rangePromptWeek: (maxRange: number) => `選擇週數不能超過${maxRange} 週`,
|
||||
rangePromptMonth: (maxRange: number) => `選擇月份不能超過${maxRange} 個月`,
|
||||
monthTitle: 'YYYY年M月',
|
||||
yearTitle: 'YYYY年',
|
||||
month: 'M月',
|
||||
hour: (value: number) => `${value} 時`,
|
||||
minute: (value: number) => `${value} 分`,
|
||||
second: (value: number) => `${value} 秒`
|
||||
},
|
||||
collapse: { expand: '展開', retract: '收起' },
|
||||
colPicker: { title: '請選擇', placeholder: '請選擇', select: '請選擇' },
|
||||
datetimePicker: { start: '開始時間', end: '結束時間', to: '至', placeholder: '請選擇', confirm: '完成', cancel: '取消' },
|
||||
loadmore: { loading: '正在努力加載中...', finished: '已加載完畢', error: '加載失敗', retry: '點擊重試' },
|
||||
messageBox: { inputPlaceholder: '請輸入', confirm: '確定', cancel: '取消', inputNoValidate: '輸入的數據不合法' },
|
||||
numberKeyboard: { confirm: '完成' },
|
||||
pagination: {
|
||||
prev: '上一頁',
|
||||
next: '下一頁',
|
||||
page: (value: number) => `當前頁:${value}`,
|
||||
total: (total: number) => `當前數據:${total}條`,
|
||||
size: (size: number) => `分頁大小:${size}`
|
||||
},
|
||||
picker: { cancel: '取消', done: '完成', placeholder: '請選擇' },
|
||||
imgCropper: { confirm: '完成', cancel: '取消' },
|
||||
search: { search: '搜索', cancel: '取消' },
|
||||
steps: { wait: '未開始', finished: '已完成', process: '進行中', failed: '失敗' },
|
||||
tabs: { all: '全部' },
|
||||
upload: { error: '上傳失敗' },
|
||||
input: { placeholder: '請輸入...' },
|
||||
selectPicker: { title: '請選擇', placeholder: '請選擇', select: '確認', confirm: '確認', filterPlaceholder: '搜索' },
|
||||
tag: { placeholder: '請輸入', add: '新增標籤' },
|
||||
textarea: { placeholder: '請輸入...' }
|
||||
}
|
||||
@ -49,7 +49,7 @@
|
||||
- 🚀 支持 APP、H5、微信小程序 等平台.
|
||||
- 🚀 60+ 个高质量组件,覆盖移动端主流场景.
|
||||
- 💪 使用 Typescript 构建,提供良好的组件类型系统.
|
||||
- 💪 采用 Vue3 最新特性,提升组件性能.
|
||||
- 🌍 支持国际化,内置 6 种语言包.
|
||||
- 📖 提供丰富的文档和组件示例.
|
||||
- 🎨 支持修改 CSS 变量实现主题定制.
|
||||
- 🍭 支持暗黑模式
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user