mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 02:58:05 +08:00
feat:action 支持设置提交后倒计时 (#1607)
This commit is contained in:
parent
696c3e4dc4
commit
f25fbbf41e
@ -319,6 +319,34 @@ icon 也可以是 url 地址,比如
|
|||||||
| feedback | `DialogObject` | - | 如果 ajax 类型的,当 ajax 返回正常后,还能接着弹出一个 dialog 做其他交互。返回的数据可用于这个 dialog 中。格式可参考[Dialog](./Dialog.md) |
|
| feedback | `DialogObject` | - | 如果 ajax 类型的,当 ajax 返回正常后,还能接着弹出一个 dialog 做其他交互。返回的数据可用于这个 dialog 中。格式可参考[Dialog](./Dialog.md) |
|
||||||
| messages | `object` | - | `success`:ajax 操作成功后提示,可以不指定,不指定时以 api 返回为准。`failed`:ajax 操作失败提示。 |
|
| messages | `object` | - | `success`:ajax 操作成功后提示,可以不指定,不指定时以 api 返回为准。`failed`:ajax 操作失败提示。 |
|
||||||
|
|
||||||
|
### 倒计时
|
||||||
|
|
||||||
|
主要用于发验证码的场景,通过设置倒计时 `countDown`(单位是秒),让点击按钮后禁用一段时间:
|
||||||
|
|
||||||
|
```schema: scope="body"
|
||||||
|
{
|
||||||
|
"type": "form",
|
||||||
|
"controls": [
|
||||||
|
{
|
||||||
|
"name": "phone",
|
||||||
|
"type": "text",
|
||||||
|
"required": true,
|
||||||
|
"label": "手机号",
|
||||||
|
"addOn": {
|
||||||
|
"label": "发送验证码",
|
||||||
|
"type": "button",
|
||||||
|
"countDown": 60,
|
||||||
|
"countDownTpl": "${timeLeft} 秒后重发",
|
||||||
|
"actionType": "ajax",
|
||||||
|
"api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm?phone=${phone}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
同时还能通过 `countDownTpl` 来控制显示的文本,其中 `${timeLeft}` 变量是剩余时间。
|
||||||
|
|
||||||
## 跳转链接
|
## 跳转链接
|
||||||
|
|
||||||
### 单页跳转
|
### 单页跳转
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {register} from '../locale';
|
import {register} from '../locale';
|
||||||
|
|
||||||
register('en-US', {
|
register('en-US', {
|
||||||
|
'Action.countDown': 'Wait for ${timeLeft}s',
|
||||||
'Alert.info': 'System Info',
|
'Alert.info': 'System Info',
|
||||||
'asc': 'Asc',
|
'asc': 'Asc',
|
||||||
'cancel': 'Cancel',
|
'cancel': 'Cancel',
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {register} from '../locale';
|
import {register} from '../locale';
|
||||||
|
|
||||||
register('zh-CN', {
|
register('zh-CN', {
|
||||||
|
'Action.countDown': '请等待 ${timeLeft} 秒',
|
||||||
'Alert.info': '系统消息',
|
'Alert.info': '系统消息',
|
||||||
'asc': '正序',
|
'asc': '正序',
|
||||||
'cancel': '取消',
|
'cancel': '取消',
|
||||||
|
@ -99,6 +99,16 @@ export interface ButtonSchema extends BaseSchema {
|
|||||||
* 可以指定让谁来触发这个动作。
|
* 可以指定让谁来触发这个动作。
|
||||||
*/
|
*/
|
||||||
target?: string;
|
target?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点击后的禁止倒计时(秒)
|
||||||
|
*/
|
||||||
|
countDown?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 倒计时文字自定义
|
||||||
|
*/
|
||||||
|
countDownTpl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AjaxActionSchema extends ButtonSchema {
|
export interface AjaxActionSchema extends ButtonSchema {
|
||||||
@ -324,19 +334,53 @@ export interface ActionProps
|
|||||||
|
|
||||||
const allowedType = ['button', 'submit', 'reset'];
|
const allowedType = ['button', 'submit', 'reset'];
|
||||||
|
|
||||||
export class Action extends React.Component<ActionProps> {
|
interface ActionState {
|
||||||
|
inCountDown: boolean; // 是否在倒计时
|
||||||
|
countDownEnd: number; // 倒计时结束的精确时间
|
||||||
|
timeLeft: number; // 倒计时剩余时间
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Action extends React.Component<ActionProps, ActionState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
type: 'button' as 'button',
|
type: 'button' as 'button',
|
||||||
componentClass: 'button' as React.ReactType,
|
componentClass: 'button' as React.ReactType,
|
||||||
tooltipPlacement: 'bottom' as 'bottom',
|
tooltipPlacement: 'bottom' as 'bottom',
|
||||||
activeClassName: 'is-active'
|
activeClassName: 'is-active',
|
||||||
|
countDownTpl: 'Action.countDown',
|
||||||
|
countDown: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
state: ActionState = {
|
||||||
|
inCountDown: false,
|
||||||
|
countDownEnd: 0,
|
||||||
|
timeLeft: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
localStorageKey: string;
|
||||||
|
|
||||||
dom: any;
|
dom: any;
|
||||||
|
|
||||||
|
constructor(props: ActionProps) {
|
||||||
|
super(props);
|
||||||
|
this.localStorageKey = 'amis-countdownend-' + (this.props.name || '');
|
||||||
|
const countDownEnd = parseInt(
|
||||||
|
localStorage.getItem(this.localStorageKey) || '0'
|
||||||
|
);
|
||||||
|
if (countDownEnd && this.props.countDown) {
|
||||||
|
if (Date.now() < countDownEnd) {
|
||||||
|
this.state = {
|
||||||
|
inCountDown: true,
|
||||||
|
countDownEnd,
|
||||||
|
timeLeft: Math.floor((countDownEnd - Date.now()) / 1000)
|
||||||
|
};
|
||||||
|
this.handleCountDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
handleAction(e: React.MouseEvent<any>) {
|
handleAction(e: React.MouseEvent<any>) {
|
||||||
const {onAction, onClick, disabled} = this.props;
|
const {onAction, onClick, disabled, countDown} = this.props;
|
||||||
|
|
||||||
const result: any = onClick && onClick(e, this.props);
|
const result: any = onClick && onClick(e, this.props);
|
||||||
|
|
||||||
@ -347,18 +391,51 @@ export class Action extends React.Component<ActionProps> {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const action = pick(this.props, ActionProps) as ActionSchema;
|
const action = pick(this.props, ActionProps) as ActionSchema;
|
||||||
onAction(e, action);
|
onAction(e, action);
|
||||||
|
|
||||||
|
if (countDown) {
|
||||||
|
const countDownEnd = Date.now() + countDown * 1000;
|
||||||
|
this.setState({
|
||||||
|
countDownEnd: countDownEnd,
|
||||||
|
inCountDown: true,
|
||||||
|
timeLeft: countDown
|
||||||
|
});
|
||||||
|
|
||||||
|
localStorage.setItem(this.localStorageKey, String(countDownEnd));
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.handleCountDown();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
handleCountDown() {
|
||||||
|
// setTimeout 一般会晚于 1s,经过几十次后就不准了,所以使用真实时间进行 diff
|
||||||
|
const timeLeft = Math.floor((this.state.countDownEnd - Date.now()) / 1000);
|
||||||
|
if (timeLeft <= 0) {
|
||||||
|
this.setState({
|
||||||
|
inCountDown: false,
|
||||||
|
timeLeft: timeLeft
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
timeLeft: timeLeft
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
this.handleCountDown();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
type,
|
type,
|
||||||
label,
|
|
||||||
icon,
|
icon,
|
||||||
iconClassName,
|
iconClassName,
|
||||||
primary,
|
primary,
|
||||||
size,
|
size,
|
||||||
level,
|
level,
|
||||||
disabled,
|
countDownTpl,
|
||||||
block,
|
block,
|
||||||
className,
|
className,
|
||||||
componentClass,
|
componentClass,
|
||||||
@ -368,6 +445,7 @@ export class Action extends React.Component<ActionProps> {
|
|||||||
actionType,
|
actionType,
|
||||||
link,
|
link,
|
||||||
data,
|
data,
|
||||||
|
translate: __,
|
||||||
activeClassName,
|
activeClassName,
|
||||||
isCurrentUrl,
|
isCurrentUrl,
|
||||||
isMenuItem,
|
isMenuItem,
|
||||||
@ -377,12 +455,23 @@ export class Action extends React.Component<ActionProps> {
|
|||||||
classnames: cx
|
classnames: cx
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
let label = this.props.label;
|
||||||
|
let disabled = this.props.disabled;
|
||||||
let isActive = !!active;
|
let isActive = !!active;
|
||||||
|
|
||||||
if (actionType === 'link' && !isActive && link && isCurrentUrl) {
|
if (actionType === 'link' && !isActive && link && isCurrentUrl) {
|
||||||
isActive = isCurrentUrl(link);
|
isActive = isCurrentUrl(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 倒计时
|
||||||
|
if (this.state.inCountDown) {
|
||||||
|
label = filterContents(__(countDownTpl), {
|
||||||
|
...data,
|
||||||
|
timeLeft: this.state.timeLeft
|
||||||
|
}) as string;
|
||||||
|
disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
const iconElement = generateIcon(cx, icon, 'Button-icon', iconClassName);
|
const iconElement = generateIcon(cx, icon, 'Button-icon', iconClassName);
|
||||||
|
|
||||||
return isMenuItem ? (
|
return isMenuItem ? (
|
||||||
|
Loading…
Reference in New Issue
Block a user