fix;提交代码子账号
This commit is contained in:
@@ -1,149 +1,141 @@
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import PageHeader from '@dukang/shared-ui/PageHeader';
|
||||
import { PARTNER_STAFF_ROLE_LABELS, PartnerStaffRole } from '@dukang/shared-types';
|
||||
import { createPartnerStaff, sendStaffAddSms } from '../lib/staff';
|
||||
import { createPartnerStaff } from '../lib/staff';
|
||||
import { toastError, toastSuccess } from '../lib/toast';
|
||||
|
||||
const ROLE_OPTIONS = Object.values(PartnerStaffRole);
|
||||
type FieldErrors = {
|
||||
name?: string;
|
||||
phone?: string;
|
||||
};
|
||||
|
||||
export default function StaffCreatePage() {
|
||||
const navigate = useNavigate();
|
||||
const [name, setName] = useState('');
|
||||
const [phone, setPhone] = useState('');
|
||||
const [code, setCode] = useState('');
|
||||
const [staffRole, setStaffRole] = useState<PartnerStaffRole>(PartnerStaffRole.INTERNAL);
|
||||
const [sending, setSending] = useState(false);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [msg, setMsg] = useState('');
|
||||
const [submitError, setSubmitError] = useState('');
|
||||
const [fieldErrors, setFieldErrors] = useState<FieldErrors>({});
|
||||
|
||||
async function sendCode() {
|
||||
if (!/^1[3-9]\d{9}$/.test(phone.trim())) {
|
||||
const text = '请输入正确的11位手机号';
|
||||
setMsg(text);
|
||||
toastError(text);
|
||||
return;
|
||||
}
|
||||
setSending(true);
|
||||
setMsg('');
|
||||
try {
|
||||
await sendStaffAddSms(phone.trim());
|
||||
setMsg('验证码已发送');
|
||||
} catch {
|
||||
/* request 已 toast */
|
||||
} finally {
|
||||
setSending(false);
|
||||
}
|
||||
function patchName(value: string) {
|
||||
setName(value);
|
||||
setSubmitError('');
|
||||
setFieldErrors((prev) => ({ ...prev, name: undefined }));
|
||||
}
|
||||
|
||||
function patchPhone(value: string) {
|
||||
setPhone(value);
|
||||
setSubmitError('');
|
||||
setFieldErrors((prev) => ({ ...prev, phone: undefined }));
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (!name.trim()) {
|
||||
const text = '请填写真实姓名';
|
||||
setMsg(text);
|
||||
toastError(text);
|
||||
return;
|
||||
}
|
||||
if (!/^1[3-9]\d{9}$/.test(phone.trim())) {
|
||||
const text = '请输入正确的11位手机号';
|
||||
setMsg(text);
|
||||
toastError(text);
|
||||
return;
|
||||
}
|
||||
if (!code.trim()) {
|
||||
const text = '请输入验证码';
|
||||
setMsg(text);
|
||||
toastError(text);
|
||||
const trimmedName = name.trim();
|
||||
const trimmedPhone = phone.trim();
|
||||
const nextFieldErrors: FieldErrors = {};
|
||||
|
||||
if (!trimmedName) nextFieldErrors.name = '请填写真实姓名';
|
||||
if (!trimmedPhone) {
|
||||
nextFieldErrors.phone = '请填写手机号码';
|
||||
} else if (!/^1[3-9]\d{9}$/.test(trimmedPhone)) {
|
||||
nextFieldErrors.phone = '请输入正确的11位手机号';
|
||||
}
|
||||
|
||||
if (Object.keys(nextFieldErrors).length) {
|
||||
setFieldErrors(nextFieldErrors);
|
||||
return;
|
||||
}
|
||||
|
||||
setSubmitting(true);
|
||||
setMsg('');
|
||||
setSubmitError('');
|
||||
setFieldErrors({});
|
||||
|
||||
try {
|
||||
await createPartnerStaff({
|
||||
name: name.trim(),
|
||||
phone: phone.trim(),
|
||||
staffRole,
|
||||
code: code.trim(),
|
||||
name: trimmedName,
|
||||
phone: trimmedPhone,
|
||||
});
|
||||
toastSuccess('子账号创建成功');
|
||||
navigate('/center/staff');
|
||||
} catch {
|
||||
/* request 已 toast */
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : '创建失败';
|
||||
if (message.includes('手机号')) {
|
||||
setFieldErrors({ phone: message });
|
||||
return;
|
||||
}
|
||||
setSubmitError(message);
|
||||
toastError(message);
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="page-no-tab partner-staff-create-page">
|
||||
<div className="partner-page-sticky">
|
||||
<PageHeader title="添加子账号" onBack={() => navigate('/center/staff')} />
|
||||
|
||||
<main style={{ padding: '16px 20px 120px' }}>
|
||||
{msg && <p className="partner-form-error" role="alert" style={{ marginBottom: 12 }}>{msg}</p>}
|
||||
{submitError && (
|
||||
<p className="partner-form-error" role="alert">{submitError}</p>
|
||||
)}
|
||||
|
||||
<div className="partner-form-card">
|
||||
<label className="partner-form-label">真实姓名 *</label>
|
||||
<div className="partner-form-input-wrap">
|
||||
<section className="partner-form-card">
|
||||
<div className="partner-section-title">
|
||||
<div className="partner-section-bar" />
|
||||
<h2 className="headline-md">子账号信息</h2>
|
||||
</div>
|
||||
|
||||
<div className="partner-field">
|
||||
<label>真实姓名 <span className="text-primary">*</span></label>
|
||||
<div className="partner-field-input">
|
||||
<span className="material-symbols-outlined">person</span>
|
||||
<input
|
||||
className="partner-form-input"
|
||||
placeholder="请输入员工姓名"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
onChange={(e) => patchName(e.target.value)}
|
||||
/>
|
||||
<span className="material-symbols-outlined">person</span>
|
||||
</div>
|
||||
{fieldErrors.name && (
|
||||
<p className="partner-field-error" role="alert">{fieldErrors.name}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="partner-form-card">
|
||||
<label className="partner-form-label">手机号码 *</label>
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<div className="partner-field">
|
||||
<label>手机号码 <span className="text-primary">*</span></label>
|
||||
<div className="partner-field-input">
|
||||
<span className="material-symbols-outlined">call</span>
|
||||
<input
|
||||
className="partner-form-input"
|
||||
type="tel"
|
||||
placeholder="请输入11位手机号"
|
||||
value={phone}
|
||||
onChange={(e) => setPhone(e.target.value)}
|
||||
inputMode="numeric"
|
||||
onChange={(e) => patchPhone(e.target.value)}
|
||||
/>
|
||||
<button type="button" className="btn btn-outline" disabled={sending} onClick={() => void sendCode()}>
|
||||
{sending ? '发送中' : '获取验证码'}
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
className="partner-form-input"
|
||||
style={{ marginTop: 8 }}
|
||||
placeholder="验证码"
|
||||
value={code}
|
||||
onChange={(e) => setCode(e.target.value)}
|
||||
inputMode="numeric"
|
||||
/>
|
||||
{fieldErrors.phone && (
|
||||
<p className="partner-field-error" role="alert">{fieldErrors.phone}</p>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="partner-form-card">
|
||||
<label className="partner-form-label">分配角色 *</label>
|
||||
<div className="partner-form-input-wrap">
|
||||
<select
|
||||
className="partner-form-input"
|
||||
value={staffRole}
|
||||
onChange={(e) => setStaffRole(e.target.value as PartnerStaffRole)}
|
||||
>
|
||||
{ROLE_OPTIONS.map((role) => (
|
||||
<option key={role} value={role}>{PARTNER_STAFF_ROLE_LABELS[role]}</option>
|
||||
))}
|
||||
</select>
|
||||
<span className="material-symbols-outlined">expand_more</span>
|
||||
</div>
|
||||
<div className="partner-info-banner">
|
||||
<div className="partner-bills-icon">
|
||||
<span className="material-symbols-outlined">info</span>
|
||||
</div>
|
||||
|
||||
<p className="label-md text-muted" style={{ marginTop: 16, textAlign: 'center' }}>
|
||||
创建即代表同意合伙人管理协议。子账号默认禁用,需手动启用。
|
||||
<p className="label-md text-variant" style={{ marginTop: 0, lineHeight: 1.5 }}>
|
||||
子账号创建后默认禁用,需在子账号列表中手动启用后方可登录。
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<div className="partner-sticky-footer">
|
||||
<button type="button" className="partner-btn-primary" disabled={submitting} onClick={() => void submit()}>
|
||||
<span className="material-symbols-outlined">person_add</span>
|
||||
{submitting ? '创建中...' : '确认创建'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<footer className="partner-sticky-footer">
|
||||
<button
|
||||
type="button"
|
||||
className="partner-btn-primary"
|
||||
disabled={submitting}
|
||||
onClick={() => void submit()}
|
||||
>
|
||||
<span className="material-symbols-outlined" style={{ fontSize: 20 }}>person_add</span>
|
||||
{submitting ? '创建中…' : '确认创建'}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user