first commit
283
.claude/workflows/build-views.wf.js
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
export const meta = {
|
||||||
|
name: 'build-chanlun-views',
|
||||||
|
description: '并行构建缠论阅读站的 5 个页面视图并评审',
|
||||||
|
phases: [
|
||||||
|
{ title: 'Build', detail: '5 个页面视图并行构建' },
|
||||||
|
{ title: 'Review', detail: '设计一致性与暗色/响应式评审' },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 共享约定契约:所有构建 agent 必须遵守
|
||||||
|
// ============================================================
|
||||||
|
const CONV = `
|
||||||
|
你在为一个名为「缠论研习社」的 Vue 3 + Vite + Tailwind v4 + TypeScript 阅读站构建页面。
|
||||||
|
站点用途:展示缠中说禅《教你炒股票》原文与杂文的沉浸式阅读。设计风格=「现代融合」:玄鉴克制 UI + 衬线正文阅读优化,亮/暗双主题。
|
||||||
|
|
||||||
|
## 硬性规范
|
||||||
|
- 仅写你被分配的那一个 .vue 文件,用 Write 工具写到指定绝对路径。不要创建或修改其它文件。
|
||||||
|
- 不要运行 pnpm install / build / typecheck / dev 等命令(共享目录会冲突)。只写文件。
|
||||||
|
- 用 <script setup lang="ts">。类型导入必须用 import type。不要留未使用的变量/导入(会被 vue-tsc 拒绝)。
|
||||||
|
- UI 文案禁止 emoji。中文标点正确。语义化 HTML(用 <section><article><h1> 等)。
|
||||||
|
- 颜色/间距/圆角全部用下方语义 Token,禁止写死任意 hex/rgb 颜色值。
|
||||||
|
|
||||||
|
## 设计 Token(Tailwind 工具类,已全局定义)
|
||||||
|
背景:bg-app(应用底色) bg-background(卡片) bg-surface(次级面板) bg-surface-2(更浅悬浮) bg-hover
|
||||||
|
文本:text-foreground(主) text-muted(次) text-subtle(辅) text-faint(占位/禁用)
|
||||||
|
品牌/语义:text-primary bg-primary bg-primary-soft(浅蓝底) text-success/warning/danger,及 bg-success/10 等 /10 透明
|
||||||
|
边框:border-line(默认弱) border-line-strong(分割) border-line-card(卡片描边)
|
||||||
|
圆角:rounded-sm(8) rounded-md(12) rounded-lg(16) rounded-xl(20) rounded-2xl(24) rounded-full
|
||||||
|
阴影:shadow-xs shadow-sm shadow-soft shadow-md shadow-lg shadow-xl
|
||||||
|
字体:font-sans(默认) font-serif(衬线,正文/标题点缀) font-mono
|
||||||
|
过渡缓动:transition 配合 duration-150/200/300
|
||||||
|
留白要克制、克制、克制——玄鉴美学核心是「安静、轻、可信」:大量留白、弱边框、柔和阴影。
|
||||||
|
|
||||||
|
## 中文图标:lucide-vue-next,按名导入,例如
|
||||||
|
import { BookOpen, Clock, ArrowRight, Search, ChevronRight } from 'lucide-vue-next'
|
||||||
|
用 <BookOpen class="size-5" /> 渲染(size-4/5/[18px])。
|
||||||
|
|
||||||
|
## 数据访问:useArticles()(@/composables/useArticles)
|
||||||
|
返回:{ chanlun, essaysList, latest, featured, all, totalCount, find, neighbors, search }
|
||||||
|
- chanlun / essaysList / latest / featured 都是 computed(用 .value 在 script 内,模板内直接用)。
|
||||||
|
- find(category, slug) → Article | undefined
|
||||||
|
- neighbors(article) → { prev?: ArticleMeta, next?: ArticleMeta }
|
||||||
|
- search(query) → ArticleMeta[]
|
||||||
|
调用方式:const { chanlun, latest } = useArticles()
|
||||||
|
|
||||||
|
## 类型(@/types/article)
|
||||||
|
ArticleMeta: { id, slug, category:'chanlun'|'essay'|'notes', title, subtitle?, lesson?, date(ISO字符串), tags:string[], excerpt, readingTime(分钟) }
|
||||||
|
Article 继承 ArticleMeta 并含 content(markdown字符串)。
|
||||||
|
|
||||||
|
## 路由(@/router)
|
||||||
|
首页 '/'(name:'home')、缠论列表 '/chanlun'(name:'chanlun')、杂谈 '/articles'(name:'articles')、关于 '/about'(name:'about')。
|
||||||
|
阅读页:name 'reader',路径 '/read/:category/:slug',用 <RouterLink :to="{ name:'reader', params:{ category, slug } }">。
|
||||||
|
用 useRouter()/useRoute() 获取路由。RouterLink 从 'vue-router' 导入。
|
||||||
|
|
||||||
|
## 已有组件(按需导入使用,不要重造)
|
||||||
|
- @/components/ui/BaseButton.vue: props variant('primary'|'outline'|'surface'|'ghost'|'danger'), size('sm'|'md'|'lg'), block(bool), disabled(bool);默认 slot
|
||||||
|
- @/components/ui/Badge.vue: props tone('primary'|'neutral'|'success'|'warning'|'danger');默认 slot
|
||||||
|
- @/components/ui/Card.vue: props hover(bool), padded(bool,默认true);默认 slot
|
||||||
|
- @/components/ui/SearchInput.vue: v-model(modelValue) + placeholder
|
||||||
|
- @/components/ArticleCard.vue: props article(ArticleMeta), showExcerpt(bool,默认true)——已是 RouterLink 包裹的卡片,直接循环渲染
|
||||||
|
- @/components/TableOfContents.vue: props items(TocItem[]),TocItem={id,text,level:2|3}
|
||||||
|
|
||||||
|
## 工具
|
||||||
|
- @/utils/cn: cn(...classes), formatDate(iso)->'YYYY年M月D日', formatDateShort(iso)->'MM-DD'
|
||||||
|
- @/composables/useMarkdown: renderMarkdown(mdString)->htmlString, extractToc(mdString)->TocItem[]
|
||||||
|
- @/stores/reading: useReadingStore() → { fontSize, fontFamily, showToc, focusMode, toggleToc()... }
|
||||||
|
- @/stores/theme: useThemeStore()
|
||||||
|
|
||||||
|
## 布局说明(重要)
|
||||||
|
- 首页/缠论列表/杂谈/关于 这 4 个视图,运行在 DefaultLayout 内——该布局已提供 AppHeader(顶栏)+AppSidebar(侧栏)+AppFooter。所以你的视图只写主体内容,不要再加顶栏/侧栏/页脚。
|
||||||
|
- 阅读视图运行在 ReaderLayout 内——该布局已提供极简顶栏(返回/主题/阅读设置/目录开关)+ReadingProgress。所以阅读视图只写:[目录 | 正文] 网格 + 文章头部 + 正文 + 上下篇导航。
|
||||||
|
`
|
||||||
|
|
||||||
|
const BUILD_SCHEMA = {
|
||||||
|
type: 'object',
|
||||||
|
additionalProperties: false,
|
||||||
|
properties: {
|
||||||
|
file: { type: 'string', description: '写入的文件绝对路径' },
|
||||||
|
summary: { type: 'string', description: '一句话说明你实现了什么' },
|
||||||
|
components_used: { type: 'array', items: { type: 'string' } },
|
||||||
|
notes: { type: 'string', description: '任何需要主流程注意的点' },
|
||||||
|
},
|
||||||
|
required: ['file', 'summary'],
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 各页面规格
|
||||||
|
// ============================================================
|
||||||
|
const HOME_SPEC = `${CONV}
|
||||||
|
|
||||||
|
## 你的任务:构建首页 HomeView
|
||||||
|
写入文件:D:/code/chan/src/views/HomeView.vue
|
||||||
|
|
||||||
|
首页是站点的门面,要精致、有呼吸感。包含以下区块(用 <section> 组织):
|
||||||
|
|
||||||
|
1. Hero 区(顶部,克制而有气质):
|
||||||
|
- 大标题「缠论研习社」(font-serif, text-4xl~5xl, font-semibold)。
|
||||||
|
- 副标题:一句简介,如「缠中说禅《教你炒股票》原文与杂文 · 沉浸式系统性研习」。
|
||||||
|
- 两个按钮:BaseButton variant=primary「开始阅读」→ 跳转 featured 文章(用 useArticles().featured 的 category/slug);BaseButton variant=outline「了解缠论」→ /about。
|
||||||
|
- 可加极淡的装饰(如右上角半透明走势曲线 SVG,opacity 很低,不抢戏)。
|
||||||
|
- Hero 下方可放一行小统计:文章总数(totalCount)、分类数等,text-subtle。
|
||||||
|
|
||||||
|
2. 缠论体系概览(4 个概念卡片):分型 / 笔与线段 / 走势中枢 / 背驰与买卖点。每个卡片:lucide 图标(在 bg-primary-soft 圆角方块里)+ 标题 + 一句话。整组用 grid(sm:grid-cols-2 lg:grid-cols-4)。卡片用 Card 或自定义 div(bg-background border rounded-lg p-5)。点击可跳转第一课 /read/chanlun/ke-02-fenxing 之类(用 featured 或第一篇 chanlun)。
|
||||||
|
|
||||||
|
3. 分类入口(用 @/data/categories 的 categories 数组,3 个):缠论108课 / 杂谈随笔 / 我的理解。每个卡片显示 label、description、文章数(chanlun.length / essaysList.length / 0)。点击跳转对应路由。notes 分类显示「即将上线」徽标且不可点(或点向 /about)。
|
||||||
|
分类数据导入:import { categories } from '@/data/categories'
|
||||||
|
|
||||||
|
4. 最新文章:取 useArticles().latest(computed,最多6篇),用 ArticleCard 渲染(grid sm:grid-cols-2)。标题旁有「查看全部 →」链接到 /chanlun。
|
||||||
|
|
||||||
|
5. 页尾引言条:一句大字衬线引言「走势无须预测,只需应对。」居中,bg-surface 或带 primary 左边框的引用样式。
|
||||||
|
|
||||||
|
区块之间用 py-12 / py-16 等充足纵向留白分隔。整体 max-w 容器用 mx-auto max-w-[1200px] px-4。
|
||||||
|
`
|
||||||
|
|
||||||
|
const CHANLUN_SPEC = `${CONV}
|
||||||
|
|
||||||
|
## 你的任务:构建缠论列表页 ChanlunListView
|
||||||
|
写入文件:D:/code/chan/src/views/ChanlunListView.vue
|
||||||
|
|
||||||
|
这是「缠论 108 课」系列的文章列表页。
|
||||||
|
|
||||||
|
1. 页头:标题「缠论 108 课」(font-serif, text-3xl, font-semibold) + 副标题描述(取 categories 里 key='chanlun' 的 description)+ 右侧或下方显示文章数「共 N 课」。
|
||||||
|
2. 搜索栏:用 SearchInput(v-model 一个 query ref),placeholder「搜索课程…」。过滤逻辑:const filtered = computed(() => query.value ? search(query.value) : chanlun.value)。注意 search 返回 ArticleMeta[]。
|
||||||
|
3. 列表:用 ArticleCard 渲染 filtered。布局用 flex flex-col gap-3(单列堆叠卡片,适合课程列表的顺序阅读感)。
|
||||||
|
4. 空状态:filtered 为空时显示一个居中提示(图标 + 「未找到相关课程」+ 清除按钮)。
|
||||||
|
5. 顶部可加一个简短的「学习路径」提示卡(可选):用 bg-primary-soft 或 bg-surface,说明建议按课次顺序学习。
|
||||||
|
|
||||||
|
用 useArticles() 取 chanlun 与 search。用 @/data/categories 取描述。注意:模板里直接用 chanlun(computed 在模板自动解包);script 里用 chanlun.value。
|
||||||
|
`
|
||||||
|
|
||||||
|
const READER_SPEC = `${CONV}
|
||||||
|
|
||||||
|
## 你的任务:构建阅读视图 ArticleReaderView(最核心页面)
|
||||||
|
写入文件:D:/code/chan/src/views/ArticleReaderView.vue
|
||||||
|
|
||||||
|
这是沉浸式阅读页。运行在 ReaderLayout 内(已提供顶栏+进度条,不要再加)。
|
||||||
|
|
||||||
|
数据获取:
|
||||||
|
- const route = useRoute(); const { find, neighbors } = useArticles()
|
||||||
|
- const article = computed(() => find(route.params.category as ArticleCategory, route.params.slug as string))
|
||||||
|
- 文章切换时要滚回顶部:watch(() => route.params.slug, () => window.scrollTo({top:0})) (或 watch article)
|
||||||
|
|
||||||
|
找不到文章时:渲染一个居中的「未找到文章」状态 + 返回首页/列表的 RouterLink。
|
||||||
|
|
||||||
|
找到文章时,布局(网格):
|
||||||
|
<div class="mx-auto grid max-w-[1180px] gap-8 px-4 py-10 sm:px-6 lg:grid-cols-[220px_minmax(0,1fr)] lg:py-14">
|
||||||
|
<!-- 目录列:桌面端且 reading.showToc 为真时显示 -->
|
||||||
|
<aside class="hidden lg:block"> <div class="sticky top-20"> <TableOfContents :items="toc" v-if="toc.length"/> </div> </aside>
|
||||||
|
<!-- 正文列 -->
|
||||||
|
<article class="min-w-0 mx-auto w-full max-w-[760px]"> ... </article>
|
||||||
|
</div>
|
||||||
|
注意:目录列的显隐 = reading.showToc(lg 才显示)。当 reading.showToc 为 false 时,整个 aside 用 hidden;为 true 时 hidden lg:block。可用 :class="reading.showToc ? 'hidden lg:block' : 'hidden'"。
|
||||||
|
|
||||||
|
文章头部(在 <article> 内,正文之前):
|
||||||
|
- 分类 Badge(chanlun→「第 N 课」primary;essay→「杂谈」neutral)。
|
||||||
|
- 标题:article.title,font-serif text-3xl sm:text-4xl font-semibold,leading-tight。
|
||||||
|
- 副标题 article.subtitle(若有):text-muted。
|
||||||
|
- meta 行:formatDate(article.date) · 阅读时间 article.readingTime 分钟 · 标签(#tag)。用 text-subtle text-sm,lucide Clock 图标。
|
||||||
|
- 一条分割线 border-t border-line mt-6。
|
||||||
|
|
||||||
|
正文渲染(关键):
|
||||||
|
- const html = computed(() => renderMarkdown(article.value.content))
|
||||||
|
- const toc = computed(() => extractToc(article.value.content))
|
||||||
|
- 容器:<div class="prose-chan mt-8" :data-font="reading.fontFamily" :data-size="reading.fontSize" v-html="html"></div>
|
||||||
|
(prose-chan 的样式与 data-font/data-size 已在 style.css 定义,会驱动衬线/字号)
|
||||||
|
|
||||||
|
底部(正文之后):
|
||||||
|
- 标签云(如有)。
|
||||||
|
- 分割线。
|
||||||
|
- 上一篇/下一篇导航:neighbors(article.value) → { prev, next }。两个卡片横向排列(grid sm:grid-cols-2 gap-4),每张显示「上一篇/下一篇」小标 + 标题,用 RouterLink 指向对应 reader 路由。缺失的一侧显示占位「已是第一篇/最后一篇」(text-subtle)。
|
||||||
|
- 一个返回列表的链接(返回 /chanlun 或 /articles,依据 article.category)。
|
||||||
|
|
||||||
|
务必:导入 ArticleCategory 类型用 import type。watch、computed 从 vue 导入。useRoute 从 vue-router 导入。
|
||||||
|
`
|
||||||
|
|
||||||
|
const ESSAYS_SPEC = `${CONV}
|
||||||
|
|
||||||
|
## 你的任务:构建杂谈列表页 OtherArticlesView
|
||||||
|
写入文件:D:/code/chan/src/views/OtherArticlesView.vue
|
||||||
|
|
||||||
|
这是「杂谈随笔」的文章列表页(结构可参考缠论列表页,但气质更"随笔")。
|
||||||
|
|
||||||
|
1. 页头:标题「杂谈随笔」(font-serif text-3xl font-semibold) + 描述(categories 里 key='essay' 的 description)+ 文章数「共 N 篇」。
|
||||||
|
2. 搜索栏:SearchInput v-model query,过滤 essaysList。
|
||||||
|
3. 列表:用 ArticleCard 渲染。可用 flex flex-col gap-3 单列,或 grid sm:grid-cols-2 双列(杂谈更适合双列卡片网格)。自行选择更美观的。
|
||||||
|
4. 空状态:无结果提示。
|
||||||
|
5. 顶部可加一段引言卡片(可选):关于缠论作者或市场哲学的短引,bg-surface + primary 左边框引用样式。
|
||||||
|
|
||||||
|
用 useArticles() 取 essaysList 与 search。模板内直接用 essaysList;script 内用 essaysList.value。
|
||||||
|
`
|
||||||
|
|
||||||
|
const ABOUT_SPEC = `${CONV}
|
||||||
|
|
||||||
|
## 你的任务:构建关于页 AboutView
|
||||||
|
写入文件:D:/code/chan/src/views/AboutView.vue
|
||||||
|
|
||||||
|
关于本站页面。运行在 DefaultLayout 内(已有顶栏侧栏页脚)。
|
||||||
|
|
||||||
|
用居中窄栏(max-w-[760px] mx-auto)+ 衬线正文风格组织,分几个 <section>:
|
||||||
|
|
||||||
|
1. 页头:标题「关于缠论研习社」(font-serif text-3xl font-semibold) + 一句定位。
|
||||||
|
2. 「什么是缠论」:用 2-3 段说明缠论是缠中说禅创立的市场分析体系,核心是形态学(分型/笔/线段/中枢/走势类型)+动力学(背驰/买卖点),强调"无须预测、只需应对"。可用 .prose-chan 排版或自定义段落样式。
|
||||||
|
3. 「关于缠中说禅」:简述作者(匿名网络ID,2006-2008博客连载《教你炒股票》108课)。提醒可点击「杂谈随笔」看相关文章——放一个 RouterLink。
|
||||||
|
4. 「关于本站」:说明本站用途(系统研习缠论原文与杂文)、内容来源(抓取整理,仅供学习)、后续计划(结合当下股市的个人理解与实战笔记,即「我的理解」分区即将上线)。
|
||||||
|
5. 免责声明:用一个小卡片(bg-surface rounded-lg p-4 text-sm text-muted) 说明「本站内容仅供学习研究,不构成任何投资建议;市场有风险,入市需谨慎。」
|
||||||
|
|
||||||
|
可以适当用 lucide 图标点缀小标题。排版要克制、有书卷气。不要 emoji。
|
||||||
|
`
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 评审规格
|
||||||
|
// ============================================================
|
||||||
|
const REVIEW_SPEC = `${CONV}
|
||||||
|
|
||||||
|
## 你的任务:评审刚构建的 5 个页面视图
|
||||||
|
用 Read 工具逐一阅读这 5 个文件:
|
||||||
|
- D:/code/chan/src/views/HomeView.vue
|
||||||
|
- D:/code/chan/src/views/ChanlunListView.vue
|
||||||
|
- D:/code/chan/src/views/ArticleReaderView.vue
|
||||||
|
- D:/code/chan/src/views/OtherArticlesView.vue
|
||||||
|
- D:/code/chan/src/views/AboutView.vue
|
||||||
|
|
||||||
|
逐一检查并报告问题(不要修改文件,只报告):
|
||||||
|
1. TypeScript 正确性:是否有未使用的导入/变量(vue-tsc noUnusedLocals 会报错)、import type 是否用于纯类型导入、props 类型是否正确、computed/watch 用法是否正确。
|
||||||
|
2. 组件 API 用法:BaseButton/Badge/Card/SearchInput/ArticleCard/TableOfContents 的 props 是否传对(尤其 ArticleCard 的 article 是 ArticleMeta;TableOfContents 的 items 是 TocItem[])。
|
||||||
|
3. 设计一致性:是否只用了语义 Token(无写死颜色)、留白是否克制、圆角/阴影是否合规、是否符合玄鉴"安静克制"美学。
|
||||||
|
4. 暗色模式:所有颜色是否都用语义 Token(能自动适配暗色),有无硬编码深浅色。
|
||||||
|
5. 响应式:移动端(<lg)与桌面端布局是否合理(grid 断点、hidden/sm:block 等)。
|
||||||
|
6. 数据访问:useArticles 返回的 computed 在 script 中是否用 .value、模板中是否正确解包。
|
||||||
|
7. 路由:RouterLink 的 :to 是否正确(reader 用 {name,params})。
|
||||||
|
8. 可访问性:按钮有无 aria-label、语义化标签、标题层级。
|
||||||
|
|
||||||
|
按严重度 high/medium/low 报告,每条给出 file + issue + 具体修复建议(可粘贴代码)。最后给 overall 总评。
|
||||||
|
`
|
||||||
|
|
||||||
|
const REVIEW_SCHEMA = {
|
||||||
|
type: 'object',
|
||||||
|
additionalProperties: false,
|
||||||
|
properties: {
|
||||||
|
findings: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
additionalProperties: false,
|
||||||
|
properties: {
|
||||||
|
file: { type: 'string' },
|
||||||
|
severity: { type: 'string', enum: ['high', 'medium', 'low'] },
|
||||||
|
issue: { type: 'string' },
|
||||||
|
suggestion: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['file', 'severity', 'issue', 'suggestion'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
overall: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['findings', 'overall'],
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 执行
|
||||||
|
// ============================================================
|
||||||
|
phase('Build')
|
||||||
|
|
||||||
|
const builds = await parallel([
|
||||||
|
() => agent(HOME_SPEC, { label: 'build:home', phase: 'Build', schema: BUILD_SCHEMA }),
|
||||||
|
() => agent(CHANLUN_SPEC, { label: 'build:chanlun', phase: 'Build', schema: BUILD_SCHEMA }),
|
||||||
|
() => agent(READER_SPEC, { label: 'build:reader', phase: 'Build', schema: BUILD_SCHEMA }),
|
||||||
|
() => agent(ESSAYS_SPEC, { label: 'build:essays', phase: 'Build', schema: BUILD_SCHEMA }),
|
||||||
|
() => agent(ABOUT_SPEC, { label: 'build:about', phase: 'Build', schema: BUILD_SCHEMA }),
|
||||||
|
])
|
||||||
|
|
||||||
|
const ok = builds.filter(Boolean)
|
||||||
|
log(`已构建 ${ok.length}/5 个视图:${ok.map((b) => b?.file?.split('/').pop()).join(', ')}`)
|
||||||
|
|
||||||
|
phase('Review')
|
||||||
|
|
||||||
|
const review = await agent(REVIEW_SPEC, { label: 'review:views', phase: 'Review', schema: REVIEW_SCHEMA })
|
||||||
|
|
||||||
|
return {
|
||||||
|
built: ok.map((b) => ({ file: b.file, summary: b.summary })),
|
||||||
|
review,
|
||||||
|
}
|
||||||
24
.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
coverage
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
94
CLAUDE.md
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
项目:缠论研习社——缠中说禅《教你炒股票》原文与杂文的沉浸式阅读站。
|
||||||
|
|
||||||
|
## 命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install # 安装依赖(需 Node 20+ 与 pnpm)
|
||||||
|
pnpm dev # 开发服务器 → http://localhost:5173(vite open 自动开浏览器)
|
||||||
|
pnpm build # vue-tsc -b 类型检查 + vite 生产构建
|
||||||
|
pnpm build:only # 跳过类型检查,仅 vite build
|
||||||
|
pnpm typecheck # 仅 vue-tsc -b 类型检查(改完 TS/Vue 先跑这个)
|
||||||
|
pnpm preview # 预览生产构建
|
||||||
|
```
|
||||||
|
|
||||||
|
本机 pnpm v11 用 `pnpm-workspace.yaml` 的 `allowBuilds`(不是 `onlyBuiltDependencies`)放行 esbuild / vue-demi 的构建脚本;新增带构建脚本的 devDep 时需在此手动放行,否则安装会被拦。
|
||||||
|
|
||||||
|
## 样式约定(重要)
|
||||||
|
|
||||||
|
### 每个用 Tailwind 写的元素必须带一个「标记类名」
|
||||||
|
|
||||||
|
用 Tailwind 工具类写样式时,**必须给每个有独立含义的元素加一个语义化的标记 class,并放在 class 列表最前面**。这样用户在对话里能精确指代「改哪个 div」。
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<!-- ❌ 不要:纯工具类堆叠,用户无法指代 -->
|
||||||
|
<div class="flex items-center gap-2 rounded-md bg-surface px-3 py-2">
|
||||||
|
|
||||||
|
<!-- ✅ 要:标记类名打头(组件名__部位,kebab-case) -->
|
||||||
|
<div class="article-card__lesson flex items-center gap-2 rounded-md bg-surface px-3 py-2">
|
||||||
|
```
|
||||||
|
|
||||||
|
命名规则:`<组件或区块名>__<部位>`,如 `home-hero__title`、`reader-meta`、`article-card__tags`。一个 `.vue` 文件内的标记类名以该组件的功能名为前缀,保证跨组件不撞。
|
||||||
|
|
||||||
|
> 现存组件(如 `ArticleCard.vue`)尚未遵循此约定;**新建或重写元素时一律补上**,改动既有元素时顺手补。
|
||||||
|
|
||||||
|
### 颜色必须走设计 Token,禁止裸色值
|
||||||
|
|
||||||
|
所有颜色用 `src/style.css` 里 `@theme inline` 定义的语义类,**不要写 `bg-white` / `text-gray-500` / `#fff` 这类**:
|
||||||
|
|
||||||
|
- 背景:`bg-app`(应用底)/ `bg-background`(卡片)/ `bg-surface` / `bg-surface-2` / `bg-hover`
|
||||||
|
- 文本:`text-foreground` / `text-muted` / `text-subtle` / `text-faint`
|
||||||
|
- 品牌/语义:`text-primary` / `bg-primary-soft` / `text-success` / `text-warning` / `text-danger`
|
||||||
|
- 边框:`border-line` / `border-line-strong` / `border-line-card`
|
||||||
|
- 圆角用 `rounded-xs/sm/md/lg/xl/2xl`(4/8/12/16/20/24),阴影用 `shadow-xs/sm/soft/md/lg/xl`
|
||||||
|
|
||||||
|
亮/暗主题切换靠 `<html class="dark">`,所有语义色自动适配——**只要用 Token,就不用单独写 dark: 变体**。
|
||||||
|
|
||||||
|
### class 合并用 `cn()`
|
||||||
|
|
||||||
|
`src/utils/cn.ts` 的 `cn()` = clsx(条件)+ tailwind-merge(冲突后写覆盖前写,如 `px-2 px-4 → px-4`)。有条件 class 或动态拼接时用它,别手写字符串拼接。
|
||||||
|
|
||||||
|
## 架构(需要跨文件理解的)
|
||||||
|
|
||||||
|
**技术栈**:Vue 3 `<script setup>` + Vite 6 + Tailwind v4(CSS-first `@theme`)+ TS strict + Pinia + Vue Router 4 + markdown-it + lucide-vue-next。`@` 别名 → `src/`。
|
||||||
|
|
||||||
|
### 数据层是完全解耦的(核心设计)
|
||||||
|
|
||||||
|
页面不直接读数据文件,而是通过 `src/composables/useArticles.ts`:它把 `chanlunLessons`(`data/chanlun.ts`)和 `essays`(`data/essays.ts`)合并,提供 `chanlun / essaysList / latest / featured / find() / neighbors() / search()`。
|
||||||
|
|
||||||
|
- 接入真实抓取数据时:只改数据源(替换 `data/*.ts`)或把 `useArticles.ts` 内的静态数组改成异步请求,**页面和组件无需改动**。
|
||||||
|
- 文章正文是 **markdown 字符串**(`Article.content`,见 `types/article.ts`)。抓取的 HTML 入库时转 markdown,或扩展 `useMarkdown.ts` 直接渲染 HTML。
|
||||||
|
|
||||||
|
### 文章正文排版 = `.prose-chan`(不要手写)
|
||||||
|
|
||||||
|
正文区一律挂 `prose-chan` 类(定义在 `style.css` 的 `@layer components`),它已处理 h2/h3/p/blockquote/code/table/列表等全部排版。字号/字体不写死,而是通过 `data-size`(`sm|base|lg|xl`)和 `data-font`(`serif|sans`)属性驱动,值来自 reading store。
|
||||||
|
|
||||||
|
### 两个 Pinia store 驱动全局体验
|
||||||
|
|
||||||
|
- `stores/theme.ts`:`light | dark | system`,持久化到 `localStorage['chan-theme']`,靠给 `<html>` 加 `.dark` 生效。
|
||||||
|
- `stores/reading.ts`:字号 / 字体 / 专注模式,分别持久化。
|
||||||
|
- **防闪烁(FOUC)**:`index.html` 里有段内联脚本在 Vue 挂载前同步读 `chan-theme` 加 `.dark`。改主题存储 key 时,`index.html` 脚本和 `stores/theme.ts` 必须**同步改**,否则首屏会闪。
|
||||||
|
|
||||||
|
### 路由与布局
|
||||||
|
|
||||||
|
5 个 view,两种 layout:
|
||||||
|
- `DefaultLayout`(`/`):顶栏 + 侧栏 + 内容 + 页脚,包 home / chanlun / articles / about。
|
||||||
|
- `ReaderLayout`(`/read/:category/:slug`):沉浸阅读,含阅读进度、阅读设置、上下篇导航。
|
||||||
|
- markdown 的 h2/h3 会被 `useMarkdown.ts` 注入 `id`(slug 来自 `utils/slug.ts`),便于锚点跳转。
|
||||||
|
|
||||||
|
### 现存组件缺标记类名
|
||||||
|
|
||||||
|
`components/ui/`(BaseButton/Badge/Card/SearchInput)、`components/layout/`(AppHeader/AppSidebar/AppFooter)及 `ArticleCard` 等目前是纯工具类。改动它们时按上面的「标记类名」约定补齐。
|
||||||
|
|
||||||
|
## 其他约定
|
||||||
|
|
||||||
|
- TS strict 且开了 `noUnusedLocals` / `noUnusedParameters`:**未用的 import / 变量会直接让 `pnpm build` 失败**,删代码时记得清干净。
|
||||||
|
- `<script setup lang="ts">` + Composition API。
|
||||||
|
- 图标:默认用 `lucide-vue-next`(Vue 组件,按需 tree-shake)。另装了 **Remix Icon**(webfont)补 lucide 缺的图标,品牌 Logo 即用 `ri-line-chart-line`:
|
||||||
|
- CSS 已在 `main.ts` 全局引入 `remixicon/fonts/remixicon.css`,直接用 `<i class="ri-xxx-line" aria-hidden="true"></i>`。
|
||||||
|
- webfont 字号靠 `text-*`(font-size 驱动,不用 `size-*`);颜色继承 `currentColor`,所以放在 `text-white` 的容器里就是白色。
|
||||||
|
- 图标名查 https://remixicon.com(v4.9,无 candlestick;走势/图表类可用 `ri-line-chart-line` / `ri-bar-chart-line` / `ri-stock-line` / `ri-funds-line`)。
|
||||||
|
- `verbatimModuleSyntax: true`:类型 import 必须写 `import type { ... }`。
|
||||||
100
README.md
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# 缠论研习社
|
||||||
|
|
||||||
|
> 缠中说禅《教你炒股票》原文与杂文的沉浸式阅读站 · Vue 3 + Tailwind v4
|
||||||
|
|
||||||
|
专注缠论的系统性研习:从分型、笔、线段,到走势中枢、背驰、买卖点。亮/暗双主题、衬线正文阅读优化、目录导航、字号字体可调。
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
| 维度 | 选型 |
|
||||||
|
|------|------|
|
||||||
|
| 框架 | Vue 3(`<script setup>` + Composition API) |
|
||||||
|
| 构建 | Vite 6 |
|
||||||
|
| 样式 | Tailwind CSS v4(CSS-first `@theme`) |
|
||||||
|
| 语言 | TypeScript(strict) |
|
||||||
|
| 路由 | Vue Router 4 |
|
||||||
|
| 状态 | Pinia(主题、阅读偏好) |
|
||||||
|
| 图标 | lucide-vue-next |
|
||||||
|
| 正文 | markdown-it |
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install # 安装依赖
|
||||||
|
pnpm dev # 启动开发服务器 → http://localhost:5173
|
||||||
|
pnpm build # 类型检查 + 生产构建
|
||||||
|
pnpm preview # 预览生产构建
|
||||||
|
pnpm typecheck # 仅类型检查
|
||||||
|
```
|
||||||
|
|
||||||
|
> 需要 Node 20+ 与 pnpm。首次安装若提示构建脚本,已通过 `pnpm-workspace.yaml` 自动放行 esbuild / vue-demi。
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── components/
|
||||||
|
│ ├── ui/ # 基础组件:BaseButton / Badge / Card / SearchInput
|
||||||
|
│ ├── layout/ # AppHeader / AppSidebar / AppFooter
|
||||||
|
│ ├── ArticleCard.vue # 文章列表卡片
|
||||||
|
│ ├── TableOfContents.vue
|
||||||
|
│ ├── ThemeToggle.vue / ReaderSettings.vue / ReadingProgress.vue
|
||||||
|
├── composables/
|
||||||
|
│ ├── useArticles.ts # 文章数据访问层(列表/查找/相邻/搜索)
|
||||||
|
│ └── useMarkdown.ts # markdown 渲染 + 目录提取
|
||||||
|
├── data/
|
||||||
|
│ ├── chanlun.ts # 缠论 108 课(示例数据)
|
||||||
|
│ ├── essays.ts # 杂谈随笔(示例数据)
|
||||||
|
│ └── categories.ts # 分类信息
|
||||||
|
├── layouts/
|
||||||
|
│ ├── DefaultLayout.vue # 顶栏 + 侧栏 + 内容 + 页脚
|
||||||
|
│ └── ReaderLayout.vue # 沉浸阅读布局
|
||||||
|
├── views/ # 5 个页面
|
||||||
|
├── stores/ # theme / reading(Pinia)
|
||||||
|
├── types/article.ts # 类型定义
|
||||||
|
├── utils/ # cn / slug
|
||||||
|
└── style.css # 设计系统:玄鉴 Token + 亮暗主题 + 正文排版
|
||||||
|
```
|
||||||
|
|
||||||
|
## 接入你抓取的真实数据
|
||||||
|
|
||||||
|
数据层是完全解耦的。当前 `src/data/chanlun.ts` 与 `src/data/essays.ts` 是示例数据,**替换它们即可接入真实抓取内容**。
|
||||||
|
|
||||||
|
每篇文章的结构(见 `src/types/article.ts`):
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface Article {
|
||||||
|
id: string // 唯一 id
|
||||||
|
slug: string // URL 标识
|
||||||
|
category: 'chanlun' | 'essay' | 'notes'
|
||||||
|
title: string
|
||||||
|
subtitle?: string
|
||||||
|
lesson?: number // 仅缠论系列:第几课
|
||||||
|
date: string // ISO 日期,如 '2006-06-07'
|
||||||
|
tags: string[]
|
||||||
|
excerpt: string // 摘要
|
||||||
|
readingTime: number // 预计阅读分钟
|
||||||
|
content: string // markdown 正文
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
正文为 **markdown 字符串**——抓取的 HTML 可在入库时转换为 markdown(如 `turndown`),或扩展 `useMarkdown.ts` 支持直接渲染 HTML。后续若接入后端 API,只需把 `useArticles.ts` 的静态数据源改为异步请求即可,页面无需改动。
|
||||||
|
|
||||||
|
## 设计系统
|
||||||
|
|
||||||
|
采用「玄鉴」设计语言(克制、安静、可信),映射到 Tailwind v4 语义 Token:
|
||||||
|
|
||||||
|
- 颜色:`bg-app / bg-background / bg-surface`、`text-foreground / muted / subtle / faint`、`text-primary(#4d95ff) / bg-primary-soft`、`text-success / warning / danger`、`border-line / line-strong / line-card`
|
||||||
|
- 亮/暗双主题:通过 `<html class="dark">` 切换,所有颜色自动适配
|
||||||
|
- 正文:`.prose-chan` 衬线排版,字号/字体由阅读设置驱动(小/中/大/特大 · 衬线/黑体)
|
||||||
|
|
||||||
|
## 后续规划
|
||||||
|
|
||||||
|
- 「我的理解」分区:结合当下股市的缠论实战笔记
|
||||||
|
- 全文搜索、书签与阅读进度记录
|
||||||
|
- 走势图可视化(分型/笔/中枢标注)
|
||||||
|
- 后端 API 接入与内容管理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
内容仅供学习研究,不构成任何投资建议。市场有风险,入市需谨慎。
|
||||||
7
env.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
declare module '*.vue' {
|
||||||
|
import type { DefineComponent } from 'vue'
|
||||||
|
const component: DefineComponent<Record<string, never>, Record<string, never>, unknown>
|
||||||
|
export default component
|
||||||
|
}
|
||||||
32
index.html
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta name="description" content="缠论研习社 — 缠中说禅《教你炒股票》原文与杂文的沉浸式阅读站,专注走势、分型、笔、线段、中枢、背驰的系统性研习。" />
|
||||||
|
<!-- iOS 不把正文里的股票代码/年份误识别为 tel 链接 -->
|
||||||
|
<meta name="format-detection" content="telephone=no" />
|
||||||
|
<meta name="theme-color" content="#4d95ff" />
|
||||||
|
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0d0d0f" />
|
||||||
|
<title>缠论研习社</title>
|
||||||
|
<script>
|
||||||
|
// 防闪烁:在应用挂载前同步应用主题
|
||||||
|
(function () {
|
||||||
|
try {
|
||||||
|
var saved = localStorage.getItem('chan-theme')
|
||||||
|
var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
var isDark = saved ? saved === 'dark' : prefersDark
|
||||||
|
if (isDark) document.documentElement.classList.add('dark')
|
||||||
|
// 同步地址栏/状态栏主题色(覆盖用户手动切换为暗色的场景)
|
||||||
|
var m = document.querySelector('meta[name="theme-color"]:not([media])')
|
||||||
|
if (m) m.setAttribute('content', isDark ? '#0d0d0f' : '#4d95ff')
|
||||||
|
} catch (e) {}
|
||||||
|
})()
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
34
package.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "chanlun-reader",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"description": "缠论研习社 — 缠中说禅《教你炒股票》原文与文章的沉浸式阅读站",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vue-tsc -b && vite build",
|
||||||
|
"build:only": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"typecheck": "vue-tsc -b"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"lucide-vue-next": "^0.468.0",
|
||||||
|
"markdown-it": "^14.1.0",
|
||||||
|
"pinia": "^2.3.0",
|
||||||
|
"remixicon": "^4.9.1",
|
||||||
|
"tailwind-merge": "^3.0.0",
|
||||||
|
"vue": "^3.5.13",
|
||||||
|
"vue-router": "^4.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/vite": "^4.0.0",
|
||||||
|
"@types/markdown-it": "^14.1.2",
|
||||||
|
"@types/node": "^22.13.0",
|
||||||
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
|
"tailwindcss": "^4.0.0",
|
||||||
|
"typescript": "^5.7.2",
|
||||||
|
"vite": "^6.0.0",
|
||||||
|
"vue-tsc": "^2.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
1519
pnpm-lock.yaml
generated
Normal file
3
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
allowBuilds:
|
||||||
|
esbuild: true
|
||||||
|
vue-demi: true
|
||||||
BIN
public/chanlun-img/p024_01.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
public/chanlun-img/p024_02.png
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
public/chanlun-img/p025_01.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
public/chanlun-img/p032_01.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
public/chanlun-img/p033_01.png
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
public/chanlun-img/p036_01.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
public/chanlun-img/p043_01.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
public/chanlun-img/p043_02.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
public/chanlun-img/p047_01.png
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
public/chanlun-img/p047_02.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
public/chanlun-img/p048_01.png
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
public/chanlun-img/p049_01.png
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
public/chanlun-img/p050_01.png
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
public/chanlun-img/p052_01.png
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
public/chanlun-img/p053_01.png
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
public/chanlun-img/p054_01.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
public/chanlun-img/p054_02.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
public/chanlun-img/p054_03.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
public/chanlun-img/p054_04.png
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
public/chanlun-img/p056_01.png
Normal file
|
After Width: | Height: | Size: 695 KiB |
BIN
public/chanlun-img/p057_01.png
Normal file
|
After Width: | Height: | Size: 362 KiB |
BIN
public/chanlun-img/p058_01.png
Normal file
|
After Width: | Height: | Size: 370 KiB |
BIN
public/chanlun-img/p059_01.png
Normal file
|
After Width: | Height: | Size: 371 KiB |
BIN
public/chanlun-img/p059_02.png
Normal file
|
After Width: | Height: | Size: 378 KiB |
BIN
public/chanlun-img/p059_03.png
Normal file
|
After Width: | Height: | Size: 355 KiB |
BIN
public/chanlun-img/p060_01.png
Normal file
|
After Width: | Height: | Size: 393 KiB |
BIN
public/chanlun-img/p061_01.png
Normal file
|
After Width: | Height: | Size: 459 KiB |
BIN
public/chanlun-img/p061_02.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
public/chanlun-img/p061_03.png
Normal file
|
After Width: | Height: | Size: 428 KiB |
BIN
public/chanlun-img/p061_04.png
Normal file
|
After Width: | Height: | Size: 428 KiB |
BIN
public/chanlun-img/p061_05.png
Normal file
|
After Width: | Height: | Size: 415 KiB |
BIN
public/chanlun-img/p062_01.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
public/chanlun-img/p063_01.png
Normal file
|
After Width: | Height: | Size: 405 KiB |
BIN
public/chanlun-img/p064_01.png
Normal file
|
After Width: | Height: | Size: 364 KiB |
BIN
public/chanlun-img/p065_01.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
public/chanlun-img/p067_01.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
public/chanlun-img/p067_02.png
Normal file
|
After Width: | Height: | Size: 322 KiB |
BIN
public/chanlun-img/p068_01.png
Normal file
|
After Width: | Height: | Size: 379 KiB |
BIN
public/chanlun-img/p068_02.png
Normal file
|
After Width: | Height: | Size: 399 KiB |
BIN
public/chanlun-img/p068_03.png
Normal file
|
After Width: | Height: | Size: 405 KiB |
BIN
public/chanlun-img/p068_04.png
Normal file
|
After Width: | Height: | Size: 434 KiB |
BIN
public/chanlun-img/p069_01.png
Normal file
|
After Width: | Height: | Size: 336 KiB |
BIN
public/chanlun-img/p069_02.png
Normal file
|
After Width: | Height: | Size: 385 KiB |
BIN
public/chanlun-img/p069_03.png
Normal file
|
After Width: | Height: | Size: 426 KiB |
BIN
public/chanlun-img/p069_04.png
Normal file
|
After Width: | Height: | Size: 424 KiB |
BIN
public/chanlun-img/p069_05.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
public/chanlun-img/p069_06.png
Normal file
|
After Width: | Height: | Size: 451 KiB |
BIN
public/chanlun-img/p069_07.png
Normal file
|
After Width: | Height: | Size: 492 KiB |
BIN
public/chanlun-img/p070_01.png
Normal file
|
After Width: | Height: | Size: 389 KiB |
BIN
public/chanlun-img/p070_02.png
Normal file
|
After Width: | Height: | Size: 492 KiB |
BIN
public/chanlun-img/p070_03.png
Normal file
|
After Width: | Height: | Size: 389 KiB |
BIN
public/chanlun-img/p071_01.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
public/chanlun-img/p071_02.png
Normal file
|
After Width: | Height: | Size: 426 KiB |
BIN
public/chanlun-img/p072_01.png
Normal file
|
After Width: | Height: | Size: 433 KiB |
BIN
public/chanlun-img/p072_02.png
Normal file
|
After Width: | Height: | Size: 386 KiB |
BIN
public/chanlun-img/p073_01.png
Normal file
|
After Width: | Height: | Size: 375 KiB |
BIN
public/chanlun-img/p076_01.png
Normal file
|
After Width: | Height: | Size: 388 KiB |
BIN
public/chanlun-img/p078_01.png
Normal file
|
After Width: | Height: | Size: 400 KiB |
BIN
public/chanlun-img/p079_01.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
public/chanlun-img/p079_02.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
public/chanlun-img/p080_01.png
Normal file
|
After Width: | Height: | Size: 391 KiB |
BIN
public/chanlun-img/p080_02.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
public/chanlun-img/p080_03.png
Normal file
|
After Width: | Height: | Size: 370 KiB |
BIN
public/chanlun-img/p080_04.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
public/chanlun-img/p080_05.png
Normal file
|
After Width: | Height: | Size: 329 KiB |
BIN
public/chanlun-img/p080_06.png
Normal file
|
After Width: | Height: | Size: 352 KiB |
BIN
public/chanlun-img/p081_01.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/chanlun-img/p081_02.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/chanlun-img/p081_03.png
Normal file
|
After Width: | Height: | Size: 359 KiB |
BIN
public/chanlun-img/p081_04.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
public/chanlun-img/p081_05.png
Normal file
|
After Width: | Height: | Size: 356 KiB |
BIN
public/chanlun-img/p082_01.png
Normal file
|
After Width: | Height: | Size: 478 KiB |
BIN
public/chanlun-img/p082_02.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
public/chanlun-img/p083_01.png
Normal file
|
After Width: | Height: | Size: 303 KiB |
BIN
public/chanlun-img/p084_01.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
public/chanlun-img/p084_02.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
public/chanlun-img/p087_01.png
Normal file
|
After Width: | Height: | Size: 422 KiB |
BIN
public/chanlun-img/p088_01.png
Normal file
|
After Width: | Height: | Size: 422 KiB |
BIN
public/chanlun-img/p088_02.png
Normal file
|
After Width: | Height: | Size: 450 KiB |
BIN
public/chanlun-img/p088_03.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
public/chanlun-img/p088_04.png
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
public/chanlun-img/p088_05.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
public/chanlun-img/p088_06.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
public/chanlun-img/p090_01.png
Normal file
|
After Width: | Height: | Size: 188 KiB |
BIN
public/chanlun-img/p090_02.png
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
public/chanlun-img/p090_03.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
public/chanlun-img/p091_01.png
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
public/chanlun-img/p091_02.png
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
public/chanlun-img/p091_03.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
public/chanlun-img/p092_01.png
Normal file
|
After Width: | Height: | Size: 398 KiB |
BIN
public/chanlun-img/p092_02.png
Normal file
|
After Width: | Height: | Size: 101 KiB |