Merge pull request #79 from sijinhui/dev

Dev
This commit is contained in:
sijinhui 2024-04-29 23:12:22 +08:00 committed by GitHub
commit c9b3ef8b94
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 164 additions and 106 deletions

View File

@ -95,7 +95,16 @@ async function handle(
if (method === "PUT") {
try {
const userId = params.path[0];
return await changeUserInfo(userId, await req.json());
let new_user_info: Partial<User> = Object.entries(
await req.json(),
).reduce((acc, [key, value]) => {
if (value !== null) {
// @ts-ignore
acc[key] = value;
}
return acc;
}, {});
return await changeUserInfo(userId, new_user_info);
} catch {
return NextResponse.json({ error: "未知错误" }, { status: 500 });
}
@ -103,16 +112,18 @@ async function handle(
return NextResponse.json({ error: "当前方法不支持" }, { status: 405 });
}
async function changeUserInfo(id: string, info: User) {
const hashDPassword = hashPassword(info?.password ?? "");
console.log("-----------", id, info, hashDPassword);
if (hashDPassword) {
async function changeUserInfo(id: string, info: Partial<User>) {
if (info.password) {
info["password"] = hashPassword(info.password);
}
// console.log("-----------", id, info, hashDPassword);
if (info) {
await prisma.user.update({
where: {
id: id,
},
data: {
password: hashDPassword,
...info,
},
});
return NextResponse.json({ result: "ok" });

10
app/api/test/route.ts Normal file
View File

@ -0,0 +1,10 @@
import { NextRequest, NextResponse } from "next/server";
async function handle(
req: NextRequest,
{ params }: { params: { path: string[] } },
) {
return NextResponse.json({});
}
export const GET = handle;

View File

@ -20,13 +20,13 @@ function SettingForm() {
const [form] = Form.useForm();
const [setting, setSetting] = useState<Setting[]>([]);
const [isModalVisible, setIsModalVisible] = useState(false);
const openModal = () => setIsModalVisible(true);
const closeModal = () => setIsModalVisible(false);
const handleFormSubmit = async (record: Setting) => {
console.log("-------", record);
};
// const [isModalVisible, setIsModalVisible] = useState(false);
// const openModal = () => setIsModalVisible(true);
// const closeModal = () => setIsModalVisible(false);
//
// const handleFormSubmit = async (record: Setting) => {
// console.log("-------", record);
// };
const handelDel = (record: Setting) => {
fetch(`/api/admin/setting/${record.key}`, {

View File

@ -5,20 +5,21 @@ import { User } from "@prisma/client";
import {
Space,
Table,
Tag,
Input,
Button,
notification,
Popconfirm,
notification as notificationModule,
Checkbox,
Modal,
Form,
} from "antd";
import type { GetRef, TableColumnsType } from "antd";
import { LockOutlined } from "@ant-design/icons";
// import { headers } from 'next/headers'
import type { NotificationArgsProps } from "antd";
import Highlighter from "react-highlight-words";
// import Highlighter from "react-highlight-words";
// 后期考虑删除该依赖
type NotificationPlacement = NotificationArgsProps["placement"];
// type NotificationPlacement = NotificationArgsProps["placement"];
import type { SearchProps } from "antd/es/input/Search";
@ -37,9 +38,6 @@ interface SearchTextProps {
setSearchText: Dispatch<SetStateAction<string>>;
}
type DataIndex = keyof User;
type InputRef = GetRef<typeof Input>;
function UserTableSearchInput({ users, setUsers, setLoading }: UserInterface) {
const [searchText, setSearchText] = useState("");
// 这里直接搜索,并获取数据不传递搜索的值给表格了。
@ -82,63 +80,114 @@ function UserTableSearchInput({ users, setUsers, setLoading }: UserInterface) {
}
function UsersTable({ users, setUsers, loading }: UserInterface) {
const [api, contextHolder] = notification.useNotification();
const [notification, notificationContextHolder] =
notificationModule.useNotification();
const [editUserModal, editUserModalContextHolder] = Modal.useModal();
const [editUserForm] = Form.useForm();
const [newPassword, setNewPassword] = useState("");
const handleUserEdit = (method: "POST" | "PUT", record: User | undefined) => {
editUserModal.confirm({
title: "编辑用户",
content: (
<Form
form={editUserForm}
labelCol={{ span: 7 }}
wrapperCol={{ span: 28 }}
layout="horizontal"
autoComplete="off"
initialValues={record}
preserve={false}
>
<Form.Item name="id" label="id" rules={[{ required: true }]}>
<Input disabled />
</Form.Item>
<Form.Item name="name" label="name">
<Input disabled />
</Form.Item>
<Form.Item name="username" label="username">
<Input autoComplete="off" />
</Form.Item>
<Form.Item name="gh_username" label="gh_username">
<Input disabled />
</Form.Item>
<Form.Item name="email" label="email">
<Input />
</Form.Item>
<Form.Item name="emailVerified" label="emailVerified">
<Input disabled />
</Form.Item>
<Form.Item name="createdAt" label="createdAt">
<Input disabled />
</Form.Item>
<Form.Item name="updatedAt" label="updatedAt">
<Input disabled />
</Form.Item>
<Form.Item
name="allowToLogin"
label="allowToLogin"
valuePropName="checked"
>
<Checkbox />
</Form.Item>
<Form.Item name="isAdmin" label="isAdmin" valuePropName="checked">
<Checkbox />
</Form.Item>
const newPasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// if ((e.nativeEvent as InputEvent).isComposing) {
// return;
// }
setNewPassword(e.target.value.trim());
};
const confirmPassword = async (id: string) => {
console.log("-----", newPassword, id);
try {
fetch(`/api/admin/users/${id}`, {
method: "put",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
password: newPassword,
}),
credentials: "include",
})
.then((response) => response.json())
.then((res) => {
if (res["result"] == "ok") {
openNotification("info", {
message: "修改密码",
description: `${id} 密码修改成功`,
<Form.Item name="password" label="password">
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"
placeholder="Password"
autoComplete="new-password"
/>
</Form.Item>
</Form>
),
onOk: () => {
const setting_key = method === "PUT" ? record?.id : "";
editUserForm.validateFields().then((values) => {
const dataToSubmit = {
username: values.username ?? null,
email: values.email ?? null,
allowToLogin: values.allowToLogin ?? true,
isAdmin: values.isAdmin ?? false,
password: values.password ?? null,
};
fetch(`/api/admin/users/${values.id}`, {
method: method,
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(dataToSubmit),
})
.then((response) => response.json())
.then((result) => {
if (result["result"] == "ok") {
openNotification("info", {
message: "修改信息",
description: `${values.id} 信息修改成功`,
});
}
})
.catch((error) => {
console.log("e", error);
openNotification("error", {
message: "修改信息",
description: `${values.id} 信息修改失败`,
});
});
}
})
.catch((error) => {
console.log("e", error);
openNotification("error", {
message: "修改密码",
description: `${id} 密码修改失败`,
});
});
} catch {
openNotification("error", {
message: "修改密码",
description: `${id} 密码修改失败`,
});
}
setNewPassword("");
},
});
};
const openNotification = (level: string, arms: NotificationArgsProps) => {
if (level === "error") {
api.error({
notification.error({
...arms,
placement: "topRight",
});
} else {
api.info({
notification.info({
...arms,
placement: "topRight",
});
@ -189,7 +238,7 @@ function UsersTable({ users, setUsers, loading }: UserInterface) {
render: (value) => getCurrentTime(new Date(value)),
},
{
title: "isAdmin",
title: "管理员",
dataIndex: "isAdmin",
width: 80,
render: (value) => {
@ -201,9 +250,9 @@ function UsersTable({ users, setUsers, loading }: UserInterface) {
},
},
{
title: "allowToLogin",
title: "允许登录",
dataIndex: "allowToLogin",
width: 120,
width: 80,
render: (value) => {
return (
<div>
@ -217,29 +266,13 @@ function UsersTable({ users, setUsers, loading }: UserInterface) {
dataIndex: "",
key: "id",
render: (_, record) => (
<Space size="middle">
{contextHolder}
<Popconfirm
id="user-admin-table-pop_confirm"
title="设置密码"
description={
<>
<Input.Password
autoComplete="new-password"
value={newPassword}
onCompositionStart={(e) => e.preventDefault()}
onChange={newPasswordChange}
/>
</>
}
onConfirm={() => confirmPassword(record.id)}
onOpenChange={() => console.log("open change")}
>
<Button type="primary" size="small">
</Button>
</Popconfirm>
<a onClick={() => handleDeleteUser(record)}></a>
<Space size="small">
<Button type="link" onClick={() => handleUserEdit("PUT", record)}>
</Button>
<Button type="link" onClick={() => handleDeleteUser(record)}>
</Button>
</Space>
),
},
@ -247,16 +280,20 @@ function UsersTable({ users, setUsers, loading }: UserInterface) {
// console.log(users, "users2");
return (
<Table
dataSource={users}
rowKey="id"
columns={columns}
loading={loading as boolean}
scroll={{
scrollToFirstRowOnChange: true,
y: 1080,
}}
/>
<>
{notificationContextHolder}
{editUserModalContextHolder}
<Table
dataSource={users}
rowKey="id"
columns={columns}
loading={loading as boolean}
scroll={{
scrollToFirstRowOnChange: true,
y: 1080,
}}
/>
</>
);
}

View File

@ -10,7 +10,7 @@ import {createTransport} from "nodemailer";
import { comparePassword, hashPassword } from "@/lib/utils";
import {getCurStartEnd} from "@/app/utils/custom";
const SECURE_COOKIES:boolean = !!process.env.SECURE_COOKIES;
type PartialUser = Partial<User>;
export const authOptions: NextAuthOptions = {
@ -89,7 +89,7 @@ export const authOptions: NextAuthOptions = {
// 判断姓名格式是否符合要求,不符合则拒绝
if (username && isName(username)) {
// Any object returned will be saved in `user` property of the JWT
let user: PartialUser = {}
let user: Partial<User> = {}
if (isEmail(username)) {
user['email'] = username;
} else {
@ -228,7 +228,7 @@ async function getSetting(key: string) {
}
}
async function existUser(user: PartialUser ) {
async function existUser(user: Partial<User> ) {
const conditions = [];
if (user?.name) {
conditions.push({ name: user.name });
@ -243,7 +243,7 @@ async function existUser(user: PartialUser ) {
}) : null
}
export async function insertUser(user: PartialUser ) {
export async function insertUser(user: Partial<User> ) {
console.log('------------', user)
try {
return await prisma.user.create({