Autosave: 20260206-092300
This commit is contained in:
parent
2a7594954f
commit
6a5fce6db2
BIN
assets/pasted-20260206-064839-95c248c7.png
Normal file
BIN
assets/pasted-20260206-064839-95c248c7.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 558 KiB |
Binary file not shown.
@ -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 = '/'
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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')
|
||||
@ -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': "全球领先的数字资产交易平台"
|
||||
}
|
||||
|
||||
0
core/management/__init__.py
Normal file
0
core/management/__init__.py
Normal file
BIN
core/management/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
core/management/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
0
core/management/commands/__init__.py
Normal file
0
core/management/commands/__init__.py
Normal file
BIN
core/management/commands/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
core/management/commands/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/management/commands/__pycache__/seed_crypto.cpython-311.pyc
Normal file
BIN
core/management/commands/__pycache__/seed_crypto.cpython-311.pyc
Normal file
Binary file not shown.
BIN
core/management/commands/__pycache__/seed_site.cpython-311.pyc
Normal file
BIN
core/management/commands/__pycache__/seed_site.cpython-311.pyc
Normal file
Binary file not shown.
71
core/management/commands/seed_crypto.py
Normal file
71
core/management/commands/seed_crypto.py
Normal 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}'))
|
||||
25
core/management/commands/seed_site.py
Normal file
25
core/management/commands/seed_site.py
Normal 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'))
|
||||
71
core/migrations/0001_initial.py
Normal file
71
core/migrations/0001_initial.py
Normal 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')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -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='交易对'),
|
||||
),
|
||||
]
|
||||
@ -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': '充提管理',
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -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',
|
||||
),
|
||||
]
|
||||
28
core/migrations/0005_sitesettings.py
Normal file
28
core/migrations/0005_sitesettings.py
Normal 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': '系统设置',
|
||||
},
|
||||
),
|
||||
]
|
||||
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
core/migrations/__pycache__/0005_sitesettings.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0005_sitesettings.cpython-311.pyc
Normal file
Binary file not shown.
143
core/models.py
143
core/models.py
@ -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 = _("充提管理")
|
||||
@ -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">© 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>
|
||||
|
||||
@ -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 %}
|
||||
|
||||
65
core/templates/core/deposit.html
Normal file
65
core/templates/core/deposit.html
Normal 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 %}
|
||||
@ -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 %}
|
||||
86
core/templates/core/login.html
Normal file
86
core/templates/core/login.html
Normal 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 %}
|
||||
222
core/templates/core/profile.html
Normal file
222
core/templates/core/profile.html
Normal 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 %}
|
||||
96
core/templates/core/register.html
Normal file
96
core/templates/core/register.html
Normal 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 %}
|
||||
356
core/templates/core/trade.html
Normal file
356
core/templates/core/trade.html
Normal 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 %}
|
||||
88
core/templates/core/verify.html
Normal file
88
core/templates/core/verify.html
Normal 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 %}
|
||||
74
core/templates/core/withdraw.html
Normal file
74
core/templates/core/withdraw.html
Normal 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 %}
|
||||
23
core/urls.py
23
core/urls.py
@ -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'),
|
||||
]
|
||||
261
core/views.py
261
core/views.py
@ -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)
|
||||
@ -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
BIN
static/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 558 KiB |
Loading…
x
Reference in New Issue
Block a user