新增软件管理权限,包括申请,管理,删除,添加使用时间等

This commit is contained in:
lq1405 2024-12-27 21:49:11 +08:00
parent ae15530766
commit 7781c6c95c
36 changed files with 728 additions and 74 deletions

View File

@ -41,7 +41,7 @@ export default [
path: '/userCenter',
name: 'userCenter',
icon: 'User',
component: './User/UserCenter/index',
component: './User/UserCenter/UserCenter.tsx',
},
{
name: 'prompt',
@ -89,7 +89,7 @@ export default [
name: 'userManagement',
icon: 'User',
access: 'canUserManagement',
component: './User/UserManagement/index',
component: './User/UserManage/UserManagement/index',
},
{
path: '/machineManagement',
@ -98,6 +98,13 @@ export default [
access: 'canMachineManagement',
component: './Machine/MachineManagement/index',
},
{
path: '/sofrwareControlManagement',
name: 'sofrwareControlManagement',
icon: 'Reconciliation',
access: 'canSofrwareControlManagement',
component: './Software/SofrwareControl/SofrwareControlManagement',
},
{
path: '/',
redirect: '/welcome',

View File

@ -3,8 +3,6 @@
* */
export default function access(initialState: { currentUser?: API.CurrentUser } | undefined): AccessType.AccessType {
const { currentUser } = initialState ?? {};
console.log("currentUser", currentUser);
console.log("userRole", currentUser?.roleNames);
let access = {
canPrompt: false,
@ -20,6 +18,9 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
canOptions: false,
canLaitoolOptions: false,
canApplySoftwareControl: false,
canSofrwareControlManagement: false,
canMachineManagement: false,
canAddMachine: true,
canEditMachine: false,
@ -72,6 +73,9 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
canEditMachine: true,
canDeleteMachine: true,
canUpgradeMachine: true,
canApplySoftwareControl: true,
canSofrwareControlManagement: true
}
}
@ -95,6 +99,9 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
canEditMachine: true,
canDeleteMachine: true,
canUpgradeMachine: true,
canApplySoftwareControl: true,
canSofrwareControlManagement: true
};
}
console.log("accsee", access);

View File

@ -57,7 +57,6 @@ export async function getInitialState(): Promise<{
let currentUser = currentUserString ? JSON.parse(currentUserString) : null;
let token = localStorage.getItem('token') ?? null;
if (token == null || currentUser == null) {
console.log('没有登录重定向到登录页面123')
history.push('/user/login');
return {
fetchUserInfo,

View File

@ -49,7 +49,6 @@ export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu, childre
/** 此方法会跳转到 redirect 参数所在的位置 */
const redirect = urlParams.get('redirect');
// Note: There may be security issues, please note
console.log('没有登录重定向到登录页面12333333333333333')
if (window.location.pathname !== '/user/login' && !redirect) {
history.replace({
pathname: '/user/login',

View File

@ -15,7 +15,7 @@ const clearCache = () => {
caches.delete(key);
});
})
.catch((e) => console.log(e));
.catch((e) => console.error(e));
}
};

View File

@ -15,6 +15,7 @@ export default {
'menu.userManagement': '用户管理',
'menu.machineManagement': '机器码管理',
'menu.sofrwareControlManagement': '软件控制管理',
'menu.more-blocks': '更多区块',
'menu.home': '首页',

View File

@ -66,7 +66,6 @@ const ModifyMachine: React.FC<ModifyMachineProps> = ({ id, setFormRef, open }) =
};
const onOk = (value: DatePickerProps['value'] | RangePickerProps['value']) => {
console.log('onOk: ', value);
};
return (
@ -145,8 +144,6 @@ const ModifyMachine: React.FC<ModifyMachineProps> = ({ id, setFormRef, open }) =
<DatePicker
showTime
onChange={(value, dateString) => {
console.log('Selected Time: ', value);
console.log('Formatted Selected Time: ', dateString);
}}
onOk={onOk}
/>

View File

@ -7,7 +7,6 @@ import TrailOptions from './TrialOptions';
const DubSetting: React.FC = () => {
const onChange = (key: string | string[]) => {
console.log(key);
};
const items: CollapseProps['items'] = [

View File

@ -13,7 +13,6 @@ const DubSettingTTsOptions: React.FC = () => {
const [messageApi, messageHolder] = message.useMessage();
async function onFinish(values: any): Promise<void> {
console.log('Received values of form: ', values);
setTopSpinning(true);
setTopSpinTip("正在保存EdgeTTs配置");
try {
@ -32,7 +31,6 @@ const DubSettingTTsOptions: React.FC = () => {
}
}
useEffect(() => {
console.log("DubSettingTTsOptions", ttsOptions)
form.setFieldsValue({ edgeTTsRoles: getOptionsStringValue(ttsOptions, 'EdgeTTsRoles', "{}") })
}, [ttsOptions])

View File

@ -11,7 +11,6 @@ const DubSetting: React.FC = () => {
const { setTopSpinning, setTopSpinTip } = useSoftStore();
const onChange = (key: string | string[]) => {
console.log(key);
};
useEffect(() => {
@ -22,9 +21,8 @@ const DubSetting: React.FC = () => {
setTTsOptions(res);
}
).catch((err) => {
console.log(err);
console.error(err);
}).finally(() => {
console.log('finally');
setTopSpinning(false);
});

View File

@ -123,7 +123,6 @@ const PromptManagement: React.FC = () => {
okText: "确认",
cancelText: "取消"
});
console.log(confirmed)
if (confirmed) {
setTopSpinning(true);
setTopSpinTip("正在删除数据。。。")

View File

@ -82,7 +82,6 @@ const PromptManagement: React.FC<PromptManagementProps> = ({ type, setFormRef, i
};
const onFinishFailed: FormProps<Prompt.AddPromptType>['onFinishFailed'] = (errorInfo) => {
console.log('Failed:', errorInfo);
};
return (<>

View File

@ -52,7 +52,6 @@ const PromptManagement: React.FC = () => {
page: tableParams.pagination?.current ?? 1,
} as Prompt.PromptTypeQueryCondition;
console.log("fetchData", params)
let promptRes = await QueryPromptypeCollection(params)
setData(promptRes.collection);
setTableParams({

View File

@ -15,7 +15,6 @@ const AddRoleForm: React.FC<AddRoleModalProps> = ({ setFormRef }) => {
}, [form, setFormRef]);
const onFinish = async (values: any) => {
console.log('Success:', values);
setLoading(true);
try {
await AddRole(values.name, values.remark);

View File

@ -41,7 +41,6 @@ const ManageRoleModal: React.FC<ManageRoleModalProps> = ({ roleId, setFormRef })
}, [roleId]);
async function onFinish(values: RoleModel.Collection): Promise<void> {
console.log("onFinish", values);
setLoading(true);
setSpinTip("更新中...");
try {

View File

@ -35,7 +35,6 @@ const RoleManagement: React.FC = () => {
},
});
useEffect(() => {
console.log("RoleManagement useEffect");
// 初始化加载数据
QueryRoleList(tableParams, form.getFieldsValue())
.then((res) => {
@ -49,7 +48,6 @@ const RoleManagement: React.FC = () => {
setLoading(false);
})
.catch((error) => {
console.log(error);
messageApi.error(error.message);
}).finally(() => {
setLoading(false);

View File

@ -0,0 +1,313 @@
import React, { useEffect, useState } from 'react';
import type { FC } from 'react';
import TemplateContainer from '@/pages/TemplateContainer';
import { useModel } from '@umijs/max';
import { Button, Dropdown, Form, Input, message, Modal, Select, Table, TableProps, Tag } from 'antd';
import { FilterValue, SorterResult, TableCurrentDataSource, TablePaginationConfig } from 'antd/es/table/interface';
import { Software, SoftwareControl } from '@/services/services/software';
import moment from 'moment';
import { DeleteOutlined, EditOutlined, MenuOutlined, PlusSquareOutlined } from '@ant-design/icons';
interface SoftwareControlManagementProps {
// Add your props here
}
const SoftwareControlManagement: FC<SoftwareControlManagementProps> = () => {
const { initialState } = useModel('@@initialState');
const [messageApi, messageHolder] = message.useMessage();
const [loading, setLoading] = React.useState<boolean>(false);
const [modalApi, modalHolder] = Modal.useModal();
const [form] = Form.useForm();
const [softwareBasicInfo, setSoftwareBasicInfo] = useState<SoftwareModel.SoftwareBasicInfo[]>();
const [softwareOptions, setSoftwareOptions] = useState<any>([]);
const [data, setData] = React.useState<SoftwareModel.SoftwareControlBase[]>([]);
const [tableParams, setTableParams] = useState<TableModel.TableParams>({
pagination: {
current: 1,
pageSize: 10,
showQuickJumper: true,
totalBoundaryShowSizeChanger: true,
},
});
const columns: TableProps<SoftwareModel.SoftwareControlBase>['columns'] = [
{
title: '软件代码',
dataIndex: 'software',
width: 100,
key: 'softwareCode',
render: (software) => <span> {software.softwareCode}</span >
},
{
title: '软件名称',
dataIndex: 'software',
key: 'softwareName',
render: (software) => <span>{software.softwareName}</span>,
},
{
title: '所属用户ID',
dataIndex: 'user',
key: 'userId',
render: (user) => <span>{user.id}</span>,
},
{
title: '所属用户名称',
dataIndex: 'user',
key: 'userName',
render: (user) => <span>{user.nickName}</span>,
},
{
title: '创建者',
dataIndex: 'createdUser',
key: 'createdUserNickName',
render: (createdUser) => <span>{createdUser.nickName}</span>,
},
{
title: '更新者',
dataIndex: 'updatedUser',
key: 'updatedUserNickName',
render: (updatedUser) => <span>{updatedUser.nickName}</span>,
},
{
title: '更新时间',
dataIndex: 'updatedTime',
key: 'updatedTime',
width: 200,
render: (updatedTime) => updatedTime ? moment(updatedTime).format('YYYY-MM-DD HH:mm:ss') : 'null',
},
{
title: '到期时间',
dataIndex: 'expirationTime',
key: 'expirationTime',
width: 200,
render: (expirationTime) => expirationTime ? moment(expirationTime).format('YYYY-MM-DD HH:mm:ss') : 'null',
},
{
title: '是否永久',
dataIndex: 'isForever',
key: 'isForever',
width: 100,
render: (isForever) => isForever ? <Tag color="green"></Tag> : <Tag color="red"></Tag>,
},
{
title: '操作',
key: 'action',
width: 100,
render: (_, record) => (
<Dropdown
menu={{
items: [
{
key: 'edit',
label: '编辑',
icon: <EditOutlined />,
onClick: () => {
// 编辑
messageApi.warning("暂不支持编辑");
}
},
{
key: 'addMouth',
label: '添加月付',
style: { color: '#38a2fc' },
icon: <PlusSquareOutlined />,
onClick: async () => {
// 延长到期时间
await AddSoftwareControlExpirationTime(record.id, 30);
}
},
{
key: 'addQuarterly',
label: '添加季付',
style: { color: '#38a2fc' },
icon: <PlusSquareOutlined />,
onClick: async () => {
// 延长到期时间
await AddSoftwareControlExpirationTime(record.id, 90);
}
},
{
key: 'addHalfYear',
label: '添加半年',
style: { color: '#38a2fc' },
icon: <PlusSquareOutlined />,
onClick: async () => {
// 延长到期时间
await AddSoftwareControlExpirationTime(record.id, 180);
}
},
{
key: 'addYear',
label: '添加年付',
style: { color: '#38a2fc' },
icon: <PlusSquareOutlined />,
onClick: async () => {
// 延长到期时间
await AddSoftwareControlExpirationTime(record.id, 365);
}
},
{
key: 'addForever',
label: '永久',
style: { color: '#38a2fc' },
icon: <PlusSquareOutlined />,
onClick: async () => {
// 延长到期时间
await AddSoftwareControlExpirationTime(record.id, 0);
}
},
{
key: 'delete',
label: '停用权限',
danger: true,
icon: <DeleteOutlined />,
onClick: async () => {
await DeleteSoftwareControl(record.id);
}
},
],
}}
>
<Button type="text" color="primary" variant="filled" icon={<MenuOutlined />} />
</Dropdown>
),
}
];
async function DeleteSoftwareControl(id: string) {
try {
const confirmed = await modalApi.confirm({
title: "确认停用",
content: "确定停用吗,重置到期时间和永久选项"
});
if (confirmed) {
setLoading(true);
await SoftwareControl.AddSoftwareControlExpirationTime(id, 0, false);
// 重新查询
await QueryUserSoftwareControlCollection();
messageApi.success("停用成功");
} else {
messageApi.info("取消停用");
}
} catch (error: any) {
messageApi.error(error.message);
} finally {
setLoading(false);
}
}
async function AddSoftwareControlExpirationTime(id: string, days: number) {
try {
const confirmed = await modalApi.confirm({
title: "确认添加",
content: `确认添加 ${days == 0 ? "永久" : days + " 天"} 吗?`
});
if (confirmed) {
setLoading(true);
await SoftwareControl.AddSoftwareControlExpirationTime(id, days, days == 0);
// 重新查询
await QueryUserSoftwareControlCollection();
if (days == 0) {
messageApi.success("添加永久成功");
} else {
messageApi.success("添加 " + days + " 天成功");
}
} else {
messageApi.info("取消添加");
}
} catch (error: any) {
messageApi.error(error.message);
} finally {
setLoading(false);
}
}
async function QueryUserSoftwareControlCollection(options?: SoftwareModel.SoftwareControlQueryParams) {
try {
setLoading(true);
let res = await SoftwareControl.GetUserSoftwareControlCollection(tableParams, options ?? {});
setData(res.collection);
setTableParams({
pagination: {
...tableParams.pagination,
total: res.total
}
});
} catch (error: any) {
messageApi.error(error.message);
} finally {
setLoading(false);
}
}
useEffect(() => {
QueryUserSoftwareControlCollection().then();
Software.GetSoftwareBaseCollection().then((res) => {
setSoftwareBasicInfo(res);
let options = []
for (let i = 0; i < res.length; i++) {
const element = res[i];
let option = {
label: element.isUse == false ? element.softwareName + "(未启用)" : element.softwareName,
value: element.id
}
options.push(option);
}
setSoftwareOptions(options);
}).catch((error) => {
messageApi.error(error.message);
})
}, []);
async function TableChangeHandle(pagination: TablePaginationConfig, filters: Record<string, FilterValue | null>, sorter: SorterResult<SoftwareModel.SoftwareControlBase> | SorterResult<SoftwareModel.SoftwareControlBase>[], extra: TableCurrentDataSource<SoftwareModel.SoftwareControlBase>): Promise<void> {
await QueryUserSoftwareControlCollection();
setTableParams({
pagination: {
...tableParams.pagination,
current: pagination.current,
pageSize: pagination.pageSize,
}
});
}
async function QuerySoftwareControlByCondition(values: any) {
await QueryUserSoftwareControlCollection(values);
}
return (
<TemplateContainer navTheme={initialState?.settings?.navTheme ?? "realDark"}>
<Form
layout='inline'
form={form}
onFinish={QuerySoftwareControlByCondition}
>
<Form.Item label="用户ID" name='userId' style={{ marginBottom: 5 }}>
<Input placeholder="请输入用户ID" />
</Form.Item>
<Form.Item label="软件" name='softwareId' style={{ marginBottom: 5 }}>
<Select placeholder="请选择用户名称" style={{ width: 200 }} options={softwareOptions} />
</Form.Item>
<Form.Item label="是否永久" name='IsForever' style={{ marginBottom: 5 }}>
<Select placeholder="请选择是否永久" style={{ width: 200 }} options={[{ label: "是", value: true }, { label: "否", value: false }]} />
</Form.Item>
<Form.Item label="备注" name='remark' style={{ marginBottom: 5 }}>
<Input placeholder="请输入备注" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit"></Button>
</Form.Item>
</Form>
<div>
<Table<SoftwareModel.SoftwareControlBase> columns={columns} dataSource={data} rowKey={(record) => record.id} pagination={tableParams.pagination} onChange={TableChangeHandle} loading={loading} />
</div>
{messageHolder}
{modalHolder}
</TemplateContainer>
);
};
export default SoftwareControlManagement;

View File

@ -130,7 +130,6 @@ const Login: React.FC = () => {
setUserLoginState({
status: 'error',
});
console.log(error);
message.error(error.message);
}
};

View File

@ -19,7 +19,6 @@ const Register: React.FC = () => {
}, []);
const onFinish = async (values: UserModel.UserRegisterParams) => {
console.log('Received values of form: ', values);
// 判断两次密码是否一致
if (values.password !== values.confirm) {
messageApi.warning('两次密码不一致!');

View File

@ -2,16 +2,19 @@ import TemplateContainer from '@/pages/TemplateContainer';
import { GetUserAgentInfo, GetUserInfo } from '@/services/services/user';
import { RedoOutlined } from '@ant-design/icons';
import { useModel } from '@umijs/max';
import { Avatar, Button, Card, Col, Input, message, Modal, Row, Spin, Tag } from 'antd';
import { Avatar, Badge, Button, Card, Col, FloatButton, Input, message, Modal, Row, Spin, Tag } from 'antd';
import React, { useEffect, useState } from 'react';
import UserCenterUserInfo from '../UserCenterUserInfo';
import UserCenterAgentMessage from '../UserCenterAgentMessage';
import UserCenterUserInfo from './UserCenterUserInfo';
import UserCenterAgentMessage from './UserCenterAgentMessage';
import { useSoftStore } from '@/store/software';
import { SoftwareControl } from '@/services/services/software';
import UserSoftwareInfo from './UserSoftwareInfo';
const UserCenter: React.FC = () => {
const { initialState, setInitialState } = useModel('@@initialState');
const [messageApi, messageHolder] = message.useMessage();
const [modalApi, modalHolder] = Modal.useModal();
const [badgeCount, setBadgeCount] = useState(0);
const { setTopSpinTip, setTopSpinning } = useSoftStore();
const [userAgentUserInfo, setUserAgentUserInfo] = useState<UserModel.UserAgentInfo>();
@ -26,13 +29,62 @@ const UserCenter: React.FC = () => {
let agentInfo = await GetUserAgentInfo();
setUserAgentUserInfo(agentInfo);
}).catch((error) => {
console.log(error)
messageApi.error(error.message);
}).finally(() => {
setTopSpinning(false);
})
// 加载当前用户可申请的的软件控制权限
SoftwareControl.GetUserSoftwareControlCount(initialState?.currentUser?.id).then((res) => {
setBadgeCount(res);
}).catch((error) => {
messageApi.error(error.message);
})
}
}, [])
/**
*
*/
async function ApplyUserSoftwareControlHandle() {
let userID = initialState?.currentUser?.id;
if (!userID) {
messageApi.error("用户信息不存在");
return;
}
// 重新获取用户关联信息
const userCanApplyCount = await SoftwareControl.GetUserSoftwareControlCount(userID);
if (userCanApplyCount <= 0) {
messageApi.warning("您已经没有可申请的软件控制权限了");
return;
}
// 开始调用申请接口
setTopSpinning(true);
setTopSpinTip("正在申请软件控制权限。。。");
try {
await SoftwareControl.ApplyUserSoftwareControl(userID);
// 提示成功
messageApi.success("申请成功");
setBadgeCount(0);
} catch (error: any) {
messageApi.error(error.message);
} finally {
setTopSpinning(false);
}
}
/**
*
*/
async function ShowSoftwareControlHandle() {
modalApi.info({
title: "用户软件控制权限",
content: <UserSoftwareInfo userId={initialState?.currentUser?.id} />,
width: 800,
footer: null,
closable: true,
});
}
function renderTitie() {
return (
<div style={{ display: 'flex' }}>
@ -81,6 +133,18 @@ const UserCenter: React.FC = () => {
</div>
<strong style={{ fontSize: 24, color: "goldenrod" }}>{initialState?.currentUser?.affiliateCode}</strong>
</Col>
<Col span={3} style={{ minWidth: 100 }}>
<div>
<span></span>
</div>
{
badgeCount > 0 ? <Badge count={badgeCount}>
<Button variant="filled" color="default" onClick={ApplyUserSoftwareControlHandle}> </Button>
</Badge> : <Button variant="filled" color="default" onClick={ApplyUserSoftwareControlHandle}> </Button>
}
<Button color="primary" variant="filled" style={{ marginLeft: 10 }} onClick={ShowSoftwareControlHandle} > </Button>
</Col>
</Row>
</Card>
</div>

View File

@ -0,0 +1,103 @@
import React, { useEffect, useState } from 'react';
import { message, Space, Table, Tag } from 'antd';
import type { TablePaginationConfig, TableProps } from 'antd';
import { FilterValue, SorterResult, TableCurrentDataSource } from 'antd/es/table/interface';
import { SoftwareControl } from '@/services/services/software';
import { useModel } from '@umijs/max';
import moment from 'moment';
const columns: TableProps<SoftwareModel.SoftwareControlBase>['columns'] = [
{
title: '软件代码',
dataIndex: 'software',
width: 100,
key: 'softwareCode',
render: (software) => <span> {software.softwareCode}</span >
},
{
title: '软件名称',
dataIndex: 'software',
key: 'softwareName',
render: (software) => <span>{software.softwareName}</span>,
},
{
title: '到期时间',
dataIndex: 'expirationTime',
key: 'expirationTime',
width: 200,
render: (expirationTime) => expirationTime ? moment(expirationTime).format('YYYY-MM-DD HH:mm:ss') : 'null',
},
{
title: '是否永久',
dataIndex: 'isForever',
key: 'isForever',
width: 100,
render: (isForever) => isForever ? <Tag color="green"></Tag> : <Tag color="red"></Tag>,
}
];
interface UserSoftwareInfoProps {
userId?: number;
}
const UserSoftwareInfo: React.FC<UserSoftwareInfoProps> = ({ userId }) => {
const [data, setData] = React.useState<SoftwareModel.SoftwareControlBase[]>([]);
const [loading, setLoading] = React.useState<boolean>(false);
const [messageApi, messageHolder] = message.useMessage();
const [tableParams, setTableParams] = useState<TableModel.TableParams>({
pagination: {
current: 1,
pageSize: 10,
showQuickJumper: true,
totalBoundaryShowSizeChanger: true,
},
});
async function QueryUserSoftwareControlCollection() {
try {
if (userId == null) {
messageApi.error("用户ID不能为空");
}
setLoading(true);
let res = await SoftwareControl.GetUserSoftwareControlCollection(tableParams, {
userId: userId
});
setData(res.collection);
setTableParams({
pagination: {
...tableParams.pagination,
total: res.total
}
})
} catch (error: any) {
messageApi.error(error.message);
} finally {
setLoading(false);
}
}
useEffect(() => {
QueryUserSoftwareControlCollection().then();
}, []);
async function TableChangeHandle(pagination: TablePaginationConfig, filters: Record<string, FilterValue | null>, sorter: SorterResult<SoftwareModel.SoftwareControlBase> | SorterResult<SoftwareModel.SoftwareControlBase>[], extra: TableCurrentDataSource<SoftwareModel.SoftwareControlBase>): Promise<void> {
await QueryUserSoftwareControlCollection();
setTableParams({
pagination: {
...tableParams.pagination,
current: pagination.current,
pageSize: pagination.pageSize,
}
});
}
return (
<div>
<Table<SoftwareModel.SoftwareControlBase> columns={columns} dataSource={data} rowKey={(record) => record.id} pagination={tableParams.pagination} onChange={TableChangeHandle} loading={loading} />
{messageHolder}
</div>
);
};
export default UserSoftwareInfo;

View File

@ -4,11 +4,13 @@ import { QueryRoleOption } from "@/services/services/role";
import { QueryUserList } from "@/services/services/user";
import { FormatDate } from "@/util/time";
import { useAccess, useModel } from "@umijs/max";
import { Button, Form, Input, InputNumber, message, Modal, Select, SelectProps, Table, Tag, Tooltip } from "antd";
import { Button, Dropdown, Form, Input, InputNumber, message, Modal, Select, SelectProps, Table, Tag, Tooltip } from "antd";
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 { SoftwareControl } from "@/services/services/software";
const UserManagement: React.FC = () => {
type TagRender = SelectProps['tagRender'];
@ -134,6 +136,33 @@ const UserManagement: React.FC = () => {
);
};
/**
*
* @param userId ID
* @returns
*/
async function ApplySoftwareControlHandle(userId: number) {
if (!access.isAdminOrSuperAdmin) {
messageApi.error("您没有权限执行此操作");
return;
}
try {
setLoading(true);
let userCanApplyCount = await SoftwareControl.GetUserSoftwareControlCount(userId);
if (userCanApplyCount <= 0) {
messageApi.warning("用户已经没有可申请的软件控制权限了");
return;
}
// 开始申请
await SoftwareControl.ApplyUserSoftwareControl(userId);
messageApi.success("用户软件控制权限申请成功");
} catch (error: any) {
messageApi.error(error.message);
} finally {
setLoading(false);
}
}
const columns: ColumnsType<UserModel.UserCollection> = [
{
title: 'ID',
@ -200,17 +229,48 @@ const UserManagement: React.FC = () => {
},
{
title: '操作',
width: '120px',
width: '80px',
hidden: !access.isAdminOrSuperAdmin,
render: (text, record) => (
<div style={{ display: "flex" }}>
<Button hidden={!access.canEditUser} size='small' style={{ marginRight: 5 }} type="primary" onClick={() => {
<Dropdown
menu={{
items: [
{
key: 'edit',
label: '编辑',
icon: <EditOutlined />,
hidden: !access.canEditUser,
primary: true,
onClick: () => {
setUserId(record.id);
setOpenModal(true);
}}></Button>
<Button hidden={!access.canDeleteUser} danger size='small' type="primary" onClick={() => {
}
},
{
key: 'apply',
label: '初始化权限',
icon: <SyncOutlined />,
hidden: !access.canApplySoftwareControl,
primary: true,
onClick: async () => {
await ApplySoftwareControlHandle(record.id);
}
},
{
key: 'delete',
label: '删除',
icon: <DeleteOutlined />,
hidden: !access.canDeleteUser,
danger: true,
onClick: () => {
messageApi.error("暂不支持删除用户");
}} ></Button>
</div>
}
}
].filter(item => !item.hidden)
}}
>
<Button color="primary" variant="filled" icon={<MenuOutlined />} />
</Dropdown>
),
},
];

View File

@ -101,33 +101,25 @@ export const errorConfig: RequestConfig = {
// 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
const { status } = error.response;
if (status === 401) {
console.log('401 error', url);
if (url.toLowerCase().includes('/refreshtoken')) {
console.log('refresh token error');
message.error('登录已过期,请重新登录');
localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
localStorage.removeItem('userInfo');
history.push('/user/login');
} else {
console.log('normal 401 error try to refresh token');
// 尝试刷新 token
const refreshSuccess = await refreshToken();
console.log('refresh token result', refreshSuccess);
if (refreshSuccess) {
console.log('refresh token success, retry request');
// 刷新成功,重试原请求
// 这里需要实现重试逻辑,可能需要修改您的请求库
message.success('已重新获取授权,正在重试请求');
// 刷新成功,重试原请求
try {
console.log('retry request', opts);
const retryResponse = await retryRequest(url, opts);
// 如果重试成功,返回重试的响应
console.log('retry success', retryResponse);
return retryResponse;
} catch (retryError) {
console.log('retry error', retryError);
message.error('重试请求失败,请重新登录');
localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
@ -136,7 +128,6 @@ export const errorConfig: RequestConfig = {
}
// 重试原请求的逻辑
} else {
console.log('refresh token failed');
// 刷新失败,重定向到登录页面
message.error('授权已过期,请重新登录');
localStorage.removeItem('token');

View File

@ -65,7 +65,6 @@ export class TokenStorage {
const request = objectStore.put({ id: 'token', value: token });
transaction.oncomplete = () => {
console.log('Token saved');
resolve();
};
@ -86,7 +85,6 @@ export class TokenStorage {
request.onsuccess = (event) => {
const result = (event.target as IDBRequest).result;
if (result) {
console.log('Token:', result.value);
let claims: any = null;
if (result.value) {
const decodedToken = jwtDecode(result.value);
@ -100,7 +98,6 @@ export class TokenStorage {
}
resolve(claims);
} else {
console.log('Token not found');
resolve(null);
}
};
@ -122,10 +119,8 @@ export class TokenStorage {
request.onsuccess = (event) => {
const result = (event.target as IDBRequest).result;
if (result) {
console.log('Token:', result.value);
resolve(result.value);
} else {
console.log('Token not found');
reject(new Error("Token not found"));
}
};
@ -145,7 +140,6 @@ export class TokenStorage {
const request = objectStore.delete('token');
transaction.oncomplete = () => {
console.log('Token deleted');
resolve();
};

View File

@ -17,7 +17,6 @@ async function QueryMachineList(tableParams: TableModel.TableParams, userParams:
let res = await request<ApiResponse.SuccessItem<MachineModel.QueryMachineData>>(`/lms/Machine/QueryMachineCollection?${query}`, {
method: 'GET',
});
console.log(QueryMachineList, res)
if (res.code != 1) {
throw new Error(res.message);
}
@ -59,7 +58,6 @@ async function GetMachineInfo(id: string): Promise<MachineModel.MachineInfo> {
let res = await request<ApiResponse.SuccessItem<MachineModel.MachineInfo>>(`/lms/Machine/GetMachineDetail/${id}`, {
method: 'GET',
});
console.log("GetMachineInfo", res)
if (res.code != 1) {
throw new Error(res.message);
}
@ -77,7 +75,6 @@ async function ModifyMachineData(id: string, params: MachineModel.ModifyMachineP
...params,
deactivationTime: deactivationTimeString
}
console.log("ModifyMachineData", params)
let res = await request<ApiResponse.SuccessItem<null>>(`/lms/Machine/ModifyMachine/${id}`, {
method: 'POST',
data: data

View File

@ -99,7 +99,6 @@ export async function GetOptions(optionsKey: string): Promise<OptionModel.Option
'Content-Type': 'application/json',
}
});
console.log("GetTTSOptions", res)
if (res.code != 1) {
throw new Error(res.message);
}
@ -120,7 +119,6 @@ export async function SaveOptions(options: object): Promise<void> {
data.push({ key: key, value: value.toString() });
return "";
}, {});
console.log("SaveOptionsDataParams", data)
let res = await request<ApiResponse.SuccessItem<boolean>>('/lms/LaitoolOptions/ModifyOptions', {
method: 'POST',

View File

@ -31,7 +31,6 @@ export async function GetPromptInfo(id: string): Promise<Prompt.PromptItem> {
if (res.code != 1) {
throw new Error(res.message);
}
console.log("GetPromptInfo", res.data);
return res.data;
}
@ -42,7 +41,6 @@ export async function GetPromptInfo(id: string): Promise<Prompt.PromptItem> {
* @returns
*/
export async function AddPrompt(data: Prompt.PromptItem): Promise<string> {
console.log("AddPrompt", data)
let res = await request('/lms/Prompt/AddPrompt', {
method: 'POST',
data: {
@ -104,14 +102,12 @@ export async function DeletePrompt(id: string): Promise<void> {
*/
export async function QueryPromptypeCollection(param: Prompt.PromptTypeQueryCondition): Promise<Prompt.PromptTypeResponse> {
let query = objectToQueryString(param)
console.log("query", query)
let res = await request<ApiResponse.SuccessItem<Prompt.PromptTypeResponse>>(`/lms/Prompt/QueryPromptypeCollection/?${query}`, {
method: 'GET',
});
if (res.code != 1) {
throw new Error(res.message);
}
console.log("QueryPromptypeCollection", res.data);
return res.data;
}

View File

@ -21,7 +21,6 @@ export async function QueryRoleList(tableParams: TableModel.TableParams, rolePar
let res = await request<ApiResponse.SuccessItem<RoleModel.QueryRoleData>>(`/lms/Role/QueryRoleCollection?${query}`, {
method: 'GET',
});
console.log("QueryRoleList", res);
if (res.code != 1) {
throw new Error(res.message);
}
@ -35,7 +34,6 @@ export async function QueryRoleOption() {
let res = await request<ApiResponse.SuccessItem<string[]>>(`/lms/Role/QueryRoleOption`, {
method: 'GET',
});
console.log("QueryRoleOption", res);
if (res.code != 1) {
throw new Error(res.message);
}
@ -49,11 +47,9 @@ export async function QueryRoleOption() {
* @returns
*/
export async function GetRoleById(roleId: number): Promise<RoleModel.Collection> {
console.log("GetRoleById", roleId);
let res = await request<ApiResponse.SuccessItem<RoleModel.Collection>>(`/lms/Role/QueryRoleById/${roleId}`, {
method: 'GET',
});
console.log("GetRoleByIdRes", res);
if (res.code != 1) {
throw new Error(res.message);
}
@ -74,7 +70,6 @@ export async function UpdeteRole(roleId: number, roleName: string, roleRemark: s
remark: roleRemark
}
});
console.log("UpdeteRole", res);
if (res.code != 1) {
throw new Error(res.message);
}
@ -89,7 +84,6 @@ export async function DeleteRoleById(roleId: number): Promise<void> {
let res = await request<ApiResponse.SuccessItem<void>>(`/lms/Role/DeleteRole/${roleId}`, {
method: 'DELETE',
});
console.log("DeleteRole", res);
if (res.code != 1) {
throw new Error(res.message);
}
@ -111,7 +105,6 @@ export async function AddRole(roleNmae: string, roleRemark: string): Promise<voi
remark: roleRemark
}
});
console.log("AddRole", res);
if (res.code != 1) {
throw new Error(res.message);
}

View File

@ -0,0 +1,94 @@
import { request } from '@umijs/max';
import { objectToQueryString } from './common';
/**
*
* @param userId
* @returns
*/
async function GetUserSoftwareControlCount(userId: number) {
let res = await request<ApiResponse.SuccessItem<number>>(`/lms/SoftWare/GetUserSoftwareControlCount/${userId}`, {
method: 'GET',
});
if (res.code == 1) {
return res.data;
}
throw new Error(res.message);
}
/**
*
* @param userId
* @returns
*/
async function ApplyUserSoftwareControl(userId: number) {
let res = await request<ApiResponse.SuccessItem<boolean>>(`/lms/SoftWare/ApplySoftwareControl/${userId}`, {
method: 'POST',
});
if (res.code == 1) {
return res.data;
}
throw new Error(res.message);
}
/**
*
* @param tableParams
* @param queryParams
* @returns
*/
async function GetUserSoftwareControlCollection(tableParams: TableModel.TableParams, queryParams: SoftwareModel.SoftwareControlQueryParams) {
let data = {
...queryParams,
page: tableParams.pagination?.current,
pageSize: tableParams.pagination?.pageSize,
}
let query = objectToQueryString(data)
let res = await request<ApiResponse.SuccessItem<SoftwareModel.QuerySoftwareControlData>>(`/lms/SoftWare/GetSoftwareControlCollection?${query}`, {
method: 'GET',
});
if (res.code != 1) {
throw new Error(res.message);
}
return res.data;
}
async function AddSoftwareControlExpirationTime(id: string, days: number, isForever: boolean) {
let res = await request<ApiResponse.SuccessItem<null>>(`/lms/SoftWare/ModifySoftwareControlValidity/${id}`, {
method: 'POST',
data: {
expirationTime: days,
isForever: isForever
}
});
if (res.code != 1) {
throw new Error(res.message);
}
}
export const SoftwareControl = {
GetUserSoftwareControlCount,
ApplyUserSoftwareControl,
GetUserSoftwareControlCollection,
AddSoftwareControlExpirationTime
}
/**
*
* @returns
*/
async function GetSoftwareBaseCollection() {
let res = await request<ApiResponse.SuccessItem<SoftwareModel.SoftwareBasicInfo[]>>(`/lms/SoftWare/GetSoftwareBaseCollection`, {
method: 'GET',
});
if (res.code == 1) {
return res.data;
}
throw new Error(res.message);
}
export const Software = {
GetSoftwareBaseCollection
}

View File

@ -74,7 +74,6 @@ async function QueryUserList(tableParams: TableModel.TableParams, userParams: Us
if (res.code != 1) {
throw new Error(res.message);
}
console.log("QueryUserList", res);
return res.data;
}

View File

@ -39,5 +39,14 @@ declare namespace AccessType {
/** 是不是有停用机器码的权限 */
canDisableMachine: boolean;
//#endregion
//#region 软件控制权限
/** 是否可以同步用户软件控制权限 */
canApplySoftwareControl: boolean;
/** 是否可以查看软件控制管理 */
canSofrwareControlManagement: boolean;
//#endregion
}
}

47
src/services/typing/software.d.ts vendored Normal file
View File

@ -0,0 +1,47 @@
declare namespace SoftwareModel {
interface SoftwareBasicInfo {
id: string;
softwareName: string;
softwareCode: string;
isUse: boolean;
}
interface SoftwareBase {
id: string;
softwareName: string;
softwareCode: string;
createdUserId: number;
updatedUserId: number;
createdTime: Date;
updatedTime: Date;
remark: string;
isUse: boolean;
}
interface SoftwareControlBase {
id: string;
user: UserModel.UserBasic;
software: SoftwareBase;
createdUser: UserModel.UserBasic;
createdTime: Date;
updatedUser: UserModel.UserBasic;
updatedTime: Date;
remark: string;
expirationTime: string;
isForever: boolean;
}
type SoftwareControlQueryParams = {
userId?: number;
softwareId?: string;
isForever?: boolean;
remark?: string
};
type QuerySoftwareControlData = {
collection: SoftwareControlBase[];
current: number;
total: number;
}
}