fix:提交修复6个问题
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import PageHeader from '@dukang/shared-ui/PageHeader';
|
||||
import {
|
||||
AccountStatus,
|
||||
PARTNER_STAFF_ROLE_LABELS,
|
||||
PartnerStaffRole,
|
||||
type PartnerStaffItem,
|
||||
} from '@dukang/shared-types';
|
||||
import { deletePartnerStaff, listPartnerStaff, updatePartnerStaff } from '../lib/staff';
|
||||
|
||||
export default function StaffListPage() {
|
||||
const navigate = useNavigate();
|
||||
const [staff, setStaff] = useState<PartnerStaffItem[]>([]);
|
||||
const [q, setQ] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const [busyId, setBusyId] = useState<string | null>(null);
|
||||
|
||||
const loadStaff = useCallback(() => {
|
||||
return listPartnerStaff().then(setStaff).catch((e) => {
|
||||
setError(e instanceof Error ? e.message : '加载失败');
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
void loadStaff();
|
||||
}, [loadStaff]);
|
||||
|
||||
const filtered = useMemo(() => staff.filter((item) => {
|
||||
if (!q.trim()) return true;
|
||||
const keyword = q.trim();
|
||||
return item.name.includes(keyword) || item.phone.includes(keyword);
|
||||
}), [staff, q]);
|
||||
|
||||
async function toggleStatus(item: PartnerStaffItem) {
|
||||
const next = item.status === AccountStatus.ACTIVE ? AccountStatus.DISABLED : AccountStatus.ACTIVE;
|
||||
setBusyId(item.id);
|
||||
setError('');
|
||||
try {
|
||||
await updatePartnerStaff(item.id, { status: next });
|
||||
await loadStaff();
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : '操作失败');
|
||||
} finally {
|
||||
setBusyId(null);
|
||||
}
|
||||
}
|
||||
|
||||
async function removeStaff(item: PartnerStaffItem) {
|
||||
const ok = window.confirm(`确认删除子账号「${item.name}」?`);
|
||||
if (!ok) return;
|
||||
setBusyId(item.id);
|
||||
setError('');
|
||||
try {
|
||||
await deletePartnerStaff(item.id);
|
||||
await loadStaff();
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : '删除失败');
|
||||
} finally {
|
||||
setBusyId(null);
|
||||
}
|
||||
}
|
||||
|
||||
async function editStaff(item: PartnerStaffItem) {
|
||||
const name = window.prompt('修改姓名', item.name);
|
||||
if (name == null || !name.trim()) return;
|
||||
const roleOptions = Object.values(PartnerStaffRole);
|
||||
const roleLabels = roleOptions.map((r) => PARTNER_STAFF_ROLE_LABELS[r]).join(' / ');
|
||||
const roleInput = window.prompt(`分配角色(${roleLabels})`, item.staffRole);
|
||||
if (roleInput == null) return;
|
||||
const staffRole = roleOptions.find((r) => r === roleInput || PARTNER_STAFF_ROLE_LABELS[r] === roleInput);
|
||||
if (!staffRole) {
|
||||
setError('无效的角色');
|
||||
return;
|
||||
}
|
||||
setBusyId(item.id);
|
||||
setError('');
|
||||
try {
|
||||
await updatePartnerStaff(item.id, { name: name.trim(), staffRole });
|
||||
await loadStaff();
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : '编辑失败');
|
||||
} finally {
|
||||
setBusyId(null);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="page-no-tab partner-staff-page">
|
||||
<PageHeader title="子账号管理" onBack={() => navigate('/center')} />
|
||||
|
||||
<div style={{ padding: '0 20px 16px' }}>
|
||||
<div className="partner-search">
|
||||
<span className="material-symbols-outlined">search</span>
|
||||
<input placeholder="搜索姓名或手机号" value={q} onChange={(e) => setQ(e.target.value)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error && <p className="partner-form-error" role="alert" style={{ margin: '0 20px 12px' }}>{error}</p>}
|
||||
|
||||
<div style={{ padding: '0 20px 100px' }}>
|
||||
{filtered.length === 0 && (
|
||||
<div className="empty">
|
||||
<p>暂无子账号</p>
|
||||
<p className="label-md text-muted">点击下方按钮添加首个子账号</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{filtered.map((item) => {
|
||||
const active = item.status === AccountStatus.ACTIVE;
|
||||
const busy = busyId === item.id;
|
||||
return (
|
||||
<div key={item.id} className="partner-staff-card">
|
||||
<div className="partner-staff-avatar">{item.name.slice(0, 1)}</div>
|
||||
<div className="partner-staff-info">
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
|
||||
<span className="headline-md">{item.name}</span>
|
||||
<span className="partner-role-badge partner-role-badge--subtle">
|
||||
{PARTNER_STAFF_ROLE_LABELS[item.staffRole]}
|
||||
</span>
|
||||
</div>
|
||||
<p className="label-md text-muted">{item.phone}</p>
|
||||
</div>
|
||||
<div className="partner-staff-actions">
|
||||
<button
|
||||
type="button"
|
||||
className={`partner-toggle${active ? ' partner-toggle--on' : ''}`}
|
||||
disabled={busy}
|
||||
aria-label={active ? '禁用' : '启用'}
|
||||
onClick={() => void toggleStatus(item)}
|
||||
>
|
||||
<span className="partner-toggle-thumb" />
|
||||
</button>
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
<button type="button" className="partner-icon-btn" disabled={busy} onClick={() => void editStaff(item)}>
|
||||
<span className="material-symbols-outlined">edit</span>
|
||||
</button>
|
||||
<button type="button" className="partner-icon-btn partner-icon-btn--danger" disabled={busy} onClick={() => void removeStaff(item)}>
|
||||
<span className="material-symbols-outlined">delete</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="partner-sticky-footer">
|
||||
<Link to="/center/staff/new" className="partner-btn-primary" style={{ display: 'flex', textDecoration: 'none' }}>
|
||||
<span className="material-symbols-outlined">person_add</span>
|
||||
添加子账号
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user