feat: reset web

master
guofei 2024-06-07 19:26:41 +08:00
parent 6e0d9cca5d
commit 12da5f60bd
19 changed files with 1043 additions and 8 deletions

View File

@ -25,7 +25,7 @@
"unocss": "^0.60.4"
},
"devDependencies": {
"@types/lodash": "^4.17.4",
"@types/lodash-es": "^4.17.12",
"@types/qs": "^6.9.15",
"@types/react": "^18.0.33",
"@types/react-dom": "^18.0.11",

View File

@ -45,9 +45,9 @@ importers:
specifier: ^0.60.4
version: 0.60.4(postcss@8.4.38)(rollup@3.29.4)(vite@4.5.2(@types/node@20.14.1)(less@4.1.3)(lightningcss@1.22.1)(terser@5.31.0))
devDependencies:
'@types/lodash':
specifier: ^4.17.4
version: 4.17.4
'@types/lodash-es':
specifier: ^4.17.12
version: 4.17.12
'@types/qs':
specifier: ^6.9.15
version: 6.9.15
@ -1319,6 +1319,9 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/lodash-es@4.17.12':
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
'@types/lodash@4.17.4':
resolution: {integrity: sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==}
@ -8068,6 +8071,10 @@ snapshots:
'@types/json-schema@7.0.15': {}
'@types/lodash-es@4.17.12':
dependencies:
'@types/lodash': 4.17.4
'@types/lodash@4.17.4': {}
'@types/minimist@1.2.5': {}

View File

@ -1,5 +1,7 @@
import { getSupderInfoApi } from '@/services/system/supderLogin';
import { history } from '@umijs/max';
import './styles/global.less';
import './styles/tailwind.css';
import { routes as appRouters, loopMenuItem, type MenuItem } from './utils/router';
export function patchClientRoutes({ routes }: any) {

View File

@ -0,0 +1,146 @@
import { addPackageAPI, editPackageAPI } from '@/services/system/package';
import { ActionType, ProFormMoney, ProFormRadio, ProFormText } from '@ant-design/pro-components';
import { App, Form, Modal, Spin } from 'antd';
import { cloneDeep } from 'lodash-es';
import { useEffect, useState } from 'react';
type PropTypes = {
visible: boolean;
onCancel: () => void;
tableRef: React.RefObject<EditRow<ActionType>>;
editRow: Package.PackageItem | undefined;
};
const CreateModel = (props: PropTypes) => {
const { message } = App.useApp();
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const { visible, editRow, tableRef, onCancel } = props;
const [title, setTitle] = useState<string>();
const handleOnCancel = () => {
form.resetFields();
onCancel();
};
const handleAddNewPackage = async () => {
const values = await form.validateFields();
const _values = cloneDeep(values);
_values['day'] = parseInt(_values['day']);
_values['materialSpace'] = parseInt(_values['materialSpace']);
try {
setLoading(true);
const result = !editRow?.id ? await addPackageAPI(_values) : await editPackageAPI(_values);
if (result.code === 200) {
message.success(`套餐${editRow?.id ? '修改' : '添加'}成功`);
handleOnCancel();
tableRef.current?.reload();
}
} finally {
setLoading(false);
}
};
useEffect(() => {
setTitle(editRow?.id ? '修改套餐' : '添加套餐');
});
useEffect(() => {
form.resetFields();
if (visible) {
if (editRow?.id) {
form.setFieldsValue(editRow);
}
}
}, [visible]);
return (
<Modal
destroyOnClose
forceRender
title={title}
width={800}
open={visible}
afterClose={handleOnCancel}
onCancel={handleOnCancel}
onOk={handleAddNewPackage}
>
<Spin spinning={loading}>
<Form form={form} labelCol={{ span: 5 }}>
<ProFormText name="id" hidden></ProFormText>
<ProFormText
initialValue={''}
width="md"
name="name"
required
label="套餐名称"
placeholder="请输入套餐名称"
rules={[{ required: true, message: '请输入套餐名称' }]}
/>
<ProFormMoney
label="套餐展示金额(元)"
name="showMoney"
locale="en-US"
initialValue={0}
min={0}
placeholder="请输入套餐展示金额"
rules={[{ required: true, message: '请输入套餐展示金额' }]}
/>
<ProFormMoney
label="套餐支付金额(元)"
name="payMoney"
locale="en-US"
initialValue={0}
min={0}
placeholder="请输入套餐支付金额"
rules={[{ required: true, message: '请输入套餐支付金额' }]}
/>
<ProFormText
initialValue={0}
width="md"
name="day"
required
label="套餐天数(天)"
placeholder="请输入套餐天数"
rules={[
{
validator: (rule, value) => {
if (!/^[0-9]+$/.test(value)) {
return Promise.reject(new Error('请输入套餐天数'));
}
return Promise.resolve();
},
},
]}
/>
<ProFormRadio.Group
initialValue={'GB'}
name="type"
label="存储类型"
options={[
{
label: 'GB',
value: 'GB',
},
{
label: 'MB',
value: 'MB',
},
]}
></ProFormRadio.Group>
<ProFormText
initialValue={0}
width="md"
name="materialSpace"
required
label="套餐存储空间"
placeholder="请输入套餐存储空间"
/>
</Form>
</Spin>
</Modal>
);
};
export default CreateModel;

View File

@ -0,0 +1,134 @@
import { delPackageAPI, getPackageAPI } from '@/services/system/package';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { App, Button, message } from 'antd';
import { useRef, useState } from 'react';
import CreateModel from './createModule';
const Page = () => {
const { modal } = App.useApp();
const tableRef = useRef<ActionType>();
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const [editRow, setEditRow] = useState<EditRow<EditRow<Package.PackageItem>>>();
const columns: ProColumns[] = [
{
title: '套餐名称',
dataIndex: 'name',
align: 'center',
hideInSearch: true,
},
{
title: '用户展示金额',
dataIndex: 'showMoney',
align: 'center',
hideInSearch: true,
renderText: (_, record: Package.PackageItem) => record.showMoney + '元',
},
{
title: '实际支付金额',
dataIndex: 'payMoney',
align: 'center',
hideInSearch: true,
renderText: (_, record: Package.PackageItem) => record.payMoney + '元',
},
{
title: '套餐天数',
dataIndex: 'day',
align: 'center',
hideInSearch: true,
renderText: (_, record: Package.PackageItem) => record.day + '天',
},
{
title: '套餐容量',
dataIndex: 'materialSpace',
align: 'center',
hideInSearch: true,
renderText: (_, record: Package.PackageItem) => record.materialSpace + '' + record?.type,
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
align: 'center',
render: (_: React.ReactNode, record: Package.PackageItem) => (
<div className="space-x-4">
<Button
key={'edit'}
type="primary"
onClick={() => {
setEditRow(record);
setCreateModalVisible(true);
}}
>
</Button>
<Button
type="primary"
danger
key={'del'}
onClick={() => {
modal.confirm({
title: '提示',
content: '确定要删除该套餐?',
async onOk() {
const flag = await delPackageAPI(record.id);
if (flag) {
message.success('删除成功');
tableRef.current?.reload();
} else {
message.error('删除失败');
}
},
});
}}
>
</Button>
</div>
),
},
];
return (
<>
<ProTable
actionRef={tableRef}
columns={columns}
rowKey={'id'}
search={false}
toolBarRender={() => [
<Button
key="addSuperAdmin"
type="primary"
onClick={() => {
setCreateModalVisible(true);
}}
>
</Button>,
]}
request={async () => {
const { meta, code, data } = await getPackageAPI();
return {
data: data ?? [],
total: meta.total,
success: code === 200,
};
}}
></ProTable>
<CreateModel
visible={createModalVisible}
onCancel={() => {
setEditRow(undefined);
setCreateModalVisible(false);
}}
tableRef={tableRef}
editRow={editRow}
/>
</>
);
};
export default Page;

View File

@ -82,7 +82,6 @@ const Page = () => {
render: (_: React.ReactNode, record: SuperAdmin.SuperAdminItem) => (
<div className="space-x-4">
<Button
className="app-btn warning"
key={'edit'}
type="primary"
onClick={() => {

View File

@ -0,0 +1,126 @@
import { addUxUserAPI } from '@/services/system/user';
import { Reg } from '@/utils/reg';
import { ActionType, ProFormText } from '@ant-design/pro-components';
import { App, Form, Modal, Spin } from 'antd';
import { useEffect, useState } from 'react';
type PropTypes = {
visible: boolean;
onCancel: () => void;
onShowPwd: (email: string, password: string) => void;
tableRef: React.RefObject<EditRow<ActionType>>;
editRow: EditRow<User.UserItem>;
};
const CreateModel = (props: PropTypes) => {
const { message } = App.useApp();
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const { visible, editRow, tableRef, onCancel, onShowPwd } = props;
const [title, setTitle] = useState<string>();
const handleOnCancel = () => {
form.resetFields();
onCancel();
};
const handleAddNewUser = async () => {
const values = await form.validateFields();
try {
setLoading(true);
const dict = 'ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
const password = Array.from({ length: 8 }, () => dict[Math.round(dict.length * Math.random())]).join('');
const submitData = values;
submitData['password'] = password;
const result = await addUxUserAPI(submitData);
if (result.code === 200) {
message.success(`用户添加成功`);
handleOnCancel();
onShowPwd(values.email, password);
tableRef.current?.reload();
}
} finally {
setLoading(false);
}
};
useEffect(() => {
setTitle(editRow?.id ? '修改用户' : '添加用户');
}, []);
useEffect(() => {
form.resetFields();
if (visible) {
if (editRow?.id) {
form.setFieldsValue(editRow);
}
}
}, [visible]);
return (
<Modal
destroyOnClose
forceRender
title={title}
width={600}
open={visible}
afterClose={handleOnCancel}
onCancel={handleOnCancel}
onOk={handleAddNewUser}
>
<Spin spinning={loading}>
<Form form={form} labelCol={{ span: 5 }}>
<ProFormText name="id" hidden></ProFormText>
<ProFormText
initialValue={''}
width="md"
name="email"
required
label="邮箱"
placeholder="请输入邮箱"
rules={[
{ required: true, message: '请输入邮箱' },
{ pattern: Reg.Email, message: '邮箱格式不正确' },
]}
/>
<ProFormText
initialValue={''}
width="md"
name="userName"
required
label="用户名称"
placeholder="请输入用户名称"
rules={[{ required: true, message: '请输入用户名称' }]}
/>
{/* <Form.Item label="" required>
<Space size="middle">
{packageOptions.map((item) => {
return (
<Card
key={item.id}
title={item.name}
size="small"
className={`cursor-pointer ${choosePackage === item.id ? 'border-[#1677ff] border-2' : ''}`}
onClick={() => {
setChoosePackage(item.id);
}}
>
<div>{item.showMoney}</div>
<div>{item.payMoney}</div>
<div>
{item.materialSpace}
{item.type}
</div>
</Card>
);
})}
</Space>
</Form.Item> */}
</Form>
</Spin>
</Modal>
);
};
export default CreateModel;

View File

@ -0,0 +1,107 @@
import { getPackageAPI } from '@/services/system/package';
import { openPackageAPI } from '@/services/system/user';
import { ActionType } from '@ant-design/pro-components';
import { App, Card, Form, Modal, Space, Spin } from 'antd';
import { useEffect, useState } from 'react';
type PropTypes = {
visible: boolean;
onCancel: () => void;
tableRef: React.RefObject<EditRow<ActionType>>;
editRow: EditRow<User.UserItem>;
};
const OpenPackageModel = (props: PropTypes) => {
const { message } = App.useApp();
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [packageOptions, setPackage] = useState<Package.PackageItem[]>([]);
const [choosePackage, setChoosePackage] = useState<string>();
const { visible, editRow, tableRef, onCancel } = props;
const [title, setTitle] = useState<string>();
const handleOnCancel = () => {
form.resetFields();
onCancel();
};
const getPackageList = () => {
getPackageAPI().then((result) => {
setPackage(result.data);
});
};
const handleSubmit = async () => {
if (!choosePackage) {
message.warning('请选择一个套餐');
return;
}
try {
setLoading(true);
const result = await openPackageAPI({ id: editRow!.id, packageId: choosePackage });
if (result.code === 200) {
message.success(result.message);
handleOnCancel();
tableRef.current?.reload();
}
} finally {
setLoading(false);
}
};
useEffect(() => {
getPackageList();
setTitle('开通用户套餐');
}, []);
useEffect(() => {
if (visible) {
setChoosePackage(undefined);
}
}, [visible]);
return (
<Modal
destroyOnClose
forceRender
title={title}
width={700}
open={visible}
afterClose={handleOnCancel}
onCancel={handleOnCancel}
onOk={handleSubmit}
>
<Spin spinning={loading}>
<Form form={form} labelCol={{ span: 5 }}>
<Form.Item label="开通套餐" required>
<Space size="middle">
{packageOptions.map((item) => {
return (
<Card
key={item.id}
title={item.name}
size="small"
className={`cursor-pointer ${choosePackage === item.id ? 'border-[#1677ff] border-2' : ''}`}
onClick={() => {
setChoosePackage(item.id);
}}
>
<div>{item.showMoney}</div>
<div>{item.payMoney}</div>
<div>
{item.materialSpace}
{item.type}
</div>
</Card>
);
})}
</Space>
</Form.Item>
</Form>
</Spin>
</Modal>
);
};
export default OpenPackageModel;

View File

@ -0,0 +1,120 @@
import { getUserByIdAPI } from '@/services/system/user';
import { ActionType } from '@ant-design/pro-components';
import { Descriptions, Form, Modal, Spin, Tabs } from 'antd';
import { useEffect, useState } from 'react';
type PropTypes = {
visible: boolean;
onCancel: () => void;
tableRef: React.RefObject<EditRow<ActionType>>;
editRow: EditRow<User.UserItem>;
};
const UserDetailsModal = (props: PropTypes) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [tabType, setTabType] = useState('details');
const [userInfo, setUserInfo] = useState<User.UserItem>();
const [projectCount, setProjectCount] = useState<User.UserItemByInfo['projectCount']>(0);
const [materialsCount, setMaterialsCount] = useState<User.UserItemByInfo['materialsCount']>(0);
const [materialsGroup, setMaterialsGroup] = useState<User.UserItemByInfo['materialsGroup']>([]);
const { visible, editRow, onCancel } = props;
const [title, setTitle] = useState<string>();
const handleOnCancel = () => {
form.resetFields();
onCancel();
};
const handleGetUserInfo = () => {
setLoading(true);
getUserByIdAPI(editRow!.id)
.then((result) => {
if (result.code === 200) {
setUserInfo(result.data.userInfo);
setProjectCount(result.data.projectCount);
setMaterialsCount(result.data.materialsCount);
setMaterialsGroup(result.data.materialsGroup);
}
})
.finally(() => {
setLoading(false);
});
};
useEffect(() => {
setTitle('用户详情');
}, []);
useEffect(() => {
if (visible) {
handleGetUserInfo();
}
}, [visible]);
const RenderUserDetails = () => {
if (!userInfo) return <></>;
return (
<Descriptions size="small" column={{ xs: 1, sm: 2, md: 3, lg: 3 }} bordered>
<Descriptions.Item label="邮箱">{userInfo.email}</Descriptions.Item>
<Descriptions.Item label="用户名称">{userInfo.userName}</Descriptions.Item>
<Descriptions.Item label="套餐信息">
{userInfo?.package?.name +
'/' +
userInfo?.package?.showMoney +
'元' +
'/' +
userInfo?.package?.materialSpace +
userInfo?.package?.type}
</Descriptions.Item>
<Descriptions.Item label="总存储空间">
{userInfo?.increasedStorageInKb && (userInfo.increasedStorageInKb / 1024).toFixed(2) + 'MB'}
</Descriptions.Item>
<Descriptions.Item label="已使用空间">
{userInfo?.UserProfile && (userInfo.UserProfile.storageUsedInKb / 1024).toFixed(2) + 'MB'}
</Descriptions.Item>
<Descriptions.Item label="剩余存储空间">
{((userInfo.increasedStorageInKb! - userInfo!.UserProfile!.storageUsedInKb) / 1024).toFixed(2) + 'MB'}
</Descriptions.Item>
<Descriptions.Item label="项目数量">{projectCount}</Descriptions.Item>
<Descriptions.Item label="素材数量">{materialsCount}</Descriptions.Item>
<Descriptions.Item label="素材分组">
<div className="flex space-x-2">
{materialsGroup.map((item, index) => {
return (
<span key={index} className="text-xs">
{item.materialType}({item._count})
</span>
);
})}
</div>
</Descriptions.Item>
</Descriptions>
);
};
return (
<Modal
destroyOnClose
forceRender
title={title}
width={1200}
open={visible}
afterClose={handleOnCancel}
onCancel={handleOnCancel}
>
<Spin spinning={loading}>
<Tabs activeKey={tabType} onChange={(activeKey) => setTabType(activeKey)}>
<Tabs.TabPane key={'details'} tab={'用户详情'}>
<RenderUserDetails />
</Tabs.TabPane>
<Tabs.TabPane key={'handleLogs'} tab={'操作记录'}></Tabs.TabPane>
<Tabs.TabPane key={'orderInfo'} tab={'订单信息'}></Tabs.TabPane>
</Tabs>
</Spin>
</Modal>
);
};
export default UserDetailsModal;

View File

@ -1,5 +1,278 @@
const UserPage = () => {
return <>1231</>;
import { changeStatusAPI, delUxUserAPI, getUserListAPI } from '@/services/system/user';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { App, Button, Space, TableProps, message } from 'antd';
import { useRef, useState } from 'react';
import CreateModel from './CreateModule';
import OpenPackageModel from './OpenPackage';
import UserDetailsModal from './UserDetails';
const Page = () => {
const { modal } = App.useApp();
const tableRef = useRef<ActionType>();
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const [openPackageVisible, setOpenPackageVisible] = useState<boolean>(false);
const [userDetailsVisible, setUserDetailsVisible] = useState<boolean>(false);
const [editRow, setEditRow] = useState<EditRow<User.UserItem>>();
const [tableParams, setTableParams] = useState<TableParams>({
pagination: {
current: 1,
pageSize: 10,
},
});
const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter) => {
setTableParams({
pagination,
filters,
...sorter,
});
};
export default UserPage;
const handleChangeUserStatus = (record: User.UserItem) => {
modal.confirm({
title: '提示',
content: `确定要将用户【${record.email}${record.enabled ? '禁用' : '启用'}`,
async onOk() {
const result = await changeStatusAPI({ id: record.id, enabled: !record.enabled });
if (result.code === 200) {
message.success(result.message);
tableRef.current?.reload();
}
},
});
};
const columns: ProColumns[] = [
{
title: '邮箱',
dataIndex: 'email',
align: 'center',
hideInSearch: true,
render: (_, record: User.UserItem) => {
return (
<Button
type="link"
onClick={() => {
setEditRow(record);
setUserDetailsVisible(true);
}}
>
{record.email}
</Button>
);
},
},
{
title: '用户名称',
dataIndex: 'userName',
align: 'center',
hideInSearch: true,
},
{
title: '当前套餐',
dataIndex: 'packageId',
align: 'center',
hideInSearch: true,
renderText: (_, record: User.UserItem) => {
if (!record.package) {
return '-';
}
return (
record?.package?.name +
'/' +
record.package.showMoney +
'元' +
'/' +
record?.package?.materialSpace +
record?.package?.type
);
},
},
{
title: '用户来源',
dataIndex: 'userSource',
align: 'center',
hideInSearch: true,
render: (_, record: User.UserItem) => {
// 用户来源 1. ux 注册 2. 后台创建
if (record.userSource === 1) {
return 'ux 注册';
} else if (record.userSource === 2) {
return '管理员创建';
}
return record.userSource;
},
},
{
title: '状态',
dataIndex: 'enabled',
align: 'center',
hideInSearch: true,
render: (_, record: User.UserItem) => {
if (record.enabled === true) {
return (
<div className="flex items-center space-x-2 justify-center">
<span className="w-[10px] h-[10px] rounded-full bg-green"></span>
<span></span>
</div>
);
}
return (
<div className="flex items-center space-x-2 justify-center">
<span className="w-[10px] h-[10px] rounded-full bg-gray"></span>
<span></span>
</div>
);
},
},
{
title: '账户创建时间',
dataIndex: 'createdDateTime',
align: 'center',
hideInSearch: true,
},
{
title: '最后登录时间',
dataIndex: 'lastLoginTime',
align: 'center',
hideInSearch: true,
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
align: 'center',
render: (_: React.ReactNode, record: User.UserItem) => (
<div className="space-x-4">
{!record.packageId && (
<Button
key={'openPackage'}
type="primary"
onClick={() => {
setEditRow(record);
setOpenPackageVisible(true);
}}
>
</Button>
)}
<Button
className="app-btn warning"
key={'changeStatus'}
type="primary"
onClick={() => {
handleChangeUserStatus(record);
}}
>
{record.enabled ? '禁用' : '启用'}
</Button>
<Button
type="primary"
danger
key={'delUser'}
onClick={() => {
modal.confirm({
title: '提示',
content: '确定要删除该用户?',
async onOk() {
const flag = await delUxUserAPI(record.id);
if (flag.code === 200) {
tableRef.current?.reload();
}
},
});
}}
>
</Button>
</div>
),
},
];
return (
<>
<ProTable
actionRef={tableRef}
columns={columns}
rowKey={'id'}
pagination={tableParams.pagination}
onChange={handleTableChange}
search={{
labelWidth: 140,
span: { xs: 24, sm: 24, md: 12, lg: 12, xl: 6, xxl: 6 },
}}
toolBarRender={() => [
<Button
key="addUxAdmin"
type="primary"
onClick={() => {
setCreateModalVisible(true);
}}
>
</Button>,
]}
request={async (params) => {
const { current, pageSize } = params;
const _params = { current, pageSize };
const { meta, code, data } = await getUserListAPI(_params);
return {
data: data ?? [],
total: meta.total,
success: code === 200,
};
}}
></ProTable>
<CreateModel
visible={createModalVisible}
onCancel={() => {
setEditRow(undefined);
setCreateModalVisible(false);
}}
onShowPwd={(email, password) => {
modal.info({
title: '账号创建成功',
cancelButtonProps: {
hidden: true,
},
content: (
<>
<Space direction="vertical" size="middle">
<div>{email}</div>
<div>{password}</div>
</Space>
</>
),
});
}}
tableRef={tableRef}
editRow={editRow}
/>
<OpenPackageModel
visible={openPackageVisible}
onCancel={() => {
setEditRow(undefined);
setOpenPackageVisible(false);
}}
tableRef={tableRef}
editRow={editRow}
/>
<UserDetailsModal
visible={userDetailsVisible}
onCancel={() => {
setEditRow(undefined);
setUserDetailsVisible(false);
}}
tableRef={tableRef}
editRow={editRow}
/>
</>
);
};
export default Page;

View File

@ -0,0 +1,17 @@
import request from '@/utils/request';
export const getPackageAPI = (): Promise<API.ResponstList<Package.PackageItem[]>> => {
return request.get(`/system/package`);
};
export const addPackageAPI = (data: Record<string, any>): Promise<API.ResponstBody> => {
return request.post(`/system/package`, data);
};
export const editPackageAPI = (data: Record<string, any>): Promise<API.ResponstBody> => {
return request.put(`/system/package`, data);
};
export const delPackageAPI = (id: string): Promise<API.ResponstBody> => {
return request.delete(`/system/package/${id}`);
};

View File

@ -0,0 +1,11 @@
declare namespace Package {
type PackageItem = {
id: string;
name: string;
showMoney?: number;
payMoney?: string;
day?: number;
type?: string;
materialSpace?: number;
};
}

View File

@ -0,0 +1,26 @@
import request from '@/utils/request';
import qs from 'qs';
export const getUserListAPI = (params: Record<string, any>): Promise<API.ResponstList<User.UserItem[]>> => {
return request.get(`/system/user?` + qs.stringify(params));
};
export const getUserByIdAPI = (id: string): Promise<API.ResponstList<User.UserItemByInfo>> => {
return request.get(`/system/user/getUserById/` + id);
};
export const addUxUserAPI = (params: User.UserItem): Promise<API.ResponstBody> => {
return request.post('/system/user', params);
};
export const changeStatusAPI = (params: User.UserItem): Promise<API.ResponstBody> => {
return request.put('/system/user/changeStatus', params);
};
export const delUxUserAPI = (id: string): Promise<API.ResponstBody> => {
return request.delete('/system/user/' + id);
};
export const openPackageAPI = (params: User.UserItem): Promise<API.ResponstBody> => {
return request.post('/system/user/openPackage', params);
};

View File

@ -0,0 +1,39 @@
declare namespace User {
type UserProfile = {
id: string;
storageUsedInKb: number;
};
type UserItem = {
id: string;
userName?: string;
email?: string;
password?: string;
passwordHash?: string;
enabled?: boolean;
packageId?: string;
expired?: string;
// 用户来源 1. ux 注册 2. 后台创建
userSource?: number;
// 用户总空间
increasedStorageInKb?: number;
createdDateTime?: string;
lastUpdateDateTime?: string;
lastLoginTime?: string;
packageId?: string;
package?: Package.PackageItem;
UserProfile?: UserProfile;
};
type UserItemByInfo = {
userInfo: UserItem;
materialsCount: number;
projectCount: number;
projectCount: number;
materialsGroup: { _count: number; materialType: string }[];
};
}

View File

@ -0,0 +1,11 @@
@import url('var.less');
.app-btn {
&.warning {
background-color: @btn-warning;
&:hover {
background-color: @btn-warning__hover !important;
}
}
}

View File

@ -0,0 +1,3 @@
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';

View File

@ -0,0 +1,2 @@
@btn-warning: #f5b753;
@btn-warning__hover: #f5b753;

View File

@ -21,6 +21,11 @@ export const routes: any[] = [
name: '系统管理',
path: '/system',
children: [
{
name: '套餐设置',
path: '/system/package',
component: '/System/Package',
},
{
name: '管理员设置',
path: '/system/superAdmin',

7
typings.d.ts vendored
View File

@ -3,6 +3,13 @@ import '@umijs/max/typings';
declare global {
declare type EditRow<T> = T | undefined;
interface TableParams {
pagination?: TablePaginationConfig;
sortField?: string;
sortOrder?: string;
filters?: Parameters<GetProp<TableProps, 'onChange'>>[1];
}
const API_URL: string;
}