diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c11f2dc --- /dev/null +++ b/.env.example @@ -0,0 +1,16 @@ +# 复制为 .env 后填写。仅在使用 frpc 内网穿透时需要。 +# cp .env.example .env + +# frps 地址与端口(公网或局域网中的 FRP 服务端) +FRP_SERVER_ADDR=your-frps-host.example.com +FRP_SERVER_PORT=7000 +FRP_TOKEN=your-frp-token + +# HTTP 穿透:在 frps 上配置的域名(须与 frps 中 vhostHTTPPort 等匹配) +FRP_CUSTOM_DOMAIN=mwy.example.com + +# 公网访问地址(用于 Django CORS / CSRF;带协议,HTTPS 时写 https://) +FRP_PUBLIC_ORIGIN=https://mwy.example.com + +# 可选:TCP 穿透时 frps 对外端口(使用 frpc.toml 中 tcp 配置时填写) +# FRP_REMOTE_PORT=18080 diff --git a/.gitignore b/.gitignore index ab23fa8..f3abf39 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ frontend/node_modules/ frontend/dist/ *.log .DS_Store +.env +frpc/frpc.log diff --git a/backend/Dockerfile b/backend/Dockerfile index ab72762..9714f67 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -20,6 +20,6 @@ RUN pip install --no-cache-dir -r requirements.txt COPY . . RUN chmod +x /app/docker-entrypoint.sh -EXPOSE 8000 +EXPOSE 8963 ENTRYPOINT ["/app/docker-entrypoint.sh"] diff --git a/backend/docker-entrypoint.sh b/backend/docker-entrypoint.sh index f3abdb0..47de625 100644 --- a/backend/docker-entrypoint.sh +++ b/backend/docker-entrypoint.sh @@ -3,4 +3,4 @@ set -e mkdir -p "$(dirname "${SQLITE_PATH:-/data/db.sqlite3}")" "${MEDIA_ROOT:-/data/media}" python manage.py migrate --noinput python manage.py collectstatic --noinput -exec gunicorn ourstory.wsgi:application --bind 0.0.0.0:8000 --workers 2 +exec gunicorn ourstory.wsgi:application --bind 0.0.0.0:8963 --workers 2 diff --git a/backend/journal/admin.py b/backend/journal/admin.py index 79d9121..4b98552 100644 --- a/backend/journal/admin.py +++ b/backend/journal/admin.py @@ -145,7 +145,6 @@ class ConfigAdmin(admin.ModelAdmin): list_display = ( "site_title", "together_since", - "bgm_enabled", "unlock_at", ) list_display_links = ("site_title",) @@ -155,17 +154,13 @@ class ConfigAdmin(admin.ModelAdmin): {"fields": ("site_title",)}, ), ( - "时间与音乐", + "时间", { "fields": ( "together_since", - "bgm_enabled", "unlock_at", ), - "description": ( - "「在一起」时间用于首页计数。顶部网易云播放器在前端 .env 的 " - "VITE_NETEASE_PLAYER_SRC 配置。unlock_at 已不使用,可留空。" - ), + "description": "「在一起」时间用于首页计数。unlock_at 已不使用,可留空。", }, ), ) diff --git a/backend/journal/migrations/0007_remove_config_bgm_enabled.py b/backend/journal/migrations/0007_remove_config_bgm_enabled.py new file mode 100644 index 0000000..1a47ffc --- /dev/null +++ b/backend/journal/migrations/0007_remove_config_bgm_enabled.py @@ -0,0 +1,15 @@ +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('journal', '0006_memory_photo'), + ] + + operations = [ + migrations.RemoveField( + model_name='config', + name='bgm_enabled', + ), + ] diff --git a/backend/journal/models.py b/backend/journal/models.py index e262889..d35e2f1 100644 --- a/backend/journal/models.py +++ b/backend/journal/models.py @@ -123,10 +123,6 @@ class Config(models.Model): null=True, help_text="用于首页「我们在一起多少天多少秒」的起点(建议为正式在一起的时刻,含时区)。", ) - bgm_enabled = models.BooleanField( - default=True, - help_text="是否展示顶部音乐区(播放器地址在前端环境变量 VITE_NETEASE_PLAYER_SRC 配置)。", - ) site_title = models.CharField( max_length=120, default="Nepal Journey: Our Story", diff --git a/backend/journal/views.py b/backend/journal/views.py index 76fc242..6e5ab9c 100644 --- a/backend/journal/views.py +++ b/backend/journal/views.py @@ -35,12 +35,10 @@ class StatusView(APIView): config = Config.objects.filter(pk=1).first() if config is None: - bgm_enabled = True site_title = "Nepal Journey: Our Story" together_since = default_together unlock_at = None else: - bgm_enabled = config.bgm_enabled site_title = config.site_title or "Nepal Journey: Our Story" ts = config.together_since if ts is None: @@ -63,7 +61,6 @@ class StatusView(APIView): "unlocked": True, "unlock_at": unlock_at, "together_since": together_since, - "bgm_enabled": bgm_enabled, "site_title": site_title, } ) diff --git a/backend/ourstory/settings.py b/backend/ourstory/settings.py index 612dd9b..263085b 100644 --- a/backend/ourstory/settings.py +++ b/backend/ourstory/settings.py @@ -134,6 +134,6 @@ CSRF_TRUSTED_ORIGINS = [ # 未配置时至少信任本机 Admin,避免部分环境下保存表单被 CSRF 拦截 if not CSRF_TRUSTED_ORIGINS: CSRF_TRUSTED_ORIGINS = [ - "http://127.0.0.1:8000", - "http://localhost:8000", + "http://127.0.0.1:8963", + "http://localhost:8963", ] diff --git a/docker-compose.yml b/docker-compose.yml index e7e074b..11f7c2a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,19 @@ # 一键启动:docker compose up --build -# 前端 http://localhost:8080 后端管理 http://localhost:8000/admin/ +# 前端 http://localhost:8080 后端管理 http://localhost:8963/admin/ +# 内网穿透:cp .env.example .env 并填写后执行 docker compose --profile frp up -d services: backend: build: ./backend ports: - - "8000:8000" + - "8963:8963" volumes: - backend_data:/data environment: DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-dev-secret-change-me} DJANGO_DEBUG: "false" - DJANGO_ALLOWED_HOSTS: localhost,127.0.0.1,backend - CORS_ALLOWED_ORIGINS: http://localhost:8080,http://127.0.0.1:8080 - CSRF_TRUSTED_ORIGINS: http://localhost:8080,http://127.0.0.1:8080 + DJANGO_ALLOWED_HOSTS: localhost,127.0.0.1,backend,${FRP_CUSTOM_DOMAIN:-} + CORS_ALLOWED_ORIGINS: http://localhost:8080,http://127.0.0.1:8080,${FRP_PUBLIC_ORIGIN:-} + CSRF_TRUSTED_ORIGINS: http://localhost:8080,http://127.0.0.1:8080,${FRP_PUBLIC_ORIGIN:-} SQLITE_PATH: /data/db.sqlite3 MEDIA_ROOT: /data/media @@ -23,5 +24,20 @@ services: depends_on: - backend + frpc: + image: snowdreamtech/frpc:0.61 + restart: unless-stopped + depends_on: + - frontend + volumes: + - ./frpc/frpc.toml:/etc/frp/frpc.toml:ro + environment: + FRP_SERVER_ADDR: ${FRP_SERVER_ADDR:-} + FRP_SERVER_PORT: ${FRP_SERVER_PORT:-7000} + FRP_TOKEN: ${FRP_TOKEN:-} + FRP_CUSTOM_DOMAIN: ${FRP_CUSTOM_DOMAIN:-} + profiles: + - frp + volumes: backend_data: diff --git a/frontend/.env.development b/frontend/.env.development index 7d195a7..d8a2e6b 100644 --- a/frontend/.env.development +++ b/frontend/.env.development @@ -1,5 +1,2 @@ # 使用 Vite 代理时保持默认 /api 即可 VITE_API_BASE_URL=/api - -# 网易云外链播放器 src(整段 iframe 亦可,会自动提取 src) -# VITE_NETEASE_PLAYER_SRC=https://music.163.com/outchain/player?type=2&id=2054353432&auto=1&height=66 diff --git a/frontend/nginx.conf b/frontend/nginx.conf index ef85e02..fff210a 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -8,7 +8,7 @@ server { gzip_types text/plain text/css application/javascript application/json image/svg+xml; location /api/ { - proxy_pass http://backend:8000; + proxy_pass http://backend:8963; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -17,7 +17,7 @@ server { } location /media/ { - proxy_pass http://backend:8000; + proxy_pass http://backend:8963; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 850da68..d1d9493 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -54,7 +54,6 @@ export interface StatusPayload { unlocked: boolean unlock_at: string | null together_since: string - bgm_enabled: boolean site_title: string } diff --git a/frontend/src/components/MessageForm.vue b/frontend/src/components/MessageForm.vue index 264216f..7c0ebb4 100644 --- a/frontend/src/components/MessageForm.vue +++ b/frontend/src/components/MessageForm.vue @@ -43,7 +43,7 @@ async function submit() {
@@ -69,7 +69,7 @@ async function submit() { rows="5" maxlength="2000" class="mt-1 w-full resize-y rounded-xl border border-paper-shadow bg-paper/80 px-4 py-3 text-ink shadow-inner outline-none transition focus:border-rose-soft/60 focus:ring-2 focus:ring-rose-soft/25" - placeholder="写下你想说的话…" + placeholder="写下你想说的话…,例如:谢谢你陪伴我度过了这么多美好的时光!" />
diff --git a/frontend/src/components/NeteaseEmbed.vue b/frontend/src/components/NeteaseEmbed.vue
deleted file mode 100644
index a322a65..0000000
--- a/frontend/src/components/NeteaseEmbed.vue
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-