Compare commits
13 Commits
8cb4a14b94
...
887019ed5e
| Author | SHA1 | Date | |
|---|---|---|---|
| 887019ed5e | |||
| aba40a5445 | |||
| 78c786ff7e | |||
| abe480a526 | |||
| 3047758550 | |||
| 26bc81aa56 | |||
| ebe58b6d08 | |||
| 367d837e2e | |||
| c075e080b5 | |||
| 69e634ded0 | |||
| 4dd0a9c1e8 | |||
| e3f7145f91 | |||
| 10fdb644fa |
1
.gitignore
vendored
1
.gitignore
vendored
@ -27,3 +27,4 @@ coverage
|
||||
*.sln
|
||||
*.sw?
|
||||
.env
|
||||
backend/main.db
|
||||
148
backend/main.py
Normal file
148
backend/main.py
Normal file
@ -0,0 +1,148 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import sqlite3
|
||||
import os
|
||||
from flask_cors import CORS
|
||||
|
||||
app = Flask(__name__)
|
||||
CORS(app)
|
||||
|
||||
DATABASE = './main.db'
|
||||
|
||||
def initDB():
|
||||
if os.path.isfile(DATABASE):
|
||||
db = sqlite3.connect(DATABASE)
|
||||
else:
|
||||
with open('schema.sql', 'r') as file:
|
||||
sql_statements = file.read()
|
||||
|
||||
db = sqlite3.connect(DATABASE)
|
||||
cursor = db.cursor()
|
||||
cursor.executescript(sql_statements)
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
@app.route('/')
|
||||
def hello():
|
||||
return 'Hello, Flask!'
|
||||
|
||||
@app.route('/order', methods=['POST'])
|
||||
def process_data():
|
||||
data = request.get_json()
|
||||
|
||||
db = sqlite3.connect(DATABASE)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT id from `shops` WHERE address=?", (data['from'], ))
|
||||
shop_id = cursor.fetchone()[0]
|
||||
|
||||
filter = []
|
||||
params = []
|
||||
for product in data['products']:
|
||||
product_id = product['product_id']
|
||||
filter.append('?')
|
||||
params.append(product_id)
|
||||
filter_str = ', '.join(filter)
|
||||
query = "SELECT id, price FROM products WHERE id IN ({})".format(filter_str)
|
||||
cursor.execute(query, params)
|
||||
prices = cursor.fetchall()
|
||||
|
||||
amount = 0
|
||||
for index, product in enumerate(data['products']):
|
||||
count = int(product['count'])
|
||||
amount += count * int(prices[index][1])
|
||||
|
||||
cursor.execute('INSERT INTO "orders"("id","shop_id","client_addr","amount") VALUES (NULL,?,NULL,?);', (shop_id, amount))
|
||||
order_id = cursor.lastrowid
|
||||
|
||||
for index, product in enumerate(data['products']):
|
||||
product_id = product['product_id']
|
||||
count = int(product['count'])
|
||||
cursor.execute('INSERT INTO "order_products"("id","order_id","product_id","count") VALUES (NULL,?,?,?);', (order_id, product_id, count))
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
return str(order_id)
|
||||
|
||||
@app.route('/order/<id>', methods=['GET'])
|
||||
def get_order(id):
|
||||
db = sqlite3.connect(DATABASE)
|
||||
cursor = db.cursor()
|
||||
|
||||
ans = {}
|
||||
|
||||
# products
|
||||
cursor.execute("SELECT `name`, `price`, `count` FROM `order_products`, `products` \
|
||||
WHERE `order_products`.`order_id`=? and `order_products`.`product_id`=`products`.`id`", (id, ))
|
||||
products = cursor.fetchall()
|
||||
|
||||
ans['products'] = []
|
||||
for product in products:
|
||||
ans['products'].append({
|
||||
'name': product[0],
|
||||
'price': str(product[1]),
|
||||
'count': product[2]
|
||||
})
|
||||
|
||||
# shop name
|
||||
cursor.execute("SELECT `address`, `name`, `amount`, `client_addr` FROM `shops`, `orders` WHERE `orders`.`shop_id`=`shops`.`id` and `orders`.`id`= ?", (id, ))
|
||||
result = cursor.fetchone()
|
||||
ans['shop'] = {
|
||||
'name': result[1],
|
||||
'address': result[0]
|
||||
}
|
||||
ans['amount'] = str(result[2])
|
||||
ans['client'] = result[3]
|
||||
|
||||
return jsonify(ans)
|
||||
|
||||
@app.route('/order/<id>', methods=['PATCH'])
|
||||
def update_client(id):
|
||||
client = request.get_json()['client']
|
||||
|
||||
db = sqlite3.connect(DATABASE)
|
||||
cursor = db.cursor()
|
||||
|
||||
ans = {}
|
||||
|
||||
# products
|
||||
cursor.execute("UPDATE `orders` SET `client_addr`=? WHERE `id`=?", (client, id ))
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
return jsonify({'status': 'OK'})
|
||||
|
||||
|
||||
@app.route('/shop/check', methods=['POST'])
|
||||
def shop_check():
|
||||
address = request.get_json()['address']
|
||||
db = sqlite3.connect(DATABASE)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT COUNT(*) FROM `shops` WHERE `address`=?", (address, ))
|
||||
result = cursor.fetchone()[0]
|
||||
print(result, type(result))
|
||||
if result != 0:
|
||||
return jsonify({'status': True})
|
||||
else:
|
||||
return jsonify({'status': False})
|
||||
|
||||
@app.route('/shop/<address>/products', methods=['GET'])
|
||||
def shop_products(address):
|
||||
db = sqlite3.connect(DATABASE)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT `products`.`id`, `products`.`name`, `products`.`price`, `products`.`code` FROM `shops`, `products` \
|
||||
WHERE `shops`.id = `products`.`shop_id`and `shops`.`address`=?", (address, ))
|
||||
result = cursor.fetchall()
|
||||
|
||||
ans = {'products': {}}
|
||||
for product in result:
|
||||
ans['products'][str(product[3])] = {
|
||||
'id': product[0],
|
||||
'name': product[1],
|
||||
'price': str(product[2]),
|
||||
}
|
||||
return jsonify(ans)
|
||||
|
||||
if __name__ == '__main__':
|
||||
initDB()
|
||||
app.run(host="0.0.0.0")
|
||||
52
backend/schema.sql
Normal file
52
backend/schema.sql
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
CREATE TABLE "shops" (
|
||||
"id" INTEGER,
|
||||
"address" TEXT,
|
||||
"name" TEXT,
|
||||
PRIMARY KEY("id" AUTOINCREMENT)
|
||||
);
|
||||
|
||||
---------------------------------------------------
|
||||
|
||||
CREATE TABLE "products" (
|
||||
"id" INTEGER,
|
||||
"shop_id" INTEGER,
|
||||
"name" TEXT,
|
||||
"code" TEXT,
|
||||
"price" INTEGER,
|
||||
FOREIGN KEY("shop_id") REFERENCES "shops"("id"),
|
||||
PRIMARY KEY("id" AUTOINCREMENT)
|
||||
);
|
||||
|
||||
---------------------------------------------------
|
||||
|
||||
CREATE TABLE "orders" (
|
||||
"id" INTEGER,
|
||||
"shop_id" INTEGER,
|
||||
"client_addr" TEXT,
|
||||
"amount" TEXT,
|
||||
PRIMARY KEY("id" AUTOINCREMENT),
|
||||
FOREIGN KEY("shop_id") REFERENCES "shops"("id")
|
||||
);
|
||||
|
||||
---------------------------------------------------
|
||||
|
||||
CREATE TABLE "order_products" (
|
||||
"id" INTEGER,
|
||||
"order_id" INTEGER,
|
||||
"product_id" INTEGER,
|
||||
"count" INTEGER,
|
||||
FOREIGN KEY("product_id") REFERENCES "products"("id"),
|
||||
PRIMARY KEY("id" AUTOINCREMENT),
|
||||
FOREIGN KEY("order_id") REFERENCES "orders"("id")
|
||||
);
|
||||
|
||||
---------------------------------------------------
|
||||
|
||||
INSERT INTO "main"."shops"("id","address","name") VALUES (NULL,"0x73D081e82b35D6E6f9f5e72EBBB6b637d4f46992","全家便利商店");
|
||||
INSERT INTO "main"."shops"("id","address","name") VALUES (NULL,"0xDa68136fcB885a2ec44db6dcE946F656aF457A76","暨大圖文部");
|
||||
|
||||
INSERT INTO "main"."products"("id","shop_id","name","code", "price") VALUES (NULL,1,"濃辛咖哩飯","7233957360139", "10000000000000000");
|
||||
INSERT INTO "main"."products"("id","shop_id","name","code", "price") VALUES (NULL,1,"霜淇淋","4718022345288", "5000000000000000");
|
||||
INSERT INTO "main"."products"("id","shop_id","name","code", "price") VALUES (NULL,2,"證件套","748009345271", "25000000000000000");
|
||||
INSERT INTO "main"."products"("id","shop_id","name","code", "price") VALUES (NULL,2,"便條紙","4979274503226", "4000000000000000");
|
||||
446
package-lock.json
generated
446
package-lock.json
generated
@ -11,6 +11,8 @@
|
||||
"@metamask/detect-provider": "^2.0.0",
|
||||
"html5-qrcode": "^2.3.8",
|
||||
"pinia": "^2.0.36",
|
||||
"qrcode": "^1.5.3",
|
||||
"qrcode-vue": "^1.2.0",
|
||||
"vue": "^3.3.2",
|
||||
"vue-cookies": "^1.8.3",
|
||||
"vue-router": "^4.2.0",
|
||||
@ -1195,7 +1197,6 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@ -1204,7 +1205,6 @@
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
@ -1626,6 +1626,14 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
@ -1693,6 +1701,16 @@
|
||||
"resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz",
|
||||
"integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw=="
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
|
||||
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^6.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/clone-response": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
|
||||
@ -1708,7 +1726,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
@ -1719,8 +1736,7 @@
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
@ -1910,6 +1926,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/decode-uri-component": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
@ -1998,6 +2022,11 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/dijkstrajs": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
|
||||
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
@ -2043,6 +2072,16 @@
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/encode-utf8": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz",
|
||||
"integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw=="
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
@ -3054,6 +3093,14 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
|
||||
@ -3632,6 +3679,14 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-function": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
|
||||
@ -4461,6 +4516,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@ -4490,7 +4553,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@ -4599,6 +4661,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pngjs": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
|
||||
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.24",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
|
||||
@ -4690,6 +4760,36 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qr.js": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz",
|
||||
"integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ=="
|
||||
},
|
||||
"node_modules/qrcode": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz",
|
||||
"integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==",
|
||||
"dependencies": {
|
||||
"dijkstrajs": "^1.0.1",
|
||||
"encode-utf8": "^1.0.3",
|
||||
"pngjs": "^5.0.0",
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
"bin": {
|
||||
"qrcode": "bin/qrcode"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode-vue": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/qrcode-vue/-/qrcode-vue-1.2.0.tgz",
|
||||
"integrity": "sha512-djGZRrXCVA/mxHJvhYXdYN2eeKrVtu+Yi0pYRuE02dbj5R3Xt4uyXa5iM3dgiEQ85r5p7m6nYFRAJaayMMwbqg==",
|
||||
"dependencies": {
|
||||
"qr.js": "0.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
@ -4847,6 +4947,19 @@
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.2",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
|
||||
@ -5128,6 +5241,11 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
||||
},
|
||||
"node_modules/setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
@ -5280,6 +5398,19 @@
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/string.prototype.trim": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
|
||||
@ -5329,7 +5460,6 @@
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
@ -6308,6 +6438,11 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/which-module": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
|
||||
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
|
||||
},
|
||||
"node_modules/which-typed-array": {
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz",
|
||||
@ -6336,6 +6471,19 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
@ -6406,6 +6554,11 @@
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
|
||||
},
|
||||
"node_modules/yaeti": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
|
||||
@ -6420,6 +6573,87 @@
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "15.4.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
||||
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
|
||||
"dependencies": {
|
||||
"cliui": "^6.0.0",
|
||||
"decamelize": "^1.2.0",
|
||||
"find-up": "^4.1.0",
|
||||
"get-caller-file": "^2.0.1",
|
||||
"require-directory": "^2.1.1",
|
||||
"require-main-filename": "^2.0.0",
|
||||
"set-blocking": "^2.0.0",
|
||||
"string-width": "^4.2.0",
|
||||
"which-module": "^2.0.0",
|
||||
"y18n": "^4.0.0",
|
||||
"yargs-parser": "^18.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "18.1.3",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
|
||||
"dependencies": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/find-up": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||
"dependencies": {
|
||||
"locate-path": "^5.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||
"dependencies": {
|
||||
"p-locate": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dependencies": {
|
||||
"p-try": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/p-locate": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||
"dependencies": {
|
||||
"p-limit": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
@ -7148,14 +7382,12 @@
|
||||
"ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
@ -7479,6 +7711,11 @@
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||
"dev": true
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
@ -7536,6 +7773,16 @@
|
||||
"resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz",
|
||||
"integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw=="
|
||||
},
|
||||
"cliui": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
|
||||
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^6.2.0"
|
||||
}
|
||||
},
|
||||
"clone-response": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
|
||||
@ -7548,7 +7795,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
@ -7556,8 +7802,7 @@
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
@ -7706,6 +7951,11 @@
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="
|
||||
},
|
||||
"decode-uri-component": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
@ -7762,6 +8012,11 @@
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
|
||||
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
|
||||
},
|
||||
"dijkstrajs": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
|
||||
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
|
||||
},
|
||||
"doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
@ -7804,6 +8059,16 @@
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"encode-utf8": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz",
|
||||
"integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw=="
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
@ -8622,6 +8887,11 @@
|
||||
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
|
||||
@ -9030,6 +9300,11 @@
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||
},
|
||||
"is-function": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
|
||||
@ -9641,6 +9916,11 @@
|
||||
"p-limit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
|
||||
},
|
||||
"parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@ -9663,8 +9943,7 @@
|
||||
"path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
@ -9728,6 +10007,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"pngjs": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
|
||||
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.4.24",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
|
||||
@ -9787,6 +10071,30 @@
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
|
||||
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA=="
|
||||
},
|
||||
"qr.js": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz",
|
||||
"integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ=="
|
||||
},
|
||||
"qrcode": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz",
|
||||
"integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==",
|
||||
"requires": {
|
||||
"dijkstrajs": "^1.0.1",
|
||||
"encode-utf8": "^1.0.3",
|
||||
"pngjs": "^5.0.0",
|
||||
"yargs": "^15.3.1"
|
||||
}
|
||||
},
|
||||
"qrcode-vue": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/qrcode-vue/-/qrcode-vue-1.2.0.tgz",
|
||||
"integrity": "sha512-djGZRrXCVA/mxHJvhYXdYN2eeKrVtu+Yi0pYRuE02dbj5R3Xt4uyXa5iM3dgiEQ85r5p7m6nYFRAJaayMMwbqg==",
|
||||
"requires": {
|
||||
"qr.js": "0.0.0"
|
||||
}
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
@ -9895,6 +10203,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
|
||||
},
|
||||
"require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.22.2",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
|
||||
@ -10099,6 +10417,11 @@
|
||||
"xhr": "^2.3.3"
|
||||
}
|
||||
},
|
||||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
||||
},
|
||||
"setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
@ -10207,6 +10530,16 @@
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"string.prototype.trim": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
|
||||
@ -10244,7 +10577,6 @@
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
}
|
||||
@ -11004,6 +11336,11 @@
|
||||
"is-symbol": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"which-module": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
|
||||
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
|
||||
},
|
||||
"which-typed-array": {
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz",
|
||||
@ -11023,6 +11360,16 @@
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"dev": true
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
@ -11089,6 +11436,11 @@
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
|
||||
},
|
||||
"yaeti": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
|
||||
@ -11100,6 +11452,68 @@
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "15.4.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
||||
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
|
||||
"requires": {
|
||||
"cliui": "^6.0.0",
|
||||
"decamelize": "^1.2.0",
|
||||
"find-up": "^4.1.0",
|
||||
"get-caller-file": "^2.0.1",
|
||||
"require-directory": "^2.1.1",
|
||||
"require-main-filename": "^2.0.0",
|
||||
"set-blocking": "^2.0.0",
|
||||
"string-width": "^4.2.0",
|
||||
"which-module": "^2.0.0",
|
||||
"y18n": "^4.0.0",
|
||||
"yargs-parser": "^18.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"find-up": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||
"requires": {
|
||||
"locate-path": "^5.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||
"requires": {
|
||||
"p-locate": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||
"requires": {
|
||||
"p-limit": "^2.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "18.1.3",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
|
||||
"requires": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
"@metamask/detect-provider": "^2.0.0",
|
||||
"html5-qrcode": "^2.3.8",
|
||||
"pinia": "^2.0.36",
|
||||
"qrcode": "^1.5.3",
|
||||
"qrcode-vue": "^1.2.0",
|
||||
"vue": "^3.3.2",
|
||||
"vue-cookies": "^1.8.3",
|
||||
"vue-router": "^4.2.0",
|
||||
|
||||
@ -1,239 +1,257 @@
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "SBT_addr",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function",
|
||||
"constant": true
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "recv",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function",
|
||||
"constant": true
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "sbt",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "contract SoulboundToken",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function",
|
||||
"constant": true
|
||||
},
|
||||
{
|
||||
"stateMutability": "payable",
|
||||
"type": "receive",
|
||||
"payable": true
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setCredit",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "number",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "register",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "shop",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "pay",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "repay",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "payable",
|
||||
"type": "function",
|
||||
"payable": true
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "start_recv",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "stop_recv",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getCredit",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function",
|
||||
"constant": true
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getArrear",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function",
|
||||
"constant": true
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getClientOrders",
|
||||
"outputs": [
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "isFinished",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "shop",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"internalType": "struct Order[]",
|
||||
"name": "",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"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
|
||||
}
|
||||
]
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "SBT_addr",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function",
|
||||
"constant": true
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "recv",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function",
|
||||
"constant": true
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "sbt",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "contract SoulboundToken",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function",
|
||||
"constant": true
|
||||
},
|
||||
{
|
||||
"stateMutability": "payable",
|
||||
"type": "receive",
|
||||
"payable": true
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setCredit",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "number",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "register",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "id",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "shop",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "pay",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "repay",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "payable",
|
||||
"type": "function",
|
||||
"payable": true
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "warning",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "start_recv",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "stop_recv",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getCredit",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function",
|
||||
"constant": true
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getArrear",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function",
|
||||
"constant": true
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getClientOrders",
|
||||
"outputs": [
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "isFinished",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "shop",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"internalType": "struct Order[]",
|
||||
"name": "",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"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
|
||||
}
|
||||
]
|
||||
@ -58,19 +58,19 @@
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "shop",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "bank",
|
||||
"type": "address"
|
||||
@ -114,13 +114,13 @@
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "bank",
|
||||
"type": "address"
|
||||
@ -170,13 +170,13 @@
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "client",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "bank",
|
||||
"type": "address"
|
||||
|
||||
@ -30,6 +30,17 @@ hr {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.svg-container {
|
||||
width: 100%; /* 設定容器寬度,根據需要調整 */
|
||||
height: 50%;
|
||||
padding-bottom: 50%; /* 設定高度,根據需要調整,這裡使用 75% 做為示例 */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
p.block {
|
||||
color: lightslategray;
|
||||
}
|
||||
|
||||
/*
|
||||
.message-header {
|
||||
background: white;
|
||||
|
||||
@ -2,18 +2,19 @@
|
||||
export default {
|
||||
name: 'ClientNav',
|
||||
props: ['path'],
|
||||
mounted () {
|
||||
console.log(this.path)
|
||||
this.navCSS[this.path] += ' is-active'
|
||||
console.log(this.navCSS)
|
||||
mounted() {
|
||||
if (this.path in this.navCSS) {
|
||||
this.navCSS[this.path] += ' is-active'
|
||||
}
|
||||
},
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
navCSS: {
|
||||
navCSS: {
|
||||
main: 'panel-block',
|
||||
pay: 'panel-block',
|
||||
credit: 'panel-block',
|
||||
info: 'panel-block',
|
||||
log: 'panel-block'
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,15 +60,26 @@ export default {
|
||||
<p>掃描支付</p>
|
||||
</template>
|
||||
</RouterLink>
|
||||
<RouterLink to="/client/log" :class="this.navCSS['log']">
|
||||
<span class="panel-icon">
|
||||
<i class="fas fa-book" aria-hidden="true"></i>
|
||||
</span>
|
||||
<template v-if="this.path == 'log'">
|
||||
<strong>借款紀錄</strong>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>借款紀錄</p>
|
||||
</template>
|
||||
</RouterLink>
|
||||
<RouterLink to="/client/credit" :class="this.navCSS['credit']">
|
||||
<span class="panel-icon">
|
||||
<i class="fas fa-book" aria-hidden="true"></i>
|
||||
</span>
|
||||
<template v-if="this.path == 'credit'">
|
||||
<strong>信用紀錄</strong>
|
||||
<strong>SBT信用紀錄</strong>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>信用紀錄</p>
|
||||
<p>SBT信用紀錄</p>
|
||||
</template>
|
||||
</RouterLink>
|
||||
</nav>
|
||||
|
||||
@ -44,6 +44,15 @@ export default {
|
||||
this.web3.eth.defaultAccount = clientAddr
|
||||
var returnNumber = await token.methods.getSBTNumber(clientAddr).call({from: clientAddr})
|
||||
if (returnNumber != 0){
|
||||
var result = await fetch(import.meta.env.VITE_BACKEND_PREFIX+"/shop/check", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({'address': clientAddr})
|
||||
})
|
||||
var result = await result.json()
|
||||
this.$cookies.set('isShop', result.status)
|
||||
this.$cookies.set('address', clientAddr)
|
||||
this.$cookies.set('linked', true)
|
||||
this.$cookies.set('SBTNumber', returnNumber)
|
||||
@ -71,6 +80,7 @@ export default {
|
||||
this.$cookies.remove('linked')
|
||||
this.$cookies.remove('address')
|
||||
this.$cookies.remove('SBTNumber')
|
||||
this.$cookies.remove('shop')
|
||||
this.$router.push('/')
|
||||
}
|
||||
}
|
||||
|
||||
62
src/components/ShopNav.vue
Normal file
62
src/components/ShopNav.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'ShopNav',
|
||||
props: ['path'],
|
||||
mounted() {
|
||||
if (this.path in this.navCSS) {
|
||||
this.navCSS[this.path] += ' is-active'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
navCSS: {
|
||||
shoppay: 'panel-block',
|
||||
shoplog: 'panel-block',
|
||||
shopproducts: 'panel-block',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="panel">
|
||||
<p class="panel-heading">
|
||||
店家選項
|
||||
</p>
|
||||
<RouterLink to="/shop/pay" :class="this.navCSS['shoppay']">
|
||||
<span class="panel-icon">
|
||||
<i class="fas fa-book" aria-hidden="true"></i>
|
||||
</span>
|
||||
<template v-if="this.path == 'shoppay'">
|
||||
<strong>店家結帳</strong>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>店家結帳</p>
|
||||
</template>
|
||||
</RouterLink>
|
||||
<RouterLink to="/shop/log" :class="this.navCSS['shoplog']">
|
||||
<span class="panel-icon">
|
||||
<i class="fas fa-book" aria-hidden="true"></i>
|
||||
</span>
|
||||
<template v-if="this.path == 'shoplog'">
|
||||
<strong>店家收款紀錄</strong>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>店家收款紀錄</p>
|
||||
</template>
|
||||
</RouterLink>
|
||||
<RouterLink to="/shop/products" :class="this.navCSS['shopproducts']">
|
||||
<span class="panel-icon">
|
||||
<i class="fas fa-book" aria-hidden="true"></i>
|
||||
</span>
|
||||
<template v-if="this.path == 'shopproducts'">
|
||||
<strong>店家商品管理</strong>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>店家商品管理</p>
|
||||
</template>
|
||||
</RouterLink>
|
||||
</nav>
|
||||
</template>
|
||||
@ -7,6 +7,12 @@ import ClientMainView from '../views/ClientMainView.vue'
|
||||
import ClientInfoView from '../views/ClientInfoView.vue'
|
||||
import ClientCreditView from '../views/ClientCreditView.vue'
|
||||
import ClientPayView from '../views/ClientPayView.vue'
|
||||
import PaymentView from '../views/PaymentView.vue'
|
||||
import ShopPayView from '../views/ShopPayView.vue'
|
||||
import ShopPayQRcodeView from '../views/ShopPayQRcodeView.vue'
|
||||
import ShopLogView from '../views/ShopLogView.vue'
|
||||
import OrderView from '../views/OrderView.vue'
|
||||
import ClientLogView from '../views/ClientLogView.vue'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
@ -51,6 +57,36 @@ const router = createRouter({
|
||||
name: 'clientpay',
|
||||
component: ClientPayView
|
||||
},
|
||||
{
|
||||
path: '/client/pay/:id',
|
||||
name: 'clientpayment',
|
||||
component: PaymentView
|
||||
},
|
||||
{
|
||||
path: '/shop/pay',
|
||||
name: 'shoppay',
|
||||
component: ShopPayView
|
||||
},
|
||||
{
|
||||
path: '/shop/pay/:id',
|
||||
name: 'shopayqrcode',
|
||||
component: ShopPayQRcodeView
|
||||
},
|
||||
{
|
||||
path: '/shop/log',
|
||||
name: 'shopaylog',
|
||||
component: ShopLogView
|
||||
},
|
||||
{
|
||||
path: '/order/:id',
|
||||
name: 'order',
|
||||
component: OrderView
|
||||
},
|
||||
{
|
||||
path: '/client/log',
|
||||
name: 'log',
|
||||
component: ClientLogView
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
183
src/views/ClientCreditView.vue
Normal file
183
src/views/ClientCreditView.vue
Normal file
@ -0,0 +1,183 @@
|
||||
<script>
|
||||
import Web3 from 'web3';
|
||||
import SBT from '@/assets/SBT.json'
|
||||
import PageTitle from '../components/PageTitle.vue'
|
||||
import detectEthereumProvider from '@metamask/detect-provider'
|
||||
import WarningModal from '../components/WarningModal.vue'
|
||||
import SuccessModal from '../components/SuccessModal.vue'
|
||||
import { useClientStore } from '../stores/Client.js'
|
||||
import ClientNav from '../components/ClientNav.vue'
|
||||
import ShopNav from '../components/ShopNav.vue'
|
||||
|
||||
// To use Html5QrcodeScanner (more info below)
|
||||
import { Html5QrcodeScanner } from "html5-qrcode";
|
||||
|
||||
// To use Html5Qrcode (more info below)
|
||||
import { Html5Qrcode } from "html5-qrcode";
|
||||
|
||||
|
||||
|
||||
export default {
|
||||
components: { PageTitle, WarningModal, SuccessModal, ClientNav, ShopNav },
|
||||
data() {
|
||||
return {
|
||||
SBTAddress: import.meta.env.VITE_SBT_ADDR,
|
||||
number: 0,
|
||||
warningModalStatus: false,
|
||||
successModalStatus: false,
|
||||
msg: '',
|
||||
clientAddr: '',
|
||||
web3: null,
|
||||
token: null,
|
||||
isWaiting: false,
|
||||
log: [],
|
||||
warningLog: [],
|
||||
scanner: null
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
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)
|
||||
|
||||
var borrow = await this.token.getPastEvents("Borrow", { fromBlock: 0, toBlock: 'latest', filter: { client: this.clientAddr } })
|
||||
for (let i of borrow) {
|
||||
let result = i.returnValues
|
||||
let obj = {
|
||||
bank: result['bank'],
|
||||
shop: result['shop'],
|
||||
id: result['id'],
|
||||
amount: this.web3.utils.fromWei(result['amount'], 'ether'),
|
||||
repay: false
|
||||
}
|
||||
this.log.push(obj)
|
||||
}
|
||||
|
||||
var repay = await this.token.getPastEvents("Repay", { fromBlock: 0, toBlock: 'latest', filter: { client: this.clientAddr } })
|
||||
for (let i of repay) {
|
||||
let result = i.returnValues
|
||||
for (let j of this.log) {
|
||||
if ((result['bank'] == j.bank) && (result['id'] == j.id)) {
|
||||
j.repay = true
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(this.log)
|
||||
|
||||
var warning = await this.token.getPastEvents("Warning", { fromBlock: 0, toBlock: 'latest', filter: { client: this.clientAddr } })
|
||||
for (let i of warning) {
|
||||
let result = i.returnValues
|
||||
this.warningLog.push(result.bank)
|
||||
}
|
||||
console.log(this.warningLog)
|
||||
},
|
||||
methods: {
|
||||
onScanSuccess(decodedText, decodedResult) {
|
||||
// handle the scanned code as you like, for example:
|
||||
console.log(`Code matched = ${decodedText}`, decodedResult);
|
||||
this.scanner.clear()
|
||||
},
|
||||
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="credit"></ClientNav>
|
||||
<template v-if="this.$cookies.get('isShop') == 'true'">
|
||||
<ShopNav path="credit"></ShopNav>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="container">
|
||||
<div class="block">
|
||||
<PageTitle title="SBT 信用紀錄" subtitle="根據 SBT 信用紀錄設定額度"></PageTitle>
|
||||
</div>
|
||||
<div class="block">
|
||||
<div class="box">
|
||||
<div class="content">
|
||||
<h5 class="title is-5">說明</h5>
|
||||
<ul>
|
||||
<li>我們會根據您提供的 SBT 查詢相關信用紀錄,我們會根據紀錄設定給予的每月額度</li>
|
||||
<li>若擁有新的 SBT,代表您不曾擁有過信用紀錄,下表為空。</li>
|
||||
<li>若您不曾擁有過信用交易紀錄,我們提供最低額度 1 ETH/1 month。</li>
|
||||
<li>請確認下表紀錄,我們將依照該紀錄表計算。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="block">
|
||||
<h1 class="title is-4">支付紀錄</h1>
|
||||
<table class="table is-fullwidth is-striped is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>銀行</th>
|
||||
<th>銀行帳款編號</th>
|
||||
<th>商店</th>
|
||||
<th>金額</th>
|
||||
<th>已結清帳款</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(value, index) of log">
|
||||
<tr>
|
||||
<th>{{ index }}</th>
|
||||
<td>{{ value.bank }}</td>
|
||||
<td>#{{ value.id }}</td>
|
||||
<td>{{ value.shop }}</td>
|
||||
<td>{{ value.amount }} ETH</td>
|
||||
<td v-if="value.repay">
|
||||
<span class="icon has-text-success">
|
||||
<i class="fas fa-check-square"></i>
|
||||
</span>
|
||||
</td>
|
||||
<td v-else>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="block">
|
||||
<h1 class="title is-4">警告紀錄</h1>
|
||||
<table class="table is-fullwidth is-striped is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>發起預警之銀行</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(value, index) of warningLog">
|
||||
<tr>
|
||||
<th>{{ index }}</th>
|
||||
<td>{{ value }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</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>
|
||||
135
src/views/ClientInfoView.vue
Normal file
135
src/views/ClientInfoView.vue
Normal file
@ -0,0 +1,135 @@
|
||||
<script>
|
||||
import Web3 from 'web3';
|
||||
import SBT from '@/assets/SBT.json'
|
||||
import Bank from '@/assets/Bank.json'
|
||||
import PageTitle from '../components/PageTitle.vue'
|
||||
import detectEthereumProvider from '@metamask/detect-provider'
|
||||
import WarningModal from '../components/WarningModal.vue'
|
||||
import SuccessModal from '../components/SuccessModal.vue'
|
||||
import { useClientStore } from '../stores/Client.js'
|
||||
import ClientNav from '../components/ClientNav.vue'
|
||||
import ShopNav from '../components/ShopNav.vue'
|
||||
|
||||
// To use Html5QrcodeScanner (more info below)
|
||||
import { Html5QrcodeScanner } from "html5-qrcode";
|
||||
|
||||
// To use Html5Qrcode (more info below)
|
||||
import { Html5Qrcode } from "html5-qrcode";
|
||||
|
||||
|
||||
export default {
|
||||
components: { PageTitle, WarningModal, SuccessModal, ClientNav, ShopNav },
|
||||
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: '',
|
||||
borrowNum: 0,
|
||||
repayNum: 0,
|
||||
warningNum: 0
|
||||
}
|
||||
},
|
||||
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 svg image
|
||||
var base64Data = await this.token.methods.tokenURI(this.$cookies.get('SBTNumber')).call()
|
||||
const commaIndex = base64Data.indexOf(',');
|
||||
if (commaIndex !== -1) {
|
||||
base64Data = base64Data.substr(commaIndex + 1);
|
||||
}
|
||||
const decodedData = JSON.parse(atob(base64Data));
|
||||
this.picName = decodedData.name
|
||||
this.pic = decodedData.image_data
|
||||
this.pic = this.pic.replace('<svg', '<svg class="svg-container"')
|
||||
|
||||
// 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')
|
||||
|
||||
var borrow = await this.token.getPastEvents("Borrow", { fromBlock: 0, toBlock: 'latest', filter: { client: this.clientAddr, bank: this.BankAddress } })
|
||||
var repay = await this.token.getPastEvents("Repay", { fromBlock: 0, toBlock: 'latest', filter: { client: this.clientAddr, bank: this.BankAddress } })
|
||||
var warning = await this.token.getPastEvents("Warning", { fromBlock: 0, toBlock: 'latest', filter: { client: this.clientAddr, bank: this.BankAddress } })
|
||||
this.borrowNum = borrow.length
|
||||
this.repayNum = repay.length
|
||||
this.warningNum = warning.length
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="blog-posts">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
<ClientNav path="info"></ClientNav>
|
||||
<template v-if="this.$cookies.get('isShop') == 'true'">
|
||||
<ShopNav path="info"></ShopNav>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="container">
|
||||
<div class="block">
|
||||
<PageTitle title="個人資料" subtitle="紀錄在區塊鏈上的相關資料"></PageTitle>
|
||||
</div>
|
||||
<div class="block">
|
||||
<table class="table is-fullwidth">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>地址:</th>
|
||||
<td>{{ this.clientAddr }}</td>
|
||||
<!-- <td>{{ this.clientAddr.slice(0, 8)+"..."+this.clientAddr.slice(33, 42) }}</td> -->
|
||||
</tr>
|
||||
<tr>
|
||||
<th>目前信用額度:</th>
|
||||
<td>{{ this.credit }} ETH (尚可使用 {{ this.credit - this.arrear }} ETH)</td>
|
||||
<!-- <td>{{ this.clientAddr.slice(0, 8)+"..."+this.clientAddr.slice(33, 42) }}</td> -->
|
||||
</tr>
|
||||
<tr>
|
||||
<th>目前欠款:</th>
|
||||
<td>{{ this.arrear }} ETH</td>
|
||||
<!-- <td>{{ this.clientAddr.slice(0, 8)+"..."+this.clientAddr.slice(33, 42) }}</td> -->
|
||||
</tr>
|
||||
<tr>
|
||||
<th>本銀行借款紀錄簡覽</th>
|
||||
<td>共計借款 {{ this.borrowNum }} 項,已還款 {{ this.repayNum }} 項。被本銀行預警 {{ this.warningNum }} 次</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Soulbound Token 號碼:</th>
|
||||
<td>{{ this.$cookies.get('SBTNumber') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Soulbound Token NFT 證書:</th>
|
||||
<td>{{ picName }}<div class="block is-fullwidth" v-html="pic"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
93
src/views/ClientLogView.vue
Normal file
93
src/views/ClientLogView.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<script>
|
||||
import Web3 from 'web3';
|
||||
import SBT from '@/assets/SBT.json'
|
||||
import PageTitle from '../components/PageTitle.vue'
|
||||
import ClientNav from '../components/ClientNav.vue'
|
||||
import ShopNav from '../components/ShopNav.vue'
|
||||
|
||||
export default {
|
||||
components: { PageTitle, ClientNav, ShopNav },
|
||||
data() {
|
||||
return {
|
||||
SBTAddress: import.meta.env.VITE_SBT_ADDR,
|
||||
BankAddress: import.meta.env.VITE_BANK_ADDR,
|
||||
clientAddr: '',
|
||||
web3: null,
|
||||
token: null,
|
||||
log: [],
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
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)
|
||||
|
||||
var borrow = await this.token.getPastEvents("Borrow", { fromBlock: 0, toBlock: 'latest', filter: { client: this.clientAddr, bank: this.BankAddress } })
|
||||
console.log(borrow)
|
||||
for (let i of borrow) {
|
||||
let result = i.returnValues
|
||||
let obj = {
|
||||
bank: result['bank'],
|
||||
shop: result['shop'],
|
||||
client: result['client'],
|
||||
id: result['id'],
|
||||
amount: this.web3.utils.fromWei(result['amount'], 'ether'),
|
||||
}
|
||||
this.log.push(obj)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="blog-posts">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
<ClientNav path="shoplog"></ClientNav>
|
||||
<template v-if="this.$cookies.get('isShop') == 'true'">
|
||||
<ShopNav path="shoplog"></ShopNav>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="container">
|
||||
<div class="block">
|
||||
<PageTitle title="借款紀錄" subtitle="查詢透過本銀行進行支付的所有紀錄"></PageTitle>
|
||||
</div>
|
||||
<div class="block">
|
||||
<h1 class="title is-4">收款紀錄</h1>
|
||||
<table class="table is-fullwidth is-striped is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>店家</th>
|
||||
<th>銀行</th>
|
||||
<th>帳款編號</th>
|
||||
<th>金額</th>
|
||||
<th>詳細訂單狀況</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(value, index) of log">
|
||||
<tr>
|
||||
<th>{{ index }}</th>
|
||||
<td>{{ value.shop }}</td>
|
||||
<td>{{ value.bank }}</td>
|
||||
<td>#{{ value.id }}</td>
|
||||
<td>{{ value.amount }} ETH</td>
|
||||
<td><RouterLink :to="'/order/'+value.id" class="button is-info is-outlined">查詢</RouterLink></td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@ -30,13 +30,18 @@ export default {
|
||||
token: null,
|
||||
isWaiting: false,
|
||||
log: [],
|
||||
scanner: null
|
||||
scanner: null,
|
||||
isShop: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (!this.$cookies.isKey('linked')) {
|
||||
this.$router.push('/')
|
||||
}
|
||||
this.web3 = new Web3(window.ethereum)
|
||||
this.clientAddr = (await this.web3.eth.getAccounts())[0]
|
||||
this.clientAddr = this.$cookies.get('address')
|
||||
this.web3.eth.defaultAccount = this.clientAddr
|
||||
this.isShop = (this.$cookies.get('isShop') == 'true')
|
||||
},
|
||||
methods: {
|
||||
onScanSuccess(decodedText, decodedResult) {
|
||||
@ -44,7 +49,7 @@ export default {
|
||||
console.log(`Code matched = ${decodedText}`, decodedResult);
|
||||
this.scanner.clear()
|
||||
},
|
||||
scan () {
|
||||
scan() {
|
||||
this.scanner = new Html5QrcodeScanner(
|
||||
"reader",
|
||||
{ fps: 10, qrbox: { width: 250, height: 250 } },
|
||||
@ -87,12 +92,41 @@ export default {
|
||||
<!-- <p class="subtitle">Top tile</p> -->
|
||||
</article>
|
||||
</RouterLink>
|
||||
<RouterLink to="/client/credit" class="tile is-child notification is-info">
|
||||
<RouterLink to="/client/log" class="tile is-child notification is-info">
|
||||
<article>
|
||||
<p class="title"><i class="fas fa-history"></i> 信用紀錄</p>
|
||||
<p class="title"><i class="fas fa-history"></i> 借款紀錄</p>
|
||||
<!-- <p class="subtitle">Top tile</p> -->
|
||||
</article>
|
||||
</RouterLink>
|
||||
<RouterLink to="/client/credit" class="tile is-child notification is-info">
|
||||
<article>
|
||||
<p class="title"><i class="fas fa-cubes"></i> SBT信用紀錄</p>
|
||||
<!-- <p class="subtitle">Top tile</p> -->
|
||||
</article>
|
||||
</RouterLink>
|
||||
|
||||
<template v-if="this.isShop">
|
||||
<RouterLink to="/shop/pay" class="tile is-child notification is-info">
|
||||
<article>
|
||||
<p class="title"><i class="fas fa-cash-register"></i> 店家結帳</p>
|
||||
<!-- <p class="subtitle">Top tile</p> -->
|
||||
</article>
|
||||
</RouterLink>
|
||||
<RouterLink to="/shop/log" class="tile is-child notification is-info">
|
||||
<article>
|
||||
<p class="title"><i class="fas fa-receipt"></i> 店家收款紀錄</p>
|
||||
<!-- <p class="subtitle">Top tile</p> -->
|
||||
</article>
|
||||
</RouterLink>
|
||||
<RouterLink to="/shop/products" class="tile is-child notification is-info">
|
||||
<article>
|
||||
<p class="title"><i class="fas fa-box-open"></i> 店家商品管理</p>
|
||||
<!-- <p class="subtitle">Top tile</p> -->
|
||||
</article>
|
||||
</RouterLink>
|
||||
</template>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
102
src/views/ClientPayView.vue
Normal file
102
src/views/ClientPayView.vue
Normal file
@ -0,0 +1,102 @@
|
||||
<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'
|
||||
import ShopNav from '../components/ShopNav.vue'
|
||||
|
||||
// To use Html5QrcodeScanner (more info below)
|
||||
import { Html5QrcodeScanner } from "html5-qrcode";
|
||||
|
||||
|
||||
export default {
|
||||
components: { PageTitle, WarningModal, SuccessModal, ClientNav, ShopNav },
|
||||
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>
|
||||
<template v-if="this.$cookies.get('isShop') == 'true'">
|
||||
<ShopNav path="pay"></ShopNav>
|
||||
</template>
|
||||
|
||||
</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>
|
||||
@ -20,12 +20,13 @@ export default {
|
||||
web3: null,
|
||||
token: null,
|
||||
isWaiting: false,
|
||||
log: []
|
||||
log: [],
|
||||
warningLog: []
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this.web3 = new Web3(window.ethereum)
|
||||
this.clientAddr = (await this.web3.eth.getAccounts())[0]
|
||||
this.clientAddr = this.$cookies.get('address')
|
||||
this.web3.eth.defaultAccount = this.clientAddr
|
||||
this.token = new this.web3.eth.Contract(SBT, this.SBTAddress)
|
||||
|
||||
@ -51,7 +52,13 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(this.log)
|
||||
|
||||
var warning = await this.token.getPastEvents("Warning", { fromBlock: 0, toBlock: 'latest', filter: { client: this.clientAddr } })
|
||||
for (let i of warning) {
|
||||
let result = i.returnValues
|
||||
this.warningLog.push(result.bank)
|
||||
}
|
||||
console.log(this.warningLog)
|
||||
},
|
||||
methods: {
|
||||
|
||||
@ -72,7 +79,7 @@ export default {
|
||||
<ul>
|
||||
<li>我們會根據您提供的 SBT 查詢相關信用紀錄,我們會根據紀錄設定給予的每月額度</li>
|
||||
<li>若在前個步驟您 mint 了新的 SBT,代表您不曾擁有過信用紀錄,下表為空。</li>
|
||||
<li>若您不曾擁有過信用交易紀錄,我們提供最低額度 3 ETH/1 month。</li>
|
||||
<li>若您不曾擁有過信用交易紀錄,我們提供最低額度 1 ETH/1 month。</li>
|
||||
<li>請確認下表紀錄,我們將依照該紀錄表計算。</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -120,10 +127,10 @@ export default {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(value, index) of log">
|
||||
<template v-for="(value, index) of warningLog">
|
||||
<tr>
|
||||
<th>{{ index }}</th>
|
||||
<td>{{ value.bank }}</td>
|
||||
<td>{{ value }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
@ -134,7 +141,8 @@ export default {
|
||||
<div class="columns">
|
||||
|
||||
<div class="column is-2 is-offset-5">
|
||||
<RouterLink to="/client" class="button is-primary is-fullwidth is-medium is-outlined">確認</RouterLink>
|
||||
<p class="block">確認完成註冊,請重新登入</p>
|
||||
<RouterLink to="/" class="button is-primary is-fullwidth is-medium is-outlined">確認並完成註冊</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
109
src/views/OrderView.vue
Normal file
109
src/views/OrderView.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<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: { PageTitle },
|
||||
data() {
|
||||
return {
|
||||
SBTAddress: import.meta.env.VITE_SBT_ADDR,
|
||||
BankAddress: import.meta.env.VITE_BANK_ADDR,
|
||||
clientAddr: '',
|
||||
web3: null,
|
||||
token: null,
|
||||
bank: null,
|
||||
link: '',
|
||||
orderId: '',
|
||||
products: [],
|
||||
amount: "0",
|
||||
amountWei: "0",
|
||||
client: '',
|
||||
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 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();
|
||||
console.log(orderData)
|
||||
this.products = orderData.products
|
||||
this.amountWei = orderData.amount
|
||||
this.client = orderData.client
|
||||
this.amount = this.web3.utils.fromWei(orderData.amount, 'ether')
|
||||
this.shop = orderData.shop
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="blog-posts">
|
||||
<div class="container">
|
||||
<div class="block">
|
||||
<PageTitle title="訂單資訊" subtitle=""></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.client }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>店家地址:</th>
|
||||
<td colspan="3">{{ this.shop.address }} ( {{ this.shop.name }} )</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="block">
|
||||
<div class="columns">
|
||||
<div class="column is-2 is-offset-5">
|
||||
<button @click="this.$router.go(-1)" class="button is-danger is-fullwidth is-medium is-outlined">返回</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
166
src/views/PaymentView.vue
Normal file
166
src/views/PaymentView.vue
Normal file
@ -0,0 +1,166 @@
|
||||
<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 })
|
||||
await fetch(import.meta.env.VITE_BACKEND_PREFIX+"/order/"+this.orderId, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({'client': 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>
|
||||
93
src/views/ShopLogView.vue
Normal file
93
src/views/ShopLogView.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<script>
|
||||
import Web3 from 'web3';
|
||||
import SBT from '@/assets/SBT.json'
|
||||
import PageTitle from '../components/PageTitle.vue'
|
||||
import ClientNav from '../components/ClientNav.vue'
|
||||
import ShopNav from '../components/ShopNav.vue'
|
||||
|
||||
export default {
|
||||
components: { PageTitle, ClientNav, ShopNav },
|
||||
data() {
|
||||
return {
|
||||
SBTAddress: import.meta.env.VITE_SBT_ADDR,
|
||||
BankAddress: import.meta.env.VITE_BANK_ADDR,
|
||||
clientAddr: '',
|
||||
web3: null,
|
||||
token: null,
|
||||
log: [],
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
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)
|
||||
|
||||
var borrow = await this.token.getPastEvents("Borrow", { fromBlock: 0, toBlock: 'latest', filter: { shop: this.clientAddr, bank: this.BankAddress } })
|
||||
console.log(borrow)
|
||||
for (let i of borrow) {
|
||||
let result = i.returnValues
|
||||
let obj = {
|
||||
bank: result['bank'],
|
||||
shop: result['shop'],
|
||||
client: result['client'],
|
||||
id: result['id'],
|
||||
amount: this.web3.utils.fromWei(result['amount'], 'ether'),
|
||||
}
|
||||
this.log.push(obj)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="blog-posts">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
<ClientNav path="shoplog"></ClientNav>
|
||||
<template v-if="this.$cookies.get('isShop') == 'true'">
|
||||
<ShopNav path="shoplog"></ShopNav>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="container">
|
||||
<div class="block">
|
||||
<PageTitle title="店家收款紀錄" subtitle="查詢客戶付款狀況"></PageTitle>
|
||||
</div>
|
||||
<div class="block">
|
||||
<h1 class="title is-4">收款紀錄</h1>
|
||||
<table class="table is-fullwidth is-striped is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>客戶</th>
|
||||
<th>銀行</th>
|
||||
<th>帳款編號</th>
|
||||
<th>金額</th>
|
||||
<th>詳細訂單狀況</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(value, index) of log">
|
||||
<tr>
|
||||
<th>{{ index }}</th>
|
||||
<td>{{ value.client }}</td>
|
||||
<td>{{ value.bank }}</td>
|
||||
<td>#{{ value.id }}</td>
|
||||
<td>{{ value.amount }} ETH</td>
|
||||
<td><RouterLink :to="'/order/'+value.id" class="button is-info is-outlined">查詢</RouterLink></td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
55
src/views/ShopPayQRcodeView.vue
Normal file
55
src/views/ShopPayQRcodeView.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<script>
|
||||
import PageTitle from '../components/PageTitle.vue'
|
||||
import ClientNav from '../components/ClientNav.vue'
|
||||
import ShopNav from '../components/ShopNav.vue'
|
||||
import QRCode from 'qrcode';
|
||||
|
||||
export default {
|
||||
components: { PageTitle, ClientNav, ShopNav },
|
||||
data() {
|
||||
return {
|
||||
size: 300,
|
||||
value: "www.google.com"
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
const qrcodeCanvas = this.$refs.qrcodeCanvas;
|
||||
const qrCodeUrl = import.meta.env.VITE_FRONTEND_PREFIX+"/client/pay/"+this.$route.params.id
|
||||
|
||||
QRCode.toCanvas(qrcodeCanvas, qrCodeUrl, (error) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="blog-posts">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
<ClientNav path="shoppay"></ClientNav>
|
||||
<ShopNav path="shoppay"></ShopNav>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="container">
|
||||
<div class="block">
|
||||
<PageTitle title="店家收款 QRcode" subtitle="提供顧客掃描以進行支付"></PageTitle>
|
||||
</div>
|
||||
<div class="block">
|
||||
<canvas id="canvas" ref="qrcodeCanvas"></canvas>
|
||||
</div>
|
||||
<div class="block">
|
||||
<RouterLink to="/shop/pay" class="button is-info is-outlined is-large" @click="send">繼續下一訂單</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
171
src/views/ShopPayView.vue
Normal file
171
src/views/ShopPayView.vue
Normal file
@ -0,0 +1,171 @@
|
||||
<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'
|
||||
import ShopNav from '../components/ShopNav.vue'
|
||||
|
||||
// To use Html5QrcodeScanner (more info below)
|
||||
import { Html5QrcodeScanner } from "html5-qrcode";
|
||||
|
||||
|
||||
export default {
|
||||
components: { PageTitle, WarningModal, SuccessModal, ClientNav, ShopNav },
|
||||
data() {
|
||||
return {
|
||||
SBTAddress: import.meta.env.VITE_SBT_ADDR,
|
||||
BankAddress: import.meta.env.VITE_BANK_ADDR,
|
||||
clientAddr: '',
|
||||
web3: null,
|
||||
token: null,
|
||||
bank: null,
|
||||
warningModalStatus: false,
|
||||
successModalStatus: false,
|
||||
msg: '',
|
||||
isWaiting: false,
|
||||
products: {},
|
||||
productCar: [],
|
||||
orderId: '0'
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this.web3 = new Web3(window.ethereum)
|
||||
if (this.$cookies.isKey('address')) {
|
||||
this.clientAddr = this.$cookies.get('address')
|
||||
} else {
|
||||
console.log("Use default address")
|
||||
this.clientAddr = import.meta.env.VITE_DEFAULT_SHOP
|
||||
}
|
||||
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)
|
||||
|
||||
var result = await fetch(import.meta.env.VITE_BACKEND_PREFIX + "/shop/" + this.clientAddr + "/products")
|
||||
var data = await result.json()
|
||||
for (let product in data['products']) {
|
||||
this.products[product] = data['products'][product]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
amount() {
|
||||
if (!this.web3) {
|
||||
return 0
|
||||
}
|
||||
var ans = 0
|
||||
for (let product of this.productCar) {
|
||||
ans += Number(product['price']) * product['count']
|
||||
}
|
||||
return this.web3.utils.fromWei(ans.toString())
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onScanSuccess(decodedText, decodedResult) {
|
||||
// handle the scanned code as you like, for example:
|
||||
console.log(`Code matched = ${decodedText}`, decodedResult);
|
||||
var product = this.products[decodedText]
|
||||
this.productCar.push({
|
||||
'name': product['name'],
|
||||
'id': product['id'],
|
||||
'price': product['price'],
|
||||
'count': 1
|
||||
})
|
||||
this.scanner.clear()
|
||||
},
|
||||
scan() {
|
||||
this.scanner = new Html5QrcodeScanner(
|
||||
"reader",
|
||||
{ fps: 10, qrbox: { width: 400, height: 400 } },
|
||||
/* verbose= */ false);
|
||||
this.scanner.render(this.onScanSuccess);
|
||||
},
|
||||
async send() {
|
||||
this.isWaiting = true
|
||||
|
||||
var data = {}
|
||||
data['from'] = this.clientAddr
|
||||
data['products'] = []
|
||||
for (let product of this.productCar) {
|
||||
data['products'].push({
|
||||
'product_id': product['id'],
|
||||
'count': product['count']
|
||||
})
|
||||
}
|
||||
try {
|
||||
var result = await fetch(import.meta.env.VITE_BACKEND_PREFIX+"/order", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
this.orderId = await result.json()
|
||||
this.msg = '完成'
|
||||
this.successModalStatus = true
|
||||
} catch (error) {
|
||||
this.msg = '錯誤'
|
||||
this.warningModalStatus = true
|
||||
}
|
||||
this.productCar = []
|
||||
this.isWaiting = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="blog-posts">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
<ClientNav path="shoppay"></ClientNav>
|
||||
<ShopNav path="shoppay"></ShopNav>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="container">
|
||||
<div class="block">
|
||||
<PageTitle title="店家收款" subtitle="掃描商品條碼以加入收款單"></PageTitle>
|
||||
</div>
|
||||
<div class="block">
|
||||
<button class="button is-success is-outlined is-large" @click="scan">掃描商品條碼</button>
|
||||
<div id="reader" width="300px"></div>
|
||||
</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 productCar">
|
||||
<tr>
|
||||
<td>{{ product['name'] }}</td>
|
||||
<td>{{ this.web3.utils.fromWei(product['price']) }} ETH</td>
|
||||
<td><input class="input is-info" type="number" v-model="product['count']">個</td>
|
||||
</tr>
|
||||
</template>
|
||||
<tr>
|
||||
<td colspan="3">共計 {{ amount }} ETH</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="block">
|
||||
<template v-if="!isWaiting">
|
||||
<button class="button is-info is-outlined is-large" @click="send">確認以上訂單</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="button is-info is-outlined is-large is-loading"></button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<WarningModal :active="warningModalStatus" :errorMsg="msg" @closeModal="warningModalStatus = false"></WarningModal>
|
||||
<SuccessModal :active="successModalStatus" :successMsg="msg" @closeModal="successModalStatus = false"
|
||||
:link="`/shop/pay/${this.orderId}`" btnName="繼續"></SuccessModal>
|
||||
</template>
|
||||
@ -7,7 +7,7 @@ import { useClientStore } from '../stores/Client.js'
|
||||
|
||||
export default {
|
||||
components: { PageTitle, WarningModal, SuccessModal },
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
warningModalStatus: false,
|
||||
successModalStatus: false,
|
||||
@ -16,7 +16,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async detect () {
|
||||
async detect() {
|
||||
const provider = await detectEthereumProvider()
|
||||
if (provider) {
|
||||
const chainId = await window.ethereum.request({ method: 'eth_chainId' })
|
||||
@ -72,6 +72,7 @@ export default {
|
||||
</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>
|
||||
<WarningModal :active="warningModalStatus" :errorMsg="msg" @closeModal="warningModalStatus = false"></WarningModal>
|
||||
<SuccessModal :active="successModalStatus" :successMsg="msg" @closeModal="successModalStatus = false"
|
||||
link="/signup/linksbt" btnName="繼續"></SuccessModal>
|
||||
</template>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user