Browse Source

commit

main
mac 2 months ago
parent
commit
e6eedf941c
  1. 28
      src/api/index.ts
  2. 36
      src/assets/js/publicFunc.ts
  3. 3
      src/components/Header/index.tsx
  4. 3
      src/components/Menu/index.tsx
  5. 2
      src/components/TabPanes/index.tsx
  6. 228
      src/pages/config-admin/admin-manage.tsx
  7. 124
      src/pages/config-admin/admin-permissions.tsx
  8. 11
      src/pages/container/index.tsx
  9. 4
      src/pages/login/index.tsx
  10. 4
      src/pages/system/withdraw.tsx
  11. 34
      src/pages/vip-manage/proxy-list.tsx
  12. 29
      src/route/routes.ts
  13. 5
      src/utils/axios.ts

28
src/api/index.ts

@ -164,5 +164,31 @@ export default {
copy_tradeapi(data: object) {
return $axios.post('/admin/copytradeapi', data)
},
cancel_follow(data: object) {
return $axios.post('/admin/copytradeapiDelete', data)
},
get_adminList(data: object) {
return $axios.post('/admin/administratorList', data)
},
add_adminList(data: object) {
return $axios.post('/admin/addAdministratorList', data)
},
delete_adminList(data: object) {
return $axios.post('/admin/delAdministratorList', data)
},
update_adminList(data: object) {
return $axios.post('/admin/updAdministratorList', data)
},
update_adminPassword(data: object) {
return $axios.post('/admin/updAdministratorPassword', data)
},
get_adminPermissionList(data: object) {
return $axios.post('/admin/permissionsList', data)
},
get_adminPermissionsUser(data: object) {
return $axios.post('/admin/permissionsUser', data)
},
set_adminPermissionList(data: object) {
return $axios.post('/admin/setPermissions', data)
},
}

36
src/assets/js/publicFunc.ts

@ -14,7 +14,7 @@ export const commonConfirm = (title: string, cb: () => void) => {
onOk() {
cb()
},
onCancel() {}
onCancel() { }
})
}
@ -52,7 +52,7 @@ export const getKeyName = (path: string = '/403') => {
const curRoute = flattenRoutes(routes).filter(
(item: { path: string | string[] }) => item.path.includes(truePath)
)
if (!curRoute[0])
return { title: '暂无权限', tabKey: '403', component: ErrorPage }
const { name, key, component } = curRoute[0]
@ -214,8 +214,12 @@ export const getPermission = () => localStorage.getItem('permissions') || []
*
*/
export const isAuthorized = (val: string): boolean => {
const permissions = getPermission();
return permissions.includes(val)
let permissions: any = getPermission();
if (typeof permissions === 'string') {
permissions = JSON.parse(permissions)
}
return permissions.map(v => v.key).includes(val)
}
/**
@ -297,18 +301,8 @@ export const setUserInfo = (
oldToken?: string
) => {
const { permission, userName, token } = userInfo
console.log(permission);
const permissionArray = permission.reduce(
(prev: CommonObjectType<string>[], next: CommonObjectType<string>) => [
...prev,
next.code
],
[]
);
localStorage.setItem('permissions', permissionArray)
localStorage.setItem('permissions', JSON.stringify(flattenRoutes(permission)))
const result = {
userName,
@ -422,18 +416,18 @@ export const treeFindParentById = (tree: Array<any>, id: string | number): Array
const forFn = function (tree, id) {
for (let i = 0; i < tree.length; i++) {
const data = tree[i]
if (data.id === id) {
return path
}
path.push(data.id)
if (data.children) {
const findChildren = forFn(data.children, id);
if (findChildren && findChildren.length > 0) return findChildren
}
path.pop()
}
}
@ -446,7 +440,7 @@ export const treeFindParentById = (tree: Array<any>, id: string | number): Array
* @param arr1
* @param arr2
*/
export const diffArray = (arr1: Array<number | string>, arr2: Array<number | string>): Array< number | string>=> {
export const diffArray = (arr1: Array<number | string>, arr2: Array<number | string>): Array<number | string> => {
const diff: Array<number | string> = []
for (let idx = 0; idx < arr1.length; idx++) {
if (!arr2.includes(arr1[idx])) {

3
src/components/Header/index.tsx

@ -7,7 +7,7 @@ import { connect } from 'react-redux'
import * as actions from '@/store/actions'
import style from './Header.module.less'
interface Props extends ReduxProps {}
interface Props extends ReduxProps { }
const Header: FC<Props> = ({
storeData: { collapsed, theme, userInfo },
@ -18,6 +18,7 @@ const Header: FC<Props> = ({
const firstWord = userName.slice(0, 1)
const logout = async () => {
await setStoreData('SET_USERINFO', {})
localStorage.setItem('permissions', '')
history.replace({ pathname: '/login' })
}

3
src/components/Menu/index.tsx

@ -22,6 +22,7 @@ const MenuView: FC<Props> = ({ storeData: { theme, userInfo, collapsed } }) => {
const { tabKey: curKey = 'home' } = getKeyName(pathname)
const [current, setCurrent] = useState(curKey)
const { permission = [] } = userInfo
// 递归逐级向上获取最近一级的菜单,并高亮
const higherMenuKey = useCallback(
(checkKey = 'home', path = pathname) => {
@ -133,7 +134,7 @@ const MenuView: FC<Props> = ({ storeData: { theme, userInfo, collapsed } }) => {
selectedKeys={[current]}
theme={theme === 'default' ? 'light' : 'dark'}
>
{renderMenuMap(menus)}
{renderMenuMap(permission)}
</Menu>
</Layout.Sider>
)

2
src/components/TabPanes/index.tsx

@ -46,7 +46,7 @@ const TabPanes: FC<Props> = (props) => {
const [isReload, setIsReload] = useState<boolean>(false)
const [selectedPanel, setSelectedPanel] = useState<CommonObjectType>({})
const pathRef: RefType = useRef<string>('')
const {
storeData: { curTab, reloadPath },
setStoreData,

228
src/pages/config-admin/admin-manage.tsx

@ -0,0 +1,228 @@
import api from "@/api"
import MyTable from "@/components/MyTable"
import { DeleteOutlined, EditOutlined } from "@ant-design/icons";
import { Button, Form, Input, Modal, Popconfirm, Radio, Switch, notification } from "antd";
import React, { useRef, useState } from "react"
const AdminManage = () => {
const tableRef = useRef(null)
const currentItem = useRef({} as any)
const [visible, setVisible] = useState(false)
const [visibleUpdate, setVisibleUpdate] = useState(false)
const [form] = Form.useForm()
const [updateForm] = Form.useForm()
const [path, setPath] = useState('info')
const createAdmin = async (values) => {
setVisible(false)
const params = {
...values,
status_code: values.status_code ? 1 : 2
}
const res: any = await api.add_adminList(params)
if (res.code === 0) {
tableRef.current.update()
form.resetFields()
notification.success({
message: '添加成功'
})
}
}
const updateAdmin = async (values) => {
setVisibleUpdate(false)
const params = {
...values,
id: currentItem.current.id
}
if (path === 'info') {
params.status_code = values.status_code ? 1 : 2;
}
let res: any = {}
if (path === 'info') {
res = await api.update_adminList(params)
} else {
res = await api.update_adminPassword(params)
}
if (res.code === 0) {
tableRef.current.update()
updateForm.resetFields()
notification.success({
message: '修改成功'
})
}
}
const columns = [
{
title: '操作',
width: 200,
render: (row) => (
<div style={{ display: 'flex' }}>
{/* <Popconfirm title="" onConfirm={() => deleteAdmin(row)}>
<DeleteOutlined />
</Popconfirm> */}
<EditOutlined onClick={() => {
currentItem.current = row
setVisibleUpdate(true)
updateForm.setFieldsValue({
...row,
status_code: row.status_code === 1 ? true : false
})
}} />
</div>
)
},
{
dataIndex: 'user_name',
title: '帐号',
width: 200
},
{
dataIndex: 'email',
title: '邮箱',
width: 200
},
{
dataIndex: 'name',
title: '姓名',
width: 200
},
{
dataIndex: 'phone',
title: '手机',
width: 200
},
{
dataIndex: 'position',
title: '职位',
width: 200
},
{
dataIndex: 'status',
title: '状态',
},
// {
// dataIndex: 'status_code',
// title: '状态码 1:正常 2:锁定',
// width: 200
// },
];
return (
<div>
<MyTable
columns={columns}
ref={tableRef}
apiFun={api.get_adminList}
header={
<Button type="primary" style={{ marginBottom: 20 }} onClick={() => {
setVisible(true)
}}></Button>
}
/>
<Modal
visible={visible}
onCancel={() => setVisible(false)}
title="添加管理员"
footer={() => null}
>
<Form form={form} onFinish={createAdmin}>
<Form.Item name="name" label="姓名" rules={[{ required: true, message: '请输入姓名' }]} >
<Input placeholder="请输入姓名" />
</Form.Item>
<Form.Item name="phone" label="手机号" rules={[{ required: true, message: '请输入手机号' }]}>
<Input placeholder="请输入手机号" />
</Form.Item>
<Form.Item name="email" label="邮箱" rules={[{ required: true, message: '请输入邮箱' }, { type: 'email', message: '邮箱格式错误' }]}>
<Input placeholder="请输入邮箱" />
</Form.Item>
<Form.Item name="position" label="职位" rules={[{ required: true, message: '请输入职位' }]}>
<Input placeholder="请输入职位" />
</Form.Item>
<Form.Item name="user_name" label="账号" rules={[{ required: true, message: '请输入账号' }]}>
<Input placeholder="请输入账号" />
</Form.Item>
<Form.Item name="password" label="密码" rules={[{ required: true, message: '请输入密码' }]}>
<Input placeholder="请输入密码" />
</Form.Item>
<Form.Item name="status_code" initialValue={true} valuePropName="checked" label="冻结/正常">
<Switch />
</Form.Item>
<Form.Item style={{ display: 'flex' }} label="操作">
<Button onClick={() => setVisible(false)}></Button>
<Button type="primary" htmlType="submit" style={{ marginLeft: 20 }}></Button>
</Form.Item>
</Form>
</Modal>
<Modal
visible={visibleUpdate}
footer={() => null}
onCancel={() => setVisibleUpdate(false)}
title={`修改管理员信息:${currentItem.current.name}`}
>
<Radio.Group value={path} onChange={e => setPath(e.target.value)} style={{ marginBottom: 20 }}>
<Radio.Button value="info"></Radio.Button>
<Radio.Button value="pwd"></Radio.Button>
</Radio.Group>
<Form form={updateForm} onFinish={updateAdmin}>
{
path === 'info' ? (
<>
<Form.Item name="name" label="姓名" rules={[{ required: true, message: '请输入姓名' }]} >
<Input placeholder="请输入姓名" />
</Form.Item>
<Form.Item name="phone" label="手机号" rules={[{ required: true, message: '请输入手机号' }]}>
<Input placeholder="请输入手机号" />
</Form.Item>
<Form.Item name="email" label="邮箱" rules={[{ required: true, message: '请输入邮箱' }, { type: 'email', message: '邮箱格式错误' }]}>
<Input placeholder="请输入邮箱" />
</Form.Item>
<Form.Item name="position" label="职位" rules={[{ required: true, message: '请输入职位' }]}>
<Input placeholder="请输入职位" />
</Form.Item>
<Form.Item name="user_name" label="账号" rules={[{ required: true, message: '请输入账号' }]}>
<Input placeholder="请输入账号" />
</Form.Item>
<Form.Item name="status_code" initialValue={true} valuePropName="checked" label="冻结/正常">
<Switch />
</Form.Item>
</>
) : (
<Form.Item name="password" label="密码" rules={[{ required: true, message: '请输入密码' }]}>
<Input placeholder="请输入密码" />
</Form.Item>
)
}
<Form.Item style={{ display: 'flex' }} label="操作">
<Button onClick={() => setVisibleUpdate(false)}></Button>
<Button type="primary" htmlType="submit" style={{ marginLeft: 20 }}></Button>
</Form.Item>
</Form>
</Modal>
</div >
)
}
export default AdminManage

124
src/pages/config-admin/admin-permissions.tsx

@ -0,0 +1,124 @@
import api from "@/api"
import MyTable from "@/components/MyTable"
import { EditOutlined } from "@ant-design/icons"
import { Modal, Tree, notification } from "antd"
import React, { useRef, useState } from "react"
const AdminPermissions = () => {
const tableRef = useRef(null)
const currentItem = useRef({} as any)
const [visible, setVisible] = useState(false)
const [treeData, setTreeData] = useState([] as any)
const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([]);
const treeDataKey = useRef({} as any)
const getPermissions = async (row) => {
currentItem.current = row
const res: any = await api.get_adminPermissionList({ id: row.id })
console.log(res);
if (res.code === 0) {
setTreeData(res.data)
getAllChecked(res.data)
setVisible(true)
}
}
// 获取所有选中的key
const getAllChecked = (data) => {
let keys = [];
let stack = [...data];
while (stack.length > 0) {
const node = stack.pop();
treeDataKey.current[node.key] = node.id
if (node.flag) {
keys.push(node.key);
}
if (node.children) {
stack = stack.concat(node.children);
}
}
setCheckedKeys(keys)
}
const setPermission = async () => {
const ids = checkedKeys.map(item => treeDataKey.current[item])
if (ids.length <= 0) return notification.warning({
message: '请选择权限'
})
const params = {
adminId: currentItem.current.id,
menuId: ids.join(',')
}
setVisible(false)
setCheckedKeys([])
currentItem.current = {}
treeDataKey.current = {}
setTreeData([])
const res: any = await api.set_adminPermissionList(params)
if (res.code === 0) {
tableRef.current.update()
notification.success({
message: '修改成功'
})
}
}
const columns = [
{
title: '操作',
render: (row) => (
<div>
<EditOutlined onClick={() => getPermissions(row)} />
</div>
)
},
{
title: 'ID',
dataIndex: 'id'
},
{
title: '名称',
dataIndex: 'name'
}
]
const onCheck = (checkedKeysValue) => {
console.log('onCheck', checkedKeysValue);
setCheckedKeys(checkedKeysValue as React.Key[]);
};
return (
<div>
<MyTable
ref={tableRef}
apiFun={api.get_adminPermissionsUser}
columns={columns}
>
</MyTable>
<Modal
title={`分配权限:${currentItem.current.name}`}
visible={visible}
onCancel={() => setVisible(false)}
onOk={setPermission}
>
<Tree
checkable
defaultExpandAll={true}
onCheck={onCheck}
checkedKeys={checkedKeys}
treeData={treeData}
/>
</Modal>
</div>
)
}
export default AdminPermissions

11
src/pages/container/index.tsx

@ -14,16 +14,11 @@ const noNewTab = ['/login'] // 不需要新建 tab的页面
const noCheckAuth = ['/', '/403'] // 不需要检查权限的页面
// 检查权限
const checkAuth = (newPathname: string): boolean => {
// 不需要检查权限的
// if (noCheckAuth.includes(newPathname)) {
// return true
// }
// const { tabKey: currentKey } = getKeyName(newPathname)
// return isAuthorized(currentKey)
return true;
const { tabKey: currentKey } = getKeyName(newPathname)
return isAuthorized(currentKey)
}
interface Props extends ReduxProps {}
interface Props extends ReduxProps { }
interface PanesItemProps {
title: string;

4
src/pages/login/index.tsx

@ -64,7 +64,7 @@ const LoginForm: FC<Props> = ({
const resData = {
userName: username,
token: res.data.token,
permission: res.data.c || []
permission: res.data.routes || []
}
setUserInfo(resData, setStoreData)
@ -128,7 +128,7 @@ const LoginForm: FC<Props> = ({
const resData = {
userName: nameRef.current,
token: res.data.token,
permission: res.data.c || []
permission: res.data.routes || []
}
setUserInfo(resData, setStoreData)
history.push('/')

4
src/pages/system/withdraw.tsx

@ -113,10 +113,10 @@ const SystemWithdraw = () => {
<Form.Item name="name" label="名称" rules={[{ required: true, message: '请输入名称' }]}>
<Input placeholder="请输入名称" />
</Form.Item>
<Form.Item name="least_amount" label="最小金额" rules={[{ required: true, message: '请输入最小金额' }]}>
<Form.Item name="LeastAmount" label="最小金额" rules={[{ required: true, message: '请输入最小金额' }]}>
<Input placeholder="请输入最小金额" />
</Form.Item>
<Form.Item name="max_amount" label="最大金额" rules={[{ required: true, message: '请输入最大金额' }]}>
<Form.Item name="MaxAmount" label="最大金额" rules={[{ required: true, message: '请输入最大金额' }]}>
<Input placeholder="请输入最大金额" />
</Form.Item>
<Form.Item name="fee" label="手续费" rules={[{ required: true, message: '请输入手续费' }]}>

34
src/pages/vip-manage/proxy-list.tsx

@ -1,7 +1,7 @@
import React, { useEffect, useRef, useState } from "react";
import api from "@/api";
import MyTable from "@/components/MyTable";
import { DeleteFilled, EditOutlined, RightCircleFilled, SolutionOutlined } from "@ant-design/icons";
import { DeleteFilled, EditOutlined, RightCircleFilled, SolutionOutlined, StopTwoTone } from "@ant-design/icons";
import { Button, Form, Input, Modal, Popconfirm, Radio, Select, Switch, notification } from "antd";
import { getBaseUrl, getOriginUrl } from "@/utils/axios";
@ -116,6 +116,16 @@ const ProxyList = () => {
}
};
const cancelFollow = async (item) => {
const res: any = await api.cancel_follow({ id: item.id })
if (res.code === 0) {
tableRef.current.update()
notification.success({
message: '取消成功'
})
}
}
const onFinishAddAccount = async (values) => {
const res: any = await api.add_account({ ...values });
if (res.code === 0) {
@ -159,10 +169,19 @@ const ProxyList = () => {
<RightCircleFilled style={{ margin: '0 10px' }} onClick={() => {
getToken(row);
}} />
<SolutionOutlined onClick={() => {
currentAccount.current = row
setModalFollow(true)
}} />
{
row.account_follow ? (
<Popconfirm onConfirm={() => cancelFollow(row)} title="确认取消跟单吗?">
<StopTwoTone />
</Popconfirm>
) : (
<SolutionOutlined onClick={() => {
currentAccount.current = row
setModalFollow(true)
}} />
)
}
{/* <Popconfirm title={` "${row.name}" `} onConfirm={() => deleteAccount(row)}>
<DeleteFilled />
</Popconfirm> */}
@ -194,6 +213,11 @@ const ProxyList = () => {
return (
<div>
<MyTable
searchConfigList={[{
key: 'search',
name: 'search',
slot: <Input style={{ minWidth: 350 }} placeholder="(邮箱、名字、账号、推荐码等)" />
}]}
apiFun={api.get_userList}
columns={columns}
ref={tableRef}

29
src/route/routes.ts

@ -20,6 +20,8 @@ import EmailLog from "@/pages/system-log/emailLog"
import OperationLog from "@/pages/system-log/operationLog"
import WalletLog from "@/pages/system-log/walletLog"
import GoogleBind from "@/pages/google"
import AdminManage from "@/pages/config-admin/admin-manage"
import AdminPermissions from "@/pages/config-admin/admin-permissions"
const routes = [
{
@ -90,6 +92,30 @@ const routes = [
}
]
},
{
path: '/config-admin',
name: '配置管理员',
exact: true,
key: 'config-admin',
icon: SolutionOutlined,
type: 'subMenu',
routes: [
{
path: '/admin-manage',
name: '管理员设置',
exact: true,
key: 'admin-manage',
component: AdminManage,
},
{
path: '/admin-permissions',
name: '分配权限',
exact: true,
key: 'admin-permissions',
component: AdminPermissions,
},
]
},
{
path: '/vip-manage',
name: '会员管理',
@ -249,7 +275,8 @@ const routes = [
key: 'google-bind',
component: GoogleBind,
icon: SolutionOutlined,
}
},
]

5
src/utils/axios.ts

@ -38,6 +38,8 @@ const clearAll = () => {
type: 'SET_USERINFO',
payload: {}
})
localStorage.setItem('permissions', '')
router.history.replace({ pathname: '/login' })
}
@ -57,6 +59,9 @@ axios.interceptors.request.use(
// 返回后拦截
axios.interceptors.response.use(
({ data }): Promise<any> => {
if (data.code === 101) {
clearAll()
}
if (data.code !== 0) {
message.error(data.message || data.msg)
return Promise.reject(data)

Loading…
Cancel
Save