Merge pull request #17 from songquanpeng/main

Fork Sync: Update from parent repository
This commit is contained in:
quzard 2023-06-10 20:51:08 +08:00 committed by GitHub
commit fdc21efd48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 12 deletions

View File

@ -68,16 +68,17 @@ _✨ All in one 的 OpenAI 接口,整合各种 API 访问方式,开箱即用
7. 支持**通道管理**,批量创建通道。 7. 支持**通道管理**,批量创建通道。
8. 支持**用户分组**以及**渠道分组**。 8. 支持**用户分组**以及**渠道分组**。
9. 支持渠道**设置模型列表**。 9. 支持渠道**设置模型列表**。
10. 支持发布公告,设置充值链接,设置新用户初始额度。 10. 支持**查看额度明细**。
11. 支持丰富的**自定义**设置, 11. 支持发布公告,设置充值链接,设置新用户初始额度。
12. 支持丰富的**自定义**设置,
1. 支持自定义系统名称logo 以及页脚。 1. 支持自定义系统名称logo 以及页脚。
2. 支持自定义首页和关于页面,可以选择使用 HTML & Markdown 代码进行自定义,或者使用一个单独的网页通过 iframe 嵌入。 2. 支持自定义首页和关于页面,可以选择使用 HTML & Markdown 代码进行自定义,或者使用一个单独的网页通过 iframe 嵌入。
12. 支持通过系统访问令牌访问管理 API。 13. 支持通过系统访问令牌访问管理 API。
13. 支持用户管理,支持**多种用户登录注册方式** 14. 支持用户管理,支持**多种用户登录注册方式**
+ 邮箱登录注册以及通过邮箱进行密码重置。 + 邮箱登录注册以及通过邮箱进行密码重置。
+ [GitHub 开放授权](https://github.com/settings/applications/new)。 + [GitHub 开放授权](https://github.com/settings/applications/new)。
+ 微信公众号授权(需要额外部署 [WeChat Server](https://github.com/songquanpeng/wechat-server))。 + 微信公众号授权(需要额外部署 [WeChat Server](https://github.com/songquanpeng/wechat-server))。
14. 未来其他大模型开放 API 后,将第一时间支持,并将其封装成同样的 API 访问方式。 15. 未来其他大模型开放 API 后,将第一时间支持,并将其封装成同样的 API 访问方式。
## 部署 ## 部署
### 基于 Docker 进行部署 ### 基于 Docker 进行部署

View File

@ -35,7 +35,13 @@ func RecordLog(userId int, logType int, content string) {
} }
func GetAllLogs(logType int, startIdx int, num int) (logs []*Log, err error) { func GetAllLogs(logType int, startIdx int, num int) (logs []*Log, err error) {
err = DB.Where("type = ?", logType).Order("id desc").Limit(num).Offset(startIdx).Find(&logs).Error var tx *gorm.DB
if logType == LogTypeUnknown {
tx = DB
} else {
tx = DB.Where("type = ?", logType)
}
err = tx.Order("id desc").Limit(num).Offset(startIdx).Find(&logs).Error
return logs, err return logs, err
} }

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Button, Label, Pagination, Table } from 'semantic-ui-react'; import { Button, Label, Pagination, Select, Table } from 'semantic-ui-react';
import { API, showError, timestamp2string } from '../helpers'; import { API, isAdmin, showError, timestamp2string } from '../helpers';
import { ITEMS_PER_PAGE } from '../constants'; import { ITEMS_PER_PAGE } from '../constants';
@ -12,6 +12,19 @@ function renderTimestamp(timestamp) {
); );
} }
const MODE_OPTIONS = [
{ key: 'all', text: '全部用户', value: 'all' },
{ key: 'self', text: '当前用户', value: 'self' },
];
const LOG_OPTIONS = [
{ key: '0', text: '全部', value: 0 },
{ key: '1', text: '充值', value: 1 },
{ key: '2', text: '消费', value: 2 },
{ key: '3', text: '管理', value: 3 },
{ key: '4', text: '系统', value: 4 }
];
function renderType(type) { function renderType(type) {
switch (type) { switch (type) {
case 1: case 1:
@ -21,7 +34,7 @@ function renderType(type) {
case 3: case 3:
return <Label basic color='orange'> 管理 </Label>; return <Label basic color='orange'> 管理 </Label>;
case 4: case 4:
return <Label basic color='red'> 系统 </Label>; return <Label basic color='purple'> 系统 </Label>;
default: default:
return <Label basic color='black'> 未知 </Label>; return <Label basic color='black'> 未知 </Label>;
} }
@ -33,9 +46,16 @@ const LogsTable = () => {
const [activePage, setActivePage] = useState(1); const [activePage, setActivePage] = useState(1);
const [searchKeyword, setSearchKeyword] = useState(''); const [searchKeyword, setSearchKeyword] = useState('');
const [searching, setSearching] = useState(false); const [searching, setSearching] = useState(false);
const [logType, setLogType] = useState(0);
const [mode, setMode] = useState('self'); // all, self
const showModePanel = isAdmin();
const loadLogs = async (startIdx) => { const loadLogs = async (startIdx) => {
const res = await API.get(`/api/log/self/?p=${startIdx}`); let url = `/api/log/self/?p=${startIdx}&type=${logType}`;
if (mode === 'all') {
url = `/api/log/?p=${startIdx}&type=${logType}`;
}
const res = await API.get(url);
const { success, message, data } = res.data; const { success, message, data } = res.data;
if (success) { if (success) {
if (startIdx === 0) { if (startIdx === 0) {
@ -74,6 +94,10 @@ const LogsTable = () => {
}); });
}, []); }, []);
useEffect(() => {
refresh().then();
}, [mode, logType]);
const searchLogs = async () => { const searchLogs = async () => {
if (searchKeyword === '') { if (searchKeyword === '') {
// if keyword is blank, load files instead. // if keyword is blank, load files instead.
@ -125,6 +149,19 @@ const LogsTable = () => {
> >
时间 时间
</Table.HeaderCell> </Table.HeaderCell>
{
showModePanel && (
<Table.HeaderCell
style={{ cursor: 'pointer' }}
onClick={() => {
sortLog('user_id');
}}
width={1}
>
用户
</Table.HeaderCell>
)
}
<Table.HeaderCell <Table.HeaderCell
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
onClick={() => { onClick={() => {
@ -139,7 +176,7 @@ const LogsTable = () => {
onClick={() => { onClick={() => {
sortLog('content'); sortLog('content');
}} }}
width={11} width={showModePanel ? 10 : 11}
> >
详情 详情
</Table.HeaderCell> </Table.HeaderCell>
@ -157,6 +194,11 @@ const LogsTable = () => {
return ( return (
<Table.Row key={log.created_at}> <Table.Row key={log.created_at}>
<Table.Cell>{renderTimestamp(log.created_at)}</Table.Cell> <Table.Cell>{renderTimestamp(log.created_at)}</Table.Cell>
{
showModePanel && (
<Table.Cell><Label>{log.user_id}</Label></Table.Cell>
)
}
<Table.Cell>{renderType(log.type)}</Table.Cell> <Table.Cell>{renderType(log.type)}</Table.Cell>
<Table.Cell>{log.content}</Table.Cell> <Table.Cell>{log.content}</Table.Cell>
</Table.Row> </Table.Row>
@ -166,7 +208,31 @@ const LogsTable = () => {
<Table.Footer> <Table.Footer>
<Table.Row> <Table.Row>
<Table.HeaderCell colSpan='4'> <Table.HeaderCell colSpan={showModePanel ? '5' : '4'}>
{
showModePanel && (
<Select
placeholder='选择模式'
options={MODE_OPTIONS}
style={{ marginRight: '8px' }}
name='mode'
value={mode}
onChange={(e, { name, value }) => {
setMode(value);
}}
/>
)
}
<Select
placeholder='选择明细分类'
options={LOG_OPTIONS}
style={{ marginRight: '8px' }}
name='logType'
value={logType}
onChange={(e, { name, value }) => {
setLogType(value);
}}
/>
<Button size='small' onClick={refresh} loading={loading}>刷新</Button> <Button size='small' onClick={refresh} loading={loading}>刷新</Button>
<Pagination <Pagination
floated='right' floated='right'