From abae2e266ad8a2f3d90b24584f38b95ac69bf204 Mon Sep 17 00:00:00 2001 From: Leonxie Date: Fri, 23 Jan 2026 13:46:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=8A=95=E7=A8=BF=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/main.py | 5 +- code_meaning.md | 4 +- front/src/api.ts | 73 +++++++++++++++++++++++++++++ front/src/components/CreatePost.tsx | 59 ++++++++++++++++++++++- 4 files changed, 137 insertions(+), 4 deletions(-) diff --git a/back/main.py b/back/main.py index 40471fc..1bf017c 100644 --- a/back/main.py +++ b/back/main.py @@ -116,7 +116,7 @@ def get_about(): # about在初始化时不会被设置,避免管理面板报错,返回默认文本 return jsonify({ "code": 1000, - "data": "# 默认关于页面\n关于页面未设置,请前往管理面板。" + "data": "# 默认关于页面\n关于页面未设置,请前往管理面板操作。" }) @app.route('/api/get_id_token', methods=['GET']) @@ -197,7 +197,8 @@ def submit_post(): db.session.add(new_post) db.session.commit() - return jsonify({"code": 1000, "data": "投稿成功"}) + code = 1002 if new_post.status == 'Pending' else 1001 + return jsonify({"code": code, "data": {"id": new_post.id}}) except Exception as e: return jsonify({"code": 2003, "data": f"投稿失败: {str(e)}"}) diff --git a/code_meaning.md b/code_meaning.md index 591e14d..abbe917 100644 --- a/code_meaning.md +++ b/code_meaning.md @@ -29,12 +29,14 @@ | Code | 含义 | | ---- | ---------------------------------------------------- | | 1000 | 正常。适用于大多数成功的GET请求的返回。 | -| | | +| 1001 | 正常。适用于大多数成功的POST请求的返回。 | +| 1002 | 正常。提交内容需要等待审核。 | | 2000 | 失败。请求方式错误,例如缺少指定参数。 | | 2001 | 失败。未初始化。不应该在成功初始化后继续使用该code。 | | 2002 | 失败。数据不存在。 | | 2003 | 失败。服务器内部错误。 | | 2004 | 失败。试图请求不存在的资源或使用不存在的Identity。 | +| 2005 | 失败。提交内容包含违禁词。 | | 404 | api端点不存在。 | | | | | | | diff --git a/front/src/api.ts b/front/src/api.ts index e9ad41e..0c9084b 100644 --- a/front/src/api.ts +++ b/front/src/api.ts @@ -89,3 +89,76 @@ export const saveDraft = (content: string): void => { export const getDraft = (): string | null => { return localStorage.getItem('draft'); }; + +export const fetch_id_token = async (): Promise => { + 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 => { + 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 => { + 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; + } +}; diff --git a/front/src/components/CreatePost.tsx b/front/src/components/CreatePost.tsx index b270c2d..63d72ee 100644 --- a/front/src/components/CreatePost.tsx +++ b/front/src/components/CreatePost.tsx @@ -23,8 +23,9 @@ import { Send24Regular, Save24Regular } from '@fluentui/react-icons'; +import { useNavigate } from 'react-router-dom'; import { useLayout } from '../context/LayoutContext'; -import { saveDraft, getDraft } from '../api'; +import { saveDraft, getDraft, createPost } from '../api'; const useStyles = makeStyles({ container: { @@ -118,6 +119,7 @@ const remarkTagPlugin = () => { const CreatePost: React.FC = () => { const styles = useStyles(); + const navigate = useNavigate(); const { isDarkMode, toasterId } = useLayout(); const { dispatchToast } = useToastController(toasterId); const [value, setValue] = useState(""); @@ -135,6 +137,60 @@ const CreatePost: React.FC = () => { const activeElapsedRef = useRef(0); const hasStartedAutoSaveRef = useRef(false); + const handlePostSubmit = async () => { + if (!value || !value.trim()) { + dispatchToast( + + 内容不能为空 + , + { intent: 'error' } + ); + return; + } + + try { + const response = await createPost(value); + if (response.code === 1001 || response.code === 1002) { + // 清除草稿 + saveDraft(''); + setValue(''); + + // 停止自动保存计时器 + if (autoSaveIntervalRef.current !== null) { + window.clearInterval(autoSaveIntervalRef.current); + autoSaveIntervalRef.current = null; + } + activeElapsedRef.current = 0; + hasStartedAutoSaveRef.current = false; + + dispatchToast( + + {response.code === 1002 ? "投稿成功,等待审核" : "投稿成功!"} + , + { intent: 'success' } + ); + + navigate('/'); + } else if (response.code === 2005) { + dispatchToast( + + 投稿中包含违禁词! + , + { intent: 'error' } + ); + } else { + throw new Error(response.data || 'Unknown error'); + } + } catch (error) { + dispatchToast( + + 投稿失败,请稍后再试。 + , + { intent: 'error' } + ); + } + }; + useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( @@ -270,6 +326,7 @@ const CreatePost: React.FC = () => {