/* eslint-disable max-lines-per-function, complexity -- 四步向导集中编排步骤、行业选择与提交校验 */ import { Button, Input, Select } from '@douyinfe/semi-ui-19'; import type { CreateCustomerInput, IndustryTreeItem } from '@lingxi/shared'; import { notifySuccess, PageSkeleton } from '@lingxi/ui'; import type { ReactNode } from 'react'; import { useMemo, useState } from 'react'; import { useNavigate } from 'react-router'; import { useCreateCustomerMutation, useIndustriesQuery } from '@/hooks/queries/use-client'; import { useUserCandidatesQuery } from '@/hooks/queries/use-users'; import { customerDetailPath, ROUTES } from '@/routes'; const STEPS = [ { key: 'industry', label: '选择行业', desc: '行业决定行业包与可用模板' }, { key: 'basic', label: '基础信息', desc: '名称、简称、负责人与对接人' }, { key: 'prefs', label: '交付偏好', desc: '命名、目录、规格与禁忌' }, { key: 'pack', label: '行业资产包', desc: '冷启动套用行业资产' }, ]; function IndustryPicker({ items, value, onChange, }: { items: readonly IndustryTreeItem[]; value: string | undefined; onChange: (id: string) => void; }): ReactNode { const groups = items .filter((root) => root.status === 'active') .map((root) => ({ root, options: root.children.length === 0 ? [root] : root.children.filter((child) => child.status === 'active'), })) .filter((group) => group.options.length > 0); return (
{groups.map((group) => (
{group.root.name} {group.root.children.length === 0 ? '无二级行业,可直接选择' : `${group.root.children.length} 个二级行业`}
{group.options.map((option) => { const checked = option.id === value; return ( ); })}
))} {groups.length === 0 ?
暂无可选行业
: null}
); } /** 新建客户(选定方案 B:左侧带说明的步骤导航 + 右侧表单) */ export function CustomerNewPage(): ReactNode { const navigate = useNavigate(); const industries = useIndustriesQuery({ limit: 100 }); const users = useUserCandidatesQuery(true); const create = useCreateCustomerMutation(); const [current, setCurrent] = useState(0); const [industryId, setIndustryId] = useState(); const [name, setName] = useState(''); const [shortName, setShortName] = useState(''); const [ownerUserId, setOwnerUserId] = useState(); const [contactName, setContactName] = useState(''); const [contactPhone, setContactPhone] = useState(''); const [remark, setRemark] = useState(''); const [naming, setNaming] = useState('客户名_方向_日期_序号'); const [directory, setDirectory] = useState('客户名/年份/方向'); const [specs, setSpecs] = useState('1080×1920,1080×1080'); const [taboo, setTaboo] = useState('绝对化用语,未授权肖像'); const [error, setError] = useState(null); const industryLabel = useMemo(() => { for (const root of industries.data?.items ?? []) { if (root.id === industryId) return root.name; for (const child of root.children) { if (child.id === industryId) return `${root.name} / ${child.name}`; } } return '未选择'; }, [industries.data, industryId]); const next = (): void => { setError(null); if (current === 0 && industryId === undefined) { setError('请选择客户归属行业'); return; } if (current === 1) { if (name.trim() === '') { setError('请输入客户名称'); return; } if (shortName.trim().length < 2) { setError('客户简称必填,用于自动命名(42201)'); return; } if (ownerUserId === undefined) { setError('请选择客户负责人'); return; } } setCurrent((step) => Math.min(step + 1, 3)); }; const submit = async (): Promise => { if (industryId === undefined || ownerUserId === undefined) return; const input: CreateCustomerInput = { industryId, name, shortName, ownerUserId, contactName: contactName === '' ? undefined : contactName, contactPhone: contactPhone === '' ? undefined : contactPhone, remark: remark === '' ? undefined : remark, preferences: { naming, directory, specs: specs .split(',') .map((item) => item.trim()) .filter((item) => item !== ''), taboo: taboo .split(',') .map((item) => item.trim()) .filter((item) => item !== ''), }, }; try { const created = await create.mutateAsync(input); notifySuccess('客户已创建'); void navigate(customerDetailPath(created.id)); } catch (cause) { setError(cause instanceof Error ? cause.message : '创建失败'); } }; if (industries.isPending) return ; return (

新建客户

分四步创建客户:选择行业 → 基础信息 → 交付偏好 → 行业资产包

{STEPS[current]?.label} {current === 0 ? `${industryLabel} · 只能选择末级行业` : current === 1 ? '简称必填,用于全部自动命名' : current === 2 ? '命名、目录、规格与素材禁忌' : '行业包发布后可一键套用'}
{current === 0 ? ( <>
客户归属行业 只能选择末级行业;一级行业没有二级时可直接选择
所属行业决定行业包;客户创建后不可跨行业移动,调整行业需停用后新建。
) : null} {current === 1 ? (
) : null} {current === 2 ? (
) : null} {current === 3 ? (
该行业尚未发布可用行业包 行业包发布后可在此一键套用模板、场景、人物、提示词与卖点,并自动替换为客户 Logo 与警示语。当前可以先完成客户创建,行业包发布后回客户详情套用。
) : null} {error !== null ? (
{error}
) : null}
步骤 {current + 1} / 4 · 可回退修改 {current === 0 ? ( ) : ( )} {current < 3 ? ( ) : ( )}
); }