From 94958d1c83b43ee8f176ed76a01bf8d5b5f016c8 Mon Sep 17 00:00:00 2001 From: lq1405 <2769838458@qq.com> Date: Thu, 6 Feb 2025 15:09:29 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E9=87=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.tsx | 4 +- src/components/Icon/DiceIcon.tsx | 15 +++++ src/pages/User/UserCenter/UserCenter.tsx | 6 +- .../UserCenterAgentMessage/index.tsx | 8 +-- .../User/UserManage/ModifyUser/index.tsx | 6 +- .../UserManagement/ResetUserPassword.tsx | 58 +++++++++++++++++++ .../User/UserManage/UserManagement/index.tsx | 36 ++++++++++-- src/services/services/user.ts | 24 +++++++- src/util/password.ts | 25 ++++++++ 9 files changed, 164 insertions(+), 18 deletions(-) create mode 100644 src/components/Icon/DiceIcon.tsx create mode 100644 src/pages/User/UserManage/UserManagement/ResetUserPassword.tsx create mode 100644 src/util/password.ts diff --git a/src/app.tsx b/src/app.tsx index 03c5bdc..d2e09d2 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -6,7 +6,7 @@ import type { RunTimeLayoutConfig } from '@umijs/max'; import { history, Link, request as q } from '@umijs/max'; import defaultSettings from '../config/defaultSettings'; import { errorConfig } from './requestErrorConfig'; -import { GetUserInfo, getCurrentUser as queryCurrentUser } from './services/services/user'; +import { UserInfo, getCurrentUser as queryCurrentUser } from './services/services/user'; import React, { useEffect, useState } from 'react'; import { TokenStorage } from './services/define/tokenStorage'; import { App, ConfigProvider } from 'antd'; @@ -46,7 +46,7 @@ export async function getInitialState(): Promise<{ }; const GetUsrInfo = async (id: number) => { - const userInfo = await GetUserInfo(id); + const userInfo = await UserInfo.GetUserInfo(id); return userInfo; } diff --git a/src/components/Icon/DiceIcon.tsx b/src/components/Icon/DiceIcon.tsx new file mode 100644 index 0000000..58ebd02 --- /dev/null +++ b/src/components/Icon/DiceIcon.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import Icon from '@ant-design/icons' +import { AntdIconProps } from '@ant-design/icons/lib/components/AntdIcon'; + +const DiceIcon: React.FC = (props) => { + let ico = ; + return ( + ( + ico + )} /> + + ); +}; +export default DiceIcon; \ No newline at end of file diff --git a/src/pages/User/UserCenter/UserCenter.tsx b/src/pages/User/UserCenter/UserCenter.tsx index cff43d0..e303b16 100644 --- a/src/pages/User/UserCenter/UserCenter.tsx +++ b/src/pages/User/UserCenter/UserCenter.tsx @@ -1,5 +1,5 @@ import TemplateContainer from '@/pages/TemplateContainer'; -import { GetUserAgentInfo, GetUserInfo } from '@/services/services/user'; +import { UserInfo } from '@/services/services/user'; import { RedoOutlined } from '@ant-design/icons'; import { useModel } from '@umijs/max'; import { Avatar, Badge, Button, Card, Col, FloatButton, Input, message, Modal, Row, Spin, Tag } from 'antd'; @@ -23,10 +23,10 @@ const UserCenter: React.FC = () => { // 初始化加载用户信息 setTopSpinning(true); setTopSpinTip("正在获取用户信息。。。"); - GetUserInfo(initialState?.currentUser?.id).then(async (res) => { + UserInfo.GetUserInfo(initialState?.currentUser?.id).then(async (res) => { setInitialState({ ...initialState, currentUser: res }); localStorage.setItem('userInfo', JSON.stringify(res)); - let agentInfo = await GetUserAgentInfo(); + let agentInfo = await UserInfo.GetUserAgentInfo(); setUserAgentUserInfo(agentInfo); }).catch((error) => { messageApi.error(error.message); diff --git a/src/pages/User/UserCenter/UserCenterAgentMessage/index.tsx b/src/pages/User/UserCenter/UserCenterAgentMessage/index.tsx index 15aee3a..f47afc2 100644 --- a/src/pages/User/UserCenter/UserCenterAgentMessage/index.tsx +++ b/src/pages/User/UserCenter/UserCenterAgentMessage/index.tsx @@ -5,7 +5,7 @@ import renderTitle from '../UserRenderList'; import { isEmpty } from 'lodash'; import { useModel } from '@umijs/max'; import { useSoftStore } from '@/store/software'; -import { EnableAgent, GetUserAgentInfo, GetUserInfo } from '@/services/services/user'; +import { UserInfo } from '@/services/services/user'; type UserCenterAgentMessageProps = { userAgentUserInfo: UserModel.UserAgentInfo | undefined; @@ -28,15 +28,15 @@ const UserCenterAgentMessage: React.FC = ({ userAge setTopSpinTip("正在启用代理。。。"); // 开始调用启用代理的接口 try { - await EnableAgent(); + await UserInfo.EnableAgent(); messageApi.success("启用代理成功"); // 冲i性能加载用户信息 if (initialState?.currentUser?.id) { - let res = await GetUserInfo(initialState?.currentUser?.id); + let res = await UserInfo.GetUserInfo(initialState?.currentUser?.id); localStorage.setItem('userInfo', JSON.stringify(res)); setInitialState({ ...initialState, currentUser: res }); // 重新加载代理信息 - let agentInfo = await GetUserAgentInfo(); + let agentInfo = await UserInfo.GetUserAgentInfo(); setUserAgentUserInfo(agentInfo); } } catch (error: any) { diff --git a/src/pages/User/UserManage/ModifyUser/index.tsx b/src/pages/User/UserManage/ModifyUser/index.tsx index 32107cf..9bf847f 100644 --- a/src/pages/User/UserManage/ModifyUser/index.tsx +++ b/src/pages/User/UserManage/ModifyUser/index.tsx @@ -1,5 +1,5 @@ import { QueryRoleOption } from '@/services/services/role'; -import { GetUserInfo, UpdatedUserInfo } from '@/services/services/user'; +import { UserInfo } from '@/services/services/user'; import { FormatDate } from '@/util/time'; import { useModel } from '@umijs/max'; import { Button, Col, Form, FormInstance, Input, InputNumber, message, Row, Select, SelectProps, Spin, Tag } from 'antd'; @@ -38,7 +38,7 @@ const ModifyUser: React.FC = ({ userId, setFormRef, open }) => setLoading(false); }) - GetUserInfo(userId).then((res) => { + UserInfo.GetUserInfo(userId).then((res) => { let tempRes = { ...res, createdDate: FormatDate(res.createdDate) @@ -55,7 +55,7 @@ const ModifyUser: React.FC = ({ userId, setFormRef, open }) => setLoading(true); setSpinTip("修改中..."); try { - await UpdatedUserInfo(values); + await UserInfo.UpdatedUserInfo(values); messageApi.success("用户修改成功"); } catch (error: any) { messageApi.error(error.message); diff --git a/src/pages/User/UserManage/UserManagement/ResetUserPassword.tsx b/src/pages/User/UserManage/UserManagement/ResetUserPassword.tsx new file mode 100644 index 0000000..e24ad8a --- /dev/null +++ b/src/pages/User/UserManage/UserManagement/ResetUserPassword.tsx @@ -0,0 +1,58 @@ +import React, { useState } from 'react'; +import { Form, Input, Button, message, Tooltip } from 'antd'; +import DiceIcon from '@/components/Icon/DiceIcon'; +import { generateRandomPassword } from '@/util/password'; +import { set, toArray } from 'lodash'; +import { useSoftStore } from '@/store/software'; +import { UserInfo } from '@/services/services/user'; + +interface ResetUserPasswordProps { + userId: number; +} + +const ResetUserPassword: React.FC = ({ userId }) => { + const [newPassword, setNewPassword] = useState(''); + const [messageApi, messageHolder] = message.useMessage(); + const { setTopSpinning, setTopSpinTip } = useSoftStore(); + + return ( +
+ setNewPassword(e.target.value)} + placeholder="请输入新密码" + /> + + + {messageHolder} +
+ ); +}; + +export default ResetUserPassword; \ No newline at end of file diff --git a/src/pages/User/UserManage/UserManagement/index.tsx b/src/pages/User/UserManage/UserManagement/index.tsx index 9acbd59..c80e9fd 100644 --- a/src/pages/User/UserManage/UserManagement/index.tsx +++ b/src/pages/User/UserManage/UserManagement/index.tsx @@ -1,7 +1,7 @@ import { useFormReset } from "@/hooks/useFormReset"; import TemplateContainer from "@/pages/TemplateContainer"; import { QueryRoleOption } from "@/services/services/role"; -import { QueryUserList } from "@/services/services/user"; +import { UserInfo } from "@/services/services/user"; import { FormatDate } from "@/util/time"; import { useAccess, useModel } from "@umijs/max"; import { Button, Dropdown, Form, Input, InputNumber, message, Modal, Select, SelectProps, Table, Tag, Tooltip } from "antd"; @@ -9,8 +9,12 @@ import { ColumnsType, TablePaginationConfig } from "antd/es/table"; import { FilterValue, SorterResult, TableCurrentDataSource } from "antd/es/table/interface"; import { useEffect, useState } from "react"; import ModifyUser from "../ModifyUser"; -import { DeleteOutlined, EditOutlined, MenuOutlined, SyncOutlined } from "@ant-design/icons"; +import Icon, { DeleteOutlined, EditOutlined, KeyOutlined, MenuOutlined, SyncOutlined } from "@ant-design/icons"; import { SoftwareControl } from "@/services/services/software"; +import { CustomIconComponentProps } from "@ant-design/icons/lib/components/Icon"; +import DiceIcon from "@/components/Icon/DiceIcon"; +import { generateRandomPassword } from "@/util/password"; +import ResetUserPassword from "./ResetUserPassword"; const UserManagement: React.FC = () => { type TagRender = SelectProps['tagRender']; @@ -33,6 +37,7 @@ const UserManagement: React.FC = () => { const [userId, setUserId] = useState(0); const [openModal, setOpenModal] = useState(false); const [roleNames, setRoleNames] = useState([]); + const [modal, modaltHolder] = Modal.useModal(); @@ -48,7 +53,7 @@ const UserManagement: React.FC = () => { messageApi.error(error.message); }) - QueryUserList(tableParams, form.getFieldsValue()) + UserInfo.QueryUserList(tableParams, form.getFieldsValue()) .then((res) => { setData(res.collection); setTableParams({ @@ -71,7 +76,7 @@ const UserManagement: React.FC = () => { setLoading(true); try { let tableParamsParams = pagination ? { pagination } : tableParams; - let res = await QueryUserList(tableParamsParams, params ?? form.getFieldsValue()); + let res = await UserInfo.QueryUserList(tableParamsParams, params ?? form.getFieldsValue()); setData(res.collection); setTableParams({ pagination: { @@ -89,7 +94,7 @@ const UserManagement: React.FC = () => { async function handleTableChange(pagination: TablePaginationConfig, filters: Record, sorter: SorterResult | SorterResult[], extra: TableCurrentDataSource): Promise { setLoading(true); try { - let queryUser = await QueryUserList({ pagination }, form.getFieldsValue()); + let queryUser = await UserInfo.QueryUserList({ pagination }, form.getFieldsValue()); setData(queryUser.collection); setTableParams({ pagination: { @@ -136,6 +141,17 @@ const UserManagement: React.FC = () => { ); }; + + async function ResetUserPasswordFunc(userId: number) { + modal.info({ + title: '重置密码', + width: 500, + closable: true, + content: , + footer: null + }); + } + /** * 给指定用户申请软件控制权限 * @param userId 用户ID @@ -246,6 +262,15 @@ const UserManagement: React.FC = () => { setOpenModal(true); } }, + { + key: 'resetPassword', + label: '重置密码', + icon: , + hidden: !access.isSuperAdmin, + onClick: async () => { + await ResetUserPasswordFunc(record.id); + } + }, { key: 'apply', label: '初始化权限', @@ -344,6 +369,7 @@ const UserManagement: React.FC = () => { {messageHolder} + {modaltHolder} ); }; diff --git a/src/services/services/user.ts b/src/services/services/user.ts index 4707f53..393b87a 100644 --- a/src/services/services/user.ts +++ b/src/services/services/user.ts @@ -91,6 +91,10 @@ async function EnableAgent() { } } +/** + * 获取用户的代理信息 + * @returns + */ async function GetUserAgentInfo(): Promise { let res = await request>(`/lms/User/GetUserAgentInfo`, { method: 'GET', @@ -101,10 +105,28 @@ async function GetUserAgentInfo(): Promise { return res.data; } -export { +/** + * 重置指定用户的用户名和密码 + * @param userId + * @param newPassword + */ +async function ResetUserPassword(userId: number, newPassword: string): Promise { + let res = await request>(`/lms/User/ResetPassword/${userId}`, { + method: 'post', + data: { + newPassword: newPassword, + } + }); + if (res.code != 1) { + throw new Error(res.message); + } +} + +export const UserInfo = { QueryUserList, GetUserInfo, UpdatedUserInfo, EnableAgent, GetUserAgentInfo, + ResetUserPassword, } \ No newline at end of file diff --git a/src/util/password.ts b/src/util/password.ts new file mode 100644 index 0000000..6549c07 --- /dev/null +++ b/src/util/password.ts @@ -0,0 +1,25 @@ +export function generateRandomPassword(): string { + const upperCase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + const lowerCase = 'abcdefghijklmnopqrstuvwxyz'; + const numbers = '0123456789'; + const special = '@$!%*?.&'; + + let password = ''; + + // Ensure at least one character from each category + password += upperCase[Math.floor(Math.random() * upperCase.length)]; + password += lowerCase[Math.floor(Math.random() * lowerCase.length)]; + password += numbers[Math.floor(Math.random() * numbers.length)]; + password += special[Math.floor(Math.random() * special.length)]; + + // Fill the rest randomly + const allChars = upperCase + lowerCase + numbers + special; + for (let i = password.length; i < 12; i++) { + password += allChars[Math.floor(Math.random() * allChars.length)]; + } + + // Shuffle the password + password = password.split('').sort(() => Math.random() - 0.5).join(''); + + return password; +} \ No newline at end of file