fix: complete first version issue remediation

This commit is contained in:
hectorzhao
2026-07-11 10:14:37 +08:00
parent 709ac97764
commit 208a6c23f8
73 changed files with 1549 additions and 245 deletions
+23 -10
View File
@@ -1,6 +1,7 @@
import { useEffect, useMemo, useState } from 'react';
import { Edit3, KeyRound, Plus, Search, Trash2, Users } from 'lucide-react';
import { clientApi, type ManagedUser, type UserPayload } from '@/api/adminApi';
import { formatDateTime } from '@/utils/dateTime';
import { readSession } from '@/api/session';
import { Button, Input, Modal, Select, Table, Tag, type TableColumn } from '@/components/ui';
@@ -50,6 +51,7 @@ export function ClientUsersPage() {
const [newPassword, setNewPassword] = useState('');
const [confirmAction, setConfirmAction] = useState<ConfirmAction | null>(null);
const [error, setError] = useState('');
const [saving, setSaving] = useState(false);
async function load() {
if (!tenantId) return;
@@ -79,6 +81,11 @@ export function ClientUsersPage() {
}
async function saveUser() {
if (!form.displayName.trim() || (!form.email.trim() && !form.phone.trim()) || (creating && form.password.length < 6)) {
setError('请填写姓名、邮箱或手机号;新增用户密码至少 6 位');
return;
}
setSaving(true);
const body: UserPayload = {
displayName: form.displayName,
username: form.username || form.email || form.phone,
@@ -88,14 +95,20 @@ export function ClientUsersPage() {
roleCode: 'enterprise_admin',
operatorId: session?.user.id,
};
if (creating) {
await clientApi.createUser({ ...body, password: form.password }, tenantId);
} else if (editingUser) {
await clientApi.updateUser(editingUser.id, body, tenantId);
try {
if (creating) {
await clientApi.createUser({ ...body, password: form.password }, tenantId);
} else if (editingUser) {
await clientApi.updateUser(editingUser.id, body, tenantId);
}
setCreating(false);
setEditingUser(null);
await load();
} catch (failure) {
setError(failure instanceof Error ? failure.message : '用户保存失败');
} finally {
setSaving(false);
}
setCreating(false);
setEditingUser(null);
await load();
}
async function runConfirm() {
@@ -122,7 +135,7 @@ export function ClientUsersPage() {
{ key: 'phone', title: '手机号', width: '160px', render: (record) => <span className="muted">{record.phone ?? '-'}</span> },
{ key: 'role', title: '角色', width: '130px', render: () => <Tag tone="info"></Tag> },
{ key: 'status', title: '状态', width: '120px', render: (record) => <Tag tone={record.status === 'active' ? 'success' : 'neutral'}>{record.status === 'active' ? '正常' : '禁用'}</Tag> },
{ key: 'lastLoginAt', title: '最后登录时间', width: '190px', render: (record) => <span className="muted">{record.lastLoginAt ? new Date(record.lastLoginAt).toLocaleString('zh-CN') : '-'}</span> },
{ key: 'lastLoginAt', title: '最后登录时间', width: '190px', render: (record) => <span className="muted">{formatDateTime(record.lastLoginAt)}</span> },
{
key: 'actions',
title: '操作',
@@ -131,7 +144,7 @@ export function ClientUsersPage() {
<div className="inline-actions">
<Button icon={<Edit3 size={15} />} onClick={() => openEditor(record)} size="sm" variant="ghost"></Button>
<Button icon={<KeyRound size={15} />} onClick={() => { setPasswordUser(record); setNewPassword(''); }} size="sm" variant="ghost"></Button>
<Button onClick={() => setConfirmAction({ type: 'status', user: record })} size="sm" variant="ghost">{record.status === 'active' ? '禁用' : '启用'}</Button>
<Button onClick={() => setConfirmAction({ type: 'status', user: record })} size="sm" variant={record.status === 'active' ? 'warning' : 'success'}>{record.status === 'active' ? '禁用' : '启用'}</Button>
<Button icon={<Trash2 size={15} />} onClick={() => setConfirmAction({ type: 'delete', user: record })} size="sm" variant="danger"></Button>
</div>
),
@@ -158,7 +171,7 @@ export function ClientUsersPage() {
{(creating || editingUser) ? (
<Modal
footer={<><Button onClick={() => { setCreating(false); setEditingUser(null); }} variant="secondary"></Button><Button onClick={() => void saveUser()}></Button></>}
footer={<><Button disabled={saving} onClick={() => { setCreating(false); setEditingUser(null); }} variant="secondary"></Button><Button disabled={saving} onClick={() => void saveUser()}>{saving ? '保存中...' : '保存'}</Button></>}
onClose={() => { setCreating(false); setEditingUser(null); }}
open
size="xl"