feat(consignment): 支持复制寄卖模板配置与一二级分类折叠展示
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
ArrowDownOutlined,
|
||||
ArrowUpOutlined,
|
||||
CopyOutlined,
|
||||
DeleteOutlined,
|
||||
DownOutlined,
|
||||
PlusOutlined,
|
||||
@@ -34,6 +35,10 @@ import {
|
||||
import { useEffect, useMemo, useState, type CSSProperties } from 'react'
|
||||
|
||||
import PercentTable from '@/components/common/PercentTable'
|
||||
import ConsignmentTemplateCopyModal, {
|
||||
type ConsignmentTemplateCopyMode,
|
||||
type ConsignmentTemplateCopySelection,
|
||||
} from '@/components/admin/ConsignmentTemplateCopyModal'
|
||||
import {
|
||||
archiveAdminConsignmentProfile,
|
||||
fetchAdminConsignmentProfiles,
|
||||
@@ -580,7 +585,7 @@ const fieldCellStyle: CSSProperties = {
|
||||
}
|
||||
|
||||
export default function ConsignmentConfigPanel() {
|
||||
const { message } = App.useApp()
|
||||
const { message, modal } = App.useApp()
|
||||
const queryClient = useQueryClient()
|
||||
const [selectedCategoryId, setSelectedCategoryId] = useState<number | null>(null)
|
||||
const [categoryKeyword, setCategoryKeyword] = useState('')
|
||||
@@ -589,6 +594,7 @@ export default function ConsignmentConfigPanel() {
|
||||
const [specDrafts, setSpecDrafts] = useState<ConsignmentSpecField[]>([])
|
||||
const [intakeDrafts, setIntakeDrafts] = useState<ConsignmentIntakeField[]>([])
|
||||
const [specSource, setSpecSource] = useState<'manual' | 'template'>('manual')
|
||||
const [copyTemplateMode, setCopyTemplateMode] = useState<ConsignmentTemplateCopyMode | null>(null)
|
||||
const [proposalOpen, setProposalOpen] = useState(false)
|
||||
// 按数量(规格)保证金:弹窗里选字段 + 配每个选项的每件保证金
|
||||
const [depositSpecOpen, setDepositSpecOpen] = useState(false)
|
||||
@@ -608,6 +614,7 @@ export default function ConsignmentConfigPanel() {
|
||||
() => new Map(profiles.map((profile) => [profile.categoryId, profile])),
|
||||
[profiles],
|
||||
)
|
||||
const hasCopyableProfiles = profiles.some((profile) => profile.categoryId !== selectedCategoryId)
|
||||
|
||||
const normalizedKeyword = categoryKeyword.trim().toLowerCase()
|
||||
const categoryTree = useMemo<CategoryNode[]>(() => {
|
||||
@@ -756,6 +763,43 @@ export default function ConsignmentConfigPanel() {
|
||||
setIntakeDrafts(cloneIntakeFields(DEFAULT_CONSIGNMENT_INTAKE_FIELDS))
|
||||
}
|
||||
|
||||
function handleCopyTemplate(selection: ConsignmentTemplateCopySelection) {
|
||||
const mode = copyTemplateMode
|
||||
if (!mode) return
|
||||
const sourceLabel = [
|
||||
selection.profile.categoryParentName,
|
||||
selection.profile.categoryName || selection.profile.name,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' / ')
|
||||
const apply = () => {
|
||||
if (mode === 'specs') {
|
||||
setSpecDrafts(cloneSpecs(selection.config.specs))
|
||||
setSpecSource(selection.config.specSource === 'template' ? 'template' : 'manual')
|
||||
message.success(
|
||||
`已复制「${sourceLabel}」的 ${selection.config.specs.length} 个规格字段,请保存草稿`,
|
||||
)
|
||||
} else {
|
||||
const fields = selection.config.intake?.fields ?? DEFAULT_CONSIGNMENT_INTAKE_FIELDS
|
||||
setIntakeDrafts(cloneIntakeFields(fields))
|
||||
message.success(`已复制「${sourceLabel}」的 ${fields.length} 个联系方式字段,请保存草稿`)
|
||||
}
|
||||
setCopyTemplateMode(null)
|
||||
}
|
||||
const existingCount = mode === 'specs' ? specDrafts.length : intakeDrafts.length
|
||||
if (existingCount > 0) {
|
||||
modal.confirm({
|
||||
title: '覆盖当前字段?',
|
||||
content: `当前区块已有 ${existingCount} 个字段,复制模板会全部替换,未保存的修改将丢失。`,
|
||||
okText: '覆盖并复制',
|
||||
cancelText: '取消',
|
||||
onOk: apply,
|
||||
})
|
||||
return
|
||||
}
|
||||
apply()
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
if (!selectedCategoryId) return
|
||||
const specs = specDrafts.map((spec) =>
|
||||
@@ -1248,6 +1292,14 @@ export default function ConsignmentConfigPanel() {
|
||||
description="初始为空;字段随配置版本发布,并写入提报与库存快照"
|
||||
/>
|
||||
<Space size={8}>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<CopyOutlined />}
|
||||
disabled={!hasCopyableProfiles}
|
||||
onClick={() => setCopyTemplateMode('specs')}
|
||||
>
|
||||
复制模板配置
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<ThunderboltOutlined />}
|
||||
@@ -1437,15 +1489,25 @@ export default function ConsignmentConfigPanel() {
|
||||
title="联系方式与游戏凭据"
|
||||
description="打手发布页按这里配置的字段动态渲染;字段为空时该模块不显示"
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
size="small"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={addIntakeField}
|
||||
>
|
||||
添加字段
|
||||
</Button>
|
||||
<Space size={8}>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<CopyOutlined />}
|
||||
disabled={!hasCopyableProfiles}
|
||||
onClick={() => setCopyTemplateMode('intake')}
|
||||
>
|
||||
复制模板配置
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
size="small"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={addIntakeField}
|
||||
>
|
||||
添加字段
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
<Text type="secondary">
|
||||
默认字段与旧发布页一致;手机号字段会校验 11
|
||||
@@ -2051,6 +2113,16 @@ export default function ConsignmentConfigPanel() {
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
<ConsignmentTemplateCopyModal
|
||||
open={copyTemplateMode !== null}
|
||||
mode={copyTemplateMode ?? 'specs'}
|
||||
currentCategoryId={selectedCategoryId}
|
||||
categories={categories}
|
||||
profiles={profiles}
|
||||
onCancel={() => setCopyTemplateMode(null)}
|
||||
onApply={handleCopyTemplate}
|
||||
/>
|
||||
|
||||
<Modal
|
||||
title="从接单模板生成规格字段"
|
||||
open={proposalOpen}
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
Switch,
|
||||
Tag,
|
||||
Tooltip,
|
||||
TreeSelect,
|
||||
Typography,
|
||||
} from 'antd'
|
||||
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
|
||||
@@ -55,12 +56,14 @@ import { fetchAdminWorkerUsers } from '@/services/admin/worker-platform'
|
||||
import ConsignmentManualMatchModal from '@/components/admin/ConsignmentManualMatchModal'
|
||||
import type {
|
||||
ConsignmentInventory,
|
||||
ConsignmentInventoryFilterCategory,
|
||||
ConsignmentInventoryFilterField,
|
||||
GiftEvidenceReviewStatus,
|
||||
} from '@/types/consignment'
|
||||
import { fetchAdminSession } from '@/services/admin/auth'
|
||||
import { resolveAdminPermission } from '@/utils/admin-auth'
|
||||
import { formatConsignmentContactSupporter } from '@/utils/consignment-contact'
|
||||
import { buildConsignmentCategoryGroups } from '@/utils/consignment-category-tree'
|
||||
import { describeGiftEvidence, resolveGiftEvidenceBadge } from '@/utils/consignment-evidence'
|
||||
import {
|
||||
CONSIGNMENT_SPEC_TAG_COLORS,
|
||||
@@ -123,12 +126,24 @@ function resolveGiftEvidenceEmptyText(record: {
|
||||
return '未上传赠送截图'
|
||||
}
|
||||
|
||||
type InventoryFilterTreeNode = {
|
||||
key: string
|
||||
value: number
|
||||
title: string
|
||||
selectable: boolean
|
||||
kind: 'group' | 'root' | 'child'
|
||||
item?: ConsignmentInventoryFilterCategory
|
||||
groupCount?: number
|
||||
children?: InventoryFilterTreeNode[]
|
||||
}
|
||||
|
||||
export default function ConsignmentInventoryPanel() {
|
||||
const { message } = App.useApp()
|
||||
|
||||
// 筛选条件:分类与规格项全部来自「寄卖配置」已发布版本
|
||||
const [status, setStatus] = useState<string>('in_stock')
|
||||
const [categoryId, setCategoryId] = useState<number | null>(null)
|
||||
const [categoryExpandedKeys, setCategoryExpandedKeys] = useState<Array<string | number>>([])
|
||||
const [specFilters, setSpecFilters] = useState<Record<string, string>>({})
|
||||
const [allowMatching, setAllowMatching] = useState<string>('')
|
||||
const [inboundRange, setInboundRange] = useState<[string, string] | null>(null)
|
||||
@@ -189,14 +204,68 @@ export default function ConsignmentInventoryPanel() {
|
||||
() => filterOptionsQuery.data?.data.items || [],
|
||||
[filterOptionsQuery.data],
|
||||
)
|
||||
const categoryOptions = useMemo(
|
||||
() =>
|
||||
filterCategories.map((item) => ({
|
||||
// 一级分类直接显示分类名;二级分类带上父级,避免同名歧义
|
||||
label: item.parentName ? `${item.parentName} / ${item.name}` : item.name,
|
||||
const categoryTreeData = useMemo<InventoryFilterTreeNode[]>(() => {
|
||||
const groups = buildConsignmentCategoryGroups({
|
||||
items: filterCategories,
|
||||
getCategoryId: (item) => item.categoryId,
|
||||
getParentId: (item) => item.parentId,
|
||||
getParentName: (item) => item.parentName,
|
||||
getFallbackName: (item) => item.name,
|
||||
})
|
||||
|
||||
return groups.flatMap((group) => {
|
||||
const root = group.root
|
||||
const rootLabel = root?.name || group.groupName || '未命名分类'
|
||||
const childNodes: InventoryFilterTreeNode[] = group.children.map((item) => ({
|
||||
key: `child-${item.categoryId}`,
|
||||
value: item.categoryId,
|
||||
})),
|
||||
[filterCategories],
|
||||
title: item.name,
|
||||
selectable: true,
|
||||
kind: 'child',
|
||||
item,
|
||||
}))
|
||||
if (root && childNodes.length === 0) {
|
||||
return [
|
||||
{
|
||||
key: `root-${root.categoryId}`,
|
||||
value: root.categoryId,
|
||||
title: rootLabel,
|
||||
selectable: true,
|
||||
kind: 'root',
|
||||
item: root,
|
||||
},
|
||||
]
|
||||
}
|
||||
if (!root) {
|
||||
if (childNodes.length === 0) return []
|
||||
const groupNode: InventoryFilterTreeNode = {
|
||||
key: `group-${group.groupCategoryId}`,
|
||||
value: -group.groupCategoryId,
|
||||
title: rootLabel,
|
||||
selectable: false,
|
||||
kind: 'group',
|
||||
groupCount: childNodes.length,
|
||||
children: childNodes,
|
||||
}
|
||||
return [groupNode]
|
||||
}
|
||||
return [
|
||||
{
|
||||
key: `group-${group.groupCategoryId}`,
|
||||
value: root.categoryId,
|
||||
title: rootLabel,
|
||||
selectable: true,
|
||||
kind: 'group',
|
||||
item: root,
|
||||
groupCount: childNodes.length,
|
||||
children: childNodes,
|
||||
},
|
||||
]
|
||||
})
|
||||
}, [filterCategories])
|
||||
const categoryGroupKeys = useMemo(
|
||||
() => categoryTreeData.filter((node) => node.children?.length).map((node) => node.key),
|
||||
[categoryTreeData],
|
||||
)
|
||||
|
||||
// 默认「苏尔南手枪」;该分类未开启寄卖时回退到第一个已开启分类
|
||||
@@ -893,14 +962,53 @@ export default function ConsignmentInventoryPanel() {
|
||||
</Radio.Group>
|
||||
|
||||
{/* 寄卖分类:选项与规格筛选项全部来自该类别的已发布寄卖配置 */}
|
||||
<Select
|
||||
style={{ width: 200 }}
|
||||
<TreeSelect<number, InventoryFilterTreeNode>
|
||||
style={{ width: 240 }}
|
||||
loading={filterOptionsQuery.isLoading}
|
||||
value={categoryId ?? undefined}
|
||||
placeholder="寄卖分类"
|
||||
options={categoryOptions}
|
||||
treeData={categoryTreeData}
|
||||
treeDefaultExpandAll={false}
|
||||
treeExpandedKeys={categoryExpandedKeys}
|
||||
onTreeExpand={(keys) => setCategoryExpandedKeys(keys as Array<string | number>)}
|
||||
showSearch={{
|
||||
treeNodeFilterProp: 'title',
|
||||
onSearch: (value) => setCategoryExpandedKeys(value.trim() ? categoryGroupKeys : []),
|
||||
}}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) setCategoryExpandedKeys([])
|
||||
}}
|
||||
popupMatchSelectWidth={false}
|
||||
listHeight={320}
|
||||
treeTitleRender={(node) => {
|
||||
const item = node as InventoryFilterTreeNode
|
||||
if (item.kind === 'group') {
|
||||
return (
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ flex: 1 }}>{item.title}</span>
|
||||
<Tag color="blue">一级</Tag>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
if (item.kind === 'root') {
|
||||
return (
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ flex: 1 }}>{item.title}</span>
|
||||
<Tag color="blue">一级</Tag>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ flex: 1 }}>{item.title}</span>
|
||||
<Tag>二级</Tag>
|
||||
{item.item?.source === 'inherited' ? <Tag color="blue">继承</Tag> : null}
|
||||
</span>
|
||||
)
|
||||
}}
|
||||
onChange={(value) => {
|
||||
setCategoryId(Number(value))
|
||||
if (typeof value !== 'number' || value <= 0) return
|
||||
setCategoryId(value)
|
||||
setSpecFilters({})
|
||||
setPage(1)
|
||||
}}
|
||||
|
||||
@@ -35,10 +35,11 @@ import {
|
||||
Space,
|
||||
Tabs,
|
||||
Tag,
|
||||
TreeSelect,
|
||||
Typography,
|
||||
Spin,
|
||||
} from 'antd'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
|
||||
import ImageUpload from '@/components/files/ImageUpload'
|
||||
import { WorkerContactModal } from '@/components/worker/WorkerContactModal'
|
||||
@@ -62,6 +63,7 @@ import type {
|
||||
} from '@/types/consignment'
|
||||
import type { UploadedFile } from '@/types/worker-platform'
|
||||
import { DEFAULT_CONSIGNMENT_INTAKE_FIELDS, buildSpecItemName } from '@/utils/consignment-spec'
|
||||
import { buildConsignmentCategoryGroups } from '@/utils/consignment-category-tree'
|
||||
import { formatConsignmentContactSupporter } from '@/utils/consignment-contact'
|
||||
import { formatGiftCooldownRemaining } from '@/utils/consignment-cooldown'
|
||||
import { resolveConsignmentDepositFen } from '@/utils/consignment-deposit'
|
||||
@@ -119,12 +121,56 @@ const COOLDOWN_TICK_MS = 30_000
|
||||
const RECORD_PAGE_SIZE = 10
|
||||
const SEARCH_DEBOUNCE_MS = 300
|
||||
|
||||
/** 一级在前、其二级紧随其后;只有二级配置时按原顺序追加。 */
|
||||
function orderWorkerProfiles(profiles: WorkerConsignmentProfile[]): WorkerConsignmentProfile[] {
|
||||
const childrenByParent = new Map<number, WorkerConsignmentProfile[]>()
|
||||
const roots: WorkerConsignmentProfile[] = []
|
||||
for (const profile of profiles) {
|
||||
if (profile.categoryParentId) {
|
||||
const list = childrenByParent.get(profile.categoryParentId) || []
|
||||
list.push(profile)
|
||||
childrenByParent.set(profile.categoryParentId, list)
|
||||
continue
|
||||
}
|
||||
roots.push(profile)
|
||||
}
|
||||
|
||||
const ordered: WorkerConsignmentProfile[] = []
|
||||
const included = new Set<number>()
|
||||
for (const root of roots) {
|
||||
ordered.push(root)
|
||||
included.add(root.profileId)
|
||||
for (const child of childrenByParent.get(root.categoryId) || []) {
|
||||
if (included.has(child.profileId)) continue
|
||||
ordered.push(child)
|
||||
included.add(child.profileId)
|
||||
}
|
||||
}
|
||||
for (const profile of profiles) {
|
||||
if (included.has(profile.profileId)) continue
|
||||
ordered.push(profile)
|
||||
}
|
||||
return ordered
|
||||
}
|
||||
|
||||
type WorkerProfileTreeNode = {
|
||||
key: string
|
||||
value: number
|
||||
title: string
|
||||
selectable: boolean
|
||||
kind: 'group' | 'root' | 'child'
|
||||
profile?: WorkerConsignmentProfile
|
||||
groupCount?: number
|
||||
children?: WorkerProfileTreeNode[]
|
||||
}
|
||||
|
||||
export default function WorkerConsignmentPage() {
|
||||
const isMobile = useIsMobile()
|
||||
const { message, modal } = App.useApp()
|
||||
const [activeTab, setActiveTabState] = useState<'publish' | 'records'>(getInitialActiveTab)
|
||||
/** 当前选中的寄卖配置(每个已发布配置一个 tab) */
|
||||
const [selectedProfileId, setSelectedProfileId] = useState<number | null>(null)
|
||||
const [profileExpandedKeys, setProfileExpandedKeys] = useState<Array<string | number>>([])
|
||||
const [recordFilter, setRecordFilterState] = useState<RecordFilter>(getInitialRecordFilter)
|
||||
/** 搜索框里的原始输入(立刻回显),防抖后才作为服务端查询条件 */
|
||||
const [recordKeywordInput, setRecordKeywordInput] = useState('')
|
||||
@@ -206,9 +252,78 @@ export default function WorkerConsignmentPage() {
|
||||
queryFn: () => fetchWorkerConsignmentProfiles(),
|
||||
})
|
||||
const consignmentProfiles = consignmentProfilesQuery.data?.data.profiles || []
|
||||
const orderedConsignmentProfiles = useMemo(
|
||||
() => orderWorkerProfiles(consignmentProfiles),
|
||||
[consignmentProfiles],
|
||||
)
|
||||
const profileTreeData = useMemo<WorkerProfileTreeNode[]>(() => {
|
||||
const groups = buildConsignmentCategoryGroups({
|
||||
items: orderedConsignmentProfiles,
|
||||
getCategoryId: (profile) => profile.categoryId,
|
||||
getParentId: (profile) => profile.categoryParentId,
|
||||
getParentName: (profile) => profile.categoryParentName,
|
||||
getFallbackName: (profile) => profile.tabTitle || profile.categoryName || profile.name,
|
||||
})
|
||||
|
||||
return groups.flatMap((group) => {
|
||||
const root = group.root
|
||||
const rootLabel = root
|
||||
? root.tabTitle || root.categoryName || root.name
|
||||
: group.groupName || '未命名分类'
|
||||
const childNodes: WorkerProfileTreeNode[] = group.children.map((child) => ({
|
||||
key: `child-${child.profileId}`,
|
||||
value: child.profileId,
|
||||
title: child.tabTitle || child.categoryName || child.name,
|
||||
selectable: true,
|
||||
kind: 'child',
|
||||
profile: child,
|
||||
}))
|
||||
if (root && childNodes.length === 0) {
|
||||
return [
|
||||
{
|
||||
key: `root-${root.profileId}`,
|
||||
value: root.profileId,
|
||||
title: rootLabel,
|
||||
selectable: true,
|
||||
kind: 'root',
|
||||
profile: root,
|
||||
},
|
||||
]
|
||||
}
|
||||
if (!root) {
|
||||
if (childNodes.length === 0) return []
|
||||
const groupNode: WorkerProfileTreeNode = {
|
||||
key: `group-${group.groupCategoryId}`,
|
||||
value: -group.groupCategoryId,
|
||||
title: rootLabel,
|
||||
selectable: false,
|
||||
kind: 'group',
|
||||
groupCount: childNodes.length,
|
||||
children: childNodes,
|
||||
}
|
||||
return [groupNode]
|
||||
}
|
||||
return [
|
||||
{
|
||||
key: `group-${group.groupCategoryId}`,
|
||||
value: root.profileId,
|
||||
title: rootLabel,
|
||||
selectable: true,
|
||||
kind: 'group',
|
||||
profile: root,
|
||||
groupCount: childNodes.length,
|
||||
children: childNodes,
|
||||
},
|
||||
]
|
||||
})
|
||||
}, [orderedConsignmentProfiles])
|
||||
const profileGroupKeys = useMemo(
|
||||
() => profileTreeData.filter((node) => node.children?.length).map((node) => node.key),
|
||||
[profileTreeData],
|
||||
)
|
||||
const selectedProfile: WorkerConsignmentProfile | null =
|
||||
consignmentProfiles.find((profile) => profile.profileId === selectedProfileId) ||
|
||||
consignmentProfiles[0] ||
|
||||
orderedConsignmentProfiles.find((profile) => profile.profileId === selectedProfileId) ||
|
||||
orderedConsignmentProfiles[0] ||
|
||||
null
|
||||
const selectedSpecs: ConsignmentSpecField[] = selectedProfile?.config.specs ?? []
|
||||
// 「允许修改寄售数量」关闭时:数量固定 1、输入框禁用,价格/押金一律按 1 件计算。
|
||||
@@ -229,15 +344,19 @@ export default function WorkerConsignmentPage() {
|
||||
const intakeFields: ConsignmentIntakeField[] =
|
||||
selectedProfile?.config.intake?.fields ?? DEFAULT_CONSIGNMENT_INTAKE_FIELDS
|
||||
useEffect(() => {
|
||||
if (selectedProfileId === null && consignmentProfiles.length > 0) {
|
||||
// 默认苏尔南手枪;没有该分类时退回第一个已发布配置。
|
||||
if (selectedProfileId === null && orderedConsignmentProfiles.length > 0) {
|
||||
// 默认苏尔南手枪一级配置;没有该分类时退回第一个一级配置,再退回第一条。
|
||||
const preferred =
|
||||
consignmentProfiles.find((profile) =>
|
||||
/苏尔南|苏里南/.test(`${profile.categoryName}${profile.tabTitle}${profile.name}`),
|
||||
) || consignmentProfiles[0]
|
||||
orderedConsignmentProfiles.find(
|
||||
(profile) =>
|
||||
!profile.categoryParentId &&
|
||||
/苏尔南|苏里南/.test(`${profile.categoryName}${profile.tabTitle}${profile.name}`),
|
||||
) ||
|
||||
orderedConsignmentProfiles.find((profile) => !profile.categoryParentId) ||
|
||||
orderedConsignmentProfiles[0]
|
||||
if (preferred) setSelectedProfileId(preferred.profileId)
|
||||
}
|
||||
}, [consignmentProfiles, selectedProfileId])
|
||||
}, [orderedConsignmentProfiles, selectedProfileId])
|
||||
|
||||
// 发布寄卖必填「对接客服」:只取启用名单,默认选第一个
|
||||
const consignmentContactsQuery = useQuery({
|
||||
@@ -769,15 +888,51 @@ export default function WorkerConsignmentPage() {
|
||||
}}
|
||||
>
|
||||
<Typography.Text strong>寄卖分类</Typography.Text>
|
||||
<Select
|
||||
<TreeSelect<number, WorkerProfileTreeNode>
|
||||
value={selectedProfile?.profileId}
|
||||
style={{ minWidth: 220 }}
|
||||
placeholder={consignmentProfiles.length === 0 ? '暂无可发布的寄卖分类' : '请选择寄卖分类'}
|
||||
options={consignmentProfiles.map((profile) => ({
|
||||
value: profile.profileId,
|
||||
label: profile.tabTitle || profile.categoryName || profile.name,
|
||||
}))}
|
||||
onChange={(value) => handleProfileChange(Number(value))}
|
||||
treeData={profileTreeData}
|
||||
treeDefaultExpandAll={false}
|
||||
treeExpandedKeys={profileExpandedKeys}
|
||||
onTreeExpand={(keys) => setProfileExpandedKeys(keys as Array<string | number>)}
|
||||
showSearch={{
|
||||
treeNodeFilterProp: 'title',
|
||||
onSearch: (value) => setProfileExpandedKeys(value.trim() ? profileGroupKeys : []),
|
||||
}}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) setProfileExpandedKeys([])
|
||||
}}
|
||||
placeholder={profileTreeData.length === 0 ? '暂无可发布的寄卖分类' : '请选择寄卖分类'}
|
||||
popupMatchSelectWidth={false}
|
||||
listHeight={320}
|
||||
treeTitleRender={(node) => {
|
||||
const item = node as WorkerProfileTreeNode
|
||||
if (item.kind === 'group') {
|
||||
return (
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ flex: 1 }}>{item.title}</span>
|
||||
<Tag color="blue">一级</Tag>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
if (item.kind === 'root') {
|
||||
return (
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ flex: 1 }}>{item.title}</span>
|
||||
<Tag color="blue">一级</Tag>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ flex: 1 }}>{item.title}</span>
|
||||
<Tag>二级</Tag>
|
||||
</span>
|
||||
)
|
||||
}}
|
||||
onChange={(value) => {
|
||||
if (typeof value === 'number' && value > 0) handleProfileChange(value)
|
||||
}}
|
||||
/>
|
||||
{selectedProfile?.tabDescription ? (
|
||||
<Typography.Text type="secondary">{selectedProfile.tabDescription}</Typography.Text>
|
||||
|
||||
Reference in New Issue
Block a user