style(格式化): 改成单引号、一行最长 160,全仓重新格式化
Deploy / deploy (push) Canceled after 0s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-26 13:52:24 +08:00
1 parent 530e1a3d5d
commit 195069450f
480 files changed
+15507 -24650

No files matched your search

+24 -27
View File
@@ -1,10 +1,10 @@
import { isLessonDone, type TutorialProgress, type TutorialSummary } from "@oj2/contract"
import { isLessonDone, type TutorialProgress, type TutorialSummary } from '@oj2/contract'
export type TutorialType = "python" | "c"
export type TutorialType = 'python' | 'c'
export const COURSES: { type: TutorialType; label: string }[] = [
{ type: "python", label: "Python" },
{ type: "c", label: "C 语言" },
{ type: 'python', label: 'Python' },
{ type: 'c', label: 'C 语言' },
]
/**
@@ -12,8 +12,8 @@ export const COURSES: { type: TutorialType; label: string }[] = [
* 所以显示时知识点在前、情境在后。没有「——」的老教程整个当知识点。
*/
export function splitTitle(title: string) {
const at = title.indexOf("——")
if (at < 0) return { kp: title.trim(), scene: "" }
const at = title.indexOf('——')
if (at < 0) return { kp: title.trim(), scene: '' }
return { kp: title.slice(at + 2).trim(), scene: title.slice(0, at).trim() }
}
@@ -30,7 +30,7 @@ export interface ProjectGroup {
/** 「智慧农业·蜜橘园」 */
name: string
icon: string
tone: "blue" | "purple" | "green" | "orange" | "gray"
tone: 'blue' | 'purple' | 'green' | 'orange' | 'gray'
/** 这个项目里的课,`step` 是在整门课里的序号(1 起) */
lessons: { id: number; title: string; step: number }[]
}
@@ -38,17 +38,17 @@ export interface ProjectGroup {
/** 「项目三 · 智慧农业·蜜橘园」拆成「项目三」和「智慧农业·蜜橘园」 */
export function splitProject(project: string) {
const match = project.match(/^(项目[一二三四五六七八九十\d]+)\s*[·・.]\s*(.+)$/)
if (!match) return { no: "", name: project || "其他" }
if (!match) return { no: '', name: project || '其他' }
return { no: match[1]!, name: match[2]!.trim() }
}
/** 项目图标按情境挑,认不出的给一本书 */
function projectLook(name: string): Pick<ProjectGroup, "icon" | "tone"> {
if (name.includes("家居")) return { icon: "ph:house", tone: "blue" }
if (name.includes("工业") || name.includes("设备")) return { icon: "ph:factory", tone: "purple" }
if (name.includes("农业")) return { icon: "ph:plant", tone: "green" }
if (name.includes("交通")) return { icon: "ph:car", tone: "orange" }
return { icon: "ph:book-open", tone: "gray" }
function projectLook(name: string): Pick<ProjectGroup, 'icon' | 'tone'> {
if (name.includes('家居')) return { icon: 'ph:house', tone: 'blue' }
if (name.includes('工业') || name.includes('设备')) return { icon: 'ph:factory', tone: 'purple' }
if (name.includes('农业')) return { icon: 'ph:plant', tone: 'green' }
if (name.includes('交通')) return { icon: 'ph:car', tone: 'orange' }
return { icon: 'ph:book-open', tone: 'gray' }
}
/** 按项目分组,保持课程原来的顺序;同一个项目被别的项目隔开时各算一组 */
@@ -72,27 +72,24 @@ export function groupByProject(titles: TutorialSummary[]): ProjectGroup[] {
return groups
}
export type LessonState = "done" | "started" | "todo"
export type LessonState = 'done' | 'started' | 'todo'
/**
* 目录上的三态。学完 = 练一练全对(契约的 `isLessonDone`);打开过或者做过练一练但没
* 全对是「在学」;别的是没开始。
*/
export function lessonState(progress: TutorialProgress | undefined): LessonState {
if (!progress) return "todo"
if (isLessonDone(progress)) return "done"
if (progress.viewCount > 0 || progress.exerciseSolved > 0) return "started"
return "todo"
if (!progress) return 'todo'
if (isLessonDone(progress)) return 'done'
if (progress.viewCount > 0 || progress.exerciseSolved > 0) return 'started'
return 'todo'
}
/**
* 「接着学」哪一课:最近打开的那课;它已经学完了,就往后找第一课没学完的。
* 一课没打开过返回 null(首页换成「开始学」)。
*/
export function continueStep(
titles: TutorialSummary[],
progress: Record<number, TutorialProgress>,
) {
export function continueStep(titles: TutorialSummary[], progress: Record<number, TutorialProgress>) {
let latest: TutorialProgress | null = null
for (const item of titles) {
const row = progress[item.id]
@@ -101,17 +98,17 @@ export function continueStep(
if (!latest) return null
const index = titles.findIndex((item) => item.id === latest!.tutorialId)
if (index < 0) return null
if (lessonState(latest) !== "done") return index + 1
if (lessonState(latest) !== 'done') return index + 1
for (let i = index + 1; i < titles.length; i++) {
if (lessonState(progress[titles[i]!.id]) !== "done") return i + 1
if (lessonState(progress[titles[i]!.id]) !== 'done') return i + 1
}
return index + 1
}
export function doneCount(titles: TutorialSummary[], progress: Record<number, TutorialProgress>) {
return titles.filter((item) => lessonState(progress[item.id]) === "done").length
return titles.filter((item) => lessonState(progress[item.id]) === 'done').length
}
export function lessonPath(type: TutorialType, step: number) {
return `/learn/${type}/${step.toString().padStart(2, "0")}`
return `/learn/${type}/${step.toString().padStart(2, '0')}`
}