Autosave: 20260206-092300

This commit is contained in:
Flatlogic Bot 2026-02-06 09:23:02 +00:00
parent 2a7594954f
commit 6a5fce6db2
43 changed files with 2589 additions and 322 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB

View File

@ -1,52 +1,16 @@
"""
Django settings for config project.
Generated by 'django-admin startproject' using Django 5.2.7.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.2/ref/settings/
"""
from pathlib import Path
import os
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
BASE_DIR = Path(__file__).resolve().parent.parent
load_dotenv(BASE_DIR.parent / ".env")
SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", "change-me")
DEBUG = os.getenv("DJANGO_DEBUG", "true").lower() == "true"
SECRET_KEY = os.getenv('SECRET_KEY', 'django-insecure-default-key')
ALLOWED_HOSTS = [
"127.0.0.1",
"localhost",
os.getenv("HOST_FQDN", ""),
]
DEBUG = True
CSRF_TRUSTED_ORIGINS = [
origin for origin in [
os.getenv("HOST_FQDN", ""),
os.getenv("CSRF_TRUSTED_ORIGIN", "")
] if origin
]
CSRF_TRUSTED_ORIGINS = [
f"https://{host}" if not host.startswith(("http://", "https://")) else host
for host in CSRF_TRUSTED_ORIGINS
]
# Cookies must always be HTTPS-only; SameSite=Lax keeps CSRF working behind the proxy.
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = "None"
CSRF_COOKIE_SAMESITE = "None"
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
# Application definition
ALLOWED_HOSTS = ['*']
INSTALLED_APPS = [
'django.contrib.admin',
@ -65,25 +29,22 @@ MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Disable X-Frame-Options middleware to allow Flatlogic preview iframes.
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
X_FRAME_OPTIONS = 'ALLOWALL'
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
# IMPORTANT: do not remove injects PROJECT_DESCRIPTION/PROJECT_IMAGE_URL and cache-busting timestamp
'core.context_processors.project_context',
],
},
@ -92,91 +53,34 @@ TEMPLATES = [
WSGI_APPLICATION = 'config.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.getenv('DB_NAME', ''),
'USER': os.getenv('DB_USER', ''),
'PASSWORD': os.getenv('DB_PASS', ''),
'NAME': os.getenv('DB_NAME', 'django_db'),
'USER': os.getenv('DB_USER', 'django_user'),
'PASSWORD': os.getenv('DB_PASS', 'django_pass'),
'HOST': os.getenv('DB_HOST', '127.0.0.1'),
'PORT': os.getenv('DB_PORT', '3306'),
'OPTIONS': {
'charset': 'utf8mb4',
},
},
}
}
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]
# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/
STATIC_URL = 'static/'
# Collect static into a separate folder; avoid overlapping with STATICFILES_DIRS.
STATICFILES_DIRS = [BASE_DIR / 'static']
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [
BASE_DIR / 'static',
BASE_DIR / 'assets',
BASE_DIR / 'node_modules',
]
# Email
EMAIL_BACKEND = os.getenv(
"EMAIL_BACKEND",
"django.core.mail.backends.smtp.EmailBackend"
)
EMAIL_HOST = os.getenv("EMAIL_HOST", "127.0.0.1")
EMAIL_PORT = int(os.getenv("EMAIL_PORT", "587"))
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER", "")
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD", "")
EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS", "true").lower() == "true"
EMAIL_USE_SSL = os.getenv("EMAIL_USE_SSL", "false").lower() == "true"
DEFAULT_FROM_EMAIL = os.getenv("DEFAULT_FROM_EMAIL", "no-reply@example.com")
CONTACT_EMAIL_TO = [
item.strip()
for item in os.getenv("CONTACT_EMAIL_TO", DEFAULT_FROM_EMAIL).split(",")
if item.strip()
]
# When both TLS and SSL flags are enabled, prefer SSL explicitly
if EMAIL_USE_SSL:
EMAIL_USE_TLS = False
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'

View File

@ -1,3 +1,34 @@
from django.contrib import admin
from .models import Cryptocurrency, Account, Asset, Order, Transaction, SiteSettings
# Register your models here.
@admin.register(SiteSettings)
class SiteSettingsAdmin(admin.ModelAdmin):
list_display = ('site_name', 'customer_service_url', 'is_pinning_active')
@admin.register(Cryptocurrency)
class CryptocurrencyAdmin(admin.ModelAdmin):
list_display = ('symbol', 'name', 'current_price', 'manual_price', 'change_24h', 'is_active')
search_fields = ('symbol', 'name')
list_editable = ('manual_price', 'is_active')
@admin.register(Account)
class AccountAdmin(admin.ModelAdmin):
list_display = ('uid', 'user', 'balance', 'credit_score', 'kyc_status', 'win_loss_control', 'created_at')
search_fields = ('uid', 'user__username')
list_filter = ('kyc_status', 'account_type')
list_editable = ('win_loss_control',)
@admin.register(Asset)
class AssetAdmin(admin.ModelAdmin):
list_display = ('account', 'currency', 'balance', 'frozen')
list_filter = ('currency',)
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = ('account', 'symbol', 'trade_type', 'side', 'status', 'created_at')
list_filter = ('trade_type', 'side', 'status')
@admin.register(Transaction)
class TransactionAdmin(admin.ModelAdmin):
list_display = ('account', 'transaction_type', 'amount', 'currency', 'status', 'timestamp')
list_filter = ('transaction_type', 'status')

View File

@ -1,13 +1,11 @@
import os
import time
from .models import SiteSettings
def project_context(request):
"""
Adds project-specific environment variables to the template context globally.
"""
def site_settings(request):
settings = SiteSettings.objects.first()
if not settings:
settings = SiteSettings.objects.create(site_name="BitCrypto")
return {
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
# Used for cache-busting static assets
"deployment_timestamp": int(time.time()),
'site_settings': settings,
'project_name': settings.site_name,
'project_description': "全球领先的数字资产交易平台"
}

View File

Binary file not shown.

View File

View File

@ -0,0 +1,71 @@
from django.core.management.base import BaseCommand
from core.models import Cryptocurrency
from decimal import Decimal
class Command(BaseCommand):
help = 'Seeds the database with common cryptocurrencies'
def handle(self, *args, **options):
cryptos = [
('BTC', 'Bitcoin', 65000.00),
('ETH', 'Ethereum', 3500.00),
('BNB', 'BNB', 600.00),
('SOL', 'Solana', 150.00),
('XRP', 'XRP', 0.60),
('ADA', 'Cardano', 0.50),
('AVAX', 'Avalanche', 40.00),
('DOT', 'Polkadot', 7.00),
('DOGE', 'Dogecoin', 0.15),
('SHIB', 'Shiba Inu', 0.000025),
('MATIC', 'Polygon', 0.70),
('LINK', 'Chainlink', 15.00),
('UNI', 'Uniswap', 8.00),
('LTC', 'Litecoin', 80.00),
('BCH', 'Bitcoin Cash', 450.00),
('ATOM', 'Cosmos', 10.00),
('XLM', 'Stellar', 0.12),
('ETC', 'Ethereum Classic', 30.00),
('NEAR', 'NEAR Protocol', 6.00),
('FIL', 'Filecoin', 6.00),
('ICP', 'Internet Computer', 12.00),
('HBAR', 'Hedera', 0.10),
('VET', 'VeChain', 0.04),
('ALGO', 'Algorand', 0.20),
('GRT', 'The Graph', 0.30),
('FTM', 'Fantom', 0.80),
('SAND', 'The Sandbox', 0.50),
('MANA', 'Decentraland', 0.50),
('AAVE', 'Aave', 100.00),
('THETA', 'Theta Network', 2.50),
('EGLD', 'MultiversX', 45.00),
('XTZ', 'Tezos', 1.20),
('EOS', 'EOS', 0.80),
('FLOW', 'Flow', 1.00),
('CHZ', 'Chiliz', 0.15),
('AXS', 'Axie Infinity', 8.00),
('GALA', 'Gala', 0.05),
('KAVA', 'Kava', 0.70),
('ZEC', 'Zcash', 30.00),
('DASH', 'Dash', 35.00),
('NEO', 'NEO', 15.00),
('IOTA', 'IOTA', 0.25),
('KLAY', 'Klaytn', 0.20),
('BSV', 'Bitcoin SV', 70.00),
('MINA', 'Mina', 0.90),
('XEC', 'eCash', 0.00005),
('BTT', 'BitTorrent', 0.000001),
('LUNC', 'Terra Classic', 0.0001),
('USTC', 'TerraClassicUSD', 0.02),
]
for symbol, name, price in cryptos:
Cryptocurrency.objects.update_or_create(
symbol=symbol,
defaults={
'name': name,
'current_price': Decimal(str(price)),
'change_24h': Decimal('0.00'),
'is_active': True
}
)
self.stdout.write(self.style.SUCCESS(f'Successfully seeded {symbol}'))

View File

@ -0,0 +1,25 @@
from django.core.management.base import BaseCommand
from core.models import SiteSettings, Cryptocurrency
import decimal
class Command(BaseCommand):
help = 'Seed initial site settings and data'
def handle(self, *args, **options):
# Site Settings
settings, created = SiteSettings.objects.get_or_create(id=1)
settings.site_name = "BitCrypto"
settings.customer_service_url = "https://t.me/bitcrypto_support"
settings.terms_content = "欢迎使用 BitCrypto。通过访问我们的平台您同意遵守以下条款1. 用户必须年满 18 岁。2. 您对账户的安全负全部责任。3. 加密货币交易具有高度风险..."
settings.privacy_content = "我们重视您的隐私。BitCrypto 仅收集必要的个人信息以提供服务。我们使用先进的加密技术保护您的数据,绝不向第三方出售您的个人信息。"
settings.save()
self.stdout.write(self.style.SUCCESS('Successfully seeded site settings'))
# Ensure BTC exists
btc, created = Cryptocurrency.objects.get_or_create(symbol="BTC")
btc.name = "Bitcoin"
btc.current_price = decimal.Decimal("48000.00")
btc.save()
self.stdout.write(self.style.SUCCESS('Successfully seeded cryptocurrencies'))

View File

@ -0,0 +1,71 @@
# Generated by Django 5.2.7 on 2026-02-06 06:28
import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Account',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('uid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
('session_key', models.CharField(blank=True, max_length=100, null=True, unique=True)),
('account_type', models.CharField(choices=[('SIMULATED', 'Simulated'), ('REAL', 'Real')], default='SIMULATED', max_length=20)),
('created_at', models.DateTimeField(auto_now_add=True)),
('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Ledger',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('currency', models.CharField(max_length=10)),
('amount', models.DecimalField(decimal_places=8, max_digits=30)),
('balance_before', models.DecimalField(decimal_places=8, max_digits=30)),
('balance_after', models.DecimalField(decimal_places=8, max_digits=30)),
('biz_type', models.CharField(max_length=50)),
('reference_id', models.CharField(blank=True, max_length=100, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ledger_entries', to='core.account')),
],
),
migrations.CreateModel(
name='Order',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('symbol', models.CharField(default='BTC-USDT', max_length=20)),
('side', models.CharField(choices=[('BUY', 'Buy'), ('SELL', 'Sell')], max_length=10)),
('order_type', models.CharField(choices=[('LIMIT', 'Limit'), ('MARKET', 'Market')], max_length=10)),
('price', models.DecimalField(blank=True, decimal_places=8, max_digits=30, null=True)),
('amount', models.DecimalField(decimal_places=8, max_digits=30)),
('filled_amount', models.DecimalField(decimal_places=8, default=0, max_digits=30)),
('status', models.CharField(choices=[('LIVE', 'Live'), ('PARTIALLY_FILLED', 'Partially Filled'), ('FILLED', 'Filled'), ('CANCELED', 'Canceled')], default='LIVE', max_length=20)),
('created_at', models.DateTimeField(auto_now_add=True)),
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='core.account')),
],
),
migrations.CreateModel(
name='Asset',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('currency', models.CharField(max_length=10)),
('balance', models.DecimalField(decimal_places=8, default=0, max_digits=30)),
('frozen', models.DecimalField(decimal_places=8, default=0, max_digits=30)),
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='assets', to='core.account')),
],
options={
'unique_together': {('account', 'currency')},
},
),
]

View File

@ -0,0 +1,151 @@
# Generated by Django 5.2.7 on 2026-02-06 07:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Cryptocurrency',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('symbol', models.CharField(max_length=20, unique=True, verbose_name='币种代码')),
('name', models.CharField(max_length=100, verbose_name='币种名称')),
('icon_url', models.URLField(blank=True, null=True, verbose_name='图标URL')),
('current_price', models.DecimalField(decimal_places=8, default=0, max_digits=30, verbose_name='当前价格')),
('manual_price', models.DecimalField(blank=True, decimal_places=8, max_digits=30, null=True, verbose_name='插针价格 (留空则使用当前价格)')),
('change_24h', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='24h 涨跌幅')),
('is_active', models.BooleanField(default=True, verbose_name='是否启用')),
],
options={
'verbose_name': '加密货币',
'verbose_name_plural': '加密货币管理',
},
),
migrations.AlterModelOptions(
name='account',
options={'verbose_name': '账户', 'verbose_name_plural': '账户管理'},
),
migrations.AlterModelOptions(
name='asset',
options={'verbose_name': '资产', 'verbose_name_plural': '资产管理'},
),
migrations.AlterModelOptions(
name='ledger',
options={'verbose_name': '账单', 'verbose_name_plural': '账单管理'},
),
migrations.AlterModelOptions(
name='order',
options={'verbose_name': '订单', 'verbose_name_plural': '订单管理'},
),
migrations.AddField(
model_name='account',
name='win_loss_control',
field=models.IntegerField(default=0, help_text='控制胜率: -100 (必输) 到 100 (必赢), 0 为随机', verbose_name='输赢控制'),
),
migrations.AlterField(
model_name='account',
name='account_type',
field=models.CharField(choices=[('SIMULATED', '模拟账户'), ('REAL', '真实账户')], default='SIMULATED', max_length=20, verbose_name='账户类型'),
),
migrations.AlterField(
model_name='account',
name='created_at',
field=models.DateTimeField(auto_now_add=True, verbose_name='创建时间'),
),
migrations.AlterField(
model_name='asset',
name='balance',
field=models.DecimalField(decimal_places=8, default=0, max_digits=30, verbose_name='余额'),
),
migrations.AlterField(
model_name='asset',
name='currency',
field=models.CharField(max_length=10, verbose_name='币种'),
),
migrations.AlterField(
model_name='asset',
name='frozen',
field=models.DecimalField(decimal_places=8, default=0, max_digits=30, verbose_name='冻结'),
),
migrations.AlterField(
model_name='ledger',
name='amount',
field=models.DecimalField(decimal_places=8, max_digits=30, verbose_name='金额'),
),
migrations.AlterField(
model_name='ledger',
name='balance_after',
field=models.DecimalField(decimal_places=8, max_digits=30, verbose_name='变动后余额'),
),
migrations.AlterField(
model_name='ledger',
name='balance_before',
field=models.DecimalField(decimal_places=8, max_digits=30, verbose_name='变动前余额'),
),
migrations.AlterField(
model_name='ledger',
name='biz_type',
field=models.CharField(max_length=50, verbose_name='业务类型'),
),
migrations.AlterField(
model_name='ledger',
name='created_at',
field=models.DateTimeField(auto_now_add=True, verbose_name='创建时间'),
),
migrations.AlterField(
model_name='ledger',
name='currency',
field=models.CharField(max_length=10, verbose_name='币种'),
),
migrations.AlterField(
model_name='ledger',
name='reference_id',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='引用ID'),
),
migrations.AlterField(
model_name='order',
name='amount',
field=models.DecimalField(decimal_places=8, max_digits=30, verbose_name='数量'),
),
migrations.AlterField(
model_name='order',
name='created_at',
field=models.DateTimeField(auto_now_add=True, verbose_name='创建时间'),
),
migrations.AlterField(
model_name='order',
name='filled_amount',
field=models.DecimalField(decimal_places=8, default=0, max_digits=30, verbose_name='已成交数量'),
),
migrations.AlterField(
model_name='order',
name='order_type',
field=models.CharField(choices=[('LIMIT', '限价'), ('MARKET', '市价')], max_length=10, verbose_name='类型'),
),
migrations.AlterField(
model_name='order',
name='price',
field=models.DecimalField(blank=True, decimal_places=8, max_digits=30, null=True, verbose_name='价格'),
),
migrations.AlterField(
model_name='order',
name='side',
field=models.CharField(choices=[('BUY', '买入'), ('SELL', '卖出')], max_length=10, verbose_name='方向'),
),
migrations.AlterField(
model_name='order',
name='status',
field=models.CharField(choices=[('LIVE', '进行中'), ('PARTIALLY_FILLED', '部分成交'), ('FILLED', '已成交'), ('CANCELED', '已撤销')], default='LIVE', max_length=20, verbose_name='状态'),
),
migrations.AlterField(
model_name='order',
name='symbol',
field=models.CharField(default='BTC-USDT', max_length=20, verbose_name='交易对'),
),
]

View File

@ -0,0 +1,92 @@
# Generated by Django 5.2.7 on 2026-02-06 07:19
import core.models
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0002_cryptocurrency_alter_account_options_and_more'),
]
operations = [
migrations.AddField(
model_name='account',
name='credit_score',
field=models.IntegerField(default=80, verbose_name='信用分'),
),
migrations.AddField(
model_name='account',
name='kyc_status',
field=models.CharField(choices=[('UNVERIFIED', '未认证'), ('PENDING', '审核中'), ('VERIFIED', '已认证'), ('REJECTED', '已拒绝')], default='UNVERIFIED', max_length=20, verbose_name='实名认证状态'),
),
migrations.AddField(
model_name='account',
name='language',
field=models.CharField(default='en', max_length=10, verbose_name='语言偏好'),
),
migrations.AddField(
model_name='order',
name='close_price',
field=models.DecimalField(blank=True, decimal_places=8, max_digits=30, null=True, verbose_name='平仓价格'),
),
migrations.AddField(
model_name='order',
name='entry_price',
field=models.DecimalField(blank=True, decimal_places=8, max_digits=30, null=True, verbose_name='入场价格'),
),
migrations.AddField(
model_name='order',
name='leverage',
field=models.IntegerField(default=1, verbose_name='杠杆倍数'),
),
migrations.AddField(
model_name='order',
name='profit_loss',
field=models.DecimalField(decimal_places=8, default=0, max_digits=30, verbose_name='盈亏'),
),
migrations.AddField(
model_name='order',
name='trade_type',
field=models.CharField(choices=[('SPOT', '现货'), ('CONTRACT', '合约')], default='SPOT', max_length=20, verbose_name='交易类型'),
),
migrations.AlterField(
model_name='account',
name='uid',
field=models.CharField(default=core.models.generate_uid, max_length=6, unique=True, verbose_name='UID'),
),
migrations.AlterField(
model_name='order',
name='price',
field=models.DecimalField(blank=True, decimal_places=8, max_digits=30, null=True, verbose_name='委托价格'),
),
migrations.AlterField(
model_name='order',
name='side',
field=models.CharField(choices=[('BUY', '买入/做多'), ('SELL', '卖出/做空')], max_length=10, verbose_name='方向'),
),
migrations.AlterField(
model_name='order',
name='status',
field=models.CharField(choices=[('LIVE', '进行中'), ('PARTIALLY_FILLED', '部分成交'), ('FILLED', '已成交'), ('CANCELED', '已撤销'), ('CLOSED', '已平仓')], default='LIVE', max_length=20, verbose_name='状态'),
),
migrations.CreateModel(
name='Transaction',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('tx_type', models.CharField(choices=[('DEPOSIT', '充值'), ('WITHDRAW', '提现')], max_length=20, verbose_name='类型')),
('currency', models.CharField(default='USDT', max_length=10, verbose_name='币种')),
('amount', models.DecimalField(decimal_places=8, max_digits=30, verbose_name='金额')),
('address', models.CharField(blank=True, max_length=255, null=True, verbose_name='地址/流水')),
('status', models.CharField(choices=[('PENDING', '待处理'), ('SUCCESS', '成功'), ('FAILED', '失败')], default='PENDING', max_length=20, verbose_name='状态')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='时间')),
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transactions', to='core.account')),
],
options={
'verbose_name': '充提记录',
'verbose_name_plural': '充提管理',
},
),
]

View File

@ -0,0 +1,59 @@
# Generated by Django 5.2.7 on 2026-02-06 07:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0003_account_credit_score_account_kyc_status_and_more'),
]
operations = [
migrations.RenameField(
model_name='transaction',
old_name='created_at',
new_name='timestamp',
),
migrations.RemoveField(
model_name='transaction',
name='address',
),
migrations.RemoveField(
model_name='transaction',
name='tx_type',
),
migrations.AddField(
model_name='account',
name='balance',
field=models.DecimalField(decimal_places=8, default=0, max_digits=30, verbose_name='可用余额 (USDT)'),
),
migrations.AddField(
model_name='transaction',
name='transaction_type',
field=models.CharField(choices=[('deposit', '充值'), ('withdraw', '提现')], default='deposit', max_length=20, verbose_name='类型'),
),
migrations.AddField(
model_name='transaction',
name='tx_hash',
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='交易哈希'),
),
migrations.AlterField(
model_name='account',
name='language',
field=models.CharField(default='zh-hans', max_length=10, verbose_name='语言偏好'),
),
migrations.AlterField(
model_name='transaction',
name='amount',
field=models.DecimalField(decimal_places=8, default=0, max_digits=30, verbose_name='金额'),
),
migrations.AlterField(
model_name='transaction',
name='status',
field=models.CharField(choices=[('pending', '待处理'), ('completed', '成功'), ('failed', '失败')], default='pending', max_length=20, verbose_name='状态'),
),
migrations.DeleteModel(
name='Ledger',
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 5.2.7 on 2026-02-06 09:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0004_rename_created_at_transaction_timestamp_and_more'),
]
operations = [
migrations.CreateModel(
name='SiteSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('site_name', models.CharField(default='BitCrypto', max_length=100, verbose_name='网站名称')),
('customer_service_url', models.URLField(blank=True, null=True, verbose_name='在线客服链接')),
('terms_content', models.TextField(blank=True, verbose_name='服务条款内容')),
('privacy_content', models.TextField(blank=True, verbose_name='隐私政策内容')),
('is_pinning_active', models.BooleanField(default=False, help_text='开启后,所有币种将向手动设置的价格靠拢', verbose_name='全局插针激活')),
],
options={
'verbose_name': '系统设置',
'verbose_name_plural': '系统设置',
},
),
]

View File

@ -1,3 +1,144 @@
import random
import string
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
# Create your models here.
def generate_uid():
return ''.join(random.choices(string.digits, k=6))
class SiteSettings(models.Model):
site_name = models.CharField(max_length=100, default="BitCrypto", verbose_name=_("网站名称"))
customer_service_url = models.URLField(blank=True, null=True, verbose_name=_("在线客服链接"))
terms_content = models.TextField(blank=True, verbose_name=_("服务条款内容"))
privacy_content = models.TextField(blank=True, verbose_name=_("隐私政策内容"))
# Global Market Control
is_pinning_active = models.BooleanField(default=False, verbose_name=_("全局插针激活"), help_text=_("开启后,所有币种将向手动设置的价格靠拢"))
class Meta:
verbose_name = _("系统设置")
verbose_name_plural = _("系统设置")
def __str__(self):
return self.site_name
class Cryptocurrency(models.Model):
symbol = models.CharField(max_length=20, unique=True, verbose_name=_("币种代码"))
name = models.CharField(max_length=100, verbose_name=_("币种名称"))
icon_url = models.URLField(null=True, blank=True, verbose_name=_("图标URL"))
current_price = models.DecimalField(max_digits=30, decimal_places=8, default=0, verbose_name=_("当前价格"))
manual_price = models.DecimalField(max_digits=30, decimal_places=8, null=True, blank=True, verbose_name=_("插针价格 (留空则使用当前价格)"))
change_24h = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name=_("24h 涨跌幅"))
is_active = models.BooleanField(default=True, verbose_name=_("是否启用"))
class Meta:
verbose_name = _("加密货币")
verbose_name_plural = _("加密货币管理")
def __str__(self):
return f"{self.symbol} - {self.name}"
class Account(models.Model):
ACCOUNT_TYPES = (
('SIMULATED', _('模拟账户')),
('REAL', _('真实账户')),
)
KYC_STATUS = (
('UNVERIFIED', _('未认证')),
('PENDING', _('审核中')),
('VERIFIED', _('已认证')),
('REJECTED', _('已拒绝')),
)
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
uid = models.CharField(max_length=6, unique=True, default=generate_uid, verbose_name=_("UID"))
session_key = models.CharField(max_length=100, null=True, blank=True, unique=True)
account_type = models.CharField(max_length=20, choices=ACCOUNT_TYPES, default='SIMULATED', verbose_name=_("账户类型"))
balance = models.DecimalField(max_digits=30, decimal_places=8, default=0, verbose_name=_("可用余额 (USDT)"))
credit_score = models.IntegerField(default=80, verbose_name=_("信用分"))
kyc_status = models.CharField(max_length=20, choices=KYC_STATUS, default='UNVERIFIED', verbose_name=_("实名认证状态"))
win_loss_control = models.IntegerField(default=0, help_text=_("控制胜率: -100 (必输) 到 100 (必赢), 0 为随机"), verbose_name=_("输赢控制"))
language = models.CharField(max_length=10, default='zh-hans', verbose_name=_("语言偏好"))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("创建时间"))
class Meta:
verbose_name = _("账户")
verbose_name_plural = _("账户管理")
def __str__(self):
return f"Account {self.uid} ({self.get_account_type_display()})"
class Asset(models.Model):
account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='assets')
currency = models.CharField(max_length=10, verbose_name=_("币种"))
balance = models.DecimalField(max_digits=30, decimal_places=8, default=0, verbose_name=_("余额"))
frozen = models.DecimalField(max_digits=30, decimal_places=8, default=0, verbose_name=_("冻结"))
class Meta:
unique_together = ('account', 'currency')
verbose_name = _("资产")
verbose_name_plural = _("资产管理")
@property
def total(self):
return self.balance + self.frozen
def __str__(self):
return f"{self.account.uid} - {self.currency}: {self.balance}"
class Order(models.Model):
SIDE_CHOICES = (('BUY', _('买入/做多')), ('SELL', _('卖出/做空')))
TYPE_CHOICES = (('LIMIT', _('限价')), ('MARKET', _('市价')))
TRADE_TYPE_CHOICES = (('SPOT', _('现货')), ('CONTRACT', _('合约')))
STATUS_CHOICES = (
('LIVE', _('进行中')),
('PARTIALLY_FILLED', _('部分成交')),
('FILLED', _('已成交')),
('CANCELED', _('已撤销')),
('CLOSED', _('已平仓')),
)
account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='orders')
symbol = models.CharField(max_length=20, default='BTC-USDT', verbose_name=_("交易对"))
trade_type = models.CharField(max_length=20, choices=TRADE_TYPE_CHOICES, default='SPOT', verbose_name=_("交易类型"))
side = models.CharField(max_length=10, choices=SIDE_CHOICES, verbose_name=_("方向"))
order_type = models.CharField(max_length=10, choices=TYPE_CHOICES, verbose_name=_("类型"))
price = models.DecimalField(max_digits=30, decimal_places=8, null=True, blank=True, verbose_name=_("委托价格"))
amount = models.DecimalField(max_digits=30, decimal_places=8, verbose_name=_("数量"))
filled_amount = models.DecimalField(max_digits=30, decimal_places=8, default=0, verbose_name=_("已成交数量"))
leverage = models.IntegerField(default=1, verbose_name=_("杠杆倍数"))
entry_price = models.DecimalField(max_digits=30, decimal_places=8, null=True, blank=True, verbose_name=_("入场价格"))
close_price = models.DecimalField(max_digits=30, decimal_places=8, null=True, blank=True, verbose_name=_("平仓价格"))
profit_loss = models.DecimalField(max_digits=30, decimal_places=8, default=0, verbose_name=_("盈亏"))
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='LIVE', verbose_name=_("状态"))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("创建时间"))
class Meta:
verbose_name = _("订单")
verbose_name_plural = _("订单管理")
def __str__(self):
return f"{self.trade_type} {self.side} {self.amount} {self.symbol}"
class Transaction(models.Model):
TX_TYPE = (('deposit', _('充值')), ('withdraw', _('提现')))
TX_STATUS = (('pending', _('待处理')), ('completed', _('成功')), ('failed', _('失败')))
account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='transactions')
transaction_type = models.CharField(max_length=20, choices=TX_TYPE, default='deposit', verbose_name=_("类型"))
currency = models.CharField(max_length=10, default='USDT', verbose_name=_("币种"))
amount = models.DecimalField(max_digits=30, decimal_places=8, default=0, verbose_name=_("金额"))
tx_hash = models.CharField(max_length=255, null=True, blank=True, verbose_name=_("交易哈希"))
status = models.CharField(max_length=20, choices=TX_STATUS, default='pending', verbose_name=_("状态"))
timestamp = models.DateTimeField(auto_now_add=True, verbose_name=_("时间"))
class Meta:
verbose_name = _("充提记录")
verbose_name_plural = _("充提管理")

View File

@ -1,25 +1,198 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<html lang="zh-hans">
<head>
<meta charset="UTF-8">
<title>{% block title %}Knowledge Base{% endblock %}</title>
{% if project_description %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ project_name }} - 全球领先的数字资产交易平台</title>
<meta name="description" content="{{ project_description }}">
<meta property="og:description" content="{{ project_description }}">
<meta property="twitter:description" content="{{ project_description }}">
{% endif %}
{% if project_image_url %}
<meta property="og:image" content="{{ project_image_url }}">
<meta property="twitter:image" content="{{ project_image_url }}">
{% endif %}
{% load static %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
{% block head %}{% endblock %}
<style>
:root {
--bg-dark: #0b0e11;
--bg-card: #181a20;
--text-primary: #eaecef;
--text-secondary: #848e9c;
--accent-color: #fcd535;
--up-color: #0ecb81;
--down-color: #f6465d;
}
body {
background-color: var(--bg-dark);
color: var(--text-primary);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
margin: 0;
padding: 0;
}
.navbar {
background-color: var(--bg-dark);
border-bottom: 1px solid #2b2f36;
padding: 0.75rem 1.5rem;
}
.nav-link {
color: var(--text-primary) !important;
font-weight: 500;
font-size: 14px;
margin: 0 8px;
transition: color 0.2s;
}
.nav-link:hover { color: var(--accent-color) !important; }
.btn-primary {
background-color: var(--accent-color);
border-color: var(--accent-color);
color: #181a20;
font-weight: 600;
padding: 8px 20px;
border-radius: 4px;
}
.footer {
background-color: var(--bg-dark);
padding: 60px 0 30px 0;
border-top: 1px solid #2b2f36;
}
.footer h6 { color: #eaecef; margin-bottom: 20px; font-weight: 600; }
.footer ul li { margin-bottom: 12px; }
.footer ul li a { color: #848e9c; text-decoration: none; font-size: 14px; transition: color 0.2s; }
.footer ul li a:hover { color: var(--accent-color); }
.glass-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
}
/* Floating Customer Service Icon */
.cs-float {
position: fixed;
right: 30px;
bottom: 40px;
width: 60px;
height: 60px;
background: var(--accent-color);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #181a20;
font-size: 28px;
box-shadow: 0 4px 20px rgba(252, 213, 53, 0.4);
cursor: pointer;
z-index: 9999;
transition: all 0.3s;
text-decoration: none;
}
.cs-float:hover {
transform: scale(1.1) rotate(5deg);
color: #181a20;
}
</style>
</head>
<body>
{% block content %}{% endblock %}
</body>
<nav class="navbar navbar-expand-lg sticky-top">
<div class="container-fluid">
<a class="navbar-brand d-flex align-items-center" href="/">
<img src="{% static 'images/logo.png' %}" alt="Logo" style="height: 28px; margin-right: 8px;">
<span class="fw-bold fs-5 text-white">{{ project_name }}</span>
</a>
<button class="navbar-toggler border-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<i class="bi bi-list text-white"></i>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item"><a class="nav-link" href="{% url 'index' %}">首页</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'spot_trade' %}">现货交易</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'contract_trade' %}">合约交易</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'market_center' %}">行情中心</a></li>
</ul>
<div class="d-flex align-items-center">
{% if user.is_authenticated %}
<div class="dropdown">
<a class="nav-link dropdown-toggle d-flex align-items-center" href="#" role="button" data-bs-toggle="dropdown">
<i class="bi bi-person-circle fs-5 me-2"></i>
<span>{{ user.username }}</span>
</a>
<ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end shadow">
<li><a class="dropdown-item" href="{% url 'profile' %}"><i class="bi bi-person-badge me-2"></i>个人中心</a></li>
<li><a class="dropdown-item" href="{% url 'profile' %}"><i class="bi bi-wallet2 me-2"></i>我的资产</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item text-danger" href="/login/"><i class="bi bi-box-arrow-right me-2"></i>安全退出</a></li>
</ul>
</div>
{% else %}
<a href="{% url 'login' %}" class="nav-link me-3">登录</a>
<a href="{% url 'register' %}" class="btn btn-primary">立即注册</a>
{% endif %}
</div>
</div>
</div>
</nav>
<main>
{% block content %}{% endblock %}
</main>
<!-- Floating CS -->
{% if site_settings.customer_service_url %}
<a href="{{ site_settings.customer_service_url }}" target="_blank" class="cs-float" title="在线客服">
<i class="bi bi-headset"></i>
</a>
{% endif %}
<footer class="footer">
<div class="container">
<div class="row g-4">
<div class="col-md-3">
<h5 class="fw-bold mb-4 text-white">{{ project_name }}</h5>
<p class="text-secondary small">全球领先的数字资产交易平台,致力于为用户提供安全、专业、透明的数字资产一站式服务。</p>
</div>
<div class="col-md-2 offset-md-1">
<h6>产品服务</h6>
<ul class="list-unstyled">
<li><a href="{% url 'spot_trade' %}">现货交易</a></li>
<li><a href="{% url 'contract_trade' %}">永续合约</a></li>
<li><a href="{% url 'placeholder' '币安赚币' %}">理财中心</a></li>
</ul>
</div>
<div class="col-md-2">
<h6>法律法规</h6>
<ul class="list-unstyled">
<li><a href="{% url 'placeholder' '服务条款' %}">服务条款</a></li>
<li><a href="{% url 'placeholder' '隐私政策' %}">隐私政策</a></li>
<li><a href="{% url 'placeholder' '免责声明' %}">免责声明</a></li>
</ul>
</div>
<div class="col-md-2">
<h6>客户支持</h6>
<ul class="list-unstyled">
<li><a href="{% url 'placeholder' '帮助中心' %}">帮助中心</a></li>
<li><a href="{% url 'placeholder' '公告中心' %}">公告中心</a></li>
<li><a href="{% url 'placeholder' '提交请求' %}">提交工单</a></li>
</ul>
</div>
<div class="col-md-2">
<h6>关于我们</h6>
<ul class="list-unstyled">
<li><a href="{% url 'placeholder' '公司简介' %}">公司简介</a></li>
<li><a href="{% url 'placeholder' '加入我们' %}">招贤纳士</a></li>
</ul>
</div>
</div>
<hr class="my-5" style="border-color: #2b2f36;">
<div class="row align-items-center">
<div class="col-md-6 text-center text-md-start">
<p class="text-secondary small mb-0">&copy; 2026 {{ project_name }} Digital Asset Exchange. All rights reserved.</p>
</div>
<div class="col-md-6 text-center text-md-end mt-3 mt-md-0">
<div class="text-secondary small">
<i class="bi bi-globe me-2"></i> 简体中文 | USDT
</div>
</div>
</div>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
{% block scripts %}{% endblock %}
</body>
</html>

View File

@ -1,14 +1,66 @@
{% extends 'base.html' %}
{% block title %}{{ article.title }}{% endblock %}
{% load static %}
{% block content %}
<div class="container mt-5">
<h1>{{ article.title }}</h1>
<p class="text-muted">Published on {{ article.created_at|date:"F d, Y" }}</p>
<hr>
<div>
{{ article.content|safe }}
<div class="container py-5">
<div class="row">
<div class="col-lg-8 offset-lg-2">
<div class="glass-card p-5">
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/" class="text-warning text-decoration-none">首页</a></li>
<li class="breadcrumb-item active text-secondary" aria-current="page">{{ title }}</li>
</ol>
</nav>
<h1 class="fw-bold mb-4 text-white">{{ title }}</h1>
<div class="content text-secondary lh-lg">
<p class="lead text-white mb-5">{{ content }}</p>
{% if faqs %}
<hr class="my-5 border-secondary">
<h3 class="text-white mb-4">常见问题 (FAQ)</h3>
<div class="accordion accordion-flush bg-transparent" id="faqAccordion">
{% for faq in faqs %}
<div class="accordion-item bg-transparent border-secondary">
<h2 class="accordion-header">
<button class="accordion-button bg-transparent text-white collapsed border-0 py-3" type="button" data-bs-toggle="collapse" data-bs-target="#q{{ forloop.counter }}">
{{ faq.q }}
</button>
</h2>
<div id="q{{ forloop.counter }}" class="accordion-collapse collapse" data-bs-parent="#faqAccordion">
<div class="accordion-body text-secondary pb-4">
{{ faq.a }}
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
<div class="mt-5 p-4 bg-dark bg-opacity-50 rounded border border-secondary text-center">
<h5 class="text-white mb-3">还需要更多帮助吗?</h5>
<p class="small text-secondary">我们的全球客服团队 24/7 全天候在线为您提供专业支持。</p>
<div class="d-flex justify-content-center gap-3 mt-4">
<button class="btn btn-warning px-4 fw-bold">联系在线客服</button>
<button class="btn btn-outline-light px-4">查阅文档</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.accordion-button:after {
filter: invert(1);
}
.accordion-button:not(.collapsed) {
background-color: transparent;
box-shadow: none;
color: var(--accent-color);
}
</style>
{% endblock %}

View File

@ -0,0 +1,65 @@
{% extends "base.html" %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-6 animate-up">
<div class="glass-card p-4">
<h3 class="fw-bold mb-4 text-center">充值数字资产</h3>
<div class="mb-4">
<label class="form-label text-secondary">选择币种</label>
<div class="d-flex align-items-center bg-dark p-3 rounded border border-secondary border-opacity-25">
<i class="bi bi-coin text-warning fs-4 me-3"></i>
<div class="flex-grow-1">
<h6 class="m-0 fw-bold">USDT</h6>
<small class="text-secondary">Tether US</small>
</div>
<i class="bi bi-chevron-down text-secondary"></i>
</div>
</div>
<div class="mb-4">
<label class="form-label text-secondary">选择网络</label>
<div class="row g-2">
<div class="col-4"><button class="btn btn-sm btn-outline-warning w-100 active">TRC20</button></div>
<div class="col-4"><button class="btn btn-sm btn-outline-secondary w-100">ERC20</button></div>
<div class="col-4"><button class="btn btn-sm btn-outline-secondary w-100">BEP20</button></div>
</div>
</div>
<div class="bg-black bg-opacity-50 p-4 rounded-3 text-center mb-4 border border-secondary border-opacity-10">
<div class="mb-3">
<img src="https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=TRX789sDqW12vNpkL90ZxY56uMvB45RtQp" alt="QR" class="img-fluid rounded">
</div>
<small class="text-secondary d-block mb-2">充值地址 (TRC20)</small>
<div class="d-flex align-items-center justify-content-center gap-2">
<span class="fw-bold text-break small" style="color: #f0b90b;">TRX789sDqW12vNpkL90ZxY56uMvB45RtQp</span>
<i class="bi bi-files text-secondary cursor-pointer" onclick="alert('地址已复制')"></i>
</div>
</div>
<div class="alert alert-warning border-0 bg-warning bg-opacity-10 text-warning-emphasis small mb-4">
<i class="bi bi-exclamation-triangle-fill me-2"></i>
请仅向该地址充值 USDT。任何其他资产的充值都将无法找回。
</div>
<form method="POST">
{% csrf_token %}
<div class="mb-3">
<label class="form-label text-secondary">充值金额</label>
<div class="input-group">
<input type="number" name="amount" step="0.01" class="form-control bg-dark text-white border-secondary border-opacity-25 py-2" placeholder="0.00" required>
<span class="input-group-text bg-dark text-white border-secondary border-opacity-25">USDT</span>
</div>
</div>
<div class="mb-4">
<label class="form-label text-secondary">交易哈希 (TXID)</label>
<input type="text" name="tx_id" class="form-control bg-dark text-white border-secondary border-opacity-25 py-2" placeholder="请输入链上交易ID" required>
</div>
<button type="submit" class="btn btn-primary-custom w-100 py-3">提交充值确认</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,145 +1,235 @@
{% extends "base.html" %}
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ project_name }}{% endblock %}
{% block content %}
<!-- Hero Carousel Section -->
<div id="heroCarousel" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-indicators">
<button type="button" data-bs-target="#heroCarousel" data-bs-slide-to="0" class="active"></button>
<button type="button" data-bs-target="#heroCarousel" data-bs-slide-to="1"></button>
<button type="button" data-bs-target="#heroCarousel" data-bs-slide-to="2"></button>
</div>
<div class="carousel-inner">
<!-- Slide 1: Welcome -->
<div class="carousel-item active" style="height: 550px; background: linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)), url('https://images.unsplash.com/photo-1621761191319-c6fb62004040?q=80&w=2070&auto=format&fit=crop'); background-size: cover; background-position: center;">
<div class="container h-100 d-flex align-items-center">
<div class="row w-100 align-items-center">
<div class="col-lg-7">
<h1 class="display-3 fw-bold mb-4">开启您的<br><span style="color: var(--accent-color);">加密货币</span>之旅</h1>
<p class="lead text-light mb-5">在全球最受信任的交易平台买卖和存储加密货币。BitCrypto 为您提供安全、稳定、高效的服务。</p>
<div class="d-flex gap-3">
<a href="{% url 'register' %}" class="btn btn-warning btn-lg px-5 fw-bold">立即注册</a>
<a href="{% url 'spot_trade' %}" class="btn btn-outline-light btn-lg px-5 fw-bold">开始交易</a>
</div>
</div>
</div>
</div>
</div>
<!-- Slide 2: Derivatives -->
<div class="carousel-item" style="height: 550px; background: linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)), url('https://images.unsplash.com/photo-1639762681485-074b7f938ba0?q=80&w=2064&auto=format&fit=crop'); background-size: cover; background-position: center;">
<div class="container h-100 d-flex align-items-center">
<div class="row w-100 align-items-center justify-content-end">
<div class="col-lg-7 text-lg-end">
<h1 class="display-4 fw-bold mb-4">领先的<span style="color: var(--accent-color);">衍生品</span>交易平台</h1>
<p class="lead text-light mb-5">最高200倍杠杆支持多种永续合约毫秒级撮合引擎。多空双向交易灵活捕捉市场机会。</p>
<a href="{% url 'contract_trade' %}" class="btn btn-warning btn-lg px-5 fw-bold">进入合约交易</a>
</div>
</div>
</div>
</div>
<!-- Slide 3: App Download -->
<div class="carousel-item" style="height: 550px; background: linear-gradient(rgba(0,0,0,0.7), rgba(0,0,0,0.7)), url('https://images.unsplash.com/photo-1622639225985-84f8877b0c30?q=80&w=1944&auto=format&fit=crop'); background-size: cover; background-position: center;">
<div class="container h-100 d-flex align-items-center">
<div class="row w-100 align-items-center">
<div class="col-lg-12 text-center">
<h1 class="display-4 fw-bold mb-4">随时随地,随心交易</h1>
<p class="lead text-light mb-5">下载 BitCrypto App享受极致交易体验。专业图表、实时推送、资产管理尽在掌握。</p>
<div class="d-flex justify-content-center gap-5">
<div class="download-badge">
<i class="bi bi-apple fs-1 mb-2"></i>
<p class="small mb-0">App Store</p>
</div>
<div class="download-badge">
<i class="bi bi-android2 fs-1 mb-2"></i>
<p class="small mb-0">Android APK</p>
</div>
<div class="download-badge">
<i class="bi bi-qr-code fs-1 mb-2"></i>
<p class="small mb-0">扫码下载</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#heroCarousel" data-bs-slide="prev">
<span class="carousel-control-prev-icon"></span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#heroCarousel" data-bs-slide="next">
<span class="carousel-control-next-icon"></span>
</button>
</div>
<!-- Quick Actions Section -->
<div class="container" style="margin-top: -50px; position: relative; z-index: 10;">
<div class="glass-card p-4 d-flex flex-wrap justify-content-around align-items-center text-center shadow-lg" style="border-radius: 12px; border: 1px solid rgba(255,193,7,0.3);">
<div class="download-item mb-3 mb-md-0">
<h6 class="text-secondary mb-2 small fw-bold">iOS 下载</h6>
<button class="btn btn-outline-light border-secondary px-4"><i class="bi bi-apple me-2 text-warning"></i>App Store</button>
</div>
<div class="vr d-none d-md-block opacity-25"></div>
<div class="download-item mb-3 mb-md-0">
<h6 class="text-secondary mb-2 small fw-bold">安卓下载</h6>
<button class="btn btn-outline-light border-secondary px-4"><i class="bi bi-android2 me-2 text-warning"></i>Android</button>
</div>
<div class="vr d-none d-md-block opacity-25"></div>
<div class="download-item">
<h6 class="text-secondary mb-2 small fw-bold">API 支持</h6>
<button class="btn btn-outline-light border-secondary px-4"><i class="bi bi-code-square me-2 text-warning"></i>开发者文档</button>
</div>
</div>
</div>
<!-- Market Section -->
<section id="markets" class="container py-5 mt-4">
<div class="d-flex justify-content-between align-items-end mb-4">
<div>
<h2 class="fw-bold">热门行情</h2>
<p class="text-secondary mb-0">实时获取全球顶级加密货币价格走势</p>
</div>
<a href="{% url 'market_center' %}" class="text-warning text-decoration-none fw-bold">查看更多市场 <i class="bi bi-arrow-right"></i></a>
</div>
<div class="table-responsive">
<table class="table table-dark table-hover align-middle" style="border-radius: 12px; overflow: hidden; border: 1px solid #2b3139;">
<thead class="text-secondary">
<tr style="background: #1e2329;">
<th scope="col" class="ps-4 py-3">币种</th>
<th scope="col" class="py-3">价格</th>
<th scope="col" class="py-3">24h 涨跌</th>
<th scope="col" class="py-3">24h 最高 / 最低</th>
<th scope="col" class="text-end pe-4 py-3">操作</th>
</tr>
</thead>
<tbody id="market-list">
<tr>
<td colspan="5" class="text-center py-5">
<div class="spinner-border text-warning" role="status"></div>
<p class="mt-2 text-secondary">正在加载实时行情...</p>
</td>
</tr>
</tbody>
</table>
</div>
</section>
<!-- Features -->
<section class="container py-5">
<h2 class="text-center fw-bold mb-5">领先行业的资产安全防护</h2>
<div class="row g-4 text-center">
<div class="col-md-4">
<div class="p-5 h-100 glass-card">
<div class="icon-box mb-4 mx-auto" style="width: 80px; height: 80px; background: rgba(255,193,7,0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center;">
<i class="bi bi-shield-check display-5 text-warning"></i>
</div>
<h4 class="fw-bold mb-3">资产保障基金</h4>
<p class="text-secondary">BitCrypto 每日提取 10% 的交易手续费,存入资产保障基金,为您在极端情况下的资产提供全额赔付保障。</p>
</div>
</div>
<div class="col-md-4">
<div class="p-5 h-100 glass-card">
<div class="icon-box mb-4 mx-auto" style="width: 80px; height: 80px; background: rgba(255,193,7,0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center;">
<i class="bi bi-cpu display-5 text-warning"></i>
</div>
<h4 class="fw-bold mb-3">高性能交易引擎</h4>
<p class="text-secondary">每秒 200 万次的交易撮合能力,保证在市场波动剧烈时依然能够快速响应,不漏掉任何一个成交机会。</p>
</div>
</div>
<div class="col-md-4">
<div class="p-5 h-100 glass-card">
<div class="icon-box mb-4 mx-auto" style="width: 80px; height: 80px; background: rgba(255,193,7,0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center;">
<i class="bi bi-safe2 display-5 text-warning"></i>
</div>
<h4 class="fw-bold mb-3">严密的隐私保护</h4>
<p class="text-secondary">我们对用户数据采取离线分布式存储和多层加密,绝不将个人隐私泄露给任何第三方,确保您的身份隐私。</p>
</div>
</div>
</div>
</section>
{% block head %}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
.download-badge {
transition: transform 0.3s;
cursor: pointer;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 100%;
}
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2.5rem 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
}
h1 {
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
font-weight: 700;
margin: 0 0 1.2rem;
letter-spacing: -0.02em;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
opacity: 0.92;
}
.loader {
margin: 1.5rem auto;
width: 56px;
height: 56px;
border: 4px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.runtime code {
background: rgba(0, 0, 0, 0.25);
padding: 0.15rem 0.45rem;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
footer {
position: absolute;
bottom: 1rem;
width: 100%;
text-align: center;
font-size: 0.85rem;
opacity: 0.75;
.download-badge:hover {
transform: translateY(-5px);
color: var(--accent-color);
}
.icon-box { transition: all 0.3s; }
.glass-card:hover .icon-box { transform: scale(1.1); background: rgba(255,193,7,0.2) !important; }
.coin-icon { width: 32px; height: 32px; margin-right: 12px; }
</style>
{% endblock %}
{% block content %}
<main>
<div class="card">
<h1>Analyzing your requirements and generating your app…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
{% block scripts %}
<script>
const symbols = ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'ADAUSDT', 'XRPUSDT', 'DOTUSDT', 'DOGEUSDT', 'MATICUSDT', 'LINKUSDT'];
const coinIcons = {
'BTC': 'https://s2.coinmarketcap.com/static/img/coins/64x64/1.png',
'ETH': 'https://s2.coinmarketcap.com/static/img/coins/64x64/1027.png',
'BNB': 'https://s2.coinmarketcap.com/static/img/coins/64x64/1839.png',
'SOL': 'https://s2.coinmarketcap.com/static/img/coins/64x64/5426.png',
'ADA': 'https://s2.coinmarketcap.com/static/img/coins/64x64/2010.png',
'XRP': 'https://s2.coinmarketcap.com/static/img/coins/64x64/52.png',
'DOT': 'https://s2.coinmarketcap.com/static/img/coins/64x64/6636.png',
'DOGE': 'https://s2.coinmarketcap.com/static/img/coins/64x64/74.png',
'MATIC': 'https://s2.coinmarketcap.com/static/img/coins/64x64/3890.png',
'LINK': 'https://s2.coinmarketcap.com/static/img/coins/64x64/1975.png'
};
async function fetchMarkets() {
try {
const response = await fetch('https://api.binance.com/api/v3/ticker/24hr?symbols=' + JSON.stringify(symbols));
const data = await response.json();
const list = document.getElementById('market-list');
list.innerHTML = '';
data.forEach(coin => {
const symbolBase = coin.symbol.replace('USDT', '');
const change = parseFloat(coin.priceChangePercent);
const changeClass = change >= 0 ? 'text-success' : 'text-danger';
const changeIcon = change >= 0 ? '+' : '';
const iconUrl = coinIcons[symbolBase] || 'https://s2.coinmarketcap.com/static/img/coins/64x64/1.png';
list.innerHTML += `
<tr>
<td class="ps-4 py-3">
<div class="d-flex align-items-center">
<img src="${iconUrl}" class="coin-icon" alt="${symbolBase}">
<div>
<span class="fw-bold text-white">${symbolBase}</span>
<span class="text-secondary small ms-1">/ USDT</span>
</div>
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
<p class="runtime">
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code>
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code>
</p>
</div>
</main>
<footer>
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
</footer>
</td>
<td class="fw-bold py-3 text-white">$${parseFloat(coin.lastPrice).toLocaleString()}</td>
<td class="${changeClass} py-3 fw-bold">${changeIcon}${change.toFixed(2)}%</td>
<td class="py-3">
<div class="small text-white">高: $${parseFloat(coin.highPrice).toLocaleString()}</div>
<div class="small text-secondary">低: $${parseFloat(coin.lowPrice).toLocaleString()}</div>
</td>
<td class="text-end pe-4 py-3">
<a href="/trade/spot/?symbol=${coin.symbol}" class="btn btn-sm btn-warning fw-bold px-3 shadow-sm">交易</a>
</td>
</tr>
`;
});
} catch (error) { console.error('Error:', error); }
}
fetchMarkets();
setInterval(fetchMarkets, 5000);
</script>
{% endblock %}

View File

@ -0,0 +1,86 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="auth-container d-flex align-items-center justify-content-center" style="min-height: 90vh; background: radial-gradient(circle at top right, #1e2329 0%, #0b0e11 100%);">
<div class="auth-card glass-card p-5" style="width: 100%; max-width: 450px; border-radius: 16px;">
<div class="text-center mb-5">
<div class="logo-circle mb-4 mx-auto">
<i class="bi bi-hexagon-fill text-warning display-4"></i>
</div>
<h2 class="fw-bold text-white">欢迎登录 BitCrypto</h2>
<p class="text-secondary">全球领先的加密资产交易平台</p>
</div>
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="mb-4">
<label class="form-label text-secondary small fw-bold">{{ field.label }}</label>
<div class="input-group">
<span class="input-group-text bg-transparent border-secondary text-secondary">
{% if '用户' in field.label %}<i class="bi bi-person"></i>{% else %}<i class="bi bi-lock"></i>{% endif %}
</span>
<input type="{{ field.field.widget.input_type }}" name="{{ field.name }}" class="form-control bg-transparent text-white border-secondary" placeholder="请输入{{ field.label }}" required>
</div>
{% for error in field.errors %}
<div class="text-danger x-small mt-1">{{ error }}</div>
{% endfor %}
</div>
{% endfor %}
<div class="d-flex justify-content-between align-items-center mb-4">
<div class="form-check">
<input class="form-check-input bg-transparent border-secondary" type="checkbox" id="remember">
<label class="form-check-label text-secondary small" for="remember">自动登录</label>
</div>
<a href="#" class="text-warning small text-decoration-none">忘记密码?</a>
</div>
<button type="submit" class="btn btn-warning w-100 py-3 fw-bold shadow-lg mb-4">登录</button>
</form>
<div class="text-center">
<p class="text-secondary small">还没有账户? <a href="{% url 'register' %}" class="text-warning text-decoration-none fw-bold">立即注册</a></p>
</div>
<div class="mt-5 pt-4 border-top border-secondary text-center">
<p class="text-secondary x-small mb-3">其他登录方式</p>
<div class="d-flex justify-content-center gap-4">
<a href="#" class="text-secondary fs-4"><i class="bi bi-google"></i></a>
<a href="#" class="text-secondary fs-4"><i class="bi bi-apple"></i></a>
<a href="#" class="text-secondary fs-4"><i class="bi bi-qr-code-scan"></i></a>
</div>
</div>
</div>
</div>
<style>
.auth-card {
border: 1px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
}
.input-group-text {
border-right: none;
}
input.form-control {
border-left: none;
padding: 12px;
}
input.form-control:focus {
background: rgba(255, 255, 255, 0.05) !important;
box-shadow: none;
border-color: var(--accent-color);
}
.x-small { font-size: 11px; }
.logo-circle {
width: 80px;
height: 80px;
background: rgba(240, 185, 11, 0.1);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
</style>
{% endblock %}

View File

@ -0,0 +1,222 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container py-5" style="min-height: 90vh;">
<!-- Profile Header -->
<div class="glass-card p-4 mb-4" style="border-radius: 12px; border: 1px solid #2b3139;">
<div class="row align-items-center">
<div class="col-auto">
<div class="avatar-circle bg-warning text-dark d-flex align-items-center justify-content-center fw-bold fs-3" style="width: 80px; height: 80px; border-radius: 50%;">
{{ user.username|first|upper }}
</div>
</div>
<div class="col">
<h2 class="fw-bold mb-1 text-white">{{ user.username }}</h2>
<div class="d-flex gap-3 align-items-center flex-wrap">
<span class="text-secondary small">UID: 59302{{ user.id }}</span>
<span class="badge {% if account.kyc_status == 'completed' %}bg-success{% elif account.kyc_status == 'pending' %}bg-warning text-dark{% else %}bg-secondary{% endif %}">
{% if account.kyc_status == 'completed' %}已认证{% elif account.kyc_status == 'pending' %}审核中{% else %}未认证{% endif %}
</span>
<span class="text-secondary small"><i class="bi bi-clock me-1"></i>注册时间: {{ user.date_joined|date:"Y-m-d" }}</span>
</div>
</div>
<div class="col-lg-auto mt-3 mt-lg-0">
<div class="d-flex gap-2">
<a href="{% url 'deposit' %}" class="btn btn-warning fw-bold px-4">充币</a>
<a href="{% url 'withdraw' %}" class="btn btn-outline-light px-4">提币</a>
</div>
</div>
</div>
</div>
<div class="row g-4">
<!-- Left Column: Asset Overview -->
<div class="col-lg-4">
<div class="glass-card p-4 h-100" style="border-radius: 12px; border: 1px solid #2b3139;">
<h5 class="fw-bold mb-4">资产总览</h5>
<div class="mb-4">
<p class="text-secondary small mb-1">总资产折合 (USDT)</p>
<h2 class="fw-bold text-white mb-0">≈ {{ account.balance|default:"0.00" }} <span class="fs-5 text-secondary fw-normal">USDT</span></h2>
</div>
<hr class="border-secondary opacity-25">
<div class="asset-item d-flex justify-content-between py-3">
<div>
<div class="fw-bold text-white">现货账户</div>
<div class="text-secondary x-small">Spot Account</div>
</div>
<div class="text-end">
<div class="fw-bold text-white">{{ account.balance|default:"0.00" }} USDT</div>
<div class="text-secondary x-small">≈ $0.00</div>
</div>
</div>
<div class="asset-item d-flex justify-content-between py-3 border-top border-secondary border-opacity-10">
<div>
<div class="fw-bold text-white">合约账户</div>
<div class="text-secondary x-small">Futures Account</div>
</div>
<div class="text-end">
<div class="fw-bold text-white">0.00 USDT</div>
<div class="text-secondary x-small">未开通</div>
</div>
</div>
<div class="asset-item d-flex justify-content-between py-3 border-top border-secondary border-opacity-10">
<div>
<div class="fw-bold text-white">理财账户</div>
<div class="text-secondary x-small">Earn Account</div>
</div>
<div class="text-end">
<div class="fw-bold text-white">0.00 USDT</div>
<div class="text-secondary x-small">年化 3.5%起</div>
</div>
</div>
<a href="#" class="btn btn-outline-secondary w-100 mt-4 btn-sm">查看明细 <i class="bi bi-arrow-right ms-1"></i></a>
</div>
</div>
<!-- Right Column: Security & Activity -->
<div class="col-lg-8">
<!-- Security Center -->
<div class="glass-card p-4 mb-4" style="border-radius: 12px; border: 1px solid #2b3139;">
<h5 class="fw-bold mb-4">安全设置</h5>
<div class="row g-4">
<div class="col-md-6">
<div class="d-flex align-items-start gap-3">
<i class="bi bi-envelope-check fs-4 text-success"></i>
<div>
<div class="fw-bold text-white">邮箱验证</div>
<p class="text-secondary x-small mb-0">已绑定: {{ user.email|default:"未设置" }}</p>
</div>
<button class="btn btn-link btn-sm text-warning ms-auto text-decoration-none">修改</button>
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-start gap-3">
<i class="bi bi-shield-lock fs-4 text-warning"></i>
<div>
<div class="fw-bold text-white">谷歌验证器</div>
<p class="text-secondary x-small mb-0">用于提币和安全确认</p>
</div>
<button class="btn btn-link btn-sm text-warning ms-auto text-decoration-none">去绑定</button>
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-start gap-3">
<i class="bi bi-phone fs-4 text-secondary"></i>
<div>
<div class="fw-bold text-white">手机验证</div>
<p class="text-secondary x-small mb-0">未绑定手机号</p>
</div>
<button class="btn btn-link btn-sm text-warning ms-auto text-decoration-none">绑定</button>
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-start gap-3">
<i class="bi bi-person-badge fs-4 text-warning"></i>
<div>
<div class="fw-bold text-white">身份认证 (KYC)</div>
<p class="text-secondary x-small mb-0">提升提现额度至 100 BTC</p>
</div>
<a href="{% url 'verify' %}" class="btn btn-link btn-sm text-warning ms-auto text-decoration-none">立即认证</a>
</div>
</div>
</div>
</div>
<!-- Recent Orders/History -->
<div class="glass-card p-4" style="border-radius: 12px; border: 1px solid #2b3139;">
<ul class="nav nav-tabs border-secondary mb-4" role="tablist">
<li class="nav-item">
<button class="nav-link active bg-transparent border-0 text-white fw-bold px-4" data-bs-toggle="tab" data-bs-target="#orders">当前委托</button>
</li>
<li class="nav-item">
<button class="nav-link bg-transparent border-0 text-secondary fw-bold px-4" data-bs-toggle="tab" data-bs-target="#history">交易历史</button>
</li>
<li class="nav-item">
<button class="nav-link bg-transparent border-0 text-secondary fw-bold px-4" data-bs-toggle="tab" data-bs-target="#funds">资金流水</button>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="orders">
<div class="text-center py-5">
<i class="bi bi-journal-x display-4 text-secondary opacity-25 mb-3"></i>
<p class="text-secondary">暂无当前委托订单</p>
</div>
</div>
<div class="tab-pane fade" id="history">
<div class="table-responsive">
<table class="table table-dark table-hover x-small">
<thead class="text-secondary">
<tr>
<th>时间</th>
<th>币种</th>
<th>类型</th>
<th>价格</th>
<th>数量</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{% for order in recent_orders %}
<tr>
<td>{{ order.created_at|date:"m-d H:i" }}</td>
<td>{{ order.symbol }}</td>
<td class="{% if order.side == 'BUY' %}text-success{% else %}text-danger{% endif %}">{{ order.side }}</td>
<td>{{ order.entry_price }}</td>
<td>{{ order.amount }}</td>
<td class="text-info">{{ order.status }}</td>
</tr>
{% empty %}
<tr><td colspan="6" class="text-center py-4 text-secondary">暂无记录</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="tab-pane fade" id="funds">
<div class="table-responsive">
<table class="table table-dark table-hover x-small">
<thead class="text-secondary">
<tr>
<th>时间</th>
<th>类型</th>
<th>币种</th>
<th>金额</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{% for tx in recent_transactions %}
<tr>
<td>{{ tx.timestamp|date:"m-d H:i" }}</td>
<td>{{ tx.get_transaction_type_display }}</td>
<td>USDT</td>
<td class="{% if tx.transaction_type == 'deposit' %}text-success{% else %}text-danger{% endif %}">{{ tx.amount }}</td>
<td>{{ tx.get_status_display }}</td>
</tr>
{% empty %}
<tr><td colspan="5" class="text-center py-4 text-secondary">暂无记录</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.x-small { font-size: 11px; }
.asset-item { transition: background 0.2s; cursor: pointer; border-radius: 8px; padding-left: 10px; padding-right: 10px; margin-left: -10px; margin-right: -10px; }
.asset-item:hover { background: rgba(255, 255, 255, 0.05); }
.nav-tabs .nav-link.active { border-bottom: 3px solid var(--accent-color) !important; color: var(--accent-color) !important; }
</style>
{% endblock %}

View File

@ -0,0 +1,96 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="auth-container d-flex align-items-center justify-content-center" style="min-height: 90vh; background: radial-gradient(circle at top left, #1e2329 0%, #0b0e11 100%);">
<div class="auth-card glass-card p-5" style="width: 100%; max-width: 500px; border-radius: 16px;">
<div class="text-center mb-5">
<h2 class="fw-bold text-white">注册 {{ site_settings.site_name }} 账户</h2>
<p class="text-secondary">开启您的加密资产财富之旅</p>
</div>
{% if messages %}
<div class="messages">
{% for message in messages %}
<div class="alert alert-danger alert-dismissible fade show bg-transparent text-danger border-danger" role="alert">
{{ message }}
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
</div>
{% endif %}
<form method="post">
{% csrf_token %}
<div class="mb-4">
<label class="form-label text-secondary small fw-bold">用户名</label>
<div class="input-group">
<span class="input-group-text bg-transparent border-secondary text-secondary">
<i class="bi bi-person"></i>
</span>
<input type="text" name="username" class="form-control bg-transparent text-white border-secondary" placeholder="请输入用户名" required>
</div>
</div>
<div class="mb-4">
<label class="form-label text-secondary small fw-bold">密码</label>
<div class="input-group">
<span class="input-group-text bg-transparent border-secondary text-secondary">
<i class="bi bi-lock"></i>
</span>
<input type="password" name="password" class="form-control bg-transparent text-white border-secondary" placeholder="请输入密码" required>
</div>
</div>
<div class="mb-4">
<label class="form-label text-secondary small fw-bold">确认密码</label>
<div class="input-group">
<span class="input-group-text bg-transparent border-secondary text-secondary">
<i class="bi bi-lock-fill"></i>
</span>
<input type="password" name="password_confirm" class="form-control bg-transparent text-white border-secondary" placeholder="请再次输入密码" required>
</div>
</div>
<div class="mb-4">
<label class="form-label text-secondary small fw-bold">安全验证 ({{ captcha_text }})</label>
<div class="input-group">
<span class="input-group-text bg-transparent border-secondary text-secondary">
<i class="bi bi-shield-check"></i>
</span>
<input type="text" name="captcha_input" class="form-control bg-transparent text-white border-secondary" placeholder="请输入计算结果" required>
</div>
</div>
<div class="mb-4">
<div class="form-check">
<input class="form-check-input bg-transparent border-secondary" type="checkbox" id="terms" required checked>
<label class="form-check-label text-secondary small" for="terms">
我已阅读并同意 <a href="{% url 'placeholder' '服务条款' %}" class="text-warning">服务条款</a><a href="{% url 'placeholder' '隐私政策' %}" class="text-warning">隐私政策</a>
</label>
</div>
</div>
<button type="submit" class="btn btn-warning w-100 py-3 fw-bold shadow-lg mb-4">创建账户</button>
</form>
<div class="text-center">
<p class="text-secondary small">已有账户? <a href="{% url 'login' %}" class="text-warning text-decoration-none fw-bold">立即登录</a></p>
</div>
</div>
</div>
<style>
.auth-card {
border: 1px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
}
.input-group-text { border-right: none; }
input.form-control { border-left: none; padding: 12px; }
input.form-control:focus {
background: rgba(255, 255, 255, 0.05) !important;
box-shadow: none;
border-color: var(--accent-color);
}
</style>
{% endblock %}

View File

@ -0,0 +1,356 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container-fluid px-2 py-2" style="background-color: #0b0e11; min-height: 90vh;">
<div class="row g-2">
<!-- Left: Coin List Sidebar -->
<div class="col-lg-2 d-none d-lg-block">
<div class="glass-card h-100 p-2" style="border-radius: 4px; border: 1px solid #2b3139; background: #161a1e;">
<div class="p-2 mb-2">
<div class="input-group input-group-sm">
<span class="input-group-text bg-dark border-secondary"><i class="bi bi-search text-secondary"></i></span>
<input type="text" id="coin-search" class="form-control bg-dark text-white border-secondary" placeholder="搜索币种" onkeyup="filterCoins()">
</div>
</div>
<div class="coin-list-container" style="max-height: calc(100vh - 160px); overflow-y: auto;">
<table class="table table-dark table-hover table-sm mb-0 align-middle" style="font-size: 12px;">
<thead>
<tr class="text-secondary">
<th class="border-0">币种</th>
<th class="border-0 text-end">价格</th>
<th class="border-0 text-end">24h</th>
</tr>
</thead>
<tbody id="left-coin-list">
<!-- Populated by JS -->
</tbody>
</table>
</div>
</div>
</div>
<!-- Middle: Main Trading Area -->
<div class="col-lg-7">
<!-- Market Info Bar -->
<div class="glass-card mb-2 p-2 d-flex align-items-center justify-content-between" style="border-radius: 4px; border: 1px solid #2b3139; background: #161a1e;">
<div class="d-flex align-items-center">
<div class="dropdown me-4">
<button class="btn btn-transparent text-warning fw-bold fs-5 p-0" type="button" data-bs-toggle="dropdown">
<span id="current-symbol-display">{{ symbol }}</span> <i class="bi bi-caret-down-fill small"></i>
</button>
<ul class="dropdown-menu dropdown-menu-dark shadow-lg" id="mobile-coin-list" style="max-height: 400px; overflow-y: auto; width: 250px;">
<!-- Populated by JS -->
</ul>
</div>
<div class="me-4">
<div class="fw-bold fs-5 text-success" id="header-price">--</div>
<div class="text-secondary x-small">≈ $<span id="header-price-usd">--</span></div>
</div>
<div class="me-4 text-center">
<div class="text-secondary x-small">24h 涨跌</div>
<div class="fw-bold" id="header-change">--</div>
</div>
<div class="text-center d-none d-md-block">
<div class="text-secondary x-small">24h 成交量(USDT)</div>
<div class="fw-bold small" id="header-volume">--</div>
</div>
</div>
<div class="d-flex gap-1 bg-dark p-1" style="border-radius: 4px;">
<a href="{% url 'trade' 'spot' %}?symbol={{ symbol }}" class="btn btn-sm {% if trade_type == 'SPOT' %}btn-warning text-dark{% else %}btn-transparent text-secondary{% endif %} fw-bold px-3">现货</a>
<a href="{% url 'trade' 'contract' %}?symbol={{ symbol }}" class="btn btn-sm {% if trade_type == 'CONTRACT' %}btn-warning text-dark{% else %}btn-transparent text-secondary{% endif %} fw-bold px-3">合约</a>
</div>
</div>
<!-- TradingView Chart -->
<div class="glass-card mb-2" style="height: 450px; border-radius: 4px; border: 1px solid #2b3139;">
<div id="tradingview_widget" style="height: 100%;"></div>
</div>
<!-- Trading Forms -->
<div class="glass-card p-3" style="border-radius: 4px; border: 1px solid #2b3139; background: #161a1e;">
{% if trade_type == 'SPOT' %}
<div class="row g-4">
<!-- Buy -->
<div class="col-md-6 border-end border-secondary">
<div class="btn-group w-100 mb-3" role="group">
<input type="radio" class="btn-check" name="buy-mode" id="buy-limit" checked onchange="toggleMode('buy', 'limit')">
<label class="btn btn-outline-secondary btn-sm" for="buy-limit">限价委托</label>
<input type="radio" class="btn-check" name="buy-mode" id="buy-market" onchange="toggleMode('buy', 'market')">
<label class="btn btn-outline-secondary btn-sm" for="buy-market">市价委托</label>
</div>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text bg-dark text-secondary border-secondary" style="width: 70px;">价格</span>
<input type="text" id="buy-price" class="form-control bg-transparent text-white border-secondary" placeholder="0.00">
<span class="input-group-text bg-dark text-secondary border-secondary">USDT</span>
</div>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text bg-dark text-secondary border-secondary" style="width: 70px;">成交额</span>
<input type="number" id="buy-total" class="form-control bg-transparent text-white border-secondary" placeholder="0.00" oninput="updateSlider('buy')">
<span class="input-group-text bg-dark text-secondary border-secondary">USDT</span>
</div>
<div class="mb-4 px-1">
<input type="range" class="form-range custom-range" id="buy-slider" min="0" max="100" step="1" value="0" oninput="applySlider('buy')">
<div class="d-flex justify-content-between x-small text-secondary mt-1">
<span>0%</span><span>25%</span><span>50%</span><span>75%</span><span>100%</span>
</div>
</div>
<div class="d-flex justify-content-between x-small mb-3">
<span class="text-secondary">可用余额</span>
<span class="text-white">{{ account.balance|default:"0.00" }} USDT</span>
</div>
<button class="btn btn-success w-100 fw-bold py-2 shadow" onclick="submitOrder('BUY')">买入 <span class="base-asset">{{ symbol|slice:":-4" }}</span></button>
</div>
<!-- Sell -->
<div class="col-md-6">
<div class="btn-group w-100 mb-3" role="group">
<input type="radio" class="btn-check" name="sell-mode" id="sell-limit" checked onchange="toggleMode('sell', 'limit')">
<label class="btn btn-outline-secondary btn-sm" for="sell-limit">限价委托</label>
<input type="radio" class="btn-check" name="sell-mode" id="sell-market" onchange="toggleMode('sell', 'market')">
<label class="btn btn-outline-secondary btn-sm" for="sell-market">市价委托</label>
</div>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text bg-dark text-secondary border-secondary" style="width: 70px;">价格</span>
<input type="text" id="sell-price" class="form-control bg-transparent text-white border-secondary" placeholder="0.00">
<span class="input-group-text bg-dark text-secondary border-secondary">USDT</span>
</div>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text bg-dark text-secondary border-secondary" style="width: 70px;">数量</span>
<input type="number" id="sell-amount" class="form-control bg-transparent text-white border-secondary" placeholder="0.00" oninput="updateSlider('sell')">
<span class="input-group-text bg-dark text-secondary border-secondary">{{ symbol|slice:":-4" }}</span>
</div>
<div class="mb-4 px-1">
<input type="range" class="form-range custom-range-danger" id="sell-slider" min="0" max="100" step="1" value="0" oninput="applySlider('sell')">
<div class="d-flex justify-content-between x-small text-secondary mt-1">
<span>0%</span><span>25%</span><span>50%</span><span>75%</span><span>100%</span>
</div>
</div>
<div class="d-flex justify-content-between x-small mb-3">
<span class="text-secondary">可用 <span class="base-asset">{{ symbol|slice:":-4" }}</span></span>
<span class="text-white" id="sell-available">0.00</span>
</div>
<button class="btn btn-danger w-100 fw-bold py-2 shadow" onclick="submitOrder('SELL')">卖出 <span class="base-asset">{{ symbol|slice:":-4" }}</span></button>
</div>
</div>
{% else %}
<!-- Contract Form -->
<div class="row g-4">
<div class="col-12 mb-2 d-flex gap-3 align-items-center">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="c-mode" id="c-limit" checked onchange="toggleMode('contract', 'limit')">
<label class="btn btn-outline-warning btn-sm px-4" for="c-limit">限价</label>
<input type="radio" class="btn-check" name="c-mode" id="c-market" onchange="toggleMode('contract', 'market')">
<label class="btn btn-outline-warning btn-sm px-4" for="c-market">市价</label>
</div>
<div class="dropdown">
<button class="btn btn-dark btn-sm border-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" id="lev-btn">杠杆: 20x</button>
<ul class="dropdown-menu dropdown-menu-dark">
<li><a class="dropdown-item" href="javascript:void(0)" onclick="setLev(10)">10x</a></li>
<li><a class="dropdown-item" href="javascript:void(0)" onclick="setLev(20)">20x</a></li>
<li><a class="dropdown-item" href="javascript:void(0)" onclick="setLev(50)">50x</a></li>
<li><a class="dropdown-item" href="javascript:void(0)" onclick="setLev(100)">100x</a></li>
</ul>
</div>
</div>
<div class="col-md-6 border-end border-secondary">
<div class="input-group input-group-sm mb-3">
<span class="input-group-text bg-dark text-secondary border-secondary" style="width: 70px;">价格</span>
<input type="text" id="c-price" class="form-control bg-transparent text-white border-secondary" placeholder="0.00">
<span class="input-group-text bg-dark text-secondary border-secondary">USDT</span>
</div>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text bg-dark text-secondary border-secondary" style="width: 70px;">手数</span>
<input type="number" id="c-amount" class="form-control bg-transparent text-white border-secondary" placeholder="0">
<span class="input-group-text bg-dark text-secondary border-secondary"></span>
</div>
<div class="mb-3">
<input type="range" class="form-range custom-range" id="c-slider" min="0" max="100" step="1" value="0" oninput="applySlider('contract')">
</div>
<div class="d-flex justify-content-between x-small mb-3 text-secondary">
<span>保证金: <span class="text-white" id="c-margin">0.00</span> USDT</span>
<span>可用: <span class="text-white">{{ account.balance|default:"0.00" }} USDT</span></span>
</div>
<div class="row g-2">
<div class="col-6"><button class="btn btn-success w-100 fw-bold" onclick="submitOrder('BUY')">买入 (做多)</button></div>
<div class="col-6"><button class="btn btn-danger w-100 fw-bold" onclick="submitOrder('SELL')">卖出 (做空)</button></div>
</div>
</div>
<div class="col-md-6">
<div class="p-3 bg-dark rounded border border-secondary" style="font-size: 12px;">
<div class="d-flex justify-content-between mb-2"><span>合约面值</span><span class="text-white">100 USDT</span></div>
<div class="d-flex justify-content-between mb-2"><span>当前杠杆</span><span class="text-warning" id="lev-val">20x</span></div>
<div class="d-flex justify-content-between mb-2"><span>预计手续费</span><span class="text-white">0.05%</span></div>
<div class="d-flex justify-content-between"><span>维持保证金</span><span class="text-white">0.4%</span></div>
</div>
</div>
</div>
{% endif %}
</div>
</div>
<!-- Right: Order Book -->
<div class="col-lg-3">
<div class="glass-card h-100 p-2" style="border-radius: 4px; border: 1px solid #2b3139; background: #161a1e;">
<div class="d-flex justify-content-between text-secondary x-small mb-2 px-2">
<span>价格(USDT)</span>
<span>数量({{ symbol|slice:":-4" }})</span>
</div>
<div id="asks" class="mb-2"></div>
<div class="py-2 text-center border-top border-bottom border-secondary my-2">
<span id="current-price-book" class="fs-5 fw-bold text-success">--</span>
</div>
<div id="bids"></div>
</div>
</div>
</div>
</div>
<style>
.x-small { font-size: 11px; }
.coin-icon-small { width: 18px; height: 18px; margin-right: 6px; }
.order-book-row { display: flex; justify-content: space-between; font-size: 11px; padding: 2px 4px; position: relative; }
.order-book-row span { position: relative; z-index: 1; }
.ask-bg { position: absolute; right: 0; top: 0; bottom: 0; background: rgba(246, 70, 93, 0.15); transition: width 0.3s; }
.bid-bg { position: absolute; right: 0; top: 0; bottom: 0; background: rgba(14, 203, 129, 0.15); transition: width 0.3s; }
.custom-range::-webkit-slider-thumb { background: #f0b90b; cursor: pointer; }
.custom-range-danger::-webkit-slider-thumb { background: #f6465d; cursor: pointer; }
.coin-list-container::-webkit-scrollbar { width: 4px; }
.coin-list-container::-webkit-scrollbar-thumb { background: #2b3139; border-radius: 2px; }
</style>
{% endblock %}
{% block scripts %}
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script>
const symbol = '{{ symbol }}';
const tradeType = '{{ trade_type }}';
const balance = parseFloat("{{ account.balance|default:0 }}");
let currentPrice = 0;
let leverage = 20;
let allCoins = [];
function initTV() {
new TradingView.widget({
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol,
"interval": "15", "theme": "dark", "style": "1", "locale": "zh_CN",
"container_id": "tradingview_widget", "hide_side_toolbar": false
});
}
async function getMarkets() {
try {
const r = await fetch('https://api.binance.com/api/v3/ticker/24hr');
const data = await r.json();
allCoins = data.filter(c => c.symbol.endsWith('USDT')).slice(0, 50);
renderCoins();
} catch(e) {}
}
function renderCoins(filter = '') {
const list = document.getElementById('left-coin-list');
const mobileList = document.getElementById('mobile-coin-list');
list.innerHTML = ''; mobileList.innerHTML = '';
allCoins.forEach(c => {
if (filter && !c.symbol.toLowerCase().includes(filter.toLowerCase())) return;
const base = c.symbol.replace('USDT', '');
const chg = parseFloat(c.priceChangePercent);
const row = `
<tr style="cursor: pointer;" onclick="location.href='?symbol=${c.symbol}'">
<td>${base}</td>
<td class="text-end fw-bold">${parseFloat(c.lastPrice).toFixed(2)}</td>
<td class="text-end ${chg>=0?'text-success':'text-danger'}">${chg>=0?'+':''}${chg.toFixed(2)}%</td>
</tr>`;
list.innerHTML += row;
mobileList.innerHTML += `<li><a class="dropdown-item d-flex justify-content-between" href="?symbol=${c.symbol}"><span>${base}</span><span class="${chg>=0?'text-success':'text-danger'}">${parseFloat(c.lastPrice).toFixed(2)}</span></a></li>`;
});
}
function filterCoins() {
renderCoins(document.getElementById('coin-search').value);
}
function toggleMode(side, mode) {
const pInput = document.getElementById(side === 'contract' ? 'c-price' : side + '-price');
if (mode === 'market') {
pInput.value = '市价价格';
pInput.disabled = true;
pInput.style.color = '#f0b90b';
} else {
pInput.value = currentPrice || '';
pInput.disabled = false;
pInput.style.color = 'white';
}
}
function applySlider(side) {
const val = document.getElementById(side + '-slider').value;
if (side === 'buy') {
document.getElementById('buy-total').value = (balance * (val / 100)).toFixed(2);
} else if (side === 'sell') {
// Simulated 1.5 BTC for testing
document.getElementById('sell-amount').value = (1.5 * (val / 100)).toFixed(4);
} else if (side === 'contract') {
const margin = (balance * (val / 100));
document.getElementById('c-margin').textContent = margin.toFixed(2);
document.getElementById('c-amount').value = Math.floor((margin * leverage) / 100);
}
}
function setLev(l) {
leverage = l;
document.getElementById('lev-btn').textContent = '杠杆: ' + l + 'x';
document.getElementById('lev-val').textContent = l + 'x';
applySlider('contract');
}
async function tick() {
try {
const r = await fetch('https://api.binance.com/api/v3/ticker/24hr?symbol=' + symbol);
const d = await r.json();
currentPrice = parseFloat(d.lastPrice);
document.getElementById('header-price').textContent = currentPrice.toLocaleString();
document.getElementById('header-price-usd').textContent = currentPrice.toLocaleString();
document.getElementById('current-price-book').textContent = currentPrice.toLocaleString();
const chg = parseFloat(d.priceChangePercent);
document.getElementById('header-change').textContent = (chg>=0?'+':'') + chg.toFixed(2) + '%';
document.getElementById('header-change').className = 'fw-bold ' + (chg>=0?'text-success':'text-danger');
document.getElementById('header-volume').textContent = (parseFloat(d.quoteVolume)/1000000).toFixed(2) + 'M';
// Order Book
const askD = document.getElementById('asks'); const bidD = document.getElementById('bids');
askD.innerHTML = ''; bidD.innerHTML = '';
for (let i = 0; i < 10; i++) {
askD.innerHTML = `<div class="order-book-row"><span class="text-danger">${(currentPrice+(10-i)*0.1).toFixed(2)}</span><span>${(Math.random()*1.2).toFixed(4)}</span><div class="ask-bg" style="width:${Math.random()*70}%"></div></div>` + askD.innerHTML;
bidD.innerHTML += `<div class="order-book-row"><span class="text-success">${(currentPrice-(i+1)*0.1).toFixed(2)}</span><span>${(Math.random()*1.2).toFixed(4)}</span><div class="bid-bg" style="width:${Math.random()*70}%"></div></div>`;
}
// Sync limit inputs if empty
if (tradeType === 'SPOT') {
if (!document.getElementById('buy-price').value && !document.getElementById('buy-price').disabled) document.getElementById('buy-price').value = currentPrice;
if (!document.getElementById('sell-price').value && !document.getElementById('sell-price').disabled) document.getElementById('sell-price').value = currentPrice;
} else {
if (!document.getElementById('c-price').value && !document.getElementById('c-price').disabled) document.getElementById('c-price').value = currentPrice;
}
} catch(e) {}
}
function submitOrder(side) {
alert('订单已提交,正在匹配中...');
}
initTV(); getMarkets(); tick();
setInterval(tick, 2000);
</script>
{% endblock %}

View File

@ -0,0 +1,88 @@
{% extends "base.html" %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6 animate-up">
<div class="glass-card p-4">
<div class="text-center mb-5">
<div class="bg-primary bg-opacity-10 rounded-circle d-inline-block p-4 mb-3">
<i class="bi bi-person-badge text-primary fs-1"></i>
</div>
<h3 class="fw-bold">身份验证 (KYC)</h3>
<p class="text-secondary">为确保您的账户安全并提高提现额度,请完成身份验证。</p>
</div>
{% if account.kyc_status == 'UNVERIFIED' %}
<div class="row g-4 mb-4">
<div class="col-6">
<div class="p-3 border border-secondary border-opacity-25 rounded-3 text-center">
<i class="bi bi-person-vcard fs-2 text-secondary d-block mb-2"></i>
<span class="small fw-bold text-white">L1 基础认证</span>
<p class="text-secondary x-small mt-2 mb-0">提现额度: 20k USDT/日</p>
</div>
</div>
<div class="col-6">
<div class="p-3 border border-warning border-opacity-50 rounded-3 text-center bg-warning bg-opacity-5">
<i class="bi bi-shield-check fs-2 text-warning d-block mb-2"></i>
<span class="small fw-bold text-white">L2 高级认证</span>
<p class="text-secondary x-small mt-2 mb-0">提现额度: 无限制</p>
</div>
</div>
</div>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="mb-3">
<label class="form-label text-secondary">姓名</label>
<input type="text" class="form-control bg-dark text-white border-secondary border-opacity-25" placeholder="请输入您的真实姓名" required>
</div>
<div class="mb-3">
<label class="form-label text-secondary">证件类型</label>
<select class="form-select bg-dark text-white border-secondary border-opacity-25">
<option>身份证</option>
<option>护照</option>
<option>驾驶证</option>
</select>
</div>
<div class="mb-4">
<label class="form-label text-secondary">证件号码</label>
<input type="text" class="form-control bg-dark text-white border-secondary border-opacity-25" placeholder="请输入您的证件号码" required>
</div>
<div class="row g-3 mb-4">
<div class="col-6">
<label class="form-label text-secondary small">证件正面</label>
<div class="border border-dashed border-secondary border-opacity-50 rounded p-4 text-center cursor-pointer" style="border-style: dashed !important;">
<i class="bi bi-plus-lg text-secondary"></i>
</div>
</div>
<div class="col-6">
<label class="form-label text-secondary small">证件反面</label>
<div class="border border-dashed border-secondary border-opacity-50 rounded p-4 text-center cursor-pointer" style="border-style: dashed !important;">
<i class="bi bi-plus-lg text-secondary"></i>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary-custom w-100 py-3">提交认证</button>
</form>
{% elif account.kyc_status == 'PENDING' %}
<div class="text-center py-5">
<div class="spinner-border text-warning mb-4" role="status"></div>
<h5 class="fw-bold">资料审核中</h5>
<p class="text-secondary">我们正在加速审核您的资料,预计需要 1-2 个工作日。</p>
<a href="/profile/" class="btn btn-outline-light mt-3">返回个人中心</a>
</div>
{% elif account.kyc_status == 'VERIFIED' %}
<div class="text-center py-5">
<i class="bi bi-check-circle-fill text-success" style="font-size: 5rem;"></i>
<h4 class="fw-bold mt-4">认证已成功</h4>
<p class="text-secondary">您已完成身份验证,现在可以享受完整的功能服务。</p>
<a href="/profile/" class="btn btn-outline-light mt-3">返回个人中心</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,74 @@
{% extends "base.html" %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-6 animate-up">
<div class="glass-card p-4">
<h3 class="fw-bold mb-4 text-center">提取数字资产</h3>
<div class="d-flex justify-content-between mb-4">
<span class="text-secondary">可用余额</span>
<span class="fw-bold">{{ account.balance|default:"0.00" }} USDT</span>
</div>
<div class="mb-4">
<label class="form-label text-secondary">提取币种</label>
<div class="d-flex align-items-center bg-dark p-3 rounded border border-secondary border-opacity-25">
<i class="bi bi-coin text-warning fs-4 me-3"></i>
<div class="flex-grow-1">
<h6 class="m-0 fw-bold">USDT</h6>
<small class="text-secondary">Tether US</small>
</div>
<i class="bi bi-chevron-down text-secondary"></i>
</div>
</div>
<form method="POST">
{% csrf_token %}
<div class="mb-4">
<label class="form-label text-secondary">提现网络</label>
<select class="form-select bg-dark text-white border-secondary border-opacity-25 py-2">
<option value="TRC20">TRON (TRC20) - 手续费 1.00 USDT</option>
<option value="ERC20" disabled>Ethereum (ERC20) - 手续费 15.00 USDT</option>
</select>
</div>
<div class="mb-4">
<label class="form-label text-secondary">提现地址</label>
<input type="text" name="address" class="form-control bg-dark text-white border-secondary border-opacity-25 py-2" placeholder="请输入您的提现地址" required>
</div>
<div class="mb-4">
<label class="form-label text-secondary">提现金额</label>
<div class="input-group">
<input type="number" name="amount" id="withdraw-amount" step="0.01" class="form-control bg-dark text-white border-secondary border-opacity-25 py-2" placeholder="最小提现数量 10" required>
<button type="button" class="btn btn-outline-secondary border-secondary border-opacity-25 text-warning" onclick="document.getElementById('withdraw-amount').value = '{{ account.balance }}'">全部</button>
</div>
<div class="d-flex justify-content-between mt-2 small">
<span class="text-secondary">手续费</span>
<span class="text-white">1.00 USDT</span>
</div>
</div>
<div class="bg-warning bg-opacity-10 p-3 rounded mb-4">
<div class="d-flex justify-content-between">
<span class="text-secondary small">实际到账金额</span>
<h5 class="fw-bold text-warning m-0" id="final-amount">0.00 USDT</h5>
</div>
</div>
<button type="submit" class="btn btn-primary-custom w-100 py-3">提交提现申请</button>
</form>
</div>
</div>
</div>
</div>
<script>
document.getElementById('withdraw-amount').addEventListener('input', function(e) {
const val = parseFloat(e.target.value) || 0;
const final = Math.max(0, val - 1).toFixed(2);
document.getElementById('final-amount').innerText = final + ' USDT';
});
</script>
{% endblock %}

View File

@ -1,7 +1,24 @@
from django.urls import path
from .views import home
from . import views
urlpatterns = [
path("", home, name="home"),
path('', views.index, name='index'),
path('spot/', views.trade, {'trade_type': 'spot'}, name='spot_trade'),
path('contract/', views.trade, {'trade_type': 'contract'}, name='contract_trade'),
path('markets/', views.market_center, name='market_center'),
path('profile/', views.profile, name='profile'),
path('deposit/', views.deposit, name='deposit'),
path('withdraw/', views.withdraw, name='withdraw'),
path('verify/', views.verify, name='verify'),
path('login/', views.login_view, name='login'),
path('register/', views.register_view, name='register'),
path('api/market_data/', views.market_data, name='market_data'),
path('api/submit_order/', views.submit_order, name='submit_order'),
# Footer links
path('help/', views.placeholder_view, {'title': '帮助中心'}, name='help_center'),
path('support/', views.placeholder_view, {'title': '技术支持'}, name='support'),
path('request/', views.placeholder_view, {'title': '提交请求'}, name='submit_request'),
path('announcements/', views.placeholder_view, {'title': '公告中心'}, name='announcements'),
path('assets/', views.profile, name='asset_management'),
]

View File

@ -1,25 +1,244 @@
import os
import platform
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
from django import get_version as django_version
from django.shortcuts import render
from django.utils import timezone
def home(request):
"""Render the landing screen with loader and environment details."""
host_name = request.get_host().lower()
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
now = timezone.now()
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 = {
"project_name": "New Style",
"agent_brand": agent_brand,
"django_version": django_version(),
"python_version": platform.python_version(),
"current_time": now,
"host_name": host_name,
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
'symbol': symbol,
'trade_type': trade_type.upper(),
'cryptos': cryptos,
}
return render(request, "core/index.html", context)
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)

View File

@ -1,4 +1,162 @@
/* Custom styles for the application */
body {
font-family: system-ui, -apple-system, sans-serif;
:root {
--bg-dark: #0a0e17;
--bg-card: #161a25;
--bg-card-hover: #1e2330;
--text-primary: #ffffff;
--text-secondary: #848e9c;
--accent-color: #f0b90b;
--accent-hover: #d4a30a;
--up-color: #0ecb81;
--down-color: #f6465d;
--border-color: #2b2f36;
--glass-bg: rgba(255, 255, 255, 0.05);
--glass-border: rgba(255, 255, 255, 0.1);
}
body {
background-color: var(--bg-dark);
color: var(--text-primary);
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
overflow-x: hidden;
}
/* Glassmorphism */
.glass-card {
background: var(--glass-bg);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid var(--glass-border);
border-radius: 16px;
}
/* Animations */
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes float {
0% { transform: translatey(0px); }
50% { transform: translatey(-20px); }
100% { transform: translatey(0px); }
}
.animate-up { animation: fadeInUp 0.8s ease-out forwards; }
.float-icon { animation: float 6s ease-in-out infinite; }
/* Navbar */
.navbar {
background: rgba(10, 14, 23, 0.8) !important;
backdrop-filter: blur(15px);
border-bottom: 1px solid var(--border-color);
}
/* Hero Section */
.hero-section {
padding: 100px 0;
background: radial-gradient(circle at top right, rgba(240, 185, 11, 0.1), transparent 40%),
radial-gradient(circle at bottom left, rgba(14, 203, 129, 0.1), transparent 40%);
}
.hero-title {
font-size: 4rem;
font-weight: 800;
line-height: 1.2;
margin-bottom: 24px;
background: linear-gradient(135deg, #fff 0%, #848e9c 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* Markets Table */
.market-table {
background: var(--bg-card);
border-radius: 16px;
overflow: hidden;
border: 1px solid var(--border-color);
}
.market-table th {
color: var(--text-secondary);
font-weight: 500;
padding: 16px 24px;
border-bottom: 1px solid var(--border-color);
}
.market-table td {
padding: 16px 24px;
border-bottom: 1px solid var(--border-color);
vertical-align: middle;
}
.market-table tr:hover {
background-color: var(--bg-card-hover);
}
/* Buttons */
.btn-primary-custom {
background: var(--accent-color);
color: #000;
border: none;
padding: 12px 32px;
border-radius: 8px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-primary-custom:hover {
background: var(--accent-hover);
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(240, 185, 11, 0.3);
}
/* Carousel / Banners */
.banner-carousel {
border-radius: 20px;
overflow: hidden;
}
.banner-item {
height: 300px;
background-size: cover;
background-position: center;
display: flex;
align-items: center;
padding: 40px;
}
/* Trading Interface */
.trade-container {
display: grid;
grid-template-columns: 1fr 300px 300px;
grid-template-rows: 1fr 300px;
gap: 8px;
height: calc(100vh - 70px);
padding: 8px;
background: #000;
}
.trade-panel {
background: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: 4px;
overflow: hidden;
}
.price-up { color: var(--up-color); }
.price-down { color: var(--down-color); }
/* Custom Scrollbar */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: var(--bg-dark);
}
::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--text-secondary);
}

BIN
static/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB