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

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

这边 我们起一下 ganache 环境

javascript 复制代码
ganache -d

然后 我们项目 发布一下智能合约

javascript 复制代码
truffle migrate --reset

然后 登录一下 MetaMask

在 运行一下测试脚本

javascript 复制代码
truffle exec .\scripts\test.js

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

编写代码如下

javascript 复制代码
//指定以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()
}

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

然后 我们终端运行

javascript 复制代码
truffle exec .\scripts\createOrder.js

然后 启动我们的dapp

这里 我们第一个用户 已经可用看到非常多订单信息了

然后 我们 MetaMask 切换一下当前账户

我们切换成第二个用户

然后刷新dapp

也是能看到自己的订单和第一个用户创建的订单

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

javascript 复制代码
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 文档中的 对话框

首先 这里 我们需要 从react中引入 useState 然后从antd中 引入 Modal对话框组件

然后 定义一下 对话框开关 和当前操作的订单id 以及逻辑函数

javascript 复制代码
//控制对话框的 布尔值
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);
};

然后 在元素中写出这个Modal对话框组件

最后 在取消订单的按钮 绑定上 onClick 开启对话框函数

item.id 表示 我们调用函数时 将当前订单的id 传进来

然后 我们运行项目 点击取消订单

对话框 就弹出来了

至于取消订单的具体逻辑 我们直接来看交易所代码 我们之前写了个cancelorder函数 用来取消订单 它只需要一个参数 订单的id 然后其他的具体逻辑 我们会自己调事件的

这里 我们先换回第一个账号吧

然后 我们将刚才在 src下 components 下的 Order.jsx中 的 handleOk编写代码如下

javascript 复制代码
//对话框点击 确定 时触发
 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 字段

然后 我们运行代码 点击取消订单

然后点击确定

然后 页面右侧 就会弹出这个操作提示按钮 因为这设计到了 燃料操作

我们直接点击确认

一路确认 最后完成之后 我们的数据并不会自动更新 因为我们没有订阅 但是 当你手动刷新界面 会发现 我们取消的那条 3ETH 的订单就没有了 因为已经被取消掉了

然后 我们也可以看MetaMask下面这个活动 会将你取消订单的动作记录下来

这样 就确认了 我们取消订单的功能 确实是好用的 然后 我们来看买入

我们先加上 逻辑层的一些控制对话框代码

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

然后 我们在元素层 加上 买入确定的对话框

这样 我们点击买入 提示弹窗就出来了

然后 我们交易所中 也写了一个 fillorder 函数 他也是 只需要一个参数id

通过id完成订单买入

这样 我们直接将 刚才写的 buyleOk 函数 改成这样就好了

javascript 复制代码
//对话框点击 确定 时触发
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

然后 我们点击买入

然后我们选择确定

然后 界面右侧 会弹出操作提示 这里 我们点击确定

因为没有订阅 所以 我们界面并不会自动更新 但我们刷新界面 我们看三个点

当前用户 在交易所的 ETH 加了 0.01 然后 我们完成的订单多了一条 别人的订单 少了一条 还有就是 在交易所的 grToken 减少了

这就说明 我们操作成功了

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

typescript 复制代码
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>
  );
}

但是 目前体验比较差 因为我们操作完成 不会自动更新 需要手动刷新界面数据才会更新

因为 我们需要对这些事件进行订阅

那么 我们下文继续

相关推荐
bin91536 分钟前
前端JavaScript导出excel,并用excel分析数据,使用SheetJS导出excel
前端·javascript·excel
Rattenking14 分钟前
node - npm常用命令和package.json说明
前端·npm·json
Easonmax14 分钟前
【HTML5】html5开篇基础(1)
前端·html·html5
For. tomorrow18 分钟前
Vue3中el-table组件实现分页,多选以及回显
前端·vue.js·elementui
布瑞泽的童话1 小时前
无需切换平台?TuneFree如何搜罗所有你爱的音乐
前端·vue.js·后端·开源
白鹭凡1 小时前
react 甘特图之旅
前端·react.js·甘特图
打野赵怀真1 小时前
你有看过vue的nextTick源码吗?
前端·javascript
2401_862886781 小时前
蓝禾,汤臣倍健,三七互娱,得物,顺丰,快手,游卡,oppo,康冠科技,途游游戏,埃科光电25秋招内推
前端·c++·python·算法·游戏
书中自有妍如玉1 小时前
layui时间选择器选择周 日月季度年
前端·javascript·layui