406 lines
14 KiB
TypeScript
406 lines
14 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import {
|
|
Button, Card, Space, Table, Tag, Typography, message, Modal, Form, Input, Select, InputNumber,
|
|
} from 'antd';
|
|
import {
|
|
MenuOutlined, ReloadOutlined, PlusOutlined, EyeOutlined, EditOutlined, DeleteOutlined,
|
|
} from '@ant-design/icons';
|
|
import { getOauthAppList, createOauthApp, getOauthApp, updateOauthApp, deleteOauthApp } from '../api';
|
|
import { formatDate } from '../utils/formatDate';
|
|
|
|
interface OAuthApp {
|
|
id: string;
|
|
appId: string;
|
|
secret: string;
|
|
status: number;
|
|
count: number;
|
|
openType: number;
|
|
authUrl?: string;
|
|
company?: string;
|
|
createBy: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
const AdminOauthAppList: React.FC = () => {
|
|
const [apps, setApps] = useState<OAuthApp[]>([]);
|
|
const [total, setTotal] = useState(0);
|
|
const [loading, setLoading] = useState(false);
|
|
const [page, setPage] = useState(1);
|
|
const [createModalVisible, setCreateModalVisible] = useState(false);
|
|
const [detailModalVisible, setDetailModalVisible] = useState(false);
|
|
const [updateModalVisible, setUpdateModalVisible] = useState(false);
|
|
const [currentApp, setCurrentApp] = useState<OAuthApp | null>(null);
|
|
const [form] = Form.useForm();
|
|
const [updateForm] = Form.useForm();
|
|
|
|
const load = async (p?: number) => {
|
|
setLoading(true);
|
|
try {
|
|
const res = await getOauthAppList(p || page);
|
|
setApps(res.items || []);
|
|
setTotal(res.total || 0);
|
|
} catch {
|
|
message.error('加载应用管理列表失败');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleCreate = async () => {
|
|
try {
|
|
const values = await form.validateFields();
|
|
await createOauthApp({
|
|
app_id: values.app_id,
|
|
secret: values.secret,
|
|
open_type: values.open_type,
|
|
count: values.count,
|
|
auth_url: values.auth_url,
|
|
company: values.company,
|
|
});
|
|
message.success('创建成功');
|
|
setCreateModalVisible(false);
|
|
form.resetFields();
|
|
load();
|
|
} catch (e: any) {
|
|
message.error(e?.message || '创建失败');
|
|
}
|
|
};
|
|
|
|
const handleDetail = async (id: string) => {
|
|
try {
|
|
const app = await getOauthApp(id);
|
|
setCurrentApp(app);
|
|
setDetailModalVisible(true);
|
|
} catch (e: any) {
|
|
message.error(e?.message || '获取详情失败');
|
|
}
|
|
};
|
|
|
|
const handleUpdate = async (id: string) => {
|
|
try {
|
|
const app = await getOauthApp(id);
|
|
setCurrentApp(app);
|
|
updateForm.setFieldsValue({
|
|
app_id: app.appId,
|
|
secret: app.secret,
|
|
open_type: app.openType,
|
|
count: app.count,
|
|
auth_url: app.authUrl,
|
|
company: app.company,
|
|
});
|
|
setUpdateModalVisible(true);
|
|
} catch (e: any) {
|
|
message.error(e?.message || '获取详情失败');
|
|
}
|
|
};
|
|
|
|
const handleSaveUpdate = async () => {
|
|
if (!currentApp) return;
|
|
try {
|
|
const values = await updateForm.validateFields();
|
|
await updateOauthApp(currentApp.id, {
|
|
app_id: values.app_id,
|
|
secret: values.secret,
|
|
open_type: values.open_type,
|
|
count: values.count,
|
|
auth_url: values.auth_url,
|
|
company: values.company,
|
|
});
|
|
message.success('更新成功');
|
|
setUpdateModalVisible(false);
|
|
updateForm.resetFields();
|
|
load();
|
|
} catch (e: any) {
|
|
message.error(e?.message || '更新失败');
|
|
}
|
|
};
|
|
|
|
const handleDelete = (id: string) => {
|
|
Modal.confirm({
|
|
title: '确认删除',
|
|
content: '确定要删除这个应用管理吗?',
|
|
okText: '删除',
|
|
okType: 'danger',
|
|
cancelText: '取消',
|
|
onOk: async () => {
|
|
try {
|
|
await deleteOauthApp(id);
|
|
message.success('删除成功');
|
|
load();
|
|
} catch (e: any) {
|
|
message.error(e?.message || '删除失败');
|
|
}
|
|
},
|
|
});
|
|
};
|
|
|
|
useEffect(() => { load(); }, []);
|
|
const columns = [
|
|
{ title: 'ID', dataIndex: 'id',
|
|
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
|
},
|
|
{ title: '应用ID', dataIndex: 'appId',
|
|
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
|
},
|
|
{ title: '应用密钥', dataIndex: 'secret',
|
|
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
|
},
|
|
{ title: '开户方式', dataIndex: 'openType',
|
|
render: (v: number) => {
|
|
const typeMap: Record<number, string> = {
|
|
1: '千川', 2: '广告', 3: '本地推', 4: '星图', 5: '快手代理商',
|
|
6: '巨量星图', 7: '巨量服务单', 8: '腾讯服务单', 9: '腾讯营销K2', 10: '腾讯营销K3'
|
|
};
|
|
return <Typography.Text>{typeMap[v] || v}</Typography.Text>;
|
|
},
|
|
},
|
|
{ title: '归属公司', dataIndex: 'company',
|
|
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
|
},
|
|
|
|
{ title: '授权次数', dataIndex: 'count',
|
|
render: (v: number) => <Typography.Text>{v}</Typography.Text>,
|
|
},
|
|
{ title: '状态', dataIndex: 'status',
|
|
render: (v: number) => <Tag color={v === 1 ? 'green' : 'red'}>{v === 1 ? '正常' : '禁用'}</Tag>,
|
|
},
|
|
{ title: '授权URL', dataIndex: 'authUrl',
|
|
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
|
},
|
|
{ title: '创建人', dataIndex: 'createBy',
|
|
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
|
},
|
|
{ title: '创建时间', dataIndex: 'createdAt',
|
|
render: (v: string) => <Typography.Text>{formatDate(v)}</Typography.Text>,
|
|
},
|
|
{ title: '更新时间', dataIndex: 'updatedAt',
|
|
render: (v: string) => <Typography.Text>{formatDate(v)}</Typography.Text>,
|
|
},
|
|
{ title: '操作',
|
|
render: (_: any, record: OAuthApp) => (
|
|
<Space>
|
|
<Button
|
|
icon={<EyeOutlined />}
|
|
size="small"
|
|
onClick={() => handleDetail(record.id)}
|
|
>详情</Button>
|
|
<Button
|
|
icon={<EditOutlined />}
|
|
size="small"
|
|
onClick={() => handleUpdate(record.id)}
|
|
>更新</Button>
|
|
<Button
|
|
icon={<DeleteOutlined />}
|
|
size="small"
|
|
danger
|
|
onClick={() => handleDelete(record.id)}
|
|
>删除</Button>
|
|
</Space>
|
|
),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div>
|
|
<Card variant="outlined" style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
|
|
<Space>
|
|
<MenuOutlined style={{ fontSize: 18, color: '#6366f1' }} />
|
|
<Typography.Text strong style={{ fontSize: 16 }}>应用管理列表</Typography.Text>
|
|
</Space>
|
|
<Space>
|
|
<Button icon={<ReloadOutlined />} onClick={() => load()}>刷新</Button>
|
|
<Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateModalVisible(true)}>创建</Button>
|
|
</Space>
|
|
</div>
|
|
<Table
|
|
columns={columns}
|
|
dataSource={apps}
|
|
rowKey="id"
|
|
loading={loading}
|
|
pagination={{
|
|
current: page,
|
|
pageSize: 20,
|
|
total,
|
|
showTotal: (t) => `共 ${t} 条记录`,
|
|
onChange: (p) => { setPage(p); load(p); },
|
|
}}
|
|
scroll={{ x: 800 }}
|
|
/>
|
|
</Card>
|
|
|
|
<Modal
|
|
title="创建应用管理"
|
|
open={createModalVisible}
|
|
onOk={handleCreate}
|
|
onCancel={() => {
|
|
setCreateModalVisible(false);
|
|
form.resetFields();
|
|
}}
|
|
okText="创建"
|
|
cancelText="取消"
|
|
width={600}
|
|
>
|
|
<Form form={form} layout="vertical">
|
|
<Form.Item
|
|
name="app_id"
|
|
label="应用ID"
|
|
rules={[{ required: true, message: '请输入应用ID' }, { max: 64, message: '应用ID不能超过64个字符' }]}
|
|
>
|
|
<Input placeholder="请输入应用ID" />
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="secret"
|
|
label="应用密钥"
|
|
rules={[{ required: true, message: '请输入应用密钥' }, { max: 256, message: '应用密钥不能超过256个字符' }]}
|
|
>
|
|
<Input placeholder="请输入应用密钥" />
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="open_type"
|
|
label="开户方式"
|
|
rules={[{ required: true, message: '请选择开户方式' }]}
|
|
>
|
|
<Select placeholder="请选择开户方式">
|
|
<Select.Option value={1}>千川</Select.Option>
|
|
<Select.Option value={2}>广告</Select.Option>
|
|
<Select.Option value={3}>本地推</Select.Option>
|
|
<Select.Option value={4}>星图</Select.Option>
|
|
<Select.Option value={5}>快手代理商</Select.Option>
|
|
<Select.Option value={6}>巨量星图</Select.Option>
|
|
<Select.Option value={7}>巨量服务单</Select.Option>
|
|
<Select.Option value={8}>腾讯服务单</Select.Option>
|
|
<Select.Option value={9}>腾讯营销K2</Select.Option>
|
|
<Select.Option value={10}>腾讯营销K3</Select.Option>
|
|
</Select>
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="count"
|
|
label="最大授权用户数"
|
|
initialValue={100}
|
|
>
|
|
<InputNumber min={1} placeholder="应用最大可以授权多少个用户" />
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="auth_url"
|
|
label="应用授权链接"
|
|
>
|
|
<Input placeholder="请输入应用授权链接" />
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="company"
|
|
label="应用归属公司名称"
|
|
rules={[{ max: 256, message: '公司名称不能超过256个字符' }]}
|
|
>
|
|
<Input placeholder="请输入应用归属公司名称" />
|
|
</Form.Item>
|
|
</Form>
|
|
</Modal>
|
|
|
|
<Modal
|
|
title="应用管理详情"
|
|
open={detailModalVisible}
|
|
onCancel={() => {
|
|
setDetailModalVisible(false);
|
|
setCurrentApp(null);
|
|
}}
|
|
okText="关闭"
|
|
cancelText="取消"
|
|
width={600}
|
|
>
|
|
{currentApp && (
|
|
<div style={{ lineHeight: '2' }}>
|
|
<p><strong>ID:</strong> {currentApp.id}</p>
|
|
<p><strong>应用ID:</strong> {currentApp.appId}</p>
|
|
<p><strong>应用密钥:</strong> {currentApp.secret}</p>
|
|
<p><strong>开户方式:</strong> {(() => {
|
|
const typeMap: Record<number, string> = {
|
|
1: '千川', 2: '广告', 3: '本地推', 4: '星图', 5: '快手代理商',
|
|
6: '巨量星图', 7: '巨量服务单', 8: '腾讯服务单', 9: '腾讯营销K2', 10: '腾讯营销K3'
|
|
};
|
|
return typeMap[currentApp.openType] || currentApp.openType;
|
|
})()}</p>
|
|
<p><strong>归属公司:</strong> {currentApp.company || '-'}</p>
|
|
<p><strong>授权次数:</strong> {currentApp.count}</p>
|
|
<p><strong>状态:</strong> {currentApp.status === 1 ? '正常' : '禁用'}</p>
|
|
<p><strong>授权URL:</strong> {currentApp.authUrl || '-'}</p>
|
|
<p><strong>创建人:</strong> {currentApp.createBy}</p>
|
|
<p><strong>创建时间:</strong> {formatDate(currentApp.createdAt)}</p>
|
|
<p><strong>更新时间:</strong> {formatDate(currentApp.updatedAt)}</p>
|
|
</div>
|
|
)}
|
|
</Modal>
|
|
|
|
<Modal
|
|
title="更新应用管理"
|
|
open={updateModalVisible}
|
|
onOk={handleSaveUpdate}
|
|
onCancel={() => {
|
|
setUpdateModalVisible(false);
|
|
updateForm.resetFields();
|
|
setCurrentApp(null);
|
|
}}
|
|
okText="更新"
|
|
cancelText="取消"
|
|
width={600}
|
|
>
|
|
<Form form={updateForm} layout="vertical">
|
|
<Form.Item
|
|
name="app_id"
|
|
label="应用ID"
|
|
rules={[{ required: true, message: '请输入应用ID' }, { max: 64, message: '应用ID不能超过64个字符' }]}
|
|
>
|
|
<Input placeholder="请输入应用ID" />
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="secret"
|
|
label="应用密钥"
|
|
rules={[{ required: true, message: '请输入应用密钥' }, { max: 256, message: '应用密钥不能超过256个字符' }]}
|
|
>
|
|
<Input placeholder="请输入应用密钥" />
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="open_type"
|
|
label="开户方式"
|
|
rules={[{ required: true, message: '请选择开户方式' }]}
|
|
>
|
|
<Select placeholder="请选择开户方式">
|
|
<Select.Option value={1}>千川</Select.Option>
|
|
<Select.Option value={2}>广告</Select.Option>
|
|
<Select.Option value={3}>本地推</Select.Option>
|
|
<Select.Option value={4}>星图</Select.Option>
|
|
<Select.Option value={5}>快手代理商</Select.Option>
|
|
<Select.Option value={6}>巨量星图</Select.Option>
|
|
<Select.Option value={7}>巨量服务单</Select.Option>
|
|
<Select.Option value={8}>腾讯服务单</Select.Option>
|
|
<Select.Option value={9}>腾讯营销K2</Select.Option>
|
|
<Select.Option value={10}>腾讯营销K3</Select.Option>
|
|
</Select>
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="count"
|
|
label="最大授权用户数"
|
|
>
|
|
<InputNumber min={1} placeholder="应用最大可以授权多少个用户" />
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="auth_url"
|
|
label="应用授权链接"
|
|
>
|
|
<Input placeholder="请输入应用授权链接" />
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="company"
|
|
label="应用归属公司名称"
|
|
rules={[{ max: 256, message: '公司名称不能超过256个字符' }]}
|
|
>
|
|
<Input placeholder="请输入应用归属公司名称" />
|
|
</Form.Item>
|
|
</Form>
|
|
</Modal>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default AdminOauthAppList; |