diff --git a/package.json b/package.json index f51de3a..e42aa10 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 42977c8..0ee45da 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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': {} diff --git a/src/app.tsx b/src/app.tsx index c939f94..c92b3ff 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -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) { diff --git a/src/pages/System/Package/createModule.tsx b/src/pages/System/Package/createModule.tsx new file mode 100644 index 0000000..9ba2ba9 --- /dev/null +++ b/src/pages/System/Package/createModule.tsx @@ -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: 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(); + + 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 ( + + +
+ + + + + { + if (!/^[0-9]+$/.test(value)) { + return Promise.reject(new Error('请输入套餐天数')); + } + return Promise.resolve(); + }, + }, + ]} + /> + + + +
+
+ ); +}; + +export default CreateModel; diff --git a/src/pages/System/Package/index.tsx b/src/pages/System/Package/index.tsx new file mode 100644 index 0000000..901f3c7 --- /dev/null +++ b/src/pages/System/Package/index.tsx @@ -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(); + + const [createModalVisible, setCreateModalVisible] = useState(false); + const [editRow, setEditRow] = useState>>(); + + 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) => ( +
+ + +
+ ), + }, + ]; + + return ( + <> + [ + , + ]} + request={async () => { + const { meta, code, data } = await getPackageAPI(); + return { + data: data ?? [], + total: meta.total, + success: code === 200, + }; + }} + > + + { + setEditRow(undefined); + setCreateModalVisible(false); + }} + tableRef={tableRef} + editRow={editRow} + /> + + ); +}; + +export default Page; diff --git a/src/pages/System/SuperAdmin/index.tsx b/src/pages/System/SuperAdmin/index.tsx index e2f263f..3829874 100644 --- a/src/pages/System/SuperAdmin/index.tsx +++ b/src/pages/System/SuperAdmin/index.tsx @@ -82,7 +82,6 @@ const Page = () => { render: (_: React.ReactNode, record: SuperAdmin.SuperAdminItem) => (
+ ); + }, + }, + { + 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 ( +
+ + 启用 +
+ ); + } + return ( +
+ + 禁用 +
+ ); + }, + }, + { + 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) => ( +
+ {!record.packageId && ( + + )} + + +
+ ), + }, + ]; + + return ( + <> + [ + , + ]} + 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, + }; + }} + > + + { + setEditRow(undefined); + setCreateModalVisible(false); + }} + onShowPwd={(email, password) => { + modal.info({ + title: '账号创建成功', + cancelButtonProps: { + hidden: true, + }, + content: ( + <> + +
登录账号:{email}
+
登录密码:{password}
+
+ + ), + }); + }} + tableRef={tableRef} + editRow={editRow} + /> + + { + setEditRow(undefined); + setOpenPackageVisible(false); + }} + tableRef={tableRef} + editRow={editRow} + /> + + { + setEditRow(undefined); + setUserDetailsVisible(false); + }} + tableRef={tableRef} + editRow={editRow} + /> + + ); }; -export default UserPage; +export default Page; diff --git a/src/services/system/package/index.ts b/src/services/system/package/index.ts new file mode 100644 index 0000000..0241d76 --- /dev/null +++ b/src/services/system/package/index.ts @@ -0,0 +1,17 @@ +import request from '@/utils/request'; + +export const getPackageAPI = (): Promise> => { + return request.get(`/system/package`); +}; + +export const addPackageAPI = (data: Record): Promise => { + return request.post(`/system/package`, data); +}; + +export const editPackageAPI = (data: Record): Promise => { + return request.put(`/system/package`, data); +}; + +export const delPackageAPI = (id: string): Promise => { + return request.delete(`/system/package/${id}`); +}; diff --git a/src/services/system/package/typing.d.ts b/src/services/system/package/typing.d.ts new file mode 100644 index 0000000..31595cf --- /dev/null +++ b/src/services/system/package/typing.d.ts @@ -0,0 +1,11 @@ +declare namespace Package { + type PackageItem = { + id: string; + name: string; + showMoney?: number; + payMoney?: string; + day?: number; + type?: string; + materialSpace?: number; + }; +} diff --git a/src/services/system/user/index.ts b/src/services/system/user/index.ts new file mode 100644 index 0000000..524b067 --- /dev/null +++ b/src/services/system/user/index.ts @@ -0,0 +1,26 @@ +import request from '@/utils/request'; +import qs from 'qs'; + +export const getUserListAPI = (params: Record): Promise> => { + return request.get(`/system/user?` + qs.stringify(params)); +}; + +export const getUserByIdAPI = (id: string): Promise> => { + return request.get(`/system/user/getUserById/` + id); +}; + +export const addUxUserAPI = (params: User.UserItem): Promise => { + return request.post('/system/user', params); +}; + +export const changeStatusAPI = (params: User.UserItem): Promise => { + return request.put('/system/user/changeStatus', params); +}; + +export const delUxUserAPI = (id: string): Promise => { + return request.delete('/system/user/' + id); +}; + +export const openPackageAPI = (params: User.UserItem): Promise => { + return request.post('/system/user/openPackage', params); +}; diff --git a/src/services/system/user/typing.d.ts b/src/services/system/user/typing.d.ts new file mode 100644 index 0000000..7f81225 --- /dev/null +++ b/src/services/system/user/typing.d.ts @@ -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 }[]; + }; +} diff --git a/src/styles/global.less b/src/styles/global.less new file mode 100644 index 0000000..139f90b --- /dev/null +++ b/src/styles/global.less @@ -0,0 +1,11 @@ +@import url('var.less'); + +.app-btn { + &.warning { + background-color: @btn-warning; + + &:hover { + background-color: @btn-warning__hover !important; + } + } +} diff --git a/src/styles/tailwind.css b/src/styles/tailwind.css new file mode 100644 index 0000000..a31e444 --- /dev/null +++ b/src/styles/tailwind.css @@ -0,0 +1,3 @@ +@import 'tailwindcss/base'; +@import 'tailwindcss/components'; +@import 'tailwindcss/utilities'; diff --git a/src/styles/var.less b/src/styles/var.less new file mode 100644 index 0000000..8113e51 --- /dev/null +++ b/src/styles/var.less @@ -0,0 +1,2 @@ +@btn-warning: #f5b753; +@btn-warning__hover: #f5b753; diff --git a/src/utils/router.tsx b/src/utils/router.tsx index abf6c84..137b24e 100644 --- a/src/utils/router.tsx +++ b/src/utils/router.tsx @@ -21,6 +21,11 @@ export const routes: any[] = [ name: '系统管理', path: '/system', children: [ + { + name: '套餐设置', + path: '/system/package', + component: '/System/Package', + }, { name: '管理员设置', path: '/system/superAdmin', diff --git a/typings.d.ts b/typings.d.ts index d117dc4..233a919 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -3,6 +3,13 @@ import '@umijs/max/typings'; declare global { declare type EditRow = T | undefined; + interface TableParams { + pagination?: TablePaginationConfig; + sortField?: string; + sortOrder?: string; + filters?: Parameters>[1]; + } + const API_URL: string; }