feat(content): 分组对所有内容类型生效,统一分区/分组/条目模型
- 分区=容器,分组=任意类型的可选子容器,条目可挂分区或分组(直属分区) - catalog 所有类型统一输出 groups + items,条目查询按节点取 - 详情/侧栏/首页卡片预览支持所有类型的分组;多组显示小标题 + 未分组 - 后台「分区」「侧栏导航」对所有类型可建组;「内容」弹窗分组可选直属分区,编辑可换组 - 修复首页卡片配置为「整个分区」时预览为空 - 测试 59 passed
This commit is contained in:
@@ -503,7 +503,7 @@ function SidebarForm({
|
||||
|
||||
{ordered.map((category, index) => {
|
||||
const visible = !value.hidden.includes(category.id)
|
||||
const groups = category.kind === 'apps' ? orderedGroups(category) : []
|
||||
const groups = orderedGroups(category)
|
||||
|
||||
return (
|
||||
<div className="admin-nav-block" key={category.id}>
|
||||
@@ -539,7 +539,7 @@ function SidebarForm({
|
||||
</div>
|
||||
))}
|
||||
|
||||
{category.kind === 'apps' && (
|
||||
{(
|
||||
<div className="admin-nav-group-row">
|
||||
<NewGroupRow sectionId={category.id} onReload={onReload} />
|
||||
</div>
|
||||
@@ -762,12 +762,8 @@ function CategoryManager({
|
||||
onReload={onReload}
|
||||
onDelete={onDelete}
|
||||
/>
|
||||
{category.kind === 'apps' && (
|
||||
<>
|
||||
<BlockSelect section={category} onReload={onReload} />
|
||||
<GroupManager section={category} onReload={onReload} />
|
||||
</>
|
||||
)}
|
||||
<BlockSelect section={category} onReload={onReload} />
|
||||
<GroupManager section={category} onReload={onReload} />
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1094,20 +1090,21 @@ function ContentManager({
|
||||
const entries: EntryRow[] =
|
||||
section === undefined
|
||||
? []
|
||||
: section.kind === 'apps'
|
||||
? (section.groups ?? []).flatMap((group) =>
|
||||
: [
|
||||
...(section.groups ?? []).flatMap((group) =>
|
||||
(group.items ?? []).map((item) => ({
|
||||
...item,
|
||||
groupName: group.name,
|
||||
sectionId: section.id,
|
||||
groupId: group.id,
|
||||
})),
|
||||
)
|
||||
: (section.items ?? []).map((item) => ({
|
||||
),
|
||||
...(section.items ?? []).map((item) => ({
|
||||
...item,
|
||||
groupName: undefined,
|
||||
sectionId: section.id,
|
||||
}))
|
||||
})),
|
||||
]
|
||||
|
||||
const removeEntry = async () => {
|
||||
if (pendingEntry === null) return
|
||||
@@ -1274,7 +1271,7 @@ function EntryDialog({
|
||||
|
||||
const section =
|
||||
categories.find((category) => category.id === sectionId) ?? categories[0]
|
||||
const groups = section?.kind === 'apps' ? (section.groups ?? []) : []
|
||||
const groups = section?.groups ?? []
|
||||
|
||||
// 打开时重置:新建用当前选择,编辑先拉完整条目
|
||||
useEffect(() => {
|
||||
@@ -1284,7 +1281,11 @@ function EntryDialog({
|
||||
const startSection =
|
||||
defaultLocation?.sectionId ?? categories[0]?.id ?? ''
|
||||
setSectionId(startSection)
|
||||
setGroupId(defaultLocation?.groupId ?? '')
|
||||
setGroupId(
|
||||
defaultLocation?.groupId ??
|
||||
categories.find((category) => category.id === startSection)?.groups?.[0]?.id ??
|
||||
'',
|
||||
)
|
||||
|
||||
if (entryKey === null) {
|
||||
setLoading(false)
|
||||
@@ -1321,19 +1322,16 @@ function EntryDialog({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open, entryKey])
|
||||
|
||||
// 分区切换后保证分组仍然合法
|
||||
// 分区切换后保证分组仍然合法(空字符串 = 直属分区)
|
||||
useEffect(() => {
|
||||
if (section?.kind !== 'apps') {
|
||||
setGroupId('')
|
||||
return
|
||||
}
|
||||
if (!groups.some((group) => group.id === groupId)) {
|
||||
if (section === undefined) return
|
||||
if (groupId !== '' && !groups.some((group) => group.id === groupId)) {
|
||||
setGroupId(groups[0]?.id ?? '')
|
||||
}
|
||||
}, [section, groups, groupId])
|
||||
|
||||
const nodeKey =
|
||||
section === undefined ? '' : section.kind === 'apps' ? groupId : section.id
|
||||
section === undefined ? '' : groupId !== '' ? groupId : section.id
|
||||
|
||||
const update = (patch: Partial<EntryForm>) =>
|
||||
setForm((previous) => ({ ...previous, ...patch }))
|
||||
@@ -1430,13 +1428,16 @@ function EntryDialog({
|
||||
onChange={setSectionId}
|
||||
/>
|
||||
</div>
|
||||
{section?.kind === 'apps' && (
|
||||
<div style={{ width: 220 }}>
|
||||
{section !== undefined && (
|
||||
<div style={{ width: 240 }}>
|
||||
<Select
|
||||
options={groups.map((group) => ({
|
||||
value: group.id,
|
||||
label: group.name,
|
||||
}))}
|
||||
options={[
|
||||
{ value: '', label: '直属分区(不分组)' },
|
||||
...groups.map((group) => ({
|
||||
value: group.id,
|
||||
label: group.name,
|
||||
})),
|
||||
]}
|
||||
value={groupId}
|
||||
onChange={setGroupId}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user