Spaces:
Paused
Paused
muxi feng commited on
Commit ·
3444669
1
Parent(s): 9c10adf
增加账号管理和收费系统
Browse files- app/api/auth.ts +5 -3
- app/api/common.ts +11 -0
- app/api/lemur/route.ts +148 -30
- app/api/newbing/route.ts +6 -4
- app/api/user/findpwd/route.ts +22 -0
- app/api/user/info/route.ts +30 -0
- app/api/user/kami/route.ts +31 -0
- app/api/user/login/route.ts +19 -0
- app/api/user/mail/route.ts +19 -0
- app/api/user/register/route.ts +22 -0
- app/api/user/set/route.ts +33 -0
- app/api/user/sig/route.ts +30 -0
- app/api/wanjuan/route.ts +10 -1
- app/components/findpwd.module.scss +74 -0
- app/components/findpwd.tsx +64 -0
- app/components/home.tsx +20 -0
- app/components/login.module.scss +74 -0
- app/components/login.tsx +77 -0
- app/components/register.module.scss +103 -0
- app/components/register.tsx +152 -0
- app/components/settings.tsx +6 -4
- app/components/sidebar.tsx +2 -2
- app/components/ui-lib.tsx +1 -1
- app/components/user.module.scss +84 -0
- app/components/user.tsx +180 -0
- app/config/server.ts +2 -2
- app/constant.ts +5 -0
- app/locales/cn.ts +16 -1
- app/locales/de.ts +11 -0
- app/locales/en.ts +11 -0
- app/locales/es.ts +11 -0
- app/locales/it.ts +11 -0
- app/locales/jp.ts +11 -0
- app/locales/tr.ts +11 -0
- app/locales/tw.ts +11 -0
- app/requests.ts +42 -6
- app/store/access.ts +11 -5
- app/store/index.ts +1 -0
- app/store/user.ts +227 -0
app/api/auth.ts
CHANGED
|
@@ -28,6 +28,7 @@ function parseApiKey(bearToken: string) {
|
|
| 28 |
|
| 29 |
export function auth(req: NextRequest) {
|
| 30 |
const authToken = req.headers.get("Authorization") ?? "";
|
|
|
|
| 31 |
|
| 32 |
// check if it is openai api key or user token
|
| 33 |
const { accessCode, apiKey: token } = parseApiKey(authToken);
|
|
@@ -37,14 +38,15 @@ export function auth(req: NextRequest) {
|
|
| 37 |
console.log("[Auth] allowed hashed codes: ", [...serverConfig.codes]);
|
| 38 |
console.log("[Auth] got access code:", accessCode);
|
| 39 |
console.log("[Auth] hashed access code:", hashedCode);
|
|
|
|
| 40 |
console.log("[User IP] ", getIP(req));
|
| 41 |
console.log("[Time] ", new Date().toLocaleString());
|
| 42 |
-
|
| 43 |
-
if (
|
| 44 |
return {
|
| 45 |
error: true,
|
| 46 |
needAccessCode: true,
|
| 47 |
-
msg: "Please go
|
| 48 |
};
|
| 49 |
}
|
| 50 |
|
|
|
|
| 28 |
|
| 29 |
export function auth(req: NextRequest) {
|
| 30 |
const authToken = req.headers.get("Authorization") ?? "";
|
| 31 |
+
const auth = req.headers.get("auth") ?? "";
|
| 32 |
|
| 33 |
// check if it is openai api key or user token
|
| 34 |
const { accessCode, apiKey: token } = parseApiKey(authToken);
|
|
|
|
| 38 |
console.log("[Auth] allowed hashed codes: ", [...serverConfig.codes]);
|
| 39 |
console.log("[Auth] got access code:", accessCode);
|
| 40 |
console.log("[Auth] hashed access code:", hashedCode);
|
| 41 |
+
console.log("[Auth] get auth:",auth);
|
| 42 |
console.log("[User IP] ", getIP(req));
|
| 43 |
console.log("[Time] ", new Date().toLocaleString());
|
| 44 |
+
// serverConfig.needCode && !serverConfig.codes.has(hashedCode) &&
|
| 45 |
+
if (!token && !auth) {
|
| 46 |
return {
|
| 47 |
error: true,
|
| 48 |
needAccessCode: true,
|
| 49 |
+
msg: "Please go login page to login.",
|
| 50 |
};
|
| 51 |
}
|
| 52 |
|
app/api/common.ts
CHANGED
|
@@ -42,3 +42,14 @@ export async function requestOpenai(req: NextRequest) {
|
|
| 42 |
body: req.body,
|
| 43 |
});
|
| 44 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
body: req.body,
|
| 43 |
});
|
| 44 |
}
|
| 45 |
+
|
| 46 |
+
export async function requestLemur(req: NextRequest) {
|
| 47 |
+
return fetch('http://lemurchat.anfans.cn/api/chat/conversation-trial', {
|
| 48 |
+
headers: {
|
| 49 |
+
"Content-Type": "application/json"
|
| 50 |
+
},
|
| 51 |
+
cache: "no-store",
|
| 52 |
+
method: req.method,
|
| 53 |
+
body: req.body,
|
| 54 |
+
});
|
| 55 |
+
}
|
app/api/lemur/route.ts
CHANGED
|
@@ -1,26 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import { createParser } from "eventsource-parser";
|
| 2 |
import { NextRequest, NextResponse } from "next/server";
|
| 3 |
import { auth } from "../auth";
|
|
|
|
| 4 |
|
| 5 |
-
async function createStream(
|
| 6 |
-
const authResult = auth(req);
|
| 7 |
-
if (authResult.error) {
|
| 8 |
-
return authResult.msg;
|
| 9 |
-
}
|
| 10 |
const encoder = new TextEncoder();
|
| 11 |
const decoder = new TextDecoder();
|
| 12 |
|
| 13 |
-
const res = await fetch(
|
| 14 |
-
"http://lemurchat.anfans.cn/api/chat/conversation-trial",
|
| 15 |
-
{
|
| 16 |
-
headers: {
|
| 17 |
-
"Content-Type": "application/json",
|
| 18 |
-
},
|
| 19 |
-
method: "POST",
|
| 20 |
-
body: req.body,
|
| 21 |
-
},
|
| 22 |
-
);
|
| 23 |
-
|
| 24 |
const stream = new ReadableStream({
|
| 25 |
async start(controller) {
|
| 26 |
function onParse(event: any) {
|
|
@@ -36,40 +106,88 @@ async function createStream(req: NextRequest) {
|
|
| 36 |
// https://beta.openai.com/docs/api-reference/completions/create#completions/create-stream
|
| 37 |
try {
|
| 38 |
const json = JSON.parse(data);
|
| 39 |
-
// console.log(
|
| 40 |
if (data.indexOf("content") == -1) {
|
| 41 |
controller.close();
|
| 42 |
return;
|
| 43 |
}
|
| 44 |
-
|
| 45 |
-
const text = JSON.parse(json.data.slice(5)).choices[0].delta
|
| 46 |
-
.content;
|
| 47 |
const queue = encoder.encode(text);
|
| 48 |
controller.enqueue(queue);
|
| 49 |
} catch (e) {
|
| 50 |
-
controller.error(
|
| 51 |
}
|
| 52 |
}
|
| 53 |
}
|
| 54 |
|
| 55 |
const parser = createParser(onParse);
|
| 56 |
for await (const chunk of res.body as any) {
|
| 57 |
-
parser.feed(decoder.decode(chunk));
|
| 58 |
}
|
| 59 |
},
|
| 60 |
});
|
| 61 |
return stream;
|
| 62 |
}
|
| 63 |
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
try {
|
| 66 |
-
const
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
}
|
| 71 |
}
|
| 72 |
|
| 73 |
-
export const
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
| 1 |
+
// import { createParser } from "eventsource-parser";
|
| 2 |
+
// import { NextRequest, NextResponse } from "next/server";
|
| 3 |
+
// import { auth } from "../auth";
|
| 4 |
+
|
| 5 |
+
// async function createStream(req: NextRequest) {
|
| 6 |
+
// const authResult = auth(req);
|
| 7 |
+
// if (authResult.error) {
|
| 8 |
+
// return authResult.msg;
|
| 9 |
+
// }
|
| 10 |
+
// const encoder = new TextEncoder();
|
| 11 |
+
// const decoder = new TextDecoder();
|
| 12 |
+
|
| 13 |
+
// const res = await fetch(
|
| 14 |
+
// "http://lemurchat.anfans.cn/api/chat/conversation-trial",
|
| 15 |
+
// {
|
| 16 |
+
// headers: {
|
| 17 |
+
// "Content-Type": "application/json",
|
| 18 |
+
// },
|
| 19 |
+
// method: "POST",
|
| 20 |
+
// body: req.body,
|
| 21 |
+
// },
|
| 22 |
+
// );
|
| 23 |
+
|
| 24 |
+
// const stream = new ReadableStream({
|
| 25 |
+
// async start(controller) {
|
| 26 |
+
// function onParse(event: any) {
|
| 27 |
+
// if (event.type === "event") {
|
| 28 |
+
// const data = event.data;
|
| 29 |
+
// if (event.id == "1") {
|
| 30 |
+
// let text1 = data.slice(data.indexOf("content"));
|
| 31 |
+
// const text = text1.slice(12, text1.indexOf("index") - 6);
|
| 32 |
+
// const queue = encoder.encode(text);
|
| 33 |
+
// controller.enqueue(queue);
|
| 34 |
+
// return;
|
| 35 |
+
// }
|
| 36 |
+
// // https://beta.openai.com/docs/api-reference/completions/create#completions/create-stream
|
| 37 |
+
// try {
|
| 38 |
+
// const json = JSON.parse(data);
|
| 39 |
+
// // console.log(data.indexOf("content"))
|
| 40 |
+
// if (data.indexOf("content") == -1) {
|
| 41 |
+
// controller.close();
|
| 42 |
+
// return;
|
| 43 |
+
// }
|
| 44 |
+
// // console.log(event.data)
|
| 45 |
+
// const text = JSON.parse(json.data.slice(5)).choices[0].delta
|
| 46 |
+
// .content;
|
| 47 |
+
// const queue = encoder.encode(text);
|
| 48 |
+
// controller.enqueue(queue);
|
| 49 |
+
// } catch (e) {
|
| 50 |
+
// controller.error(e);
|
| 51 |
+
// }
|
| 52 |
+
// }
|
| 53 |
+
// }
|
| 54 |
+
|
| 55 |
+
// const parser = createParser(onParse);
|
| 56 |
+
// for await (const chunk of res.body as any) {
|
| 57 |
+
// parser.feed(decoder.decode(chunk));
|
| 58 |
+
// }
|
| 59 |
+
// },
|
| 60 |
+
// });
|
| 61 |
+
// return stream;
|
| 62 |
+
// }
|
| 63 |
+
|
| 64 |
+
// export async function POST(req: NextRequest) {
|
| 65 |
+
// try {
|
| 66 |
+
// const authResult = auth(req);
|
| 67 |
+
// if (authResult.error) {
|
| 68 |
+
// return NextResponse.json(authResult, {
|
| 69 |
+
// status: 401,
|
| 70 |
+
// });
|
| 71 |
+
// }
|
| 72 |
+
// const stream = await createStream(req);
|
| 73 |
+
// return new Response(stream);
|
| 74 |
+
// } catch (error) {
|
| 75 |
+
// console.error("[Chat Stream]", error);
|
| 76 |
+
// }
|
| 77 |
+
// }
|
| 78 |
+
|
| 79 |
+
// export const config = {
|
| 80 |
+
// runtime: "edge",
|
| 81 |
+
// };
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
|
| 85 |
import { createParser } from "eventsource-parser";
|
| 86 |
import { NextRequest, NextResponse } from "next/server";
|
| 87 |
import { auth } from "../auth";
|
| 88 |
+
import { requestLemur} from "../common";
|
| 89 |
|
| 90 |
+
async function createStream(res: Response) {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
const encoder = new TextEncoder();
|
| 92 |
const decoder = new TextDecoder();
|
| 93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
const stream = new ReadableStream({
|
| 95 |
async start(controller) {
|
| 96 |
function onParse(event: any) {
|
|
|
|
| 106 |
// https://beta.openai.com/docs/api-reference/completions/create#completions/create-stream
|
| 107 |
try {
|
| 108 |
const json = JSON.parse(data);
|
| 109 |
+
// console.log(json)
|
| 110 |
if (data.indexOf("content") == -1) {
|
| 111 |
controller.close();
|
| 112 |
return;
|
| 113 |
}
|
| 114 |
+
const text = JSON.parse(json.data.slice(6)).choices[0].delta.content;
|
|
|
|
|
|
|
| 115 |
const queue = encoder.encode(text);
|
| 116 |
controller.enqueue(queue);
|
| 117 |
} catch (e) {
|
| 118 |
+
controller.error(JSON.parse(data));
|
| 119 |
}
|
| 120 |
}
|
| 121 |
}
|
| 122 |
|
| 123 |
const parser = createParser(onParse);
|
| 124 |
for await (const chunk of res.body as any) {
|
| 125 |
+
parser.feed(decoder.decode(chunk, { stream: true }));
|
| 126 |
}
|
| 127 |
},
|
| 128 |
});
|
| 129 |
return stream;
|
| 130 |
}
|
| 131 |
|
| 132 |
+
function formatResponse(msg: any) {
|
| 133 |
+
const jsonMsg = ["```json\n", JSON.stringify(msg, null, " "), "\n```"].join(
|
| 134 |
+
"",
|
| 135 |
+
);
|
| 136 |
+
return new Response(jsonMsg);
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
async function handle(
|
| 140 |
+
req: NextRequest,
|
| 141 |
+
{ params }: { params: { path: string[] } },
|
| 142 |
+
) {
|
| 143 |
+
console.log("[Lemur Route] params ", params);
|
| 144 |
+
|
| 145 |
+
const authResult = auth(req);
|
| 146 |
+
if (authResult.error) {
|
| 147 |
+
return NextResponse.json(authResult, {
|
| 148 |
+
status: 401,
|
| 149 |
+
});
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
try {
|
| 153 |
+
const api = await requestLemur(req);
|
| 154 |
+
|
| 155 |
+
const contentType = api.headers.get("Content-Type") ?? "";
|
| 156 |
+
|
| 157 |
+
// streaming response
|
| 158 |
+
if (contentType.includes("stream")) {
|
| 159 |
+
const stream = await createStream(api);
|
| 160 |
+
const res = new Response(stream);
|
| 161 |
+
res.headers.set("Content-Type", contentType);
|
| 162 |
+
return res;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
// try to parse error msg
|
| 166 |
+
try {
|
| 167 |
+
const mayBeErrorBody = await api.json();
|
| 168 |
+
if (mayBeErrorBody.error) {
|
| 169 |
+
console.error("[Lemur Response] ", mayBeErrorBody);
|
| 170 |
+
return formatResponse(mayBeErrorBody);
|
| 171 |
+
} else {
|
| 172 |
+
const res = new Response(JSON.stringify(mayBeErrorBody));
|
| 173 |
+
res.headers.set("Content-Type", "application/json");
|
| 174 |
+
res.headers.set("Cache-Control", "no-cache");
|
| 175 |
+
return res;
|
| 176 |
+
}
|
| 177 |
+
} catch (e) {
|
| 178 |
+
console.error("[Lemur Parse] ", e);
|
| 179 |
+
return formatResponse({
|
| 180 |
+
msg: "invalid response from Lemur server",
|
| 181 |
+
error: e,
|
| 182 |
+
});
|
| 183 |
+
}
|
| 184 |
+
} catch (e) {
|
| 185 |
+
console.error("[Lemur] ", e);
|
| 186 |
+
return formatResponse(e);
|
| 187 |
}
|
| 188 |
}
|
| 189 |
|
| 190 |
+
export const GET = handle;
|
| 191 |
+
export const POST = handle;
|
| 192 |
+
|
| 193 |
+
export const runtime = "edge";
|
app/api/newbing/route.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
| 1 |
-
import { NextRequest } from "next/server";
|
| 2 |
import { BingChat, ChatMessage } from "../../bing-chat/index";
|
| 3 |
import { auth } from "../auth";
|
| 4 |
|
| 5 |
export async function POST(req: NextRequest) {
|
| 6 |
const authResult = auth(req);
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
| 10 |
try {
|
| 11 |
let cookies = process.env.COOKIES;
|
| 12 |
const api = new BingChat({
|
|
|
|
| 1 |
+
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
import { BingChat, ChatMessage } from "../../bing-chat/index";
|
| 3 |
import { auth } from "../auth";
|
| 4 |
|
| 5 |
export async function POST(req: NextRequest) {
|
| 6 |
const authResult = auth(req);
|
| 7 |
+
if (authResult.error) {
|
| 8 |
+
return NextResponse.json(authResult, {
|
| 9 |
+
status: 401,
|
| 10 |
+
});
|
| 11 |
+
}
|
| 12 |
try {
|
| 13 |
let cookies = process.env.COOKIES;
|
| 14 |
const api = new BingChat({
|
app/api/user/findpwd/route.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { NextRequest } from "next/server";
|
| 2 |
+
|
| 3 |
+
export async function GET(req: NextRequest) {
|
| 4 |
+
try {
|
| 5 |
+
const token=req.headers.get("auth") ?? ""
|
| 6 |
+
const admin=process.env.ADMIN
|
| 7 |
+
const key=process.env.KEY
|
| 8 |
+
const user=req.nextUrl.searchParams.get("user")
|
| 9 |
+
let res=await fetch("https://dujiaoka.dwzynj.top/main/api/user/find_password.php?admin="+admin+"&key="+key+"&user="+user, {
|
| 10 |
+
method: "GET",
|
| 11 |
+
headers:{
|
| 12 |
+
"token":token
|
| 13 |
+
},
|
| 14 |
+
})
|
| 15 |
+
let msg=await res.json()
|
| 16 |
+
// console.log(msg)
|
| 17 |
+
return new Response(JSON.stringify(msg))
|
| 18 |
+
} catch (e) {
|
| 19 |
+
console.error("[shuixian] ", e);
|
| 20 |
+
return new Response(JSON.stringify(e));
|
| 21 |
+
}
|
| 22 |
+
}
|
app/api/user/info/route.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
+
import { auth } from "../../auth";
|
| 3 |
+
|
| 4 |
+
export async function GET(req: NextRequest) {
|
| 5 |
+
try {
|
| 6 |
+
const authResult = auth(req);
|
| 7 |
+
if (authResult.error) {
|
| 8 |
+
return NextResponse.json(authResult, {
|
| 9 |
+
status: 401,
|
| 10 |
+
});
|
| 11 |
+
}
|
| 12 |
+
const token=req.headers.get("auth") ?? ""
|
| 13 |
+
const admin=process.env.ADMIN
|
| 14 |
+
const key=process.env.KEY
|
| 15 |
+
const user=req.nextUrl.searchParams.get("user")
|
| 16 |
+
const password=req.nextUrl.searchParams.get("password")
|
| 17 |
+
let res=await fetch("https://dujiaoka.dwzynj.top/main/api/user/user_data.php?admin="+admin+"&key="+key+"&user="+user+"&password="+password, {
|
| 18 |
+
method: "GET",
|
| 19 |
+
headers:{
|
| 20 |
+
"token":token
|
| 21 |
+
}
|
| 22 |
+
})
|
| 23 |
+
let msg=await res.json()
|
| 24 |
+
// console.log(msg)
|
| 25 |
+
return new Response(JSON.stringify(msg))
|
| 26 |
+
} catch (e) {
|
| 27 |
+
console.error("[shuixian] ", e);
|
| 28 |
+
return new Response(JSON.stringify(e));
|
| 29 |
+
}
|
| 30 |
+
}
|
app/api/user/kami/route.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
+
import { auth } from "../../auth";
|
| 3 |
+
|
| 4 |
+
export async function GET(req: NextRequest) {
|
| 5 |
+
try {
|
| 6 |
+
const authResult = auth(req);
|
| 7 |
+
if (authResult.error) {
|
| 8 |
+
return NextResponse.json(authResult, {
|
| 9 |
+
status: 401,
|
| 10 |
+
});
|
| 11 |
+
}
|
| 12 |
+
const token=req.headers.get("auth") ?? ""
|
| 13 |
+
const admin=process.env.ADMIN
|
| 14 |
+
const key=process.env.KEY
|
| 15 |
+
const user=req.nextUrl.searchParams.get("user")
|
| 16 |
+
const password=req.nextUrl.searchParams.get("password")
|
| 17 |
+
const code=req.nextUrl.searchParams.get("code")
|
| 18 |
+
let res=await fetch("https://dujiaoka.dwzynj.top/main/api/kami/use.php?admin="+admin+"&key="+key+"&user="+user+"&password="+password+"&code="+code, {
|
| 19 |
+
method: "GET",
|
| 20 |
+
headers:{
|
| 21 |
+
"token":token
|
| 22 |
+
},
|
| 23 |
+
})
|
| 24 |
+
let msg=await res.json()
|
| 25 |
+
console.log(msg)
|
| 26 |
+
return new Response(JSON.stringify(msg))
|
| 27 |
+
} catch (e) {
|
| 28 |
+
console.error("[shuixian] ", e);
|
| 29 |
+
return new Response(JSON.stringify(e));
|
| 30 |
+
}
|
| 31 |
+
}
|
app/api/user/login/route.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { NextRequest } from "next/server";
|
| 2 |
+
|
| 3 |
+
export async function GET(req: NextRequest) {
|
| 4 |
+
try {
|
| 5 |
+
const admin=process.env.ADMIN
|
| 6 |
+
const key=process.env.KEY
|
| 7 |
+
const user=req.nextUrl.searchParams.get("user")
|
| 8 |
+
const password=req.nextUrl.searchParams.get("password")
|
| 9 |
+
let res=await fetch("https://dujiaoka.dwzynj.top/main/api/user/login.php?admin="+admin+"&key="+key+"&user="+user+"&password="+password, {
|
| 10 |
+
method: "GET"
|
| 11 |
+
})
|
| 12 |
+
let msg=await res.json()
|
| 13 |
+
// console.log(msg)
|
| 14 |
+
return new Response(JSON.stringify(msg))
|
| 15 |
+
} catch (e) {
|
| 16 |
+
console.error("[shuixian] ", e);
|
| 17 |
+
return new Response(JSON.stringify(e));
|
| 18 |
+
}
|
| 19 |
+
}
|
app/api/user/mail/route.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { NextRequest } from "next/server";
|
| 2 |
+
|
| 3 |
+
export async function GET(req: NextRequest) {
|
| 4 |
+
try {
|
| 5 |
+
const admin=process.env.ADMIN
|
| 6 |
+
const key=process.env.KEY
|
| 7 |
+
const user=req.nextUrl.searchParams.get("user")
|
| 8 |
+
const mail=req.nextUrl.searchParams.get("mail")
|
| 9 |
+
let res=await fetch("https://dujiaoka.dwzynj.top/main/api/user/code.php?admin="+admin+"&key="+key+"&user="+user+"&mail="+mail, {
|
| 10 |
+
method: "GET"
|
| 11 |
+
})
|
| 12 |
+
let msg=await res.json()
|
| 13 |
+
// console.log(msg)
|
| 14 |
+
return new Response(JSON.stringify(msg))
|
| 15 |
+
} catch (e) {
|
| 16 |
+
console.error("[shuixian] ", e);
|
| 17 |
+
return new Response(JSON.stringify(e));
|
| 18 |
+
}
|
| 19 |
+
}
|
app/api/user/register/route.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { NextRequest } from "next/server";
|
| 2 |
+
|
| 3 |
+
export async function GET(req: NextRequest) {
|
| 4 |
+
try {
|
| 5 |
+
const admin=process.env.ADMIN
|
| 6 |
+
const key=process.env.KEY
|
| 7 |
+
const user=req.nextUrl.searchParams.get("user")
|
| 8 |
+
const password=req.nextUrl.searchParams.get("password")
|
| 9 |
+
const name=req.nextUrl.searchParams.get("name")
|
| 10 |
+
const mail=req.nextUrl.searchParams.get("mail")
|
| 11 |
+
const code=req.nextUrl.searchParams.get("code")
|
| 12 |
+
let res=await fetch("https://dujiaoka.dwzynj.top/main/api/user/register.php?admin="+admin+"&key="+key+"&user="+user+"&password="+password+"&name="+name+"&mail="+mail+"&code="+code, {
|
| 13 |
+
method: "GET"
|
| 14 |
+
})
|
| 15 |
+
let msg=await res.json()
|
| 16 |
+
// console.log(msg)
|
| 17 |
+
return new Response(JSON.stringify(msg))
|
| 18 |
+
} catch (e) {
|
| 19 |
+
console.error("[shuixian] ", e);
|
| 20 |
+
return new Response(JSON.stringify(e));
|
| 21 |
+
}
|
| 22 |
+
}
|
app/api/user/set/route.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
+
import { auth } from "../../auth";
|
| 3 |
+
|
| 4 |
+
export async function GET(req: NextRequest) {
|
| 5 |
+
try {
|
| 6 |
+
const authResult = auth(req);
|
| 7 |
+
if (authResult.error) {
|
| 8 |
+
return NextResponse.json(authResult, {
|
| 9 |
+
status: 401,
|
| 10 |
+
});
|
| 11 |
+
}
|
| 12 |
+
const token=req.headers.get("auth") ?? ""
|
| 13 |
+
const admin=process.env.ADMIN
|
| 14 |
+
const key=process.env.KEY
|
| 15 |
+
const user=req.nextUrl.searchParams.get("user")
|
| 16 |
+
const project=req.nextUrl.searchParams.get("project")
|
| 17 |
+
const projectName=req.nextUrl.searchParams.get("projectName")
|
| 18 |
+
const data=req.nextUrl.searchParams.get("data")
|
| 19 |
+
let res=await fetch("https://dujiaoka.dwzynj.top/main/api/user/user_set.php?admin="+admin+"&key="+key+"&user="+user+"&project="+project+"&"+projectName+"="+data, {
|
| 20 |
+
method: "GET",
|
| 21 |
+
headers:{
|
| 22 |
+
"token":token
|
| 23 |
+
},
|
| 24 |
+
})
|
| 25 |
+
|
| 26 |
+
let msg=await res.json()
|
| 27 |
+
// console.log(msg)
|
| 28 |
+
return new Response(JSON.stringify(msg))
|
| 29 |
+
} catch (e) {
|
| 30 |
+
console.error("[shuixian] ", e);
|
| 31 |
+
return new Response(JSON.stringify(e));
|
| 32 |
+
}
|
| 33 |
+
}
|
app/api/user/sig/route.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
+
import { auth } from "../../auth";
|
| 3 |
+
|
| 4 |
+
export async function GET(req: NextRequest) {
|
| 5 |
+
try {
|
| 6 |
+
const authResult = auth(req);
|
| 7 |
+
if (authResult.error) {
|
| 8 |
+
return NextResponse.json(authResult, {
|
| 9 |
+
status: 401,
|
| 10 |
+
});
|
| 11 |
+
}
|
| 12 |
+
const token=req.headers.get("auth") ?? ""
|
| 13 |
+
const admin=process.env.ADMIN
|
| 14 |
+
const key=process.env.KEY
|
| 15 |
+
const user=req.nextUrl.searchParams.get("user")
|
| 16 |
+
const password=req.nextUrl.searchParams.get("password")
|
| 17 |
+
let res=await fetch("https://dujiaoka.dwzynj.top/main/api/user/user_sig.php?admin="+admin+"&key="+key+"&user="+user+"&password="+password, {
|
| 18 |
+
method: "GET",
|
| 19 |
+
headers:{
|
| 20 |
+
"token":token
|
| 21 |
+
}
|
| 22 |
+
})
|
| 23 |
+
let msg=await res.json()
|
| 24 |
+
console.log(msg)
|
| 25 |
+
return new Response(JSON.stringify(msg))
|
| 26 |
+
} catch (e) {
|
| 27 |
+
console.error("[shuixian] ", e);
|
| 28 |
+
return new Response(JSON.stringify(e));
|
| 29 |
+
}
|
| 30 |
+
}
|
app/api/wanjuan/route.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
| 1 |
-
|
|
|
|
|
|
|
|
|
|
| 2 |
try {
|
| 3 |
let token = process.env.WANJUAN_TOKEN;
|
| 4 |
let body = { message: await req.json() };
|
| 5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
console.log(JSON.stringify(body));
|
| 7 |
let res = "";
|
| 8 |
await fetch("http://47.94.237.159:8080/v1/wanjuan", {
|
|
|
|
| 1 |
+
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
+
import { auth } from "../auth";
|
| 3 |
+
|
| 4 |
+
export async function POST(req: NextRequest) {
|
| 5 |
try {
|
| 6 |
let token = process.env.WANJUAN_TOKEN;
|
| 7 |
let body = { message: await req.json() };
|
| 8 |
|
| 9 |
+
const authResult = auth(req);
|
| 10 |
+
if (authResult.error) {
|
| 11 |
+
return NextResponse.json(authResult, {
|
| 12 |
+
status: 401,
|
| 13 |
+
});
|
| 14 |
+
}
|
| 15 |
console.log(JSON.stringify(body));
|
| 16 |
let res = "";
|
| 17 |
await fetch("http://47.94.237.159:8080/v1/wanjuan", {
|
app/components/findpwd.module.scss
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.name{
|
| 2 |
+
border: var(--border-in-light);
|
| 3 |
+
padding: 10px;
|
| 4 |
+
border-radius: 10px;
|
| 5 |
+
-webkit-appearance: none;
|
| 6 |
+
-moz-appearance: none;
|
| 7 |
+
appearance: none;
|
| 8 |
+
cursor: pointer;
|
| 9 |
+
background-color: var(--white);
|
| 10 |
+
color: var(--black);
|
| 11 |
+
text-align: left;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
.user {
|
| 15 |
+
padding: 20px;
|
| 16 |
+
overflow: auto;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.font{
|
| 20 |
+
font-size: 15px;
|
| 21 |
+
padding-right: 5px;
|
| 22 |
+
text-align: center;
|
| 23 |
+
.wallet{
|
| 24 |
+
color: #2279ca;
|
| 25 |
+
};
|
| 26 |
+
.vipTime{
|
| 27 |
+
font-size: 8px;
|
| 28 |
+
padding-top: 5px;
|
| 29 |
+
};
|
| 30 |
+
.vipState{
|
| 31 |
+
color: #dc423c;
|
| 32 |
+
}
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
.sigState{
|
| 36 |
+
color: #2279ca;
|
| 37 |
+
padding-right: 10px;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
.sigButton{
|
| 41 |
+
border: var(--border-in-light);
|
| 42 |
+
padding: 10px;
|
| 43 |
+
border-radius: 10px;
|
| 44 |
+
cursor: pointer;
|
| 45 |
+
&:hover{
|
| 46 |
+
border-color: #2279ca;
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
.login{
|
| 51 |
+
text-align: center;
|
| 52 |
+
div{
|
| 53 |
+
padding: 10px;
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
.wangji{
|
| 58 |
+
padding-right: 60px;
|
| 59 |
+
font-size: 12px;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
.zhuce{
|
| 63 |
+
padding-left: 60px;
|
| 64 |
+
font-size: 12px;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
.loginButton{
|
| 68 |
+
background-color: #1db144;
|
| 69 |
+
color: white;
|
| 70 |
+
padding: 0;
|
| 71 |
+
width: 183px;
|
| 72 |
+
display: block;
|
| 73 |
+
margin: 0 auto;
|
| 74 |
+
}
|
app/components/findpwd.tsx
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { ErrorBoundary } from "./error";
|
| 2 |
+
import Locale, { AllLangs, changeLang, getLang } from "../locales";
|
| 3 |
+
import ChatIcon from "../icons/chatgpt.svg"
|
| 4 |
+
import styles from "./findpwd.module.scss";
|
| 5 |
+
import { IconButton } from "./button";
|
| 6 |
+
import { useUserStore } from "../store";
|
| 7 |
+
import { useState } from "react";
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
export function findpwd(){
|
| 11 |
+
const userStore=useUserStore()
|
| 12 |
+
const [user, setUser] = useState("");
|
| 13 |
+
|
| 14 |
+
const onUser = (text: string) => {
|
| 15 |
+
setUser(text)
|
| 16 |
+
};
|
| 17 |
+
|
| 18 |
+
const findpwd=()=>{
|
| 19 |
+
userStore.findpwd(user)
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
return (
|
| 23 |
+
<ErrorBoundary>
|
| 24 |
+
<div className="window-header">
|
| 25 |
+
<div className="window-header-title">
|
| 26 |
+
<div className="window-header-main-title">
|
| 27 |
+
{Locale.User.Login}
|
| 28 |
+
</div>
|
| 29 |
+
<div className="window-header-sub-title">
|
| 30 |
+
{Locale.User.LoginTitle}
|
| 31 |
+
</div>
|
| 32 |
+
</div>
|
| 33 |
+
</div>
|
| 34 |
+
|
| 35 |
+
<div>
|
| 36 |
+
<div className={styles.login}>
|
| 37 |
+
<div><ChatIcon></ChatIcon></div>
|
| 38 |
+
<div>
|
| 39 |
+
<input
|
| 40 |
+
type="input"
|
| 41 |
+
className={styles.name}
|
| 42 |
+
placeholder="账号"
|
| 43 |
+
onInput={(e) => onUser(e.currentTarget.value)}
|
| 44 |
+
value={user}
|
| 45 |
+
></input>
|
| 46 |
+
</div>
|
| 47 |
+
<div>
|
| 48 |
+
<span className={styles.wangji}><a href="/#/login">登录</a></span>
|
| 49 |
+
<span className={styles.zhuce}><a href="/#/register">注册</a></span>
|
| 50 |
+
</div>
|
| 51 |
+
<div>
|
| 52 |
+
<IconButton
|
| 53 |
+
text="找回密码"
|
| 54 |
+
className={styles.loginButton}
|
| 55 |
+
onClick={()=>{
|
| 56 |
+
findpwd()
|
| 57 |
+
}}
|
| 58 |
+
></IconButton>
|
| 59 |
+
</div>
|
| 60 |
+
</div>
|
| 61 |
+
</div>
|
| 62 |
+
</ErrorBoundary>
|
| 63 |
+
);
|
| 64 |
+
}
|
app/components/home.tsx
CHANGED
|
@@ -42,6 +42,22 @@ const Chat = dynamic(async () => (await import("./chat")).Chat, {
|
|
| 42 |
loading: () => <Loading noLogo />,
|
| 43 |
});
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
const NewChat = dynamic(async () => (await import("./new-chat")).NewChat, {
|
| 46 |
loading: () => <Loading noLogo />,
|
| 47 |
});
|
|
@@ -116,6 +132,10 @@ function Screen() {
|
|
| 116 |
<Route path={Path.NewChat} element={<NewChat />} />
|
| 117 |
<Route path={Path.Masks} element={<MaskPage />} />
|
| 118 |
<Route path={Path.Chat} element={<Chat />} />
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
<Route path={Path.Settings} element={<Settings />} />
|
| 120 |
</Routes>
|
| 121 |
</div>
|
|
|
|
| 42 |
loading: () => <Loading noLogo />,
|
| 43 |
});
|
| 44 |
|
| 45 |
+
const User = dynamic(async () => (await import("./user")).User, {
|
| 46 |
+
loading: () => <Loading noLogo />,
|
| 47 |
+
});
|
| 48 |
+
|
| 49 |
+
const Findpwd = dynamic(async () => (await import("./findpwd")).findpwd, {
|
| 50 |
+
loading: () => <Loading noLogo />,
|
| 51 |
+
});
|
| 52 |
+
|
| 53 |
+
const Login = dynamic(async () => (await import("./login")).Login, {
|
| 54 |
+
loading: () => <Loading noLogo />,
|
| 55 |
+
});
|
| 56 |
+
|
| 57 |
+
const Register = dynamic(async () => (await import("./register")).Register, {
|
| 58 |
+
loading: () => <Loading noLogo />,
|
| 59 |
+
});
|
| 60 |
+
|
| 61 |
const NewChat = dynamic(async () => (await import("./new-chat")).NewChat, {
|
| 62 |
loading: () => <Loading noLogo />,
|
| 63 |
});
|
|
|
|
| 132 |
<Route path={Path.NewChat} element={<NewChat />} />
|
| 133 |
<Route path={Path.Masks} element={<MaskPage />} />
|
| 134 |
<Route path={Path.Chat} element={<Chat />} />
|
| 135 |
+
<Route path={Path.User} element={<User />} />
|
| 136 |
+
<Route path={Path.Login} element={<Login />} />
|
| 137 |
+
<Route path={Path.Findpwd} element={<Findpwd />} />
|
| 138 |
+
<Route path={Path.Register} element={<Register />} />
|
| 139 |
<Route path={Path.Settings} element={<Settings />} />
|
| 140 |
</Routes>
|
| 141 |
</div>
|
app/components/login.module.scss
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.name{
|
| 2 |
+
border: var(--border-in-light);
|
| 3 |
+
padding: 10px;
|
| 4 |
+
border-radius: 10px;
|
| 5 |
+
-webkit-appearance: none;
|
| 6 |
+
-moz-appearance: none;
|
| 7 |
+
appearance: none;
|
| 8 |
+
cursor: pointer;
|
| 9 |
+
background-color: var(--white);
|
| 10 |
+
color: var(--black);
|
| 11 |
+
text-align: left;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
.user {
|
| 15 |
+
padding: 20px;
|
| 16 |
+
overflow: auto;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.font{
|
| 20 |
+
font-size: 15px;
|
| 21 |
+
padding-right: 5px;
|
| 22 |
+
text-align: center;
|
| 23 |
+
.wallet{
|
| 24 |
+
color: #2279ca;
|
| 25 |
+
};
|
| 26 |
+
.vipTime{
|
| 27 |
+
font-size: 8px;
|
| 28 |
+
padding-top: 5px;
|
| 29 |
+
};
|
| 30 |
+
.vipState{
|
| 31 |
+
color: #dc423c;
|
| 32 |
+
}
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
.sigState{
|
| 36 |
+
color: #2279ca;
|
| 37 |
+
padding-right: 10px;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
.sigButton{
|
| 41 |
+
border: var(--border-in-light);
|
| 42 |
+
padding: 10px;
|
| 43 |
+
border-radius: 10px;
|
| 44 |
+
cursor: pointer;
|
| 45 |
+
&:hover{
|
| 46 |
+
border-color: #2279ca;
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
.login{
|
| 51 |
+
text-align: center;
|
| 52 |
+
div{
|
| 53 |
+
padding: 10px;
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
.wangji{
|
| 58 |
+
padding-right: 50px;
|
| 59 |
+
font-size: 12px;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
.zhuce{
|
| 63 |
+
padding-left: 50px;
|
| 64 |
+
font-size: 12px;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
.loginButton{
|
| 68 |
+
background-color: #1db144;
|
| 69 |
+
color: white;
|
| 70 |
+
padding: 0;
|
| 71 |
+
width: 183px;
|
| 72 |
+
display: block;
|
| 73 |
+
margin: 0 auto;
|
| 74 |
+
}
|
app/components/login.tsx
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { ErrorBoundary } from "./error";
|
| 2 |
+
import Locale, { AllLangs, changeLang, getLang } from "../locales";
|
| 3 |
+
import ChatIcon from "../icons/chatgpt.svg"
|
| 4 |
+
import styles from "./login.module.scss";
|
| 5 |
+
import { IconButton } from "./button";
|
| 6 |
+
import { useUserStore } from "../store";
|
| 7 |
+
import { useState } from "react";
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
export function Login(){
|
| 11 |
+
const userStore=useUserStore()
|
| 12 |
+
const [user, setUser] = useState("");
|
| 13 |
+
const [password, setPassword] = useState("");
|
| 14 |
+
|
| 15 |
+
const onUser = (text: string) => {
|
| 16 |
+
setUser(text)
|
| 17 |
+
};
|
| 18 |
+
const onPassword = (text: string) => {
|
| 19 |
+
setPassword(text)
|
| 20 |
+
};
|
| 21 |
+
|
| 22 |
+
const loginTo=()=>{
|
| 23 |
+
userStore.login(user,password)
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
return (
|
| 27 |
+
<ErrorBoundary>
|
| 28 |
+
<div className="window-header">
|
| 29 |
+
<div className="window-header-title">
|
| 30 |
+
<div className="window-header-main-title">
|
| 31 |
+
{Locale.User.Login}
|
| 32 |
+
</div>
|
| 33 |
+
<div className="window-header-sub-title">
|
| 34 |
+
{Locale.User.LoginTitle}
|
| 35 |
+
</div>
|
| 36 |
+
</div>
|
| 37 |
+
</div>
|
| 38 |
+
|
| 39 |
+
<div>
|
| 40 |
+
<div className={styles.login}>
|
| 41 |
+
<div><ChatIcon></ChatIcon></div>
|
| 42 |
+
<div>
|
| 43 |
+
<input
|
| 44 |
+
type="input"
|
| 45 |
+
className={styles.name}
|
| 46 |
+
placeholder="账号"
|
| 47 |
+
onInput={(e) => onUser(e.currentTarget.value)}
|
| 48 |
+
value={user}
|
| 49 |
+
></input>
|
| 50 |
+
</div>
|
| 51 |
+
<div>
|
| 52 |
+
<input
|
| 53 |
+
type="password"
|
| 54 |
+
className={styles.name}
|
| 55 |
+
placeholder="密码"
|
| 56 |
+
onInput={(e) => onPassword(e.currentTarget.value)}
|
| 57 |
+
value={password}
|
| 58 |
+
></input>
|
| 59 |
+
</div>
|
| 60 |
+
<div>
|
| 61 |
+
<span className={styles.wangji}><a href="/#/findpwd">忘记密码</a></span>
|
| 62 |
+
<span className={styles.zhuce}><a href="/#/register">注册</a></span>
|
| 63 |
+
</div>
|
| 64 |
+
<div>
|
| 65 |
+
<IconButton
|
| 66 |
+
text="登录"
|
| 67 |
+
className={styles.loginButton}
|
| 68 |
+
onClick={()=>{
|
| 69 |
+
loginTo()
|
| 70 |
+
}}
|
| 71 |
+
></IconButton>
|
| 72 |
+
</div>
|
| 73 |
+
</div>
|
| 74 |
+
</div>
|
| 75 |
+
</ErrorBoundary>
|
| 76 |
+
);
|
| 77 |
+
}
|
app/components/register.module.scss
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.name{
|
| 2 |
+
border: var(--border-in-light);
|
| 3 |
+
padding: 10px;
|
| 4 |
+
border-radius: 10px;
|
| 5 |
+
-webkit-appearance: none;
|
| 6 |
+
-moz-appearance: none;
|
| 7 |
+
appearance: none;
|
| 8 |
+
cursor: pointer;
|
| 9 |
+
background-color: var(--white);
|
| 10 |
+
color: var(--black);
|
| 11 |
+
text-align: left;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
.code{
|
| 15 |
+
border: var(--border-in-light);
|
| 16 |
+
padding: 10px;
|
| 17 |
+
margin-right: 10px;
|
| 18 |
+
border-radius: 10px;
|
| 19 |
+
-webkit-appearance: none;
|
| 20 |
+
-moz-appearance: none;
|
| 21 |
+
appearance: none;
|
| 22 |
+
cursor: pointer;
|
| 23 |
+
background-color: var(--white);
|
| 24 |
+
color: var(--black);
|
| 25 |
+
text-align: left;
|
| 26 |
+
width: 58px;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
.codebox{
|
| 30 |
+
vertical-align: bottom;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
.user {
|
| 34 |
+
padding: 20px;
|
| 35 |
+
overflow: auto;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.font{
|
| 39 |
+
font-size: 15px;
|
| 40 |
+
padding-right: 5px;
|
| 41 |
+
text-align: center;
|
| 42 |
+
.wallet{
|
| 43 |
+
color: #2279ca;
|
| 44 |
+
};
|
| 45 |
+
.vipTime{
|
| 46 |
+
font-size: 8px;
|
| 47 |
+
padding-top: 5px;
|
| 48 |
+
};
|
| 49 |
+
.vipState{
|
| 50 |
+
color: #dc423c;
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
.sigState{
|
| 55 |
+
color: #2279ca;
|
| 56 |
+
padding-right: 10px;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
.sigButton{
|
| 60 |
+
border: var(--border-in-light);
|
| 61 |
+
padding: 10px;
|
| 62 |
+
border-radius: 10px;
|
| 63 |
+
cursor: pointer;
|
| 64 |
+
&:hover{
|
| 65 |
+
border-color: #2279ca;
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
.register{
|
| 70 |
+
text-align: center;
|
| 71 |
+
div{
|
| 72 |
+
padding: 10px;
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
.wangji{
|
| 77 |
+
padding-right: 50px;
|
| 78 |
+
font-size: 12px;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
.zhuce{
|
| 82 |
+
padding-left: 50px;
|
| 83 |
+
font-size: 12px;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
.registerButton{
|
| 87 |
+
background-color: #1db144;
|
| 88 |
+
color: white;
|
| 89 |
+
padding: 0;
|
| 90 |
+
width: 183px;
|
| 91 |
+
display: block;
|
| 92 |
+
margin: 0 auto;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
.codeButton{
|
| 96 |
+
background-color: #1db144;
|
| 97 |
+
color: white;
|
| 98 |
+
padding: 0;
|
| 99 |
+
width: 93px;
|
| 100 |
+
display: inline;
|
| 101 |
+
margin: 0 auto;
|
| 102 |
+
font-size: 8px;
|
| 103 |
+
}
|
app/components/register.tsx
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { ErrorBoundary } from "./error";
|
| 2 |
+
import Locale, { AllLangs, changeLang, getLang } from "../locales";
|
| 3 |
+
import { useUserStore } from "../store";
|
| 4 |
+
import { useEffect, useState } from "react";
|
| 5 |
+
import styles from "./register.module.scss";
|
| 6 |
+
import ChatIcon from "../icons/chatgpt.svg"
|
| 7 |
+
import { IconButton } from "./button";
|
| 8 |
+
import { showToast } from "./ui-lib";
|
| 9 |
+
|
| 10 |
+
export function Register(){
|
| 11 |
+
const userStore=useUserStore()
|
| 12 |
+
const [userName, setUserName] = useState("");
|
| 13 |
+
const [getcode, setgetcode] = useState("");
|
| 14 |
+
const [codeStatus, setcodeStatus] = useState("");
|
| 15 |
+
const [name, setName] = useState("");
|
| 16 |
+
const [password, setPassword] = useState("");
|
| 17 |
+
const [mail, setMail] = useState("");
|
| 18 |
+
const [code, setCode] = useState("");
|
| 19 |
+
|
| 20 |
+
const onUserName = (text: string) => {
|
| 21 |
+
setUserName(text)
|
| 22 |
+
};
|
| 23 |
+
const onName = (text: string) => {
|
| 24 |
+
setName(text)
|
| 25 |
+
};
|
| 26 |
+
const onPassword = (text: string) => {
|
| 27 |
+
setPassword(text)
|
| 28 |
+
};
|
| 29 |
+
const onMail = (text: string) => {
|
| 30 |
+
setMail(text)
|
| 31 |
+
};
|
| 32 |
+
const onCode = (text: string) => {
|
| 33 |
+
setCode(text)
|
| 34 |
+
};
|
| 35 |
+
|
| 36 |
+
const loginTo=()=>{
|
| 37 |
+
userStore.register(userName,password,name,mail,code)
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
const getMailCode=()=>{
|
| 41 |
+
userStore.getMailCode(userName,mail)
|
| 42 |
+
getCode()
|
| 43 |
+
}
|
| 44 |
+
var countdown=60;
|
| 45 |
+
const getCode=()=>{
|
| 46 |
+
if (countdown == 0) {
|
| 47 |
+
setcodeStatus("")
|
| 48 |
+
setgetcode("发送验证码")
|
| 49 |
+
countdown = 60;
|
| 50 |
+
return;
|
| 51 |
+
} else {
|
| 52 |
+
setcodeStatus("true")
|
| 53 |
+
setgetcode("(" + countdown + ")")
|
| 54 |
+
countdown--;
|
| 55 |
+
}
|
| 56 |
+
setTimeout(function() {
|
| 57 |
+
getCode() }
|
| 58 |
+
,1000)
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
useEffect(()=>{
|
| 62 |
+
setcodeStatus("")
|
| 63 |
+
setgetcode("发送验证码")
|
| 64 |
+
},[])
|
| 65 |
+
|
| 66 |
+
return (
|
| 67 |
+
<ErrorBoundary>
|
| 68 |
+
<div className="window-header">
|
| 69 |
+
<div className="window-header-title">
|
| 70 |
+
<div className="window-header-main-title">
|
| 71 |
+
{Locale.User.Login}
|
| 72 |
+
</div>
|
| 73 |
+
<div className="window-header-sub-title">
|
| 74 |
+
{Locale.User.LoginTitle}
|
| 75 |
+
</div>
|
| 76 |
+
</div>
|
| 77 |
+
</div>
|
| 78 |
+
|
| 79 |
+
<div>
|
| 80 |
+
<div className={styles.register}>
|
| 81 |
+
<div><ChatIcon></ChatIcon></div>
|
| 82 |
+
<div>
|
| 83 |
+
<input
|
| 84 |
+
type="input"
|
| 85 |
+
className={styles.name}
|
| 86 |
+
placeholder="呢称"
|
| 87 |
+
onInput={(e) => onName(e.currentTarget.value)}
|
| 88 |
+
value={name}
|
| 89 |
+
></input>
|
| 90 |
+
</div>
|
| 91 |
+
<div>
|
| 92 |
+
<input
|
| 93 |
+
type="input"
|
| 94 |
+
className={styles.name}
|
| 95 |
+
placeholder="账号 (纯数字)"
|
| 96 |
+
onInput={(e) => onUserName(e.currentTarget.value)}
|
| 97 |
+
value={userName}
|
| 98 |
+
></input>
|
| 99 |
+
</div>
|
| 100 |
+
<div>
|
| 101 |
+
<input
|
| 102 |
+
type="password"
|
| 103 |
+
className={styles.name}
|
| 104 |
+
placeholder="密码 (最少六位)"
|
| 105 |
+
onInput={(e) => onPassword(e.currentTarget.value)}
|
| 106 |
+
value={password}
|
| 107 |
+
></input>
|
| 108 |
+
</div>
|
| 109 |
+
<div>
|
| 110 |
+
<input
|
| 111 |
+
type="input"
|
| 112 |
+
className={styles.name}
|
| 113 |
+
placeholder="邮箱"
|
| 114 |
+
onInput={(e) => onMail(e.currentTarget.value)}
|
| 115 |
+
value={mail}
|
| 116 |
+
></input>
|
| 117 |
+
</div>
|
| 118 |
+
<div className={styles.codebox}>
|
| 119 |
+
<input
|
| 120 |
+
type="input"
|
| 121 |
+
className={styles.code}
|
| 122 |
+
placeholder="验证码"
|
| 123 |
+
onInput={(e) => onCode(e.currentTarget.value)}
|
| 124 |
+
value={code}
|
| 125 |
+
></input>
|
| 126 |
+
<IconButton
|
| 127 |
+
disabled={!!codeStatus}
|
| 128 |
+
text={getcode}
|
| 129 |
+
className={styles.codeButton}
|
| 130 |
+
onClick={()=>{
|
| 131 |
+
getMailCode()
|
| 132 |
+
}}
|
| 133 |
+
></IconButton>
|
| 134 |
+
</div>
|
| 135 |
+
<div>
|
| 136 |
+
<span className={styles.wangji}><a href="/#/findpwd">忘记密码</a></span>
|
| 137 |
+
<span className={styles.zhuce}><a href="/#/login">登录</a></span>
|
| 138 |
+
</div>
|
| 139 |
+
<div>
|
| 140 |
+
<IconButton
|
| 141 |
+
text="注册"
|
| 142 |
+
className={styles.registerButton}
|
| 143 |
+
onClick={()=>{
|
| 144 |
+
loginTo()
|
| 145 |
+
}}
|
| 146 |
+
></IconButton>
|
| 147 |
+
</div>
|
| 148 |
+
</div>
|
| 149 |
+
</div>
|
| 150 |
+
</ErrorBoundary>
|
| 151 |
+
);
|
| 152 |
+
}
|
app/components/settings.tsx
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
| 23 |
useAppConfig,
|
| 24 |
ALL_BOT,
|
| 25 |
ModalConfigValidator,
|
|
|
|
| 26 |
} from "../store";
|
| 27 |
|
| 28 |
import Locale, { AllLangs, changeLang, getLang } from "../locales";
|
|
@@ -292,6 +293,7 @@ export function Settings() {
|
|
| 292 |
onClick={() => {
|
| 293 |
if (confirm(Locale.Settings.Actions.ConfirmClearAll)) {
|
| 294 |
chatStore.clearAllData();
|
|
|
|
| 295 |
}
|
| 296 |
}}
|
| 297 |
bordered
|
|
@@ -322,7 +324,7 @@ export function Settings() {
|
|
| 322 |
</div>
|
| 323 |
<div className={styles["settings"]}>
|
| 324 |
<List>
|
| 325 |
-
<ListItem title={Locale.Settings.Avatar}>
|
| 326 |
<Popover
|
| 327 |
onClose={() => setShowEmojiPicker(false)}
|
| 328 |
content={
|
|
@@ -342,7 +344,7 @@ export function Settings() {
|
|
| 342 |
<Avatar avatar={config.avatar} />
|
| 343 |
</div>
|
| 344 |
</Popover>
|
| 345 |
-
</ListItem>
|
| 346 |
|
| 347 |
{/* <ListItem
|
| 348 |
title={Locale.Settings.Update.Version(currentVersion ?? "unknown")}
|
|
@@ -507,7 +509,7 @@ export function Settings() {
|
|
| 507 |
</ListItem>
|
| 508 |
) : null}
|
| 509 |
|
| 510 |
-
<ListItem
|
| 511 |
title={Locale.Settings.Usage.Title}
|
| 512 |
subTitle={
|
| 513 |
showUsage
|
|
@@ -529,7 +531,7 @@ export function Settings() {
|
|
| 529 |
onClick={() => checkUsage(true)}
|
| 530 |
/>
|
| 531 |
)}
|
| 532 |
-
</ListItem>
|
| 533 |
</List>
|
| 534 |
|
| 535 |
<List>
|
|
|
|
| 23 |
useAppConfig,
|
| 24 |
ALL_BOT,
|
| 25 |
ModalConfigValidator,
|
| 26 |
+
useUserStore,
|
| 27 |
} from "../store";
|
| 28 |
|
| 29 |
import Locale, { AllLangs, changeLang, getLang } from "../locales";
|
|
|
|
| 293 |
onClick={() => {
|
| 294 |
if (confirm(Locale.Settings.Actions.ConfirmClearAll)) {
|
| 295 |
chatStore.clearAllData();
|
| 296 |
+
useUserStore.getState().reset();
|
| 297 |
}
|
| 298 |
}}
|
| 299 |
bordered
|
|
|
|
| 324 |
</div>
|
| 325 |
<div className={styles["settings"]}>
|
| 326 |
<List>
|
| 327 |
+
{/* <ListItem title={Locale.Settings.Avatar}>
|
| 328 |
<Popover
|
| 329 |
onClose={() => setShowEmojiPicker(false)}
|
| 330 |
content={
|
|
|
|
| 344 |
<Avatar avatar={config.avatar} />
|
| 345 |
</div>
|
| 346 |
</Popover>
|
| 347 |
+
</ListItem> */}
|
| 348 |
|
| 349 |
{/* <ListItem
|
| 350 |
title={Locale.Settings.Update.Version(currentVersion ?? "unknown")}
|
|
|
|
| 509 |
</ListItem>
|
| 510 |
) : null}
|
| 511 |
|
| 512 |
+
{/* <ListItem
|
| 513 |
title={Locale.Settings.Usage.Title}
|
| 514 |
subTitle={
|
| 515 |
showUsage
|
|
|
|
| 531 |
onClick={() => checkUsage(true)}
|
| 532 |
/>
|
| 533 |
)}
|
| 534 |
+
</ListItem> */}
|
| 535 |
</List>
|
| 536 |
|
| 537 |
<List>
|
app/components/sidebar.tsx
CHANGED
|
@@ -174,9 +174,9 @@ export function SideBar(props: { className?: string }) {
|
|
| 174 |
</Link>
|
| 175 |
</div>
|
| 176 |
<div className={styles["sidebar-action"]}>
|
| 177 |
-
|
| 178 |
<IconButton icon={<GithubIcon />} shadow />
|
| 179 |
-
</
|
| 180 |
</div>
|
| 181 |
</div>
|
| 182 |
<div>
|
|
|
|
| 174 |
</Link>
|
| 175 |
</div>
|
| 176 |
<div className={styles["sidebar-action"]}>
|
| 177 |
+
<Link to={Path.User}>
|
| 178 |
<IconButton icon={<GithubIcon />} shadow />
|
| 179 |
+
</Link>
|
| 180 |
</div>
|
| 181 |
</div>
|
| 182 |
<div>
|
app/components/ui-lib.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import EyeIcon from "../icons/eye.svg";
|
|
| 5 |
import EyeOffIcon from "../icons/eye-off.svg";
|
| 6 |
|
| 7 |
import { createRoot } from "react-dom/client";
|
| 8 |
-
import React, { HTMLProps, useEffect, useState
|
| 9 |
import { IconButton } from "./button";
|
| 10 |
|
| 11 |
export function Popover(props: {
|
|
|
|
| 5 |
import EyeOffIcon from "../icons/eye-off.svg";
|
| 6 |
|
| 7 |
import { createRoot } from "react-dom/client";
|
| 8 |
+
import React, { HTMLProps, useEffect, useState} from "react";
|
| 9 |
import { IconButton } from "./button";
|
| 10 |
|
| 11 |
export function Popover(props: {
|
app/components/user.module.scss
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.name{
|
| 2 |
+
border: var(--border-in-light);
|
| 3 |
+
padding: 10px;
|
| 4 |
+
border-radius: 10px;
|
| 5 |
+
-webkit-appearance: none;
|
| 6 |
+
-moz-appearance: none;
|
| 7 |
+
appearance: none;
|
| 8 |
+
cursor: pointer;
|
| 9 |
+
background-color: var(--white);
|
| 10 |
+
color: var(--black);
|
| 11 |
+
text-align: right;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
.kamicode{
|
| 15 |
+
border: var(--border-in-light);
|
| 16 |
+
padding: 10px;
|
| 17 |
+
border-radius: 10px;
|
| 18 |
+
-webkit-appearance: none;
|
| 19 |
+
-moz-appearance: none;
|
| 20 |
+
appearance: none;
|
| 21 |
+
cursor: pointer;
|
| 22 |
+
background-color: var(--white);
|
| 23 |
+
color: var(--black);
|
| 24 |
+
text-align: right;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
.kamiButton{
|
| 28 |
+
display: inline;
|
| 29 |
+
margin-left: 10px;
|
| 30 |
+
background-color: #e8f8ff;
|
| 31 |
+
div{
|
| 32 |
+
margin-right: 5px;
|
| 33 |
+
}
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
.avatar {
|
| 37 |
+
cursor: pointer;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
.user {
|
| 41 |
+
padding: 20px;
|
| 42 |
+
overflow: auto;
|
| 43 |
+
height: 100%;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
.font{
|
| 47 |
+
font-size: 15px;
|
| 48 |
+
padding-right: 5px;
|
| 49 |
+
text-align: center;
|
| 50 |
+
.wallet{
|
| 51 |
+
color: #2279ca;
|
| 52 |
+
};
|
| 53 |
+
.vipTime{
|
| 54 |
+
font-size: 8px;
|
| 55 |
+
padding-top: 5px;
|
| 56 |
+
};
|
| 57 |
+
.vipState{
|
| 58 |
+
color: #dc423c;
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
.sigState{
|
| 63 |
+
color: #2279ca;
|
| 64 |
+
padding-right: 10px;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
.sigButton{
|
| 68 |
+
border: var(--border-in-light);
|
| 69 |
+
padding: 10px;
|
| 70 |
+
border-radius: 10px;
|
| 71 |
+
cursor: pointer;
|
| 72 |
+
&:hover{
|
| 73 |
+
border-color: #2279ca;
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
.logoutButton{
|
| 78 |
+
background-color: #fc090f;
|
| 79 |
+
text-align: center;
|
| 80 |
+
color: white;
|
| 81 |
+
div{
|
| 82 |
+
margin-right: 5px;
|
| 83 |
+
}
|
| 84 |
+
}
|
app/components/user.tsx
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { useState, useEffect } from "react";
|
| 2 |
+
|
| 3 |
+
import styles from "./user.module.scss";
|
| 4 |
+
import EditIcon from "../icons/edit.svg";
|
| 5 |
+
import { List, ListItem, Popover, showModal, showToast } from "./ui-lib";
|
| 6 |
+
|
| 7 |
+
import { IconButton } from "./button";
|
| 8 |
+
import {
|
| 9 |
+
useAccessStore,
|
| 10 |
+
useAppConfig,
|
| 11 |
+
} from "../store";
|
| 12 |
+
|
| 13 |
+
import Locale from "../locales";
|
| 14 |
+
import { Path } from "../constant";
|
| 15 |
+
import { ErrorBoundary } from "./error";
|
| 16 |
+
import { useNavigate } from "react-router-dom";
|
| 17 |
+
import { Avatar, AvatarPicker } from "./emoji";
|
| 18 |
+
import { useUserStore } from "../store/user";
|
| 19 |
+
|
| 20 |
+
export function User() {
|
| 21 |
+
const navigate = useNavigate();
|
| 22 |
+
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
| 23 |
+
const config = useAppConfig();
|
| 24 |
+
const updateConfig = config.update;
|
| 25 |
+
|
| 26 |
+
const accessStore = useAccessStore();
|
| 27 |
+
const userStor = useUserStore()
|
| 28 |
+
|
| 29 |
+
const [userName, setUserName] = useState("");
|
| 30 |
+
const [kami, setKami] = useState("");
|
| 31 |
+
const onUserName = (text: string) => {
|
| 32 |
+
setUserName(text)
|
| 33 |
+
userStor.updateName(userName)
|
| 34 |
+
};
|
| 35 |
+
|
| 36 |
+
function getVipTime(){
|
| 37 |
+
if(!userStor.vip_time_stmp){
|
| 38 |
+
return ""
|
| 39 |
+
}
|
| 40 |
+
let time=new Date().getTime();
|
| 41 |
+
console.log(time)
|
| 42 |
+
time=time+Number(userStor.vip_time_stmp)*1000
|
| 43 |
+
console.log(time)
|
| 44 |
+
const date = new Date(time)
|
| 45 |
+
const Y = date.getFullYear()
|
| 46 |
+
const M = date.getMonth() + 1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1
|
| 47 |
+
const D = date.getDate()
|
| 48 |
+
return `${Y} - ${M} - ${D}`
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
useEffect(()=>{
|
| 52 |
+
setUserName(()=>{return userStor.name;})
|
| 53 |
+
},[])
|
| 54 |
+
|
| 55 |
+
useEffect(() => {
|
| 56 |
+
const keydownEvent = (e: KeyboardEvent) => {
|
| 57 |
+
if (e.key === "Escape") {
|
| 58 |
+
navigate(Path.Home);
|
| 59 |
+
}
|
| 60 |
+
};
|
| 61 |
+
document.addEventListener("keydown", keydownEvent);
|
| 62 |
+
return () => {
|
| 63 |
+
document.removeEventListener("keydown", keydownEvent);
|
| 64 |
+
};
|
| 65 |
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
| 66 |
+
}, []);
|
| 67 |
+
|
| 68 |
+
return (
|
| 69 |
+
<ErrorBoundary>
|
| 70 |
+
<div className="window-header">
|
| 71 |
+
<div className="window-header-title">
|
| 72 |
+
<div className="window-header-main-title">
|
| 73 |
+
{Locale.User.Title}
|
| 74 |
+
</div>
|
| 75 |
+
<div className="window-header-sub-title">
|
| 76 |
+
{Locale.User.SubTitle}
|
| 77 |
+
</div>
|
| 78 |
+
</div>
|
| 79 |
+
</div>
|
| 80 |
+
<div className={styles["user"]}>
|
| 81 |
+
<List>
|
| 82 |
+
<ListItem title={Locale.Settings.Avatar}>
|
| 83 |
+
<Popover
|
| 84 |
+
onClose={() => setShowEmojiPicker(false)}
|
| 85 |
+
content={
|
| 86 |
+
<AvatarPicker
|
| 87 |
+
onEmojiClick={(avatar: string) => {
|
| 88 |
+
updateConfig((config) => (config.avatar = avatar));
|
| 89 |
+
setShowEmojiPicker(false);
|
| 90 |
+
}}
|
| 91 |
+
/>
|
| 92 |
+
}
|
| 93 |
+
open={showEmojiPicker}
|
| 94 |
+
>
|
| 95 |
+
<div
|
| 96 |
+
className={styles.avatar}
|
| 97 |
+
onClick={() => setShowEmojiPicker(true)}
|
| 98 |
+
>
|
| 99 |
+
<Avatar avatar={config.avatar} />
|
| 100 |
+
</div>
|
| 101 |
+
</Popover>
|
| 102 |
+
</ListItem>
|
| 103 |
+
|
| 104 |
+
<ListItem title={Locale.User.Name}>
|
| 105 |
+
<input
|
| 106 |
+
type="input"
|
| 107 |
+
className={styles.name}
|
| 108 |
+
value={userName}
|
| 109 |
+
disabled={!accessStore.auth}
|
| 110 |
+
onBlur={(e)=>{onUserName(e.currentTarget.value)}}
|
| 111 |
+
onChange={(e)=>{setUserName(e.currentTarget.value)}}
|
| 112 |
+
></input>
|
| 113 |
+
</ListItem>
|
| 114 |
+
|
| 115 |
+
<ListItem title={Locale.User.Mail}>
|
| 116 |
+
<span>{userStor.mail}</span>
|
| 117 |
+
</ListItem>
|
| 118 |
+
|
| 119 |
+
<ListItem title={Locale.User.Wallet}>
|
| 120 |
+
<div className={styles.font} >
|
| 121 |
+
剩余积分:<span className={styles.wallet}>{userStor.wallet}</span>
|
| 122 |
+
</div>
|
| 123 |
+
</ListItem>
|
| 124 |
+
|
| 125 |
+
<ListItem title={Locale.User.Vip}>
|
| 126 |
+
<div className={styles.font}>
|
| 127 |
+
<div className={styles.vipState}>{userStor.vip_state=="已开通"?"VIP":"非VIP"}</div>
|
| 128 |
+
<div className={styles.vipTime}>{getVipTime()}</div>
|
| 129 |
+
</div>
|
| 130 |
+
</ListItem>
|
| 131 |
+
|
| 132 |
+
<ListItem title={Locale.User.kami}>
|
| 133 |
+
<div>
|
| 134 |
+
<input
|
| 135 |
+
type="input"
|
| 136 |
+
className={styles.kamicode}
|
| 137 |
+
value={kami}
|
| 138 |
+
onChange={(e)=>{setKami(e.currentTarget.value)}}>
|
| 139 |
+
</input>
|
| 140 |
+
<IconButton
|
| 141 |
+
className={styles.kamiButton}
|
| 142 |
+
disabled={!accessStore.auth}
|
| 143 |
+
text="兑换"
|
| 144 |
+
onClick={()=>{
|
| 145 |
+
userStor.useKami(kami)
|
| 146 |
+
setKami("")
|
| 147 |
+
}}
|
| 148 |
+
/>
|
| 149 |
+
</div>
|
| 150 |
+
</ListItem>
|
| 151 |
+
|
| 152 |
+
<ListItem title={Locale.User.SigState}>
|
| 153 |
+
<IconButton
|
| 154 |
+
icon={<EditIcon />}
|
| 155 |
+
disabled={!accessStore.auth || userStor.sig_state=="已签到"}
|
| 156 |
+
text="签到"
|
| 157 |
+
onClick={()=>{
|
| 158 |
+
userStor.userSig()
|
| 159 |
+
}}
|
| 160 |
+
/>
|
| 161 |
+
</ListItem>
|
| 162 |
+
|
| 163 |
+
<ListItem title={Locale.User.Ststus}>
|
| 164 |
+
<IconButton
|
| 165 |
+
className={styles.logoutButton}
|
| 166 |
+
disabled={!accessStore.auth}
|
| 167 |
+
text="登出"
|
| 168 |
+
onClick={()=>{
|
| 169 |
+
accessStore.updateAuth("")
|
| 170 |
+
userStor.reset()
|
| 171 |
+
showToast("登出成功!")
|
| 172 |
+
}}
|
| 173 |
+
/>
|
| 174 |
+
</ListItem>
|
| 175 |
+
</List>
|
| 176 |
+
</div>
|
| 177 |
+
</ErrorBoundary>
|
| 178 |
+
);
|
| 179 |
+
}
|
| 180 |
+
|
app/config/server.ts
CHANGED
|
@@ -37,10 +37,10 @@ export const getServerSideConfig = () => {
|
|
| 37 |
apiKey: process.env.OPENAI_API_KEY,
|
| 38 |
code: process.env.CODE,
|
| 39 |
codes: ACCESS_CODES,
|
| 40 |
-
needCode: ACCESS_CODES.size
|
| 41 |
proxyUrl: process.env.PROXY_URL,
|
| 42 |
isVercel: !!process.env.VERCEL,
|
| 43 |
-
hideUserApiKey: !!process.env.HIDE_USER_API_KEY,
|
| 44 |
enableGPT4: !process.env.DISABLE_GPT4,
|
| 45 |
};
|
| 46 |
};
|
|
|
|
| 37 |
apiKey: process.env.OPENAI_API_KEY,
|
| 38 |
code: process.env.CODE,
|
| 39 |
codes: ACCESS_CODES,
|
| 40 |
+
needCode: ACCESS_CODES.size,
|
| 41 |
proxyUrl: process.env.PROXY_URL,
|
| 42 |
isVercel: !!process.env.VERCEL,
|
| 43 |
+
hideUserApiKey: !!process.env.HIDE_USER_API_KEY || true,
|
| 44 |
enableGPT4: !process.env.DISABLE_GPT4,
|
| 45 |
};
|
| 46 |
};
|
app/constant.ts
CHANGED
|
@@ -10,9 +10,13 @@ export const RUNTIME_CONFIG_DOM = "danger-runtime-config";
|
|
| 10 |
export enum Path {
|
| 11 |
Home = "/",
|
| 12 |
Chat = "/chat",
|
|
|
|
| 13 |
Settings = "/settings",
|
| 14 |
NewChat = "/new-chat",
|
| 15 |
Masks = "/masks",
|
|
|
|
|
|
|
|
|
|
| 16 |
}
|
| 17 |
|
| 18 |
export enum SlotID {
|
|
@@ -31,6 +35,7 @@ export enum StoreKey {
|
|
| 31 |
Mask = "mask-store",
|
| 32 |
Prompt = "prompt-store",
|
| 33 |
Update = "chat-update",
|
|
|
|
| 34 |
}
|
| 35 |
|
| 36 |
export const MAX_SIDEBAR_WIDTH = 500;
|
|
|
|
| 10 |
export enum Path {
|
| 11 |
Home = "/",
|
| 12 |
Chat = "/chat",
|
| 13 |
+
User = "/user",
|
| 14 |
Settings = "/settings",
|
| 15 |
NewChat = "/new-chat",
|
| 16 |
Masks = "/masks",
|
| 17 |
+
Login = "/login",
|
| 18 |
+
Register = "/register",
|
| 19 |
+
Findpwd = "/findpwd"
|
| 20 |
}
|
| 21 |
|
| 22 |
export enum SlotID {
|
|
|
|
| 35 |
Mask = "mask-store",
|
| 36 |
Prompt = "prompt-store",
|
| 37 |
Update = "chat-update",
|
| 38 |
+
User = "chat-user"
|
| 39 |
}
|
| 40 |
|
| 41 |
export const MAX_SIDEBAR_WIDTH = 500;
|
app/locales/cn.ts
CHANGED
|
@@ -4,7 +4,7 @@ const cn = {
|
|
| 4 |
WIP: "该功能仍在开发中……",
|
| 5 |
Error: {
|
| 6 |
Unauthorized:
|
| 7 |
-
"
|
| 8 |
},
|
| 9 |
ChatItem: {
|
| 10 |
ChatItemCount: (count: number) => `${count} 条对话`,
|
|
@@ -56,6 +56,21 @@ const cn = {
|
|
| 56 |
DeleteToast: "已删除会话",
|
| 57 |
Revert: "撤销",
|
| 58 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
Settings: {
|
| 60 |
Title: "设置",
|
| 61 |
SubTitle: "设置选项",
|
|
|
|
| 4 |
WIP: "该功能仍在开发中……",
|
| 5 |
Error: {
|
| 6 |
Unauthorized:
|
| 7 |
+
"尚未登录,请前往[登录](/#/login)页登录。",
|
| 8 |
},
|
| 9 |
ChatItem: {
|
| 10 |
ChatItemCount: (count: number) => `${count} 条对话`,
|
|
|
|
| 56 |
DeleteToast: "已删除会话",
|
| 57 |
Revert: "撤销",
|
| 58 |
},
|
| 59 |
+
User:{
|
| 60 |
+
Title: "用户",
|
| 61 |
+
SubTitle: "用户信息界面",
|
| 62 |
+
Login:"登录",
|
| 63 |
+
LoginTitle:"用户登录",
|
| 64 |
+
Register:"注册",
|
| 65 |
+
RegisterTitle:"注册新用户",
|
| 66 |
+
Name:"用户名",
|
| 67 |
+
Wallet:"用户积分",
|
| 68 |
+
Mail:"用户邮箱",
|
| 69 |
+
SigState:"签到状态",
|
| 70 |
+
Ststus:"登出",
|
| 71 |
+
Vip:"会员",
|
| 72 |
+
kami:"兑换码"
|
| 73 |
+
},
|
| 74 |
Settings: {
|
| 75 |
Title: "设置",
|
| 76 |
SubTitle: "设置选项",
|
app/locales/de.ts
CHANGED
|
@@ -58,6 +58,17 @@ const de: LocaleType = {
|
|
| 58 |
DeleteToast: "Chat gelöscht",
|
| 59 |
Revert: "Zurücksetzen",
|
| 60 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
Settings: {
|
| 62 |
Title: "Einstellungen",
|
| 63 |
SubTitle: "Alle Einstellungen",
|
|
|
|
| 58 |
DeleteToast: "Chat gelöscht",
|
| 59 |
Revert: "Zurücksetzen",
|
| 60 |
},
|
| 61 |
+
User:{
|
| 62 |
+
Title: "用户",
|
| 63 |
+
SubTitle: "用户信息界面",
|
| 64 |
+
Actions: {
|
| 65 |
+
ClearAll: "清除所有数据",
|
| 66 |
+
ResetAll: "重置所有选项",
|
| 67 |
+
Close: "关闭",
|
| 68 |
+
ConfirmResetAll: "确认重置所有配置?",
|
| 69 |
+
ConfirmClearAll: "确认清除所有数据?",
|
| 70 |
+
},
|
| 71 |
+
},
|
| 72 |
Settings: {
|
| 73 |
Title: "Einstellungen",
|
| 74 |
SubTitle: "Alle Einstellungen",
|
app/locales/en.ts
CHANGED
|
@@ -58,6 +58,17 @@ const en: LocaleType = {
|
|
| 58 |
DeleteToast: "Chat Deleted",
|
| 59 |
Revert: "Revert",
|
| 60 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
Settings: {
|
| 62 |
Title: "Settings",
|
| 63 |
SubTitle: "All Settings",
|
|
|
|
| 58 |
DeleteToast: "Chat Deleted",
|
| 59 |
Revert: "Revert",
|
| 60 |
},
|
| 61 |
+
User:{
|
| 62 |
+
Title: "用户",
|
| 63 |
+
SubTitle: "用户信息界面",
|
| 64 |
+
Actions: {
|
| 65 |
+
ClearAll: "清除所有数据",
|
| 66 |
+
ResetAll: "重置所有选项",
|
| 67 |
+
Close: "关闭",
|
| 68 |
+
ConfirmResetAll: "确认重置所有配置?",
|
| 69 |
+
ConfirmClearAll: "确认清除所有数据?",
|
| 70 |
+
},
|
| 71 |
+
},
|
| 72 |
Settings: {
|
| 73 |
Title: "Settings",
|
| 74 |
SubTitle: "All Settings",
|
app/locales/es.ts
CHANGED
|
@@ -58,6 +58,17 @@ const es: LocaleType = {
|
|
| 58 |
DeleteToast: "Chat Deleted",
|
| 59 |
Revert: "Revert",
|
| 60 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
Settings: {
|
| 62 |
Title: "Configuración",
|
| 63 |
SubTitle: "Todas las configuraciones",
|
|
|
|
| 58 |
DeleteToast: "Chat Deleted",
|
| 59 |
Revert: "Revert",
|
| 60 |
},
|
| 61 |
+
User:{
|
| 62 |
+
Title: "用户",
|
| 63 |
+
SubTitle: "用户信息界面",
|
| 64 |
+
Actions: {
|
| 65 |
+
ClearAll: "清除所有数据",
|
| 66 |
+
ResetAll: "重置所有选项",
|
| 67 |
+
Close: "关闭",
|
| 68 |
+
ConfirmResetAll: "确认重置所有配置?",
|
| 69 |
+
ConfirmClearAll: "确认清除所有数据?",
|
| 70 |
+
},
|
| 71 |
+
},
|
| 72 |
Settings: {
|
| 73 |
Title: "Configuración",
|
| 74 |
SubTitle: "Todas las configuraciones",
|
app/locales/it.ts
CHANGED
|
@@ -58,6 +58,17 @@ const it: LocaleType = {
|
|
| 58 |
DeleteToast: "Chat Cancellata",
|
| 59 |
Revert: "Revert",
|
| 60 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
Settings: {
|
| 62 |
Title: "Impostazioni",
|
| 63 |
SubTitle: "Tutte le impostazioni",
|
|
|
|
| 58 |
DeleteToast: "Chat Cancellata",
|
| 59 |
Revert: "Revert",
|
| 60 |
},
|
| 61 |
+
User:{
|
| 62 |
+
Title: "用户",
|
| 63 |
+
SubTitle: "用户信息界面",
|
| 64 |
+
Actions: {
|
| 65 |
+
ClearAll: "清除所有数据",
|
| 66 |
+
ResetAll: "重置所有选项",
|
| 67 |
+
Close: "关闭",
|
| 68 |
+
ConfirmResetAll: "确认重置所有配置?",
|
| 69 |
+
ConfirmClearAll: "确认清除所有数据?",
|
| 70 |
+
},
|
| 71 |
+
},
|
| 72 |
Settings: {
|
| 73 |
Title: "Impostazioni",
|
| 74 |
SubTitle: "Tutte le impostazioni",
|
app/locales/jp.ts
CHANGED
|
@@ -58,6 +58,17 @@ const jp: LocaleType = {
|
|
| 58 |
DeleteToast: "チャットが削除されました",
|
| 59 |
Revert: "元に戻す",
|
| 60 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
Settings: {
|
| 62 |
Title: "設定",
|
| 63 |
SubTitle: "設定オプション",
|
|
|
|
| 58 |
DeleteToast: "チャットが削除されました",
|
| 59 |
Revert: "元に戻す",
|
| 60 |
},
|
| 61 |
+
User:{
|
| 62 |
+
Title: "用户",
|
| 63 |
+
SubTitle: "用户信息界面",
|
| 64 |
+
Actions: {
|
| 65 |
+
ClearAll: "清除所有数据",
|
| 66 |
+
ResetAll: "重置所有选项",
|
| 67 |
+
Close: "关闭",
|
| 68 |
+
ConfirmResetAll: "确认重置所有配置?",
|
| 69 |
+
ConfirmClearAll: "确认清除所有数据?",
|
| 70 |
+
},
|
| 71 |
+
},
|
| 72 |
Settings: {
|
| 73 |
Title: "設定",
|
| 74 |
SubTitle: "設定オプション",
|
app/locales/tr.ts
CHANGED
|
@@ -58,6 +58,17 @@ const tr: LocaleType = {
|
|
| 58 |
DeleteToast: "Sohbet Silindi",
|
| 59 |
Revert: "Geri Al",
|
| 60 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
Settings: {
|
| 62 |
Title: "Ayarlar",
|
| 63 |
SubTitle: "Tüm Ayarlar",
|
|
|
|
| 58 |
DeleteToast: "Sohbet Silindi",
|
| 59 |
Revert: "Geri Al",
|
| 60 |
},
|
| 61 |
+
User:{
|
| 62 |
+
Title: "用户",
|
| 63 |
+
SubTitle: "用户信息界面",
|
| 64 |
+
Actions: {
|
| 65 |
+
ClearAll: "清除所有数据",
|
| 66 |
+
ResetAll: "重置所有选项",
|
| 67 |
+
Close: "关闭",
|
| 68 |
+
ConfirmResetAll: "确认重置所有配置?",
|
| 69 |
+
ConfirmClearAll: "确认清除所有数据?",
|
| 70 |
+
},
|
| 71 |
+
},
|
| 72 |
Settings: {
|
| 73 |
Title: "Ayarlar",
|
| 74 |
SubTitle: "Tüm Ayarlar",
|
app/locales/tw.ts
CHANGED
|
@@ -56,6 +56,17 @@ const tw: LocaleType = {
|
|
| 56 |
DeleteToast: "已刪除對話",
|
| 57 |
Revert: "撤銷",
|
| 58 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
Settings: {
|
| 60 |
Title: "設定",
|
| 61 |
SubTitle: "設定選項",
|
|
|
|
| 56 |
DeleteToast: "已刪除對話",
|
| 57 |
Revert: "撤銷",
|
| 58 |
},
|
| 59 |
+
User:{
|
| 60 |
+
Title: "用户",
|
| 61 |
+
SubTitle: "用户信息界面",
|
| 62 |
+
Actions: {
|
| 63 |
+
ClearAll: "清除所有数据",
|
| 64 |
+
ResetAll: "重置所有选项",
|
| 65 |
+
Close: "关闭",
|
| 66 |
+
ConfirmResetAll: "确认重置所有配置?",
|
| 67 |
+
ConfirmClearAll: "确认清除所有数据?",
|
| 68 |
+
},
|
| 69 |
+
},
|
| 70 |
Settings: {
|
| 71 |
Title: "設定",
|
| 72 |
SubTitle: "設定選項",
|
app/requests.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
| 6 |
useAccessStore,
|
| 7 |
useAppConfig,
|
| 8 |
useChatStore,
|
|
|
|
| 9 |
} from "./store";
|
| 10 |
import { showToast } from "./components/ui-lib";
|
| 11 |
import { ACCESS_CODE_PREFIX } from "./constant";
|
|
@@ -87,6 +88,8 @@ function getHeaders() {
|
|
| 87 |
);
|
| 88 |
}
|
| 89 |
|
|
|
|
|
|
|
| 90 |
return headers;
|
| 91 |
}
|
| 92 |
|
|
@@ -170,6 +173,21 @@ export async function requestUsage() {
|
|
| 170 |
};
|
| 171 |
}
|
| 172 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
export async function requestChatStream(
|
| 174 |
messages: Message[],
|
| 175 |
options?: {
|
|
@@ -180,6 +198,12 @@ export async function requestChatStream(
|
|
| 180 |
onController?: (controller: AbortController) => void;
|
| 181 |
},
|
| 182 |
) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
const Bot = useAppConfig.getState().bot;
|
| 184 |
if (Bot == "OpenAI") {
|
| 185 |
const req = makeRequestParam(messages, {
|
|
@@ -238,7 +262,6 @@ export async function requestChatStream(
|
|
| 238 |
break;
|
| 239 |
}
|
| 240 |
}
|
| 241 |
-
|
| 242 |
finish();
|
| 243 |
} else if (res.status === 401) {
|
| 244 |
console.error("Unauthorized");
|
|
@@ -267,7 +290,8 @@ export async function requestChatStream(
|
|
| 267 |
});
|
| 268 |
|
| 269 |
clearTimeout(reqTimeoutId);
|
| 270 |
-
|
|
|
|
| 271 |
const response = (await res.json()) as ChatImagesResponse;
|
| 272 |
options?.onMessage(
|
| 273 |
";
|
| 278 |
controller.abort();
|
|
|
|
|
|
|
|
|
|
|
|
|
| 279 |
} catch (err) {
|
| 280 |
console.error("NetWork Error", err);
|
| 281 |
options?.onMessage("请换一个问题试试吧", true);
|
|
@@ -295,8 +323,8 @@ export async function requestChatStream(
|
|
| 295 |
});
|
| 296 |
|
| 297 |
clearTimeout(reqTimeoutId);
|
| 298 |
-
|
| 299 |
-
|
| 300 |
// let responseText = "";
|
| 301 |
// for (let i = 1; i <= message.length; i++) {
|
| 302 |
// // handle time out, will stop if no response in 10 secs
|
|
@@ -307,6 +335,10 @@ export async function requestChatStream(
|
|
| 307 |
// }
|
| 308 |
options?.onMessage(message, true);
|
| 309 |
controller.abort();
|
|
|
|
|
|
|
|
|
|
|
|
|
| 310 |
} catch (err) {
|
| 311 |
console.error("NetWork Error", err);
|
| 312 |
options?.onMessage("请换一个问题试试吧", true);
|
|
@@ -326,8 +358,13 @@ export async function requestChatStream(
|
|
| 326 |
});
|
| 327 |
|
| 328 |
clearTimeout(reqTimeoutId);
|
| 329 |
-
|
|
|
|
| 330 |
controller.abort();
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
} catch (err) {
|
| 332 |
console.error("NetWork Error", err);
|
| 333 |
options?.onMessage("请换一个问题试试吧", true);
|
|
@@ -407,7 +444,6 @@ export async function requestChatStream(
|
|
| 407 |
break;
|
| 408 |
}
|
| 409 |
}
|
| 410 |
-
|
| 411 |
finish();
|
| 412 |
} else if (res.status === 401) {
|
| 413 |
console.error("Unauthorized");
|
|
|
|
| 6 |
useAccessStore,
|
| 7 |
useAppConfig,
|
| 8 |
useChatStore,
|
| 9 |
+
useUserStore,
|
| 10 |
} from "./store";
|
| 11 |
import { showToast } from "./components/ui-lib";
|
| 12 |
import { ACCESS_CODE_PREFIX } from "./constant";
|
|
|
|
| 88 |
);
|
| 89 |
}
|
| 90 |
|
| 91 |
+
headers.Auth=useAccessStore.getState().auth.trim()
|
| 92 |
+
|
| 93 |
return headers;
|
| 94 |
}
|
| 95 |
|
|
|
|
| 173 |
};
|
| 174 |
}
|
| 175 |
|
| 176 |
+
function updateWallet() {
|
| 177 |
+
fetch("/api/user/set?user="+useUserStore.getState().user+"&project=wallet&projectName=num&data=1",{
|
| 178 |
+
method:"GET",
|
| 179 |
+
headers:{
|
| 180 |
+
...getHeaders()
|
| 181 |
+
}
|
| 182 |
+
})
|
| 183 |
+
if(useUserStore.getState().wallet>0){
|
| 184 |
+
useUserStore.getState().updateWallet(1)
|
| 185 |
+
return true
|
| 186 |
+
}else{
|
| 187 |
+
return false
|
| 188 |
+
}
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
export async function requestChatStream(
|
| 192 |
messages: Message[],
|
| 193 |
options?: {
|
|
|
|
| 198 |
onController?: (controller: AbortController) => void;
|
| 199 |
},
|
| 200 |
) {
|
| 201 |
+
if(useUserStore.getState().vip_state=="未开通"){
|
| 202 |
+
if(!updateWallet()){
|
| 203 |
+
options?.onMessage("积分不足请充值或开通会员!", true);
|
| 204 |
+
return
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
const Bot = useAppConfig.getState().bot;
|
| 208 |
if (Bot == "OpenAI") {
|
| 209 |
const req = makeRequestParam(messages, {
|
|
|
|
| 262 |
break;
|
| 263 |
}
|
| 264 |
}
|
|
|
|
| 265 |
finish();
|
| 266 |
} else if (res.status === 401) {
|
| 267 |
console.error("Unauthorized");
|
|
|
|
| 290 |
});
|
| 291 |
|
| 292 |
clearTimeout(reqTimeoutId);
|
| 293 |
+
if(res.ok){
|
| 294 |
+
const reg = /^['|"](.*)['|"]$/;
|
| 295 |
const response = (await res.json()) as ChatImagesResponse;
|
| 296 |
options?.onMessage(
|
| 297 |
";
|
| 302 |
controller.abort();
|
| 303 |
+
}else if(res.status === 401){
|
| 304 |
+
console.error("Unauthorized");
|
| 305 |
+
options?.onError(new Error("Unauthorized"), res.status);
|
| 306 |
+
}
|
| 307 |
} catch (err) {
|
| 308 |
console.error("NetWork Error", err);
|
| 309 |
options?.onMessage("请换一个问题试试吧", true);
|
|
|
|
| 323 |
});
|
| 324 |
|
| 325 |
clearTimeout(reqTimeoutId);
|
| 326 |
+
if(res.ok){
|
| 327 |
+
let message = await res.text();
|
| 328 |
// let responseText = "";
|
| 329 |
// for (let i = 1; i <= message.length; i++) {
|
| 330 |
// // handle time out, will stop if no response in 10 secs
|
|
|
|
| 335 |
// }
|
| 336 |
options?.onMessage(message, true);
|
| 337 |
controller.abort();
|
| 338 |
+
}else if(res.status === 401){
|
| 339 |
+
console.error("Unauthorized");
|
| 340 |
+
options?.onError(new Error("Unauthorized"), res.status);
|
| 341 |
+
}
|
| 342 |
} catch (err) {
|
| 343 |
console.error("NetWork Error", err);
|
| 344 |
options?.onMessage("请换一个问题试试吧", true);
|
|
|
|
| 358 |
});
|
| 359 |
|
| 360 |
clearTimeout(reqTimeoutId);
|
| 361 |
+
if(res.ok){
|
| 362 |
+
options?.onMessage(await res.text(), true);
|
| 363 |
controller.abort();
|
| 364 |
+
}else if(res.status === 401){
|
| 365 |
+
console.error("Unauthorized");
|
| 366 |
+
options?.onError(new Error("Unauthorized"), res.status);
|
| 367 |
+
}
|
| 368 |
} catch (err) {
|
| 369 |
console.error("NetWork Error", err);
|
| 370 |
options?.onMessage("请换一个问题试试吧", true);
|
|
|
|
| 444 |
break;
|
| 445 |
}
|
| 446 |
}
|
|
|
|
| 447 |
finish();
|
| 448 |
} else if (res.status === 401) {
|
| 449 |
console.error("Unauthorized");
|
app/store/access.ts
CHANGED
|
@@ -7,14 +7,16 @@ import { ALL_MODELS } from "./config";
|
|
| 7 |
export interface AccessControlStore {
|
| 8 |
accessCode: string;
|
| 9 |
token: string;
|
|
|
|
| 10 |
|
| 11 |
-
needCode:
|
| 12 |
hideUserApiKey: boolean;
|
| 13 |
openaiUrl: string;
|
| 14 |
|
| 15 |
updateToken: (_: string) => void;
|
| 16 |
updateCode: (_: string) => void;
|
| 17 |
-
|
|
|
|
| 18 |
isAuthorized: () => boolean;
|
| 19 |
fetch: () => void;
|
| 20 |
}
|
|
@@ -25,9 +27,10 @@ export const useAccessStore = create<AccessControlStore>()(
|
|
| 25 |
persist(
|
| 26 |
(set, get) => ({
|
| 27 |
token: "",
|
|
|
|
| 28 |
accessCode: "",
|
| 29 |
-
needCode:
|
| 30 |
-
hideUserApiKey:
|
| 31 |
openaiUrl: "/api/openai/",
|
| 32 |
|
| 33 |
enabledAccessControl() {
|
|
@@ -41,11 +44,14 @@ export const useAccessStore = create<AccessControlStore>()(
|
|
| 41 |
updateToken(token: string) {
|
| 42 |
set(() => ({ token }));
|
| 43 |
},
|
|
|
|
|
|
|
|
|
|
| 44 |
isAuthorized() {
|
| 45 |
get().fetch();
|
| 46 |
// has token or has code or disabled access control
|
| 47 |
return (
|
| 48 |
-
!!get().token || !!get().accessCode || !get().enabledAccessControl()
|
| 49 |
);
|
| 50 |
},
|
| 51 |
fetch() {
|
|
|
|
| 7 |
export interface AccessControlStore {
|
| 8 |
accessCode: string;
|
| 9 |
token: string;
|
| 10 |
+
auth: string;
|
| 11 |
|
| 12 |
+
needCode: number;
|
| 13 |
hideUserApiKey: boolean;
|
| 14 |
openaiUrl: string;
|
| 15 |
|
| 16 |
updateToken: (_: string) => void;
|
| 17 |
updateCode: (_: string) => void;
|
| 18 |
+
updateAuth: (_: string) => void;
|
| 19 |
+
enabledAccessControl: () => number;
|
| 20 |
isAuthorized: () => boolean;
|
| 21 |
fetch: () => void;
|
| 22 |
}
|
|
|
|
| 27 |
persist(
|
| 28 |
(set, get) => ({
|
| 29 |
token: "",
|
| 30 |
+
auth: "",
|
| 31 |
accessCode: "",
|
| 32 |
+
needCode: 0,
|
| 33 |
+
hideUserApiKey: true,
|
| 34 |
openaiUrl: "/api/openai/",
|
| 35 |
|
| 36 |
enabledAccessControl() {
|
|
|
|
| 44 |
updateToken(token: string) {
|
| 45 |
set(() => ({ token }));
|
| 46 |
},
|
| 47 |
+
updateAuth(token: string) {
|
| 48 |
+
set(() => ({ auth:token }));
|
| 49 |
+
},
|
| 50 |
isAuthorized() {
|
| 51 |
get().fetch();
|
| 52 |
// has token or has code or disabled access control
|
| 53 |
return (
|
| 54 |
+
!!get().token || !!get().accessCode || !!get().enabledAccessControl() || !!get().auth
|
| 55 |
);
|
| 56 |
},
|
| 57 |
fetch() {
|
app/store/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
export * from "./chat";
|
|
|
|
| 2 |
export * from "./update";
|
| 3 |
export * from "./access";
|
| 4 |
export * from "./config";
|
|
|
|
| 1 |
export * from "./chat";
|
| 2 |
+
export * from "./user";
|
| 3 |
export * from "./update";
|
| 4 |
export * from "./access";
|
| 5 |
export * from "./config";
|
app/store/user.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { create } from "zustand";
|
| 2 |
+
import { persist } from "zustand/middleware";
|
| 3 |
+
import { StoreKey } from "../constant";
|
| 4 |
+
import { showToast } from "../components/ui-lib";
|
| 5 |
+
import { useAccessStore } from "./access";
|
| 6 |
+
|
| 7 |
+
function getHeaders() {
|
| 8 |
+
let headers: Record<string, string> = {};
|
| 9 |
+
headers.Auth=useAccessStore.getState().auth.trim()
|
| 10 |
+
return headers;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
export interface shuixianRes{
|
| 14 |
+
code: number,
|
| 15 |
+
msg: string,
|
| 16 |
+
token: string,
|
| 17 |
+
data:{
|
| 18 |
+
name:string,
|
| 19 |
+
head:string,
|
| 20 |
+
signatrue:string,
|
| 21 |
+
wallet:number,
|
| 22 |
+
vip_state:string,
|
| 23 |
+
vip_time_stmp:string,
|
| 24 |
+
ban:string,
|
| 25 |
+
sig_state:string,
|
| 26 |
+
title:string,
|
| 27 |
+
mail:string
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
export interface UserStore {
|
| 32 |
+
user:string;
|
| 33 |
+
password:string;
|
| 34 |
+
name:string;
|
| 35 |
+
wallet:number;
|
| 36 |
+
vip_state:string;
|
| 37 |
+
vip_time_stmp:string;
|
| 38 |
+
mail:string;
|
| 39 |
+
sig_state:string;
|
| 40 |
+
head:string;
|
| 41 |
+
update: (updater: (user: UserInfo) => void) => void;
|
| 42 |
+
login: (userName:string,password:string) => void;
|
| 43 |
+
register: (user:string,password:string,name:string,mail:string,code:string) => void;
|
| 44 |
+
getMailCode: (user:string,mail:string) => void;
|
| 45 |
+
userSig: () => void;
|
| 46 |
+
reset: () => void;
|
| 47 |
+
updateUser: (user:string) => void;
|
| 48 |
+
updatePassword: (password:string) => void;
|
| 49 |
+
updateInfo: (
|
| 50 |
+
name:string,
|
| 51 |
+
wallet:number,
|
| 52 |
+
vip_state:string,
|
| 53 |
+
vip_time_stmp:string,
|
| 54 |
+
mail:string,
|
| 55 |
+
sig_state:string,
|
| 56 |
+
head:string) => void;
|
| 57 |
+
updateWallet:(wallet:number) => void;
|
| 58 |
+
updateName:(name:string) => void;
|
| 59 |
+
getUserInfo:() => void;
|
| 60 |
+
findpwd:(user:string) => void;
|
| 61 |
+
useKami:(code:string) => void;
|
| 62 |
+
}
|
| 63 |
+
export const DEFAULT_USER = {
|
| 64 |
+
user:"",
|
| 65 |
+
password:"",
|
| 66 |
+
name:"",
|
| 67 |
+
wallet:0,
|
| 68 |
+
vip_state:"",
|
| 69 |
+
vip_time_stmp:"",
|
| 70 |
+
mail:"",
|
| 71 |
+
sig_state:"",
|
| 72 |
+
head:""
|
| 73 |
+
}
|
| 74 |
+
export type UserInfo = typeof DEFAULT_USER;
|
| 75 |
+
export const useUserStore = create<UserStore>()(
|
| 76 |
+
persist(
|
| 77 |
+
(set, get) => ({
|
| 78 |
+
...DEFAULT_USER,
|
| 79 |
+
update(updater) {
|
| 80 |
+
const config = { ...get() };
|
| 81 |
+
updater(config);
|
| 82 |
+
set(() => config);
|
| 83 |
+
},
|
| 84 |
+
updateInfo(
|
| 85 |
+
name:string,
|
| 86 |
+
wallet:number,
|
| 87 |
+
vip_state:string,
|
| 88 |
+
vip_time_stmp:string,
|
| 89 |
+
mail:string,
|
| 90 |
+
sig_state:string,
|
| 91 |
+
head:string){
|
| 92 |
+
set(()=>({
|
| 93 |
+
name:name,
|
| 94 |
+
wallet:wallet,
|
| 95 |
+
vip_state:vip_state,
|
| 96 |
+
vip_time_stmp:vip_time_stmp,
|
| 97 |
+
mail:mail,
|
| 98 |
+
sig_state:sig_state,
|
| 99 |
+
head:head
|
| 100 |
+
}))
|
| 101 |
+
},
|
| 102 |
+
reset() {
|
| 103 |
+
set(() => ({ ...DEFAULT_USER }));
|
| 104 |
+
},
|
| 105 |
+
updateUser(user:string){
|
| 106 |
+
set(() => ({ user:user }));
|
| 107 |
+
},
|
| 108 |
+
async updateName(name:string){
|
| 109 |
+
let res=await fetch("/api/user/set?user="+get().user+"&project=name&projectName=name&data="+name,{
|
| 110 |
+
method: "GET",
|
| 111 |
+
headers:{
|
| 112 |
+
...getHeaders()
|
| 113 |
+
}
|
| 114 |
+
});
|
| 115 |
+
let response = await res.json() as shuixianRes
|
| 116 |
+
console.log(response)
|
| 117 |
+
showToast(response.msg)
|
| 118 |
+
if(response.code==1){
|
| 119 |
+
await this.getUserInfo()
|
| 120 |
+
}
|
| 121 |
+
},
|
| 122 |
+
updatePassword(password:string){
|
| 123 |
+
set(() => ({ password:password }));
|
| 124 |
+
},
|
| 125 |
+
updateWallet(wallet:number){
|
| 126 |
+
set(() => ({ wallet:get().wallet-wallet }));
|
| 127 |
+
},
|
| 128 |
+
async login(user, password) {
|
| 129 |
+
let res=await fetch("/api/user/login?user="+user+"&password="+password,{
|
| 130 |
+
method: "GET"
|
| 131 |
+
});
|
| 132 |
+
let response = await res.json() as shuixianRes
|
| 133 |
+
console.log(response)
|
| 134 |
+
if(response.code=1){
|
| 135 |
+
useUserStore.getState().updateUser(user)
|
| 136 |
+
useUserStore.getState().updatePassword(password)
|
| 137 |
+
useAccessStore.getState().updateAuth(response.token)
|
| 138 |
+
window.location.href="/#/chat"
|
| 139 |
+
await this.getUserInfo()
|
| 140 |
+
}else{
|
| 141 |
+
showToast(response.msg)
|
| 142 |
+
}
|
| 143 |
+
},
|
| 144 |
+
async register(user, password, name, mail, code) {
|
| 145 |
+
let res=await fetch("/api/user/register?user="+user+"&password="+password+"&name="+name+"&mail="+mail+"&code="+code,{
|
| 146 |
+
method: "GET"
|
| 147 |
+
});
|
| 148 |
+
let response = await res.json() as shuixianRes
|
| 149 |
+
console.log(response)
|
| 150 |
+
if(response.code=1){
|
| 151 |
+
showToast(response.msg)
|
| 152 |
+
window.location.href="/#/login"
|
| 153 |
+
}else{
|
| 154 |
+
showToast(response.msg)
|
| 155 |
+
}
|
| 156 |
+
},
|
| 157 |
+
async getMailCode(user:string,mail:string) {
|
| 158 |
+
let res=await fetch("/api/user/mail?user="+user+"&mail="+mail,{
|
| 159 |
+
method: "GET"
|
| 160 |
+
});
|
| 161 |
+
let response = await res.json() as shuixianRes
|
| 162 |
+
console.log(response)
|
| 163 |
+
showToast(response.msg)
|
| 164 |
+
},
|
| 165 |
+
async userSig() {
|
| 166 |
+
let res=await fetch("/api/user/sig?user="+get().user+"&password="+get().password,{
|
| 167 |
+
method: "GET",
|
| 168 |
+
headers:{
|
| 169 |
+
...getHeaders()
|
| 170 |
+
}
|
| 171 |
+
});
|
| 172 |
+
let response = await res.json() as shuixianRes
|
| 173 |
+
console.log(response)
|
| 174 |
+
showToast(response.msg)
|
| 175 |
+
if(response.code==1){
|
| 176 |
+
await this.getUserInfo()
|
| 177 |
+
}
|
| 178 |
+
},
|
| 179 |
+
async getUserInfo() {
|
| 180 |
+
let resdata=await fetch("/api/user/info?user="+get().user+"&password="+get().password,{
|
| 181 |
+
method: "GET",
|
| 182 |
+
headers:{
|
| 183 |
+
...getHeaders()
|
| 184 |
+
}
|
| 185 |
+
});
|
| 186 |
+
let responsedata=await resdata.json() as shuixianRes
|
| 187 |
+
let data=responsedata.data
|
| 188 |
+
this.updateInfo(data.name,data.wallet,data.vip_state,data.vip_time_stmp,data.mail,data.sig_state,data.head)
|
| 189 |
+
},
|
| 190 |
+
async findpwd(user) {
|
| 191 |
+
let res=await fetch("/api/user/findpwd?user="+user,{
|
| 192 |
+
method: "GET",
|
| 193 |
+
headers:{
|
| 194 |
+
...getHeaders()
|
| 195 |
+
}
|
| 196 |
+
});
|
| 197 |
+
let response = await res.json() as shuixianRes
|
| 198 |
+
console.log(response)
|
| 199 |
+
if(response.code==1){
|
| 200 |
+
showToast("密码已发送至您的邮箱,请注意查收!")
|
| 201 |
+
}else{
|
| 202 |
+
showToast(response.msg)
|
| 203 |
+
}
|
| 204 |
+
},
|
| 205 |
+
async useKami(code) {
|
| 206 |
+
let res=await fetch("/api/user/kami?user="+get().user+"&password="+get().password+"&code="+code,{
|
| 207 |
+
method: "GET",
|
| 208 |
+
headers:{
|
| 209 |
+
...getHeaders()
|
| 210 |
+
}
|
| 211 |
+
});
|
| 212 |
+
let response = await res.json() as shuixianRes
|
| 213 |
+
console.log(response)
|
| 214 |
+
if(response.code==1){
|
| 215 |
+
showToast(response.msg)
|
| 216 |
+
await this.getUserInfo()
|
| 217 |
+
}else{
|
| 218 |
+
showToast(response.msg)
|
| 219 |
+
}
|
| 220 |
+
},
|
| 221 |
+
}),
|
| 222 |
+
{
|
| 223 |
+
name: StoreKey.User,
|
| 224 |
+
version: 1,
|
| 225 |
+
},
|
| 226 |
+
),
|
| 227 |
+
);
|