Merge branch 'zh' into 'main'
feat(header): modify_password See merge request prism/lable/labelmain!25
This commit is contained in:
@@ -38,6 +38,15 @@ export const userEditById = (data: User.EditProps, id: number) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改用户密码
|
||||||
|
export const userModifyPassword = (data: User.ModifyPasswordProps) => {
|
||||||
|
return httpFetch({
|
||||||
|
url: BASE_LABEL_API + `/api/v1/label_server/user/modify_password`,
|
||||||
|
method: "PUT",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 编辑用户组织
|
// 编辑用户组织
|
||||||
export const userUpdateGroup = (data: User.UpdateGroupProps) => {
|
export const userUpdateGroup = (data: User.UpdateGroupProps) => {
|
||||||
return httpFetch({
|
return httpFetch({
|
||||||
@@ -65,16 +74,7 @@ export const userGroupAdd = (data: Organization.CreateProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 修改用户密码
|
// 修改用户密码
|
||||||
export const modifyUserPassword = (data: {
|
export const modifyUserPassword = userModifyPassword
|
||||||
old_password: string
|
|
||||||
new_password: string
|
|
||||||
}) => {
|
|
||||||
return httpFetch({
|
|
||||||
url: BASE_LABEL_API + "/api/v1/label_server/user/modify_password",
|
|
||||||
method: "PUT",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ****************************** Options ****************************** */
|
/* ****************************** Options ****************************** */
|
||||||
interface Option {
|
interface Option {
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ export namespace User {
|
|||||||
work_status?: number
|
work_status?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ModifyPasswordProps {
|
||||||
|
new_password: string
|
||||||
|
old_password: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface UpdateGroupProps {
|
export interface UpdateGroupProps {
|
||||||
user_id: number
|
user_id: number
|
||||||
group_uuid: string
|
group_uuid: string
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
Button,
|
||||||
AppShell,
|
AppShell,
|
||||||
Box,
|
Box,
|
||||||
Burger,
|
Burger,
|
||||||
Divider,
|
Divider,
|
||||||
Flex,
|
Flex,
|
||||||
|
Group,
|
||||||
|
Modal,
|
||||||
Menu,
|
Menu,
|
||||||
NavLink,
|
NavLink,
|
||||||
|
PasswordInput,
|
||||||
ScrollArea,
|
ScrollArea,
|
||||||
Space,
|
Space,
|
||||||
Stack,
|
Stack,
|
||||||
@@ -20,10 +24,13 @@ import {
|
|||||||
import Avvvatars from "avvvatars-react"
|
import Avvvatars from "avvvatars-react"
|
||||||
|
|
||||||
import { useDisclosure, useMediaQuery } from "@mantine/hooks"
|
import { useDisclosure, useMediaQuery } from "@mantine/hooks"
|
||||||
|
import { useForm } from "@mantine/form"
|
||||||
|
import { notifications } from "@mantine/notifications"
|
||||||
import {
|
import {
|
||||||
IconChevronDown,
|
IconChevronDown,
|
||||||
IconChevronLeft,
|
IconChevronLeft,
|
||||||
IconChevronRight,
|
IconChevronRight,
|
||||||
|
IconLock,
|
||||||
IconLogout,
|
IconLogout,
|
||||||
IconMoon,
|
IconMoon,
|
||||||
IconSun,
|
IconSun,
|
||||||
@@ -36,7 +43,14 @@ import headerLinkClasses from "./HeaderLink.module.css"
|
|||||||
import { useUserStore } from "@/app/store/user"
|
import { useUserStore } from "@/app/store/user"
|
||||||
import { usePathname, useRouter } from "next/navigation"
|
import { usePathname, useRouter } from "next/navigation"
|
||||||
import { usePermissionStore } from "../label/store/auth"
|
import { usePermissionStore } from "../label/store/auth"
|
||||||
|
import { userModifyPassword } from "../label/api/user"
|
||||||
import { deleteCookie } from "../login/api"
|
import { deleteCookie } from "../login/api"
|
||||||
|
import {
|
||||||
|
settingModalActionsClassName,
|
||||||
|
settingModalClassNames,
|
||||||
|
settingModalFormClassName,
|
||||||
|
settingModalMetaTextClassName,
|
||||||
|
} from "../setting/PageSurface"
|
||||||
import classes from "./AppLayout.module.css"
|
import classes from "./AppLayout.module.css"
|
||||||
import { MenuItem, withoutLayoutRoutes } from "./common"
|
import { MenuItem, withoutLayoutRoutes } from "./common"
|
||||||
import { ClientIcon } from "./components/ClientIcon"
|
import { ClientIcon } from "./components/ClientIcon"
|
||||||
@@ -149,6 +163,10 @@ export default function AppLayout({
|
|||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure()
|
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure()
|
||||||
|
const [
|
||||||
|
passwordModalOpened,
|
||||||
|
{ open: openPasswordModal, close: closePasswordModal },
|
||||||
|
] = useDisclosure(false)
|
||||||
|
|
||||||
const { updateIsOpen } = useAppLayoutStore.getState()
|
const { updateIsOpen } = useAppLayoutStore.getState()
|
||||||
const { isOpen } = useAppLayoutStore()
|
const { isOpen } = useAppLayoutStore()
|
||||||
@@ -178,6 +196,67 @@ export default function AppLayout({
|
|||||||
|
|
||||||
const { menuDefaultRouter } = useAppLayoutStore.getState()
|
const { menuDefaultRouter } = useAppLayoutStore.getState()
|
||||||
|
|
||||||
|
const passwordForm = useForm({
|
||||||
|
initialValues: {
|
||||||
|
old_password: "",
|
||||||
|
new_password: "",
|
||||||
|
confirm_new_password: "",
|
||||||
|
},
|
||||||
|
validate: {
|
||||||
|
old_password: (value) => (value ? null : "请输入当前密码"),
|
||||||
|
new_password: (value) => (value ? null : "请输入新密码"),
|
||||||
|
confirm_new_password: (value) => (value ? null : "请再次确认新密码"),
|
||||||
|
},
|
||||||
|
validateInputOnChange: true,
|
||||||
|
validateInputOnBlur: true,
|
||||||
|
clearInputErrorOnChange: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [passwordSubmitting, setPasswordSubmitting] = useState(false)
|
||||||
|
|
||||||
|
const handleOpenPasswordModal = () => {
|
||||||
|
passwordForm.reset()
|
||||||
|
openPasswordModal()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClosePasswordModal = () => {
|
||||||
|
passwordForm.reset()
|
||||||
|
closePasswordModal()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePasswordSubmit = passwordForm.onSubmit(async (values) => {
|
||||||
|
if (values.new_password !== values.confirm_new_password) {
|
||||||
|
passwordForm.setFieldError(
|
||||||
|
"confirm_new_password",
|
||||||
|
"两次输入的新密码不一致"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setPasswordSubmitting(true)
|
||||||
|
try {
|
||||||
|
await userModifyPassword({
|
||||||
|
old_password: values.old_password,
|
||||||
|
new_password: values.new_password,
|
||||||
|
})
|
||||||
|
handleClosePasswordModal()
|
||||||
|
notifications.show({
|
||||||
|
color: "green",
|
||||||
|
title: "修改成功",
|
||||||
|
message: "密码已更新",
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
notifications.show({
|
||||||
|
color: "red",
|
||||||
|
title: "修改失败",
|
||||||
|
message:
|
||||||
|
error instanceof Error ? error.message : "密码修改失败,请重试",
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
setPasswordSubmitting(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const headItems = menu.map((item) => (
|
const headItems = menu.map((item) => (
|
||||||
<a
|
<a
|
||||||
key={item.url}
|
key={item.url}
|
||||||
@@ -374,6 +453,11 @@ export default function AppLayout({
|
|||||||
</Box>
|
</Box>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Label>操作</Menu.Label>
|
<Menu.Label>操作</Menu.Label>
|
||||||
|
<Menu.Item
|
||||||
|
leftSection={<IconLock size={14} />}
|
||||||
|
onClick={handleOpenPasswordModal}>
|
||||||
|
修改密码
|
||||||
|
</Menu.Item>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
leftSection={<IconLogout size={14} />}
|
leftSection={<IconLogout size={14} />}
|
||||||
onClick={handleLogout}>
|
onClick={handleLogout}>
|
||||||
@@ -381,6 +465,54 @@ export default function AppLayout({
|
|||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu.Dropdown>
|
</Menu.Dropdown>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
<Modal
|
||||||
|
opened={passwordModalOpened}
|
||||||
|
onClose={handleClosePasswordModal}
|
||||||
|
title="修改密码"
|
||||||
|
centered
|
||||||
|
size={440}
|
||||||
|
classNames={settingModalClassNames}>
|
||||||
|
<form onSubmit={handlePasswordSubmit}>
|
||||||
|
<Stack gap={12} className={settingModalFormClassName}>
|
||||||
|
<Text className={settingModalMetaTextClassName}>
|
||||||
|
请输入当前密码,并再次确认新密码后提交修改。
|
||||||
|
</Text>
|
||||||
|
<PasswordInput
|
||||||
|
withAsterisk
|
||||||
|
data-autofocus
|
||||||
|
label="当前密码"
|
||||||
|
placeholder="请输入当前密码"
|
||||||
|
{...passwordForm.getInputProps("old_password")}
|
||||||
|
/>
|
||||||
|
<PasswordInput
|
||||||
|
withAsterisk
|
||||||
|
label="新密码"
|
||||||
|
placeholder="请输入新密码"
|
||||||
|
{...passwordForm.getInputProps("new_password")}
|
||||||
|
/>
|
||||||
|
<PasswordInput
|
||||||
|
withAsterisk
|
||||||
|
label="确认新密码"
|
||||||
|
placeholder="请再次输入新密码"
|
||||||
|
{...passwordForm.getInputProps("confirm_new_password")}
|
||||||
|
/>
|
||||||
|
<Group
|
||||||
|
justify="flex-end"
|
||||||
|
gap={12}
|
||||||
|
className={settingModalActionsClassName}>
|
||||||
|
<Button
|
||||||
|
variant="default"
|
||||||
|
onClick={handleClosePasswordModal}
|
||||||
|
type="button">
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" loading={passwordSubmitting}>
|
||||||
|
确认修改
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</form>
|
||||||
|
</Modal>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</AppShell.Header>
|
</AppShell.Header>
|
||||||
|
|||||||
Reference in New Issue
Block a user