import { EyeOutlined, PlusOutlined, ReloadOutlined, SearchOutlined } from "@ant-design/icons"; import { listUsers } from "@/api"; import { Button, Card, Col, Descriptions, Form, Input, InputNumber, message, Modal, Row, Select, Space, Statistic, Table, Tag, Typography, } from "antd"; import { useEffect, useMemo, useState } from "react"; import PageContainer from "@/components/shared/PageContainer"; import ListTable from "@/components/shared/ListTable/ListTable"; import AppPagination from "@/components/shared/AppPagination"; import { getMeetingPointsLedgerDetail, getMeetingPointsLedgerPage, getMeetingPointsOverview, transferMeetingPoints, type MeetingPointsChargeItemVO, type MeetingPointsLedgerDetailVO, type MeetingPointsLedgerListItemVO, type MeetingPointsOverviewVO, } from "@/api/business/meetingPoints"; import type { SysUser } from "@/types"; const { Text } = Typography; const POINTS_TYPE_OPTIONS = [ { label: "全部类型", value: "" }, { label: "转录", value: "ASR" }, { label: "总结", value: "LLM" }, ]; function getAccountModeLabel(mode?: string) { if (mode === "PERSONAL") return "个人账户"; if (mode === "BOTH") return "公共和个人共存"; return "公共账户"; } function getChargePriorityLabel(priority?: string) { return priority === "PUBLIC_FIRST" ? "公共优先" : "个人优先"; } function getAccountTypeLabel(type?: string) { return type === "PERSONAL" ? "个人账户" : "公共账户"; } function getPointsTypeLabel(value?: string) { if (value === "ASR") return "转录"; if (value === "LLM") return "总结"; if (value === "TRANSFER_OUT") return "转出"; if (value === "TRANSFER_IN") return "转入"; if (value === "INIT") return "初始化"; return value || "-"; } function getPointsTypeColor(value?: string) { if (value === "ASR") return "blue"; if (value === "LLM") return "purple"; if (value === "TRANSFER_IN") return "green"; if (value === "TRANSFER_OUT") return "orange"; return "default"; } function getChargeTriggerLabel(value?: string) { if (value === "RESUMMARY") return "重新总结"; if (value === "AUTO_SUMMARY") return "自动总结"; return "-"; } function formatDateTime(value?: string) { return value ? value.replace("T", " ").substring(0, 19) : "-"; } export default function MeetingPointsManagement() { const [overview, setOverview] = useState(null); const [loading, setLoading] = useState(false); const [detailLoading, setDetailLoading] = useState(false); const [transferLoading, setTransferLoading] = useState(false); const [records, setRecords] = useState([]); const [total, setTotal] = useState(0); const [detailOpen, setDetailOpen] = useState(false); const [transferOpen, setTransferOpen] = useState(false); const [detail, setDetail] = useState(null); const [users, setUsers] = useState([]); const [params, setParams] = useState({ current: 1, size: 20, username: "", pointsType: "", }); const [transferForm] = Form.useForm(); const loadOverview = async () => { const data = await getMeetingPointsOverview(); setOverview(data); }; const loadUsers = async () => { const data = await listUsers(); setUsers(data || []); }; const loadPage = async (nextParams = params) => { setLoading(true); try { const result = await getMeetingPointsLedgerPage(nextParams); setRecords(result.records || []); setTotal(result.total || 0); } finally { setLoading(false); } }; useEffect(() => { void Promise.all([loadOverview(), loadPage(), loadUsers()]); }, []); const handleSearch = () => { const nextParams = { ...params, current: 1 }; setParams(nextParams); void loadPage(nextParams); }; const handleReset = () => { const nextParams = { current: 1, size: 20, username: "", pointsType: "", }; setParams(nextParams); void loadPage(nextParams); }; const handleRefresh = async () => { await Promise.all([loadOverview(), loadPage(), loadUsers()]); message.success("已刷新积分数据"); }; const handleOpenDetail = async (ledgerId: number) => { setDetailLoading(true); setDetailOpen(true); try { const data = await getMeetingPointsLedgerDetail(ledgerId); setDetail(data); } finally { setDetailLoading(false); } }; const handleTransferSubmit = async () => { const values = await transferForm.validateFields(); setTransferLoading(true); try { await transferMeetingPoints(values); message.success("积分分配成功"); setTransferOpen(false); transferForm.resetFields(); await Promise.all([loadOverview(), loadPage()]); } finally { setTransferLoading(false); } }; const columns = useMemo( () => [ { title: "用户", dataIndex: "ownerUserName", key: "ownerUserName", width: 140, render: (value: string) => {value || "-"}, }, { title: "扣费账户", dataIndex: "chargeAccountType", key: "chargeAccountType", width: 120, render: (value: string) => {getAccountTypeLabel(value)}, }, { title: "消耗类型", dataIndex: "pointsType", key: "pointsType", width: 100, render: (value: string) => {getPointsTypeLabel(value)}, }, { title: "消耗积分", dataIndex: "consumedPoints", key: "consumedPoints", width: 110, render: (value: number) => {value ?? 0}, }, { title: "会议标题", dataIndex: "meetingTitle", key: "meetingTitle", ellipsis: true, render: (value: string) => {value || "-"}, }, { title: "触发类型", dataIndex: "chargeTriggerType", key: "chargeTriggerType", width: 130, render: (value: string) => {getChargeTriggerLabel(value)}, }, { title: "消耗时间", dataIndex: "createdAt", key: "createdAt", width: 180, render: (value: string) => {formatDateTime(value)}, }, { title: "操作", key: "action", width: 88, fixed: "right" as const, render: (_: unknown, record: MeetingPointsLedgerListItemVO) => ( ), }, ], [], ); const chargeItemColumns = useMemo( () => [ { title: "阶段", dataIndex: "chargeStage", key: "chargeStage", render: (value: string) => {getPointsTypeLabel(value)}, }, { title: "扣费账户", dataIndex: "accountType", key: "accountType", render: (value: string) => getAccountTypeLabel(value), }, { title: "账户用户ID", dataIndex: "accountUserId", key: "accountUserId", }, { title: "扣费积分", dataIndex: "chargedPoints", key: "chargedPoints", }, { title: "扣费前余额", dataIndex: "balanceBefore", key: "balanceBefore", }, { title: "扣费后余额", dataIndex: "balanceAfter", key: "balanceAfter", }, ], [], ); return ( 当前模式:{getAccountModeLabel(overview?.accountMode)} 优先级:{getChargePriorityLabel(overview?.chargePriority)} } toolbar={ setParams((prev) => ({ ...prev, username: event.target.value }))} style={{ width: 220 }} prefix={} allowClear /> user.userId && user.userId > 0) .map((user) => ({ label: `${user.displayName || user.username} (#${user.userId})`, value: user.userId, }))} /> ); }