fix(web): 四个页面共用一份会话列表,空会话不入列
Independent Staging Quality Gate / publish (push) Canceled after 0s
Independent Staging Quality Gate / validate (push) Canceled after 9m33s

对话、星盘、星历、报告进同一 (app) 外壳,列表只拉一次。服务端不再列出空咨询;新建复用已有空会话。新标题改成「生时校正 · M月D日」,侧栏副标题用创建时间。
This commit is contained in:
jesse-ux
2026-09-17 21:27:40 +08:00
parent 5203f9f0c3
commit e4e73f56c0
76 changed files with 1209 additions and 627 deletions
+13 -15
View File
@@ -5,6 +5,7 @@ import {
isGeneralDailyFortuneQuestion,
isRectificationHandoffQuestion,
} from "./consultation-entrypoint.ts";
import { shanghaiDateParts } from "./session-shanghai-clock.ts";
export type ReplyTheme = ConsultationDomain;
@@ -64,10 +65,14 @@ export type SessionTitleOptions = {
readonly existingTitles?: readonly string[];
};
const DATED_CATEGORY_PREFIX = /^(?:生时校正|今日节奏)\s*·\s*\d{1,2}月\d{1,2}日/;
const DATED_CATEGORY_SUFFIX = /^\d{1,2}月\d{1,2}日\s*·\s*(?:生时校正|今日节奏)(?:\s+\d{2}:\d{2})?$/;
export function isGenericSessionTitle(title: string): boolean {
const text = title.replace(/\s+/g, " ").trim();
if (!text) return true;
if (GENERIC_SESSION_TITLES.has(text)) return true;
if (DATED_CATEGORY_PREFIX.test(text) || DATED_CATEGORY_SUFFIX.test(text)) return true;
return /^(?:深入看今日|从今日问起|查看今日运势|生时校正|再次校正)/.test(text);
}
@@ -76,15 +81,9 @@ function clipTitle(value: string, maxChars = 14): string {
return characters.length > maxChars ? `${characters.slice(0, maxChars).join("")}…` : value;
}
function datedSessionTitle(at: Date, suffix: string): string {
return `${at.getMonth() + 1}月${at.getDate()}日 · ${suffix}`;
}
function uniquifySessionTitle(title: string, existingTitles: readonly string[], at: Date): string {
if (!existingTitles.includes(title)) return title;
const hours = String(at.getHours()).padStart(2, "0");
const minutes = String(at.getMinutes()).padStart(2, "0");
return `${title} ${hours}:${minutes}`;
function datedSessionTitle(at: Date, category: string): string {
const { month, day } = shanghaiDateParts(at);
return `${category} · ${month}月${day}日`;
}
export function resolveSessionTitle(
@@ -93,21 +92,20 @@ export function resolveSessionTitle(
options: SessionTitleOptions = {},
): string {
const at = options.at ?? new Date(); // new sessions only; see SessionTitleOptions.at
const existingTitles = options.existingTitles ?? [];
if (modelTitle && !isGenericSessionTitle(modelTitle)) {
return uniquifySessionTitle(clipTitle(modelTitle), existingTitles, at);
return clipTitle(modelTitle);
}
if (options.entrypoint === "daily_starlanguage" || isGeneralDailyFortuneQuestion(question)) {
return uniquifySessionTitle(datedSessionTitle(at, "今日节奏"), existingTitles, at);
return datedSessionTitle(at, "今日节奏");
}
if (options.entrypoint === "birth_time_rectification" || isRectificationHandoffQuestion(question)) {
return uniquifySessionTitle(datedSessionTitle(at, "生时校正"), existingTitles, at);
return datedSessionTitle(at, "生时校正");
}
const normalized = question.replace(/\s+/g, " ").trim().replace(/[??!!。.,,;;::]+$/u, "");
if (!normalized) return "新对话";
if (options.theme && options.theme !== "general") {
const label = consultationDomainDefinition(options.theme).label;
return uniquifySessionTitle(`${label} · ${clipTitle(normalized, 10)}`, existingTitles, at);
return `${label} · ${clipTitle(normalized, 10)}`;
}
return uniquifySessionTitle(clipTitle(normalized), existingTitles, at);
return clipTitle(normalized);
}