Jelajahi Sumber

提交代码

zlwu 10 bulan lalu
induk
melakukan
b2a8356200

+ 10 - 10
backend/main.py

@@ -298,8 +298,8 @@ class ShareImageItem(BaseModel):
 
 
 SHARE_IMAGES: List[ShareImageItem] = [
-    ShareImageItem(id="share-1", url="https://assets.lyrria.com/share-1.png"),
-    ShareImageItem(id="share-2", url="https://assets.lyrria.com/share-2.png"),
+    ShareImageItem(id="share-1", url="https://www.lyrria.com/img/share-1.png"),
+    ShareImageItem(id="share-2", url="https://www.lyrria.com/img/share-2.png"),
 ]
 
 
@@ -361,16 +361,16 @@ class SessionInitRequest(BaseModel):
 
 AVATAR_GIF_CONFIG = {
     "avatar_default": AvatarGifSet(
-        default="https://assets.lyrria.com/01-Default.gif",
-        positive="https://assets.lyrria.com/04-Positive-emotion.gif",
-        negative="https://assets.lyrria.com/05-Negative-emotion.gif",
-        talking="https://assets.lyrria.com/06-talking.gif",
+        default="https://www.lyrria.com/img/01-Default.gif",
+        positive="https://www.lyrria.com/img/04-Positive-emotion.gif",
+        negative="https://www.lyrria.com/img/05-Negative-emotion.gif",
+        talking="https://www.lyrria.com/img/06-talking.gif",
     ),
     "avatar_registered_cap": AvatarGifSet(
-        default="https://assets.lyrria.com/01-Default-Registered.gif",
-        positive="https://assets.lyrria.com/04-Positive-emotion-Registered.gif",
-        negative="https://assets.lyrria.com/05-Negative-emotion-Registered.gif",
-        talking="https://assets.lyrria.com/06-talking-Registered.gif",
+        default="https://www.lyrria.com/img/01-Default-Registered.gif",
+        positive="https://www.lyrria.com/img/04-Positive-emotion-Registered.gif",
+        negative="https://www.lyrria.com/img/05-Negative-emotion-Registered.gif",
+        talking="https://www.lyrria.com/img/06-talking-Registered.gif",
     ),
 }
 

+ 8 - 8
backend/migrations/migrate_add_avatars.py

@@ -16,10 +16,10 @@ REGISTERED_AVATAR_ID = "avatar_registered_cap"
 
 # 默认形象 GIF 资源
 DEFAULT_AVATAR_ASSETS = [
-    (DEFAULT_AVATAR_ID, "default", "https://assets.lyrria.com/01-Default.gif"),
-    (DEFAULT_AVATAR_ID, "positive", "https://assets.lyrria.com/04-Positive-emotion.gif"),
-    (DEFAULT_AVATAR_ID, "negative", "https://assets.lyrria.com/05-Negative-emotion.gif"),
-    (DEFAULT_AVATAR_ID, "talking", "https://assets.lyrria.com/06-talking.gif"),
+    (DEFAULT_AVATAR_ID, "default", "https://www.lyrria.com/img/01-Default.gif"),
+    (DEFAULT_AVATAR_ID, "positive", "https://www.lyrria.com/img/04-Positive-emotion.gif"),
+    (DEFAULT_AVATAR_ID, "negative", "https://www.lyrria.com/img/05-Negative-emotion.gif"),
+    (DEFAULT_AVATAR_ID, "talking", "https://www.lyrria.com/img/06-talking.gif"),
 ]
 
 # 注册赠送形象 GIF 资源
@@ -27,22 +27,22 @@ REGISTERED_AVATAR_ASSETS = [
     (
         REGISTERED_AVATAR_ID,
         "default",
-        "https://assets.lyrria.com/01-Default-Registered.gif",
+        "https://www.lyrria.com/img/01-Default-Registered.gif",
     ),
     (
         REGISTERED_AVATAR_ID,
         "positive",
-        "https://assets.lyrria.com/04-Positive-emotion-Registered.gif",
+        "https://www.lyrria.com/img/04-Positive-emotion-Registered.gif",
     ),
     (
         REGISTERED_AVATAR_ID,
         "negative",
-        "https://assets.lyrria.com/05-Negative-emotion-Registered.gif",
+        "https://www.lyrria.com/img/05-Negative-emotion-Registered.gif",
     ),
     (
         REGISTERED_AVATAR_ID,
         "talking",
-        "https://assets.lyrria.com/06-talking-Registered.gif",
+        "https://www.lyrria.com/img/06-talking-Registered.gif",
     ),
 ]
 

+ 2 - 2
backend/migrations/migrate_add_background_images.py

@@ -142,7 +142,7 @@ async def migrate_create_background_images_tables() -> bool:
                     INSERT INTO background_images 
                     (image_id, image_name, image_url, unlock_type, display_order, description)
                     VALUES 
-                    ('default', '默认背景', 'https://assets.lyrria.com/init.jpg', 'default', 1, '默认背景图片')
+                    ('default', '默认背景', 'https://www.lyrria.com/img/init.jpg', 'default', 1, '默认背景图片')
                     """
                 )
                 print("✅ 默认背景图片已添加")
@@ -161,7 +161,7 @@ async def migrate_create_background_images_tables() -> bool:
                     INSERT INTO background_images 
                     (image_id, image_name, image_url, unlock_type, display_order, description)
                     VALUES 
-                    ('happynewyear', '新年背景', 'https://assets.lyrria.com/bg-happynewyear.png', 'default', 2, '新年背景图片')
+                    ('happynewyear', '新年背景', 'https://www.lyrria.com/img/bg-happynewyear.png', 'default', 2, '新年背景图片')
                     """
                 )
                 print("✅ 新年背景图片已添加")

+ 2 - 2
frontend/.env.production

@@ -13,8 +13,8 @@ VITE_SSL_KEYFILE=/etc/nginx/cert/lyrria.com.key
 VITE_SSL_CERTFILE=/etc/nginx/cert/lyrria.com.pem
 
 VITE_ENABLE_HTTPS=true
-VITE_WELCOME_VIDEO_URL=https://assets.lyrria.com/Lyrria-video.mp4
-VITE_OSS_BASE_URL=https://assets.lyrria.com
+VITE_WELCOME_VIDEO_URL=https://www.lyrria.com/img/Lyrria-video.mp4
+VITE_OSS_BASE_URL=https://www.lyrria.com/img
 
 # SSL证书路径(可选,打包时不需要)
 # VITE_SSL_KEYFILE=/path/to/production/key.pem

+ 2 - 2
frontend/.env.production-cy

@@ -10,7 +10,7 @@ VITE_ENABLE_HTTPS=true
 VITE_SSL_KEYFILE=/root/.acme.sh/chengyantek.cn_ecc/chengyantek.cn.key
 VITE_SSL_CERTFILE=/root/.acme.sh/chengyantek.cn_ecc/fullchain.cer
 
-VITE_WELCOME_VIDEO_URL=http://assets.lyrria.com/Lyrria-video.mp4
-VITE_OSS_BASE_URL=http://assets.lyrria.com
+VITE_WELCOME_VIDEO_URL=http://www.lyrria.com/img/Lyrria-video.mp4
+VITE_OSS_BASE_URL=http://www.lyrria.com/img
 
 VITE_API_CLIENT_KEY=jdafdsfasfaakkkzxmfdxdd

+ 2 - 2
frontend/ENV_CONFIG.md

@@ -24,8 +24,8 @@ cp .env.example .env
 | `VITE_API_BASE_URL` | API 基础 URL | - | 否 |
 | `VITE_API_CLIENT_KEY` | API Key,用于验证请求来源(必须与后端 `API_CLIENT_KEY` 一致) | - | 是 |
 | `VITE_APP_BASE_PATH` | 前端部署子路径(以 `/` 开头和结尾) | `/` | 否 |
-| `VITE_WELCOME_VIDEO_URL` | Welcome 页面视频 URL | `https://assets.lyrria.com/Lyrria-video.mp4` | 否 |
-| `VITE_OSS_BASE_URL` | OSS 资源基础 URL(用于图片、GIF 等静态资源) | `https://assets.lyrria.com` | 否 |
+| `VITE_WELCOME_VIDEO_URL` | Welcome 页面视频 URL | `https://www.lyrria.com/img/Lyrria-video.mp4` | 否 |
+| `VITE_OSS_BASE_URL` | OSS 资源基础 URL(用于图片、GIF 等静态资源) | `https://www.lyrria.com/img` | 否 |
 
 ## 使用场景
 

+ 2 - 2
frontend/index.html

@@ -19,10 +19,10 @@
     <meta property="og:description" content="Your adventure begins now." />
     <meta property="og:type" content="website" />
     <meta property="og:site_name" content="Lumi" />
-    <meta property="og:image" content="https://assets.lyrria.com/Lumi-cap.png" />
+    <meta property="og:image" content="https://www.lyrria.com/img/Lumi-cap.png" />
     <meta itemprop="name" content="Lumi (by Lyrria, Early Access)" />
     <meta itemprop="description" content="Your adventure begins now." />
-    <meta itemprop="image" content="https://assets.lyrria.com/Lumi-cap.png" />
+    <meta itemprop="image" content="https://www.lyrria.com/img/Lumi-cap.png" />
     <meta name="description" content="Your adventure begins now." />
     
     <title>Lumi</title>

+ 1 - 1
frontend/src/index.css

@@ -50,7 +50,7 @@ body {
   padding: 0;
   /* 全局背景:在宽度超过 600px 时,左右区域仍然使用应用背景而不是纯白色 */
   background-color: #E8E8E8;
-  background-image: var(--oss-chatbot-bg-url, url("https://assets.lyrria.com/chatbot-bg.svg"));
+  background-image: var(--oss-chatbot-bg-url, url("https://www.lyrria.com/img/chatbot-bg.svg"));
   background-size: cover;
   background-position: center;
   background-repeat: no-repeat;

+ 22 - 0
frontend/src/pages/ChatBotPage.tsx

@@ -53,6 +53,7 @@ const missionEnergyStone = getOssUrl('Mission-Energy-Stone.png');
 const conversationEnergyStone = getOssUrl('Conversation-Energy-Stone.png');
 const missionEnergyStoneHint = getOssUrl('Mission-Energy-Stone-hint.png');
 const conversationEnergyStoneHint = getOssUrl('Conversation-Energy-Stone-hint.png');
+const YpImage = getOssUrl('yp.png');
 import { useEnergyStones, type EnergyStoneEventPayload } from '@/hooks/useEnergyStones';
 import { MissionEnergyStoneModal } from '@/components/MissionEnergyStoneModal';
 
@@ -2918,6 +2919,27 @@ export const ChatBotPage = () => {
         />
       </div>
 
+      {/* Yp 图片 - 位于动画形象下方 */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(248)} + ${px2vmin(302)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(113),
+          height: px2vmin(18),
+          zIndex: 10,
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
+
       {/* 音频波形 - 宽度 100% 自适应 */}
       <div
         className="chatbot-audio-wave overflow-hidden"

+ 20 - 0
frontend/src/pages/FirstLoginPage.tsx

@@ -15,6 +15,7 @@ const emailLogin = getOssUrl('email-login.png');
 const continueBtn = getOssUrl('continue-btn.png');
 const continueBtnA = getOssUrl('continue-btn-a.png');
 const XIconImage = getOssUrl('x-icon.png');
+const YpImage = getOssUrl('yp.png');
 const focusGradient =
   'linear-gradient(90deg, #FFC900 11%, #13A6FF 32%, #806EFF 50%, #FF8EEC 66%, #FE4F51 89%)';
 
@@ -168,6 +169,25 @@ export const FirstLoginPage = () => {
           transform: 'translateX(-50%)',
         }}
       />
+      {/* Yp 图片 - 位于动画形象下方 */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(132)} + ${px2vmin(160)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(85),
+          height: px2vmin(13),
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
       {/* 输入框 */}
       <div
         className="absolute"

+ 21 - 1
frontend/src/pages/FirstLoginRewardPage.tsx

@@ -27,6 +27,7 @@ const closeBtn = getOssUrl('close-btn.png');
 const claimGiftBtnImage = getOssUrl('claim-the-gift.png');
 const chevronLeftImage = getOssUrl('Chevron-L.png');
 const chevronRightImage = getOssUrl('Chevron-R.png');
+const YpImage = getOssUrl('yp.png');
 import { shareImages as fallbackShareImages } from '@/data/shareImages';
 import { getShareImages, type ShareImageItem } from '@/utils/api';
 
@@ -311,11 +312,30 @@ export const FirstLoginRewardPage = () => {
         style={{
           position: 'absolute',
           left: '50%',
-          top: px2vmin(192),
+          top: px2vmin(142),
           width: px2vmin(343),
           transform: 'translateX(-50%)',
         }}
       />
+      {/* Yp 图片 - 位于动画形象下方 */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(192)} + ${px2vmin(238)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(113),
+          height: px2vmin(18),
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
 
       {!showShareModal && (
         <>

+ 20 - 0
frontend/src/pages/GreetingPage.tsx

@@ -16,6 +16,7 @@ import { getOssUrl } from '../utils/oss';
 
 const ConfirmBtnImage = getOssUrl('confirm-btn.png');
 const XIconImage = getOssUrl('x-icon.png');
+const YpImage = getOssUrl('yp.png');
 const focusGradient =
   'linear-gradient(90deg, #FFC900 11%, #13A6FF 32%, #806EFF 50%, #FF8EEC 66%, #FE4F51 89%)';
 
@@ -387,6 +388,25 @@ export const GreetingPage = () => {
           />
         </div>
 
+        <div
+          className="absolute"
+          style={{
+            top: `calc(${px2vh(layout.avatarTop)} + ${px2vmin(225)})`,
+            left: '50%',
+            transform: 'translateX(-50%)',
+            width: px2vmin(85),
+            height: px2vmin(13),
+          }}
+        >
+          <img
+            src={YpImage}
+            alt="Yp"
+            className="w-full h-full object-contain"
+            style={{ width: '100%', height: '100%' }}
+            draggable={false}
+          />
+        </div>
+
         <button
           type="button"
           onClick={handleSubmit}

+ 24 - 2
frontend/src/pages/Level34WelcomePage.tsx

@@ -8,6 +8,7 @@ import { getOssUrl } from '@/utils/oss';
 // const giftProgressBar = getOssUrl('gift-progress-bar.png'); // Unused
 const registerForGift = getOssUrl('register-for-gift.png');
 const backButton = getOssUrl('backbutn.png');
+const YpImage = getOssUrl('yp.png');
 
 export const Level34WelcomePage = () => {
   const navigate = useNavigate();
@@ -96,14 +97,14 @@ export const Level34WelcomePage = () => {
           animation: 'imageSlideDownAndShake 1s ease-out 2s forwards',
         }}
       />
-      {/* GIF动画图片 - Y: 192, 左右居中, width: 343, height: 280,动画结束后显示 */}
+      {/* GIF动画图片 - Y: 142, 左右居中, width: 343, height: 280,动画结束后显示 */}
       <img
         src={getOssUrl('03-Cheer.gif')}
         alt="cheer animation"
         style={{
           position: 'absolute',
           left: '50%',
-          top: px2vmin(192),
+          top: px2vmin(142),
           width: px2vmin(343),
           // height: px2vmin(280),
           transform: 'translateX(-50%)',
@@ -111,6 +112,27 @@ export const Level34WelcomePage = () => {
           animation: 'imageSlideDownAndShake 1s ease-out 2s forwards',
         }}
       />
+      {/* Yp 图片 - 位于动画形象下方,跟随动画形象一起出现 */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(192)} + ${px2vmin(238)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(113),
+          height: px2vmin(18),
+          opacity: 0,
+          animation: 'imageSlideDownAndShake 1s ease-out 2s forwards',
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
       {/* 文字 - Congratulation! - Y: 504, 左右居中, 24px加粗白色,动画结束后显示 */}
       <div
         style={{

+ 25 - 2
frontend/src/pages/Level5WelcomePage.tsx

@@ -7,6 +7,7 @@ import { getOssUrl } from '@/utils/oss';
 
 const giftProgressBar = getOssUrl('gift-progress-bar.png');
 const registerForGift = getOssUrl('register-for-gift.png');
+const YpImage = getOssUrl('yp.png');
 
 export const Level5WelcomePage = () => {
   const navigate = useNavigate();
@@ -60,14 +61,14 @@ export const Level5WelcomePage = () => {
           animationIterationCount: 1,
         }}
       />
-      {/* GIF动画图片 - Y: 192, 左右居中, width: 343, height: 280,动画结束后显示 */}
+      {/* GIF动画图片 - Y: 142, 左右居中, width: 343, height: 280,动画结束后显示 */}
       <img
         src={getOssUrl('03-Cheer.gif')}
         alt="cheer animation"
         style={{
           position: 'absolute',
           left: '50%',
-          top: px2vmin(192),
+          top: px2vmin(142),
           width: px2vmin(343),
           // height: px2vmin(280),
           transform: 'translateX(-50%)',
@@ -76,6 +77,28 @@ export const Level5WelcomePage = () => {
           animationIterationCount: 1,
         }}
       />
+      {/* Yp 图片 - 位于动画形象下方,跟随动画形象一起出现 */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(192)} + ${px2vmin(238)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(113),
+          height: px2vmin(18),
+          opacity: 0,
+          animation: 'imageSlideDownAndShake 1s ease-out 2s forwards',
+          animationIterationCount: 1,
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
       {/* 文字 - Congratulation! - Y: 504, 左右居中, 24px加粗白色,动画结束后显示 */}
       <div
         style={{

+ 20 - 0
frontend/src/pages/LoginPage.tsx

@@ -14,6 +14,7 @@ const continueBtn = getOssUrl('continue-btn.png');
 const continueBtnA = getOssUrl('continue-btn-a.png');
 const backButton = getOssUrl('backbutn.png');
 const XIconImage = getOssUrl('x-icon.png');
+const YpImage = getOssUrl('yp.png');
 
 interface LocationState {
   loginType?: 'phone' | 'qq' | 'email';
@@ -235,6 +236,25 @@ export const LoginPage = () => {
           transform: 'translateX(-50%)',
         }}
       />
+      {/* Yp 图片 - 位于动画形象下方 */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(192)} + ${px2vmin(154)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(85),
+          height: px2vmin(13),
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
       {/* 输入框 */}
       <div
         className="absolute"

+ 20 - 0
frontend/src/pages/LoginVerificationCodePage.tsx

@@ -12,6 +12,7 @@ const sendCodeNo = getOssUrl('send-code-no.png');
 const sendCodeImage = getOssUrl('send-code.png');
 const backButton = getOssUrl('backbutn.png');
 const XIconImage = getOssUrl('x-icon.png');
+const YpImage = getOssUrl('yp.png');
 const focusGradient =
   'linear-gradient(90deg, #FFC900 11%, #13A6FF 32%, #806EFF 50%, #FF8EEC 66%, #FE4F51 89%)';
 
@@ -200,6 +201,25 @@ export const LoginVerificationCodePage = () => {
           transform: 'translateX(-50%)',
         }}
       />
+      {/* Yp 图片 - 位于动画形象下方(与 VerificationCodePage 对齐) */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(132)} + ${px2vmin(160)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(85),
+          height: px2vmin(13),
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
       {/* 输入框 */}
       <div
         className="absolute"

+ 23 - 3
frontend/src/pages/LoginVerificationInputPage.tsx

@@ -8,6 +8,7 @@ import { getOssUrl } from '@/utils/oss';
 
 const sendCodeWaitNo = getOssUrl('send-code-wait-no.png');
 const backButton = getOssUrl('backbutn.png');
+const YpImage = getOssUrl('yp.png');
 
 interface LocationState {
   loginType?: 'phone' | 'email';
@@ -422,11 +423,30 @@ export const LoginVerificationInputPage = () => {
           transform: 'translateX(-50%)',
         }}
       />
+      {/* Yp 图片 - 位于动画形象下方 */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(132)} + ${px2vmin(160)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(85),
+          height: px2vmin(13),
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
       {/* 验证码发送提示文字 */}
       <div
         className="absolute"
         style={{
-          top: px2vmin(304),
+          top: px2vmin(324),
           left: '50%',
           transform: 'translateX(-50%)',
           width: px2vmin(312),
@@ -445,7 +465,7 @@ export const LoginVerificationInputPage = () => {
       <div
         className="absolute"
         style={{
-          top: px2vmin(326),
+          top: px2vmin(346),
           left: '50%',
           transform: 'translateX(-50%)',
           width: px2vmin(312),
@@ -510,7 +530,7 @@ export const LoginVerificationInputPage = () => {
         style={{
           position: 'absolute',
           left: '50%',
-          top: px2vmin(436),
+          top: px2vmin(456),
           width: px2vmin(279),
           transform: 'translateX(-50%)',
           border: 'none',

+ 20 - 0
frontend/src/pages/LumiNamingPage.tsx

@@ -7,6 +7,7 @@ import { getOssUrl } from '../utils/oss';
 
 const ConfirmBtnImage = getOssUrl('confirm-btn.png');
 const XIconImage = getOssUrl('x-icon.png');
+const YpImage = getOssUrl('yp.png');
 
 const DEFAULT_LUMI_NAME = 'Lumi';
 const focusGradient =
@@ -259,6 +260,25 @@ export const LumiNamingPage = () => {
           />
         </div>
 
+        <div
+          className="absolute"
+          style={{
+            top: `calc(${px2vh(layout.avatarTop)} + ${px2vmin(225)})`,
+            left: '50%',
+            transform: 'translateX(-50%)',
+            width: px2vmin(85),
+            height: px2vmin(13),
+          }}
+        >
+          <img
+            src={YpImage}
+            alt="Yp"
+            className="w-full h-full object-contain"
+            style={{ width: '100%', height: '100%' }}
+            draggable={false}
+          />
+        </div>
+
         <button
           type="button"
           onClick={handleSubmit}

+ 21 - 1
frontend/src/pages/ShareSuccessPage.tsx

@@ -8,6 +8,7 @@ import { getOssUrl } from '@/utils/oss';
 // const fullProgressBar = getOssUrl('full-progress-bar.png'); // Unused
 const avatarAnimaZone = getOssUrl('Avatar-anima-zone-cap.png');
 const continueChatBtn = getOssUrl('continue-chat.png');
+const YpImage = getOssUrl('yp.png');
 
 // 新年背景图片 ID
 const NEW_YEAR_BACKGROUND_IMAGE_ID = 'happynewyear';
@@ -88,11 +89,30 @@ export const ShareSuccessPage = () => {
         style={{
           position: 'absolute',
           left: '50%',
-          top: px2vmin(192),
+          top: px2vmin(142),
           width: px2vmin(343),
           transform: 'translateX(-50%)',
         }}
       />
+      {/* Yp 图片 - 位于动画形象下方 */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(192)} + ${px2vmin(238)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(113),
+          height: px2vmin(18),
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
 
       {/* 标题文案 */}
       <div

+ 20 - 0
frontend/src/pages/VerificationCodePage.tsx

@@ -12,6 +12,7 @@ const sendCodeNo = getOssUrl('send-code-no.png');
 const sendCodeImage = getOssUrl('send-code.png');
 const backButton = getOssUrl('backbutn.png');
 const XIconImage = getOssUrl('x-icon.png');
+const YpImage = getOssUrl('yp.png');
 const focusGradient =
   'linear-gradient(90deg, #FFC900 11%, #13A6FF 32%, #806EFF 50%, #FF8EEC 66%, #FE4F51 89%)';
 
@@ -200,6 +201,25 @@ export const VerificationCodePage = () => {
           transform: 'translateX(-50%)',
         }}
       />
+      {/* Yp 图片 - 位于动画形象下方(与 FirstLoginPage 对齐) */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(132)} + ${px2vmin(160)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(85),
+          height: px2vmin(13),
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
       {/* 输入框 */}
       <div
         className="absolute"

+ 24 - 4
frontend/src/pages/VerificationInputPage.tsx

@@ -10,6 +10,7 @@ import { getOssUrl } from '@/utils/oss';
 const sendCodeWaitNo = getOssUrl('send-code-wait-no.png');
 const registerForGift = getOssUrl('register-for-gift.png');
 const backButton = getOssUrl('backbutn.png');
+const YpImage = getOssUrl('yp.png');
 
 interface LocationState {
   loginType?: 'phone' | 'email';
@@ -467,11 +468,30 @@ export const VerificationInputPage = () => {
           transform: 'translateX(-50%)',
         }}
       />
+      {/* Yp 图片 - 位于动画形象下方 */}
+      <div
+        className="absolute"
+        style={{
+          top: `calc(${px2vmin(132)} + ${px2vmin(160)})`,
+          left: '50%',
+          transform: 'translateX(-50%)',
+          width: px2vmin(85),
+          height: px2vmin(13),
+        }}
+      >
+        <img
+          src={YpImage}
+          alt="Yp"
+          className="w-full h-full object-contain"
+          style={{ width: '100%', height: '100%' }}
+          draggable={false}
+        />
+      </div>
       {/* 验证码发送提示文字 */}
       <div
         className="absolute"
         style={{
-          top: px2vmin(304),
+          top: px2vmin(324),
           left: '50%',
           transform: 'translateX(-50%)',
           width: px2vmin(312),
@@ -490,7 +510,7 @@ export const VerificationInputPage = () => {
       <div
         className="absolute"
         style={{
-          top: px2vmin(326),
+          top: px2vmin(346),
           left: '50%',
           transform: 'translateX(-50%)',
           width: px2vmin(312),
@@ -556,7 +576,7 @@ export const VerificationInputPage = () => {
           style={{
             position: 'absolute',
             left: '50%',
-            top: px2vmin(436),
+            top: px2vmin(456),
             width: px2vmin(279),
             transform: 'translateX(-50%)',
             border: 'none',
@@ -582,7 +602,7 @@ export const VerificationInputPage = () => {
           style={{
             position: 'absolute',
             left: '50%',
-            top: px2vmin(436),
+            top: px2vmin(456),
             width: px2vmin(279),
             transform: 'translateX(-50%)',
             border: 'none',

+ 1 - 1
frontend/src/utils/oss.ts

@@ -4,7 +4,7 @@
  */
 
 // 从环境变量读取 OSS 基础 URL,如果没有配置则使用默认值
-let OSS_BASE_URL = import.meta.env.VITE_OSS_BASE_URL || 'https://assets.lyrria.com';
+let OSS_BASE_URL = import.meta.env.VITE_OSS_BASE_URL || 'https://www.lyrria.com/img';
 
 // 如果配置的是协议相对 URL(以 // 开头),根据当前页面协议自动选择
 if (OSS_BASE_URL.startsWith('//')) {

+ 1 - 1
sendmsg/send_email.py

@@ -92,7 +92,7 @@ EMAIL_BODY_TEMPLATE = """
           <div class="container">
             <div class="logo">Lumi</div>
             <div class="hero">
-              <img src="https://assets.lyrria.com/Lumi-cap.png" alt="Lumi" />
+              <img src="https://www.lyrria.com/img/Lumi-cap.png" alt="Lumi" />
             </div>
             <div class="title">您的登录验证码</div>
             <div class="subtitle">请在 5 分钟内完成校验,保护您的账号安全。</div>

+ 2 - 0
项目文档/小进度值异常阴影修复方案.md

@@ -159,3 +159,5 @@ if (progress > 0) {
 
 
 
+
+