iter(g95): 统计数值支持倒计时模式
This commit is contained in:
@@ -1116,6 +1116,14 @@
|
|||||||
"acceptance": "recipes.md 新增「配方 5:数据表 + 独立分页器 + 导出」,覆盖同一 page 信号双绑、exportable 导全量行与当页的区别、拖拽只对数字列宽生效、rowKey 记账;npm run docs 后 llms-full.txt 出现该配方;npm run check 全绿",
|
"acceptance": "recipes.md 新增「配方 5:数据表 + 独立分页器 + 导出」,覆盖同一 page 信号双绑、exportable 导全量行与当页的区别、拖拽只对数字列宽生效、rowKey 记账;npm run docs 后 llms-full.txt 出现该配方;npm run check 全绿",
|
||||||
"notes": "自补:文档完善;只写用法不碰实现,配方随 docs 注入 llms-full",
|
"notes": "自补:文档完善;只写用法不碰实现,配方随 docs 注入 llms-full",
|
||||||
"status": "done"
|
"status": "done"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "g95",
|
||||||
|
"title": "统计数值支持倒计时模式",
|
||||||
|
"motivation": "活动剩余时间这类需求只能调用方自己 setInterval 改信号再塞进 statistic,还得自己管停表;组件本身只认一个数值信号,秒级刷新没有落脚点",
|
||||||
|
"acceptance": "StatisticProps 新增 countdown(目标时间戳毫秒),传了即每秒显示 DD 天 HH:MM:SS(不足一天省天数),value 转为可选;到点或组件被移除后自动 clearInterval,不留常驻定时器;倒计时不走滚动动画;文档与演示同步;npm run check 全绿",
|
||||||
|
"notes": "自补:功能补齐;停表条件放在 tick 内自检 isConnected,无需额外卸载钩子",
|
||||||
|
"status": "open"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "ui-arch-registry-index/0.1",
|
"$schema": "ui-arch-registry-index/0.1",
|
||||||
"generatedAt": "2026-10-26T05:12:11.001Z",
|
"generatedAt": "2026-10-26T05:13:47.565Z",
|
||||||
"repoRoot": ".",
|
"repoRoot": ".",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
@@ -1953,7 +1953,12 @@
|
|||||||
"n": "value",
|
"n": "value",
|
||||||
"t": "Signal<number>",
|
"t": "Signal<number>",
|
||||||
"r": 1,
|
"r": 1,
|
||||||
"d": "数值信号:变化时从当前显示值滚动到新值,首跑即入场动画"
|
"d": "数值信号:变化时滚动过渡到新值;倒计时模式可不传"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"n": "countdown",
|
||||||
|
"t": "number",
|
||||||
|
"d": "目标时间戳(毫秒):传了即倒计时模式,每秒显示 DD 天 HH:MM:SS,忽略 value"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"n": "precision",
|
"n": "precision",
|
||||||
@@ -1984,7 +1989,8 @@
|
|||||||
"precision 控制小数位,千分位由 toLocaleString 自动加,不要自己拼格式化",
|
"precision 控制小数位,千分位由 toLocaleString 自动加,不要自己拼格式化",
|
||||||
"trend 只表达方向与颜色(涨红跌绿),数值本身与环比幅度仍由调用方组织",
|
"trend 只表达方向与颜色(涨红跌绿),数值本身与环比幅度仍由调用方组织",
|
||||||
"多条指标并排时用 descriptions 或 flex 容器排列,本组件不自带网格",
|
"多条指标并排时用 descriptions 或 flex 容器排列,本组件不自带网格",
|
||||||
"用户开启「减弱动效」时组件直接落终值,无需调用方判断"
|
"用户开启「减弱动效」时组件直接落终值,无需调用方判断",
|
||||||
|
"做倒计时(活动剩余时间等)传 countdown: 目标时间戳,组件每秒刷新并在到点/卸载时自动停表"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+2
-1
@@ -552,12 +552,13 @@ const content = h(
|
|||||||
section(
|
section(
|
||||||
'sec-statistic',
|
'sec-statistic',
|
||||||
'统计数值',
|
'统计数值',
|
||||||
'statistic:大号等宽数字 + 前后缀 + 环比趋势;value 变化时 400ms 缓出滚动(减弱动效偏好下直落终值)。',
|
'statistic:大号等宽数字 + 前后缀 + 环比趋势;value 变化时 400ms 缓出滚动(减弱动效偏好下直落终值);传 countdown 目标时间戳即变倒计时,到点自动停表。',
|
||||||
h(
|
h(
|
||||||
'div',
|
'div',
|
||||||
{ class: 'row' },
|
{ class: 'row' },
|
||||||
statistic({ title: '本月 GMV', value: gmv, prefix: '¥', precision: 2, trend: 'up' }),
|
statistic({ title: '本月 GMV', value: gmv, prefix: '¥', precision: 2, trend: 'up' }),
|
||||||
statistic({ title: '订单数', value: orders, suffix: '单', trend: 'down' }),
|
statistic({ title: '订单数', value: orders, suffix: '单', trend: 'down' }),
|
||||||
|
statistic({ title: '活动倒计时', countdown: Date.now() + 95 * 60 * 1000 }),
|
||||||
),
|
),
|
||||||
h(
|
h(
|
||||||
'div',
|
'div',
|
||||||
|
|||||||
+4
-2
@@ -1,6 +1,6 @@
|
|||||||
# @ui-arch 组件库 Agent 文档(无图形版)
|
# @ui-arch 组件库 Agent 文档(无图形版)
|
||||||
|
|
||||||
> 自动生成于 2026-10-26T05:12:11.001Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
> 自动生成于 2026-10-26T05:13:47.565Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||||
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
||||||
|
|
||||||
## 快速上手
|
## 快速上手
|
||||||
@@ -1052,7 +1052,8 @@ descriptions({ title: '订单信息', column: 2, bordered: true, items: [{ label
|
|||||||
参数:
|
参数:
|
||||||
|
|
||||||
- title:string —— 指标名(小字灰标题);缺省不渲染
|
- title:string —— 指标名(小字灰标题);缺省不渲染
|
||||||
- value(必填):Signal<number> —— 数值信号:变化时从当前显示值滚动到新值,首跑即入场动画
|
- value(必填):Signal<number> —— 数值信号:变化时滚动过渡到新值;倒计时模式可不传
|
||||||
|
- countdown:number —— 目标时间戳(毫秒):传了即倒计时模式,每秒显示 DD 天 HH:MM:SS,忽略 value
|
||||||
- precision(默认 0):number —— 小数位,千分位分隔自动带;缺省 0
|
- precision(默认 0):number —— 小数位,千分位分隔自动带;缺省 0
|
||||||
- prefix:string —— 数字前缀(如 ¥);缺省不渲染
|
- prefix:string —— 数字前缀(如 ¥);缺省不渲染
|
||||||
- suffix:string —— 数字后缀(如 元 / %);缺省不渲染
|
- suffix:string —— 数字后缀(如 元 / %);缺省不渲染
|
||||||
@@ -1072,6 +1073,7 @@ const gmv = signal(128000); statistic({ title: '本月 GMV', value: gmv, prefix:
|
|||||||
4. trend 只表达方向与颜色(涨红跌绿),数值本身与环比幅度仍由调用方组织
|
4. trend 只表达方向与颜色(涨红跌绿),数值本身与环比幅度仍由调用方组织
|
||||||
5. 多条指标并排时用 descriptions 或 flex 容器排列,本组件不自带网格
|
5. 多条指标并排时用 descriptions 或 flex 容器排列,本组件不自带网格
|
||||||
6. 用户开启「减弱动效」时组件直接落终值,无需调用方判断
|
6. 用户开启「减弱动效」时组件直接落终值,无需调用方判断
|
||||||
|
7. 做倒计时(活动剩余时间等)传 countdown: 目标时间戳,组件每秒刷新并在到点/卸载时自动停表
|
||||||
|
|
||||||
现场演示:apps/docs/demo.html#sec-statistic
|
现场演示:apps/docs/demo.html#sec-statistic
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
import { effect, h } from '@ui-arch/frame';
|
import { effect, h, signal } from '@ui-arch/frame';
|
||||||
import type { StatisticProps } from './types.js';
|
import type { StatisticProps } from './types.js';
|
||||||
|
|
||||||
/*** 统计数值:标题 + 大号数字 + 前后缀 + 环比趋势,数值变化时 rAF 滚动过渡(400ms,easeOutCubic) ***/
|
/*** 剩余毫秒 → DD 天 HH:MM:SS(不足一天省略天数,保持等宽跳动不抖动) ***/
|
||||||
|
function fmtLeft(ms: number): string {
|
||||||
|
const total = Math.floor(ms / 1000);
|
||||||
|
const d = Math.floor(total / 86400);
|
||||||
|
const hh = String(Math.floor((total % 86400) / 3600)).padStart(2, '0');
|
||||||
|
const mm = String(Math.floor((total % 3600) / 60)).padStart(2, '0');
|
||||||
|
const ss = String(total % 60).padStart(2, '0');
|
||||||
|
return d > 0 ? `${d} 天 ${hh}:${mm}:${ss}` : `${hh}:${mm}:${ss}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** 统计数值:标题 + 大号数字 + 前后缀 + 环比趋势;数值滚动过渡,传 countdown 则改为每秒倒计时 ***/
|
||||||
export function statistic(props: StatisticProps): HTMLElement {
|
export function statistic(props: StatisticProps): HTMLElement {
|
||||||
// —— 状态集中声明 ——
|
// —— 状态集中声明 ——
|
||||||
const precision = props.precision ?? 0; // 小数位
|
const precision = props.precision ?? 0; // 小数位
|
||||||
@@ -36,6 +46,17 @@ export function statistic(props: StatisticProps): HTMLElement {
|
|||||||
props.trend ? h('span', { class: `ua-stat-trend is-${props.trend}` }, props.trend === 'up' ? '▲' : '▼') : null);
|
props.trend ? h('span', { class: `ua-stat-trend is-${props.trend}` }, props.trend === 'up' ? '▲' : '▼') : null);
|
||||||
const view = h('div', { class: 'ua-stat' }, props.title ? h('div', { class: 'ua-stat-title' }, props.title) : null, row);
|
const view = h('div', { class: 'ua-stat' }, props.title ? h('div', { class: 'ua-stat-title' }, props.title) : null, row);
|
||||||
|
|
||||||
effect(() => roll(props.value())); // 信号变化即滚动到新值(首跑做入场动画)
|
const target = props.countdown;
|
||||||
|
if (target) {
|
||||||
|
const left = signal(Math.max(0, target - Date.now())); // 剩余毫秒
|
||||||
|
const timer = window.setInterval(() => {
|
||||||
|
const ms = Math.max(0, target - Date.now());
|
||||||
|
left(ms);
|
||||||
|
if (!ms || !view.isConnected) window.clearInterval(timer); // 到点或已卸载即停表,不留常驻定时器
|
||||||
|
}, 1000);
|
||||||
|
effect(() => { num.textContent = fmtLeft(left()); }); // 倒计时模式不走滚动动画,每秒直落
|
||||||
|
} else if (props.value) {
|
||||||
|
effect(() => roll(props.value!())); // 信号变化即滚动到新值(首跑做入场动画)
|
||||||
|
}
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -419,7 +419,8 @@ export interface DescriptionsProps {
|
|||||||
/*** 统计数值入参 ***/
|
/*** 统计数值入参 ***/
|
||||||
export interface StatisticProps {
|
export interface StatisticProps {
|
||||||
title?: string; // 指标名;缺省不渲染标题行
|
title?: string; // 指标名;缺省不渲染标题行
|
||||||
value: Signal<number>; // 数值信号:变化时滚动过渡到新值(首跑即入场动画)
|
value?: Signal<number>; // 数值信号:变化时滚动过渡到新值(首跑即入场动画);倒计时模式可不传
|
||||||
|
countdown?: number; // 目标时间戳(毫秒):传了即倒计时模式,每秒显示 DD 天 HH:MM:SS,忽略 value
|
||||||
precision?: number; // 小数位;缺省 0
|
precision?: number; // 小数位;缺省 0
|
||||||
prefix?: string; // 数字前缀(如 ¥);缺省不渲染
|
prefix?: string; // 数字前缀(如 ¥);缺省不渲染
|
||||||
suffix?: string; // 数字后缀(如 元 / %);缺省不渲染
|
suffix?: string; // 数字后缀(如 元 / %);缺省不渲染
|
||||||
|
|||||||
@@ -1824,7 +1824,12 @@
|
|||||||
"n": "value",
|
"n": "value",
|
||||||
"t": "Signal<number>",
|
"t": "Signal<number>",
|
||||||
"r": 1,
|
"r": 1,
|
||||||
"d": "数值信号:变化时从当前显示值滚动到新值,首跑即入场动画"
|
"d": "数值信号:变化时滚动过渡到新值;倒计时模式可不传"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"n": "countdown",
|
||||||
|
"t": "number",
|
||||||
|
"d": "目标时间戳(毫秒):传了即倒计时模式,每秒显示 DD 天 HH:MM:SS,忽略 value"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"n": "precision",
|
"n": "precision",
|
||||||
@@ -1855,7 +1860,8 @@
|
|||||||
"precision 控制小数位,千分位由 toLocaleString 自动加,不要自己拼格式化",
|
"precision 控制小数位,千分位由 toLocaleString 自动加,不要自己拼格式化",
|
||||||
"trend 只表达方向与颜色(涨红跌绿),数值本身与环比幅度仍由调用方组织",
|
"trend 只表达方向与颜色(涨红跌绿),数值本身与环比幅度仍由调用方组织",
|
||||||
"多条指标并排时用 descriptions 或 flex 容器排列,本组件不自带网格",
|
"多条指标并排时用 descriptions 或 flex 容器排列,本组件不自带网格",
|
||||||
"用户开启「减弱动效」时组件直接落终值,无需调用方判断"
|
"用户开启「减弱动效」时组件直接落终值,无需调用方判断",
|
||||||
|
"做倒计时(活动剩余时间等)传 countdown: 目标时间戳,组件每秒刷新并在到点/卸载时自动停表"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user