作者 202304001

代码优化

1 import { getServerSideConfig } from "@/app/config/server"; 1 import { getServerSideConfig } from "@/app/config/server";
2 import { NextRequest, NextResponse } from "next/server"; 2 import { NextRequest, NextResponse } from "next/server";
3 3
  4 +// 处理每日使用限制逻辑
  5 +function parseDailyUsage(allowNum: string, configMax: number): number {
  6 + if (allowNum === "first") return configMax;
  7 + const parsed = parseInt(allowNum, 10);
  8 + return Number.isNaN(parsed) ? configMax : parsed;
  9 +}
  10 +
4 export async function handle( 11 export async function handle(
5 req: NextRequest, 12 req: NextRequest,
6 { params }: { params: { path: string[] } }, 13 { params }: { params: { path: string[] } },
@@ -14,7 +21,25 @@ export async function handle( @@ -14,7 +21,25 @@ export async function handle(
14 try { 21 try {
15 // 获取 accessCode 22 // 获取 accessCode
16 const body = await new Response(req.body).text(); 23 const body = await new Response(req.body).text();
17 - const uid = JSON.parse(body); 24 + const parsedBody = JSON.parse(body);
  25 +
  26 + // 提取 accessCode 和 max_use 参数
  27 + const uid = parsedBody.accessCode;
  28 + let maxUse = parsedBody.max_use;
  29 + if (!uid) {
  30 + return NextResponse.json({
  31 + data: "请前往设置页面输入登录密码",
  32 + status: 400,
  33 + });
  34 + }
  35 + if (!maxUse) {
  36 + return NextResponse.json({
  37 + data: "参数错误",
  38 + status: 400,
  39 + });
  40 + }
  41 + maxUse = parseDailyUsage(maxUse, config.docmeeMaxDailyUses);
  42 +
18 const headers = new Headers({ 43 const headers = new Headers({
19 "Api-Key": config.docmeeApiKey, 44 "Api-Key": config.docmeeApiKey,
20 "Content-Type": "application/json", 45 "Content-Type": "application/json",
@@ -24,7 +49,7 @@ export async function handle( @@ -24,7 +49,7 @@ export async function handle(
24 const response = await fetch(reqUrl, { 49 const response = await fetch(reqUrl, {
25 headers, 50 headers,
26 method: "POST", 51 method: "POST",
27 - body: JSON.stringify({ uid: uid, limit: config.docmeeMaxDailyUses }), 52 + body: JSON.stringify({ uid: uid, limit: maxUse }),
28 }); 53 });
29 if (!response.ok) { 54 if (!response.ok) {
30 throw new Error( 55 throw new Error(
@@ -62,6 +62,9 @@ export async function handle( @@ -62,6 +62,9 @@ export async function handle(
62 return createErrorResponse("无效请求参数", 400); 62 return createErrorResponse("无效请求参数", 400);
63 } 63 }
64 const localDataObj: LocalData = JSON.parse(localData); 64 const localDataObj: LocalData = JSON.parse(localData);
  65 + if (!localDataObj.maxDailyUses) {
  66 + return createErrorResponse("缺少请求参数", 400);
  67 + }
65 const maxDailyUses = parseDailyUsage( 68 const maxDailyUses = parseDailyUsage(
66 localDataObj.maxDailyUses, 69 localDataObj.maxDailyUses,
67 config.maxDailyUses, 70 config.maxDailyUses,
@@ -95,7 +95,7 @@ const useTaskPoller = () => { @@ -95,7 +95,7 @@ const useTaskPoller = () => {
95 }; 95 };
96 96
97 // 日期处理工具 97 // 日期处理工具
98 -const useDateUtils = () => { 98 +export const useDateUtils = () => {
99 const getFormattedToday = (): string => { 99 const getFormattedToday = (): string => {
100 const today = new Date(); 100 const today = new Date();
101 return today.toISOString().split("T")[0].replace(/-/g, ""); 101 return today.toISOString().split("T")[0].replace(/-/g, "");
@@ -109,9 +109,8 @@ const useDateUtils = () => { @@ -109,9 +109,8 @@ const useDateUtils = () => {
109 }; 109 };
110 110
111 // 本地存储管理 111 // 本地存储管理
112 -const useLocalStorage = () => { 112 +export const useLocalStorage = () => {
113 const { getFormattedToday, isToday } = useDateUtils(); 113 const { getFormattedToday, isToday } = useDateUtils();
114 -  
115 const getLocalData = (accessCode: string): LocalData => { 114 const getLocalData = (accessCode: string): LocalData => {
116 try { 115 try {
117 const data = localStorage.getItem(accessCode); 116 const data = localStorage.getItem(accessCode);
@@ -123,25 +122,45 @@ const useLocalStorage = () => { @@ -123,25 +122,45 @@ const useLocalStorage = () => {
123 return { 122 return {
124 date: parsed.date || getFormattedToday(), 123 date: parsed.date || getFormattedToday(),
125 maxDailyUses: parsed.maxDailyUses || "first", 124 maxDailyUses: parsed.maxDailyUses || "first",
  125 + pptMaxUses: parsed.pptMsxUses || "first",
126 }; 126 };
127 } catch (e) { 127 } catch (e) {
128 return defaultLocalData(); 128 return defaultLocalData();
129 } 129 }
130 }; 130 };
131 131
132 - const updateLocalUsage = (accessCode: string, maxDailyUses: number) => {  
133 - const saveData: LocalData = { 132 + const updateLocalUsage = (
  133 + accessCode: string,
  134 + maxDailyUses?: number,
  135 + pptMaxUses?: number,
  136 + ) => {
  137 + const existingData = getLocalData(accessCode);
  138 + // 检查现有数据的日期是否是今天
  139 + const isNewDay = !isToday(existingData.date);
  140 + // 创建新的数据对象
  141 + const newData: LocalData = {
134 date: getFormattedToday(), 142 date: getFormattedToday(),
135 - maxDailyUses: maxDailyUses.toString(), 143 + maxDailyUses:
  144 + maxDailyUses !== undefined
  145 + ? maxDailyUses.toString()
  146 + : isNewDay
  147 + ? "first"
  148 + : existingData.maxDailyUses,
  149 + pptMaxUses:
  150 + pptMaxUses !== undefined
  151 + ? pptMaxUses.toString()
  152 + : isNewDay
  153 + ? "first"
  154 + : existingData.pptMaxUses,
136 }; 155 };
137 - localStorage.setItem(accessCode, JSON.stringify(saveData)); 156 + localStorage.setItem(accessCode, JSON.stringify(newData));
138 }; 157 };
139 158
140 const defaultLocalData = (): LocalData => ({ 159 const defaultLocalData = (): LocalData => ({
141 date: getFormattedToday(), 160 date: getFormattedToday(),
142 maxDailyUses: "first", 161 maxDailyUses: "first",
  162 + pptMaxUses: "first",
143 }); 163 });
144 -  
145 return { getLocalData, updateLocalUsage }; 164 return { getLocalData, updateLocalUsage };
146 }; 165 };
147 166
@@ -283,18 +302,28 @@ export function BgPanel(props: FileProps) { @@ -283,18 +302,28 @@ export function BgPanel(props: FileProps) {
283 return message.error("请先输入提示词"); 302 return message.error("请先输入提示词");
284 } 303 }
285 setIsLoading(true); 304 setIsLoading(true);
286 - const res = await fetch(`${ApiPath.OpenAiImg}/generations`, {  
287 - method: "POST",  
288 - body: JSON.stringify(prompt),  
289 - });  
290 - if (!res.ok) {  
291 - const errorData = await res.json();  
292 - throw new Error(errorData.message || Locale.BgRemoval.error.reqErr); 305 + try {
  306 + const res = await fetch(`${ApiPath.OpenAiImg}/generations`, {
  307 + method: "POST",
  308 + body: JSON.stringify(prompt),
  309 + });
  310 + if (!res.ok) {
  311 + const errorData = await res.json();
  312 + throw new Error(errorData.message || Locale.BgRemoval.error.reqErr);
  313 + }
  314 + const responseData = await res.json();
  315 + // 获取新图片的Blob
  316 + const newBlob = await urlToBlob(responseData.data.data[0].url);
  317 + // 创建新的对象URL
  318 + const newUrl = URL.createObjectURL(newBlob);
  319 + // 同步更新所有相关状态
  320 + setPreviewUrl(newUrl);
  321 + setFileData(newBlob);
  322 + } catch (error) {
  323 + message.error(Locale.BgRemoval.error.reqErr);
  324 + } finally {
  325 + setIsLoading(false);
293 } 326 }
294 - const responseData = await res.json();  
295 - console.log(responseData.data.data[0]);  
296 - setPreviewUrl(responseData.data.data[0].url);  
297 - setIsLoading(false);  
298 }; 327 };
299 328
300 const handleApiRequest = async (endpoint: string) => { 329 const handleApiRequest = async (endpoint: string) => {
@@ -315,7 +344,7 @@ export function BgPanel(props: FileProps) { @@ -315,7 +344,7 @@ export function BgPanel(props: FileProps) {
315 const formData = new FormData(); 344 const formData = new FormData();
316 const localData = getLocalData(accessStore.accessCode); // 获取本地数据 345 const localData = getLocalData(accessStore.accessCode); // 获取本地数据
317 formData.append("accessCode", accessStore.accessCode); 346 formData.append("accessCode", accessStore.accessCode);
318 - formData.append("localData", JSON.stringify(localData)); // 序列化后添加 347 + formData.append("localData", JSON.stringify(localData));
319 formData.append("image_file", fileData as Blob); 348 formData.append("image_file", fileData as Blob);
320 if (endpoint === "visual/r-background") { 349 if (endpoint === "visual/r-background") {
321 formData.append("prompt", prompt); 350 formData.append("prompt", prompt);
@@ -6,6 +6,7 @@ import { getMindPrompt } from "@/app/utils/prompt"; @@ -6,6 +6,7 @@ import { getMindPrompt } from "@/app/utils/prompt";
6 import { useChatStore } from "@/app/store"; 6 import { useChatStore } from "@/app/store";
7 import { type MindElixirData } from "mind-elixir"; 7 import { type MindElixirData } from "mind-elixir";
8 import { message } from "antd"; 8 import { message } from "antd";
  9 +import Locale from "@/app/locales";
9 10
10 export interface MindPanelProps { 11 export interface MindPanelProps {
11 setData: React.Dispatch<React.SetStateAction<MindElixirData>>; 12 setData: React.Dispatch<React.SetStateAction<MindElixirData>>;
@@ -19,31 +20,21 @@ export function MindPanel(props: MindPanelProps) { @@ -19,31 +20,21 @@ export function MindPanel(props: MindPanelProps) {
19 const [loading, setLoading] = useState(false); 20 const [loading, setLoading] = useState(false);
20 const chatStore = useChatStore(); 21 const chatStore = useChatStore();
21 const submit = async () => { 22 const submit = async () => {
22 - if (!inputValue.trim()) return message.error("请输入提示词!"); 23 + if (!inputValue.trim()) return message.error(Locale.BgRemoval.error.prompt);
23 setIsLoading(true); 24 setIsLoading(true);
24 try { 25 try {
25 const prompt = getMindPrompt(inputValue, false); 26 const prompt = getMindPrompt(inputValue, false);
  27 + console.log("请求------------");
26 const response = await chatStore.directLlmInvoke(prompt, "gpt-4o-mini"); 28 const response = await chatStore.directLlmInvoke(prompt, "gpt-4o-mini");
27 - console.log("原始响应:", response);  
28 - let cleanedContent = response.startsWith("```json")  
29 - ? response.substring(8)  
30 - : response;  
31 - if (cleanedContent.endsWith("```")) {  
32 - cleanedContent = cleanedContent.substring(0, cleanedContent.length - 4);  
33 - }  
34 - const parsedData: MindElixirData = JSON.parse(response);  
35 - console.log("解析后响应:", parsedData);  
36 - // 增强校验逻辑  
37 - if (  
38 - !parsedData?.nodeData?.id ||  
39 - !Array.isArray(parsedData.nodeData.children)  
40 - ) {  
41 - throw new Error("数据结构不完整");  
42 - } 29 + console.log(response);
  30 + const cleanedContent = response.replace(/^```json|```$/g, "");
  31 + console.log(cleanedContent);
  32 + const parsedData: MindElixirData = JSON.parse(cleanedContent);
  33 + console.log("-----" + parsedData);
43 setData(parsedData); 34 setData(parsedData);
44 } catch (error) { 35 } catch (error) {
45 console.log(error); 36 console.log(error);
46 - message.error("请求失败,请重试"); 37 + message.error(Locale.BgRemoval.error.reqErr);
47 } finally { 38 } finally {
48 setIsLoading(false); // 确保关闭加载状态‌:ml-citation{ref="2,5" data="citationList"} 39 setIsLoading(false); // 确保关闭加载状态‌:ml-citation{ref="2,5" data="citationList"}
49 } 40 }
@@ -21,6 +21,20 @@ import SDIcon from "@/app/icons/sd.svg"; @@ -21,6 +21,20 @@ import SDIcon from "@/app/icons/sd.svg";
21 import { useChatStore, useMindMapStore } from "@/app/store"; 21 import { useChatStore, useMindMapStore } from "@/app/store";
22 import { message } from "antd"; 22 import { message } from "antd";
23 23
  24 +// 常量配置抽取
  25 +const INITIAL_DATA: MindElixirData = {
  26 + nodeData: {
  27 + id: "root",
  28 + topic: "中心主题",
  29 + },
  30 +};
  31 +const LOADING_DATA: MindElixirData = {
  32 + nodeData: {
  33 + id: "root",
  34 + topic: "生成中....",
  35 + },
  36 +};
  37 +
24 export function MindPage() { 38 export function MindPage() {
25 const isMobileScreen = useMobileScreen(); 39 const isMobileScreen = useMobileScreen();
26 const navigate = useNavigate(); 40 const navigate = useNavigate();
@@ -35,13 +49,8 @@ export function MindPage() { @@ -35,13 +49,8 @@ export function MindPage() {
35 const chatStore = useChatStore(); 49 const chatStore = useChatStore();
36 const { newMessages, content } = useMindMapStore.getState(); 50 const { newMessages, content } = useMindMapStore.getState();
37 const query = useLocation(); 51 const query = useLocation();
38 - const { msg } = query.state || {};  
39 - const [data, setData] = useState<MindElixirData>({  
40 - nodeData: {  
41 - id: "root",  
42 - topic: "中心主题",  
43 - },  
44 - }); 52 + let { msg } = query.state || {};
  53 + const [data, setData] = useState<MindElixirData>(INITIAL_DATA);
45 54
46 useEffect(() => { 55 useEffect(() => {
47 // 确保容器元素已挂载 56 // 确保容器元素已挂载
@@ -68,15 +77,7 @@ export function MindPage() { @@ -68,15 +77,7 @@ export function MindPage() {
68 newMessages, 77 newMessages,
69 "gpt-4o-mini", 78 "gpt-4o-mini",
70 ); 79 );
71 - let cleanedContent = response.startsWith("```json")  
72 - ? response.substring(8)  
73 - : response;  
74 - if (cleanedContent.endsWith("```")) {  
75 - cleanedContent = cleanedContent.substring(  
76 - 0,  
77 - cleanedContent.length - 4,  
78 - );  
79 - } 80 + const cleanedContent = response.replace(/^```json|```$/g, "");
80 const parsedData: MindElixirData = JSON.parse(cleanedContent); 81 const parsedData: MindElixirData = JSON.parse(cleanedContent);
81 // 增强校验逻辑 82 // 增强校验逻辑
82 if ( 83 if (
@@ -86,6 +87,7 @@ export function MindPage() { @@ -86,6 +87,7 @@ export function MindPage() {
86 throw new Error("数据结构不完整"); 87 throw new Error("数据结构不完整");
87 } 88 }
88 setData(parsedData); 89 setData(parsedData);
  90 + navigate(Path.Mind, { replace: true, state: { msg: null } });
89 } catch (error) { 91 } catch (error) {
90 console.log(error); 92 console.log(error);
91 message.error("请求失败,请重试"); 93 message.error("请求失败,请重试");
@@ -100,9 +102,6 @@ export function MindPage() { @@ -100,9 +102,6 @@ export function MindPage() {
100 return () => { 102 return () => {
101 if (mindInstance.current) { 103 if (mindInstance.current) {
102 mindInstance.current.destroy(); 104 mindInstance.current.destroy();
103 - // 移除事件监听器  
104 - document.removeEventListener("mousemove", () => {});  
105 - document.removeEventListener("mouseup", () => {});  
106 } 105 }
107 }; 106 };
108 }, []); 107 }, []);
@@ -113,76 +112,10 @@ export function MindPage() { @@ -113,76 +112,10 @@ export function MindPage() {
113 112
114 useEffect(() => { 113 useEffect(() => {
115 if (isLoading) { 114 if (isLoading) {
116 - mindInstance.current?.refresh({  
117 - nodeData: {  
118 - id: "root",  
119 - topic: "生成中....",  
120 - },  
121 - });  
122 - } else {  
123 - mindInstance.current?.refresh({  
124 - nodeData: {  
125 - id: "root",  
126 - topic: "中心主题",  
127 - },  
128 - }); 115 + mindInstance.current?.refresh(LOADING_DATA);
129 } 116 }
130 }, [isLoading]); 117 }, [isLoading]);
131 118
132 - // const meNode=document.querySelector('me-nodes')  
133 - // const draggableElement = meNode?.querySelector('me-root') as HTMLElement | null;  
134 - // if (draggableElement) {  
135 - // let isDragging = false; // 是否正在拖拽  
136 - // let startX = 0; // 鼠标按下时的 X 坐标  
137 - // let startY = 0; // 鼠标按下时的 Y 坐标  
138 - // let initialLeft = 0; // 元素初始的左偏移量  
139 - // let initialTop = 0; // 元素初始的上偏移量  
140 - // // 鼠标按下事件  
141 - // draggableElement.addEventListener('mousedown', (e) => {  
142 - // isDragging = true;  
143 - // startX = e.clientX;  
144 - // startY = e.clientY;  
145 - // // 获取 me-root 元素当前的位置  
146 - // const draggableStyle = window.getComputedStyle(draggableElement);  
147 - // initialLeft = parseInt(draggableStyle.left) || 0;  
148 - // initialTop = parseInt(draggableStyle.top) || 0;  
149 - // // 确保元素可以移动  
150 - // draggableElement.style.position = 'absolute';  
151 - // });  
152 - // // 鼠标移动事件  
153 - // document.addEventListener('mousemove', (e) => {  
154 - // if (isDragging) {  
155 - // const currentX = e.clientX;  
156 - // const currentY = e.clientY;  
157 - // // 计算偏移量  
158 - // const diffX = currentX - startX;  
159 - // const diffY = currentY - startY;  
160 - // // 更新 me-root 元素位置  
161 - // draggableElement.style.left = `${initialLeft + diffX}px`;  
162 - // draggableElement.style.top = `${initialTop + diffY}px`;  
163 - // // 检查 meMain 是否存在,如果存在则更新其位置  
164 - // const meMain = meNode?.querySelector('me-main') as HTMLElement | null;  
165 - // if (meMain) {  
166 - // // 获取 meMain 元素当前的位置  
167 - // const meMainStyle = window.getComputedStyle(meMain);  
168 - // const meMainInitialLeft = parseInt(meMainStyle.left) || 0;  
169 - // const meMainInitialTop = parseInt(meMainStyle.top) || 0;  
170 - // // 更新 meMain 元素位置  
171 - // meMain.style.position = 'absolute';  
172 - // meMain.style.left = `${meMainInitialLeft + diffX}px`;  
173 - // meMain.style.top = `${meMainInitialTop + diffY}px`;  
174 - // }  
175 - // }  
176 - // });  
177 -  
178 - // // 鼠标释放事件  
179 - // document.addEventListener('mouseup', () => {  
180 - // isDragging = false;  
181 - // });  
182 - // } else {  
183 - // console.error('未找到 me-root 元素');  
184 - // }  
185 -  
186 return ( 119 return (
187 <> 120 <>
188 <MindSiderBar 121 <MindSiderBar
@@ -12,32 +12,15 @@ import { CreatorType, DocmeeUI } from "@docmee/sdk-ui"; @@ -12,32 +12,15 @@ import { CreatorType, DocmeeUI } from "@docmee/sdk-ui";
12 import { getClientConfig } from "@/app/config/client"; 12 import { getClientConfig } from "@/app/config/client";
13 import { useAppConfig, useAccessStore } from "@/app/store"; 13 import { useAppConfig, useAccessStore } from "@/app/store";
14 import type { generateError, generateOutline } from "@/app/types/docmee"; 14 import type { generateError, generateOutline } from "@/app/types/docmee";
  15 +import type { LocalData } from "@/app/types/zuotang";
  16 +import { useLocalStorage } from "../bgRemoval";
15 import axios from "axios"; 17 import axios from "axios";
  18 +
16 import ReturnIcon from "@/app/icons/return.svg"; 19 import ReturnIcon from "@/app/icons/return.svg";
17 import MinIcon from "@/app/icons/min.svg"; 20 import MinIcon from "@/app/icons/min.svg";
18 import MaxIcon from "@/app/icons/max.svg"; 21 import MaxIcon from "@/app/icons/max.svg";
19 import { message } from "antd"; 22 import { message } from "antd";
20 23
21 -// 错误消息映射  
22 -const errorMap: { [key: number]: string } = {  
23 - [-1]: "操作失败",  
24 - [88]: "功能受限(积分已用完 或 非VIP)",  
25 - [98]: "认证失败(检查token是否过期)",  
26 - [99]: "登录过期",  
27 - [1001]: "数据不存在",  
28 - [1002]: "数据访问异常",  
29 - [1003]: "无权限访问",  
30 - [1006]: "内容涉及敏感信息",  
31 - [1009]: "AI服务异常",  
32 - [1010]: "你的次数已用完",  
33 - [1012]: "请求太频繁,限流",  
34 -};  
35 -  
36 -// 获取错误消息的函数  
37 -const getErrorMessage = (errorCode: number): string => {  
38 - return errorMap[errorCode] || `未知错误(错误码:${errorCode})`;  
39 -};  
40 -  
41 export function PowerPoint() { 24 export function PowerPoint() {
42 const accessStore = useAccessStore(); 25 const accessStore = useAccessStore();
43 const containerRef = useRef<HTMLDivElement>(null); 26 const containerRef = useRef<HTMLDivElement>(null);
@@ -48,20 +31,23 @@ export function PowerPoint() { @@ -48,20 +31,23 @@ export function PowerPoint() {
48 const showMaxIcon = !isMobileScreen && !clientConfig?.isApp; 31 const showMaxIcon = !isMobileScreen && !clientConfig?.isApp;
49 const config = useAppConfig(); 32 const config = useAppConfig();
50 const scrollRef = useRef<HTMLDivElement>(null); 33 const scrollRef = useRef<HTMLDivElement>(null);
  34 + const { updateLocalUsage, getLocalData } = useLocalStorage();
  35 + const query = useLocation(); //获取路由参数
  36 + const { msg, pptMessage } = query.state || {}; //获取路由参数
51 37
52 - const query = useLocation();  
53 - const { msg, pptMessage } = query.state || {};  
54 - 38 + const localData: LocalData = getLocalData(accessStore.accessCode); //获取限制次数
55 const getToken = async () => { 39 const getToken = async () => {
56 if (!accessStore.accessCode) { 40 if (!accessStore.accessCode) {
57 return message.error("请先输入登录秘钥"); 41 return message.error("请先输入登录秘钥");
58 } 42 }
59 const res = await fetch("/api/ppt/createApiToken", { 43 const res = await fetch("/api/ppt/createApiToken", {
60 method: "POST", 44 method: "POST",
61 - body: JSON.stringify(accessStore.accessCode), 45 + body: JSON.stringify({
  46 + accessCode: accessStore.accessCode,
  47 + max_use: localData.pptMaxUses,
  48 + }),
62 }); 49 });
63 const data = await res.json(); 50 const data = await res.json();
64 - console.log(data);  
65 if (data.status == 200) { 51 if (data.status == 200) {
66 return data.data.data.token; 52 return data.data.data.token;
67 } else { 53 } else {
@@ -89,7 +75,7 @@ export function PowerPoint() { @@ -89,7 +75,7 @@ export function PowerPoint() {
89 container: containerRef.current, 75 container: containerRef.current,
90 page: "creator-v2", 76 page: "creator-v2",
91 token: token, 77 token: token,
92 - mode: "light", 78 + mode: config.theme as "dark" | "light",
93 lang: "zh", 79 lang: "zh",
94 isMobile: isMobileScreen, 80 isMobile: isMobileScreen,
95 creatorData: { 81 creatorData: {
@@ -99,19 +85,52 @@ export function PowerPoint() { @@ -99,19 +85,52 @@ export function PowerPoint() {
99 }); 85 });
100 if (msg) { 86 if (msg) {
101 docmee.on("mounted", (msg: generateOutline) => { 87 docmee.on("mounted", (msg: generateOutline) => {
  88 + if (localData.pptMaxUses == "0") {
  89 + message.error("你的免费次数已用完");
  90 + return false;
  91 + }
102 docmee.changeCreatorData({ text: pptMessage }, true); 92 docmee.changeCreatorData({ text: pptMessage }, true);
103 }); 93 });
104 } 94 }
105 docmee.on("beforeGenerate", (msg: generateOutline) => { 95 docmee.on("beforeGenerate", (msg: generateOutline) => {
  96 + //生成大纲事件
  97 + console.log(localData.pptMaxUses);
  98 + if (localData.pptMaxUses == "0") {
  99 + message.error("你的免费次数已用完");
  100 + return false;
  101 + }
106 axios.post("https://docmee.cn/api/ppt/v2/generateContent", msg, { 102 axios.post("https://docmee.cn/api/ppt/v2/generateContent", msg, {
107 headers: { token: token }, 103 headers: { token: token },
108 }); 104 });
109 }); 105 });
110 - docmee.on("error", (msg: generateError) => { 106 +
  107 + docmee.on("charge", (msg: string) => {
  108 + //PPT生成后扣费
  109 + // 解析 pptMaxUses 为数字
  110 + let max_use = parseInt(localData.pptMaxUses, 10);
  111 + // 校验解析结果是否为有效数字
  112 + if (isNaN(max_use)) {
  113 + max_use = 0; // 如果解析失败,设置默认值为 0
  114 + }
  115 + max_use = max_use - 1;
  116 + if (max_use < 0) {
  117 + max_use = 0;
  118 + }
  119 + updateLocalUsage(accessStore.accessCode, undefined, max_use);
  120 + });
  121 +
  122 + docmee.on("error", async (msg: generateError) => {
  123 + //请求错误事件
  124 + console.log(msg);
111 if (msg.data.code == 98) { 125 if (msg.data.code == 98) {
  126 + // message.error('token失效,请重试')
  127 + const token = await getToken();
112 docmee.updateToken(token); 128 docmee.updateToken(token);
  129 + return;
113 } 130 }
114 - message.error(msg.data.message); 131 + message.error(
  132 + msg.data.code == 403 ? "请检查登录密码或网络" : msg.data.message,
  133 + );
115 }); 134 });
116 return () => docmee.destroy(); 135 return () => docmee.destroy();
117 }; 136 };
@@ -685,7 +685,6 @@ export function Settings() { @@ -685,7 +685,6 @@ export function Settings() {
685 type="text" 685 type="text"
686 placeholder={Locale.Settings.Access.AccessCode.Placeholder} 686 placeholder={Locale.Settings.Access.AccessCode.Placeholder}
687 onChange={(e) => { 687 onChange={(e) => {
688 - console.log("更改密码了");  
689 if (localStorage.getItem("token")) { 688 if (localStorage.getItem("token")) {
690 localStorage.removeItem("token"); 689 localStorage.removeItem("token");
691 } //20250328新增更改访问密码删除本地储存token 690 } //20250328新增更改访问密码删除本地储存token
@@ -100,6 +100,7 @@ declare global { @@ -100,6 +100,7 @@ declare global {
100 100
101 DOCMEE_URL: string; 101 DOCMEE_URL: string;
102 DOCMEE_API_KEY: string; 102 DOCMEE_API_KEY: string;
  103 + DOCMEE_MAX_DAILY_USES: number;
103 104
104 NXET_PUBLIC_BGREMOVAL_MODEL: string; 105 NXET_PUBLIC_BGREMOVAL_MODEL: string;
105 NXET_PUBLIC_WRITING_MODEL: string; 106 NXET_PUBLIC_WRITING_MODEL: string;
@@ -866,7 +866,7 @@ const cn = { @@ -866,7 +866,7 @@ const cn = {
866 reqErr: "请求失败", 866 reqErr: "请求失败",
867 selectImg: "请选择图片", 867 selectImg: "请选择图片",
868 code: "请先输入访问密码", 868 code: "请先输入访问密码",
869 - prompt: "请输入背景提示词", 869 + prompt: "请输入提示词",
870 resultErr: "结果图片加载失败", 870 resultErr: "结果图片加载失败",
871 downLoadErr: "请先完成图片处理", 871 downLoadErr: "请先完成图片处理",
872 statuErr: "状态查询失败", 872 statuErr: "状态查询失败",
1 -export type FileProps={  
2 - fileData: Blob | null;  
3 - setFileData: React.Dispatch<React.SetStateAction<Blob | null>>;  
4 - previewUrl: string | null;  
5 - setPreviewUrl: React.Dispatch<React.SetStateAction<string | null>>;  
6 - isLoading:boolean;  
7 - setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;  
8 -} 1 +export type FileProps = {
  2 + fileData: Blob | null;
  3 + setFileData: React.Dispatch<React.SetStateAction<Blob | null>>;
  4 + previewUrl: string | null;
  5 + setPreviewUrl: React.Dispatch<React.SetStateAction<string | null>>;
  6 + isLoading: boolean;
  7 + setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
  8 +};
9 9
10 -export type LocalData={  
11 - date:string  
12 - maxDailyUses:string  
13 -} 10 +export type LocalData = {
  11 + date: string;
  12 + maxDailyUses: string;
  13 + pptMaxUses: string;
  14 +};
14 15
  16 +export type CreateTaskResponse = {
  17 + status: number;
  18 + message: string;
  19 + data: {
  20 + task_id: string;
  21 + };
  22 + maxDailyUses?: number;
  23 +};
15 24
16 -export type CreateTaskResponse={  
17 - status: number;  
18 - message: string;  
19 - data: {  
20 - task_id: string;  
21 - };  
22 - maxDailyUses?:number;  
23 -}  
24 -  
25 -export type GetTaskResponse={  
26 - status: number;  
27 - message: string;  
28 - data: {  
29 - err_info: string; //错误信息  
30 - image: string; //抠图完成后的图片URL  
31 - image_height: number; //抠图完成后的图片高  
32 - image_width: number; //抠图完成后的图片宽  
33 - output_type: number; //返回图片 1为返回图片和蒙版 2为图片 3为蒙版  
34 - result_type: string; //图片前景类型  
35 - return_type: number; //返回图片的类型 1为图片URL 2为base64  
36 - type: string; //图片前景类型  
37 - task_id: string; //任务队列ID  
38 - state:number; //任务状态码。1 为成功,大于 1 为处理中,小于 0 为失败。  
39 - state_detail: string; //结果为Completed表示转换完成  
40 - };  
41 -}  
42 -export type GetGenerateTaskResponse={  
43 - status: number;  
44 - message: string;  
45 - data: {  
46 - /**错误信息 */  
47 - err_info: string;  
48 - /**抠图完成后的图片URL */  
49 - image_1: string;  
50 - /**抠图完成后的图片高 */  
51 - image_height: number;  
52 - /**抠图完成后的图片宽 */  
53 - image_width: number;  
54 - /**返回图片 1为返回图片和蒙版 2为图片 3为蒙版 */  
55 - output_type: number;  
56 - /**图片前景类型 */  
57 - result_type: string;  
58 - /**返回图片的类型 1为图片URL 2为base64 */  
59 - return_type: number;  
60 - /**图片前景类型 */  
61 - type: string;  
62 - /**任务队列ID */  
63 - task_id: string;  
64 - state:number; //任务状态码。1 为成功,大于 1 为处理中,小于 0 为失败。  
65 - /**结果为Completed表示转换完成 */  
66 - state_detail: string;  
67 - };  
68 -}  
  25 +export type GetTaskResponse = {
  26 + status: number;
  27 + message: string;
  28 + data: {
  29 + err_info: string; //错误信息
  30 + image: string; //抠图完成后的图片URL
  31 + image_height: number; //抠图完成后的图片高
  32 + image_width: number; //抠图完成后的图片宽
  33 + output_type: number; //返回图片 1为返回图片和蒙版 2为图片 3为蒙版
  34 + result_type: string; //图片前景类型
  35 + return_type: number; //返回图片的类型 1为图片URL 2为base64
  36 + type: string; //图片前景类型
  37 + task_id: string; //任务队列ID
  38 + state: number; //任务状态码。1 为成功,大于 1 为处理中,小于 0 为失败。
  39 + state_detail: string; //结果为Completed表示转换完成
  40 + };
  41 +};
  42 +export type GetGenerateTaskResponse = {
  43 + status: number;
  44 + message: string;
  45 + data: {
  46 + /**错误信息 */
  47 + err_info: string;
  48 + /**抠图完成后的图片URL */
  49 + image_1: string;
  50 + /**抠图完成后的图片高 */
  51 + image_height: number;
  52 + /**抠图完成后的图片宽 */
  53 + image_width: number;
  54 + /**返回图片 1为返回图片和蒙版 2为图片 3为蒙版 */
  55 + output_type: number;
  56 + /**图片前景类型 */
  57 + result_type: string;
  58 + /**返回图片的类型 1为图片URL 2为base64 */
  59 + return_type: number;
  60 + /**图片前景类型 */
  61 + type: string;
  62 + /**任务队列ID */
  63 + task_id: string;
  64 + state: number; //任务状态码。1 为成功,大于 1 为处理中,小于 0 为失败。
  65 + /**结果为Completed表示转换完成 */
  66 + state_detail: string;
  67 + };
  68 +};