feat: 编辑企业弹窗增加管理员信息编辑(姓名、手机号、重置密码)
This commit is contained in:
@@ -259,6 +259,53 @@ router.put('/orgs/:id', async (req: AuthRequest, res, next) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑企业管理员(姓名、手机号、可选重置密码)
|
||||||
|
*/
|
||||||
|
router.put('/orgs/:id/admin', async (req: AuthRequest, res, next) => {
|
||||||
|
try {
|
||||||
|
const { adminName, adminPhone, adminPassword } = req.body as {
|
||||||
|
adminName?: string; adminPhone?: string; adminPassword?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到该企业的 ADMIN 角色用户(第一个管理员)
|
||||||
|
const admin = await prisma.user.findFirst({
|
||||||
|
where: { orgId: req.params.id, role: 'ADMIN' },
|
||||||
|
orderBy: { createdAt: 'asc' },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!admin) {
|
||||||
|
return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '该企业未设置管理员' } })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果修改了手机号,检查是否已被其他用户占用
|
||||||
|
if (adminPhone && adminPhone !== admin.phone) {
|
||||||
|
const existing = await prisma.user.findUnique({ where: { phone: adminPhone } })
|
||||||
|
if (existing && existing.id !== admin.id) {
|
||||||
|
return res.status(409).json({ success: false, error: { code: 'DUPLICATE_PHONE', message: '该手机号已被使用' } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateData: any = {}
|
||||||
|
if (adminName) updateData.name = adminName
|
||||||
|
if (adminPhone) updateData.phone = adminPhone
|
||||||
|
if (adminPassword && adminPassword.length >= 8) {
|
||||||
|
const bcrypt = require('bcryptjs')
|
||||||
|
updateData.passwordHash = await bcrypt.hash(adminPassword, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated = await prisma.user.update({
|
||||||
|
where: { id: admin.id },
|
||||||
|
data: updateData,
|
||||||
|
select: { id: true, name: true, phone: true, role: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
res.json({ success: true, data: updated })
|
||||||
|
} catch (err) {
|
||||||
|
next(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除企业(级联删除所有数据)
|
* 删除企业(级联删除所有数据)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ export default function PlatformOrgs() {
|
|||||||
adminName: '管理员', adminPhone: '', adminPassword: '12345678',
|
adminName: '管理员', adminPhone: '', adminPassword: '12345678',
|
||||||
})
|
})
|
||||||
const [creating, setCreating] = useState(false)
|
const [creating, setCreating] = useState(false)
|
||||||
|
const [editAdmin, setEditAdmin] = useState({ name: '', phone: '', password: '' })
|
||||||
|
const [savingAdmin, setSavingAdmin] = useState(false)
|
||||||
|
|
||||||
const fetchOrgs = async () => {
|
const fetchOrgs = async () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
@@ -55,6 +57,21 @@ export default function PlatformOrgs() {
|
|||||||
|
|
||||||
const totalPages = Math.ceil(total / pageSize)
|
const totalPages = Math.ceil(total / pageSize)
|
||||||
|
|
||||||
|
const handleEditOrg = async (org: Org) => {
|
||||||
|
setEditOrg(org)
|
||||||
|
setEditAdmin({ name: '', phone: '', password: '' })
|
||||||
|
// 加载企业管理员信息
|
||||||
|
try {
|
||||||
|
const res = await api.get(`/platform/orgs/${org.id}`) as any
|
||||||
|
const admin = res.data.users?.find((u: any) => u.role === 'ADMIN')
|
||||||
|
if (admin) {
|
||||||
|
setEditAdmin({ name: admin.name || '', phone: admin.phone || '', password: '' })
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// 忽略
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleSaveEdit = async () => {
|
const handleSaveEdit = async () => {
|
||||||
if (!editOrg) return
|
if (!editOrg) return
|
||||||
try {
|
try {
|
||||||
@@ -66,6 +83,14 @@ export default function PlatformOrgs() {
|
|||||||
contactName: editOrg.contactName,
|
contactName: editOrg.contactName,
|
||||||
contactPhone: editOrg.contactPhone,
|
contactPhone: editOrg.contactPhone,
|
||||||
})
|
})
|
||||||
|
// 如果管理员信息有改动,同步保存
|
||||||
|
if (editAdmin.name || editAdmin.phone || editAdmin.password) {
|
||||||
|
await api.put(`/platform/orgs/${editOrg.id}/admin`, {
|
||||||
|
adminName: editAdmin.name || undefined,
|
||||||
|
adminPhone: editAdmin.phone || undefined,
|
||||||
|
adminPassword: editAdmin.password || undefined,
|
||||||
|
})
|
||||||
|
}
|
||||||
setEditOrg(null)
|
setEditOrg(null)
|
||||||
fetchOrgs()
|
fetchOrgs()
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
@@ -183,7 +208,7 @@ export default function PlatformOrgs() {
|
|||||||
<td className="px-4 py-3">
|
<td className="px-4 py-3">
|
||||||
<div className="flex items-center justify-center gap-1">
|
<div className="flex items-center justify-center gap-1">
|
||||||
<button
|
<button
|
||||||
onClick={() => setEditOrg(org)}
|
onClick={() => handleEditOrg(org)}
|
||||||
className="p-1.5 rounded text-gray-400 hover:text-primary hover:bg-gray-100"
|
className="p-1.5 rounded text-gray-400 hover:text-primary hover:bg-gray-100"
|
||||||
title="编辑"
|
title="编辑"
|
||||||
>
|
>
|
||||||
@@ -316,6 +341,26 @@ export default function PlatformOrgs() {
|
|||||||
<Label>联系电话</Label>
|
<Label>联系电话</Label>
|
||||||
<Input value={editOrg.contactPhone || ''} onChange={(e) => setEditOrg({ ...editOrg, contactPhone: e.target.value })} />
|
<Input value={editOrg.contactPhone || ''} onChange={(e) => setEditOrg({ ...editOrg, contactPhone: e.target.value })} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 管理员账号 */}
|
||||||
|
<div className="border-t border-gray-100 pt-3 mt-3">
|
||||||
|
<h3 className="text-xs text-primary font-medium mb-3">企业管理员</h3>
|
||||||
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
<div>
|
||||||
|
<Label>管理员姓名</Label>
|
||||||
|
<Input value={editAdmin.name} onChange={(e) => setEditAdmin({ ...editAdmin, name: e.target.value })} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>管理员手机号</Label>
|
||||||
|
<Input value={editAdmin.phone} maxLength={11} onChange={(e) => setEditAdmin({ ...editAdmin, phone: e.target.value })} />
|
||||||
|
</div>
|
||||||
|
<div className="col-span-2">
|
||||||
|
<Label>重置密码(留空则不修改)</Label>
|
||||||
|
<Input placeholder="输入新密码(至少8位)" value={editAdmin.password} onChange={(e) => setEditAdmin({ ...editAdmin, password: e.target.value })} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-2 pt-2">
|
<div className="flex gap-2 pt-2">
|
||||||
<Button className="flex-1" onClick={handleSaveEdit}>保存</Button>
|
<Button className="flex-1" onClick={handleSaveEdit}>保存</Button>
|
||||||
<Button variant="secondary" onClick={() => setEditOrg(null)}>取消</Button>
|
<Button variant="secondary" onClick={() => setEditOrg(null)}>取消</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user