@didaoktv/didaoui-uniapp 1.3.2 → 1.3.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
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @didaoktv/didaoui-uniapp
|
|
1
|
+
# @didaoktv/didaoui-uniapp
|
|
2
2
|
|
|
3
3
|
专为 KTV 场景打造的 UniApp 组件库。
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
- **帝王级配色** — 帝王金 `#F5A623` + 皇家蓝 `#2D4BA0` 双主色,暗色主题默认
|
|
8
8
|
- **玻璃拟态设计** — 多层级玻璃拟态效果,打造高端夜店沉浸感
|
|
9
|
-
- **
|
|
9
|
+
- **89 个精心打磨的组件** — 覆盖表单、导航、布局卡片、数据展示、浮层反馈、交互、画布七大类,含 KTV 业务组件(房态卡、账单明细、工单卡、日历、二维码)
|
|
10
10
|
- **Vue3 + TypeScript** — 完整类型定义,Composition API
|
|
11
11
|
- **多端兼容** — H5 / 微信小程序 / 抖音小程序 / Android / iOS
|
|
12
12
|
|
|
@@ -50,13 +50,14 @@ import { DdButton, DdInput } from '@didaoktv/didaoui-uniapp'
|
|
|
50
50
|
|
|
51
51
|
| 分类 | 数量 | 组件 |
|
|
52
52
|
| ----- | -- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
53
|
-
| 表单输入 |
|
|
53
|
+
| 表单输入 | 23 | Button, CodeButton, Input, Form, Field, Switch, Checkbox, CheckboxGroup, Radio, RadioGroup, Stepper, SearchBar, Slider, DatePicker, Picker, Rate, Upload, Icon, Keyboard, NumberKeyboard, CarKeyboard, Cascader, GoodsSku |
|
|
54
54
|
| 导航 | 12 | Navigation, TopNavbar, SwipeableTab, SegmentedTab, Drawer, Tabbar, TabbarItem, Backtop, Collapse, CollapseItem, DropdownMenu, DropdownItem |
|
|
55
55
|
| 布局/卡片 | 8 | Card, RoomCard, FeatureGrid, Sticky, BillDetail, WorkorderCard, Calendar, Qrcode |
|
|
56
|
-
| 数据展示 |
|
|
56
|
+
| 数据展示 | 24 | Tag, StatCard, ChampionCard, Avatar, AvatarGroup, Badge, ListCell, Cell, CellGroup, CountDown, Divider, Image, Progress, Skeleton, EmptyState, Step, Steps, Text, Link, Copy, Album, Coupon, Parse, Markdown |
|
|
57
57
|
| 浮层反馈 | 10 | Modal, ActionSheet, Toast, Alert, Loading, Dialog, Overlay, Popup, Popover, PopoverItem |
|
|
58
58
|
| 交互 | 5 | SwipeAction, Swipe, SwipeItem, PullRefresh, Loadmore |
|
|
59
|
-
| 小程序专属 | 2 | CapsuleButton, MiniProgramNavbar
|
|
59
|
+
| 小程序专属 | 2 | CapsuleButton, MiniProgramNavbar |
|
|
60
|
+
| 画布 | 5 | Canvas, Barcode, Cropper, Signature, Poster |
|
|
60
61
|
|
|
61
62
|
## 设计规范
|
|
62
63
|
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- class/style 经单根节点 fallthrough 合并到 dd-button 根元素 -->
|
|
3
|
+
<dd-button
|
|
4
|
+
:type="type"
|
|
5
|
+
:size="size"
|
|
6
|
+
:disabled="!canGetCode"
|
|
7
|
+
:class="customClass"
|
|
8
|
+
:style="customStyle"
|
|
9
|
+
@click="handleClick"
|
|
10
|
+
>
|
|
11
|
+
{{ showText }}
|
|
12
|
+
</dd-button>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
17
|
+
import DdButton from '../dd-button/dd-button.vue'
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
/** 倒计时秒数 */
|
|
21
|
+
time?: number | string
|
|
22
|
+
/** 初始文本 */
|
|
23
|
+
startText?: string
|
|
24
|
+
/** 倒计时文本,X/x 占位剩余秒数 */
|
|
25
|
+
changeText?: string
|
|
26
|
+
/** 倒计时结束文本 */
|
|
27
|
+
endText?: string
|
|
28
|
+
/** H5刷新/各端离开再进入时是否继续倒计时 */
|
|
29
|
+
keepRunning?: boolean
|
|
30
|
+
/** 多个组件间的区分 key */
|
|
31
|
+
uniqueKey?: string
|
|
32
|
+
type?: 'primary' | 'secondary' | 'ghost' | 'text' | 'success' | 'warning' | 'danger'
|
|
33
|
+
size?: 'sm' | 'md' | 'lg'
|
|
34
|
+
customClass?: string
|
|
35
|
+
customStyle?: Record<string, string>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
39
|
+
time: 60,
|
|
40
|
+
startText: '获取验证码',
|
|
41
|
+
changeText: 'X秒重新获取',
|
|
42
|
+
endText: '重新获取',
|
|
43
|
+
keepRunning: false,
|
|
44
|
+
uniqueKey: 'dd-code-button',
|
|
45
|
+
type: 'primary',
|
|
46
|
+
size: 'sm',
|
|
47
|
+
customClass: '',
|
|
48
|
+
customStyle: () => ({}),
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const emit = defineEmits<{
|
|
52
|
+
(e: 'click'): void
|
|
53
|
+
(e: 'start'): void
|
|
54
|
+
(e: 'change', seconds: number): void
|
|
55
|
+
(e: 'finish'): void
|
|
56
|
+
}>()
|
|
57
|
+
|
|
58
|
+
const totalSeconds = computed(() => Math.max(1, Math.floor(Number(props.time) || 60)))
|
|
59
|
+
|
|
60
|
+
const storageKey = computed(() => `dd-code-btn:${props.uniqueKey}`)
|
|
61
|
+
|
|
62
|
+
const remainMs = ref(totalSeconds.value * 1000)
|
|
63
|
+
// 是否点过(用于区分初始文本与结束文本)
|
|
64
|
+
const isClick = ref(false)
|
|
65
|
+
const isRunning = ref(false)
|
|
66
|
+
const canGetCode = ref(true)
|
|
67
|
+
|
|
68
|
+
// ponytail: endTime + Date.now() 差值计时而非递减计数,避免 setInterval 漂移;小程序退后台定时器冻结,回前台下一个 tick 自动对齐
|
|
69
|
+
let endTime = 0
|
|
70
|
+
let timer: ReturnType<typeof setInterval> | null = null
|
|
71
|
+
|
|
72
|
+
const showText = computed(() => {
|
|
73
|
+
if (!isClick.value) return props.startText
|
|
74
|
+
if (!isRunning.value) return props.endText
|
|
75
|
+
const seconds = Math.ceil(remainMs.value / 1000)
|
|
76
|
+
return props.changeText.replace(/X|x/g, String(seconds))
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
function tick() {
|
|
80
|
+
remainMs.value = Math.max(0, endTime - Date.now())
|
|
81
|
+
if (remainMs.value <= 0) {
|
|
82
|
+
finish()
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
emit('change', Math.ceil(remainMs.value / 1000))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function finish() {
|
|
89
|
+
stopTimer()
|
|
90
|
+
isRunning.value = false
|
|
91
|
+
canGetCode.value = true
|
|
92
|
+
remainMs.value = totalSeconds.value * 1000
|
|
93
|
+
if (props.keepRunning) uni.removeStorageSync(storageKey.value)
|
|
94
|
+
emit('finish')
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function stopTimer() {
|
|
98
|
+
if (timer) {
|
|
99
|
+
clearInterval(timer)
|
|
100
|
+
timer = null
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** 开始倒计时(外部发验证码成功后调用),可传入剩余毫秒用于恢复 */
|
|
105
|
+
function start(remainOverride?: number) {
|
|
106
|
+
stopTimer()
|
|
107
|
+
if (!canGetCode.value && isClick.value) return
|
|
108
|
+
emit('start')
|
|
109
|
+
canGetCode.value = false
|
|
110
|
+
isClick.value = true
|
|
111
|
+
isRunning.value = true
|
|
112
|
+
remainMs.value = remainOverride ?? totalSeconds.value * 1000
|
|
113
|
+
endTime = Date.now() + remainMs.value
|
|
114
|
+
// 开始即落盘结束时间戳:H5 刷新/进程被杀时 onUnmounted 不可靠,写一次比每秒写便宜
|
|
115
|
+
if (props.keepRunning) {
|
|
116
|
+
uni.setStorageSync(storageKey.value, Math.floor(endTime / 1000))
|
|
117
|
+
}
|
|
118
|
+
tick()
|
|
119
|
+
timer = setInterval(tick, 1000)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function reset() {
|
|
123
|
+
stopTimer()
|
|
124
|
+
canGetCode.value = true
|
|
125
|
+
isRunning.value = false
|
|
126
|
+
remainMs.value = totalSeconds.value * 1000
|
|
127
|
+
if (props.keepRunning) uni.removeStorageSync(storageKey.value)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function handleClick() {
|
|
131
|
+
if (!canGetCode.value) return
|
|
132
|
+
emit('click')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** keepRunning: 挂载时检查本地记录的结束时间戳,未到期则续跑 */
|
|
136
|
+
function resume() {
|
|
137
|
+
if (!props.keepRunning) return
|
|
138
|
+
const endTs = Number(uni.getStorageSync(storageKey.value))
|
|
139
|
+
if (!endTs) return
|
|
140
|
+
uni.removeStorageSync(storageKey.value)
|
|
141
|
+
const remain = (endTs - Math.floor(Date.now() / 1000)) * 1000
|
|
142
|
+
if (remain > 0) start(remain)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
onMounted(resume)
|
|
146
|
+
|
|
147
|
+
onUnmounted(stopTimer)
|
|
148
|
+
|
|
149
|
+
defineExpose({ canGetCode, start, reset })
|
|
150
|
+
</script>
|
|
@@ -69,11 +69,8 @@ const emit = defineEmits<{
|
|
|
69
69
|
const isFocused = ref(false)
|
|
70
70
|
const visible = ref(false)
|
|
71
71
|
|
|
72
|
-
// ponytail: search
|
|
73
|
-
const inputType = computed<'text' | 'number'>(() =>
|
|
74
|
-
if (props.type === 'password' || props.type === 'search') return 'text'
|
|
75
|
-
return 'number'
|
|
76
|
-
})
|
|
72
|
+
// ponytail: search 在小程序降级为 text;password 用 uni 原生 password 布尔属性跨端
|
|
73
|
+
const inputType = computed<'text' | 'number'>(() => (props.type === 'number' ? 'number' : 'text'))
|
|
77
74
|
const isPassword = computed(() => props.type === 'password' && !visible.value)
|
|
78
75
|
const confirmType = computed(() => (props.type === 'search' ? 'search' : 'done'))
|
|
79
76
|
const showClear = computed(() => props.clearable && !!props.modelValue && !props.disabled)
|
package/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { App } from 'vue'
|
|
2
2
|
|
|
3
|
-
// === Input (
|
|
3
|
+
// === Input (23) ===
|
|
4
4
|
import DdButton from './components/dd-button/dd-button.vue'
|
|
5
|
+
import DdCodeButton from './components/dd-code-button/dd-code-button.vue'
|
|
5
6
|
import DdInput from './components/dd-input/dd-input.vue'
|
|
6
7
|
import DdSwitch from './components/dd-switch/dd-switch.vue'
|
|
7
8
|
import DdCheckbox from './components/dd-checkbox/dd-checkbox.vue'
|
|
@@ -38,7 +39,7 @@ import DdCollapseItem from './components/dd-collapse-item/dd-collapse-item.vue'
|
|
|
38
39
|
import DdDropdownMenu from './components/dd-dropdown-menu/dd-dropdown-menu.vue'
|
|
39
40
|
import DdDropdownItem from './components/dd-dropdown-item/dd-dropdown-item.vue'
|
|
40
41
|
|
|
41
|
-
// === Layout (
|
|
42
|
+
// === Layout (8) ===
|
|
42
43
|
import DdCard from './components/dd-card/dd-card.vue'
|
|
43
44
|
import DdRoomCard from './components/dd-room-card/dd-room-card.vue'
|
|
44
45
|
import DdFeatureGrid from './components/dd-feature-grid/dd-feature-grid.vue'
|
|
@@ -105,7 +106,7 @@ import DdSignature from './components/dd-signature/dd-signature.vue'
|
|
|
105
106
|
import DdPoster from './components/dd-poster/dd-poster.vue'
|
|
106
107
|
|
|
107
108
|
const components = {
|
|
108
|
-
DdButton, DdInput, DdSwitch, DdCheckbox, DdCheckboxGroup, DdRadio, DdRadioGroup, DdForm,
|
|
109
|
+
DdButton, DdCodeButton, DdInput, DdSwitch, DdCheckbox, DdCheckboxGroup, DdRadio, DdRadioGroup, DdForm,
|
|
109
110
|
DdSearchBar, DdSlider, DdStepper, DdDatePicker, DdField,
|
|
110
111
|
DdPicker, DdRate, DdUpload, DdIcon,
|
|
111
112
|
DdKeyboard, DdNumberKeyboard, DdCarKeyboard, DdCascader, DdGoodsSku,
|
|
@@ -135,7 +136,7 @@ export default { install }
|
|
|
135
136
|
// 全量具名导出
|
|
136
137
|
export {
|
|
137
138
|
components,
|
|
138
|
-
DdButton, DdInput, DdSwitch, DdCheckbox, DdCheckboxGroup, DdRadio, DdRadioGroup, DdForm,
|
|
139
|
+
DdButton, DdCodeButton, DdInput, DdSwitch, DdCheckbox, DdCheckboxGroup, DdRadio, DdRadioGroup, DdForm,
|
|
139
140
|
DdSearchBar, DdSlider, DdStepper, DdDatePicker, DdField,
|
|
140
141
|
DdPicker, DdRate, DdUpload, DdIcon,
|
|
141
142
|
DdKeyboard, DdNumberKeyboard, DdCarKeyboard, DdCascader, DdGoodsSku,
|