fix(): 修改布局
This commit is contained in:
3
.vite/deps/package.json
Normal file
3
.vite/deps/package.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
104
src/App.css
104
src/App.css
@@ -29,32 +29,32 @@
|
||||
box-shadow: 0 8px 20px rgba(0,0,0,0.25);
|
||||
}
|
||||
.form-split { color: var(--muted); }
|
||||
:root{ /* 深色科技风主题 - 参考 x.ai */
|
||||
--bg: #0a0a0f;
|
||||
--bg-secondary: #12121a;
|
||||
--panel: rgba(20, 20, 30, 0.6);
|
||||
--panel-solid: #14141e;
|
||||
--soft: rgba(30, 30, 45, 0.5);
|
||||
--text: #e8e8f0;
|
||||
--text-secondary: #a0a0b0;
|
||||
--muted: #6a6a7a;
|
||||
--accent: #7c5cff;
|
||||
--accent-glow: rgba(124, 92, 255, 0.3);
|
||||
--accent-gradient: linear-gradient(135deg, #7c5cff 0%, #a084ff 100%);
|
||||
--primary-gradient: linear-gradient(135deg, #7c5cff 0%, #5d3fd3 100%);
|
||||
:root{ /* 浅色主题 */
|
||||
--bg: #f5f7fb;
|
||||
--bg-secondary: #ffffff;
|
||||
--panel: #ffffff;
|
||||
--panel-solid: #ffffff;
|
||||
--soft: #f1f3f7;
|
||||
--text: #171a1f;
|
||||
--text-secondary: #4d5562;
|
||||
--muted: #6b7280;
|
||||
--accent: #5f97d2;
|
||||
--accent-glow: rgba(95, 151, 210, 0.2);
|
||||
--accent-gradient: linear-gradient(135deg, #5f97d2 0%, #4a7bb8 100%);
|
||||
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
--secondary-gradient: linear-gradient(135deg, #ff6b9d 0%, #c06cf5 100%);
|
||||
--success-gradient: linear-gradient(135deg, #00d4ff 0%, #0088ff 100%);
|
||||
--warning-gradient: linear-gradient(135deg, #ff9f1c 0%, #ffbf69 100%);
|
||||
--info-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
--good: #00d4aa;
|
||||
--warn: #ffb347;
|
||||
--bad: #ff6b9d;
|
||||
--border: rgba(124, 92, 255, 0.15);
|
||||
--border-subtle: rgba(255, 255, 255, 0.05);
|
||||
--shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
|
||||
--shadow-lg: 0 20px 60px rgba(0, 0, 0, 0.6);
|
||||
--shadow-colored: 0 10px 30px rgba(124, 92, 255, 0.3);
|
||||
--glow: 0 0 20px rgba(124, 92, 255, 0.4);
|
||||
--good: #2fb167;
|
||||
--warn: #caa410;
|
||||
--bad: #b6404a;
|
||||
--border: #e5e7ef;
|
||||
--border-subtle: #f0f1f5;
|
||||
--shadow: 0 10px 25px rgba(10,16,25,.08);
|
||||
--shadow-lg: 0 20px 40px rgba(10,16,25,.12);
|
||||
--shadow-colored: 0 10px 30px rgba(102, 126, 234, 0.15);
|
||||
--glow: 0 0 20px rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
:root.light{
|
||||
--bg: #f5f7fb;
|
||||
@@ -83,42 +83,6 @@ body{
|
||||
overflow:hidden;
|
||||
position: relative;
|
||||
}
|
||||
/* 科技感网格背景 - 类似 x.ai */
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image:
|
||||
linear-gradient(rgba(124, 92, 255, 0.03) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(124, 92, 255, 0.03) 1px, transparent 1px);
|
||||
background-size: 50px 50px;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
/* 光晕效果 */
|
||||
body::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
background: radial-gradient(
|
||||
circle at 50% 50%,
|
||||
rgba(124, 92, 255, 0.08) 0%,
|
||||
transparent 50%
|
||||
);
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
animation: pulse 8s ease-in-out infinite;
|
||||
}
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 0.5; transform: scale(1); }
|
||||
50% { opacity: 1; transform: scale(1.1); }
|
||||
}
|
||||
a{color:inherit; text-decoration:none}
|
||||
.container{display:flex; flex:1; width:100vw; height:100vh; max-width:none; margin:0; padding:0}
|
||||
|
||||
@@ -346,6 +310,30 @@ a{color:inherit; text-decoration:none}
|
||||
|
||||
.hidden{display:none}
|
||||
|
||||
/* Ant Design Spin 加载组件样式 */
|
||||
.ant-spin {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-spin-text {
|
||||
color: var(--text) !important;
|
||||
display: inline-block !important;
|
||||
white-space: nowrap !important;
|
||||
writing-mode: horizontal-tb !important;
|
||||
text-orientation: mixed !important;
|
||||
}
|
||||
|
||||
.ant-spin-dot {
|
||||
color: var(--accent) !important;
|
||||
}
|
||||
|
||||
.ant-spin-spinning {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
align-items: center !important;
|
||||
gap: 12px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px){
|
||||
.kpis{grid-template-columns: repeat(2, minmax(0,1fr));}
|
||||
.flex-3{grid-template-columns: repeat(2, minmax(0,1fr));}
|
||||
|
||||
@@ -59,6 +59,500 @@
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
/* Card 深色主题 */
|
||||
.ant-card {
|
||||
background: var(--panel) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
color: var(--text) !important;
|
||||
backdrop-filter: blur(20px);
|
||||
}
|
||||
|
||||
.ant-card-head {
|
||||
background: transparent !important;
|
||||
border-bottom: 1px solid var(--border) !important;
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-card-head-title {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-card-body {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
/* Table 深色主题 */
|
||||
.ant-table {
|
||||
background: var(--panel) !important;
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-table-thead > tr > th {
|
||||
background: var(--soft) !important;
|
||||
border-bottom: 1px solid var(--border) !important;
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr > td {
|
||||
border-bottom: 1px solid var(--border-subtle) !important;
|
||||
color: var(--text) !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr:hover > td {
|
||||
background: rgba(124, 92, 255, 0.08) !important;
|
||||
}
|
||||
|
||||
.ant-table-wrapper {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-table-container {
|
||||
border: 1px solid var(--border) !important;
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-table-tbody {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-table-cell {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.ant-table-placeholder {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-table-placeholder .ant-empty-description {
|
||||
color: var(--muted) !important;
|
||||
}
|
||||
|
||||
.ant-table-pagination {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
/* 表格内容区域强制深色 */
|
||||
.ant-table-content {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-table-body {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
/* 修复表格加载时的闪烁 - 更全面的覆盖 */
|
||||
.ant-spin-container {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-spin-nested-loading {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-spin-nested-loading > div > .ant-spin {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.ant-spin-blur {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-spin-blur::after {
|
||||
background: var(--panel) !important;
|
||||
opacity: 0.4 !important;
|
||||
}
|
||||
|
||||
/* 确保表格区域始终是深色 */
|
||||
.ant-table-wrapper .ant-table {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-table-wrapper .ant-table-container {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-table-wrapper .ant-table-content {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-table-wrapper .ant-table-body {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
/* 表格所有可能的子元素都设置深色背景 */
|
||||
.ant-table-wrapper .ant-spin-nested-loading,
|
||||
.ant-table-wrapper .ant-spin-container {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
/* Card 内的表格 */
|
||||
.ant-card .ant-table-wrapper,
|
||||
.ant-card .ant-table,
|
||||
.ant-card .ant-table-container,
|
||||
.ant-card .ant-table-content,
|
||||
.ant-card .ant-spin-container,
|
||||
.ant-card .ant-spin-nested-loading {
|
||||
background: var(--panel) !important;
|
||||
}
|
||||
|
||||
.ant-pagination-item {
|
||||
background: var(--soft) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-pagination-item a {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-pagination-item-active {
|
||||
background: var(--accent) !important;
|
||||
border-color: var(--accent) !important;
|
||||
}
|
||||
|
||||
.ant-pagination-item-active a {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
/* Form 深色主题 */
|
||||
.ant-form-item-label > label {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-input,
|
||||
.ant-input-affix-wrapper,
|
||||
.ant-input-number,
|
||||
.ant-select-selector,
|
||||
.ant-picker {
|
||||
background: var(--soft) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-input::placeholder,
|
||||
.ant-input-affix-wrapper input::placeholder {
|
||||
color: var(--muted) !important;
|
||||
}
|
||||
|
||||
.ant-input:hover,
|
||||
.ant-input-affix-wrapper:hover,
|
||||
.ant-input-number:hover,
|
||||
.ant-select-selector:hover,
|
||||
.ant-picker:hover {
|
||||
border-color: var(--accent) !important;
|
||||
}
|
||||
|
||||
.ant-input:focus,
|
||||
.ant-input-affix-wrapper:focus,
|
||||
.ant-input-affix-wrapper-focused,
|
||||
.ant-input-number:focus,
|
||||
.ant-select-focused .ant-select-selector,
|
||||
.ant-picker-focused {
|
||||
border-color: var(--accent) !important;
|
||||
box-shadow: 0 0 0 2px rgba(124, 92, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
/* Select 深色主题 */
|
||||
.ant-select-dropdown {
|
||||
background: var(--panel-solid) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-select-item {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-select-item-option-selected {
|
||||
background: rgba(124, 92, 255, 0.15) !important;
|
||||
}
|
||||
|
||||
.ant-select-item-option-active {
|
||||
background: rgba(124, 92, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
.ant-select-arrow {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-select-clear {
|
||||
background: var(--soft) !important;
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
/* Button 深色主题 */
|
||||
.ant-btn {
|
||||
border: 1px solid var(--border) !important;
|
||||
background: var(--soft) !important;
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-btn:hover {
|
||||
border-color: var(--accent) !important;
|
||||
background: rgba(124, 92, 255, 0.1) !important;
|
||||
color: var(--accent) !important;
|
||||
}
|
||||
|
||||
.ant-btn-primary {
|
||||
background: var(--primary-gradient) !important;
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.ant-btn-primary:hover {
|
||||
background: linear-gradient(135deg, #9075ff 0%, #7051e0 100%) !important;
|
||||
box-shadow: 0 0 20px rgba(124, 92, 255, 0.4) !important;
|
||||
}
|
||||
|
||||
.ant-btn-link {
|
||||
color: var(--accent) !important;
|
||||
border: none !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.ant-btn-link:hover {
|
||||
color: #9075ff !important;
|
||||
}
|
||||
|
||||
/* Modal 深色主题 */
|
||||
.ant-modal-content {
|
||||
background: var(--panel-solid) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-modal-header {
|
||||
background: transparent !important;
|
||||
border-bottom: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-modal-title {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-modal-body {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-modal-footer {
|
||||
border-top: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-modal-close {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-modal-close:hover {
|
||||
color: var(--accent) !important;
|
||||
}
|
||||
|
||||
/* Drawer 深色主题 */
|
||||
.ant-drawer-content {
|
||||
background: var(--panel-solid) !important;
|
||||
}
|
||||
|
||||
.ant-drawer-header {
|
||||
background: transparent !important;
|
||||
border-bottom: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-drawer-title {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-drawer-body {
|
||||
color: var(--text) !important;
|
||||
background: var(--panel-solid) !important;
|
||||
}
|
||||
|
||||
.ant-drawer-close {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-drawer-close:hover {
|
||||
color: var(--accent) !important;
|
||||
}
|
||||
|
||||
/* DatePicker 深色主题 */
|
||||
.ant-picker-panel-container {
|
||||
background: var(--panel-solid) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-picker-header {
|
||||
color: var(--text) !important;
|
||||
border-bottom: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-picker-content th {
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
.ant-picker-cell {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-picker-cell:hover .ant-picker-cell-inner {
|
||||
background: rgba(124, 92, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
.ant-picker-cell-selected .ant-picker-cell-inner {
|
||||
background: var(--accent) !important;
|
||||
}
|
||||
|
||||
.ant-picker-today-btn {
|
||||
color: var(--accent) !important;
|
||||
}
|
||||
|
||||
/* Tag 深色主题 */
|
||||
.ant-tag {
|
||||
background: var(--soft) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-tag-success {
|
||||
background: rgba(0, 212, 170, 0.15) !important;
|
||||
border-color: var(--good) !important;
|
||||
color: var(--good) !important;
|
||||
}
|
||||
|
||||
.ant-tag-processing {
|
||||
background: rgba(102, 126, 234, 0.15) !important;
|
||||
border-color: #667eea !important;
|
||||
color: #667eea !important;
|
||||
}
|
||||
|
||||
.ant-tag-error {
|
||||
background: rgba(255, 107, 157, 0.15) !important;
|
||||
border-color: var(--bad) !important;
|
||||
color: var(--bad) !important;
|
||||
}
|
||||
|
||||
.ant-tag-warning {
|
||||
background: rgba(255, 179, 71, 0.15) !important;
|
||||
border-color: var(--warn) !important;
|
||||
color: var(--warn) !important;
|
||||
}
|
||||
|
||||
/* Divider 深色主题 */
|
||||
.ant-divider {
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
/* Typography 深色主题 */
|
||||
.ant-typography {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-typography-secondary {
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
/* Statistic 深色主题 */
|
||||
.ant-statistic-title {
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
.ant-statistic-content {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
/* Message 深色主题 */
|
||||
.ant-message-notice-content {
|
||||
background: var(--panel-solid) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
/* Empty 深色主题 */
|
||||
.ant-empty-description {
|
||||
color: var(--muted) !important;
|
||||
}
|
||||
|
||||
/* Spin 深色主题 */
|
||||
.ant-spin-text {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
/* Switch 深色主题 */
|
||||
.ant-switch {
|
||||
background: var(--soft) !important;
|
||||
}
|
||||
|
||||
.ant-switch-checked {
|
||||
background: var(--accent) !important;
|
||||
}
|
||||
|
||||
/* Checkbox & Radio 深色主题 */
|
||||
.ant-checkbox-wrapper,
|
||||
.ant-radio-wrapper {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-checkbox-inner,
|
||||
.ant-radio-inner {
|
||||
background: var(--soft) !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-checkbox-checked .ant-checkbox-inner,
|
||||
.ant-radio-checked .ant-radio-inner {
|
||||
background: var(--accent) !important;
|
||||
border-color: var(--accent) !important;
|
||||
}
|
||||
|
||||
/* Dropdown 深色主题 */
|
||||
.ant-dropdown-menu {
|
||||
background: var(--panel-solid) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item:hover {
|
||||
background: rgba(124, 92, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
/* Tabs 深色主题 */
|
||||
.ant-tabs-nav {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.ant-tabs-tab {
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
.ant-tabs-tab:hover {
|
||||
color: var(--accent) !important;
|
||||
}
|
||||
|
||||
.ant-tabs-tab-active {
|
||||
color: var(--accent) !important;
|
||||
}
|
||||
|
||||
.ant-tabs-ink-bar {
|
||||
background: var(--accent) !important;
|
||||
}
|
||||
|
||||
/* Alert 深色主题 */
|
||||
.ant-alert {
|
||||
background: var(--soft) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.ant-alert-message {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
.ant-alert-description {
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
/* 容器层级 */
|
||||
.container {
|
||||
position: relative;
|
||||
|
||||
@@ -3,7 +3,6 @@ import { createRoot } from 'react-dom/client'
|
||||
import { Provider } from 'jotai'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import './App.css'
|
||||
import './darkTheme.css'
|
||||
import 'antd/dist/reset.css'
|
||||
import App from './App.tsx'
|
||||
import AuthGuard from './components/AuthGuard'
|
||||
|
||||
@@ -33,27 +33,27 @@ const FinanceTokenUsage: React.FC = () => {
|
||||
useEffect(() => { fetchList(); }, []);
|
||||
|
||||
const columns: ColumnsType<any> = useMemo(() => ([
|
||||
{ title: '用户id', dataIndex: 'user_id', key: 'user_id' },
|
||||
{ title: 'API分组', dataIndex: 'api_group', key: 'api_group' },
|
||||
{ title: '对话id', dataIndex: 'project_id', key: 'project_id' },
|
||||
{ title: '日期', dataIndex: 'day', key: 'day' },
|
||||
{ title: '小时', dataIndex: 'hour', key: 'hour' },
|
||||
{ title: '服务商', dataIndex: 'provider', key: 'provider' },
|
||||
{ title: '账号', dataIndex: 'account', key: 'account' },
|
||||
{ title: '模型', dataIndex: 'model', key: 'model' },
|
||||
{ title: '代理类型', dataIndex: 'agent_type', key: 'agent_type' },
|
||||
{ title: '任务id', dataIndex: 'chat_id', key: 'chat_id' },
|
||||
{ title: '花费金额(总)', dataIndex: 'cost', key: 'cost' },
|
||||
{ title: '提示Tokens', dataIndex: 'prompt_token', key: 'prompt_token' },
|
||||
{ title: '输出Tokens', dataIndex: 'completion_token', key: 'completion_token' },
|
||||
{ title: '缓存创建Tokens', dataIndex: 'cache_create_token', key: 'cache_create_token' },
|
||||
{ title: '缓存命中Tokens', dataIndex: 'cache_read_token', key: 'cache_read_token' },
|
||||
{ title: '提示花费', dataIndex: 'prompt_cost', key: 'prompt_cost' },
|
||||
{ title: '输出花费', dataIndex: 'completion_cost', key: 'completion_cost' },
|
||||
{ title: '缓存创建花费', dataIndex: 'cache_create_cost', key: 'cache_create_cost' },
|
||||
{ title: '缓存命花费', dataIndex: 'cache_read_cost', key: 'cache_read_cost' },
|
||||
{ title: '创建时间', dataIndex: 'created_at', key: 'created_at' },
|
||||
{ title: '修改时间', dataIndex: 'updated_at', key: 'updated_at' },
|
||||
{ title: '用户id', dataIndex: 'user_id', key: 'user_id', width: 100 },
|
||||
{ title: 'API分组', dataIndex: 'api_group', key: 'api_group', width: 120 },
|
||||
{ title: '对话id', dataIndex: 'project_id', key: 'project_id', width: 80 },
|
||||
{ title: '日期', dataIndex: 'day', key: 'day', width: 110 },
|
||||
{ title: '小时', dataIndex: 'hour', key: 'hour', width: 60 },
|
||||
{ title: '服务商', dataIndex: 'provider', key: 'provider', width: 80 },
|
||||
{ title: '账号', dataIndex: 'account', key: 'account', width: 80 },
|
||||
{ title: '模型', dataIndex: 'model', key: 'model', width: 150 },
|
||||
{ title: '代理类型', dataIndex: 'agent_type', key: 'agent_type', width: 80 },
|
||||
{ title: '任务id', dataIndex: 'chat_id', key: 'chat_id', width: 100 },
|
||||
{ title: '花费金额(总)', dataIndex: 'cost', key: 'cost', width: 120 },
|
||||
{ title: '提示Tokens', dataIndex: 'prompt_token', key: 'prompt_token', width: 110 },
|
||||
{ title: '输出Tokens', dataIndex: 'completion_token', key: 'completion_token', width: 110 },
|
||||
{ title: '缓存创建Tokens', dataIndex: 'cache_create_token', key: 'cache_create_token', width: 130 },
|
||||
{ title: '缓存命中Tokens', dataIndex: 'cache_read_token', key: 'cache_read_token', width: 130 },
|
||||
{ title: '提示花费', dataIndex: 'prompt_cost', key: 'prompt_cost', width: 100 },
|
||||
{ title: '输出花费', dataIndex: 'completion_cost', key: 'completion_cost', width: 100 },
|
||||
{ title: '缓存创建花费', dataIndex: 'cache_create_cost', key: 'cache_create_cost', width: 120 },
|
||||
{ title: '缓存命花费', dataIndex: 'cache_read_cost', key: 'cache_read_cost', width: 120 },
|
||||
{ title: '创建时间', dataIndex: 'created_at', key: 'created_at', width: 160 },
|
||||
{ title: '修改时间', dataIndex: 'updated_at', key: 'updated_at', width: 160 },
|
||||
]), []);
|
||||
|
||||
return (
|
||||
@@ -81,7 +81,7 @@ const FinanceTokenUsage: React.FC = () => {
|
||||
dataSource={data}
|
||||
loading={loading}
|
||||
pagination={{ current: page, pageSize: size, total, onChange: (p, s) => { setPage(p); setSize(s); fetchList(p, s); } }}
|
||||
scroll={{ x: 1200 }}
|
||||
scroll={{ x: 2300 }}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -58,40 +58,57 @@ const FinanceTransactionLogs: React.FC = () => {
|
||||
|
||||
return (
|
||||
<Card bordered={false} title={<Typography.Title level={4} style={{ margin: 0 }}>用户流水</Typography.Title>}>
|
||||
<Form form={form} layout="inline" onFinish={() => fetchList(1, size)} style={{ marginBottom: 12 }}>
|
||||
<Form.Item name="user_id" label="用户id">
|
||||
<Input allowClear placeholder="用户id" style={{ width: 180 }} />
|
||||
</Form.Item>
|
||||
<Form.Item name="order_id" label="订单id">
|
||||
<Input allowClear placeholder="订单id" style={{ width: 180 }} />
|
||||
</Form.Item>
|
||||
<Form.Item name="type" label="流水类型">
|
||||
<Select allowClear placeholder="recharge/refund/consume" style={{ width: 200 }}
|
||||
options={[
|
||||
{ label: 'recharge', value: 'recharge' },
|
||||
{ label: 'refund', value: 'refund' },
|
||||
{ label: 'consume', value: 'consume' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name="status" label="状态">
|
||||
<Select allowClear placeholder="success/failed/pending" style={{ width: 200 }}
|
||||
options={[
|
||||
{ label: 'success', value: 'success' },
|
||||
{ label: 'failed', value: 'failed' },
|
||||
{ label: 'pending', value: 'pending' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name="range" label="时间范围">
|
||||
<DatePicker.RangePicker />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Space>
|
||||
<Button type="primary" htmlType="submit" onClick={() => { setPage(1); }}>查询</Button>
|
||||
<Button onClick={() => { form.resetFields(); fetchList(1, size); setPage(1); }}>重置</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={() => fetchList(1, size)}
|
||||
style={{ marginBottom: 20 }}
|
||||
>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
||||
{/* 第一行:用户ID、订单编号、流水类型、状态、时间范围 */}
|
||||
<div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap', alignItems: 'center' }}>
|
||||
<Form.Item name="user_id" label="用户PID:" style={{ margin: 0, flex: '0 0 auto' }}>
|
||||
<Input allowClear placeholder="用户ID" style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
<Form.Item name="order_id" label="订单编号:" style={{ margin: 0, flex: '0 0 auto' }}>
|
||||
<Input allowClear placeholder="订单编号" style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
<Form.Item name="type" label="流水类型:" style={{ margin: 0, flex: '0 0 auto' }}>
|
||||
<Select allowClear placeholder="充值/退款/消费" style={{ width: 220 }}
|
||||
options={[
|
||||
{ label: 'recharge', value: 'recharge' },
|
||||
{ label: 'refund', value: 'refund' },
|
||||
{ label: 'consume', value: 'consume' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name="status" label="状态:" style={{ margin: 0, flex: '0 0 auto' }}>
|
||||
<Select allowClear placeholder="成功/失败/待定" style={{ width: 220 }}
|
||||
options={[
|
||||
{ label: 'success', value: 'success' },
|
||||
{ label: 'failed', value: 'failed' },
|
||||
{ label: 'pending', value: 'pending' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
{/* 第二行:时间范围和按钮 */}
|
||||
<div style={{ display: 'flex', gap: '16px', alignItems: 'center', flexWrap: 'wrap' }}>
|
||||
<Form.Item name="range" label="时间范围:" style={{ margin: 0, flex: '0 0 auto' }}>
|
||||
<DatePicker.RangePicker style={{ width: 300 }} />
|
||||
</Form.Item>
|
||||
<Form.Item style={{ margin: 0, flex: '0 0 auto' }}>
|
||||
<Space size="middle">
|
||||
<Button type="primary" htmlType="submit" onClick={() => { setPage(1); }} size="middle">
|
||||
查 询
|
||||
</Button>
|
||||
<Button onClick={() => { form.resetFields(); fetchList(1, size); setPage(1); }} size="middle">
|
||||
重 置
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
<Table
|
||||
rowKey={(r) => r.id || r.transaction_id}
|
||||
|
||||
Reference in New Issue
Block a user