From 975969a1b9f1998be99316b941877f9486fc6a18 Mon Sep 17 00:00:00 2001 From: zhl Date: Wed, 19 Apr 2023 19:44:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=83=A8=E5=88=86=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E7=9A=84=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/css/main.css | 121 +++++++++++++++++++++++++++ assets/scripts/confirm.js | 163 +++++++++++++++++++++++++++++-------- assets/scripts/redirect.js | 24 +++--- confirm.html | 67 ++++++++------- 4 files changed, 302 insertions(+), 73 deletions(-) create mode 100644 assets/css/main.css diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..37af17e --- /dev/null +++ b/assets/css/main.css @@ -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); + } +} diff --git a/assets/scripts/confirm.js b/assets/scripts/confirm.js index 28832d1..bea2d5e 100644 --- a/assets/scripts/confirm.js +++ b/assets/scripts/confirm.js @@ -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, ]); }, diff --git a/assets/scripts/redirect.js b/assets/scripts/redirect.js index 856cb4b..182783b 100644 --- a/assets/scripts/redirect.js +++ b/assets/scripts/redirect.js @@ -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 - } -})() \ No newline at end of file +(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; + } +})(); diff --git a/confirm.html b/confirm.html index 92871fc..80488b8 100644 --- a/confirm.html +++ b/confirm.html @@ -24,15 +24,15 @@ - +
+
-

-

-
+

{{showType(sub.type)}}

{{sub.address}}

+

{{sub.from}}

{{sub.to}}

{{sub.amount}}

-

{{sub.tokenId}}

+

{{sub.tokenId || sub.tokenid}}

@@ -74,26 +81,30 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
{{loadingTxt}}
+