157 lines
6.7 KiB
JavaScript
157 lines
6.7 KiB
JavaScript
import AddOutlined from "@mui/icons-material/AddOutlined";
|
|
import RefreshOutlined from "@mui/icons-material/RefreshOutlined";
|
|
import Button from "@mui/material/Button";
|
|
import MenuItem from "@mui/material/MenuItem";
|
|
import Table from "@mui/material/Table";
|
|
import TableBody from "@mui/material/TableBody";
|
|
import TableCell from "@mui/material/TableCell";
|
|
import TableContainer from "@mui/material/TableContainer";
|
|
import TableHead from "@mui/material/TableHead";
|
|
import TableRow from "@mui/material/TableRow";
|
|
import TextField from "@mui/material/TextField";
|
|
import { APPLICATION_STATUS } from "../constants.js";
|
|
import { formatAmount, formatTime, operationLabel, statusLabel, walletIdentityLabel } from "../format.js";
|
|
|
|
export function FinanceMyApplicationList({ applications, error, filters, loading, onCreate, onFiltersChange, onReload, operations, options }) {
|
|
const items = applications.items || [];
|
|
const page = Number(applications.page || filters.page || 1);
|
|
const pageSize = Number(applications.pageSize || 50);
|
|
const total = Number(applications.total || 0);
|
|
const hasNextPage = page * pageSize < total;
|
|
|
|
return (
|
|
<section className="finance-panel finance-list">
|
|
<div className="finance-toolbar finance-toolbar--with-action">
|
|
<TextField label="APP" select value={filters.appCode} onChange={(event) => onFiltersChange({ appCode: event.target.value })}>
|
|
<MenuItem value="">全部 APP</MenuItem>
|
|
{options.apps.map((app) => (
|
|
<MenuItem key={app.appCode} value={app.appCode}>
|
|
{app.appName || app.appCode}
|
|
</MenuItem>
|
|
))}
|
|
</TextField>
|
|
<TextField label="操作内容" select value={filters.operation} onChange={(event) => onFiltersChange({ operation: event.target.value })}>
|
|
<MenuItem value="">全部操作</MenuItem>
|
|
{operations.map((operation) => (
|
|
<MenuItem key={operation.value} value={operation.value}>
|
|
{operation.label}
|
|
</MenuItem>
|
|
))}
|
|
</TextField>
|
|
<TextField label="状态" select value={filters.status} onChange={(event) => onFiltersChange({ status: event.target.value })}>
|
|
<MenuItem value="">全部状态</MenuItem>
|
|
{APPLICATION_STATUS.map(([value, label]) => (
|
|
<MenuItem key={value} value={value}>
|
|
{label}
|
|
</MenuItem>
|
|
))}
|
|
</TextField>
|
|
<TextField label="搜索" value={filters.keyword} onChange={(event) => onFiltersChange({ keyword: event.target.value })} />
|
|
<Button startIcon={<RefreshOutlined fontSize="small" />} variant="outlined" onClick={onReload}>
|
|
刷新列表
|
|
</Button>
|
|
<Button startIcon={<AddOutlined fontSize="small" />} variant="contained" onClick={onCreate}>
|
|
添加
|
|
</Button>
|
|
</div>
|
|
{error ? <div className="finance-error">{error}</div> : null}
|
|
{loading && !items.length ? <div className="finance-skeleton" /> : null}
|
|
{!loading || items.length ? (
|
|
<TableContainer className="finance-table-wrap">
|
|
<Table className="finance-table" size="small" stickyHeader>
|
|
<TableHead>
|
|
<TableRow>
|
|
<TableCell>APP</TableCell>
|
|
<TableCell>操作</TableCell>
|
|
<TableCell>目标用户</TableCell>
|
|
<TableCell align="right">金币数量</TableCell>
|
|
<TableCell align="right">充值金额</TableCell>
|
|
<TableCell>凭证</TableCell>
|
|
<TableCell>状态</TableCell>
|
|
<TableCell className="finance-time-cell">发起申请时间</TableCell>
|
|
<TableCell>审批人</TableCell>
|
|
<TableCell className="finance-time-cell">审核时间</TableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
{items.length ? (
|
|
items.map((item) => (
|
|
<TableRow key={item.id}>
|
|
<TableCell>{item.appName || item.appCode || "-"}</TableCell>
|
|
<TableCell>
|
|
<Stacked primary={operationLabel(item.operation, operations)} secondary={walletIdentityLabel(item.walletIdentity)} />
|
|
</TableCell>
|
|
<TableCell>{item.targetUserId || "-"}</TableCell>
|
|
<TableCell align="right">{formatAmount(item.coinAmount)}</TableCell>
|
|
<TableCell align="right">{formatAmount(item.rechargeAmount)}</TableCell>
|
|
<TableCell>
|
|
<Evidence item={item} />
|
|
</TableCell>
|
|
<TableCell>
|
|
<StatusBadge status={item.status} />
|
|
</TableCell>
|
|
<TableCell className="finance-time-cell">{formatTime(item.createdAtMs)}</TableCell>
|
|
<TableCell>
|
|
<Stacked primary={item.auditorName || "-"} secondary={item.auditorUserId || ""} />
|
|
</TableCell>
|
|
<TableCell className="finance-time-cell">{formatTime(item.auditedAtMs)}</TableCell>
|
|
</TableRow>
|
|
))
|
|
) : (
|
|
<TableRow>
|
|
<TableCell align="center" colSpan={10}>
|
|
当前无数据
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</TableContainer>
|
|
) : null}
|
|
{total > pageSize ? (
|
|
<div className="finance-pagination">
|
|
<Button disabled={page <= 1 || loading} variant="outlined" onClick={() => onFiltersChange({ page: page - 1 })}>
|
|
上一页
|
|
</Button>
|
|
<span>
|
|
第 {page} 页 / 共 {total} 条
|
|
</span>
|
|
<Button disabled={!hasNextPage || loading} variant="outlined" onClick={() => onFiltersChange({ page: page + 1 })}>
|
|
下一页
|
|
</Button>
|
|
</div>
|
|
) : null}
|
|
</section>
|
|
);
|
|
}
|
|
|
|
function Evidence({ item }) {
|
|
if (!item.credentialImageUrl && !item.credentialText) {
|
|
return "-";
|
|
}
|
|
return (
|
|
<span className="finance-evidence">
|
|
{item.credentialImageUrl ? (
|
|
<a href={item.credentialImageUrl} rel="noreferrer" target="_blank">
|
|
图片
|
|
</a>
|
|
) : null}
|
|
{item.credentialText ? <span title={item.credentialText}>{item.credentialText}</span> : null}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
function Stacked({ primary, secondary }) {
|
|
return (
|
|
<span className="finance-stack">
|
|
<span>{primary || "-"}</span>
|
|
<small>{secondary || ""}</small>
|
|
</span>
|
|
);
|
|
}
|
|
|
|
function StatusBadge({ status }) {
|
|
const tone = status === "approved" ? "success" : status === "rejected" ? "danger" : "warning";
|
|
return <span className={`finance-status finance-status--${tone}`}>{statusLabel(status)}</span>;
|
|
}
|