feat: complete payment flow
This commit is contained in:
parent
367d837e2e
commit
ebe58b6d08
@ -1,8 +1,10 @@
|
|||||||
from flask import Flask, request, jsonify
|
from flask import Flask, request, jsonify
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import os
|
import os
|
||||||
|
from flask_cors import CORS
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
CORS(app)
|
||||||
|
|
||||||
DATABASE = './main.db'
|
DATABASE = './main.db'
|
||||||
|
|
||||||
@ -77,7 +79,7 @@ def get_order(id):
|
|||||||
for product in products:
|
for product in products:
|
||||||
ans['products'].append({
|
ans['products'].append({
|
||||||
'name': product[0],
|
'name': product[0],
|
||||||
'price': product[1],
|
'price': str(product[1]),
|
||||||
'count': product[2]
|
'count': product[2]
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -88,11 +90,11 @@ def get_order(id):
|
|||||||
'name': result[1],
|
'name': result[1],
|
||||||
'address': result[0]
|
'address': result[0]
|
||||||
}
|
}
|
||||||
ans['amount'] = result[2]
|
ans['amount'] = str(result[2])
|
||||||
|
|
||||||
return jsonify(ans)
|
return jsonify(ans)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
initDB()
|
initDB()
|
||||||
app.run()
|
app.run(host="0.0.0.0")
|
||||||
|
|||||||
@ -1,239 +1,257 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"internalType": "address",
|
"internalType": "address",
|
||||||
"name": "SBT_addr",
|
"name": "SBT_addr",
|
||||||
"type": "address"
|
"type": "address"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stateMutability": "nonpayable",
|
"stateMutability": "nonpayable",
|
||||||
"type": "constructor"
|
"type": "constructor"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"inputs": [],
|
"inputs": [],
|
||||||
"name": "owner",
|
"name": "owner",
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"internalType": "address",
|
"internalType": "address",
|
||||||
"name": "",
|
"name": "",
|
||||||
"type": "address"
|
"type": "address"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stateMutability": "view",
|
"stateMutability": "view",
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"constant": true
|
"constant": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"inputs": [],
|
"inputs": [],
|
||||||
"name": "recv",
|
"name": "recv",
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"internalType": "bool",
|
"internalType": "bool",
|
||||||
"name": "",
|
"name": "",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stateMutability": "view",
|
"stateMutability": "view",
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"constant": true
|
"constant": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"inputs": [],
|
"inputs": [],
|
||||||
"name": "sbt",
|
"name": "sbt",
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"internalType": "contract SoulboundToken",
|
"internalType": "contract SoulboundToken",
|
||||||
"name": "",
|
"name": "",
|
||||||
"type": "address"
|
"type": "address"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stateMutability": "view",
|
"stateMutability": "view",
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"constant": true
|
"constant": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"stateMutability": "payable",
|
"stateMutability": "payable",
|
||||||
"type": "receive",
|
"type": "receive",
|
||||||
"payable": true
|
"payable": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"internalType": "address",
|
"internalType": "address",
|
||||||
"name": "client",
|
"name": "client",
|
||||||
"type": "address"
|
"type": "address"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"internalType": "uint256",
|
"internalType": "uint256",
|
||||||
"name": "amount",
|
"name": "amount",
|
||||||
"type": "uint256"
|
"type": "uint256"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "setCredit",
|
"name": "setCredit",
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"stateMutability": "nonpayable",
|
"stateMutability": "nonpayable",
|
||||||
"type": "function"
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"internalType": "uint256",
|
"internalType": "uint256",
|
||||||
"name": "number",
|
"name": "number",
|
||||||
"type": "uint256"
|
"type": "uint256"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "register",
|
"name": "register",
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"stateMutability": "nonpayable",
|
"stateMutability": "nonpayable",
|
||||||
"type": "function"
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"internalType": "address",
|
"internalType": "uint256",
|
||||||
"name": "shop",
|
"name": "id",
|
||||||
"type": "address"
|
"type": "uint256"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"internalType": "uint256",
|
"internalType": "address",
|
||||||
"name": "amount",
|
"name": "shop",
|
||||||
"type": "uint256"
|
"type": "address"
|
||||||
}
|
},
|
||||||
],
|
{
|
||||||
"name": "pay",
|
"internalType": "uint256",
|
||||||
"outputs": [],
|
"name": "amount",
|
||||||
"stateMutability": "nonpayable",
|
"type": "uint256"
|
||||||
"type": "function"
|
}
|
||||||
},
|
],
|
||||||
{
|
"name": "pay",
|
||||||
"inputs": [],
|
"outputs": [],
|
||||||
"name": "repay",
|
"stateMutability": "nonpayable",
|
||||||
"outputs": [
|
"type": "function"
|
||||||
{
|
},
|
||||||
"internalType": "uint256",
|
{
|
||||||
"name": "",
|
"inputs": [],
|
||||||
"type": "uint256"
|
"name": "repay",
|
||||||
},
|
"outputs": [
|
||||||
{
|
{
|
||||||
"internalType": "uint256",
|
"internalType": "uint256",
|
||||||
"name": "",
|
"name": "",
|
||||||
"type": "uint256"
|
"type": "uint256"
|
||||||
}
|
},
|
||||||
],
|
{
|
||||||
"stateMutability": "payable",
|
"internalType": "uint256",
|
||||||
"type": "function",
|
"name": "",
|
||||||
"payable": true
|
"type": "uint256"
|
||||||
},
|
}
|
||||||
{
|
],
|
||||||
"inputs": [],
|
"stateMutability": "payable",
|
||||||
"name": "start_recv",
|
"type": "function",
|
||||||
"outputs": [],
|
"payable": true
|
||||||
"stateMutability": "nonpayable",
|
},
|
||||||
"type": "function"
|
{
|
||||||
},
|
"inputs": [
|
||||||
{
|
{
|
||||||
"inputs": [],
|
"internalType": "address",
|
||||||
"name": "stop_recv",
|
"name": "client",
|
||||||
"outputs": [],
|
"type": "address"
|
||||||
"stateMutability": "nonpayable",
|
}
|
||||||
"type": "function"
|
],
|
||||||
},
|
"name": "warning",
|
||||||
{
|
"outputs": [],
|
||||||
"inputs": [
|
"stateMutability": "nonpayable",
|
||||||
{
|
"type": "function"
|
||||||
"internalType": "address",
|
},
|
||||||
"name": "client",
|
{
|
||||||
"type": "address"
|
"inputs": [],
|
||||||
}
|
"name": "start_recv",
|
||||||
],
|
"outputs": [],
|
||||||
"name": "getCredit",
|
"stateMutability": "nonpayable",
|
||||||
"outputs": [
|
"type": "function"
|
||||||
{
|
},
|
||||||
"internalType": "uint256",
|
{
|
||||||
"name": "",
|
"inputs": [],
|
||||||
"type": "uint256"
|
"name": "stop_recv",
|
||||||
}
|
"outputs": [],
|
||||||
],
|
"stateMutability": "nonpayable",
|
||||||
"stateMutability": "view",
|
"type": "function"
|
||||||
"type": "function",
|
},
|
||||||
"constant": true
|
{
|
||||||
},
|
"inputs": [
|
||||||
{
|
{
|
||||||
"inputs": [
|
"internalType": "address",
|
||||||
{
|
"name": "client",
|
||||||
"internalType": "address",
|
"type": "address"
|
||||||
"name": "client",
|
}
|
||||||
"type": "address"
|
],
|
||||||
}
|
"name": "getCredit",
|
||||||
],
|
"outputs": [
|
||||||
"name": "getArrear",
|
{
|
||||||
"outputs": [
|
"internalType": "uint256",
|
||||||
{
|
"name": "",
|
||||||
"internalType": "uint256",
|
"type": "uint256"
|
||||||
"name": "",
|
}
|
||||||
"type": "uint256"
|
],
|
||||||
}
|
"stateMutability": "view",
|
||||||
],
|
"type": "function",
|
||||||
"stateMutability": "view",
|
"constant": true
|
||||||
"type": "function",
|
},
|
||||||
"constant": true
|
{
|
||||||
},
|
"inputs": [
|
||||||
{
|
{
|
||||||
"inputs": [
|
"internalType": "address",
|
||||||
{
|
"name": "client",
|
||||||
"internalType": "address",
|
"type": "address"
|
||||||
"name": "client",
|
}
|
||||||
"type": "address"
|
],
|
||||||
}
|
"name": "getArrear",
|
||||||
],
|
"outputs": [
|
||||||
"name": "getClientOrders",
|
{
|
||||||
"outputs": [
|
"internalType": "uint256",
|
||||||
{
|
"name": "",
|
||||||
"components": [
|
"type": "uint256"
|
||||||
{
|
}
|
||||||
"internalType": "bool",
|
],
|
||||||
"name": "isFinished",
|
"stateMutability": "view",
|
||||||
"type": "bool"
|
"type": "function",
|
||||||
},
|
"constant": true
|
||||||
{
|
},
|
||||||
"internalType": "uint256",
|
{
|
||||||
"name": "amount",
|
"inputs": [
|
||||||
"type": "uint256"
|
{
|
||||||
},
|
"internalType": "address",
|
||||||
{
|
"name": "client",
|
||||||
"internalType": "address",
|
"type": "address"
|
||||||
"name": "shop",
|
}
|
||||||
"type": "address"
|
],
|
||||||
}
|
"name": "getClientOrders",
|
||||||
],
|
"outputs": [
|
||||||
"internalType": "struct Order[]",
|
{
|
||||||
"name": "",
|
"components": [
|
||||||
"type": "tuple[]"
|
{
|
||||||
}
|
"internalType": "bool",
|
||||||
],
|
"name": "isFinished",
|
||||||
"stateMutability": "view",
|
"type": "bool"
|
||||||
"type": "function",
|
},
|
||||||
"constant": true
|
{
|
||||||
},
|
"internalType": "uint256",
|
||||||
{
|
"name": "amount",
|
||||||
"inputs": [
|
"type": "uint256"
|
||||||
{
|
},
|
||||||
"internalType": "address",
|
{
|
||||||
"name": "client",
|
"internalType": "address",
|
||||||
"type": "address"
|
"name": "shop",
|
||||||
}
|
"type": "address"
|
||||||
],
|
}
|
||||||
"name": "getSBTNumber",
|
],
|
||||||
"outputs": [
|
"internalType": "struct Order[]",
|
||||||
{
|
"name": "",
|
||||||
"internalType": "uint256",
|
"type": "tuple[]"
|
||||||
"name": "",
|
}
|
||||||
"type": "uint256"
|
],
|
||||||
}
|
"stateMutability": "view",
|
||||||
],
|
"type": "function",
|
||||||
"stateMutability": "view",
|
"constant": true
|
||||||
"type": "function",
|
},
|
||||||
"constant": true
|
{
|
||||||
}
|
"inputs": [
|
||||||
]
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "client",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "getSBTNumber",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function",
|
||||||
|
"constant": true
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -7,6 +7,7 @@ import ClientMainView from '../views/ClientMainView.vue'
|
|||||||
import ClientInfoView from '../views/ClientInfoView.vue'
|
import ClientInfoView from '../views/ClientInfoView.vue'
|
||||||
import ClientCreditView from '../views/ClientCreditView.vue'
|
import ClientCreditView from '../views/ClientCreditView.vue'
|
||||||
import ClientPayView from '../views/ClientPayView.vue'
|
import ClientPayView from '../views/ClientPayView.vue'
|
||||||
|
import PaymentView from '../views/PaymentView.vue'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
@ -51,6 +52,11 @@ const router = createRouter({
|
|||||||
name: 'clientpay',
|
name: 'clientpay',
|
||||||
component: ClientPayView
|
component: ClientPayView
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/client/pay/:id',
|
||||||
|
name: 'clientpayment',
|
||||||
|
component: PaymentView
|
||||||
|
},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
97
src/views/ClientPayView.vue
Normal file
97
src/views/ClientPayView.vue
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<script>
|
||||||
|
import Web3 from 'web3';
|
||||||
|
import SBT from '@/assets/SBT.json'
|
||||||
|
import Bank from '@/assets/Bank.json'
|
||||||
|
import PageTitle from '../components/PageTitle.vue'
|
||||||
|
import WarningModal from '../components/WarningModal.vue'
|
||||||
|
import SuccessModal from '../components/SuccessModal.vue'
|
||||||
|
import ClientNav from '../components/ClientNav.vue'
|
||||||
|
|
||||||
|
// To use Html5QrcodeScanner (more info below)
|
||||||
|
import { Html5QrcodeScanner } from "html5-qrcode";
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { PageTitle, WarningModal, SuccessModal, ClientNav },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
SBTAddress: import.meta.env.VITE_SBT_ADDR,
|
||||||
|
BankAddress: import.meta.env.VITE_BANK_ADDR,
|
||||||
|
clientAddr: '',
|
||||||
|
web3: null,
|
||||||
|
token: null,
|
||||||
|
bank: null,
|
||||||
|
picName: '',
|
||||||
|
pic: '',
|
||||||
|
credit: '',
|
||||||
|
arrear: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
// if (!this.$cookies.isKey('linked')) {
|
||||||
|
// this.$router.push('/')
|
||||||
|
// }
|
||||||
|
this.web3 = new Web3(window.ethereum)
|
||||||
|
this.clientAddr = this.$cookies.get('address')
|
||||||
|
this.web3.eth.defaultAccount = this.clientAddr
|
||||||
|
this.token = new this.web3.eth.Contract(SBT, this.SBTAddress)
|
||||||
|
this.bank = new this.web3.eth.Contract(Bank, this.BankAddress)
|
||||||
|
|
||||||
|
// get credit
|
||||||
|
this.credit = await this.bank.methods.getCredit(this.clientAddr).call()
|
||||||
|
this.credit = await this.web3.utils.fromWei(this.credit, 'ether')
|
||||||
|
|
||||||
|
// get arrear
|
||||||
|
this.arrear = await this.bank.methods.getArrear(this.clientAddr).call()
|
||||||
|
this.arrear = await this.web3.utils.fromWei(this.arrear, 'ether')
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onScanSuccess(decodedText, decodedResult) {
|
||||||
|
// handle the scanned code as you like, for example:
|
||||||
|
console.log(`Code matched = ${decodedText}`, decodedResult);
|
||||||
|
var last_id = decodedText.split('/').pop()
|
||||||
|
this.scanner.clear()
|
||||||
|
this.$router.push('/client/pay/'+last_id)
|
||||||
|
},
|
||||||
|
scan() {
|
||||||
|
this.scanner = new Html5QrcodeScanner(
|
||||||
|
"reader",
|
||||||
|
{ fps: 10, qrbox: { width: 250, height: 250 } },
|
||||||
|
/* verbose= */ false);
|
||||||
|
this.scanner.render(this.onScanSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="blog-posts">
|
||||||
|
<div class="container">
|
||||||
|
<div class="columns">
|
||||||
|
<div class="column is-2">
|
||||||
|
<ClientNav path="pay"></ClientNav>
|
||||||
|
</div>
|
||||||
|
<div class="column">
|
||||||
|
<div class="container">
|
||||||
|
<div class="block">
|
||||||
|
<PageTitle title="掃描支付" subtitle="掃描店家給的訂單 QRcode 進行支付"></PageTitle>
|
||||||
|
</div>
|
||||||
|
<div class="block">
|
||||||
|
<p class="block">使用地址:{{ this.clientAddr }}</p>
|
||||||
|
<p class="block">剩餘額度:{{ this.credit-this.arrear }} ETH (總額度 {{ this.credit }} ETH )</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="block">
|
||||||
|
<button class="button is-success is-outlined is-large" @click="scan">Pay</button>
|
||||||
|
<div id="reader" width="300px"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<WarningModal :active="warningModalStatus" :errorMsg="msg" @closeModal="warningModalStatus = false"></WarningModal>
|
||||||
|
<SuccessModal :active="successModalStatus" :successMsg="msg" @closeModal="successModalStatus = false"
|
||||||
|
link="/signup/linksbt" btnName="繼續"></SuccessModal>
|
||||||
|
</template>
|
||||||
159
src/views/PaymentView.vue
Normal file
159
src/views/PaymentView.vue
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
<script>
|
||||||
|
|
||||||
|
import Web3 from 'web3';
|
||||||
|
import SBT from '@/assets/SBT.json'
|
||||||
|
import WarningModal from '../components/WarningModal.vue'
|
||||||
|
import SuccessModal from '../components/SuccessModal.vue'
|
||||||
|
import PageTitle from '../components/PageTitle.vue'
|
||||||
|
import Bank from '@/assets/Bank.json'
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { WarningModal, SuccessModal, PageTitle },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
SBTAddress: import.meta.env.VITE_SBT_ADDR,
|
||||||
|
BankAddress: import.meta.env.VITE_BANK_ADDR,
|
||||||
|
warningModalStatus: false,
|
||||||
|
successModalStatus: false,
|
||||||
|
clientAddr: '',
|
||||||
|
web3: null,
|
||||||
|
token: null,
|
||||||
|
bank: null,
|
||||||
|
link: '',
|
||||||
|
msg: '',
|
||||||
|
credit: '',
|
||||||
|
arrear: '',
|
||||||
|
orderId: '',
|
||||||
|
products: [],
|
||||||
|
amount: "0",
|
||||||
|
amountWei: "0",
|
||||||
|
creditWei: "0",
|
||||||
|
arrearWei: "0",
|
||||||
|
shop: {
|
||||||
|
'address': '',
|
||||||
|
'name': '',
|
||||||
|
},
|
||||||
|
waiting: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
// if (!this.$cookies.isKey('linked')) {
|
||||||
|
// this.$router.push('/')
|
||||||
|
// }
|
||||||
|
this.web3 = new Web3(window.ethereum)
|
||||||
|
this.clientAddr = this.$cookies.get('address')
|
||||||
|
this.web3.eth.defaultAccount = this.clientAddr
|
||||||
|
this.token = new this.web3.eth.Contract(SBT, this.SBTAddress)
|
||||||
|
this.bank = new this.web3.eth.Contract(Bank, this.BankAddress)
|
||||||
|
|
||||||
|
// get credit
|
||||||
|
this.credit = await this.bank.methods.getCredit(this.clientAddr).call()
|
||||||
|
this.creditWei = this.credit
|
||||||
|
this.credit = await this.web3.utils.fromWei(this.credit, 'ether')
|
||||||
|
|
||||||
|
// get arrear
|
||||||
|
this.arrear = await this.bank.methods.getArrear(this.clientAddr).call()
|
||||||
|
this.arrearWei = this.arrear
|
||||||
|
this.arrear = await this.web3.utils.fromWei(this.arrear, 'ether')
|
||||||
|
|
||||||
|
// get order
|
||||||
|
this.orderId = this.$route.params.id
|
||||||
|
console.log("id: ", this.orderId)
|
||||||
|
const response = await fetch(`${import.meta.env.VITE_BACKEND_PREFIX}/order/${this.orderId}`);
|
||||||
|
var orderData = await response.json();
|
||||||
|
this.products = orderData.products
|
||||||
|
this.amountWei = orderData.amount
|
||||||
|
this.amount = this.web3.utils.fromWei(orderData.amount, 'ether')
|
||||||
|
this.shop = orderData.shop
|
||||||
|
console.log(this.products)
|
||||||
|
console.log(this.amount)
|
||||||
|
console.log(this.shop)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async pay () {
|
||||||
|
this.waiting = true
|
||||||
|
// await this.bank.methods.pay(this.number, this.shop.address, this.amountWei).send({ from: this.clientAddr })
|
||||||
|
try {
|
||||||
|
await this.bank.methods.pay(this.orderId, this.shop.address, this.amountWei).send({ from: this.clientAddr })
|
||||||
|
this.link = '/client/info'
|
||||||
|
this.msg = '支付成功!<br>已經支付'+this.amount+" ETH 給"+this.shop.name+" ("+this.shop.address+")"
|
||||||
|
this.successModalStatus = true
|
||||||
|
} catch (error) {
|
||||||
|
this.msg = '支付失敗'
|
||||||
|
this.warningModalStatus = true
|
||||||
|
}
|
||||||
|
this.waiting = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="blog-posts">
|
||||||
|
<div class="container">
|
||||||
|
<div class="block">
|
||||||
|
<PageTitle title="確認付款資訊" subtitle="確認後由銀行先向店家支付 ETH"></PageTitle>
|
||||||
|
</div>
|
||||||
|
<div class="block">
|
||||||
|
<table class="table is-fullwidth">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th colspan="4" style="text-align: center;">商品清單</th>
|
||||||
|
</tr>
|
||||||
|
<template v-for="product in products">
|
||||||
|
<tr>
|
||||||
|
<td><b>{{ product.name }}</b></td>
|
||||||
|
<td>{{ web3.utils.fromWei(product.price, 'ether') }} ETH/個</td>
|
||||||
|
<td> * {{ product.count }} 個</td>
|
||||||
|
<td> 合計 {{ web3.utils.fromWei(product.price, 'ether') * product.count }} ETH</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3"></td>
|
||||||
|
<td>共計 {{ amount }} ETH</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="table is-fullwidth">
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th>支付地址:</th>
|
||||||
|
<td colspan="3">{{ this.clientAddr }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>店家地址:</th>
|
||||||
|
<td colspan="3">{{ this.shop.address }} ( {{ this.shop.name }} )</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>目前信用額度:</th>
|
||||||
|
<td colspan="4">{{ this.credit }} ETH (尚可使用 {{ this.credit - this.arrear }} ETH)</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="block">
|
||||||
|
<div class="columns">
|
||||||
|
<div class="column is-2 is-offset-5">
|
||||||
|
<template v-if="(this.creditWei - this.arrearWei) >= this.amountWei">
|
||||||
|
<template v-if="!waiting">
|
||||||
|
<button @click="pay" class="button is-primary is-fullwidth is-medium is-outlined">支付</button>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<button class="button is-primary is-fullwidth is-medium is-outlined is-loading">支付</button>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<RouterLink to="/client" class="button is-danger is-fullwidth is-medium is-outlined">額度不足,取消</RouterLink>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<WarningModal :active="warningModalStatus" :errorMsg="msg" @closeModal="warningModalStatus = false"></WarningModal>
|
||||||
|
<SuccessModal :active="successModalStatus" :successMsg="msg" @closeModal="successModalStatus = false" :link="link"
|
||||||
|
btnName="繼續"></SuccessModal>
|
||||||
|
</template>
|
||||||
Loading…
Reference in New Issue
Block a user