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>&nbsp;&nbsp;
            <Button htmlType="reset" onClick={this.handleFormReset}>
              重置
            </Button>&nbsp;&nbsp;
          </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;

 

posted @ 2022-09-15 14:57  荷风伊夏  阅读(553)  评论(0编辑  收藏  举报