diff --git a/assets/pasted-20260206-064839-95c248c7.png b/assets/pasted-20260206-064839-95c248c7.png new file mode 100644 index 0000000..9bf70e3 Binary files /dev/null and b/assets/pasted-20260206-064839-95c248c7.png differ diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 96bce55..30bf111 100644 Binary files a/config/__pycache__/settings.cpython-311.pyc and b/config/__pycache__/settings.cpython-311.pyc differ diff --git a/config/settings.py b/config/settings.py index 291d043..2ee5fc7 100644 --- a/config/settings.py +++ b/config/settings.py @@ -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 = '/' diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index a5ed392..05b1b5e 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/context_processors.cpython-311.pyc b/core/__pycache__/context_processors.cpython-311.pyc index 75bf223..000b231 100644 Binary files a/core/__pycache__/context_processors.cpython-311.pyc and b/core/__pycache__/context_processors.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index e061640..d3e41d7 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 5a69659..af3b707 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 2a36fd6..84d71d7 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index 8c38f3f..e54966f 100644 --- a/core/admin.py +++ b/core/admin.py @@ -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') \ No newline at end of file diff --git a/core/context_processors.py b/core/context_processors.py index 0bf87c3..c0cf4a5 100644 --- a/core/context_processors.py +++ b/core/context_processors.py @@ -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': "全球领先的数字资产交易平台" } diff --git a/core/management/__init__.py b/core/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/management/__pycache__/__init__.cpython-311.pyc b/core/management/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..2a037ef Binary files /dev/null and b/core/management/__pycache__/__init__.cpython-311.pyc differ diff --git a/core/management/commands/__init__.py b/core/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/management/commands/__pycache__/__init__.cpython-311.pyc b/core/management/commands/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..dec3ff4 Binary files /dev/null and b/core/management/commands/__pycache__/__init__.cpython-311.pyc differ diff --git a/core/management/commands/__pycache__/seed_crypto.cpython-311.pyc b/core/management/commands/__pycache__/seed_crypto.cpython-311.pyc new file mode 100644 index 0000000..bb07013 Binary files /dev/null and b/core/management/commands/__pycache__/seed_crypto.cpython-311.pyc differ diff --git a/core/management/commands/__pycache__/seed_site.cpython-311.pyc b/core/management/commands/__pycache__/seed_site.cpython-311.pyc new file mode 100644 index 0000000..fd61850 Binary files /dev/null and b/core/management/commands/__pycache__/seed_site.cpython-311.pyc differ diff --git a/core/management/commands/seed_crypto.py b/core/management/commands/seed_crypto.py new file mode 100644 index 0000000..8384480 --- /dev/null +++ b/core/management/commands/seed_crypto.py @@ -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}')) diff --git a/core/management/commands/seed_site.py b/core/management/commands/seed_site.py new file mode 100644 index 0000000..cdd6c7b --- /dev/null +++ b/core/management/commands/seed_site.py @@ -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')) diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..cabb973 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -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')}, + }, + ), + ] diff --git a/core/migrations/0002_cryptocurrency_alter_account_options_and_more.py b/core/migrations/0002_cryptocurrency_alter_account_options_and_more.py new file mode 100644 index 0000000..b838c67 --- /dev/null +++ b/core/migrations/0002_cryptocurrency_alter_account_options_and_more.py @@ -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='交易对'), + ), + ] diff --git a/core/migrations/0003_account_credit_score_account_kyc_status_and_more.py b/core/migrations/0003_account_credit_score_account_kyc_status_and_more.py new file mode 100644 index 0000000..7268e17 --- /dev/null +++ b/core/migrations/0003_account_credit_score_account_kyc_status_and_more.py @@ -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': '充提管理', + }, + ), + ] diff --git a/core/migrations/0004_rename_created_at_transaction_timestamp_and_more.py b/core/migrations/0004_rename_created_at_transaction_timestamp_and_more.py new file mode 100644 index 0000000..e34b655 --- /dev/null +++ b/core/migrations/0004_rename_created_at_transaction_timestamp_and_more.py @@ -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', + ), + ] diff --git a/core/migrations/0005_sitesettings.py b/core/migrations/0005_sitesettings.py new file mode 100644 index 0000000..64aac27 --- /dev/null +++ b/core/migrations/0005_sitesettings.py @@ -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': '系统设置', + }, + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..6c50eb3 Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/0002_cryptocurrency_alter_account_options_and_more.cpython-311.pyc b/core/migrations/__pycache__/0002_cryptocurrency_alter_account_options_and_more.cpython-311.pyc new file mode 100644 index 0000000..109ba6b Binary files /dev/null and b/core/migrations/__pycache__/0002_cryptocurrency_alter_account_options_and_more.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/0003_account_credit_score_account_kyc_status_and_more.cpython-311.pyc b/core/migrations/__pycache__/0003_account_credit_score_account_kyc_status_and_more.cpython-311.pyc new file mode 100644 index 0000000..2d398f0 Binary files /dev/null and b/core/migrations/__pycache__/0003_account_credit_score_account_kyc_status_and_more.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/0004_rename_created_at_transaction_timestamp_and_more.cpython-311.pyc b/core/migrations/__pycache__/0004_rename_created_at_transaction_timestamp_and_more.cpython-311.pyc new file mode 100644 index 0000000..6a634ad Binary files /dev/null and b/core/migrations/__pycache__/0004_rename_created_at_transaction_timestamp_and_more.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/0005_sitesettings.cpython-311.pyc b/core/migrations/__pycache__/0005_sitesettings.cpython-311.pyc new file mode 100644 index 0000000..2d7e26f Binary files /dev/null and b/core/migrations/__pycache__/0005_sitesettings.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 71a8362..a9c352c 100644 --- a/core/models.py +++ b/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 = _("充提管理") \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..43afb9b 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,25 +1,198 @@ +{% load static %} - - + - - {% block title %}Knowledge Base{% endblock %} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - {% load static %} - - {% block head %}{% endblock %} + + + {{ project_name }} - 全球领先的数字资产交易平台 + + + + + - - {% block content %}{% endblock %} - + +
+ {% block content %}{% endblock %} +
+ + + {% if site_settings.customer_service_url %} + + + + {% endif %} + + + + + {% block scripts %}{% endblock %} + diff --git a/core/templates/core/article_detail.html b/core/templates/core/article_detail.html index 8820990..1841531 100644 --- a/core/templates/core/article_detail.html +++ b/core/templates/core/article_detail.html @@ -1,14 +1,66 @@ {% extends 'base.html' %} - -{% block title %}{{ article.title }}{% endblock %} +{% load static %} {% block content %} -
-

{{ article.title }}

-

Published on {{ article.created_at|date:"F d, Y" }}

-
-
- {{ article.content|safe }} +
+
+
+
+ + +

{{ title }}

+ +
+

{{ content }}

+ + {% if faqs %} +
+

常见问题 (FAQ)

+
+ {% for faq in faqs %} +
+

+ +

+
+
+ {{ faq.a }} +
+
+
+ {% endfor %} +
+ {% endif %} + +
+
还需要更多帮助吗?
+

我们的全球客服团队 24/7 全天候在线为您提供专业支持。

+
+ + +
+
+
+
+
+ + {% endblock %} diff --git a/core/templates/core/deposit.html b/core/templates/core/deposit.html new file mode 100644 index 0000000..7a22c87 --- /dev/null +++ b/core/templates/core/deposit.html @@ -0,0 +1,65 @@ +{% extends "base.html" %} +{% block content %} +
+
+
+
+

充值数字资产

+ +
+ +
+ +
+
USDT
+ Tether US +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+
+ QR +
+ 充值地址 (TRC20) +
+ TRX789sDqW12vNpkL90ZxY56uMvB45RtQp + +
+
+ +
+ + 请仅向该地址充值 USDT。任何其他资产的充值都将无法找回。 +
+ +
+ {% csrf_token %} +
+ +
+ + USDT +
+
+
+ + +
+ +
+
+
+
+
+{% endblock %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..3cb6fda 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,235 @@ -{% extends "base.html" %} +{% extends 'base.html' %} +{% load static %} -{% block title %}{{ project_name }}{% endblock %} +{% block content %} + + + + +
+
+
+
iOS 下载
+ +
+
+
+
安卓下载
+ +
+
+
+
API 支持
+ +
+
+
+ + +
+
+
+

热门行情

+

实时获取全球顶级加密货币价格走势

+
+ 查看更多市场 +
+ +
+ + + + + + + + + + + + + + + +
币种价格24h 涨跌24h 最高 / 最低操作
+
+

正在加载实时行情...

+
+
+
+ + +
+

领先行业的资产安全防护

+
+
+
+
+ +
+

资产保障基金

+

BitCrypto 每日提取 10% 的交易手续费,存入资产保障基金,为您在极端情况下的资产提供全额赔付保障。

+
+
+
+
+
+ +
+

高性能交易引擎

+

每秒 200 万次的交易撮合能力,保证在市场波动剧烈时依然能够快速响应,不漏掉任何一个成交机会。

+
+
+
+
+
+ +
+

严密的隐私保护

+

我们对用户数据采取离线分布式存储和多层加密,绝不将个人隐私泄露给任何第三方,确保您的身份隐私。

+
+
+
+
-{% block head %} - - - {% endblock %} -{% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… -
-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
-
-
- Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC) -
+{% block scripts %} + {% endblock %} \ No newline at end of file diff --git a/core/templates/core/login.html b/core/templates/core/login.html new file mode 100644 index 0000000..8d6ce2c --- /dev/null +++ b/core/templates/core/login.html @@ -0,0 +1,86 @@ +{% extends 'base.html' %} +{% load static %} + +{% block content %} +
+
+
+
+ +
+

欢迎登录 BitCrypto

+

全球领先的加密资产交易平台

+
+ +
+ {% csrf_token %} + {% for field in form %} +
+ +
+ + {% if '用户' in field.label %}{% else %}{% endif %} + + +
+ {% for error in field.errors %} +
{{ error }}
+ {% endfor %} +
+ {% endfor %} + +
+
+ + +
+ 忘记密码? +
+ + +
+ +
+

还没有账户? 立即注册

+
+ +
+

其他登录方式

+
+ + + +
+
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/profile.html b/core/templates/core/profile.html new file mode 100644 index 0000000..437e3ee --- /dev/null +++ b/core/templates/core/profile.html @@ -0,0 +1,222 @@ +{% extends 'base.html' %} +{% load static %} + +{% block content %} +
+ +
+
+
+
+ {{ user.username|first|upper }} +
+
+
+

{{ user.username }}

+
+ UID: 59302{{ user.id }} + + {% if account.kyc_status == 'completed' %}已认证{% elif account.kyc_status == 'pending' %}审核中{% else %}未认证{% endif %} + + 注册时间: {{ user.date_joined|date:"Y-m-d" }} +
+
+
+
+ 充币 + 提币 +
+
+
+
+ +
+ +
+
+
资产总览
+
+

总资产折合 (USDT)

+

≈ {{ account.balance|default:"0.00" }} USDT

+
+ +
+ +
+
+
现货账户
+
Spot Account
+
+
+
{{ account.balance|default:"0.00" }} USDT
+
≈ $0.00
+
+
+ +
+
+
合约账户
+
Futures Account
+
+
+
0.00 USDT
+
未开通
+
+
+ +
+
+
理财账户
+
Earn Account
+
+
+
0.00 USDT
+
年化 3.5%起
+
+
+ + 查看明细 +
+
+ + +
+ +
+
安全设置
+
+
+
+ +
+
邮箱验证
+

已绑定: {{ user.email|default:"未设置" }}

+
+ +
+
+
+
+ +
+
谷歌验证器
+

用于提币和安全确认

+
+ +
+
+
+
+ +
+
手机验证
+

未绑定手机号

+
+ +
+
+
+
+ +
+
身份认证 (KYC)
+

提升提现额度至 100 BTC

+
+ 立即认证 +
+
+
+
+ + +
+ + +
+
+
+ +

暂无当前委托订单

+
+
+
+
+ + + + + + + + + + + + + {% for order in recent_orders %} + + + + + + + + + {% empty %} + + {% endfor %} + +
时间币种类型价格数量状态
{{ order.created_at|date:"m-d H:i" }}{{ order.symbol }}{{ order.side }}{{ order.entry_price }}{{ order.amount }}{{ order.status }}
暂无记录
+
+
+
+
+ + + + + + + + + + + + {% for tx in recent_transactions %} + + + + + + + + {% empty %} + + {% endfor %} + +
时间类型币种金额状态
{{ tx.timestamp|date:"m-d H:i" }}{{ tx.get_transaction_type_display }}USDT{{ tx.amount }}{{ tx.get_status_display }}
暂无记录
+
+
+
+
+
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/register.html b/core/templates/core/register.html new file mode 100644 index 0000000..2aaa8be --- /dev/null +++ b/core/templates/core/register.html @@ -0,0 +1,96 @@ +{% extends 'base.html' %} +{% load static %} + +{% block content %} +
+
+
+

注册 {{ site_settings.site_name }} 账户

+

开启您的加密资产财富之旅

+
+ + {% if messages %} +
+ {% for message in messages %} + + {% endfor %} +
+ {% endif %} + +
+ {% csrf_token %} +
+ +
+ + + + +
+
+ +
+ +
+ + + + +
+
+ +
+ +
+ + + + +
+
+ +
+ +
+ + + + +
+
+ +
+
+ + +
+
+ + +
+ +
+

已有账户? 立即登录

+
+
+
+ + +{% endblock %} diff --git a/core/templates/core/trade.html b/core/templates/core/trade.html new file mode 100644 index 0000000..912103a --- /dev/null +++ b/core/templates/core/trade.html @@ -0,0 +1,356 @@ +{% extends 'base.html' %} +{% load static %} + +{% block content %} +
+
+ +
+
+
+
+ + +
+
+
+ + + + + + + + + + + +
币种价格24h
+
+
+
+ + +
+ +
+
+ +
+
--
+
≈ $--
+
+
+
24h 涨跌
+
--
+
+
+
24h 成交量(USDT)
+
--
+
+
+
+ 现货 + 合约 +
+
+ + +
+
+
+ + +
+ {% if trade_type == 'SPOT' %} +
+ +
+
+ + + + +
+ +
+ 价格 + + USDT +
+ +
+ 成交额 + + USDT +
+ +
+ +
+ 0%25%50%75%100% +
+
+ +
+ 可用余额 + {{ account.balance|default:"0.00" }} USDT +
+ +
+ + +
+
+ + + + +
+ +
+ 价格 + + USDT +
+ +
+ 数量 + + {{ symbol|slice:":-4" }} +
+ +
+ +
+ 0%25%50%75%100% +
+
+ +
+ 可用 {{ symbol|slice:":-4" }} + 0.00 +
+ +
+
+ {% else %} + +
+
+
+ + + + +
+ +
+
+
+ 价格 + + USDT +
+
+ 手数 + + +
+
+ +
+
+ 保证金: 0.00 USDT + 可用: {{ account.balance|default:"0.00" }} USDT +
+
+
+
+
+
+
+
+
合约面值100 USDT
+
当前杠杆20x
+
预计手续费0.05%
+
维持保证金0.4%
+
+
+
+ {% endif %} +
+
+ + +
+
+
+ 价格(USDT) + 数量({{ symbol|slice:":-4" }}) +
+
+
+ -- +
+
+
+
+
+
+ + +{% endblock %} + +{% block scripts %} + + +{% endblock %} diff --git a/core/templates/core/verify.html b/core/templates/core/verify.html new file mode 100644 index 0000000..1898200 --- /dev/null +++ b/core/templates/core/verify.html @@ -0,0 +1,88 @@ +{% extends "base.html" %} +{% block content %} +
+
+
+
+
+
+ +
+

身份验证 (KYC)

+

为确保您的账户安全并提高提现额度,请完成身份验证。

+
+ + {% if account.kyc_status == 'UNVERIFIED' %} +
+
+
+ + L1 基础认证 +

提现额度: 20k USDT/日

+
+
+
+
+ + L2 高级认证 +

提现额度: 无限制

+
+
+
+ +
+ {% csrf_token %} +
+ + +
+
+ + +
+
+ + +
+ +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ + +
+ {% elif account.kyc_status == 'PENDING' %} +
+
+
资料审核中
+

我们正在加速审核您的资料,预计需要 1-2 个工作日。

+ 返回个人中心 +
+ {% elif account.kyc_status == 'VERIFIED' %} +
+ +

认证已成功

+

您已完成身份验证,现在可以享受完整的功能服务。

+ 返回个人中心 +
+ {% endif %} +
+
+
+
+{% endblock %} diff --git a/core/templates/core/withdraw.html b/core/templates/core/withdraw.html new file mode 100644 index 0000000..63dd5cd --- /dev/null +++ b/core/templates/core/withdraw.html @@ -0,0 +1,74 @@ +{% extends "base.html" %} +{% block content %} +
+
+
+
+

提取数字资产

+ +
+ 可用余额 + {{ account.balance|default:"0.00" }} USDT +
+ +
+ +
+ +
+
USDT
+ Tether US +
+ +
+
+ +
+ {% csrf_token %} +
+ + +
+ +
+ + +
+ +
+ +
+ + +
+
+ 手续费 + 1.00 USDT +
+
+ +
+
+ 实际到账金额 +
0.00 USDT
+
+
+ + +
+
+
+
+
+ + +{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..3c7eeea 100644 --- a/core/urls.py +++ b/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'), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index c9aed12..270d68f 100644 --- a/core/views.py +++ b/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) \ No newline at end of file diff --git a/static/css/custom.css b/static/css/custom.css index 925f6ed..2dcebb2 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -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); +} \ No newline at end of file diff --git a/static/images/logo.png b/static/images/logo.png new file mode 100644 index 0000000..9bf70e3 Binary files /dev/null and b/static/images/logo.png differ