developing

This commit is contained in:
wystan_rin 2024-11-19 20:07:35 +08:00
parent 31a0b7ff4d
commit 9421f798db
23 changed files with 987 additions and 207 deletions

View File

@ -1 +1 @@
from tronscan import Tronscan from .tronscan import Tronscan

View File

@ -1,58 +1,96 @@
from flask import Flask, request, jsonify import os
import subprocess
import sys
from flask import Flask, request, jsonify, make_response
from flask_cors import CORS
from config import get_config from config import get_config
from services.order import OrderService from services.order import OrderService
from services.user import UserService from services.user import UserService
from utils.datetime import parse_time_string, to_milliseconds
app = Flask('app')
CORS(app, resources={r"/*": {"origins": "http://localhost:8080"}})
config = get_config() config = get_config()
config.order.lifetime = to_milliseconds(**parse_time_string(config.order.lifetime))
order_service = OrderService(config)
user_service = UserService(config)
app = Flask(__name__)
order_service = OrderService() @app.after_request
user_service = UserService() def add_cors_headers(response):
response.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8080' # 具体的来源
# response.headers['Access-Control-Allow-Credentials'] = 'true' # 如果需要凭据支持
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
return response
@app.route('/createOrder', methods=['POST']) @app.route('/createOrder', methods=['POST'])
def create_order(): def create_order():
data = request.get_json() data = request.get_json()
payment_method = data.get('paymentMethod', None)
if payment_method not in config['PaymentAddresses']:
return jsonify({
"message": "wrong payment method"
}), 400
quant = data.get('amount', 0)
if quant < config.order.min_quant:
return jsonify({
"message": "Amount below minimum limit."
}), 400
wallet_address = data.get('wallet_address', None)
if wallet_address is None:
name = data.get('name', None) name = data.get('name', None)
phone = data.get('phone', None) phone = data.get('phone', None)
email = data.get('email', None) email = data.get('email', None)
payment_method = data.get('payment_method', None) wallet_addresses = user_service.get_wallet_addresses(name, phone, email)
if payment_method not in config['PaymentAddresses']:
return jsonify({
"message": "Unsupported payment method. Currently, only USDT payments are supported."
}), 400
address = data.get('address', None)
if address is None: if not wallet_addresses:
addresses = user_service.get_addresses(name, phone, email)
if not addresses:
return jsonify({ return jsonify({
"message": "No payment address associated with you was found. Please provide a payment address." "message": "empty wallet address"
}), 400 }), 400
if len(addresses) > 1: if len(wallet_addresses) > 1:
return jsonify({ return jsonify({
"message": "Please select an address to place your order.", "message": "Please select an address to place your order.",
"addresses": addresses "wallet_addresses": wallet_addresses
}), 200 }), 200
# 单个地址 # 单个地址
address = addresses[0] wallet_address = wallet_addresses[0]
order_id = order_service.create_order(address) order_id, create_timestamp = order_service.create_order(quant, wallet_address)
return jsonify({"order_id": order_id}), 200
return jsonify({"orderID": order_id,
"amount": quant,
"orderCreateTimestamp": create_timestamp,
"orderExpirationTime": config.order.lifetime}), 200
order_status = config.order.order_status order_status = config.order.order_status
@app.route('/finishOrder', methods=['GET']) @app.route('/finishOrder', methods=['GET'])
def finish_order(): def finish_order():
data = request.get_json() data = request.get_json()
order_id = data.get('order_id', None) order_id = data.get('orderID', None)
status = order_service.finish_order(order_id) status = order_service.finish_order(order_id)
return jsonify({"order_id": order_id, return jsonify({"order_id": order_id,
"status": status, "status": status,
"msg": order_status[status]}), 200 "msg": order_status[status]}), 200
def run_gunicorn():
# Gunicorn 的命令和参数
command = [sys.executable, '-m', 'gunicorn', 'app:app']
# 启动 Gunicorn
subprocess.run(command)
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True) if os.name == 'nt':
app.run(debug=True, port=5000, host='0.0.0.0')
elif os.name == 'posix':
run_gunicorn()

View File

@ -1,13 +1,14 @@
[APIKey] [APIKey]
tronscan=cc87d361-7cd6-4f69-a57b-f0a77a213355 tronscan = cc87d361-7cd6-4f69-a57b-f0a77a213355
[PaymentAddresses] [PaymentAddresses]
usdt=TB592A5QwHvvcJoCmvALmzT3S9Pux91Gub usdt = TB592A5QwHvvcJoCmvALmzT3S9Pux91Gub
;usdt=TNrzRLi2ArZhiMx51zusBEHHh1qyB9Ldq2
[MYSQL] ;[MYSQL]
user: 'your_mysql_username' ;user = wystan
password: 'your_mysql_password' ;password = Wystan14Brown!
host: 'localhost' ;host = 100.64.0.1
database: 'your_database_name' ;port = 3306
autocommit: false ;database = payment
allow_multi_statements: True ;autocommit = 0

View File

@ -1,4 +1,5 @@
order: order:
min_quant: 30
lifetime: 10min lifetime: 10min
order_status: order_status:
- Timed Out - Timed Out
@ -6,3 +7,10 @@ order:
- Unpaid - Unpaid
- Wrong Amount - Wrong Amount
- Pending - Pending
mysql:
user: wystan
password: Wystan14Brown!
host: 100.64.0.1
port: 3306
database: payment
autocommit: false

View File

@ -15,6 +15,7 @@ from argparse import Namespace
from configparser import ConfigParser from configparser import ConfigParser
import requests import requests
import yaml
from loguru import logger from loguru import logger
random_seed = 20240717 random_seed = 20240717
@ -36,7 +37,7 @@ setup_seed(random_seed)
class Setting: class Setting:
def __init__(self, def __init__(self,
settings:dict = None, settings: dict = None,
config_parser: ConfigParser = None, config_parser: ConfigParser = None,
argument_parser: Namespace = None, argument_parser: Namespace = None,
_visited=None, _visited=None,
@ -44,6 +45,7 @@ class Setting:
**kwargs): **kwargs):
self._parent = _parent self._parent = _parent
if settings is not None:
self.update(_visited=_visited, **settings) self.update(_visited=_visited, **settings)
if config_parser: if config_parser:
@ -61,6 +63,8 @@ class Setting:
cls_attr = getattr(self.__class__, k, None) cls_attr = getattr(self.__class__, k, None)
if callable(cls_attr): if callable(cls_attr):
raise KeyError(f"The key '{k}' conflicts with an existing class method. you can use {k}_ instead.") raise KeyError(f"The key '{k}' conflicts with an existing class method. you can use {k}_ instead.")
if k.startswith('_'):
raise KeyError(f"The key '{k}' is a private attribute.")
if isinstance(v, dict): if isinstance(v, dict):
obj_id = id(v) obj_id = id(v)
if obj_id in _visited: if obj_id in _visited:
@ -69,22 +73,22 @@ class Setting:
else: else:
v = Setting(_visited=_visited, _parent=self, **v) v = Setting(_visited=_visited, _parent=self, **v)
_visited[obj_id] = v _visited[obj_id] = v
self.__dict__[k] = v self[k] = v
def update_config_parser(self, config_parser: ConfigParser): def update_config_parser(self, config_parser: ConfigParser):
for section in config_parser.sections(): for section in config_parser.sections():
section_config = Setting(_parent=self) section_config = Setting(_parent=self)
for option in config_parser.options(section): for option in config_parser.options(section):
section_config[option] = config_parser.get(section, option) section_config[option] = config_parser.get(section, option)
self.__dict__[section] = section_config self[section] = section_config
def update_argument_parser(self, argument_parser: Namespace): def update_argument_parser(self, argument_parser: Namespace):
for k in vars(argument_parser): for k in vars(argument_parser):
self.__dict__[k] = getattr(argument_parser, k) self[k] = getattr(argument_parser, k)
def get(self, item, default=None): def get(self, item, default=None):
if item not in self.__dict__ and self._parent is not None: if item not in self.__dict__ and self._parent is not None:
return self._parent.get(item, default) return self._parent.get(item.lower(), default)
return default return default
def get_int(self, item): def get_int(self, item):
@ -100,21 +104,28 @@ class Setting:
self.__dict__[item] = value self.__dict__[item] = value
def __getitem__(self, item): def __getitem__(self, item):
return self.__dict__[item] return self.__dict__[item.lower()]
def __setitem__(self, key, value): def __setitem__(self, key, value):
self.__dict__[key] = value self.__dict__[key.lower()] = value
def __getattr__(self, key): def __getattr__(self, key):
return self.get(key) return self[key]
def keys(self):
return set(k for k in self.__dict__.keys() if not k.startswith('_'))
def __iter__(self):
for k, v in self.__dict__.items():
yield k, v
def __str__(self): def __str__(self):
def _str_helper(config, indent=0, visited=None): def _str_helper(settings, visited=None, indent_count=0):
if visited is None: if visited is None:
visited = set() visited = set()
lines = [] lines = []
indent_str = ' ' * indent indent_str = ' ' * indent_count
for key, value in config.__dict__.items(): for key, value in settings.__dict__.items():
if key.startswith('_'): if key.startswith('_'):
continue continue
if isinstance(value, Setting): if isinstance(value, Setting):
@ -123,11 +134,29 @@ class Setting:
else: else:
visited.add(id(value)) visited.add(id(value))
lines.append(f"{indent_str}{key}:") lines.append(f"{indent_str}{key}:")
lines.append(_str_helper(value, indent + 1, visited)) lines.append(_str_helper(value, visited=visited, indent_count=indent_count + 1))
else: else:
lines.append(f"{indent_str}{key}: {value}") lines.append(f"{indent_str}{key}: {value}")
return '\n'.join(lines) return '\n'.join(lines)
return _str_helper(self)
def __repr__(self):
def _str_helper(settings, visited=None, indent_count=0):
if visited is None:
visited = set()
lines = []
for key, value in settings.__dict__.items():
if key.startswith('_'):
continue
if isinstance(value, Setting):
if id(value) in visited:
lines.append(f"{key}=<Circular Reference>")
else:
visited.add(id(value))
lines.append(f"{key}={_str_helper(value, visited=visited, indent_count=indent_count + 1)}")
else:
lines.append(f"{key}={value}")
return f'Setting({", ".join(lines)})'
return _str_helper(self) return _str_helper(self)
@ -154,7 +183,7 @@ def get_config(yaml_file=fr'{ROOT_DIR}/config/param.yaml', ini_file=fr'{ROOT_DIR
args = parser.parse_args() args = parser.parse_args()
config.update_argument_parser(args) config.update_argument_parser(args)
if os.path.exists(yaml_file): if os.path.exists(yaml_file):
with open('config.yaml', 'r') as file: with open(yaml_file, 'r') as file:
data = yaml.safe_load(file) data = yaml.safe_load(file)
config.update(data) config.update(**data)
return config return config

View File

@ -1,5 +1,5 @@
from loguru import logger from loguru import logger
from mysql.connector import connect, Error, OperationalError from mysql.connector import connect as connect_mysql, Error, OperationalError
from mysql.connector import errors as db_errors from mysql.connector import errors as db_errors
from custom_decorators import singleton from custom_decorators import singleton
@ -15,9 +15,12 @@ class Database:
def connect(self): def connect(self):
"""Establish a new database connection.""" """Establish a new database connection."""
try: try:
self.connection = connect(**self.config) self.connection = connect_mysql(**self.config)
if self.connection.is_connected(): if self.connection.is_connected():
logger.info("Connected to MySQL database") logger.info("Connected to MySQL database")
except AttributeError as e:
e.args = (f'{e.args[0]} in MYSQL configuration',)
raise
except Error as e: except Error as e:
logger.info(f"Error while connecting to MySQL: {e}") logger.info(f"Error while connecting to MySQL: {e}")
self.connection = None self.connection = None

View File

@ -2,31 +2,31 @@ from utils.database import pack_params
class User: class User:
def __init__(self, id_=None, name=None, phone=None, email=None, address=None, payment_method=None): def __init__(self, id_=None, name=None, phone=None, email=None, wallet_address=None, payment_method=None):
self.id = id_ self.id = id_
self.name = name self.name = name
self.phone = phone self.phone = phone
self.email = email self.email = email
self.address = address self.wallet_address = wallet_address
self.payment_method = payment_method self.payment_method = payment_method
def insert_sql(self, params_format="list"): def insert_sql(self, params_format="list"):
params_sql, params = pack_params(params_format=params_format, param_sql="{param}", join_str=",", params_sql, params = pack_params(params_format=params_format, param_sql="{param}", join_str=",",
name=self.name, phone=self.phone, email=self.email, address=self.address, name=self.name, phone=self.phone, email=self.email, wallet_address=self.wallet_address,
payment_method=self.payment_method) payment_method=self.payment_method)
return f"INSERT INTO user ({params_sql}) VALUES ({','.join('%s' for _ in params)})", params return f"INSERT INTO users ({params_sql}) VALUES ({','.join('%s' for _ in params)})", params
def select_sql(self, condition="AND", params_format="list"): def select_sql(self, condition="AND", params_format="list"):
params_sql, params = pack_params(params_format=params_format, param_sql="{param}=%s", join_str=f" {condition} ", params_sql, params = pack_params(params_format=params_format, param_sql="{param}=%s", join_str=f" {condition} ",
name=self.name, phone=self.phone, email=self.email, address=self.address, name=self.name, phone=self.phone, email=self.email, wallet_address=self.wallet_address,
payment_method=self.payment_method) payment_method=self.payment_method)
return f"SELECT id, name, phone, email, address, payment_method FROM user WHERE {params_sql}", params return f"SELECT id, name, phone, email, wallet_address, payment_method FROM users WHERE {params_sql}", params
def exists_sql(self, condition="AND", params_format="list"): def exists_sql(self, condition="AND", params_format="list"):
params_sql, params = pack_params(params_format=params_format, param_sql="{param}=%s", join_str=f" {condition} ", params_sql, params = pack_params(params_format=params_format, param_sql="{param}=%s", join_str=f" {condition} ",
name=self.name, phone=self.phone, email=self.email, address=self.address, name=self.name, phone=self.phone, email=self.email, wallet_address=self.wallet_address,
payment_method=self.payment_method) payment_method=self.payment_method)
return f"SELECT id FROM user WHERE {params_sql} LIMIT 1", params return f"SELECT id FROM users WHERE {params_sql} LIMIT 1", params
def params(self, format="dict"): def params(self, format="dict"):
if format == "list": if format == "list":
@ -50,11 +50,11 @@ class User:
params.append(self.email) params.append(self.email)
elif format == "dict": elif format == "dict":
params["email"] = self.email params["email"] = self.email
if self.address: if self.wallet_address:
if format == "list": if format == "list":
params.append(self.address) params.append(self.wallet_address)
elif format == "dict": elif format == "dict":
params["address"] = self.address params["wallet_address"] = self.wallet_address
if self.payment_method: if self.payment_method:
if format == "list": if format == "list":
params.append(self.payment_method) params.append(self.payment_method)
@ -70,17 +70,17 @@ class User:
different_attrs["phone"] = (self.phone, other_user.phone) different_attrs["phone"] = (self.phone, other_user.phone)
if self.email != other_user.email: if self.email != other_user.email:
different_attrs["email"] = (self.email, other_user.email) different_attrs["email"] = (self.email, other_user.email)
if self.address != other_user.address: if self.wallet_address != other_user.wallet_address:
different_attrs["address"] = (self.address, other_user.address) different_attrs["wallet_address"] = (self.wallet_address, other_user.wallet_address)
if self.payment_method != other_user.payment_method: if self.payment_method != other_user.payment_method:
different_attrs["payment_method"] = (self.payment_method, other_user.payment_method) different_attrs["payment_method"] = (self.payment_method, other_user.payment_method)
return different_attrs return different_attrs
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, User): if isinstance(other, User):
return ((self.name, self.phone, self.email, self.address, self.payment_method) return ((self.name, self.phone, self.email, self.wallet_address, self.payment_method)
== (other.name, other.phone, other.email, other.address, other.payment_method)) == (other.name, other.phone, other.email, other.wallet_address, other.payment_method))
return False return False
def __hash__(self): def __hash__(self):
return hash((self.name, self.phone, self.email, self.address, self.payment_method)) return hash((self.name, self.phone, self.email, self.wallet_address, self.payment_method))

View File

@ -1,5 +1,3 @@
from ruamel_yaml.util import create_timestamp
from custom_decorators import singleton from custom_decorators import singleton
from database import Database from database import Database
from utils.datetime import current_timestamp from utils.datetime import current_timestamp
@ -10,15 +8,16 @@ class OrderRepository:
def __init__(self, config): def __init__(self, config):
self.db = Database(config['MYSQL']) self.db = Database(config['MYSQL'])
def create(self, order_id, from_address, to_address): def create(self, order_id, quant, from_address, to_address):
cur_time = current_timestamp() timestamp = current_timestamp()
try: try:
self.db.execute_query( self.db.execute_query(
"INSERT INTO orders (order_id, from_address, to_address, create_timestamp, update_timestamp) " "INSERT INTO orders (order_id, quant, from_address, to_address, create_timestamp, update_timestamp) "
"VALUES (%s, %s, %s, %s, %s)", "VALUES (%s, %s, %s, %s, %s, %s)",
[order_id, from_address, to_address, cur_time, cur_time] [order_id, quant, from_address, to_address, timestamp, timestamp]
) )
self.db.commit() self.db.commit()
return timestamp
except Exception: except Exception:
self.db.rollback() self.db.rollback()
raise raise

View File

@ -1,3 +1,7 @@
loguru==0.7.2 loguru==0.7.2
mysql-connector-python==9.1.0 mysql-connector-python==9.1.0
Requests==2.32.3 Requests==2.32.3
flask==3.1.0
gunicorn==23.0.0
pyyaml==6.0.2
flask-cors==5.0.0

View File

@ -3,37 +3,38 @@ import uuid
from custom_decorators import singleton from custom_decorators import singleton
from repositories.order import OrderRepository from repositories.order import OrderRepository
from services.payment import PaymentService from services.payment import PaymentService
from utils.datetime import current, current_timestamp, is_time_difference_greater_than, parse_time_string from utils.datetime import current, current_timestamp, is_time_difference_greater_than
@singleton @singleton
class OrderService: class OrderService:
def __init__(self, config): def __init__(self, config):
self.config = config self.config = config
self.payment_service = PaymentService() self.payment_service = PaymentService(config.APIKey.tronscan)
self.order_repo = OrderRepository(config) self.order_repo = OrderRepository(config)
def create_order(self, address=None): def create_order(self, quant, address):
date_str = current().strftime('%Y%m%d%H%M%S') date_str = current().strftime('%Y%m%d%H%M%S')
unique_id = str(uuid.uuid4()).split('-')[0] unique_id = str(uuid.uuid4()).split('-')[0]
order_id = f"{date_str}-{unique_id}" order_id = f"{date_str}-{unique_id}"
self.order_repo.create(order_id, address, create_timestamp = self.order_repo.create(order_id, quant,
self.config['PaymentAddresses']) address, self.config['PaymentAddresses'])
return order_id return order_id, create_timestamp
def finish_order(self, order_id): def finish_order(self, order_id):
# 判断支付时间是否超过订单存活时间 # 判断支付时间是否超过订单存活时间
status = 2 status = 2
now = current_timestamp() now = current_timestamp()
quant, from_address, to_address, create_timestamp = self.order_repo.get_order_info(order_id) quant, from_address, to_address, create_timestamp = self.order_repo.get_order_info(order_id)
if is_time_difference_greater_than(create_timestamp, now, **parse_time_string(self.config.order.lifetime)): if is_time_difference_greater_than(create_timestamp, now, milliseconds=self.config.order.lifetime):
# 订单超时 # 订单超时
status = 0 status = 0
else: else:
correct_quant, confirmed = self.payment_service.check_payment(quant, correct_quant, confirmed = self.payment_service.check_payment(quant,
from_address, to_address, from_address, to_address,
create_timestamp, now) # 减去十秒, 避免网络延迟导致的订单创建时间太晚
create_timestamp - 10, now)
if correct_quant and confirmed: if correct_quant and confirmed:
# 支付成功 # 支付成功
status = 1 status = 1

View File

@ -9,7 +9,7 @@ class UserService:
self.config = config self.config = config
self.user_repo = UserRepository(config) self.user_repo = UserRepository(config)
def get_addresses(self, name=None, phone=None, email=None): def get_wallet_addresses(self, name=None, phone=None, email=None):
if phone or email: if phone or email:
users = self.user_repo.get_or_create(User(name=name, phone=phone, email=email)) users = self.user_repo.get_or_create(User(name=name, phone=phone, email=email))
addresses = set(user.address for user in users if user.address) addresses = set(user.address for user in users if user.address)

View File

@ -7,10 +7,10 @@ def current():
def current_timestamp(): def current_timestamp():
datetime.datetime.now().timestamp() return int(datetime.datetime.now().timestamp() * 1000)
def is_time_difference_greater_than(timestamp1, timestamp2, hours=0, minutes=0, seconds=0): def is_time_difference_greater_than(timestamp1, timestamp2, hours=0, minutes=0, seconds=0, milliseconds=0):
""" """
判断两个时间戳的时间差是否大于指定的小时分钟和秒数 判断两个时间戳的时间差是否大于指定的小时分钟和秒数
@ -25,14 +25,14 @@ def is_time_difference_greater_than(timestamp1, timestamp2, hours=0, minutes=0,
bool: 如果时间差大于指定的小时分钟和秒数返回True否则返回False bool: 如果时间差大于指定的小时分钟和秒数返回True否则返回False
""" """
# 将时间戳转换为 datetime 对象 # 将时间戳转换为 datetime 对象
time1 = datetime.fromtimestamp(timestamp1) time1 = datetime.fromtimestamp(timestamp1) / 1000.0
time2 = datetime.fromtimestamp(timestamp2) time2 = datetime.fromtimestamp(timestamp2) / 1000.0
# 计算时间差 # 计算时间差
time_difference = abs(time2 - time1) time_difference = abs(time2 - time1)
# 计算指定的时间差值 # 计算指定的时间差值
threshold = datetime.timedelta(hours=hours, minutes=minutes, seconds=seconds) threshold = datetime.timedelta(hours=hours, minutes=minutes, seconds=seconds, milliseconds=milliseconds)
# 判断时间差是否大于指定的时间 # 判断时间差是否大于指定的时间
return time_difference > threshold return time_difference > threshold
@ -44,7 +44,8 @@ def parse_time_string(time_str):
'd': 'days', 'd': 'days',
'h': 'hours', 'h': 'hours',
'min': 'minutes', 'min': 'minutes',
's': 'seconds' 's': 'seconds',
'ms': 'milliseconds'
} }
# 使用正则表达式匹配数字和单位的模式 # 使用正则表达式匹配数字和单位的模式
@ -61,3 +62,6 @@ def parse_time_string(time_str):
raise ValueError(f"Unsupported unit: {unit}") raise ValueError(f"Unsupported unit: {unit}")
return result return result
def to_milliseconds(days=0, hours=0, minutes=0, seconds=0, milliseconds=0):
return days * 24 * 60 * 60 * 1000 + hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000 + milliseconds

View File

@ -1,2 +1,3 @@
def convert_to_tronscan_timestamp(timestamp): def convert_to_tronscan_timestamp(timestamp):
return int(timestamp * 1000) # return int(timestamp * 1000)
return timestamp

View File

@ -1,3 +1,5 @@
.idea
# Python: # Python:
*.ipynb *.ipynb
*/__pycache__ */__pycache__
@ -12,7 +14,6 @@ docs/build
venv venv
build build
dist dist
.idea
htmlcov/ htmlcov/
.coverage .coverage
.pytest_cache/ .pytest_cache/

View File

@ -0,0 +1 @@
.el-card[data-v-0f66bda2] .el-card__header{padding:calc(var(--el-card-padding) - 2px) var(--el-card-padding);border-bottom:1px solid var(--el-card-border-color)}.description[data-v-0f66bda2]{margin-bottom:15px;padding:10px 20px 12px;color:#0d236d;-webkit-text-size-adjust:none;background:rgba(52,100,255,.1);border:1px solid rgba(52,100,255,.3);font:12px Microsoft YaHei,Arial}.description p.title[data-v-0f66bda2]{line-height:30px}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,238 @@
body {
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 0;
background-color: #f4f7fa;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
background: white;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
max-width: 500px;
padding: 20px 30px;
}
h1 {
text-align: center;
color: #333;
}
.tips {
background-color: #eef3ff;
border-left: 4px solid #5b8def;
padding: 15px;
margin-bottom: 20px;
border-radius: 4px;
font-size: 14px;
color: #333;
}
.special-notice {
background-color: #d6e4ff;
padding: 1vh;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
font-weight: 500;
margin-bottom: 5px;
color: #555;
}
.form-group input[type="text"],
.form-group input[type="email"],
.form-group input[type="number"] {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.form-group input:focus {
border-color: #5b8def;
outline: none;
box-shadow: 0 0 5px rgba(91, 141, 239, 0.2);
}
.form-group input[type="radio"] {
margin-right: 10px;
}
.payment-container {
display: flex;
align-items: center;
gap: 10px;
}
.payment-label {
font-weight: 500;
margin-right: 10px;
}
.payment-option {
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #ccc;
border-radius: 5px;
padding: 8px 15px;
cursor: pointer;
transition: border-color 0.3s, background-color 0.3s;
}
.payment-option.selected {
border: 2px solid #5b8def;
background-color: rgba(91, 141, 239, 0.1);
}
.payment-option input[type="radio"] {
display: none;
}
.payment-option span {
margin-left: 5px;
color: #333;
}
.payment-option img {
width: 24px;
height: 24px;
}
.dot {
width: 12px;
height: 12px;
background-color: #5b8def;
border-radius: 50%;
margin-right: 8px;
}
.payment-option.selected .dot {
background-color: #007bff;
}
button {
width: 100%;
padding: 12px;
background-color: #5b8def;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #487acc;
}
.el-icon {
--color: inherit;
height: 1em;
width: 1em;
line-height: 1em;
display: inline-flex;
justify-content: center;
align-items: center;
position: relative;
fill: currentColor;
color: var(--color);
font-size: inherit;
}
.modal {
display: none; /* 初始隐藏 */
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
align-items: center;
justify-content: center;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 8px;
width: 90%;
max-width: 46vh;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
position: relative;
}
.close-btn {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
position: absolute;
top: 10px;
right: 20px;
cursor: pointer;
}
.close-btn:hover,
.close-btn:focus {
color: black;
}
.modal-header h2 {
display: flex;
justify-content: center; /* 标题居中 */
align-items: center;
position: relative;
}
.modal-body {
max-height: 45vh;
overflow-y: auto;
display: flex; /* 添加 Flexbox */
flex-direction: column; /* 垂直排列子元素 */
align-items: center; /* 水平居中 */
justify-content: center; /* 垂直居中 */
text-align: center;
}
.modal-footer {
margin-top: 15px;
text-align: center;
}
.qr-code {
margin-top: 15px;
max-width: 100%;
height: auto;
max-height: 200px;
display: block;
}
.payment-address {
margin-top: 10px;
font-size: 14px;
word-break: break-all;
text-align: center;
}
.address-option {
padding: 10px;
border-bottom: 1px solid #ccc;
cursor: pointer;
}
.address-option:hover {
background: #f1f1f1;
}

BIN
payment_headend/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -1,131 +1,153 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh-CN"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>创建订单</title> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<style> <title>Recharge Page</title>
/* 简单的样式 */ <link href="/css/modules.fdcec670.css" rel="stylesheet"/>
.hidden { display: none; } <link rel="stylesheet" href="/css/styles.css"/>
.error { color: red; } <link rel="preload" href="/index.js" as="script">
</style> <script src="/index.js"></script>
</head> </head>
<body> <body>
<h1>创建订单</h1> <div class="container">
<form id="order-form"> <h1>Recharge</h1>
<label for="phone">手机号:</label> <div class="tips">
<input type="text" id="phone" name="phone"><br><br> <p>Kind Reminder:</p>
<ol>
<label for="email">邮箱:</label> <li>Currently, only USDT deposits are supported, and balances can be withdrawn. Other deposit methods are under development. Please stay tuned for announcements regarding their release.</li>
<input type="email" id="email" name="email"><br><br> <li>The deposit amount will be credited within 1 minute after payment. If it does not arrive within 5 minutes, please contact customer support and provide your U address, deposit screenshot, transaction ID, and account name.</li>
<li>The actual amount credited for USDT deposits must match the amount displayed on the USDT deposit payment page; otherwise, the deposit will not be credited. Please be informed.</li>
<label for="address">地址:</label> </ol>
<input type="text" id="address" name="address"><br><br> <div class="special-notice">
<strong>Special Notice:</strong> Please ensure the recipient address is correct when making a transfer!
<button type="submit">提交订单</button> </div>
</form> </div>
<form>
<div id="message" class="hidden"></div> <div class="form-group">
<div id="addresses" class="hidden"> <label>Payment method:</label>
<h2>请选择一个地址:</h2> <div class="el-form-item el-form-item--default" data-v-0f66bda2="">
<ul id="address-list"></ul> <div class="el-form-item__content">
<i class="el-icon"
data-v-0f66bda2=""
style="font-size: 30px">
<svg
t="1693061019040"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="4072"
width="200"
height="200"
data-v-0f66bda2="">
<path
d="M1023.082985 511.821692c0 281.370746-228.08199 509.452736-509.452736 509.452736-281.360557 0-509.452736-228.08199-509.452737-509.452736 0-281.365652 228.092179-509.452736 509.452737-509.452737 281.370746 0 509.452736 228.087085 509.452736 509.452737"
fill="#1BA27A"
p-id="4073"></path>
<path
d="M752.731701 259.265592h-482.400796v116.460896h182.969951v171.176119h116.460895v-171.176119h182.96995z"
fill="#FFFFFF"
p-id="4074"></path>
<path
d="M512.636816 565.13592c-151.358408 0-274.070289-23.954468-274.070289-53.50782 0-29.548259 122.706786-53.507821 274.070289-53.507821 151.358408 0 274.065194 23.959562 274.065194 53.507821 0 29.553353-122.706786 53.507821-274.065194 53.50782m307.734925-44.587303c0-38.107065-137.776398-68.995184-307.734925-68.995184-169.953433 0-307.74002 30.888119-307.74002 68.995184 0 33.557652 106.837333 61.516418 248.409154 67.711363v245.729433h116.450707v-245.632637c142.66205-6.001353 250.615085-34.077294 250.615084-67.808159"
fill="#FFFFFF"
p-id="4075"></path>
</svg>
</i>
<div data-v-0f66bda2="" style="margin-left: 20px">
<div class="el-radio-group" role="radiogroup" aria-labelledby="el-id-7163-5" data-v-0f66bda2=""
id="el-id-7163-12">
<label class="el-radio is-bordered is-checked el-radio--default" data-v-0f66bda2="">
<span class="el-radio__input is-checked">
<input class="el-radio__original" name="el-id-7163-6" type="radio" value="30"
onclick="setAmountValue(this.value)"/>
<span class="el-radio__inner"></span>
</span>
<span class="el-radio__label">30U</span>
</label>
<label class="el-radio is-bordered el-radio--default" data-v-0f66bda2="">
<span class="el-radio__input">
<input class="el-radio__original" name="el-id-7163-6" type="radio" value="90"
onclick="setAmountValue(this.value)"/>
<span class="el-radio__inner"></span>
</span>
<span class="el-radio__label">90U</span>
</label>
<label class="el-radio is-bordered el-radio--default" data-v-0f66bda2="">
<span class="el-radio__input">
<input class="el-radio__original" name="el-id-7163-6" type="radio"
value="150" onclick="setAmountValue(this.value)"/>
<span class="el-radio__inner"></span>
</span>
<span class="el-radio__label">150U</span>
</label>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="amount">Amount:</label>
<input type="number" id="amount" value="30" min="30" step="any" tabindex="0" autocomplete="off"
style="width: 18%;"> (USDT)
</div>
<div class="form-group">
<label for="nickname">Name:</label>
<input type="text" id="nickname" placeholder="Please enter your Nickname.">
</div>
<div class="form-group">
<label for="phone">Phone:</label>
<input type="text" id="phone" placeholder="Please enter your phone number.">
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" placeholder="Please enter your email.">
</div>
<div class="form-group">
<label for="wallet">Wallet address:</label>
<input type="text" id="wallet" placeholder="Enter your wallet address.">
</div>
<button type="button" onclick="handleSubmit()">Gain Points Now!!!</button>
</form>
</div> </div>
<div id="error" class="error hidden"></div>
<div id="addressModal" class="modal" style="display: none;">
<div class="modal-content">
<div class="modal-header">
<h2>Select a wallet address</h2>
</div>
<div class="modal-body" id="addressList"></div>
<div class="modal-footer">
<button id="closeAddress">Enter a new wallet address.</button>
</div>
</div>
</div>
<div id="paymentModal" class="modal" style="display: none;">
<div class="modal-content">
<span id="closePayment" class="close-btn">&times;</span>
<div class="modal-body">
<h2>Payment Information</h2>
<div id="orderInfo"></div>
<img src="/img/wallet_QRCode_detail.png" alt="付款二维码" class="qr-code">
<div class="payment-address">Wallet address: TNrzRLi2ArZhiMx51zusBEHHh1qyB9Ldq2
<button onclick="copyText('TNrzRLi2ArZhiMx51zusBEHHh1qyB9Ldq2')" id="copyAddress"
style="all: unset; cursor: pointer; margin-left: 10px; background-color: #00bfff; color: #fff; border: none; padding: 5px 10px;border-radius: 3px;">
copy
</button>
</div>
</div>
<div class="modal-footer">
<button id="completeBtn" style="width: 11vh">Paid</button>
</div>
</div>
</div>
<script> <script>
async function createOrder(phone = "", email = "", address = "") { function copyText(text) {
try { navigator.clipboard.writeText(text).then(() => {
const response = await fetch('/create_order', { document.getElementById('copyAddress').textContent = 'Copied';
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ phone, email, address })
}); });
const data = await response.json();
if (response.ok) {
if (data.order_id) {
handleOrderSuccess(data.order_id);
} else if (data.addresses && Array.isArray(data.addresses)) {
handleMultipleAddresses(data.addresses);
} }
} else {
if (data.message === "地址不能为空,请输入地址。") {
promptUserForAddress();
} else {
handleError(data.message || '发生未知错误。');
}
}
} catch (error) {
console.error('网络或服务器错误:', error);
handleError('网络或服务器错误,请稍后再试。');
}
}
function handleOrderSuccess(orderId) {
document.getElementById('message').innerText = `订单创建成功!您的订单号是:${orderId}`;
document.getElementById('message').classList.remove('hidden');
document.getElementById('addresses').classList.add('hidden');
document.getElementById('error').classList.add('hidden');
}
function handleMultipleAddresses(addresses) {
const addressList = document.getElementById('address-list');
addressList.innerHTML = ''; // 清空现有列表
addresses.forEach((addr, index) => {
const li = document.createElement('li');
const button = document.createElement('button');
button.innerText = `选择地址 ${index + 1}`;
button.addEventListener('click', () => {
// 选择地址后重新提交订单
createOrder(null, null, addr);
});
li.innerText = addr + ' ';
li.appendChild(button);
addressList.appendChild(li);
});
document.getElementById('addresses').classList.remove('hidden');
document.getElementById('message').classList.add('hidden');
document.getElementById('error').classList.add('hidden');
}
function promptUserForAddress() {
const address = prompt('地址不能为空,请输入您的地址:');
if (address && address.trim() !== "") {
createOrder(null, null, address.trim());
} else {
handleError('地址输入为空,无法创建订单。');
}
}
function handleError(message) {
const errorDiv = document.getElementById('error');
errorDiv.innerText = `错误:${message}`;
errorDiv.classList.remove('hidden');
document.getElementById('message').classList.add('hidden');
document.getElementById('addresses').classList.add('hidden');
}
// 绑定表单提交事件
document.getElementById('order-form').addEventListener('submit', function(event) {
event.preventDefault(); // 阻止表单默认提交行为
// 获取表单输入值
const phone = document.getElementById('phone').value.trim();
const email = document.getElementById('email').value.trim();
const address = document.getElementById('address').value.trim();
// 清除之前的消息
document.getElementById('message').classList.add('hidden');
document.getElementById('addresses').classList.add('hidden');
document.getElementById('error').classList.add('hidden');
// 调用createOrder函数
createOrder(phone, email, address);
});
</script> </script>
</body> </body>
</html> </html>

View File

@ -1 +1,250 @@
console.log('Happy developing ✨') document.addEventListener('DOMContentLoaded', () => {
const options = document.querySelectorAll('.el-radio');
options.forEach(option => {
option.addEventListener('click', selectAmount);
});
function selectAmount(event) {
const options = document.querySelectorAll('.el-radio.is-checked');
options.forEach(option => {
option.classList.remove('is-checked');
option.querySelector('.el-radio__input').classList.remove('is-checked');
});
event.currentTarget.classList.add('is-checked');
event.currentTarget.querySelector('.el-radio__input').classList.add('is-checked');
// 获取选中的输入值并更新到 id="amount" 的元素
document.getElementById('amount').value = event.currentTarget.querySelector('input').value; // 显示金额
}
// Modal functionality
const closeAddress = document.getElementById('closeAddress');
closeAddress.addEventListener('click', () => {
document.getElementById('wallet').focus()
document.getElementById('addressModal').style.display = 'none';
});
const closePayment = document.getElementById('closePayment');
closePayment.addEventListener('click', () => {
document.getElementById('paymentModal').style.display = 'none';
});
const completeBtn = document.getElementById('completeBtn');
completeBtn.addEventListener('click', () => {
closePaymentModal();
finishOrder();
});
// Close modal when clicking outside the modal content
document.getElementById('addressModal').addEventListener('click', closeModalOnClickOutside);
document.getElementById('paymentModal').addEventListener('click', closeModalOnClickOutside);
});
function finishOrder() {
const orderID = localStorage.getItem('currentOrderID'); // 获取订单 ID
if (!orderID) {
console.error('Order ID is not available.');
handleError('Order ID is not available. Please create an order first.');
return;
}
const url = `/finishOrder?orderID=${orderID}`;
return fetch(url, {
method: 'GET'
})
.then(response => {
if (!response.ok) {
throw new Error(`Network response was not ok: ${response.statusText}`);
}
return response.json();
})
.then(data => {
console.log('Response data:', data);
return data;
})
.catch(error => {
console.error('There was a problem with the GET request:', error);
throw error;
});
}
function handleOrderSuccess(orderId, amount, orderCreateTimestamp, orderExpirationTime) {
openPaymentModal(orderId, amount, orderCreateTimestamp, orderExpirationTime);
}
// Function to show the modal with addresses
function handleMultipleAddresses(walletAddresses) {
// Find the modal and the modal body
const addressList = document.getElementById('addressList');
addressList.innerHTML = ''; // 清空当前内容
// Create a list of wallet addresses
walletAddresses.forEach(address => {
const div = document.createElement('div');
div.className = 'address-option';
div.textContent = address;
div.addEventListener('click', () => {
document.getElementById('wallet').value = address;
closeAddressModal();
handleSubmit();
});
addressList.appendChild(div);
});
openAddressModal();
}
// Function to show the modal with an image
function showImageModal(imageUrl, walletAddress) {
// Find the modal and modal body
const modal = document.getElementById('modal');
const modalBody = document.getElementById('modalBody');
// Clear any previous content
modalBody.innerHTML = '';
// Create an image element
const imageElement = document.createElement('img');
imageElement.src = imageUrl;
imageElement.alt = 'Image';
imageElement.style.maxWidth = '100%';
imageElement.style.maxHeight = '80vh'; // Limit the height for better UX
// Create a div to display the wallet address
const addressDiv = document.createElement('div');
addressDiv.textContent = walletAddress;
addressDiv.style.marginTop = '10px';
addressDiv.style.fontSize = '16px';
addressDiv.style.color = '#333';
// Add image and address to modal body
modalBody.appendChild(imageElement);
modalBody.appendChild(addressDiv);
openAddressModal();
}
function openPaymentModal(orderId, amount, orderCreateTimestamp, orderExpirationTime) {
document.getElementById('paymentModal').style.display = 'flex';
// 显示订单ID
const orderInfoElement = document.getElementById('orderInfo');
orderInfoElement.innerHTML = `<p>Order ID: ${orderId}</p>`;
// 计算剩余支付时间 (以秒为单位)
const expirationTime = orderCreateTimestamp + orderExpirationTime; // 10 分钟后的时间戳(单位:毫秒)
const updateRemainingTime = () => {
const now = new Date().getTime();
const remainingTime = Math.max(0, expirationTime - now);
const minutes = Math.floor((remainingTime / 1000 / 60) % 60);
const seconds = Math.floor((remainingTime / 1000) % 60);
// 更新剩余时间
orderInfoElement.innerHTML = `<p>Order ID: ${orderId}, You need to pay <span style="color: red">${amount}</span>USDT.</p>`;
orderInfoElement.innerHTML += `<p style="color: red">Time remaining: ${minutes} minutes ${seconds} seconds</p>`;
// 如果时间到了,停止更新
if (remainingTime <= 0) {
clearInterval(interval);
orderInfoElement.innerHTML = `<p style="color: red">Order ${orderId} has expired, please place a new order.</p>`;
}
};
// 开始倒计时
const interval = setInterval(updateRemainingTime, 1000);
updateRemainingTime(); // 立即更新一次
}
function closePaymentModal() {
document.getElementById('paymentModal').style.display = 'none';
}
function openAddressModal() {
document.getElementById('addressModal').style.display = 'flex';
}
function closeAddressModal() {
document.getElementById('addressModal').style.display = 'none';
}
function closeModalOnClickOutside(event) {
const modals = document.querySelectorAll('.modal');
modals.forEach(modal => {
const modalContent = modal.querySelector('.modal-content');
if (!modalContent.contains(event.target) && modal.style.display === 'flex') {
modal.style.display = 'none';
}
});
}
function promptUserForPaymentMethod() {
handleError('Unsupported payment method. Currently, only USDT payments are supported.');
}
function handleError(message) {
const errorDiv = document.getElementById('error');
errorDiv.innerText = `错误:${message}`;
errorDiv.classList.remove('hidden');
document.getElementById('message').classList.add('hidden');
document.getElementById('addresses').classList.add('hidden');
}
function promptUserForAddress() {
const address = prompt('No payment address associated with this phone number was found. Please enter a payment address or provide additional information.');
if (address && address.trim() !== "") {
createOrder(null, null, address.trim());
} else {
handleError('No payment address associated with you was found. Please provide a payment address.');
}
}
async function createOrder(amount, name, phone, email, wallet_address, paymentMethod) {
try {
const response = await fetch('http://127.0.0.1:5000/createOrder', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({amount, name, phone, email, wallet_address, paymentMethod})
});
const data = await response.json(); // 确保正确解析响应
if (response.ok) {
if (data.orderID) {
localStorage.setItem('currentOrderID', data.orderID); // 保存订单 ID 到 localStorage
handleOrderSuccess(data.orderID, amount, data.orderCreateTimestamp, data.orderExpirationTime);
} else if (data.wallet_addresses && Array.isArray(data.wallet_addresses)) {
handleMultipleAddresses(data.wallet_addresses);
}
} else {
if (data.message === "wrong payment method") {
promptUserForPaymentMethod();
} else if (data.message === "empty wallet address") {
promptUserForAddress();
} else {
handleError(data.message || 'Unknown error.');
}
}
} catch (error) {
console.error('Network or server error:', error);
handleError('Network or server error. Please try again later.');
}
}
// 绑定表单提交事件
function handleSubmit() {
const amount = document.getElementById('amount').value.trim();
const name = document.getElementById('nickname').value.trim();
const phone = document.getElementById('phone').value.trim();
const email = document.getElementById('email').value.trim();
const payment_address = document.getElementById('wallet').value.trim();
// 清除之前的消息
// document.getElementById('message').classList.add('hidden');
// 调用createOrder函数
createOrder(amount, name, phone, email, payment_address, "USDT");
}

177
payment_headend/index1.html Normal file
View File

@ -0,0 +1,177 @@
<html lang="en" class=" ">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
<title>余额充值 - API管理平台</title>
<link href="/css/modules.fdcec670.css" rel="stylesheet" />
<link href="/css/app.f2b97341.css" rel="stylesheet" />
<link rel="stylesheet" type="text/css" href="/css/admin-system-adminMoneyRecharge.5cf4644c.css"
<link rel="stylesheet" type="text/css" href="/css/styles.css"/>
<link rel="preload" href="/index.js" as="script">
</head>
<body inmaintabuse="1" data-layout="default">
<div id="app" class="aminui" data-v-app="">
<section class="aminui-wrapper">
<div class="aminui-body el-container">
<div class="adminui-main" id="adminui-main">
<main class="el-main" data-v-0f66bda2="">
<div class="el-card is-always-shadow" data-v-0f66bda2="">
<div class="el-card__header">
<div class="card-header" data-v-0f66bda2="">
<span data-v-0f66bda2="">充值</span>
</div>
</div>
<div class="el-card__body" style="">
<div class="el-scrollbar table-form-scrollbar" data-v-0f66bda2="">
<div class="el-scrollbar__wrap el-scrollbar__wrap--hidden-default">
<div class="el-scrollbar__view" style="">
<div data-v-0f66bda2="">
<section class="description" data-v-0f66bda2="">
<p class="title" data-v-0f66bda2="">温馨提示:</p>
<p data-v-0f66bda2="">
1、目前仅支持USDT充值充值的金额不支持提现
</p>
<p data-v-0f66bda2="">
2、金额会在支付后1分钟内到账如果5分钟未到账请联系客服
</p>
<p data-v-0f66bda2="" style="color: red">
3、实际转账金额必须与支付页面显示金额一致否则无法到账
</p>
</section>
<div class="el-form-item el-form-item--default" data-v-0f66bda2="">
<label id="el-id-7163-5" for="el-id-7163-12" class="el-form-item__label">Payment method:</label>
<div class="el-form-item__content">
<i class="el-icon"
data-v-0f66bda2=""
style="font-size: 30px">
<svg
t="1693061019040"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="4072"
width="200"
height="200"
data-v-0f66bda2="">
<path
d="M1023.082985 511.821692c0 281.370746-228.08199 509.452736-509.452736 509.452736-281.360557 0-509.452736-228.08199-509.452737-509.452736 0-281.365652 228.092179-509.452736 509.452737-509.452737 281.370746 0 509.452736 228.087085 509.452736 509.452737"
fill="#1BA27A"
p-id="4073"></path>
<path
d="M752.731701 259.265592h-482.400796v116.460896h182.969951v171.176119h116.460895v-171.176119h182.96995z"
fill="#FFFFFF"
p-id="4074"></path>
<path
d="M512.636816 565.13592c-151.358408 0-274.070289-23.954468-274.070289-53.50782 0-29.548259 122.706786-53.507821 274.070289-53.507821 151.358408 0 274.065194 23.959562 274.065194 53.507821 0 29.553353-122.706786 53.507821-274.065194 53.50782m307.734925-44.587303c0-38.107065-137.776398-68.995184-307.734925-68.995184-169.953433 0-307.74002 30.888119-307.74002 68.995184 0 33.557652 106.837333 61.516418 248.409154 67.711363v245.729433h116.450707v-245.632637c142.66205-6.001353 250.615085-34.077294 250.615084-67.808159"
fill="#FFFFFF"
p-id="4075"></path>
</svg>
</i>
<div data-v-0f66bda2="" style="margin-left: 20px">
<div class="el-radio-group" role="radiogroup" aria-labelledby="el-id-7163-5" data-v-0f66bda2="" id="el-id-7163-12">
<label class="el-radio is-bordered is-checked el-radio--default" data-v-0f66bda2="">
<span class="el-radio__input is-checked">
<input class="el-radio__original" name="el-id-7163-6" type="radio" value="30" onclick="setAmountValue(this.value)"/>
<span class="el-radio__inner"></span>
</span>
<span class="el-radio__label">30$</span>
</label>
<label class="el-radio is-bordered el-radio--default" data-v-0f66bda2="">
<span class="el-radio__input">
<input class="el-radio__original" name="el-id-7163-6" type="radio" value="90" onclick="setAmountValue(this.value)"/>
<span class="el-radio__inner"></span>
</span>
<span class="el-radio__label">90$</span>
</label>
<label class="el-radio is-bordered el-radio--default" data-v-0f66bda2="">
<span class="el-radio__input">
<input class="el-radio__original" name="el-id-7163-6" type="radio" value="150" onclick="setAmountValue(this.value)"/>
<span class="el-radio__inner"></span>
</span>
<span class="el-radio__label">150$</span>
</label>
</div>
</div>
</div>
</div>
<div class="el-form-item el-form-item--default" data-v-0f66bda2="">
<label id="amount_label" for="amount_input" class="el-form-item__label">Amount:</label>
<div class="el-form-item__content">
<div class="el-input el-input--default" data-v-0f66bda2="" style="width: 7em">
<div class="el-input__wrapper">
<input class="el-input__inner" type="number" min="30" step="any" autocomplete="off" tabindex="0"
id="amount_input" value="30"/>
</div>
</div>USDT
</div>
</div>
<div class="el-form-item el-form-item--default" data-v-0f66bda2="">
<label id="name_label" for="name_input" class="el-form-item__label">Name:</label>
<div class="el-form-item__content">
<div class="el-input el-input--default" data-xv-0f66bda2="">
<div class="el-input__wrapper">
<input class="el-input__inner" type="text" autocomplete="off" tabindex="0" placeholder="Please enter your Nickname." id="name_input"/>
</div>
</div>
</div>
</div>
<div class="el-form-item el-form-item--default" data-v-0f66bda2="">
<label id="phone_label" for="phone_input" class="el-form-item__label">Phone:</label>
<div class="el-form-item__content">
<div class="el-input el-input--default" data-v-0f66bda2="">
<div class="el-input__wrapper">
<input class="el-input__inner" type="tel" autocomplete="off" tabindex="0" placeholder="Please enter your phone number." id="phone_input"/>
</div>
</div>
</div>
</div>
<div class="el-form-item el-form-item--default" data-v-0f66bda2="">
<label id="email_label" for="email_input" class="el-form-item__label">Email:</label>
<div class="el-form-item__content">
<div class="el-input el-input--default" data-v-0f66bda2="">
<div class="el-input__wrapper">
<input class="el-input__inner" type="email" autocomplete="off" tabindex="0" placeholder="Please enter your email." id="email_input"/>
</div>
</div>
</div>
</div>
<div class="el-form-item el-form-item--default" data-v-0f66bda2="">
<label id="address_label" for="address_input" class="el-form-item__label">Wallet address:</label>
<div class="el-form-item__content">
<div class="el-input el-input--default" data-v-0f66bda2="">
<div class="el-input__wrapper">
<input class="el-input__inner" type="text" autocomplete="off" tabindex="0" placeholder="Please enter your wallet address." id="address_input"/>
</div>
</div>
</div>
</div>
<button class="el-button el-button--primary el-button--default" type="button" data-v-0f66bda2="" onclick="handleSubmit()">
<span class="">Gain Points Now!!!</span>
</button>
</div>
</div>
</div>
<div class="el-scrollbar__bar is-horizontal" style="display: none">
<div class="el-scrollbar__thumb" style="transform: translateX(0%)"></div>
</div>
<div class="el-scrollbar__bar is-vertical" style="display: none">
<div class="el-scrollbar__thumb" style="transform: translateY(0%)"></div>
</div>
</div>
</div>
</div>
<div class="el-overlay" style="z-index: 2002; display: none">
<div role="dialog" aria-modal="true" aria-label="支付" aria-describedby="el-id-7163-9" class="el-overlay-dialog"></div>
</div>
</main>
</div>
</div>
</section>
</div>
</body>
</html>

BIN
payment_headend/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB