完善部分信息的显示

This commit is contained in:
zhl 2023-04-19 19:44:55 +08:00
parent 2facd8f67a
commit 975969a1b9
4 changed files with 302 additions and 73 deletions

121
assets/css/main.css Normal file
View File

@ -0,0 +1,121 @@
.small-address {
font-size: 0.8rem;
}
.loader {
background: #00000035;
background: radial-gradient(#22222282, #00000059);
bottom: 0;
left: 0;
overflow: hidden;
position: fixed;
right: 0;
top: 0;
z-index: 99999;
}
.loader-inner {
bottom: 0;
height: 60px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-tip {
bottom: 0;
height: 60px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
display: flex;
justify-content: center;
}
.loader-tip .msg {
color: white;
line-height: 216px;
text-shadow: 1px 1px #000;
}
.loader-line-wrap {
animation: spin 2000ms cubic-bezier(0.175, 0.885, 0.32, 1.275) infinite;
box-sizing: border-box;
height: 50px;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
transform-origin: 50% 100%;
width: 100px;
}
.loader-line {
border: 4px solid transparent;
border-radius: 100%;
box-sizing: border-box;
height: 100px;
left: 0;
margin: 0 auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap:nth-child(1) {
animation-delay: -50ms;
}
.loader-line-wrap:nth-child(2) {
animation-delay: -100ms;
}
.loader-line-wrap:nth-child(3) {
animation-delay: -150ms;
}
.loader-line-wrap:nth-child(4) {
animation-delay: -200ms;
}
.loader-line-wrap:nth-child(5) {
animation-delay: -250ms;
}
.loader-line-wrap:nth-child(1) .loader-line {
border-color: hsl(0, 80%, 60%);
height: 90px;
width: 90px;
top: 7px;
}
.loader-line-wrap:nth-child(2) .loader-line {
border-color: hsl(60, 80%, 60%);
height: 76px;
width: 76px;
top: 14px;
}
.loader-line-wrap:nth-child(3) .loader-line {
border-color: hsl(120, 80%, 60%);
height: 62px;
width: 62px;
top: 21px;
}
.loader-line-wrap:nth-child(4) .loader-line {
border-color: hsl(180, 80%, 60%);
height: 48px;
width: 48px;
top: 28px;
}
.loader-line-wrap:nth-child(5) .loader-line {
border-color: hsl(240, 80%, 60%);
height: 34px;
width: 34px;
top: 35px;
}
@keyframes spin {
0%,
15% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}

View File

@ -11,17 +11,7 @@ const DEFAULT_CHAIN_DATA = {
symbol: "MATIC",
explorerurl: "https://mumbai.polygonscan.com/",
};
const loader = document.getElementById("loader");
// 显示加载动画
function showLoading() {
// add style display: block
loader.style.display = "block";
}
// 隐藏加载动画
function hideLoading() {
// add style display: none
loader.style.display = "none";
}
async function loadJson(url) {
return fetch(url).then((response) => response.json());
}
@ -83,25 +73,62 @@ createApp({
contract: null,
wallet: null,
disabled: false,
loading: false,
loadingMask: false,
showCancel: false,
showConfirm: false,
loadingTxt: "加载中",
chainId: 0,
hasPermission: false, // 当前用户是否有权限执行confirm
alertShow: false,
alertMsg: "",
alertType: "success",
};
},
async created() {
let params = getAllParameter();
this.id = params.id;
console.log("taskid: ", this.id);
let result = await fetchTaskInfo(this.id);
this.task = result.chainTask;
this.subTasks = result.requestTasks;
this.address = result.address;
this.types = result.types;
console.log(result);
await this.initWallet();
this.loading = true;
try {
let params = getAllParameter();
this.id = params.id;
console.log("taskid: ", this.id);
let result = await fetchTaskInfo(this.id);
this.task = result.chainTask;
this.subTasks = result.requestTasks;
this.address = result.address;
this.types = result.types;
console.log(result);
await this.initWallet();
} catch (err) {
this.alert("加载数据失败", "danger", true);
}
this.loading = false;
},
methods: {
alert(msg, type, autoClose = false) {
this.alertMsg = msg;
this.alertType = type;
this.alertShow = true;
if (autoClose) {
setTimeout(() => {
this.closeAlert();
}, 3000);
}
},
closeAlert() {
this.alertShow = false;
},
showType(type) {
return this.types[type];
},
// 显示加载动画
showLoadingMask(txt) {
this.loadingTxt = txt || "加载中";
this.loadingMask = true;
},
// 隐藏加载动画
hideLoadingMask() {
this.loadingMask = false;
},
async initInstance(user, address, jsonUrl) {
let json = await loadJson(jsonUrl);
return new this.web3.eth.Contract(json.abi, address, { from: user });
@ -121,46 +148,116 @@ createApp({
this.chainId = await this.web3.eth.getChainId();
this.walletConnect = true;
console.log(this.chainId, this.account);
console.log(this.contract);
await this.refreshData();
},
async refreshData() {
let hasRole = await this.checkRole();
console.log("has role: ", hasRole);
let cando = true;
let canCancel = false;
for (let sub of this.subTasks) {
let status = await this.querySchedule(sub.scheduleId);
console.log("task status: ", status);
sub.taskExists = status[0]; // 任务是否在链上存在
sub.executed = status[1]; // 是否已经执行了
sub.confirmed = status[2]; // 是否已经满足多签条件
sub.selfConfirm = status[3]; // 当前用户是否已经确认
let statusArr = [];
if (!sub.taskExists) {
cando = false;
statusArr.push(["任务未上链", "danger"]);
}
if (sub.selfConfirm) {
cando = false;
statusArr.push(["已确认", "danger"]);
}
if (sub.confirmed) {
cando = false;
statusArr.push(["已满足条件", "danger"]);
}
if (sub.executed) {
cando = false;
statusArr.push(["已执行", "danger"]);
}
if (sub.selfConfirm && !sub.executed) {
canCancel = true;
}
if (statusArr.length === 0 && cando) {
statusArr.push(["可操作", "info"]);
}
sub.statusArr = statusArr;
}
this.showCancel = canCancel;
this.showConfirm = cando;
},
async checkRole() {
let roleConfirm = await this.contract.methods.CONFIRM_ROLE().call();
let result = await this.contract.methods
.hasRole(roleConfirm, this.account)
.call();
return result;
},
makeBatchRequest(calls, callFrom) {
let batch = new this.web3.BatchRequest();
let promises = calls.map((call) => {
return new Promise((resolve, reject) => {
let request = call.request({ from: callFrom }, (error, data) => {
if (error) {
reject(error);
} else {
resolve(data);
}
});
batch.add(request);
});
});
batch.execute();
return Promise.all(promises);
},
async confirmTask() {
let ids = this.subTasks.map((o) => o.scheduleId);
console.log("confirm task", ids);
showLoading();
this.showLoadingMask("处理上链请求");
try {
let gas = await this.contract.methods
.confirmTransaction(ids)
.estimateGas();
gas = gas | 0;
await this.contract.methods.confirmTransaction(ids).send({ gas });
await this.refreshData();
} catch (err) {
console.log("error confirm task", err);
}
hideLoading();
this.hideLoadingMask();
},
async rejectTask() {
console.log("reject task");
let ids = this.subTasks.map((o) => o.scheduleId);
showLoading();
this.showLoadingMask("撤销确认信息");
try {
let gas = await this.contract.methods
.revokeConfirmation(ids)
.estimateGas();
gas = gas | 0;
await this.contract.methods.revokeConfirmation(ids).send({ gas });
await this.refreshData();
} catch (err) {
console.log("error confirm task", err);
}
hideLoading();
this.hideLoadingMask();
},
async querySchedule(id) {
let instance = wallet.contract;
return makeBatchRequest([
instance.methods.isOperation(id).call,
instance.methods.isOperationPending(id).call,
instance.methods.isOperationReady(id).call,
instance.methods.isOperationDone(id).call,
instance.methods.isConfirmed(id).call,
let instance = this.contract;
return this.makeBatchRequest([
instance.methods.isOperation(id).call, //id是否在合约里
// instance.methods.isOperationPending(id).call, // 任务是否在等待执行
// instance.methods.isOperationReady(id).call, // 任务是否已经准备好, 但未执行
instance.methods.isOperationDone(id).call, // 任务是否已经执行
instance.methods.isConfirmed(id).call, // 任务是否已经已经满足多签的条件
instance.methods.confirmations(id, this.account).call, //当前用户是否已经确认
instance.methods.required().call, //多签的最小确认数
instance.methods.getTimestamp(id).call,
]);
},

View File

@ -1,12 +1,12 @@
(function() {
var params = getAllParameter()
console.log(params)
console.log(location)
var next = `confirm.html?id=${params.id}`
if (isMobile()) {
var url = `https://metamask.app.link/dapp/${location.host}/ct/${next}`
document.getElementById('href').setAttribute('href', url)
} else {
// location.href = url
}
})()
(function () {
var params = getAllParameter();
console.log(params);
console.log(location);
var next = `confirm.html?id=${params.id}`;
if (isMobile()) {
var url = `https://metamask.app.link/dapp/xwork.kingsome.cn/pages/${next}`;
document.getElementById("href").setAttribute("href", url);
} else {
location.href = url;
}
})();

View File

@ -24,15 +24,15 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<style>
.small-address{
font-size: 0.8rem;
}
</style>
<link rel="stylesheet" type="text/css" href="assets/css/main.css"/>
</head>
<body>
<div id="app" class="container">
<div class="alert alert-dismissible fixed-top" :class="'alert-'+alertType" role="alert" v-if="alertShow">
<div>{{alertMsg}}</div>
<button type="button" class="btn-close" @click="closeAlert" aria-label="Close"></button>
</div>
<div class="page-header">
<h1>
{{task.name}} - <small>{{task.starterName}}</small>
@ -45,28 +45,35 @@
<button type="button" class="btn btn-info" @click="initWallet">连接钱包</button>
<div class="vr"></div>
</template>
<button type="button" class="btn btn-primary" :disabled="disabled" @click="confirmTask">确认</button>
<button type="button" class="btn btn-primary" v-if="showConfirm" @click="confirmTask">确认</button>
<div class="vr"></div>
<button type="button" class="btn btn-danger" :disabled="disabled">拒绝</button>
<button type="button" class="btn btn-danger" v-if="showCancel" @click="rejectTask">取消</button>
</div>
<div class="row">
<div class="col-md-12">
<div class="accordion" id="accordionExample">
<div class="accordion-item" v-for="(item, i) in subTasks" >
<h2 class="accordion-header" id="heading{{i}}">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{i}}" aria-expanded="true" aria-controls="collapse{{i}}">
任务{{item.index}}: {{item.reqDatas.length}}个子任务
<h2 class="accordion-header" :id="'heading'+i">
<button class="accordion-button" type="button" data-bs-toggle="collapse" :data-bs-target="'#collapse'+i" aria-expanded="true" :aria-controls="'collapse'+i">
任务数{{item.index}}: {{item.reqDatas.length}}
<div class="spinner-border" role="status" v-if="loading">
<span class="visually-hidden">Loading...</span>
</div>
<template v-for="sub in item.statusArr">
<span class="badge" :class="'text-bg-'+sub[1]">{{sub[0]}}</span>
</template>
</button>
</h2>
<div id="collapse{{i}}" class="accordion-collapse collapse show" aria-labelledby="heading{{i}}" data-bs-parent="#accordionExample">
<div :id="'collapse'+i" class="accordion-collapse collapse show" :aria-labelledby="'heading'+i" data-bs-parent="#accordionExample">
<div class="accordion-body">
<div v-for="sub in item.reqDatas" class="border-bottom">
<p><label class="text-secondary">类型:</label> {{showType(sub.type)}}</p>
<p class="small-address"><label class="text-secondary">合约地址: </label>{{sub.address}}</p>
<p class="small-address" v-if="sub.from"><label class="text-secondary">转出钱包: </label>{{sub.from}}</p>
<p class="small-address"><label class="text-secondary">目标钱包: </label>{{sub.to}}</p>
<p v-if="sub.amount"><label class="text-secondary">数量: </label>{{sub.amount}}</p>
<p v-if="sub.tokenId"><label class="text-secondary">NFT ID: </label>{{sub.tokenId}}</p>
<p v-if="sub.tokenid || sub.tokenId"><label class="text-secondary">NFT ID: </label>{{sub.tokenId || sub.tokenid}}</p>
</div>
</div>
</div>
@ -74,26 +81,30 @@
</div>
</div>
</div>
</div>
<div class="loader" id="loader">
<div class="loader-inner">
<div class="loader-line-wrap">
<div class="loader-line"></div>
<div class="loader" id="loader" v-if="loadingMask">
<div class="loader-inner">
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
<div class="loader-tip">
<div class="msg">{{loadingTxt}}</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/vconsole@3.15.0/dist/vconsole.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/web3@1.9.0/dist/web3.min.js"></script>