ant design 的table 每行单独添加可操作的定时器
工作中有个需求,先获取一个list列表数据展示成一个表格。每一条列表数据都可以动态查看当前数据的运行状态,就是需要不停的去做运行状态的请求。如果每条数据都开启一个定时器的话,不好好管理,所以考虑把在运行状态中的请求都放在一个定时器里。现在我简单的做个定时器模拟这一效果。

看图:刚开始是前三条数据在运行,过了10秒以后(实际工作中,可以把10秒变成运行结束的判断条件),只有第三条在运行,然后我又点击了第四条,3,4两条又重新开启了定时器。
const { Table, Divider, Tag } = antd;
const data = [
{
key: 1,
name: 'John Brown',
age: 32,
address: '1',
},
{
key: 2,
name: 'Jim Green',
age: 42,
address: '1',
},
{
key: 3,
name: 'Joe Black',
age: 32,
address: '1',
},
{
key: 4,
name: 'Jim Green',
age: 42,
address: '1',
},
{
key: 5,
name: 'Joe Black',
age: 32,
address: '1',
},
];
class Sider extends React.Component {
constructor(props) {
super(props);
this.state = {
scan:[1,2,3],
scunNum:[1,1,1],
};
}
componentDidMount(){
const {scan} = this.state;
let i=1;
// 初始化开启定时器
this.timer = setInterval(()=> {
i += 1;
if(i>10){
const runId=scan.filter((_,n)=> n>1);
const runIdTime=runId.map(()=>i);
this.setState({scunNum:runIdTime,scan:runId})
}else{
const runIdTime=scan.map(()=>i);
this.setState({scunNum:runIdTime})
}
},1000);
}
componentWillUnmount() {
// 离开页面关闭定时器
clearInterval(this.timer);
}
start = (i) =>{
const { scunNum } = this.state;
return scunNum[i]
}
render() {
const {scan} = this.state;
const columns = [
{
title: 'id',
dataIndex: 'key',
key: 'key',
},
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: '计时',
dataIndex: 'address',
key: 'address',
render: (address,record)=> {
if(scan.indexOf(record.key)>-1){
return this.start(scan.indexOf(record.key))
}
return <span>未开始</span>
}
},
{
title: 'Action',
key: 'action',
render: (text, record) => (
<div>
{
scan.indexOf(record.key)===-1?
<a
onClick={()=>{
this.setState({scan:[...scan,record.key]});
clearInterval(this.timer);
let i=1;
this.timer = setInterval(()=> {
i += 1;
const runIdTime=[...scan,record.key].map(()=>i);
this.setState({scunNum:runIdTime})
},1000);
}}
>
开始</a>:
<span>开始</span>
}
</div>
),
},
];
return (
<Table columns={columns} dataSource={data} />
);
}
}
ReactDOM.render(<Sider />, mountNode);
这个场景适用于多条数据的运行,实时观测每一条的运行过程。只需要把你的轮训请求放在定时器里就可以了

我的项目文件:
import React from 'react'; import { connect } from 'dva'; import { Card, Table, Popconfirm, Divider, Input, message, Form, Row, Col, Select, Button, Progress } from 'antd'; import Link from 'umi/link'; import request from '@/utils/request'; const FormItem = Form.Item; const { Option } = Select; const bizId=["","","kdbMySql","mysql2","hive","kafka2","es"]; @connect(({ ruleList, loading }) => ({ ruleList, loading: loading.models.ruleList, })) @Form.create() class RuleList extends React.Component { constructor(props) { super(props); this.state = { bizTypes: [], allTypes:[], scan:[], }; } componentWillMount() { const { location: { query: { biz }, }, dispatch, } = this.props; request(`/api/data_marking/biz-types`, { credentials: 'same-origin', }).then(resp => { if (resp && resp.success) { const val = resp.data.filter(vals=>vals.id===Number(biz))[0]; this.setState({ bizTypes: val?val.subTypeList:[],allTypes:resp.data }); } else { message.error(`[请求失败]${JSON.stringify(resp.data)}`); } }); dispatch({ type: 'ruleList/fetchRuleList', payload: { page: 1, pageSize: 10, filter: { union: true }, biz, }, }).then((res)=>{ this.requestStatus(res,biz) }) } componentWillUnmount() { clearInterval(this.timer); } requestStatus=(res,biz)=>{ const statusId= res.map((i) => ({ id:i.id ,status:i.runInfo.ruleRunState.id})) this.setState({scan:statusId}) let runData=statusId.filter(m=>[3,4].indexOf(m.status)===-1); if(runData.length){ this.timer = setInterval(()=> { Promise.all( runData.map((run)=>{ return request(`/api/data_marking/biz/${biz}/db-column-tag-rule/${run.id}/run-state`, { credentials: 'same-origin', }).then(r=>({id:run.id,status:r.data.ruleRunState.id})) }) ).then((val)=>{ const oId=val.map(v=>v.id); const newScan=statusId.map(j=>(oId.indexOf(j.id)>-1?{id:j.id,status:val[oId.indexOf(j.id)].status}:j)); this.setState({scan:newScan}); runData=newScan.filter(m=>[3,4].indexOf(m.status)===-1); if(!runData.length){ clearInterval(this.timer); } }) },1200); } } handleTableChange = pagination => { const pageNum = pagination.current; const { pageSize } = pagination; const { dispatch, ruleList: { filter }, location: { query: {biz}, }, } = this.props; dispatch({ type: 'ruleList/fetchRuleList', payload: { page: pageNum, filter, pageSize, biz }, }).then((res)=>{ this.requestStatus(res,biz) }) }; handleSearch = (e) => { e.preventDefault(); const { dispatch, location: { query: { biz }, }, form, } = this.props; form.validateFields((err, values) => { if (err) return; dispatch({ type: 'ruleList/fetchRuleList', payload: { page: 1, pageSize: 10, filter: {...values,union: true}, biz, }, }).then((res)=>{ this.requestStatus(res,biz) }) }) }; handleFormReset = () => { const { form, dispatch, location: { query: { biz }, }, } = this.props; form.resetFields(); dispatch({ type: 'ruleList/fetchRuleList', payload: { page: 1, pageSize: 10, filter: { union: true }, biz, }, }).then((res)=>{ this.requestStatus(res,biz) }) }; deleteRuleHandler = id => { const { dispatch, location: { query: {biz}, }, } = this.props; dispatch({ type: 'ruleList/fetchDeleteRule', payload: { id, biz, filter: { union: true }, }, }) }; ddd = (i) =>{ const { scan } = this.state; const statu=scan.filter(n=>n.id===i)[0]?.status; switch (statu) { case 1: return <><Progress percent={70} strokeColor='orange' size="small" status="active" format={() => ''} /><br />等待运行</>; case 2: return <><Progress percent={50} size="small" status="active" format={() => ''} /><br />运行中</>; case 3: return <><Progress percent={100} size="small" /><br />上次执行成功</>; case 4: return <><Progress percent={70} size="small" status="exception" /><br />上次执行失败</>; case 5: return <><Progress percent={100} strokeColor='orange' size="small" status="active" format={() => ''} /><br />排队中</>; default: break; } return '' } searchForm(){ const { form: { getFieldDecorator }, } = this.props; const { bizTypes } = this.state; const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 }, }; return ( <Form {...formItemLayout} style={{ marginBottom: 20 }} onSubmit={this.handleSearch}> <Row> <Col span={8}> <FormItem label="子场景"> {getFieldDecorator('biz_sub_id')( <Select allowClear placeholder="请选择子场景" > {bizTypes.map(dn => ( <Option key={dn.name} value={`${dn.id}`}> {`${dn.name} ( ${dn.desc} )`} </Option> ))} </Select> )} </FormItem> </Col> <Col span={8}> <FormItem label="关键字"> {getFieldDecorator('key_word')( <Input placeholder='请输入关键字搜索' allowClear />, )} </FormItem> </Col> <Col span={8} align='right'> <Button type="primary" htmlType="submit"> 查询 </Button> <Button htmlType="reset" onClick={this.handleFormReset}> 重置 </Button> </Col> </Row> </Form> ); }; render() { const { ruleList, loading,location: { query: {biz}, }, } = this.props; const { allTypes, scan, } = this.state; const columns = [ { title: 'ID', dataIndex: 'id', }, { title: '子场景', dataIndex: 'bizSubTypeName', }, { title: '规则名称', dataIndex: 'name', }, { title: '规则版本', dataIndex: 'version', }, { title: '规则状态', dataIndex: 'state', render: text => { return text && text.desc ? text.desc : ''; }, }, { title: '命中总量', dataIndex:'evalInfo.hitCount', }, { title: '已评估量', key: 'total', dataIndex: 'evalInfo', render: el => el.checkSuccCount+el.checkFailCount }, { title: '正确量', dataIndex: 'evalInfo.checkSuccCount', }, { title: '错误量', dataIndex: 'evalInfo.checkFailCount', }, { title: '用户', dataIndex: 'updateUser', }, { title: '更新时间', dataIndex: 'updateTime', }, { title: '运行状态', dataIndex: 'runInfo', width: 160, render: (runInfo,record)=> this.ddd(record.id) }, { title: '操作', width: '150px', render: record => ( <div> <Link to={`/dataMarking/${bizId[biz*1]}/ruleHitList/${record.id}/${biz}?version=${record.version}`}>评估</Link> <Divider type="vertical" /> <Link to={`/dataMarking/${bizId[biz*1]}/rule/edit/${record.id}?biz=${biz}`}>编辑</Link> <br /> { [3,4].indexOf(scan.filter(m=>m.id===record.id)[0]?.status)===-1? <span>手动扫描</span>: <a onClick={()=>{ clearInterval(this.timer); request(`/api/data_marking/biz/${biz}/db-column-tag-rule/${record.id}/run-state-wait-run`, { method: 'POST', credentials: 'same-origin', }).then(resp => { if (resp && resp.success) { let newData=scan.map(n=>(n.id===record.id?{id:n.id,status:1}:n)); this.setState({scan:newData}); let runData=newData.filter(m=>[3,4].indexOf(m.status)===-1); this.timer = setInterval(()=> { console.log("Promise",runData) Promise.all( runData.map((run)=>{ return request(`/api/data_marking/biz/${biz}/db-column-tag-rule/${run.id}/run-state`, { credentials: 'same-origin', }).then(r=>({id:run.id,status:r.data.ruleRunState.id})) }) ).then((val)=>{ const oId=val.map(v=>v.id); newData=newData.map(j=>(oId.indexOf(j.id)>-1?{id:j.id,status:val[oId.indexOf(j.id)].status}:j)); runData=val.filter(m=>[3,4].indexOf(m.status)===-1); console.log("8989",runData,oId) this.setState({scan:newData}); if(!runData.length){ clearInterval(this.timer); } }) },1200); } else { message.error(`[请求失败]${JSON.stringify(resp.data)}`); } }); }} > 手动扫描 </a> } <Divider type="vertical" /> <Popconfirm title="是否删除?" onConfirm={() => this.deleteRuleHandler(record.id)}> <a>删除</a> </Popconfirm> </div> ), }, ]; const { data, page, total, pageSize } = ruleList; return ( <Card bordered={false} title="规则列表" > { this.searchForm() } <Table columns={columns} dataSource={data} rowKey="id" loading={loading} pagination={{ showSizeChanger: true, current: page, pageSize, total, }} footer={() => { return ( <tr className="ant-table-row ant-table-row-level-0"> <td>记录数: {total} </td> </tr> ); }} onChange={this.handleTableChange} /> </Card> ); } } export default RuleList;

浙公网安备 33010602011771号