244 lines
9.9 KiB
Python
244 lines
9.9 KiB
Python
from django.shortcuts import render, redirect
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.contrib.auth import login, authenticate
|
|
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
|
|
from django.http import JsonResponse
|
|
from django.contrib.auth.models import User
|
|
from django.contrib import messages
|
|
from .models import Account, Order, Transaction, Cryptocurrency, SiteSettings
|
|
import random
|
|
import decimal
|
|
import json
|
|
from django.views.decorators.csrf import csrf_exempt
|
|
|
|
def index(request):
|
|
return render(request, 'core/index.html')
|
|
|
|
def trade(request, trade_type='spot'):
|
|
symbol = request.GET.get('symbol', 'BTCUSDT')
|
|
# Fetch all active cryptocurrencies for the sidebar
|
|
cryptos = Cryptocurrency.objects.filter(is_active=True)
|
|
context = {
|
|
'symbol': symbol,
|
|
'trade_type': trade_type.upper(),
|
|
'cryptos': cryptos,
|
|
}
|
|
return render(request, 'core/trade.html', context)
|
|
|
|
def market_center(request):
|
|
return render(request, 'core/index.html', {'market_only': True})
|
|
|
|
def placeholder_view(request, title):
|
|
settings = SiteSettings.objects.first()
|
|
|
|
if title == '服务条款':
|
|
content = settings.terms_content if settings and settings.terms_content else '暂无服务条款内容。'
|
|
elif title == '隐私政策':
|
|
content = settings.privacy_content if settings and settings.privacy_content else '暂无隐私政策内容。'
|
|
else:
|
|
contents = {
|
|
'帮助中心': '欢迎来到 BitCrypto 帮助中心。在这里您可以找到关于账户设置、资产充提、交易指南等所有问题的答案。我们为您准备了详尽的视频教程和图文说明,帮助您快速上手。',
|
|
'技术支持': 'BitCrypto 技术支持团队 24/7 在线。如果您遇到任何 API 对接、系统报错或连接问题,请随时联系我们的工程师。我们承诺在 15 分钟内给予首次回复。',
|
|
'提交请求': '请在下方表单提交您的需求或反馈。无论是工单申请、投诉建议还是商务合作,我们都会认真对待。您的每一份反馈都是我们前进的动力。',
|
|
'公告中心': '查看 BitCrypto 最新动态。包括新币上线通知、系统维护公告、市场活动资讯等。订阅我们的邮件列表,第一时间获取核心商业情报。',
|
|
}
|
|
content = contents.get(title, f'这是{title}的详细内容。BitCrypto为您提供最优质的服务。')
|
|
|
|
faqs = [
|
|
{'q': '如何进行身份认证?', 'a': '登录后在个人中心点击身份认证,上传身份证件并完成人脸识别即可。'},
|
|
{'q': '充值多久能到账?', 'a': '区块链网络确认后自动到账,通常 5-30 分钟。'},
|
|
{'q': '手续费是多少?', 'a': '现货交易基础手续费为 0.1%,使用平台币抵扣可享 7.5 折优惠。'},
|
|
]
|
|
|
|
return render(request, 'core/article_detail.html', {
|
|
'title': title,
|
|
'content': content,
|
|
'faqs': faqs if title == '帮助中心' else None
|
|
})
|
|
|
|
@login_required
|
|
def profile(request):
|
|
account, created = Account.objects.get_or_create(user=request.user)
|
|
recent_transactions = Transaction.objects.filter(account=account).order_by('-timestamp')[:10]
|
|
recent_orders = Order.objects.filter(account=account).order_by('-created_at')[:10]
|
|
context = {
|
|
'account': account,
|
|
'recent_transactions': recent_transactions,
|
|
'recent_orders': recent_orders,
|
|
}
|
|
return render(request, 'core/profile.html', context)
|
|
|
|
@login_required
|
|
def deposit(request):
|
|
if request.method == 'POST':
|
|
amount = request.POST.get('amount')
|
|
tx_id = request.POST.get('tx_id')
|
|
if amount and tx_id:
|
|
account = request.user.account
|
|
Transaction.objects.create(
|
|
account=account,
|
|
transaction_type='deposit',
|
|
amount=decimal.Decimal(amount),
|
|
status='pending',
|
|
tx_hash=tx_id
|
|
)
|
|
return redirect('profile')
|
|
return render(request, 'core/deposit.html')
|
|
|
|
@login_required
|
|
def withdraw(request):
|
|
account = request.user.account
|
|
if request.method == 'POST':
|
|
amount = request.POST.get('amount')
|
|
address = request.POST.get('address')
|
|
if amount and address:
|
|
amount_dec = decimal.Decimal(amount)
|
|
if account.balance >= amount_dec:
|
|
account.balance -= amount_dec
|
|
account.save()
|
|
Transaction.objects.create(
|
|
account=account,
|
|
transaction_type='withdraw',
|
|
amount=amount_dec,
|
|
status='completed',
|
|
tx_hash=f"wd_{random.randint(1000, 9999)}"
|
|
)
|
|
return redirect('profile')
|
|
return render(request, 'core/withdraw.html', {'account': account})
|
|
|
|
@login_required
|
|
def verify(request):
|
|
account = request.user.account
|
|
if request.method == 'POST':
|
|
account.kyc_status = 'pending'
|
|
account.save()
|
|
return redirect('profile')
|
|
return render(request, 'core/verify.html', {'account': account})
|
|
|
|
def generate_captcha():
|
|
a = random.randint(1, 10)
|
|
b = random.randint(1, 10)
|
|
op = random.choice(['+', '-', '*'])
|
|
if op == '+':
|
|
res = a + b
|
|
elif op == '-':
|
|
res = a - b
|
|
else:
|
|
res = a * b
|
|
return f"{a} {op} {b} = ?", res
|
|
|
|
def register_view(request):
|
|
if request.method == 'POST':
|
|
username = request.POST.get('username')
|
|
password = request.POST.get('password')
|
|
password_confirm = request.POST.get('password_confirm')
|
|
captcha_input = request.POST.get('captcha_input')
|
|
captcha_expected = request.session.get('captcha_result')
|
|
|
|
if password != password_confirm:
|
|
messages.error(request, "两次输入的密码不一致")
|
|
elif str(captcha_input) != str(captcha_expected):
|
|
messages.error(request, "验证码错误")
|
|
elif User.objects.filter(username=username).exists():
|
|
messages.error(request, "用户名已存在")
|
|
else:
|
|
user = User.objects.create_user(username=username, password=password)
|
|
Account.objects.get_or_create(user=user)
|
|
login(request, user)
|
|
return redirect('index')
|
|
|
|
# Generate new captcha
|
|
captcha_text, captcha_result = generate_captcha()
|
|
request.session['captcha_result'] = captcha_result
|
|
|
|
return render(request, 'core/register.html', {
|
|
'captcha_text': captcha_text
|
|
})
|
|
|
|
def login_view(request):
|
|
if request.method == 'POST':
|
|
form = AuthenticationForm(data=request.POST)
|
|
if form.is_valid():
|
|
user = form.get_user()
|
|
login(request, user)
|
|
return redirect('index')
|
|
else:
|
|
form = AuthenticationForm()
|
|
return render(request, 'core/login.html', {'form': form})
|
|
|
|
@login_required
|
|
@csrf_exempt
|
|
def submit_order(request):
|
|
if request.method == 'POST':
|
|
try:
|
|
data = json.loads(request.body)
|
|
symbol = data.get('symbol', 'BTCUSDT')
|
|
side = data.get('side')
|
|
amount = decimal.Decimal(data.get('amount', 0))
|
|
trade_type = data.get('trade_type', 'SPOT')
|
|
order_type = data.get('order_type', 'MARKET')
|
|
price = data.get('price')
|
|
|
|
account = request.user.account
|
|
|
|
# Fetch current price from DB or simulated
|
|
crypto = Cryptocurrency.objects.filter(symbol=symbol.replace('USDT', '')).first()
|
|
current_price = crypto.current_price if crypto else decimal.Decimal('48000')
|
|
|
|
# If market order, use current price. If limit, use provided price.
|
|
exec_price = decimal.Decimal(str(price)) if order_type == 'LIMIT' else current_price
|
|
|
|
if side == 'BUY':
|
|
cost = amount * exec_price
|
|
if account.balance >= cost:
|
|
account.balance -= cost
|
|
account.save()
|
|
Order.objects.create(
|
|
account=account,
|
|
symbol=symbol,
|
|
side=side,
|
|
amount=amount,
|
|
trade_type=trade_type,
|
|
order_type=order_type,
|
|
status='FILLED',
|
|
entry_price=exec_price,
|
|
price=exec_price if order_type == 'LIMIT' else None
|
|
)
|
|
return JsonResponse({'status': 'success'})
|
|
else:
|
|
return JsonResponse({'status': 'error', 'message': '余额不足'})
|
|
else:
|
|
# SELL
|
|
revenue = amount * exec_price
|
|
Order.objects.create(
|
|
account=account,
|
|
symbol=symbol,
|
|
side=side,
|
|
amount=amount,
|
|
trade_type=trade_type,
|
|
order_type=order_type,
|
|
status='FILLED',
|
|
entry_price=exec_price,
|
|
price=exec_price if order_type == 'LIMIT' else None
|
|
)
|
|
account.balance += revenue
|
|
account.save()
|
|
return JsonResponse({'status': 'success'})
|
|
|
|
except Exception as e:
|
|
return JsonResponse({'status': 'error', 'message': str(e)})
|
|
return JsonResponse({'status': 'error', 'message': 'Invalid request'})
|
|
|
|
def market_data(request):
|
|
# This might be used by some local scripts, though index/trade use Binance API directly
|
|
symbols = ['BTC', 'ETH', 'BNB', 'SOL', 'ADA', 'XRP', 'DOT', 'DOGE']
|
|
data = []
|
|
for s in symbols:
|
|
price = random.uniform(10, 60000)
|
|
change = random.uniform(-5, 5)
|
|
data.append({
|
|
'symbol': s,
|
|
'price': round(price, 4),
|
|
'change': round(change, 2)
|
|
})
|
|
return JsonResponse(data, safe=False) |