rwadurian/frontend/admin-web/src/app/(dashboard)/authorization/page.tsx

448 lines
25 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { useState } from 'react';
import { PageContainer } from '@/components/layout';
import { cn } from '@/utils/helpers';
import styles from './authorization.module.scss';
/**
* 省/市公司数据接口
*/
interface CompanyItem {
id: string;
avatar: string;
nickname: string;
accountId: string;
province: string;
city?: string;
teamAdoptions: number;
authStatus: 'authorized' | 'pending';
}
/**
* 阶梯性考核目标数据接口
*/
interface TargetItem {
month: string;
provinceMonthly: number;
provinceTotal: number;
cityMonthly: number;
cityTotal: number;
}
/**
* 特殊城市规则接口
*/
interface SpecialCityRule {
city: string;
enabled: boolean;
}
// 模拟省公司数据
const mockProvinceCompanies: CompanyItem[] = [
{ id: '1', avatar: '', nickname: '用户昵称一', accountId: '123456789', province: '广东省', teamAdoptions: 1234, authStatus: 'authorized' },
];
// 模拟市公司数据
const mockCityCompanies: CompanyItem[] = [
{ id: '1', avatar: '', nickname: '用户昵称二', accountId: '987654321', province: '广东省', city: '深圳市', teamAdoptions: 567, authStatus: 'pending' },
];
// 阶梯性考核目标数据
const targetData: TargetItem[] = [
{ month: '第 1 个月', provinceMonthly: 500, provinceTotal: 500, cityMonthly: 100, cityTotal: 100 },
{ month: '第 2 个月', provinceMonthly: 500, provinceTotal: 1000, cityMonthly: 100, cityTotal: 200 },
{ month: '...', provinceMonthly: 0, provinceTotal: 0, cityMonthly: 0, cityTotal: 0 },
{ month: '第 9 个月', provinceMonthly: 1000, provinceTotal: 6000, cityMonthly: 200, cityTotal: 1200 },
];
// 特殊城市规则
const specialCities: SpecialCityRule[] = [
{ city: '北京市', enabled: false },
{ city: '上海市', enabled: true },
];
/**
* 授权管理页面
* 基于 UIPro Figma 设计实现
*/
export default function AuthorizationPage() {
// 省公司规则状态
const [provinceThreshold, setProvinceThreshold] = useState('500');
const [provinceBenefit, setProvinceBenefit] = useState('20');
const [provinceAfterBenefit, setProvinceAfterBenefit] = useState('20');
const [provinceResetEnabled, setProvinceResetEnabled] = useState(true);
// 市公司规则状态
const [cityThreshold, setCityThreshold] = useState('100');
const [cityBenefit, setCityBenefit] = useState('40');
const [cityAfterBenefit, setCityAfterBenefit] = useState('40');
const [cityResetEnabled, setCityResetEnabled] = useState(true);
// 授权限制规则
const [topRankLimit, setTopRankLimit] = useState('10');
const [specialRules, setSpecialRules] = useState(specialCities);
// 渲染开关组件
const renderToggle = (checked: boolean, onChange: (checked: boolean) => void) => (
<div
className={cn(styles.authorization__toggle, checked ? styles['authorization__toggle--on'] : styles['authorization__toggle--off'])}
onClick={() => onChange(!checked)}
role="switch"
aria-checked={checked}
tabIndex={0}
onKeyDown={(e) => e.key === 'Enter' && onChange(!checked)}
>
<div className={cn(styles.authorization__toggleHandle, checked ? styles['authorization__toggleHandle--on'] : styles['authorization__toggleHandle--off'])} />
</div>
);
// 渲染省公司表格
const renderProvinceTable = () => (
<div className={styles.authorization__table}>
<div className={styles.authorization__tableHeader}>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--avatar'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--nickname'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--accountId'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--province'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--teamAdoptions'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--status'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--actions'])}></div>
</div>
{mockProvinceCompanies.map((item) => (
<div key={item.id} className={styles.authorization__tableRow}>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--avatar'])}>
<div
className={styles.authorization__avatar}
style={item.avatar ? { backgroundImage: `url(${item.avatar})` } : undefined}
/>
</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--nickname'])}>{item.nickname}</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--accountId'])}>{item.accountId}</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--province'])}>{item.province}</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--teamAdoptions'])}>{item.teamAdoptions.toLocaleString()}</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--status'])}>
<span className={cn(styles.authorization__badge, item.authStatus === 'authorized' ? styles['authorization__badge--authorized'] : styles['authorization__badge--pending'])}>
{item.authStatus === 'authorized' ? '已授权' : '待授权'}
</span>
</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--actions'])}>
<button className={cn(styles.authorization__actionBtn, styles['authorization__actionBtn--authorize'])}></button>
<button className={cn(styles.authorization__actionBtn, styles['authorization__actionBtn--revoke'])}></button>
</div>
</div>
))}
</div>
);
// 渲染市公司表格
const renderCityTable = () => (
<div className={styles.authorization__table}>
<div className={styles.authorization__tableHeader}>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--avatar'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--nickname'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--accountId'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--city'])}>/</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--teamAdoptions'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--status'])}></div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--header'], styles['authorization__tableCell--actions'])}></div>
</div>
{mockCityCompanies.map((item) => (
<div key={item.id} className={styles.authorization__tableRow}>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--avatar'])}>
<div
className={styles.authorization__avatar}
style={item.avatar ? { backgroundImage: `url(${item.avatar})` } : undefined}
/>
</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--nickname'])}>{item.nickname}</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--accountId'])}>{item.accountId}</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--city'])}>{item.province} / {item.city}</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--teamAdoptions'])}>{item.teamAdoptions}</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--status'])}>
<span className={cn(styles.authorization__badge, item.authStatus === 'authorized' ? styles['authorization__badge--authorized'] : styles['authorization__badge--pending'])}>
{item.authStatus === 'authorized' ? '已授权' : '待授权'}
</span>
</div>
<div className={cn(styles.authorization__tableCell, styles['authorization__tableCell--actions'])}>
<button className={cn(styles.authorization__actionBtn, styles['authorization__actionBtn--authorize'])}></button>
<button className={cn(styles.authorization__actionBtn, styles['authorization__actionBtn--revoke'])}></button>
</div>
</div>
))}
</div>
);
return (
<PageContainer title="授权管理">
<div className={styles.authorization}>
{/* 授权省公司管理 */}
<section className={styles.authorization__card}>
<h3 className={styles.authorization__cardTitle}></h3>
<div className={styles.authorization__filters}>
<select className={styles.authorization__select} aria-label="选择省份">
<option value=""></option>
<option value="guangdong">广</option>
<option value="zhejiang"></option>
<option value="jiangsu"></option>
</select>
<select className={styles.authorization__select} aria-label="授权状态">
<option value=""></option>
<option value="authorized"></option>
<option value="pending"></option>
</select>
<input className={styles.authorization__input} placeholder="关键词搜索" type="text" aria-label="关键词搜索" />
<button className={styles.authorization__searchBtn}></button>
</div>
{renderProvinceTable()}
<p className={styles.authorization__help}></p>
</section>
{/* 授权省公司团队权益考核规则 */}
<section className={styles.authorization__card}>
<h3 className={styles.authorization__cardTitle}></h3>
<div className={styles.authorization__form}>
<div className={styles.authorization__formRow}>
<div className={styles.authorization__formGroup}>
<label className={styles.authorization__formLabel}></label>
<input
className={styles.authorization__formInput}
type="text"
value={provinceThreshold}
onChange={(e) => setProvinceThreshold(e.target.value)}
placeholder="500"
/>
</div>
<div className={styles.authorization__formGroup}>
<label className={styles.authorization__formLabel}></label>
<input
className={styles.authorization__formInput}
type="text"
value={provinceBenefit}
onChange={(e) => setProvinceBenefit(e.target.value)}
placeholder="20"
/>
<span className={styles.authorization__formHint}> {provinceThreshold} 1 </span>
</div>
</div>
<div className={styles.authorization__formRow}>
<div className={styles.authorization__formGroup}>
<label className={styles.authorization__formLabel}> 1 </label>
<input
className={styles.authorization__formInput}
type="text"
value={provinceAfterBenefit}
onChange={(e) => setProvinceAfterBenefit(e.target.value)}
placeholder="20"
/>
</div>
<div className={styles.authorization__formGroup}>
<label className={styles.authorization__formLabel}></label>
<select className={styles.authorization__select} style={{ width: '100%' }} aria-label="考核周期">
<option value="monthly"></option>
<option value="quarterly"></option>
</select>
</div>
</div>
</div>
<div className={styles.authorization__toggleRow}>
<span className={styles.authorization__toggleLabel}> 0 {provinceThreshold} </span>
{renderToggle(provinceResetEnabled, setProvinceResetEnabled)}
</div>
<div className={styles.authorization__saveWrapper}>
<button className={styles.authorization__saveBtn}></button>
</div>
</section>
{/* 授权市公司管理 */}
<section className={styles.authorization__card}>
<h3 className={styles.authorization__cardTitle}></h3>
<div className={styles.authorization__filters}>
<select className={styles.authorization__select} aria-label="选择省份">
<option value=""></option>
<option value="guangdong">广</option>
<option value="zhejiang"></option>
</select>
<select className={styles.authorization__select} aria-label="选择城市">
<option value=""></option>
<option value="shenzhen"></option>
<option value="guangzhou">广</option>
</select>
<select className={styles.authorization__select} aria-label="授权状态">
<option value=""></option>
<option value="authorized"></option>
<option value="pending"></option>
</select>
<input className={styles.authorization__input} placeholder="关键词搜索" type="text" aria-label="关键词搜索" />
<button className={styles.authorization__searchBtn}></button>
</div>
{renderCityTable()}
<p className={styles.authorization__help}></p>
</section>
{/* 授权市公司团队权益考核规则 */}
<section className={styles.authorization__card}>
<h3 className={styles.authorization__cardTitle}></h3>
<div className={styles.authorization__form}>
<div className={styles.authorization__formRow}>
<div className={styles.authorization__formGroup}>
<label className={styles.authorization__formLabel}></label>
<input
className={styles.authorization__formInput}
type="text"
value={cityThreshold}
onChange={(e) => setCityThreshold(e.target.value)}
placeholder="100"
/>
</div>
<div className={styles.authorization__formGroup}>
<label className={styles.authorization__formLabel}></label>
<input
className={styles.authorization__formInput}
type="text"
value={cityBenefit}
onChange={(e) => setCityBenefit(e.target.value)}
placeholder="40"
/>
<span className={styles.authorization__formHint}> {cityThreshold} 1 </span>
</div>
</div>
<div className={styles.authorization__formRow}>
<div className={styles.authorization__formGroup}>
<label className={styles.authorization__formLabel}> 1 </label>
<input
className={styles.authorization__formInput}
type="text"
value={cityAfterBenefit}
onChange={(e) => setCityAfterBenefit(e.target.value)}
placeholder="40"
/>
</div>
<div className={styles.authorization__formGroup}>
<label className={styles.authorization__formLabel}></label>
<select className={styles.authorization__select} style={{ width: '100%' }} aria-label="考核周期">
<option value="monthly"></option>
<option value="quarterly"></option>
</select>
</div>
</div>
</div>
<div className={styles.authorization__toggleRow}>
<span className={styles.authorization__toggleLabel}> 0 {cityThreshold} </span>
{renderToggle(cityResetEnabled, setCityResetEnabled)}
</div>
<div className={styles.authorization__saveWrapper}>
<button className={styles.authorization__saveBtn}></button>
</div>
</section>
{/* 正式省公司/市公司授权管理 */}
<div className={styles.authorization__officialSection}>
<section className={styles.authorization__officialCard}>
<h3 className={styles.authorization__officialTitle}></h3>
<p className={styles.authorization__officialDesc}></p>
<div className={styles.authorization__officialTable}>
<div className={styles.authorization__officialRow}>
<div className={styles.authorization__officialCell}></div>
<div className={styles.authorization__officialCell}></div>
<div className={styles.authorization__officialCell}></div>
<div className={styles.authorization__officialCell}></div>
<div className={styles.authorization__officialCell}></div>
<div className={styles.authorization__officialCell}></div>
</div>
</div>
</section>
<section className={styles.authorization__officialCard}>
<h3 className={styles.authorization__officialTitle}></h3>
<p className={styles.authorization__officialDesc}></p>
<div className={styles.authorization__officialTable}>
<div className={styles.authorization__officialRow}>
<div className={styles.authorization__officialCell}></div>
<div className={styles.authorization__officialCell}></div>
<div className={styles.authorization__officialCell}></div>
<div className={styles.authorization__officialCell}>/</div>
<div className={styles.authorization__officialCell}></div>
<div className={styles.authorization__officialCell}></div>
</div>
</div>
</section>
</div>
{/* 省公司 / 市公司 授权限制规则 */}
<section className={styles.authorization__card}>
<h3 className={styles.authorization__cardTitle}> / </h3>
<div className={styles.authorization__rules}>
<div className={styles.authorization__ruleItem}> 1 </div>
<div className={styles.authorization__ruleItem}>
<div className={styles.authorization__ruleInline}>
<span> 1 </span>
<span className={styles.authorization__ruleNote}>(广)</span>
</div>
</div>
<div className={styles.authorization__ruleItem}>
<div className={styles.authorization__ruleInline}>
<span></span>
<input
className={styles.authorization__ruleInput}
type="text"
value={topRankLimit}
onChange={(e) => setTopRankLimit(e.target.value)}
aria-label="排名限制"
/>
<span></span>
</div>
</div>
<div className={styles.authorization__specialRules}>
<div className={styles.authorization__specialTitle}> ()</div>
<div className={styles.authorization__specialTable}>
{specialRules.map((rule, index) => (
<div key={rule.city} className={styles.authorization__specialRow}>
<div className={styles.authorization__specialCity}>{rule.city}</div>
<div className={styles.authorization__specialToggle}>
{renderToggle(rule.enabled, (enabled) => {
const newRules = [...specialRules];
newRules[index] = { ...rule, enabled };
setSpecialRules(newRules);
})}
<span className={styles.authorization__specialLabel}></span>
</div>
</div>
))}
</div>
</div>
</div>
</section>
{/* 省公司 / 市公司 阶梯性考核目标 */}
<section className={styles.authorization__card}>
<div className={styles.authorization__targetHeader}>
<h3 className={styles.authorization__targetTitle}> / </h3>
<button className={styles.authorization__editBtn}></button>
</div>
<div className={styles.authorization__targetTable}>
<div className={styles.authorization__targetHeader2}>
<div className={cn(styles.authorization__targetCell, styles['authorization__targetCell--header'], styles['authorization__targetCell--month'])}></div>
<div className={cn(styles.authorization__targetCell, styles['authorization__targetCell--header'], styles['authorization__targetCell--provinceMonthly'])}></div>
<div className={cn(styles.authorization__targetCell, styles['authorization__targetCell--header'], styles['authorization__targetCell--provinceTotal'])}></div>
<div className={cn(styles.authorization__targetCell, styles['authorization__targetCell--header'], styles['authorization__targetCell--cityMonthly'])}></div>
<div className={cn(styles.authorization__targetCell, styles['authorization__targetCell--header'], styles['authorization__targetCell--cityTotal'])}></div>
</div>
<div className={styles.authorization__targetBody}>
{targetData.map((row, index) => (
<div key={row.month} className={cn(styles.authorization__targetRow, index < targetData.length - 1 && styles['authorization__targetRow--bordered'])}>
<div className={cn(styles.authorization__targetCell, styles['authorization__targetCell--month'])}>{row.month}</div>
<div className={cn(styles.authorization__targetCell, styles['authorization__targetCell--provinceMonthly'])}>{row.month === '...' ? '...' : row.provinceMonthly}</div>
<div className={cn(styles.authorization__targetCell, styles['authorization__targetCell--provinceTotal'])}>{row.month === '...' ? '...' : row.provinceTotal}</div>
<div className={cn(styles.authorization__targetCell, styles['authorization__targetCell--cityMonthly'])}>{row.month === '...' ? '...' : row.cityMonthly}</div>
<div className={cn(styles.authorization__targetCell, styles['authorization__targetCell--cityTotal'])}>{row.month === '...' ? '...' : row.cityTotal}</div>
</div>
))}
</div>
</div>
<p className={styles.authorization__help}> 9 /</p>
</section>
</div>
</PageContainer>
);
}