| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- import type { IntlShape } from "react-intl";
- import type { ArticleMode, TContentType } from "./Article";
- import { get, put } from "../request";
- import { message } from "antd";
- import { toISentence } from "../components/sentence/utils";
- import type { IStudio, IUser } from "./Auth";
- import type { IChannel } from "./Channel";
- import type { ISuggestionCount } from "./Suggestion";
- import type { ITocPathNode } from "./pali-text";
- // ─── 以下是原有类型定义,保持不动 ─────────────────────────────────────────────
- export interface ISentence {
- id?: string;
- uid?: string;
- content: string | null;
- contentType?: TContentType;
- html: string;
- book: number;
- para: number;
- wordStart: number;
- wordEnd: number;
- editor: IUser;
- acceptor?: IUser;
- prEditAt?: string;
- channel: IChannel;
- studio?: IStudio;
- forkAt?: string | null;
- updateAt: string;
- createdAt?: string;
- suggestionCount?: ISuggestionCount;
- openInEditMode?: boolean;
- translationChannels?: string[];
- }
- export interface ISentenceDiffRequest {
- sentences: string[];
- channels: string[];
- }
- export interface ISentenceDiffData {
- book_id: number;
- paragraph: number;
- word_start: number;
- word_end: number;
- channel_uid: string;
- content: string | null;
- content_type: string;
- editor_uid: string;
- updated_at: string;
- }
- export interface ISentenceDiffResponse {
- ok: boolean;
- message: string;
- data: { rows: ISentenceDiffData[]; count: number };
- }
- export interface ISentenceRequest {
- book: number;
- para: number;
- wordStart: number;
- wordEnd: number;
- channel: string;
- content: string | null;
- contentType?: TContentType;
- prEditor?: string;
- prId?: string;
- prUuid?: string;
- prEditAt?: string;
- channels?: string;
- html?: boolean;
- token?: string | null;
- }
- export interface ISentenceData {
- id?: string;
- book: number;
- paragraph: number;
- word_start: number;
- word_end: number;
- content: string;
- content_type?: TContentType;
- html: string;
- editor: IUser;
- channel: IChannel;
- studio: IStudio;
- updated_at: string;
- acceptor?: IUser;
- pr_edit_at?: string;
- fork_at?: string;
- suggestionCount?: ISuggestionCount;
- }
- export interface ISentenceResponse {
- ok: boolean;
- message: string;
- data: ISentenceData;
- }
- export interface ISentenceListResponse {
- ok: boolean;
- message: string;
- data: { rows: ISentenceData[]; count: number };
- }
- export interface ISentenceNewRequest {
- sentences: ISentenceDiffData[];
- channel?: string;
- copy?: boolean;
- fork_from?: string;
- }
- export interface ISentenceWbwListResponse {
- ok: boolean;
- message: string;
- data: { rows: ISentEditData[]; count: number };
- }
- export interface IEditableSentence {
- ok: boolean;
- message: string;
- data: ISentEditData;
- }
- export interface ISentEditData {
- id: string;
- book: number;
- para: number;
- wordStart: number;
- wordEnd: number;
- channels?: string[];
- origin?: ISentence[];
- translation?: ISentence[];
- commentaries?: ISentence[];
- answer?: ISentence;
- path?: ITocPathNode[];
- layout?: "row" | "column";
- tranNum?: number;
- nissayaNum?: number;
- commNum?: number;
- originNum: number;
- simNum?: number;
- compact?: boolean;
- mode?: ArticleMode;
- showWbwProgress?: boolean;
- readonly?: boolean;
- wbwProgress?: number;
- wbwScore?: number;
- }
- // ─── 原有函数,保持不动,重构完成后再删除 ──────────────────────────────────────
- export const sentSave = async (
- sent: ISentence,
- intl: IntlShape,
- ok?: (res: ISentence) => void,
- finish?: () => void
- ): Promise<ISentenceData | null> => {
- //FIXME
- //store.dispatch(statusChange({ status: "loading" }));
- const id = `${sent.book}_${sent.para}_${sent.wordStart}_${sent.wordEnd}_${sent.channel.id}`;
- const url = `/v2/sentence/${id}?mode=edit&html=true`;
- console.info("SentWbwEdit url", url);
- try {
- const res = await put<ISentenceRequest, ISentenceResponse>(url, {
- book: sent.book,
- para: sent.para,
- wordStart: sent.wordStart,
- wordEnd: sent.wordEnd,
- channel: sent.channel.id,
- content: sent.content,
- contentType: sent.contentType,
- channels: sent.translationChannels?.join(),
- token: sessionStorage.getItem(sent.channel.id),
- });
- if (res.ok) {
- if (ok) {
- console.debug("sent save ok", res.data);
- const newData: ISentence = toISentence(res.data);
- ok(newData);
- }
- /**
- * FIXME
- store.dispatch(
- statusChange({
- status: "success",
- message: intl.formatMessage({ id: "flashes.success" }),
- })
- );
- */
- return res.data;
- } else {
- message.error(res.message);
- /**
- * FIXME
- store.dispatch(
- statusChange({
- status: "fail",
- message: res.message,
- })
- );
- */
- return null;
- }
- } catch (e) {
- console.error("catch", e);
- return null;
- } finally {
- finish?.();
- }
- };
- // ─── 新增:纯 HTTP 函数,供 hooks 层调用 ────────────────────────────────────────
- // 规范:只管收发,不含 UI 反馈、不含 store.dispatch、不含业务判断
- /**
- * 加载单条句子
- */
- export async function fetchSentence(
- book: number,
- para: number,
- wordStart: number,
- wordEnd: number,
- channelId: string
- ): Promise<ISentenceData> {
- const sentId = `${book}-${para}-${wordStart}-${wordEnd}`;
- const url = `/v2/sentence?view=channel&sentence=${sentId}&channel=${channelId}&html=true`;
- const json = await get<ISentenceListResponse>(url);
- if (!json.ok || json.data.count === 0) {
- throw new Error(json.message ?? "句子加载失败");
- }
- return json.data.rows[0];
- }
- /**
- * 保存句子内容(新建 or 更新)
- */
- export async function saveSentence(sent: ISentence): Promise<ISentenceData> {
- const id = `${sent.book}_${sent.para}_${sent.wordStart}_${sent.wordEnd}_${sent.channel.id}`;
- const url = `/v2/sentence/${id}?mode=edit&html=true`;
- const json = await put<ISentenceRequest, ISentenceResponse>(url, {
- book: sent.book,
- para: sent.para,
- wordStart: sent.wordStart,
- wordEnd: sent.wordEnd,
- channel: sent.channel.id,
- content: sent.content,
- contentType: sent.contentType,
- channels: sent.translationChannels?.join(),
- token: sessionStorage.getItem(sent.channel.id),
- });
- if (!json.ok) {
- throw new Error(json.message ?? "保存失败");
- }
- return json.data;
- }
- /**
- * 采纳 PR:把 PR 内容写回正式句子
- */
- export async function acceptSentencePr(
- prData: ISentence
- ): Promise<ISentenceData> {
- const id = `${prData.book}_${prData.para}_${prData.wordStart}_${prData.wordEnd}_${prData.channel.id}`;
- const url = `/v2/sentence/${id}?mode=edit&html=true`;
- const json = await put<ISentenceRequest, ISentenceResponse>(url, {
- book: prData.book,
- para: prData.para,
- wordStart: prData.wordStart,
- wordEnd: prData.wordEnd,
- channel: prData.channel.id,
- content: prData.content,
- prEditor: prData.editor?.id,
- prId: prData.id,
- prUuid: prData.uid,
- prEditAt: prData.updateAt,
- token: sessionStorage.getItem(prData.channel.id),
- });
- if (!json.ok) {
- throw new Error(json.message ?? "采纳失败");
- }
- return json.data;
- }
- /**
- * 获取 Snowflake ID(wbw 节点赋 uid 用)
- */
- export async function fetchSnowflakeIds(count: number): Promise<string[]> {
- const json = await get<{
- ok: boolean;
- message?: string;
- data: { rows: string[]; count: number };
- }>(`/v2/snowflake?count=${count}`);
- if (!json.ok) {
- throw new Error(json.message ?? "获取 ID 失败");
- }
- return json.data.rows;
- }
|