610 lines
30 KiB
TypeScript
610 lines
30 KiB
TypeScript
'use client';
|
||
|
||
import { useState, useEffect, useCallback } from 'react';
|
||
import { PageContainer } from '@/components/layout';
|
||
import { cn } from '@/utils/helpers';
|
||
import styles from './settings.module.scss';
|
||
import { systemConfigService, type DisplaySettings } from '@/services/systemConfigService';
|
||
|
||
/**
|
||
* 后台账号数据接口
|
||
*/
|
||
interface AdminAccount {
|
||
id: string;
|
||
name: string;
|
||
role: string;
|
||
status: 'active' | 'disabled';
|
||
lastLogin: string;
|
||
}
|
||
|
||
/**
|
||
* 操作日志数据接口
|
||
*/
|
||
interface OperationLog {
|
||
id: string;
|
||
time: string;
|
||
account: string;
|
||
type: string;
|
||
description: string;
|
||
result: 'pass' | 'reject' | 'pending';
|
||
}
|
||
|
||
/**
|
||
* 考核目标数据接口
|
||
*/
|
||
interface AssessmentTarget {
|
||
month: number;
|
||
provinceMonthly: number;
|
||
provinceCumulative: number;
|
||
cityMonthly: number;
|
||
cityCumulative: number;
|
||
}
|
||
|
||
// 模拟后台账号数据
|
||
const mockAccounts: AdminAccount[] = [
|
||
{ id: '1', name: 'admin', role: '超级管理员', status: 'active', lastLogin: '2023-10-26 10:30' },
|
||
{ id: '2', name: 'operator01', role: '运营人员', status: 'active', lastLogin: '2023-10-26 09:15' },
|
||
];
|
||
|
||
// 模拟操作日志数据
|
||
const mockLogs: OperationLog[] = [
|
||
{ id: '1', time: '10-26 10:35', account: 'admin', type: '修改配置', description: '修改结算参数', result: 'pass' },
|
||
];
|
||
|
||
// 模拟考核目标数据
|
||
const mockTargets: AssessmentTarget[] = [
|
||
{ month: 1, provinceMonthly: 100, provinceCumulative: 100, cityMonthly: 20, cityCumulative: 20 },
|
||
{ month: 2, provinceMonthly: 120, provinceCumulative: 220, cityMonthly: 25, cityCumulative: 45 },
|
||
];
|
||
|
||
export default function SettingsPage() {
|
||
// 结算参数设置
|
||
const [settlementCurrencies, setSettlementCurrencies] = useState<string[]>(['BNB', '积分']);
|
||
const [defaultCurrency, setDefaultCurrency] = useState('');
|
||
|
||
// 龙虎榜设置
|
||
const [enableVirtualAccount, setEnableVirtualAccount] = useState(false);
|
||
const [virtualAccountCount, setVirtualAccountCount] = useState('');
|
||
const [dailyRankEnabled, setDailyRankEnabled] = useState(true);
|
||
const [weeklyRankEnabled, setWeeklyRankEnabled] = useState(true);
|
||
const [monthlyRankEnabled, setMonthlyRankEnabled] = useState(true);
|
||
const [displayCount, setDisplayCount] = useState('');
|
||
|
||
// 认种限额设置
|
||
const [singleAccountLimitEnabled, setSingleAccountLimitEnabled] = useState(false);
|
||
const [singleAccountDays, setSingleAccountDays] = useState('');
|
||
const [singleAccountTrees, setSingleAccountTrees] = useState('');
|
||
const [networkLimitEnabled, setNetworkLimitEnabled] = useState(false);
|
||
const [networkDays, setNetworkDays] = useState('');
|
||
const [networkTrees, setNetworkTrees] = useState('');
|
||
|
||
// 考核规则设置
|
||
const [localUserThreshold, setLocalUserThreshold] = useState('5');
|
||
const [exemptionEnabled, setExemptionEnabled] = useState(false);
|
||
|
||
// 前端展示设置
|
||
const [allowNonAdopterView, setAllowNonAdopterView] = useState(false);
|
||
const [heatDisplayMode, setHeatDisplayMode] = useState<'count' | 'level'>('count');
|
||
const [displaySettingsLoading, setDisplaySettingsLoading] = useState(false);
|
||
const [displaySettingsSaving, setDisplaySettingsSaving] = useState(false);
|
||
const [displaySettingsError, setDisplaySettingsError] = useState<string | null>(null);
|
||
|
||
// 后台账号与安全
|
||
const [approvalCount, setApprovalCount] = useState('3');
|
||
const [sensitiveOperations, setSensitiveOperations] = useState(['修改结算参数', '删除用户']);
|
||
const [logDate, setLogDate] = useState('');
|
||
const [logSearch, setLogSearch] = useState('');
|
||
|
||
// 加载前端展示设置
|
||
const loadDisplaySettings = useCallback(async () => {
|
||
setDisplaySettingsLoading(true);
|
||
setDisplaySettingsError(null);
|
||
try {
|
||
const settings = await systemConfigService.getDisplaySettings();
|
||
setAllowNonAdopterView(settings.allowNonAdopterViewHeat);
|
||
setHeatDisplayMode(settings.heatDisplayMode);
|
||
} catch (error) {
|
||
console.error('Failed to load display settings:', error);
|
||
setDisplaySettingsError('加载展示设置失败');
|
||
} finally {
|
||
setDisplaySettingsLoading(false);
|
||
}
|
||
}, []);
|
||
|
||
// 保存前端展示设置
|
||
const saveDisplaySettings = useCallback(async () => {
|
||
setDisplaySettingsSaving(true);
|
||
setDisplaySettingsError(null);
|
||
try {
|
||
await systemConfigService.updateDisplaySettings({
|
||
allowNonAdopterViewHeat: allowNonAdopterView,
|
||
heatDisplayMode: heatDisplayMode,
|
||
});
|
||
alert('展示设置保存成功');
|
||
} catch (error) {
|
||
console.error('Failed to save display settings:', error);
|
||
setDisplaySettingsError('保存展示设置失败');
|
||
} finally {
|
||
setDisplaySettingsSaving(false);
|
||
}
|
||
}, [allowNonAdopterView, heatDisplayMode]);
|
||
|
||
// 组件挂载时加载展示设置
|
||
useEffect(() => {
|
||
loadDisplaySettings();
|
||
}, [loadDisplaySettings]);
|
||
|
||
// 切换货币选择
|
||
const toggleCurrency = (currency: string) => {
|
||
if (settlementCurrencies.includes(currency)) {
|
||
setSettlementCurrencies(settlementCurrencies.filter(c => c !== currency));
|
||
} else {
|
||
setSettlementCurrencies([...settlementCurrencies, currency]);
|
||
}
|
||
};
|
||
|
||
// Toggle 组件
|
||
const Toggle = ({ checked, onChange, size = 'normal' }: { checked: boolean; onChange: (v: boolean) => void; size?: 'normal' | 'small' }) => {
|
||
if (size === 'small') {
|
||
return (
|
||
<div
|
||
className={cn(styles.settings__toggleSmall, checked ? styles['settings__toggleSmall--on'] : styles['settings__toggleSmall--off'])}
|
||
onClick={() => onChange(!checked)}
|
||
>
|
||
<div className={cn(styles.settings__toggleSmallHandle, checked ? styles['settings__toggleSmallHandle--on'] : styles['settings__toggleSmallHandle--off'])} />
|
||
</div>
|
||
);
|
||
}
|
||
return (
|
||
<div
|
||
className={cn(styles.settings__toggle, checked ? styles['settings__toggle--on'] : styles['settings__toggle--off'])}
|
||
onClick={() => onChange(!checked)}
|
||
>
|
||
<div className={cn(styles.settings__toggleHandle, checked ? styles['settings__toggleHandle--on'] : styles['settings__toggleHandle--off'])} />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
return (
|
||
<PageContainer title="系统设置">
|
||
<div className={styles.settings}>
|
||
{/* 页面头部 */}
|
||
<header className={styles.settings__header}>
|
||
<h1 className={styles.settings__title}>系统设置</h1>
|
||
<p className={styles.settings__desc}>配置结算参数、龙虎榜规则、认种限额、考核规则及后台安全策略</p>
|
||
<div className={styles.settings__notice}>
|
||
所有设置修改后请点击下方"保存设置"按钮生效
|
||
</div>
|
||
</header>
|
||
|
||
{/* 结算参数设置 */}
|
||
<section className={styles.settings__section}>
|
||
<div className={styles.settings__sectionHeader}>
|
||
<h2 className={styles.settings__sectionTitle}>结算参数设置</h2>
|
||
<button className={styles.settings__resetBtn}>恢复默认</button>
|
||
</div>
|
||
<div className={styles.settings__content}>
|
||
<div className={styles.settings__fieldGroup}>
|
||
<label className={styles.settings__label}>可用结算币种</label>
|
||
<div className={styles.settings__checkboxGroup}>
|
||
{['BNB', 'OG', '积分', 'DST'].map(currency => (
|
||
<label key={currency} className={styles.settings__checkboxItem}>
|
||
<input
|
||
type="checkbox"
|
||
className={styles.settings__checkbox}
|
||
checked={settlementCurrencies.includes(currency)}
|
||
onChange={() => toggleCurrency(currency)}
|
||
/>
|
||
<span className={styles.settings__checkboxLabel}>{currency}</span>
|
||
</label>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<div className={styles.settings__selectWrapper}>
|
||
<label className={styles.settings__label}>默认结算币种</label>
|
||
<select
|
||
className={styles.settings__select}
|
||
value={defaultCurrency}
|
||
onChange={(e) => setDefaultCurrency(e.target.value)}
|
||
>
|
||
<option value="">请选择默认结算币种</option>
|
||
{settlementCurrencies.map(currency => (
|
||
<option key={currency} value={currency}>{currency}</option>
|
||
))}
|
||
</select>
|
||
<span className={styles.settings__hint}>提示:默认结算币种将用于用户点击"一键结算"时的自动兑换。</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* 龙虎榜设置 */}
|
||
<section className={styles.settings__section}>
|
||
<div className={styles.settings__sectionHeader}>
|
||
<h2 className={styles.settings__sectionTitle}>龙虎榜设置</h2>
|
||
<button className={styles.settings__resetBtn}>恢复默认</button>
|
||
</div>
|
||
<div className={styles.settings__content}>
|
||
<div className={styles.settings__toggleRow}>
|
||
<span className={styles.settings__toggleLabel}>启用虚拟账户参与排名</span>
|
||
<Toggle checked={enableVirtualAccount} onChange={setEnableVirtualAccount} />
|
||
</div>
|
||
<div className={styles.settings__inputRow}>
|
||
<span className={styles.settings__toggleLabel}>虚拟账户数量</span>
|
||
<input
|
||
type="text"
|
||
className={cn(styles.settings__input, styles['settings__input--medium'])}
|
||
placeholder="请输入数量"
|
||
value={virtualAccountCount}
|
||
onChange={(e) => setVirtualAccountCount(e.target.value)}
|
||
/>
|
||
<span className={styles.settings__inputUnit}>个</span>
|
||
</div>
|
||
<div className={styles.settings__fieldGroup}>
|
||
<label className={styles.settings__label}>榜单开关</label>
|
||
<div className={styles.settings__switchGroup}>
|
||
<div className={styles.settings__switchItem}>
|
||
<span className={styles.settings__switchLabel}>日榜开关</span>
|
||
<Toggle checked={dailyRankEnabled} onChange={setDailyRankEnabled} size="small" />
|
||
</div>
|
||
<div className={styles.settings__switchItem}>
|
||
<span className={styles.settings__switchLabel}>周榜开关</span>
|
||
<Toggle checked={weeklyRankEnabled} onChange={setWeeklyRankEnabled} size="small" />
|
||
</div>
|
||
<div className={styles.settings__switchItem}>
|
||
<span className={styles.settings__switchLabel}>月榜开关</span>
|
||
<Toggle checked={monthlyRankEnabled} onChange={setMonthlyRankEnabled} size="small" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className={styles.settings__fieldGroup}>
|
||
<label className={styles.settings__label}>前端显示名次数量</label>
|
||
<input
|
||
type="text"
|
||
className={cn(styles.settings__input, styles['settings__input--medium'])}
|
||
placeholder="例如:10、20、31"
|
||
value={displayCount}
|
||
onChange={(e) => setDisplayCount(e.target.value)}
|
||
/>
|
||
<span className={styles.settings__hint}>仅显示前 N 名的排行榜数据</span>
|
||
</div>
|
||
<div className={styles.settings__hint}>
|
||
提示:虚拟账户仅用于展示效果,不影响真实收益结算。
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* 认种限额设置 */}
|
||
<section className={styles.settings__section}>
|
||
<div className={styles.settings__sectionHeader}>
|
||
<h2 className={styles.settings__sectionTitle}>认种限额设置</h2>
|
||
<button className={styles.settings__resetBtn}>恢复默认</button>
|
||
</div>
|
||
<div className={styles.settings__content}>
|
||
{/* 单账户认种限额 */}
|
||
<div className={styles.settings__quotaCard}>
|
||
<div className={styles.settings__quotaHeader}>
|
||
<span className={styles.settings__quotaTitle}>单账户认种限额</span>
|
||
<Toggle checked={singleAccountLimitEnabled} onChange={setSingleAccountLimitEnabled} />
|
||
</div>
|
||
<div className={styles.settings__quotaInputRow}>
|
||
<span className={styles.settings__quotaText}>在</span>
|
||
<input
|
||
type="text"
|
||
className={cn(styles.settings__input, styles['settings__input--small'])}
|
||
placeholder="天数"
|
||
value={singleAccountDays}
|
||
onChange={(e) => setSingleAccountDays(e.target.value)}
|
||
/>
|
||
<span className={styles.settings__quotaText}>天内,每个账户最多认种</span>
|
||
<input
|
||
type="text"
|
||
className={cn(styles.settings__input, styles['settings__input--small'])}
|
||
placeholder="棵数"
|
||
value={singleAccountTrees}
|
||
onChange={(e) => setSingleAccountTrees(e.target.value)}
|
||
/>
|
||
<span className={styles.settings__quotaText}>棵</span>
|
||
</div>
|
||
<span className={styles.settings__hint}>示例:5 天内最多认种 1 棵</span>
|
||
</div>
|
||
|
||
{/* 全网总量限额 */}
|
||
<div className={styles.settings__quotaCard}>
|
||
<div className={styles.settings__quotaHeader}>
|
||
<span className={styles.settings__quotaTitle}>全网总量限额</span>
|
||
<Toggle checked={networkLimitEnabled} onChange={setNetworkLimitEnabled} />
|
||
</div>
|
||
<div className={styles.settings__quotaInputRow}>
|
||
<span className={styles.settings__quotaText}>在</span>
|
||
<input
|
||
type="text"
|
||
className={cn(styles.settings__input, styles['settings__input--small'])}
|
||
placeholder="天数"
|
||
value={networkDays}
|
||
onChange={(e) => setNetworkDays(e.target.value)}
|
||
/>
|
||
<span className={styles.settings__quotaText}>天内,全网总认种上限</span>
|
||
<input
|
||
type="text"
|
||
className={cn(styles.settings__input, styles['settings__input--small'])}
|
||
placeholder="棵数"
|
||
value={networkTrees}
|
||
onChange={(e) => setNetworkTrees(e.target.value)}
|
||
/>
|
||
<span className={styles.settings__quotaText}>棵</span>
|
||
</div>
|
||
<span className={styles.settings__hint}>示例:2 天内总量 100 棵</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* 考核规则设置 */}
|
||
<section className={styles.settings__section}>
|
||
<div className={styles.settings__sectionHeader}>
|
||
<h2 className={styles.settings__sectionTitle}>考核规则设置</h2>
|
||
<button className={styles.settings__resetBtn}>恢复默认</button>
|
||
</div>
|
||
<div className={styles.settings__content}>
|
||
{/* 本地用户占比阈值 */}
|
||
<div className={styles.settings__assessmentRow}>
|
||
<label className={styles.settings__assessmentLabel}>省/市本地用户占比阈值</label>
|
||
<div className={styles.settings__assessmentInputRow}>
|
||
<input
|
||
type="text"
|
||
className={cn(styles.settings__input, styles['settings__input--small'])}
|
||
value={localUserThreshold}
|
||
onChange={(e) => setLocalUserThreshold(e.target.value)}
|
||
/>
|
||
<span className={styles.settings__assessmentUnit}>%</span>
|
||
</div>
|
||
<span className={styles.settings__hint}>当团队中本省/市用户占比低于此值时,将触发相应考核机制。</span>
|
||
</div>
|
||
|
||
{/* 豁免设置 */}
|
||
<div className={styles.settings__exemptionRow}>
|
||
<div className={styles.settings__exemptionInfo}>
|
||
<span className={styles.settings__exemptionLabel}>允许为单个账号设置"不考核自有团队本省/市占比"豁免</span>
|
||
<span className={styles.settings__exemptionHint}>开启后,可在用户管理页面为特定账号设置豁免权。</span>
|
||
</div>
|
||
<Toggle checked={exemptionEnabled} onChange={setExemptionEnabled} />
|
||
</div>
|
||
|
||
{/* 阶梯性考核目标表 */}
|
||
<div className={styles.settings__tableSection}>
|
||
<div className={styles.settings__tableHeader}>
|
||
<h3 className={styles.settings__tableTitle}>省代 / 市代阶梯性考核目标表</h3>
|
||
<div className={styles.settings__tableBtns}>
|
||
<button className={styles.settings__tableBtn}>新增行</button>
|
||
<button className={styles.settings__tableBtn}>导出表格</button>
|
||
</div>
|
||
</div>
|
||
<div className={styles.settings__table}>
|
||
<div className={styles.settings__tableHead}>
|
||
<div className={cn(styles.settings__tableHeadCell, styles['settings__tableHeadCell--month'])}>考核月</div>
|
||
<div className={cn(styles.settings__tableHeadCell, styles['settings__tableHeadCell--target'])}>省代当月目标</div>
|
||
<div className={cn(styles.settings__tableHeadCell, styles['settings__tableHeadCell--target'])}>省代累计目标</div>
|
||
<div className={cn(styles.settings__tableHeadCell, styles['settings__tableHeadCell--target'])}>市代当月目标</div>
|
||
<div className={cn(styles.settings__tableHeadCell, styles['settings__tableHeadCell--target'])}>市代累计目标</div>
|
||
</div>
|
||
<div className={styles.settings__tableBody}>
|
||
{mockTargets.map((target) => (
|
||
<div key={target.month} className={styles.settings__tableRow}>
|
||
<div className={cn(styles.settings__tableCell, styles['settings__tableCell--month'])}>第{target.month}个月</div>
|
||
<div className={cn(styles.settings__tableCell, styles['settings__tableCell--target'])}>{target.provinceMonthly}</div>
|
||
<div className={cn(styles.settings__tableCell, styles['settings__tableCell--target'])}>{target.provinceCumulative}</div>
|
||
<div className={cn(styles.settings__tableCell, styles['settings__tableCell--target'])}>{target.cityMonthly}</div>
|
||
<div className={cn(styles.settings__tableCell, styles['settings__tableCell--target'])}>{target.cityCumulative}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<span className={styles.settings__hint}>此表格用于设定不同代理级别的月度和累计业绩目标。</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* 前端展示设置 */}
|
||
<section className={styles.settings__section}>
|
||
<div className={styles.settings__sectionHeader}>
|
||
<h2 className={styles.settings__sectionTitle}>前端展示设置</h2>
|
||
<div className={styles.settings__sectionActions}>
|
||
<button
|
||
className={styles.settings__resetBtn}
|
||
onClick={loadDisplaySettings}
|
||
disabled={displaySettingsLoading}
|
||
>
|
||
{displaySettingsLoading ? '加载中...' : '刷新'}
|
||
</button>
|
||
<button
|
||
className={styles.settings__saveBtn}
|
||
onClick={saveDisplaySettings}
|
||
disabled={displaySettingsSaving || displaySettingsLoading}
|
||
>
|
||
{displaySettingsSaving ? '保存中...' : '保存展示设置'}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
{displaySettingsError && (
|
||
<div className={styles.settings__error}>{displaySettingsError}</div>
|
||
)}
|
||
<div className={styles.settings__content}>
|
||
<div className={styles.settings__toggleRow}>
|
||
<span className={styles.settings__toggleLabel}>允许未认种用户查看各省认种热度</span>
|
||
<Toggle checked={allowNonAdopterView} onChange={setAllowNonAdopterView} />
|
||
</div>
|
||
<div className={styles.settings__fieldGroup}>
|
||
<label className={styles.settings__label}>热度展示方式</label>
|
||
<div className={styles.settings__radioGroup}>
|
||
<label className={styles.settings__radioItem}>
|
||
<input
|
||
type="radio"
|
||
className={styles.settings__radio}
|
||
name="heatDisplayMode"
|
||
checked={heatDisplayMode === 'count'}
|
||
onChange={() => setHeatDisplayMode('count')}
|
||
/>
|
||
<span className={styles.settings__radioLabel}>显示具体认种数量</span>
|
||
</label>
|
||
<label className={styles.settings__radioItem}>
|
||
<input
|
||
type="radio"
|
||
className={styles.settings__radio}
|
||
name="heatDisplayMode"
|
||
checked={heatDisplayMode === 'level'}
|
||
onChange={() => setHeatDisplayMode('level')}
|
||
/>
|
||
<span className={styles.settings__radioLabel}>仅显示热度等级(高 / 中 / 低)</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<span className={styles.settings__hint}>提示:仅影响前端展示,不影响任何收益计算及排名。</span>
|
||
</div>
|
||
</section>
|
||
|
||
{/* 后台账号与安全 */}
|
||
<section className={styles.settings__section}>
|
||
<div className={styles.settings__sectionHeader}>
|
||
<h2 className={styles.settings__sectionTitle}>后台账号与安全</h2>
|
||
<button className={styles.settings__resetBtn}>恢复默认</button>
|
||
</div>
|
||
<div className={styles.settings__securityContent}>
|
||
{/* 左侧:账号管理 */}
|
||
<div className={styles.settings__securityLeft}>
|
||
<div className={styles.settings__accountHeader}>
|
||
<h3 className={styles.settings__accountTitle}>后台账号与角色</h3>
|
||
<button className={styles.settings__addBtn}>新增后台账号</button>
|
||
</div>
|
||
<div className={styles.settings__accountTable}>
|
||
<div className={styles.settings__accountTableInner}>
|
||
<div className={styles.settings__accountHead}>
|
||
<div className={cn(styles.settings__accountHeadCell, styles['settings__accountHeadCell--name'])}>账号名</div>
|
||
<div className={cn(styles.settings__accountHeadCell, styles['settings__accountHeadCell--role'])}>角色</div>
|
||
<div className={cn(styles.settings__accountHeadCell, styles['settings__accountHeadCell--status'])}>状态</div>
|
||
<div className={cn(styles.settings__accountHeadCell, styles['settings__accountHeadCell--login'])}>最近登录</div>
|
||
<div className={cn(styles.settings__accountHeadCell, styles['settings__accountHeadCell--actions'])}>操作</div>
|
||
</div>
|
||
<div className={styles.settings__accountBody}>
|
||
{mockAccounts.map((account) => (
|
||
<div key={account.id} className={styles.settings__accountRow}>
|
||
<div className={cn(styles.settings__accountCell, styles['settings__accountCell--name'])}>{account.name}</div>
|
||
<div className={cn(styles.settings__accountCell, styles['settings__accountCell--role'])}>{account.role}</div>
|
||
<div className={cn(styles.settings__accountCell, styles['settings__accountCell--status'])}>
|
||
<span className={cn(styles.settings__statusBadge, account.status === 'disabled' && styles['settings__statusBadge--disabled'])}>
|
||
{account.status === 'active' ? '正常' : '禁用'}
|
||
</span>
|
||
</div>
|
||
<div className={cn(styles.settings__accountCell, styles['settings__accountCell--login'])}>{account.lastLogin}</div>
|
||
<div className={cn(styles.settings__accountCell, styles['settings__accountCell--actions'])}>
|
||
<button className={styles.settings__actionLink}>编辑</button>
|
||
<button className={cn(styles.settings__actionLink, styles['settings__actionLink--danger'])}>禁用</button>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<span className={styles.settings__hint}>管理后台操作员账号及其权限角色。</span>
|
||
</div>
|
||
|
||
{/* 右侧:敏感操作和日志 */}
|
||
<div className={styles.settings__securityRight}>
|
||
{/* 敏感操作审批 */}
|
||
<div className={styles.settings__sensitiveCard}>
|
||
<div className={styles.settings__sensitiveRow}>
|
||
<span className={styles.settings__sensitiveLabel}>敏感操作审批人数</span>
|
||
<input
|
||
type="text"
|
||
className={cn(styles.settings__input, styles['settings__input--small'])}
|
||
value={approvalCount}
|
||
onChange={(e) => setApprovalCount(e.target.value)}
|
||
/>
|
||
<span className={styles.settings__inputUnit}>人</span>
|
||
</div>
|
||
<div className={styles.settings__sensitiveFieldGroup}>
|
||
<label className={styles.settings__label}>需要审批的敏感操作</label>
|
||
<input
|
||
type="text"
|
||
className={styles.settings__tagInput}
|
||
placeholder="选择或输入操作名称"
|
||
/>
|
||
<div className={styles.settings__tagList}>
|
||
{sensitiveOperations.map((op, index) => (
|
||
<span key={index} className={styles.settings__tag}>
|
||
{op}
|
||
<button
|
||
className={styles.settings__tagRemove}
|
||
onClick={() => setSensitiveOperations(sensitiveOperations.filter((_, i) => i !== index))}
|
||
>
|
||
×
|
||
</button>
|
||
</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 操作日志 */}
|
||
<div className={styles.settings__logSection}>
|
||
<h3 className={styles.settings__logTitle}>操作日志</h3>
|
||
<div className={styles.settings__logFilters}>
|
||
<input
|
||
type="date"
|
||
className={styles.settings__dateInput}
|
||
value={logDate}
|
||
onChange={(e) => setLogDate(e.target.value)}
|
||
/>
|
||
<input
|
||
type="text"
|
||
className={styles.settings__searchInput}
|
||
placeholder="操作账号/关键字搜索"
|
||
value={logSearch}
|
||
onChange={(e) => setLogSearch(e.target.value)}
|
||
/>
|
||
<button className={styles.settings__exportBtn}>导出日志</button>
|
||
</div>
|
||
<div className={styles.settings__logTable}>
|
||
<div className={styles.settings__logTableInner}>
|
||
<div className={styles.settings__logHead}>
|
||
<div className={cn(styles.settings__logHeadCell, styles['settings__logHeadCell--time'])}>时间</div>
|
||
<div className={cn(styles.settings__logHeadCell, styles['settings__logHeadCell--account'])}>操作账号</div>
|
||
<div className={cn(styles.settings__logHeadCell, styles['settings__logHeadCell--type'])}>类型</div>
|
||
<div className={cn(styles.settings__logHeadCell, styles['settings__logHeadCell--desc'])}>描述</div>
|
||
<div className={cn(styles.settings__logHeadCell, styles['settings__logHeadCell--result'])}>审批结果</div>
|
||
</div>
|
||
<div className={styles.settings__logBody}>
|
||
{mockLogs.map((log) => (
|
||
<div key={log.id} className={styles.settings__logRow}>
|
||
<div className={cn(styles.settings__logCell, styles['settings__logCell--time'])}>{log.time}</div>
|
||
<div className={cn(styles.settings__logCell, styles['settings__logCell--account'])}>{log.account}</div>
|
||
<div className={cn(styles.settings__logCell, styles['settings__logCell--type'])}>{log.type}</div>
|
||
<div className={cn(styles.settings__logCell, styles['settings__logCell--desc'])}>{log.description}</div>
|
||
<div className={cn(styles.settings__logCell, styles['settings__logCell--result'])}>
|
||
<span className={cn(
|
||
styles.settings__logResult,
|
||
log.result === 'pass' && styles['settings__logResult--pass'],
|
||
log.result === 'reject' && styles['settings__logResult--reject'],
|
||
log.result === 'pending' && styles['settings__logResult--pending']
|
||
)}>
|
||
{log.result === 'pass' ? '通过' : log.result === 'reject' ? '拒绝' : '待审'}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* 页面底部操作按钮 */}
|
||
<footer className={styles.settings__footer}>
|
||
<button className={styles.settings__cancelBtn}>取消修改</button>
|
||
<button className={styles.settings__saveBtn}>保存设置</button>
|
||
</footer>
|
||
</div>
|
||
</PageContainer>
|
||
);
|
||
}
|