Files
v2/front/src/api.ts
2026-01-27 13:19:18 +08:00

381 lines
10 KiB
TypeScript

export interface SiteSettings {
siteTitle: string;
siteFooter: string;
enableCodeIcon: boolean;
repoUrl: string;
favicon: string;
}
export const getSettings = async (): Promise<SiteSettings> => {
try {
const response = await fetch('/api/settings');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code === 1000 && json.data) {
const data = json.data;
return {
siteTitle: data.title,
siteFooter: data.footer_text,
enableCodeIcon: data.enable_repo_button ?? true,
repoUrl: data.repo_link,
favicon: data.icon,
};
} else {
throw new Error('Invalid response code or missing data');
}
} catch (error) {
console.error('Failed to fetch settings:', error);
throw error;
}
};
export const getAbout = async (): Promise<string> => {
try {
const response = await fetch('/api/about');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code === 1000) {
return json.data;
} else {
throw new Error('Invalid response code');
}
} catch (error) {
console.error('Failed to fetch about content:', error);
throw error;
}
};
export interface StaticsData {
posts: number;
comments: number;
images: number;
}
export const testApiStatus = async (): Promise<boolean> => {
try {
const response = await fetch('/api/test');
return response.ok;
} catch (error) {
return false;
}
};
export const getStatics = async (): Promise<StaticsData> => {
try {
const response = await fetch('/api/statics');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code === 1000) {
return json.data;
} else {
throw new Error('Invalid response code');
}
} catch (error) {
console.error('Failed to fetch statics:', error);
throw error;
}
};
export const saveDraft = (content: string): void => {
localStorage.setItem('draft', content);
};
export const getDraft = (): string | null => {
return localStorage.getItem('draft');
};
export const fetch_id_token = async (): Promise<string> => {
try {
const response = await fetch('/api/get_id_token');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code === 1000) {
return json.data;
} else {
throw new Error(json.data || 'Failed to fetch identity token');
}
} catch (error) {
console.error('Failed to fetch identity token:', error);
throw error;
}
};
export const get_id_token = async (): Promise<string> => {
let token = localStorage.getItem('identity_token');
if (!token) {
token = await fetch_id_token();
localStorage.setItem('identity_token', token);
}
return token;
};
export interface CreatePostResponse {
code: number;
data: any;
}
export const createPost = async (content: string): Promise<CreatePostResponse> => {
try {
const identity = await get_id_token();
// 解析标签:#开头,后跟非空白字符
const hashtopic: string[] = [];
const regex = /#\S+/g;
const matches = content.match(regex);
if (matches) {
matches.forEach(tag => {
const cleanTag = tag.substring(1);
// 去重添加
if (!hashtopic.includes(cleanTag)) {
hashtopic.push(cleanTag);
}
});
}
const response = await fetch('/api/post', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
content,
hashtopic,
identity
}),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Failed to create post:', error);
throw error;
}
};
export interface Article {
id: number;
content: string;
upvotes: number;
downvotes: number;
created_at?: string;
comment_count?: number;
total_pages?: number;
}
export const fetchArticles = async (page: number, signal?: AbortSignal): Promise<Article[]> => {
try {
const response = await fetch(`/api/posts_info?page=${page}`, { signal });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code === 1000 && Array.isArray(json.data)) {
return json.data as Article[];
}
throw new Error('Invalid response code or missing data');
} catch (error) {
console.error('Failed to fetch articles:', error);
throw error;
}
};
export const voteArticle = async (id: number, type: 'up' | 'down'): Promise<void> => {
try {
const response = await fetch(`/api/${type}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ id, type: 'submission' }),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code !== 1000) {
throw new Error('Vote failed');
}
} catch (error) {
console.error('Failed to vote:', error);
throw error;
}
};
export interface Comment {
id: number;
nickname: string;
content: string;
parent_comment_id: number;
}
export interface CommentPage {
comments: Comment[];
total_pages: number;
}
export const getComments = async (id: string | number, page: number = 1): Promise<CommentPage> => {
try {
const response = await fetch(`/api/get/comment?id=${id}&page=${page}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code === 1000 && json.data && Array.isArray(json.data.comments)) {
return {
comments: json.data.comments as Comment[],
total_pages: Number(json.data.total_pages) || 0,
};
}
throw new Error('Invalid response code or missing data');
} catch (error) {
console.error('Failed to fetch comments:', error);
throw error;
}
};
export interface PostCommentRequest {
content: string;
submission_id: number;
parent_comment_id: number;
nickname: string;
}
export interface PostCommentResponse {
id: number;
}
export const postComment = async (commentData: PostCommentRequest): Promise<PostCommentResponse> => {
try {
const identity = await get_id_token();
const hashtopic: string[] = [];
const regex = /#\S+/g;
const matches = commentData.content.match(regex);
if (matches) {
matches.forEach(tag => {
const cleanTag = tag.substring(1);
if (!hashtopic.includes(cleanTag)) {
hashtopic.push(cleanTag);
}
});
}
const response = await fetch('/api/comment', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...commentData,
hashtopic,
identity,
}),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code === 1001 && json.data?.id !== undefined) {
return { id: Number(json.data.id) };
}
if (json.code === 2005) {
throw new Error('评论包含违禁词');
}
throw new Error('Comment failed');
} catch (error) {
console.error('Failed to post comment:', error);
throw error;
}
};
export interface ReportPostResponse {
id: number;
}
export const reportPost = async (reportData: { id: number; title: string; content: string }): Promise<ReportPostResponse> => {
try {
const identity = await get_id_token();
const response = await fetch('/api/report', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...reportData,
identity,
}),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code === 1001 && json.data?.id !== undefined) {
return { id: Number(json.data.id) };
}
throw new Error(json.data || 'Report failed');
} catch (error) {
console.error('Failed to report post:', error);
throw error;
}
};
export const uploadImage = async (file: File): Promise<string> => {
try {
const identity_token = await get_id_token();
const formData = new FormData();
formData.append('file', file);
if (identity_token) {
formData.append('identity_token', identity_token);
}
const response = await fetch('/api/upload_pic', {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code === 1001 && typeof json.data === 'string') {
return json.data;
}
if (json.code === 2006) {
throw new Error('UPLOAD_TOO_LARGE');
}
if (json.code === 2007) {
throw new Error('UNSUPPORTED_FORMAT');
}
throw new Error(json.data || 'Upload failed');
} catch (error) {
console.error('Failed to upload image:', error);
throw error;
}
};
export const getFileName = async (path: string): Promise<string> => {
try {
const response = await fetch(`/api/file_name?path=${encodeURIComponent(path)}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
if (json.code === 1000 && typeof json.data === 'string') {
return json.data;
}
throw new Error('Invalid response code or missing data');
} catch (error) {
console.error('Failed to fetch file name:', error);
throw error;
}
};