This commit is contained in:
2026-07-06 16:35:22 +08:00
parent 4412bc9378
commit cff69423d7
7 changed files with 92 additions and 64 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -28,7 +28,7 @@
}
})();
</script>
<script type="module" crossorigin src="/assets/index-D7ovjI8j.js"></script>
<script type="module" crossorigin src="/assets/index-DlbOvnzQ.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D9_3MPsN.css">
</head>
<body>
+49 -23
View File
@@ -2,15 +2,20 @@ import React, { useEffect, useState, useCallback } from 'react';
import {
Button, Card, Empty, Form, Input, InputNumber, message, Modal, Radio, Select, Space, Table, Tabs, Tag, Tooltip, Typography,
} from 'antd';
import { DatePicker } from 'antd';
import dayjs from 'dayjs';
import {
CopyOutlined, DownloadOutlined, PlusOutlined, ReloadOutlined, UserOutlined, HistoryOutlined, WalletOutlined,
} from '@ant-design/icons';
const { RangePicker } = DatePicker;
import {
createTeamInvitation, getJoinTeamInfo, getManagedTeam, getPendingJoinRequests,
getTeamCreditExportUrl, getTeamCreditRecords, getTeamInvitations, getTeamMembers, handleJoinRequest, revokeInvitation, submitJoinRequest, transferCredits,
} from '../api';
import type { ManagedTeam, TeamInvitation, TeamJoinRequest, TeamMember } from '../types';
import { formatDate } from '../utils/formatDate';
import { useAuthStore } from '../store/useAuthStore';
const TeamManagementPage: React.FC = () => {
const [team, setTeam] = useState<ManagedTeam | null>(null);
@@ -329,10 +334,10 @@ const TeamManagementPage: React.FC = () => {
{/* 搜索栏 */}
<div style={{ marginBottom: 12, display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
<Select
value={creditFilterType}
value={creditFilterType || undefined}
onChange={(v) => { setCreditFilterType(v || ''); setCreditPage(1); }}
allowClear
placeholder="全部类型"
placeholder="交易类型"
style={{ width: 130 }}
options={[
{ value: 'recharge', label: '充值' },
@@ -348,30 +353,28 @@ const TeamManagementPage: React.FC = () => {
style={{ width: 160 }}
allowClear
/>
<Input
placeholder="起始日期 YYYY-MM-DD"
value={creditFilterStart}
onChange={(e) => { setCreditFilterStart(e.target.value); setCreditPage(1); }}
style={{ width: 160 }}
/>
<Input
placeholder="截止日期 YYYY-MM-DD"
value={creditFilterEnd}
onChange={(e) => { setCreditFilterEnd(e.target.value); setCreditPage(1); }}
style={{ width: 160 }}
<RangePicker
value={creditFilterStart && creditFilterEnd ? [dayjs(creditFilterStart), dayjs(creditFilterEnd)] : undefined}
onChange={(dates) => {
if (dates && dates[0] && dates[1]) {
setCreditFilterStart(dates[0].format('YYYY-MM-DD'));
setCreditFilterEnd(dates[1].format('YYYY-MM-DD'));
} else {
setCreditFilterStart('');
setCreditFilterEnd('');
}
setCreditPage(1);
}}
/>
<Button onClick={resetCreditFilters}></Button>
<Button type="primary" icon={<DownloadOutlined />} onClick={handleExportCredits}> Excel</Button>
</div>
{/* 汇总统计 */}
{creditSummary && (
<div style={{ marginBottom: 12, padding: '8px 12px', background: '#f8f9fc', borderRadius: 8, display: 'flex', gap: 20, flexWrap: 'wrap', fontSize: 13 }}>
<span><strong style={{ color: '#16a34a' }}>+{creditSummary.total_recharge ?? 0}</strong></span>
<span><strong style={{ color: '#dc2626' }}>-{creditSummary.total_consume ?? 0}</strong></span>
<span><strong>{creditSummary.transaction_count ?? 0}</strong></span>
</div>
)}
<div style={{ marginBottom: 12, padding: '8px 12px', background: '#f8f9fc', borderRadius: 8, display: 'flex', gap: 20, flexWrap: 'wrap', fontSize: 13 }}>
<span><strong style={{ color: '#16a34a' }}>+{creditSummary?.total_recharge ?? 0}</strong></span>
<span><strong style={{ color: '#dc2626' }}>-{creditSummary?.total_consume ?? 0}</strong></span>
</div>
<Table
size="small"
@@ -481,14 +484,37 @@ const TeamManagementPage: React.FC = () => {
width={480}
>
<Form form={creditForm} layout="vertical" style={{ marginTop: 16 }} initialValues={{ direction: 'increase' }}>
<Form.Item name="direction" label="操作类型" rules={[{ required: true }]}>
{/* 显示管理人当前积分 */}
<div style={{ marginBottom: 16, padding: '8px 12px', background: '#f0f4ff', borderRadius: 8, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography.Text type="secondary"></Typography.Text>
<Typography.Text strong style={{ fontSize: 18, color: '#6366f1' }}>
{useAuthStore.getState().user?.credits?.toFixed(2) ?? '0.00'}
</Typography.Text>
</div>
<Form.Item name="direction" label="操作类型" rules={[{ required: true, message: '请选择操作类型' }]}>
<Radio.Group buttonStyle="solid" size="large" style={{ width: '100%' }}>
<Radio.Button value="increase" style={{ width: '50%', textAlign: 'center' }}></Radio.Button>
<Radio.Button value="decrease" style={{ width: '50%', textAlign: 'center' }}></Radio.Button>
</Radio.Group>
</Form.Item>
<Form.Item name="amount" label="积分数量" rules={[{ required: true, message: '请输入数量' }, { type: 'number', min: 0.01, message: '必须大于 0' }]}>
<InputNumber style={{ width: '100%' }} step={1} min={0.01} placeholder="请输入正数积分数量" size="large" />
<Form.Item
name="amount"
label="积分数量"
rules={[
{ required: true, message: '请输入积分数量' },
{ type: 'number', min: 0.01, message: '必须大于 0' },
{ type: 'number', max: 9999999, message: '单次不能超过 9999999' },
{
validator: (_, value) => {
if (!value || value <= 0) return Promise.reject(new Error('请输入有效的正数'));
const decimals = String(value).split('.')[1];
if (decimals && decimals.length > 2) return Promise.reject(new Error('最多两位小数'));
return Promise.resolve();
},
},
]}
>
<InputNumber style={{ width: '100%' }} step={1} min={0.01} precision={2} placeholder="请输入正数积分数量" size="large" />
</Form.Item>
<Form.Item name="description" label="备注">
<Input.TextArea rows={2} maxLength={256} placeholder="选填,例如:活动奖励" />