迁移
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
# Commit 规范(北斗治理规范 v1)
|
||||
|
||||
> 团队来源:北斗 / 瑞升
|
||||
> 设计文档:`docs/superpowers/specs/2026-05-14-beidou-git-governance-design.md`(myproject 仓)
|
||||
> 适用范围:JHA-126-bili / JHA-117-pronhub 两个项目编号下所有前端仓库
|
||||
|
||||
---
|
||||
|
||||
## 1. 首次安装
|
||||
|
||||
clone 完仓库后,在仓库根执行一次:
|
||||
|
||||
```bash
|
||||
bash scripts/install-hooks.sh
|
||||
```
|
||||
|
||||
效果:把 `core.hooksPath` 指向仓库内 `.githooks/`,启用本地 commit-msg 校验。
|
||||
|
||||
紧急绕过:
|
||||
|
||||
```bash
|
||||
git commit --no-verify
|
||||
```
|
||||
|
||||
仅用于紧急上线,事后必须 `git commit --amend` 补全合规 prefix 后再 push。
|
||||
|
||||
---
|
||||
|
||||
## 2. Commit Subject 必含 4 个 Prefix 之一
|
||||
|
||||
每条 commit 的 subject(第一行)必须以下列 4 个 prefix 之一开头,**大小写敏感、方括号包裹、后接一个空格**:
|
||||
|
||||
| Prefix | 含义 | 是否计入 AI 占比统计 |
|
||||
|---|---|---|
|
||||
| `[Ai]` | AI 辅助生成 | ✅ 计入 AI 分子 |
|
||||
| `[Human]` | 纯人工 | ✅ 计入人工分子 |
|
||||
| `[Lib-Upgrade]` | 框架/依赖升级(复用) | ❌ 排除(不计入分母) |
|
||||
| `[Migrate]` | 跨项目迁移代码 | ❌ 排除(不计入分母) |
|
||||
|
||||
---
|
||||
|
||||
## 3. 推荐写法
|
||||
|
||||
Prefix 后接 Conventional Commits 风格的 `type(scope): subject`:
|
||||
|
||||
```
|
||||
[Ai] feat(player): 钻石购买确认弹窗 ModalPayDiamondPop
|
||||
[Human] fix(wallet): 修正运营后台金额 currencyType Number 兜底
|
||||
[Lib-Upgrade] chore(deps): 升级 web-sdk 1.0.8 → 1.1.2
|
||||
[Migrate] feat(ui): 从 bili2_h5_client 迁入 AvatarWithBadge 组件
|
||||
```
|
||||
|
||||
常用 type:`feat / fix / refactor / docs / test / chore / perf / ci`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 可选 trailer:Co-Authored-By
|
||||
|
||||
`Co-Authored-By` 仅作元数据,**不参与 hook 校验**。统一格式(不带邮箱):
|
||||
|
||||
```
|
||||
Co-Authored-By: Claude
|
||||
Co-Authored-By: Cursor
|
||||
Co-Authored-By: Copilot
|
||||
Co-Authored-By: Cline
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 豁免列表
|
||||
|
||||
下列自动生成的 commit message,hook 直接放行,无需补 prefix:
|
||||
|
||||
- `Merge branch ...` / `Merge remote-tracking ...`(merge 自动消息)
|
||||
- `Revert "..."`(revert 自动消息)
|
||||
- `fixup! ...` / `squash! ...`(rebase 临时产物)
|
||||
|
||||
---
|
||||
|
||||
## 6. 紧急绕过
|
||||
|
||||
```bash
|
||||
git commit --no-verify
|
||||
```
|
||||
|
||||
适用场景:线上 P0 hotfix、CI 阻塞导致无法启动 hook 时。
|
||||
|
||||
事后补救:
|
||||
|
||||
```bash
|
||||
git commit --amend # 补全 prefix
|
||||
git push --force-with-lease # 仅在尚未被他人 pull 时使用
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. FAQ
|
||||
|
||||
**Q1:AI 生成代码我又手工大改了一遍,算 `[Ai]` 还是 `[Human]`?**
|
||||
|
||||
A:看主导工作量。AI 写完后超过 50% 代码由人手改,标 `[Human]`;否则 `[Ai]`。原则:"谁产出主要代码就归谁"。
|
||||
|
||||
**Q2:revert 一个 `[Ai]` commit 算什么?**
|
||||
|
||||
A:revert 自动生成的 `Revert "..."` 消息走豁免分支,无需打 prefix。如果手动写 revert 的 subject,按"撤销动作"的来源标 prefix(自己手工写就 `[Human]`)。
|
||||
|
||||
**Q3:cherry-pick 从其它仓库带来的 commit 算 `[Migrate]` 吗?**
|
||||
|
||||
A:是。跨项目迁移(cherry-pick / 复制代码 / 移植)统一标 `[Migrate]`,不计入 AI/Human 分母。
|
||||
|
||||
---
|
||||
|
||||
## 8. 关联文档
|
||||
|
||||
- 本仓库 `project.md`(项目元信息 + 风险点 + 交接说明)
|
||||
- myproject 仓库 `docs/superpowers/specs/2026-05-14-beidou-git-governance-design.md`(设计 spec)
|
||||
- 北斗治理规范 v1(公司原始文档)
|
||||
@@ -0,0 +1,519 @@
|
||||
# 黄果短剧落地页(电脑版 5 变体)实施计划
|
||||
|
||||
> **For agentic workers:** 用 superpowers:executing-plans 或 subagent-driven-development 按 Task 执行。步骤用 `- [ ]` 勾选。
|
||||
>
|
||||
> **用户规则覆盖(最高优先级):**
|
||||
> - 不强制 TDD:本计划不写"先写测试"步骤。
|
||||
> - 收尾只做静态检查(`pnpm exec tsc --noEmit` / `pnpm build`),不跑单测/E2E。
|
||||
> - 不自动 commit / push / 建 PR:除非用户明确说"提交"。
|
||||
|
||||
**Goal:** 把 repo 改造为黄果短剧落地页:1 个共用电脑模板 `PcLanding.vue` + 5 变体素材(背景大图 + 底部封面),进站 5 路随机分流 A~E,并更新 index.html 为简体黄果 SEO。
|
||||
|
||||
**Architecture:** Vue 3 `<script setup lang="ts">` + Vite + SCSS,`zoom` 缩放(基于 1920×1080),绝对定位 + 图片叠加,`<picture>` webp+png。版面只写一次,`variants.ts` 映射每变体的 `bg`/`covers`。共用元素(logo/主文案/二维码文字烤成图,导航程式画)全变体复用。二维码复用 `DesktopQrcode`。
|
||||
|
||||
**Tech Stack:** Vue 3 + Vite + SCSS + `qrcode.vue`;Figma MCP `get_screenshot`(导出节点 PNG)+ `curl` 下载;`pnpm webp`(sharp q80)生成 webp。
|
||||
|
||||
**规格来源:** `docs/superpowers/specs/2026-05-29-huangguo-landing-design.md`
|
||||
|
||||
---
|
||||
|
||||
## 关键设计参数(Figma `yD7lloED2Okdp1FJTYvhe3`,变体 1 `73:53`,5 变体共用版面)
|
||||
|
||||
画布 1920×1080,全部绝对坐标。
|
||||
|
||||
| 元素 | 位置 (x,y) | 尺寸 | 说明 |
|
||||
|---|---|---|---|
|
||||
| 背景大图 | 0,0 | 1920×1080 | 每变体不同,含底部深色渐变 |
|
||||
| 顶部 pill 条 | 360,0 | 1200×70 | 半透明圆角,水平居中(CSS 画) |
|
||||
| logo 锁定组 | 420,15 | 154×40 | 烤图(icon+黄果短剧+标语) |
|
||||
| 联系方式 容器 | 1094,23 | 406×24 | 3 项 + 圆点分隔(程式画) |
|
||||
| 主文案 | 204,308 | 630×381 | 烤图 |
|
||||
| 二维码本体 | 204,750 | 180×180 | 白底圆角,内 150×150 动态二维码 |
|
||||
| 二维码文字块 | 408,757 | 502×166 | 烤图 |
|
||||
| 底部封面行 | 1184,778 | 606×152 | 每变体不同,烤成长条图 |
|
||||
|
||||
联系方式 3 项(相对 406×24 容器,容器位于顶部内容 (734,8)):
|
||||
- 官方群组:item @x=0(icon 24×24 + 文字 @x=30)
|
||||
- 圆点分隔 @x=124(竖排 4 点,2×2,间距 4px)
|
||||
- 商务合作:item @x=156
|
||||
- 圆点分隔 @x=280
|
||||
- 渠道合作:item @x=312
|
||||
|
||||
导出节点 ID:
|
||||
|
||||
| 变体(版本) | 背景 frame | 轮动 cover row |
|
||||
|---|---|---|
|
||||
| 1 (A) | `73:54` | `81:766` |
|
||||
| 2 (B) | `73:112` | `81:735` |
|
||||
| 3 (C) | `73:169` | `81:704` |
|
||||
| 4 (D) | `73:225` | `81:673` |
|
||||
| 5 (E) | `73:281` | `73:356` |
|
||||
|
||||
共用元素(从变体 1 导出):logo `73:76`、主文案 `73:62`、二维码文字 `73:69`、官方群组 icon `73:83`、商务合作 icon `73:93`、渠道合作 icon `73:104`。
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── pages/index.vue # 改:设备检测 + 5 路随机 A~E
|
||||
├── components/landing/PcLanding.vue # 新:电脑共用模板
|
||||
├── config/variants.ts # 新:变体素材映射 + 导航链接常量
|
||||
├── components/desktop/qrcode.vue # 复用(必要时微调 .qr-inner 尺寸)
|
||||
└── assets/image/hg/
|
||||
├── common/ logo / theme / qr-text / icon-tg / icon-biz / icon-channel (.png+.webp)
|
||||
└── pc/ bg1..bg5 / covers1..covers5 (.png+.webp)
|
||||
index.html # 改:简体黄果 SEO
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Tasks
|
||||
|
||||
## Task 1:从 Figma 导出全部素材 PNG
|
||||
|
||||
**Files:**
|
||||
- Create: `src/assets/image/hg/common/{logo,theme,qr-text,icon-tg,icon-biz,icon-channel}.png`
|
||||
- Create: `src/assets/image/hg/pc/{bg1..bg5,covers1..covers5}.png`
|
||||
|
||||
导出方式:对每个节点调用 `mcp__figma__get_screenshot`(fileKey `yD7lloED2Okdp1FJTYvhe3`),拿到 `image_url` 后用 `curl -s -o <目标路径> "<url>"` 下载。背景用默认整合渲染;其余叠加元素用 `contentsOnly: true`(透明底)。
|
||||
|
||||
- [ ] **Step 1.1:建目录**
|
||||
|
||||
```bash
|
||||
mkdir -p src/assets/image/hg/common src/assets/image/hg/pc
|
||||
```
|
||||
|
||||
- [ ] **Step 1.2:导出 5 张背景**(`maxDimension: 1920`,默认模式)
|
||||
- 73:54 → `src/assets/image/hg/pc/bg1.png`
|
||||
- 73:112 → `bg2.png`
|
||||
- 73:169 → `bg3.png`
|
||||
- 73:225 → `bg4.png`
|
||||
- 73:281 → `bg5.png`
|
||||
|
||||
- [ ] **Step 1.3:导出 5 张封面长条**(`contentsOnly: true`,`maxDimension: 1212` ≈2×)
|
||||
- 81:766 → `covers1.png`,81:735 → `covers2.png`,81:704 → `covers3.png`,81:673 → `covers4.png`,73:356 → `covers5.png`
|
||||
|
||||
- [ ] **Step 1.4:导出共用元素**(`contentsOnly: true`)
|
||||
- 73:76 → `common/logo.png`(`maxDimension: 308`)
|
||||
- 73:62 → `common/theme.png`(`maxDimension: 1260`)
|
||||
- 73:69 → `common/qr-text.png`(`maxDimension: 1004`)
|
||||
- 73:83 → `common/icon-tg.png`(`maxDimension: 72`)
|
||||
- 73:93 → `common/icon-biz.png`(`maxDimension: 72`)
|
||||
- 73:104 → `common/icon-channel.png`(`maxDimension: 72`)
|
||||
|
||||
- [ ] **Step 1.5:核对**
|
||||
|
||||
```bash
|
||||
ls -la src/assets/image/hg/common src/assets/image/hg/pc
|
||||
```
|
||||
Expected:14 个 png,皆非 0 字节。用 Read 抽看 `theme.png`/`qr-text.png`/`logo.png` 确认是透明底、无背景大图穿透;若穿透,改该节点为 `contentsOnly: true` 重导,或退化为 CSS 文字渲染(见 Task 3 备注)。
|
||||
|
||||
- [ ] **Step 1.6:生成 webp**
|
||||
|
||||
```bash
|
||||
pnpm webp
|
||||
```
|
||||
Expected:上述 png 同目录生成同名 `.webp`。
|
||||
|
||||
---
|
||||
|
||||
## Task 2:建立 `src/config/variants.ts`
|
||||
|
||||
**Files:**
|
||||
- Create: `src/config/variants.ts`
|
||||
|
||||
- [ ] **Step 2.1:写入完整内容**
|
||||
|
||||
```ts
|
||||
import bg1 from '~/assets/image/hg/pc/bg1.png'
|
||||
import bg1W from '~/assets/image/hg/pc/bg1.webp'
|
||||
import bg2 from '~/assets/image/hg/pc/bg2.png'
|
||||
import bg2W from '~/assets/image/hg/pc/bg2.webp'
|
||||
import bg3 from '~/assets/image/hg/pc/bg3.png'
|
||||
import bg3W from '~/assets/image/hg/pc/bg3.webp'
|
||||
import bg4 from '~/assets/image/hg/pc/bg4.png'
|
||||
import bg4W from '~/assets/image/hg/pc/bg4.webp'
|
||||
import bg5 from '~/assets/image/hg/pc/bg5.png'
|
||||
import bg5W from '~/assets/image/hg/pc/bg5.webp'
|
||||
import c1 from '~/assets/image/hg/pc/covers1.png'
|
||||
import c1W from '~/assets/image/hg/pc/covers1.webp'
|
||||
import c2 from '~/assets/image/hg/pc/covers2.png'
|
||||
import c2W from '~/assets/image/hg/pc/covers2.webp'
|
||||
import c3 from '~/assets/image/hg/pc/covers3.png'
|
||||
import c3W from '~/assets/image/hg/pc/covers3.webp'
|
||||
import c4 from '~/assets/image/hg/pc/covers4.png'
|
||||
import c4W from '~/assets/image/hg/pc/covers4.webp'
|
||||
import c5 from '~/assets/image/hg/pc/covers5.png'
|
||||
import c5W from '~/assets/image/hg/pc/covers5.webp'
|
||||
|
||||
export interface PcVariant {
|
||||
bg: string
|
||||
bgW: string
|
||||
covers: string
|
||||
coversW: string
|
||||
}
|
||||
|
||||
export const PC_VARIANTS: PcVariant[] = [
|
||||
{ bg: bg1, bgW: bg1W, covers: c1, coversW: c1W },
|
||||
{ bg: bg2, bgW: bg2W, covers: c2, coversW: c2W },
|
||||
{ bg: bg3, bgW: bg3W, covers: c3, coversW: c3W },
|
||||
{ bg: bg4, bgW: bg4W, covers: c4, coversW: c4W },
|
||||
{ bg: bg5, bgW: bg5W, covers: c5, coversW: c5W },
|
||||
]
|
||||
|
||||
export const VERSION_LETTERS = ['A', 'B', 'C', 'D', 'E'] as const
|
||||
|
||||
// 导航链接:官方群组已定,其余为占位,给到网址改这里即可
|
||||
export const NAV_LINKS = {
|
||||
group: 'https://t.me/huangguoshortdrama',
|
||||
biz: '#TODO-business',
|
||||
channel: '#TODO-channel',
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3:建立 `src/components/landing/PcLanding.vue`
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/landing/PcLanding.vue`
|
||||
|
||||
- [ ] **Step 3.1:写入完整 SFC**
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="hg-pc">
|
||||
<!-- 背景大图(变体) -->
|
||||
<div class="bg">
|
||||
<picture>
|
||||
<source type="image/webp" :srcset="v.bgW" />
|
||||
<img :src="v.bg" alt="" />
|
||||
</picture>
|
||||
</div>
|
||||
|
||||
<!-- 顶部 pill 导航条 -->
|
||||
<div class="top">
|
||||
<div class="logo">
|
||||
<picture>
|
||||
<source type="image/webp" :srcset="logoW" />
|
||||
<img :src="logo" alt="黄果短剧" />
|
||||
</picture>
|
||||
</div>
|
||||
<div class="nav">
|
||||
<a class="item" :href="NAV_LINKS.group">
|
||||
<picture>
|
||||
<source type="image/webp" :srcset="iconTgW" />
|
||||
<img :src="iconTg" alt="官方群组" />
|
||||
</picture>
|
||||
<span>官方群組</span>
|
||||
</a>
|
||||
<i class="dot" />
|
||||
<a class="item" :href="NAV_LINKS.biz">
|
||||
<picture>
|
||||
<source type="image/webp" :srcset="iconBizW" />
|
||||
<img :src="iconBiz" alt="商务合作" />
|
||||
</picture>
|
||||
<span>商務合作</span>
|
||||
</a>
|
||||
<i class="dot" />
|
||||
<a class="item" :href="NAV_LINKS.channel">
|
||||
<picture>
|
||||
<source type="image/webp" :srcset="iconChW" />
|
||||
<img :src="iconCh" alt="渠道合作" />
|
||||
</picture>
|
||||
<span>渠道合作</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主文案 -->
|
||||
<div class="theme">
|
||||
<picture>
|
||||
<source type="image/webp" :srcset="themeW" />
|
||||
<img :src="theme" alt="每一帧都能解你的色" />
|
||||
</picture>
|
||||
</div>
|
||||
|
||||
<!-- 二维码区 -->
|
||||
<div class="qr">
|
||||
<div class="qr-box">
|
||||
<DesktopQrcode />
|
||||
</div>
|
||||
<div class="qr-text">
|
||||
<picture>
|
||||
<source type="image/webp" :srcset="qrTextW" />
|
||||
<img :src="qrText" alt="" />
|
||||
</picture>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部封面行(变体) -->
|
||||
<div class="covers">
|
||||
<picture>
|
||||
<source type="image/webp" :srcset="v.coversW" />
|
||||
<img :src="v.covers" alt="" />
|
||||
</picture>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, onBeforeUnmount } from 'vue'
|
||||
import DesktopQrcode from '~/components/desktop/qrcode.vue'
|
||||
import { PC_VARIANTS, NAV_LINKS } from '~/config/variants'
|
||||
import logo from '~/assets/image/hg/common/logo.png'
|
||||
import logoW from '~/assets/image/hg/common/logo.webp'
|
||||
import theme from '~/assets/image/hg/common/theme.png'
|
||||
import themeW from '~/assets/image/hg/common/theme.webp'
|
||||
import qrText from '~/assets/image/hg/common/qr-text.png'
|
||||
import qrTextW from '~/assets/image/hg/common/qr-text.webp'
|
||||
import iconTg from '~/assets/image/hg/common/icon-tg.png'
|
||||
import iconTgW from '~/assets/image/hg/common/icon-tg.webp'
|
||||
import iconBiz from '~/assets/image/hg/common/icon-biz.png'
|
||||
import iconBizW from '~/assets/image/hg/common/icon-biz.webp'
|
||||
import iconCh from '~/assets/image/hg/common/icon-channel.png'
|
||||
import iconChW from '~/assets/image/hg/common/icon-channel.webp'
|
||||
|
||||
const props = defineProps<{ variant: number }>()
|
||||
const v = computed(() => PC_VARIANTS[props.variant] ?? PC_VARIANTS[0])
|
||||
|
||||
function resizeBox() {
|
||||
const w = window.innerWidth
|
||||
const h = window.innerHeight
|
||||
const ratio = w / h
|
||||
const pct = ratio >= 1920 / 1080 ? (h / 1080) * 100 : (w / 1920) * 100
|
||||
document.body.style.cssText = 'zoom:' + pct + '%'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
resizeBox()
|
||||
window.addEventListener('resize', resizeBox)
|
||||
})
|
||||
onBeforeUnmount(() => window.removeEventListener('resize', resizeBox))
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
img { -webkit-user-drag: none; }
|
||||
|
||||
.hg-pc {
|
||||
user-select: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
img { width: 100%; height: 100%; object-fit: cover; }
|
||||
}
|
||||
|
||||
.top {
|
||||
position: absolute;
|
||||
left: 360px;
|
||||
top: 0;
|
||||
width: 1200px;
|
||||
height: 70px;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 0 0 20px 20px;
|
||||
|
||||
.logo {
|
||||
position: absolute;
|
||||
left: 60px;
|
||||
top: 15px;
|
||||
width: 154px;
|
||||
height: 40px;
|
||||
img { width: 100%; height: 100%; object-fit: contain; }
|
||||
}
|
||||
|
||||
.nav {
|
||||
position: absolute;
|
||||
left: 734px;
|
||||
top: 23px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 32px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
img { width: 24px; height: 24px; display: block; }
|
||||
span { color: #fff; font-size: 16px; line-height: 1; white-space: nowrap; }
|
||||
}
|
||||
|
||||
.dot {
|
||||
width: 2px;
|
||||
height: 14px;
|
||||
background-image: radial-gradient(rgba(255,255,255,0.6) 1px, transparent 1px);
|
||||
background-size: 2px 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.theme {
|
||||
position: absolute;
|
||||
left: 204px;
|
||||
top: 308px;
|
||||
width: 630px;
|
||||
height: 381px;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
img { width: 100%; height: 100%; object-fit: contain; }
|
||||
}
|
||||
|
||||
.qr {
|
||||
position: absolute;
|
||||
left: 204px;
|
||||
top: 750px;
|
||||
width: 706px;
|
||||
height: 180px;
|
||||
z-index: 2;
|
||||
|
||||
.qr-box {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.qr-text {
|
||||
position: absolute;
|
||||
left: 204px;
|
||||
top: 7px;
|
||||
width: 502px;
|
||||
height: 166px;
|
||||
img { width: 100%; height: 100%; object-fit: contain; }
|
||||
}
|
||||
}
|
||||
|
||||
.covers {
|
||||
position: absolute;
|
||||
left: 1184px;
|
||||
top: 778px;
|
||||
width: 606px;
|
||||
height: 152px;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
img { width: 100%; height: 100%; object-fit: contain; }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
> **备注(若 Task 1.5 发现 theme/qr-text/logo 透明导出失败):** 把对应 `<picture>` 换成 CSS 文字。logo 文字「黃果短劇」18px bold + 标语 12px;主文案标题约 60px bold + 副标 18px;二维码文字三行(24px / 18px semibold / 13px regular)。字体用系统 CJK 栈 `"PingFang SC","Microsoft YaHei",sans-serif`。
|
||||
|
||||
---
|
||||
|
||||
## Task 4:改造 `src/pages/index.vue` 为 5 路随机分流
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/pages/index.vue`
|
||||
|
||||
- [ ] **Step 4.1:替换为以下完整内容**
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import PcLanding from '~/components/landing/PcLanding.vue'
|
||||
import { computed, onBeforeMount, onBeforeUnmount, ref } from 'vue'
|
||||
import { useEventTracker, getSessionTraceId } from '~/utils/useEventTracker'
|
||||
import { VERSION_LETTERS } from '~/config/variants'
|
||||
|
||||
const isMobile = computed(() =>
|
||||
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|
||||
)
|
||||
|
||||
const variantIndex = ref(0)
|
||||
const version = computed(() => VERSION_LETTERS[variantIndex.value])
|
||||
const { trackLandingPageView, trackLandingPageClick, generateSessionId } = useEventTracker()
|
||||
|
||||
const handleClick = (e) => {
|
||||
const rawText = e?.target?.alt || e.target.innerText || ''
|
||||
const tabKey = rawText.replace(/[^A-Za-z0-9_一-鿿]/g, '_').replace(/_{2,}/g, '_').replace(/^_+|_+$/g, '') || ''
|
||||
const isDownload = tabKey.toLowerCase() === 'download'
|
||||
trackLandingPageClick({
|
||||
landing_page_id: `JHA-126${version.value}`,
|
||||
tab_key: tabKey,
|
||||
tab_name: rawText,
|
||||
click_coordinates_x: e.clientX,
|
||||
click_coordinates_y: e.clientY,
|
||||
click_x_percent: Math.round((e.clientX / window.innerWidth) * 100),
|
||||
click_y_percent: Math.round((e.clientY / window.innerHeight) * 100),
|
||||
screen_width: window.innerWidth,
|
||||
screen_height: window.innerHeight,
|
||||
trace_id: isDownload ? getSessionTraceId() : generateSessionId(),
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
variantIndex.value = Math.floor(Math.random() * 5)
|
||||
trackLandingPageView({ landing_page_id: `JHA-126${version.value}` })
|
||||
window.addEventListener('click', handleClick)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('click', handleClick)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 手机版黄果变体待做:暂时桌面/手机都先用 PcLanding 占位 -->
|
||||
<PcLanding :variant="variantIndex" />
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
```
|
||||
|
||||
> **手机过渡说明:** 黄果手机版未做,此处先全部走 `PcLanding`。手机 Figma 到位后新增 `MobileLanding.vue`,模板改为 `isMobile ? MobileLanding : PcLanding`。`isMobile` 已保留备用。
|
||||
|
||||
---
|
||||
|
||||
## Task 5:更新 `index.html` 为简体黄果 SEO
|
||||
|
||||
**Files:**
|
||||
- Modify: `index.html`
|
||||
|
||||
- [ ] **Step 5.1:替换 `<title>` 与各 meta**
|
||||
- `<title>`:`黄果短剧官网 - 竖屏短剧APP下载 | 黄果`
|
||||
- `description`:`黄果短剧官网 —— 竖屏短剧新世代。强情节、快节奏、随时随地,把最上瘾的好故事装进你的每一个碎片时间。支持安卓/iOS下载,海量都市情感、甜宠恋爱、古装传奇、悬疑反转短剧,免费在线看。`
|
||||
- `keywords`:用户提供整串清单(逗号分隔)
|
||||
- `og:title`:`黄果短剧 | 竖屏短剧APP下载官方入口`,`og:site_name`:`黄果短剧`,`og:url`:`https://huangguo.com`,`og:description` 同 description
|
||||
- `twitter:title/description/site` 同步为黄果
|
||||
- `canonical`:`https://huangguo.com`
|
||||
- 删除 bili 专用 `rating`(adult / RTA)两行
|
||||
- `favicon` / `og:image`:暂留现有(开放项)
|
||||
|
||||
---
|
||||
|
||||
## Task 6:静态检查 + 浏览器目检
|
||||
|
||||
> 不跑测试。先静态检查,再起 dev server 目检。
|
||||
|
||||
- [ ] **Step 6.1:类型检查** `pnpm exec tsc --noEmit` → 无错误
|
||||
- [ ] **Step 6.2:构建** `pnpm build` → 成功输出 dist/
|
||||
- [ ] **Step 6.3:dev 目检** `pnpm dev`,开 `http://localhost:3000/`,多刷几次确认随机命中不同变体;核对:背景大图、顶部 logo+3 导航、主文案、二维码(扫码=当前页)、底部封面行位置正确;点官方群组跳 `https://t.me/huangguoshortdrama`;缩放窗口无横向滚动条。
|
||||
|
||||
---
|
||||
|
||||
## Self-Review
|
||||
|
||||
- ✅ Spec §2 架构 → Task 2/3/4。✅ §3 坐标 → Task 3 样式。✅ §4 烤图/程式画 → Task 1+3。✅ §5 分流埋点 → Task 4。✅ §6 导航链接常量 → Task 2。✅ §7 二维码现状 → 复用 DesktopQrcode。✅ §8 SEO → Task 5。✅ §9 压缩 → Task 1.6 + `<picture>` + vsharp。
|
||||
- Placeholder:biz/channel 链接为有意占位(规格 §10 已记),非计划缺漏。
|
||||
- 类型一致:`PC_VARIANTS`/`NAV_LINKS`/`VERSION_LETTERS` 在 Task 2 定义,Task 3/4 引用一致;`PcVariant` 字段 `bg/bgW/covers/coversW` 与模板用法一致。
|
||||
- 风险:Figma 文字节点透明导出可能穿背景 → Task 1.5 已加核对 + Task 3 CSS 退化备注。
|
||||
@@ -0,0 +1,173 @@
|
||||
# 黄果短剧落地页设计规格(电脑版 5 变体)
|
||||
|
||||
> **用户规则覆盖(最高优先级):**
|
||||
> - 不强制 TDD:不写"先写测试"步骤。
|
||||
> - 收尾只做静态检查(`tsc --noEmit` / lint / `pnpm build`),不自动跑单测/E2E。
|
||||
> - 不自动 commit / push / 建 PR:除非用户明确说"提交"。
|
||||
|
||||
**日期:** 2026-05-29
|
||||
**范围:** 本规格只覆盖**电脑版 5 个变体**。手机版 Figma 用户稍后提供,届时另起规格沿用同一套架构。
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标
|
||||
|
||||
把当前 repo(残留的"逼哩逼哩 bili"模板)改造为**黄果短剧**落地页。电脑版有 5 个变体,版面结构完全相同,仅**背景大图**与**底部 5 张封面**不同。进站随机分流到其中之一(5 路 A~E,各 20%),并复用现有埋点。
|
||||
|
||||
设计来源 Figma:`yD7lloED2Okdp1FJTYvhe3`
|
||||
- 变体 1 `73:53`、变体 2 `73:111`、变体 3 `73:168`、变体 4 `73:224`、变体 5 `73:280`
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构总览
|
||||
|
||||
沿用现有技术栈:Vue 3 `<script setup lang="ts">` + Vite + SCSS,电脑端 `zoom` 缩放方案(基于 1920×1080)。**不引入新依赖**。
|
||||
|
||||
```
|
||||
src/
|
||||
├── pages/index.vue # 入口:设备检测 + 5 路随机分流 A~E
|
||||
├── components/landing/PcLanding.vue # 电脑版共用模板(本次重点)
|
||||
├── components/landing/MobileLanding.vue # 手机版共用模板(占位,后续做)
|
||||
├── components/desktop/qrcode.vue # 复用现有二维码组件
|
||||
├── config/variants.ts # 变体 → 素材映射表 + 导航链接常量
|
||||
└── assets/image/hg/
|
||||
├── common/ # 5 变体共用素材
|
||||
│ ├── logo.png / .webp # 左上 logo 锁定组(图标+黄果短剧+标语)
|
||||
│ ├── theme.png / .webp # 主文案大图(每一帧都能… + 副标)
|
||||
│ ├── qr-text.png / .webp # 二维码旁文字块(安卓手机 / UC扫码 / 安装提示)
|
||||
│ ├── icon-tg.png / .webp # 官方群组图标
|
||||
│ ├── icon-biz.png / .webp # 商务合作图标
|
||||
│ └── icon-channel.png / .webp # 渠道合作图标
|
||||
└── pc/ # 每变体一份
|
||||
├── bg1.png … bg5.png / .webp # 背景大图 1920×1080
|
||||
└── covers1.png … covers5.png / .webp # 底部封面长条 606×152(静态,5 张烤成一张)
|
||||
```
|
||||
|
||||
**核心思路:版面只写一次。** `PcLanding.vue` 接收 `variant`(0~4)prop,从 `variants.ts` 取该变体的 `bg` 与 `covers` 图,其余元素(导航、主文案、二维码区)5 变体完全共用。
|
||||
|
||||
---
|
||||
|
||||
## 3. 版面坐标(取自 Figma 变体 1 `73:53`,5 变体共用)
|
||||
|
||||
画布 1920×1080,全部为绝对坐标。
|
||||
|
||||
| 元素 | 位置 (x,y) | 尺寸 | 说明 |
|
||||
|---|---|---|---|
|
||||
| 背景大图 | 0,0 | 1920×1080 | **每变体不同**,含底部深色渐变压暗(保证文字可读) |
|
||||
| 顶部 pill 导航条 | 360,0 | 1200×70 | 半透明圆角条,水平居中 |
|
||||
| ├ logo 锁定组 | 420,15 | 154×40 | 图标 40×40 + "黄果短剧" + 标语,烤成一张图 |
|
||||
| └ 联系方式(3 项) | 1094,23 | 406×24 | 官方群组 / 商务合作 / 渠道合作,项间有圆点分隔 |
|
||||
| 主文案 | 204,308 | 630×381 | 标题"每一幀都能 解你的色" + 副标,烤成一张图 |
|
||||
| 二维码区 | 204,750 | 706×180 | 左二维码 + 右文字块 |
|
||||
| ├ 二维码本体 | 204,750 | 180×180 | 白底圆角,内 150×150 动态二维码 |
|
||||
| └ 二维码文字块 | 408,757 | 502×166 | 安卓手机 / 建议使用UC浏览器扫码 / 安装提示,烤成一张图 |
|
||||
| 底部封面行 | 1184,778 | 606×152 | **每变体不同**,5 张 110×152 封面,间距 14px,烤成一张长条图 |
|
||||
|
||||
> 实作计画阶段会逐变体拉取背景与封面的 imageRef / 导出节点。3 个联系方式项的精确间距(item1@0 / 分隔@124 / item2@156 / 分隔@280 / item3@312,相对 406 宽容器)届时核对。
|
||||
|
||||
---
|
||||
|
||||
## 4. 烤图 vs 程式画(沿用 pc2 约定)
|
||||
|
||||
| 元素 | 做法 | 共用/变体 |
|
||||
|---|---|---|
|
||||
| 背景大图 | `<picture>` webp+png | **变体** bg1–bg5 |
|
||||
| 底部 5 封面 | 烤成 606×152 长条图 | **变体** covers1–covers5 |
|
||||
| logo 锁定组 | 烤图 | 共用 |
|
||||
| 主文案 | 烤图 | 共用 |
|
||||
| 二维码旁文字 | 烤图 | 共用 |
|
||||
| 3 个导航项(图标+文字) | **程式画**:可点击、可埋点 | 共用 |
|
||||
| 二维码本体 | 动态 `DesktopQrcode`(编码当前网址) | 共用 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 路由 / 分流 / 埋点
|
||||
|
||||
改造 `src/pages/index.vue`:
|
||||
|
||||
- 设备检测沿用现有 UA 正则。
|
||||
- 把当前 `Math.random() < 0.5 ? "A" : "B"` 扩成 **5 路随机**:`variantIndex = Math.floor(Math.random() * 5)`(0~4),`version = ["A","B","C","D","E"][variantIndex]`。
|
||||
- 桌面 → `<PcLanding :variant="variantIndex" />`。
|
||||
- 埋点照旧:`trackLandingPageView({ landing_page_id: 'JHA-126' + version })`,点击埋点 `handleClick` 逻辑保留不动。
|
||||
- **手机分支(过渡):** 黄果手机版尚未做。本期先让手机分支渲染一个简单的黄果占位(或暂时保留现有 mobile 组件),等手机 Figma 到位后换成 `<MobileLanding :variant="variantIndex" />`。**实作时确认**取哪种过渡(默认:简单占位)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 导航链接(`config/variants.ts` 顶部常量,易替换)
|
||||
|
||||
```ts
|
||||
export const NAV_LINKS = {
|
||||
group: 'https://t.me/huangguoshortdrama', // 官方群组(已定)
|
||||
biz: '#TODO-business', // 商务合作(待用户提供)
|
||||
channel: '#TODO-channel', // 渠道合作(待用户提供)
|
||||
}
|
||||
```
|
||||
|
||||
- 商务合作 / 渠道合作链接**用户尚未提供**,先放占位常量,给到网址后改一行即可。
|
||||
- 点击导航项跳转 `window.location.href = NAV_LINKS.xxx`,并经由现有 `handleClick`(监听 window click,按 alt/innerText 取 tab_key)上报埋点。
|
||||
|
||||
---
|
||||
|
||||
## 7. 二维码行为
|
||||
|
||||
维持现状:`DesktopQrcode` 编码 `window.location.href`(手机扫码 → 打开当前落地页的手机版)。
|
||||
> 用户尚未决定是否改成固定 APK/下载链接。若后续要改,只需把 `qrcode.vue` 的 `URL.value` 来源换成固定值,影响面单一。
|
||||
|
||||
---
|
||||
|
||||
## 8. index.html SEO 改造(简体,黄果短剧)
|
||||
|
||||
| 字段 | 新值 |
|
||||
|---|---|
|
||||
| `lang` | 保持 `zh-CN` |
|
||||
| `<title>` | 黄果短剧官网 - 竖屏短剧APP下载 \| 黄果 |
|
||||
| `description` | 黄果短剧官网 —— 竖屏短剧新世代。强情节、快节奏、随时随地,把最上瘾的好故事装进你的每一个碎片时间。支持安卓/iOS下载,海量都市情感、甜宠恋爱、古装传奇、悬疑反转短剧,免费在线看。 |
|
||||
| `keywords` | 用户提供的整串清单(黄果 / 黄果短剧 / 短剧 / 竖屏短剧 / 下载 / 安卓 / iOS / 各题材 / 竞品词 等,逗号分隔) |
|
||||
| `og:title` | 黄果短剧 \| 竖屏短剧APP下载官方入口 |
|
||||
| `og:site_name` | 黄果短剧 |
|
||||
| `og:url` / `canonical` | https://huangguo.com |
|
||||
| `og:description` / twitter 同 description |
|
||||
| `theme-color` 等 | 保留 |
|
||||
|
||||
- `favicon` / `og:image`:暂保留现有,等黄果素材到位再换(**实作开放项**)。
|
||||
- 移除 `rating: adult` / RTA 等 bili 专用、与黄果无关的 meta(实作时确认)。
|
||||
|
||||
---
|
||||
|
||||
## 9. 图片压缩流程(用户明确要求)
|
||||
|
||||
1. 从 Figma 导出 PNG:背景用 **1×(1920×1080)**,不用 2×,控制体积;图标/封面按需 1×~2×。
|
||||
2. 跑 `pnpm webp`(`convertToWebp.js`,sharp `quality: 80`)批量生成 `.webp` 同名副本。
|
||||
3. 模板用 `<picture><source type="image/webp" :srcset="xxxW" /><img :src="xxx" /></picture>` 优先吃 webp、png 后备。
|
||||
4. build 时 `vite-plugin-vsharp` 再压一次。
|
||||
5. 背景为最大体积项,重点核对压后单张体积(目标尽量 < 300KB webp,必要时降质量或尺寸)。
|
||||
|
||||
---
|
||||
|
||||
## 10. 开放项(实作前/中确认)
|
||||
|
||||
1. 商务合作 / 渠道合作 链接 — 用户提供后替换占位。
|
||||
2. 二维码是否改固定下载链接 — 默认维持现状。
|
||||
3. 手机分支过渡方案 — 默认简单占位。
|
||||
4. favicon / og:image 黄果素材 — 默认暂留现有。
|
||||
5. 是否删除 / 保留旧 bili 页面(pc/pc2/mobile/mobile2)与 `project.md` — 默认**先保留**,不在本期清理。
|
||||
|
||||
---
|
||||
|
||||
## 11. 不在本期范围
|
||||
|
||||
- 手机版 5 变体(等 Figma)。
|
||||
- 删除旧 bili 页面 / 重写 project.md。
|
||||
- 新增后端接口 / 埋点字段。
|
||||
- 自动 commit / 部署。
|
||||
|
||||
---
|
||||
|
||||
## 12. 自检
|
||||
|
||||
- ✅ 5 变体共用版面 → `PcLanding.vue` 单组件 + `variants.ts` 映射。
|
||||
- ✅ 仅背景+封面随变体变 → 素材分 `common/` 与 `pc/`。
|
||||
- ✅ 5 路随机分流 + 埋点 A~E → `index.vue` 改造。
|
||||
- ✅ 图片压缩 → `pnpm webp` + `<picture>` + vsharp。
|
||||
- ✅ 官方群组链接已定,其余占位易替换。
|
||||
- ⚠️ 占位项(biz/channel 链接、二维码、手机过渡、favicon)已在第 10 节列明,不阻塞电脑版实作。
|
||||
Reference in New Issue
Block a user