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 %} - - +
- -Published on {{ article.created_at|date:"F d, Y" }}
-{{ content }}
+ + {% if faqs %} +我们的全球客服团队 24/7 全天候在线为您提供专业支持。
+实时获取全球顶级加密货币价格走势
+BitCrypto 每日提取 10% 的交易手续费,存入资产保障基金,为您在极端情况下的资产提供全额赔付保障。
+每秒 200 万次的交易撮合能力,保证在市场波动剧烈时依然能够快速响应,不漏掉任何一个成交机会。
+我们对用户数据采取离线分布式存储和多层加密,绝不将个人隐私泄露给任何第三方,确保您的身份隐私。
+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" }}
-
总资产折合 (USDT)
+已绑定: {{ user.email|default:"未设置" }}
+用于提币和安全确认
+未绑定手机号
+提升提现额度至 100 BTC
+暂无当前委托订单
+| 时间 | +币种 | +类型 | +价格 | +数量 | +状态 | +
|---|---|---|---|---|---|
| {{ order.created_at|date:"m-d H:i" }} | +{{ order.symbol }} | +{{ order.side }} | +{{ order.entry_price }} | +{{ order.amount }} | +{{ order.status }} | +
| 暂无记录 | |||||
| 时间 | +类型 | +币种 | +金额 | +状态 | +
|---|---|---|---|---|
| {{ tx.timestamp|date:"m-d H:i" }} | +{{ tx.get_transaction_type_display }} | +USDT | +{{ tx.amount }} | +{{ tx.get_status_display }} | +
| 暂无记录 | ||||
开启您的加密资产财富之旅
+已有账户? 立即登录
+| 币种 | +价格 | +24h | +
|---|
为确保您的账户安全并提高提现额度,请完成身份验证。
+提现额度: 20k USDT/日
+提现额度: 无限制
+