web3 React Dapp书写订单 买入/取消操作

好 上文web3 前端dapp从redux过滤出 (我创建与别人创建)正在执行的订单 并展示在Table上中 我们过滤出了 我创建的 与 别人创建的 且 未完成 未取消的订单数据
这边 我们起一下 ganache 环境

ganache -d

web3 React Dapp书写订单 买入/取消操作_第1张图片
然后 我们项目 发布一下智能合约

truffle migrate --reset

web3 React Dapp书写订单 买入/取消操作_第2张图片
然后 登录一下 MetaMask
web3 React Dapp书写订单 买入/取消操作_第3张图片
在 运行一下测试脚本

truffle exec .\scripts\test.js

然后 打开我们的项目 在根目录下的 scripts 目录中 创建一个文件 我这里叫 createOrder.js
编写代码如下

//指定以token grtoken合约
const GrToken = artifacts.require("grToken.sol")
//交易所合约
const Exchange = artifacts.require("Exchange.sol")
//定义E代理地址
const ETHER_ADDRESS = '0x0000000000000000000000000000000000000000';

const toWei = (bn) => {
    return web3.utils.toWei(bn.toString(), "ether");
}

module.exports = async function(callback) {
    const grTokenDai = await GrToken.deployed();
    const exchage = await Exchange.deployed();
    //获取用户列表
    const accounts = await web3.eth.getAccounts();
    //循环用 accounts 用户列表中第一个用户创建 五个订单
    for (let i = 1; i <= 5; i++) {
        await exchage.makeOrder(grTokenDai.address,toWei(101), ETHER_ADDRESS ,toWei(0.01),{
            from: accounts[0]
        });
    }
    //循环用 accounts 用户列表中第二个用户创建 五个订单
    for (let i = 1; i <= 5; i++) {
        await exchage.makeOrder(grTokenDai.address,toWei(101), ETHER_ADDRESS ,toWei(0.01),{
            from: accounts[1]
        });
    }
    callback()
}

这里 我们直接脚本执行 第一和第二个用户 分别创建出 五个订单 方便 我们后期操作
然后 我们终端运行

truffle exec .\scripts\createOrder.js

web3 React Dapp书写订单 买入/取消操作_第4张图片
然后 启动我们的dapp
这里 我们第一个用户 已经可用看到非常多订单信息了
web3 React Dapp书写订单 买入/取消操作_第5张图片
然后 我们 MetaMask 切换一下当前账户
web3 React Dapp书写订单 买入/取消操作_第6张图片
我们切换成第二个用户
然后刷新dapp
web3 React Dapp书写订单 买入/取消操作_第7张图片
也是能看到自己的订单和第一个用户创建的订单

然后 我们将 src目录下的 components 下的 Order.jsx 组件代码更改如下

import React from 'react';
import { Card, Col, Row ,Table,Button } from 'antd';
import {useSelector} from "react-redux"
import moment from "moment"

function converTime(t){
  return moment(t*1000).format("YYYY/MM/DD")
}

function convert(unit) {
  return window.WebData ? unit&&window.WebData.web3.utils.fromWei(unit, "ether") : ""
}

function getRenderOrder(order,type) {
  if(!window.WebData) {
    return []
  }
  const account = window.WebData.account
  //收集起所有 已完成 或 已取消的数据id
  let filterIds = [...order.Cancelorders,...order.Fillorders].map(item=>item.id)
  let makeorders = order.Allorders.filter(item=> !filterIds.includes(item.id))
  if (type === 1) {
    return makeorders.filter(item=>item.user === account)
  } else {
    return makeorders.filter(item=>item.user !== account)
  }
}

export default function Order() {
  const order = useSelector(state => state.order)
  
  const columns = [
    {
      title: 'ETH',
      dataIndex: 'amountGive',
      render:(amountGive)=><b>{ convert(amountGive) }</b>,
      key: 'amountGive'
    },
    {
      title: 'GrToken',
      dataIndex: 'amountGet',
      render:(amountGet)=><b>{ convert(amountGet) }</b>,
      key: 'amountGet'
    },
    {
      title: '创建时间',
      dataIndex: 'timestamp',
      render:(timestamp)=><div>{ converTime(timestamp) }</div>,
      key: 'timestamp'
    },
  ];

  const columns1 = [
    ...columns,
    {
      title: '操作',
      render:(item)=><Button type = "text">取消</Button>
    }
  ]

  const columns2 = [
    ...columns,
    {
      title: '操作',
      render:(item)=><Button type = "text">买入</Button>
    }
  ]
  
  return (
    <div style = {{marginTop:'10px'}}>
      <Row>
         <Col span={8}>
          <Card title="已完成" bordered={false} style = {{ margin: '10px' }}>
            <Table dataSource={order.Fillorders} columns={columns} rowKey={item=> item.id}/>
          </Card>
         </Col>
         <Col span={8}>
          <Card title="我创建的" bordered={false} style = {{ margin: '10px' }}>
            <Table dataSource={getRenderOrder(order,1)} columns={columns1} rowKey={item=> item.id}/>
          </Card>
         </Col>
         <Col span={8}>
          <Card title="其他交易中订单" bordered={false} style = {{ margin: '10px' }}>
            <Table dataSource={getRenderOrder(order,2)} columns={columns2} rowKey={item=> item.id}/>
          </Card>
         </Col>
      </Row>
    </div>
  );
}

这里 我们引入了 Button 按钮
然后 重新加了 两个 表头数据 columns1 和 columns2
他们都合并了 columns 原本的数据结果 然后多加了一列 叫操作 对应一个Button按钮
我创建的 叫取消
另一个叫 买入 买入别人创建的订单

然后 这里 我们先找到 antd 文档中的 对话框
web3 React Dapp书写订单 买入/取消操作_第8张图片
首先 这里 我们需要 从react中引入 useState 然后从antd中 引入 Modal对话框组件
web3 React Dapp书写订单 买入/取消操作_第9张图片
然后 定义一下 对话框开关 和当前操作的订单id 以及逻辑函数

//控制对话框的 布尔值
const [isModalOpen, setIsModalOpen] = useState(false);
//记录当前正在操作的订单id
const [currentId, setCurrentId] = useState(null);

//点击取消订单时触发
const triggerCancellation = (id) => {
  setIsModalOpen(true);
  setCurrentId(id);
}
//对话框点击 确定 时触发
const handleOk = () => {
  setIsModalOpen(false);
};
//取消 或 关闭 对话框时触发
const handleCancel = () => {
  setIsModalOpen(false);
};

web3 React Dapp书写订单 买入/取消操作_第10张图片
然后 在元素中写出这个Modal对话框组件
web3 React Dapp书写订单 买入/取消操作_第11张图片
最后 在取消订单的按钮 绑定上 onClick 开启对话框函数
web3 React Dapp书写订单 买入/取消操作_第12张图片
item.id 表示 我们调用函数时 将当前订单的id 传进来
然后 我们运行项目 点击取消订单
对话框 就弹出来了
web3 React Dapp书写订单 买入/取消操作_第13张图片
至于取消订单的具体逻辑 我们直接来看交易所代码 我们之前写了个cancelorder函数 用来取消订单 它只需要一个参数 订单的id 然后其他的具体逻辑 我们会自己调事件的
web3 React Dapp书写订单 买入/取消操作_第14张图片
这里 我们先换回第一个账号吧
web3 React Dapp书写订单 买入/取消操作_第15张图片
然后 我们将刚才在 src下 components 下的 Order.jsx中 的 handleOk编写代码如下

//对话框点击 确定 时触发
 const handleOk = () => {
   const {
     account,
     Exchange
   } = window.WebData;
   Exchange.methods.cancelorder(currentId).send({from: account})
   setIsModalOpen(false);
 };

这里 我们函数也写了注释了 他是只有用户点击确认之后才触发的 就表示 用户已经确定 要取消这个订单了
然后 我们通过我们存在window上的 WebData对象 拿到 交易所智能合约Exchange对象 和 account当前登录用户
然后通过Exchange 调用我们自己写的 取消订单 cancelorder函数 传入 我们之前存起来的 当前订单id currentId 然后 指定 send 因为 我们这个操作是要上链的
然后 我们传入当前用户为from 字段
然后 我们运行代码 点击取消订单
web3 React Dapp书写订单 买入/取消操作_第16张图片
然后点击确定
web3 React Dapp书写订单 买入/取消操作_第17张图片
然后 页面右侧 就会弹出这个操作提示按钮 因为这设计到了 燃料操作
web3 React Dapp书写订单 买入/取消操作_第18张图片
我们直接点击确认
web3 React Dapp书写订单 买入/取消操作_第19张图片
一路确认 最后完成之后 我们的数据并不会自动更新 因为我们没有订阅 但是 当你手动刷新界面 会发现 我们取消的那条 3ETH 的订单就没有了 因为已经被取消掉了
web3 React Dapp书写订单 买入/取消操作_第20张图片
然后 我们也可以看MetaMask下面这个活动 会将你取消订单的动作记录下来
web3 React Dapp书写订单 买入/取消操作_第21张图片
这样 就确认了 我们取消订单的功能 确实是好用的 然后 我们来看买入
我们先加上 逻辑层的一些控制对话框代码

//控制买入弹出开启
const [buy, setBuy] = useState(false);
//取消 或 关闭 对话框时触发
const buyCancel = () => {
  setBuy(false);
};
//对话框点击 确定 时触发
const buyleOk = () => {
  setIsModalOpen(false);
};
//点击买入订单时触发
const startBuying = (id) => {
  setBuy(true);
  setCurrentId(id);
}

web3 React Dapp书写订单 买入/取消操作_第22张图片
然后 我们在元素层 加上 买入确定的对话框
web3 React Dapp书写订单 买入/取消操作_第23张图片
这样 我们点击买入 提示弹窗就出来了
web3 React Dapp书写订单 买入/取消操作_第24张图片
然后 我们交易所中 也写了一个 fillorder 函数 他也是 只需要一个参数id
通过id完成订单买入
web3 React Dapp书写订单 买入/取消操作_第25张图片
这样 我们直接将 刚才写的 buyleOk 函数 改成这样就好了

//对话框点击 确定 时触发
const buyleOk = () => {
  const {
    account,
    Exchange
  } = window.WebData;
  Exchange.methods.fillorder(currentId).send({from: account})
  setBuy(false);
};

逻辑还是跟取消订单差不多 用户确定之后 从我们挂在 window上的WebData 对象中 结构出 当前用户和交易所合约对象
然后 我们通过交易所对象 调用fillorder函数 传入当前操作订单的id
他也会改变链上结构 要用send
当前用户为from字段

然后 我们运行代码
然后 我们记好 自己 ETH的数量 因为我们的grtoken存在燃料的概念 所以 可能有点额外扣除 我们就看ETH
然后 我们点击买入
web3 React Dapp书写订单 买入/取消操作_第26张图片
然后我们选择确定
web3 React Dapp书写订单 买入/取消操作_第27张图片
然后 界面右侧 会弹出操作提示 这里 我们点击确定
web3 React Dapp书写订单 买入/取消操作_第28张图片
因为没有订阅 所以 我们界面并不会自动更新 但我们刷新界面 我们看三个点
ETH 加了 0.01 然后 我们完成的订单多了一条 别人的订单 少了一条
web3 React Dapp书写订单 买入/取消操作_第29张图片
这就说明 我们操作成功了

最后 我们订单组件的代码是这样

import React, { useState } from 'react';

import { Card, Col, Row ,Table,Button, Modal } from 'antd';
import {useSelector} from "react-redux"
import moment from "moment"

function converTime(t){
  return moment(t*1000).format("YYYY/MM/DD")
}

function convert(unit) {
  return window.WebData ? unit&&window.WebData.web3.utils.fromWei(unit, "ether") : ""
}

function getRenderOrder(order,type) {
  if(!window.WebData) {
    return []
  }
  const account = window.WebData.account
  //收集起所有 已完成 或 已取消的数据id
  let filterIds = [...order.Cancelorders,...order.Fillorders].map(item=>item.id)
  let makeorders = order.Allorders.filter(item=> !filterIds.includes(item.id))
  if (type === 1) {
    return makeorders.filter(item=>item.user === account)
  } else {
    return makeorders.filter(item=>item.user !== account)
  }
}

export default function Order() {
  //控制对话框的 布尔值
  const [isModalOpen, setIsModalOpen] = useState(false);
  //记录当前正在操作的订单id
  const [currentId, setCurrentId] = useState(null);

  //点击取消订单时触发
  const triggerCancellation = (id) => {
    setIsModalOpen(true);
    setCurrentId(id);
  }
  //对话框点击 确定 时触发
  const handleOk = () => {
    const {
      account,
      Exchange
    } = window.WebData;
    Exchange.methods.cancelorder(currentId).send({from: account})
    setIsModalOpen(false);
  };
  //取消 或 关闭 对话框时触发
  const handleCancel = () => {
    setIsModalOpen(false);
  };
  
  //控制买入弹出开启
  const [buy, setBuy] = useState(false);
  //取消 或 关闭 对话框时触发
  const buyCancel = () => {
    setBuy(false);
  };
  //对话框点击 确定 时触发
  const buyleOk = () => {
    const {
      account,
      Exchange
    } = window.WebData;
    Exchange.methods.fillorder(currentId).send({from: account})
    setBuy(false);
  };
  //点击买入订单时触发
  const startBuying = (id) => {
    setBuy(true);
    setCurrentId(id);
  }


  const order = useSelector(state => state.order)
  
  const columns = [
    {
      title: 'ETH',
      dataIndex: 'amountGive',
      render:(amountGive)=><b>{ convert(amountGive) }</b>,
      key: 'amountGive'
    },
    {
      title: 'GrToken',
      dataIndex: 'amountGet',
      render:(amountGet)=><b>{ convert(amountGet) }</b>,
      key: 'amountGet'
    },
    {
      title: '创建时间',
      dataIndex: 'timestamp',
      render:(timestamp)=><div>{ converTime(timestamp) }</div>,
      key: 'timestamp'
    },
  ];

  const columns1 = [
    ...columns,
    {
      title: '操作',
      render:(item)=><Button type = "text" onClick={()=>{triggerCancellation(item.id)}}>取消</Button>
    }
  ]

  const columns2 = [
    ...columns,
    {
      title: '操作',
      render:(item)=><Button type = "text" onClick={()=>{startBuying(item.id)}}>买入</Button>
    }
  ]
  
  return (
    <div style = {{marginTop:'10px'}}>
      <Row>
         <Col span={8}>
          <Card title="已完成" bordered={false} style = {{ margin: '10px' }}>
            <Table dataSource={order.Fillorders} columns={columns} rowKey={item=> item.id}/>
          </Card>
         </Col>
         <Col span={8}>
          <Card title="我创建的" bordered={false} style = {{ margin: '10px' }}>
            <Table dataSource={getRenderOrder(order,1)} columns={columns1} rowKey={item=> item.id}/>
          </Card>
         </Col>
         <Col span={8}>
          <Card title="其他交易中订单" bordered={false} style = {{ margin: '10px' }}>
            <Table dataSource={getRenderOrder(order,2)} columns={columns2} rowKey={item=> item.id}/>
          </Card>
         </Col>
      </Row>
      <Modal
        title="操作提示"
        open={isModalOpen}
        okText="确定"
        cancelText="取消"
        onOk={handleOk}
        onCancel={handleCancel}
      >
        <p>您确定要取消当前订单吗?</p>
      </Modal>
      <Modal
        title="操作提示"
        open={buy}
        okText="确定"
        cancelText="取消"
        onOk={buyleOk}
        onCancel={buyCancel}
      >
        <p>您确认要买入当前订单吗?</p>
      </Modal>
    </div>
  );
}

但是 目前体验比较差 因为我们操作完成 不会自动更新 需要手动刷新界面数据才会更新
因为 我们需要对这些事件进行订阅
那么 我们下文继续

你可能感兴趣的:(web3,react.js,前端)