diff --git a/config/proxy.ts b/config/proxy.ts
index a887ff36..4d04c15f 100644
--- a/config/proxy.ts
+++ b/config/proxy.ts
@@ -1,4 +1,4 @@
-const proxyTableList = ['cli', 'v1'];
+const proxyTableList = ['cli', 'v1', 'auth'];
// @ts-ingore
export default function createProxyTable(target?: string) {
diff --git a/config/routes.ts b/config/routes.ts
index d816a057..6417ac85 100644
--- a/config/routes.ts
+++ b/config/routes.ts
@@ -4,7 +4,8 @@ export default [
key: 'dashboard',
layout: false,
icon: 'home',
- redirect: '/dashboard'
+ redirect: '/dashboard',
+ access: 'canLogin'
},
{
name: 'Dashboard',
diff --git a/package.json b/package.json
index 2aa51e84..a0fda671 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"dayjs": "^1.11.11",
"lodash": "^4.17.21",
"numeral": "^2.0.6",
+ "query-string": "^9.0.0",
"umi-presets-pro": "^2.0.3"
},
"devDependencies": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 906959c9..aaeeb11d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -50,6 +50,9 @@ dependencies:
numeral:
specifier: ^2.0.6
version: 2.0.6
+ query-string:
+ specifier: ^9.0.0
+ version: 9.0.0
umi-presets-pro:
specifier: ^2.0.3
version: 2.0.3(@babel/core@7.24.5)(@types/react-dom@18.3.0)(@types/react@18.3.1)(antd@5.17.0)(dva@2.5.0-beta.2)(rc-field-form@1.44.0)(react-dom@18.3.1)(react@18.3.1)(umi@4.2.1)
@@ -4246,7 +4249,7 @@ packages:
dependencies:
'@babel/core': 7.24.5
postcss: 7.0.39
- postcss-syntax: 0.36.2(postcss@7.0.39)
+ postcss-syntax: 0.36.2(postcss@8.4.38)
transitivePeerDependencies:
- supports-color
dev: false
@@ -4273,7 +4276,7 @@ packages:
postcss-syntax: '>=0.36.2'
dependencies:
postcss: 7.0.39
- postcss-syntax: 0.36.2(postcss@7.0.39)
+ postcss-syntax: 0.36.2(postcss@8.4.38)
remark: 13.0.0
unist-util-find-all-after: 3.0.2
transitivePeerDependencies:
@@ -7852,10 +7855,15 @@ packages:
dev: false
/decode-uri-component@0.2.2:
- resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
+ resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==, tarball: https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz}
engines: {node: '>=0.10'}
dev: false
+ /decode-uri-component@0.4.1:
+ resolution: {integrity: sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==, tarball: https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.4.1.tgz}
+ engines: {node: '>=14.16'}
+ dev: false
+
/deep-equal@1.1.2:
resolution: {integrity: sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==}
engines: {node: '>= 0.4'}
@@ -9361,10 +9369,15 @@ packages:
to-regex-range: 5.0.1
/filter-obj@1.1.0:
- resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==}
+ resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==, tarball: https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz}
engines: {node: '>=0.10.0'}
dev: false
+ /filter-obj@5.1.0:
+ resolution: {integrity: sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==, tarball: https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz}
+ engines: {node: '>=14.16'}
+ dev: false
+
/finalhandler@1.2.0:
resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
engines: {node: '>= 0.8'}
@@ -12380,7 +12393,7 @@ packages:
dependencies:
htmlparser2: 3.10.1
postcss: 7.0.39
- postcss-syntax: 0.36.2(postcss@7.0.39)
+ postcss-syntax: 0.36.2(postcss@8.4.38)
dev: false
/postcss-image-set-function@4.0.7(postcss@8.4.38):
@@ -12670,30 +12683,6 @@ packages:
lodash: 4.17.21
postcss: 8.4.38
- /postcss-syntax@0.36.2(postcss@7.0.39):
- resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
- peerDependencies:
- postcss: '>=5.0.0'
- postcss-html: '*'
- postcss-jsx: '*'
- postcss-less: '*'
- postcss-markdown: '*'
- postcss-scss: '*'
- peerDependenciesMeta:
- postcss-html:
- optional: true
- postcss-jsx:
- optional: true
- postcss-less:
- optional: true
- postcss-markdown:
- optional: true
- postcss-scss:
- optional: true
- dependencies:
- postcss: 7.0.39
- dev: false
-
/postcss-syntax@0.36.2(postcss@8.4.38):
resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
peerDependencies:
@@ -12955,7 +12944,7 @@ packages:
dev: false
/query-string@6.14.1:
- resolution: {integrity: sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==}
+ resolution: {integrity: sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==, tarball: https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz}
engines: {node: '>=6'}
dependencies:
decode-uri-component: 0.2.2
@@ -12964,6 +12953,15 @@ packages:
strict-uri-encode: 2.0.0
dev: false
+ /query-string@9.0.0:
+ resolution: {integrity: sha512-4EWwcRGsO2H+yzq6ddHcVqkCQ2EFUSfDMEjF8ryp8ReymyZhIuaFRGLomeOQLkrzacMHoyky2HW0Qe30UbzkKw==, tarball: https://registry.npmjs.org/query-string/-/query-string-9.0.0.tgz}
+ engines: {node: '>=18'}
+ dependencies:
+ decode-uri-component: 0.4.1
+ filter-obj: 5.1.0
+ split-on-first: 3.0.0
+ dev: false
+
/querystring-es3@0.2.1:
resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==}
engines: {node: '>=0.4.x'}
@@ -15408,10 +15406,15 @@ packages:
dev: false
/split-on-first@1.1.0:
- resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==}
+ resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==, tarball: https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz}
engines: {node: '>=6'}
dev: false
+ /split-on-first@3.0.0:
+ resolution: {integrity: sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==, tarball: https://registry.npmjs.org/split-on-first/-/split-on-first-3.0.0.tgz}
+ engines: {node: '>=12'}
+ dev: false
+
/split2@4.2.0:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
@@ -15756,7 +15759,7 @@ packages:
postcss-sass: 0.4.4
postcss-scss: 2.1.1
postcss-selector-parser: 6.0.16
- postcss-syntax: 0.36.2(postcss@7.0.39)
+ postcss-syntax: 0.36.2(postcss@8.4.38)
postcss-value-parser: 4.2.0
resolve-from: 5.0.0
slash: 3.0.0
diff --git a/src/access.ts b/src/access.ts
index f81d09e1..340d990a 100644
--- a/src/access.ts
+++ b/src/access.ts
@@ -6,6 +6,7 @@ export default (initialState: API.UserInfo) => {
);
return {
canSeeAdmin,
- canDelete: true
+ canDelete: true,
+ canLogin: true
};
};
diff --git a/src/app.tsx b/src/app.tsx
index 0666fbed..7ebe2662 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -23,17 +23,15 @@ export async function getInitialState() {
return undefined;
};
- // if (![loginPath].includes(location.pathname)) {
- // const currentUser = await fetchUserInfo();
- // return {
- // fetchUserInfo,
- // name: 'admin',
- // ...currentUser
- // };
- // }
+ if (![loginPath].includes(location.pathname)) {
+ const userInfo = await fetchUserInfo();
+ return {
+ fetchUserInfo,
+ currentUser: userInfo
+ };
+ }
return {
- fetchUserInfo,
- name: 'admin'
+ fetchUserInfo
};
}
diff --git a/src/assets/styles/common.less b/src/assets/styles/common.less
index a176d749..daf1724f 100644
--- a/src/assets/styles/common.less
+++ b/src/assets/styles/common.less
@@ -6,6 +6,10 @@
margin-left: 10px;
}
+.m-l-5 {
+ margin-left: 5px;
+}
+
.flex {
display: flex;
}
diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx
index bf232618..a9f0a524 100644
--- a/src/layouts/index.tsx
+++ b/src/layouts/index.tsx
@@ -1,5 +1,6 @@
// @ts-nocheck
+import { logout } from '@/pages/login/apis';
import { useAccessMarkedRoutes } from '@@/plugin-access';
import { useModel } from '@@/plugin-model';
import { ProLayout } from '@ant-design/pro-components';
@@ -106,18 +107,19 @@ export default (props: any) => {
// });
const runtimeConfig = {
...initialInfo,
- logout: () => {
- console.log('logout');
+ logout: async (userInfo) => {
+ console.log('logout', userInfo);
+ await logout();
+ navigate(loginPath);
},
- notFound:
not found
+ notFound: 404 not found
};
- console.log(
- 'clientRoute==========2=',
+ console.log('clientRoute==========2=', {
props,
clientRoutes,
runtimeConfig,
initialInfo
- );
+ });
// 现在的 layout 及 wrapper 实现是通过父路由的形式实现的, 会导致路由数据多了冗余层级, proLayout 消费时, 无法正确展示菜单, 这里对冗余数据进行过滤操作
const newRoutes = filterRoutes(
@@ -153,12 +155,12 @@ export default (props: any) => {
navigate('/');
}}
onPageChange={(route) => {
- console.log('onRouteChange', route);
+ console.log('onRouteChange', initialState, route);
const { location } = history;
// 如果没有登录,重定向到 login
- // if (!initialState?.currentUser && location.pathname !== loginPath) {
- // history.push(loginPath);
- // }
+ if (!initialState?.currentUser && location.pathname !== loginPath) {
+ history.push(loginPath);
+ }
}}
formatMessage={userConfig.formatMessage || formatMessage}
menu={{ locale: userConfig.locale }}
diff --git a/src/layouts/rightRender.tsx b/src/layouts/rightRender.tsx
index 036d52c5..434c98c3 100644
--- a/src/layouts/rightRender.tsx
+++ b/src/layouts/rightRender.tsx
@@ -4,10 +4,9 @@ import avatarImg from '@/assets/images/avatar.png';
import {
GlobalOutlined,
LogoutOutlined,
- SettingOutlined,
- SunOutlined
+ SettingOutlined
} from '@ant-design/icons';
-import { useNavigate } from '@umijs/max';
+import { history } from '@umijs/max';
import { Avatar, Dropdown, Menu, Spin, version } from 'antd';
export function getRightRenderContent(opts: {
@@ -26,10 +25,10 @@ export function getRightRenderContent(opts: {
}
const showAvatar =
- opts.initialState?.avatar ||
- opts.initialState?.name ||
+ opts.initialState?.currentUser?.avatar ||
+ opts.initialState?.currentUser?.username ||
opts.runtimeConfig.logout;
- const disableAvatarImg = opts.initialState?.avatar === false;
+ const disableAvatarImg = opts.initialState?.currentUser?.avatar === false;
const nameClassName = disableAvatarImg
? 'umi-plugin-layout-name umi-plugin-layout-hide-avatar-img'
: 'umi-plugin-layout-name';
@@ -39,11 +38,13 @@ export function getRightRenderContent(opts: {
) : null}
- {opts.initialState?.name}
+
+ {opts.initialState?.currentUser?.username}
+
) : null;
@@ -58,8 +59,6 @@ export function getRightRenderContent(opts: {
// 如果没有打开Locale,并且头像为空就取消掉这个返回的内容
if (!avatar) return null;
- const navigate = useNavigate();
-
const langMenu = {
className: 'umi-plugin-layout-menu',
selectedKeys: [],
@@ -73,21 +72,21 @@ export function getRightRenderContent(opts: {
>
),
onClick: () => {
- navigate('/profile');
- }
- },
- {
- key: 'theme',
- label: (
- <>
-
- 外观
- >
- ),
- onClick: () => {
- console.log('theme');
+ history.push('/profile');
}
},
+ // {
+ // key: 'theme',
+ // label: (
+ // <>
+ //
+ // 外观
+ // >
+ // ),
+ // onClick: () => {
+ // console.log('theme');
+ // }
+ // },
{
key: 'lang',
label: (
@@ -109,14 +108,13 @@ export function getRightRenderContent(opts: {
>
),
onClick: () => {
- opts?.runtimeConfig?.logout?.(opts.initialState);
+ opts?.runtimeConfig?.logout?.(opts.initialState.currentUser);
}
}
]
};
// antd@5 和 4.24 之后推荐使用 menu,性能更好
- console.log('version+++++++++=', opts.runtimeConfig, version);
let dropdownProps;
if (version.startsWith('5.') || version.startsWith('4.24.')) {
dropdownProps = { menu: langMenu };
diff --git a/src/models/global.ts b/src/models/global.ts
index 708ccff9..fd0bc4a2 100644
--- a/src/models/global.ts
+++ b/src/models/global.ts
@@ -1,13 +1,13 @@
// 全局共享数据示例
-import { DEFAULT_NAME } from '@/constants';
+// import { DEFAULT_NAME } from '@/constants';
import { useState } from 'react';
-const useUser = () => {
- const [name, setName] = useState(DEFAULT_NAME);
+const useGlobalState = () => {
+ const [globalState, setGlobalState] = useState({});
return {
- name,
- setName,
+ globalState,
+ setGlobalState
};
};
-export default useUser;
+export default useGlobalState;
diff --git a/src/pages/api-keys/apis/index.ts b/src/pages/api-keys/apis/index.ts
new file mode 100644
index 00000000..13d053ab
--- /dev/null
+++ b/src/pages/api-keys/apis/index.ts
@@ -0,0 +1,26 @@
+import { request } from '@umijs/max';
+import { FormData, ListItem } from '../config/types';
+
+export const APIS_KEYS_API = '/api_keys';
+
+export async function queryApisKeysList(
+ params: Global.Pagination & { query?: string }
+) {
+ return request>(`${APIS_KEYS_API}`, {
+ method: 'GET',
+ params
+ });
+}
+
+export async function createApisKey(params: { data: FormData }) {
+ return request(`${APIS_KEYS_API}`, {
+ method: 'POST',
+ data: params.data
+ });
+}
+
+export async function deleteApisKey(id: number) {
+ return request(`${APIS_KEYS_API}/${id}`, {
+ method: 'DELETE'
+ });
+}
diff --git a/src/pages/api-keys/components/add-apikey.tsx b/src/pages/api-keys/components/add-apikey.tsx
index b7ccdbce..7e025149 100644
--- a/src/pages/api-keys/components/add-apikey.tsx
+++ b/src/pages/api-keys/components/add-apikey.tsx
@@ -1,24 +1,20 @@
-import CopyButton from '@/components/copy-button';
import ModalFooter from '@/components/modal-footer';
import SealInput from '@/components/seal-form/seal-input';
import SealSelect from '@/components/seal-form/seal-select';
import { PageActionType } from '@/config/types';
import { SyncOutlined } from '@ant-design/icons';
import { Form, Modal } from 'antd';
+import { expirationOptions } from '../config';
+import { FormData } from '../config/types';
type AddModalProps = {
title: string;
action: PageActionType;
open: boolean;
- onOk: () => void;
+ onOk: (values: FormData) => void;
onCancel: () => void;
};
-const expirationOptions = [
- { label: '1 Month', value: '1m' },
- { label: '6 Months', value: '6m' },
- { label: 'Never', value: 'never' }
-];
const AddModal: React.FC = ({
title,
action,
@@ -36,11 +32,15 @@ const AddModal: React.FC = ({
/>
);
+ const handleSumit = () => {
+ form.submit();
+ };
+
return (
= ({
keyboard={false}
width={600}
styles={{}}
- footer={}
+ footer={
+
+ }
>
-
-
-
-
-
- }
- >
+ name="name" rules={[{ required: true }]}>
+
-
+ name="expires_in" rules={[{ required: true }]}>
+ name="description" rules={[{ required: false }]}>
+
+
);
diff --git a/src/pages/api-keys/config/index.ts b/src/pages/api-keys/config/index.ts
new file mode 100644
index 00000000..4a0a27f0
--- /dev/null
+++ b/src/pages/api-keys/config/index.ts
@@ -0,0 +1,7 @@
+export const expirationOptions = [
+ { label: '7 days', type: 'day', value: 7 },
+ { label: '1 month', type: 'month', value: 1 },
+ { label: '6 months', type: 'month', value: 6 },
+ // { label: '1 year', type: 'year', value: 1 },
+ { label: 'never', type: 'never', value: -1 }
+];
diff --git a/src/pages/api-keys/config/types.ts b/src/pages/api-keys/config/types.ts
new file mode 100644
index 00000000..e3bf24bb
--- /dev/null
+++ b/src/pages/api-keys/config/types.ts
@@ -0,0 +1,15 @@
+export interface ListItem {
+ name: string;
+ description: string;
+ id: number;
+ value: string;
+ created_at: string;
+ updated_at: string;
+ expires_at: string;
+}
+
+export interface FormData {
+ name: string;
+ description: string;
+ expires_in: number | null;
+}
diff --git a/src/pages/api-keys/index.tsx b/src/pages/api-keys/index.tsx
index 4be61616..e0850e6f 100644
--- a/src/pages/api-keys/index.tsx
+++ b/src/pages/api-keys/index.tsx
@@ -1,21 +1,33 @@
+import CopyButton from '@/components/copy-button';
import PageTools from '@/components/page-tools';
import { PageAction } from '@/config';
import type { PageActionType } from '@/config/types';
import useTableRowSelection from '@/hooks/use-table-row-selection';
import useTableSort from '@/hooks/use-table-sort';
-import {
- DeleteOutlined,
- EditOutlined,
- PlusOutlined,
- SyncOutlined
-} from '@ant-design/icons';
+import { handleBatchRequest } from '@/utils';
+import { DeleteOutlined, PlusOutlined, SyncOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
-import { Button, Input, Modal, Space, Table, Tooltip, message } from 'antd';
-import { useState } from 'react';
+import {
+ Button,
+ Input,
+ Modal,
+ Space,
+ Table,
+ Tag,
+ Tooltip,
+ message
+} from 'antd';
+import dayjs from 'dayjs';
+import _ from 'lodash';
+import { useEffect, useState } from 'react';
+import { createApisKey, deleteApisKey, queryApisKeysList } from './apis';
import AddAPIKeyModal from './components/add-apikey';
+import { expirationOptions } from './config';
+import { FormData, ListItem } from './config/types';
+
const { Column } = Table;
-const dataSource = [
+const list = [
{
key: '1',
name: 'local',
@@ -51,22 +63,32 @@ const Models: React.FC = () => {
const { sortOrder, setSortOrder } = useTableSort({
defaultSortOrder: 'descend'
});
+ const [dataSource, setDataSource] = useState([]);
const [total, setTotal] = useState(0);
const [openAddModal, setOpenAddModal] = useState(false);
const [loading, setLoading] = useState(false);
const [action, setAction] = useState(PageAction.CREATE);
const [title, setTitle] = useState('');
const [queryParams, setQueryParams] = useState({
- current: 1,
- pageSize: 10,
- name: ''
+ page: 1,
+ perPage: 10,
+ query: ''
});
- const handleShowSizeChange = (current: number, size: number) => {
- console.log(current, size);
+
+ const handleShowSizeChange = (page: number, size: number) => {
+ console.log(page, size);
+ setQueryParams({
+ ...queryParams,
+ perPage: size
+ });
};
const handlePageChange = (page: number, pageSize: number | undefined) => {
console.log(page, pageSize);
+ setQueryParams({
+ ...queryParams,
+ page: page
+ });
};
const handleTableChange = (pagination: any, filters: any, sorter: any) => {
@@ -74,8 +96,40 @@ const Models: React.FC = () => {
setSortOrder(sorter.order);
};
+ const getExpireValue = (val: number | null) => {
+ const expires_in = val;
+ if (expires_in === -1) {
+ return 0;
+ }
+ const selected = expirationOptions.find(
+ (item) => expires_in === item.value
+ );
+
+ const d1 = dayjs().add(
+ selected?.value as number,
+ `${selected?.type}` as never
+ );
+ const d2 = dayjs();
+ const res = d1.diff(d2, 'second');
+ return res;
+ };
+
const fetchData = async () => {
- console.log('fetchData');
+ setLoading(true);
+ try {
+ const params = {
+ ..._.pickBy(queryParams, (val: any) => !!val)
+ };
+ const res = await queryApisKeysList(params);
+ console.log('res=======', res);
+ setDataSource(res.items || []);
+ setTotal(res.pagination.total);
+ } catch (error) {
+ console.log('error', error);
+ setDataSource([]);
+ } finally {
+ setLoading(false);
+ }
};
const handleSearch = (e: any) => {
fetchData();
@@ -84,7 +138,7 @@ const Models: React.FC = () => {
const handleNameChange = (e: any) => {
setQueryParams({
...queryParams,
- name: e.target.value
+ query: e.target.value
});
};
@@ -94,13 +148,22 @@ const Models: React.FC = () => {
setTitle('Add API Key');
};
- const handleClickMenu = (e: any) => {
- console.log('click', e);
- };
-
- const handleModalOk = () => {
+ const handleModalOk = async (data: FormData) => {
console.log('handleModalOk');
- setOpenAddModal(false);
+
+ try {
+ const params = {
+ ...data,
+ expires_in: getExpireValue(data.expires_in)
+ };
+ const res = await createApisKey({ data: params });
+ setOpenAddModal(false);
+ message.success('successfully!');
+ setDataSource([res, ...dataSource]);
+ setTotal(total + 1);
+ } catch (error) {
+ setOpenAddModal(false);
+ }
};
const handleModalCancel = () => {
@@ -108,13 +171,30 @@ const Models: React.FC = () => {
setOpenAddModal(false);
};
- const handleDelete = () => {
+ const handleDelete = (row: ListItem) => {
Modal.confirm({
title: '',
content: 'Are you sure you want to delete the selected keys?',
- onOk() {
+ async onOk() {
console.log('OK');
+ await deleteApisKey(row.id);
+ message.success('successfully!');
+ fetchData();
+ },
+ onCancel() {
+ console.log('Cancel');
+ }
+ });
+ };
+
+ const handleDeleteBatch = () => {
+ Modal.confirm({
+ title: '',
+ content: 'Are you sure you want to delete the selected keys?',
+ async onOk() {
+ await handleBatchRequest(rowSelection.selectedRowKeys, deleteApisKey);
message.success('successfully!');
+ fetchData();
},
onCancel() {
console.log('Cancel');
@@ -127,6 +207,34 @@ const Models: React.FC = () => {
setAction(PageAction.EDIT);
setTitle('Edit User');
};
+
+ const renderSecrectKey = (text: string, record: ListItem) => {
+ const { value } = record;
+
+ return (
+
+ {text}
+ {value && (
+
+
+ 确保立即复制您的个人访问密钥。您将无法再次看到它!
+
+
+ {`${value?.slice(0, 8)}...${value?.slice(-8, -1)}`}
+
+
+
+ )}
+
+ );
+ };
+
+ useEffect(() => {
+ fetchData();
+ }, [queryParams]);
+
return (
<>
{
}
danger
- onClick={handleDelete}
+ onClick={handleDeleteBatch}
disabled={!rowSelection.selectedRowKeys.length}
>
Delete
@@ -177,49 +285,58 @@ const Models: React.FC = () => {
dataSource={dataSource}
rowSelection={rowSelection}
loading={loading}
+ rowKey="id"
onChange={handleTableChange}
pagination={{
showSizeChanger: true,
- pageSize: 10,
- current: 2,
+ pageSize: queryParams.perPage,
+ current: queryParams.page,
total: total,
hideOnSinglePage: true,
onShowSizeChange: handleShowSizeChange,
onChange: handlePageChange
}}
>
-
-
+
+
{
+ return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+ }}
/>
{
+ return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+ }}
/>
{
+ render={(text, record: ListItem) => {
return (
-
-
-
@@ -274,6 +310,7 @@ const Models: React.FC = () => {
open={openAddModal}
action={action}
title={title}
+ data={currentData}
onCancel={handleModalCancel}
onOk={handleModalOk}
>
diff --git a/src/request-config.ts b/src/request-config.ts
index c5556f0c..75b395d8 100644
--- a/src/request-config.ts
+++ b/src/request-config.ts
@@ -1,6 +1,8 @@
import { RequestConfig } from '@umijs/max';
import { message } from 'antd';
+const NoBaseURLAPIs = ['/auth'];
+
export const requestConfig: RequestConfig = {
errorConfig: {
errorThrower: (res: any) => {
@@ -17,6 +19,10 @@ export const requestConfig: RequestConfig = {
requestInterceptors: [
(url, options) => {
console.log('requestInterceptors+++++++++++++++', url, options);
+ if (NoBaseURLAPIs.some((api) => url.startsWith(api))) {
+ options.baseURL = '';
+ return { url, options };
+ }
return { url, options };
}
],
diff --git a/src/utils/index.ts b/src/utils/index.ts
index bf82ed5c..e805792e 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -2,7 +2,13 @@ export const isNotEmptyValue = (value: any) => {
if (Array.isArray(value)) {
return value.length > 0;
}
- return value !== null && value !== undefined && value !== '';
+ return (
+ value !== null &&
+ value !== undefined &&
+ value !== '' &&
+ value !== false &&
+ value !== 0
+ );
};
export const handleBatchRequest = async (