feat: 自托管超分媒体 + 详情页优先清晰JPG

- 后端 main.ts: 新增 /media 静态服务(指向容器内 /app/media,由卷挂载)
  配合 MEDIA_BASE_URL 指向本服务 /media,彻底脱离 jsDelivr 依赖
- 详情页 hero 优先用超分 JPG(720px),GIF/JPG 互为降级兜底
This commit is contained in:
2026-07-22 15:33:29 +08:00
parent 06bd96a473
commit 98126c62ec
2 changed files with 17 additions and 6 deletions

View File

@@ -1,9 +1,18 @@
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import { existsSync, mkdirSync } from 'fs';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const app = await NestFactory.create<NestExpressApplication>(AppModule);
// 自托管媒体(超分图/动图)静态服务:/media/** -> /app/media/**
// 容器内 /app/media 通过卷挂载服务器目录MEDIA_BASE_URL 指向本服务 /media
const mediaRoot = join(__dirname, '..', 'media');
if (!existsSync(mediaRoot)) mkdirSync(mediaRoot, { recursive: true });
app.useStaticAssets(mediaRoot, { prefix: '/media' });
if (process.env.CORS_ENABLED !== 'false') {
app.enableCors();

View File

@@ -37,8 +37,8 @@ Page({
load() {
this.setData({ loading: true });
svc.getExercise(this.data.id).then((ex) => {
// 详情页用 GIF 演示动作;记录当前图源以便失败降级到 JPG / 占位
const heroSrc = ex && (ex.gifUrl || ex.image) ? (ex.gifUrl || ex.image) : '';
// 详情大图优先用超分 JPG(720px 清晰)失败降级到 GIF / 占位
const heroSrc = ex && (ex.image || ex.gifUrl) ? (ex.image || ex.gifUrl) : '';
this.setData({ exercise: ex, heroSrc, heroError: false, loading: false });
if (ex && ex.target) {
svc.listExercises({ target: ex.target, pageSize: 6 }).then((res) => {
@@ -110,11 +110,13 @@ Page({
}
},
// 详情大图加载失败:GIF→JPG→emoji 占位,三级降级保证不空白
// 详情大图加载失败:JPG↔GIF 互为降级,最后 emoji 占位,保证不空白
onHeroError() {
const ex = this.data.exercise || {};
const showingGif = this.data.heroSrc && ex.gifUrl && this.data.heroSrc === ex.gifUrl;
if (showingGif && ex.image) {
const cur = this.data.heroSrc;
if (cur === ex.image && ex.gifUrl) {
this.setData({ heroSrc: ex.gifUrl });
} else if (cur === ex.gifUrl && ex.image) {
this.setData({ heroSrc: ex.image });
} else {
this.setData({ heroError: true });