diff --git a/app/admin/_components/CategoriesTab.tsx b/app/admin/_components/CategoriesTab.tsx index 768768c..0629f83 100644 --- a/app/admin/_components/CategoriesTab.tsx +++ b/app/admin/_components/CategoriesTab.tsx @@ -52,6 +52,7 @@ interface CategoryFieldMeta { interface CategoriesTabProps { showToast: (message: string, type?: 'success' | 'error') => void onDataChange?: () => void + isSuperAdmin?: boolean } const sanitizeOptionLabel = (value: string): string => { @@ -115,7 +116,7 @@ const normalizeOptionArray = (values: string[]): string[] => { return normalized } -export default function CategoriesTab({ showToast, onDataChange }: CategoriesTabProps) { +export default function CategoriesTab({ showToast, onDataChange, isSuperAdmin = false }: CategoriesTabProps) { const styles = useThemeStyles() const theme = useTheme() const { confirm, prompt } = useDialog() @@ -127,6 +128,7 @@ export default function CategoriesTab({ showToast, onDataChange }: CategoriesTab const [renamingOption, setRenamingOption] = useState>(new Map()) const [categoryFieldOptions, setCategoryFieldOptions] = useState([]) const [categoryFieldLoading, setCategoryFieldLoading] = useState(false) + const [categoryFieldSyncing, setCategoryFieldSyncing] = useState(false) const [savingFieldKey, setSavingFieldKey] = useState(null) const [isEditingFields, setIsEditingFields] = useState(false) const [categoryOrder, setCategoryOrder] = useState([]) @@ -268,6 +270,33 @@ export default function CategoriesTab({ showToast, onDataChange }: CategoriesTab fetchCategoryFieldOptions() }, [fetchCategoryFieldOptions]) + const handleSyncCategoryFields = useCallback(async () => { + if (!isSuperAdmin) { + showToast('仅最高权限账号可同步分类字段', 'error') + return + } + + try { + setCategoryFieldSyncing(true) + const response = await fetch('/api/category-fields', { + method: 'POST', + cache: 'no-store', + }) + if (!response.ok) { + const data = await response.json().catch(() => ({})) + throw new Error(data.error || '同步失败') + } + showToast('字段池已同步') + await Promise.all([fetchCategoryFieldOptions(), fetchData()]) + onDataChange?.() + } catch (error: any) { + console.error('[CategoriesTab] Failed to sync category fields:', error) + showToast(error?.message || '同步分类字段失败', 'error') + } finally { + setCategoryFieldSyncing(false) + } + }, [fetchCategoryFieldOptions, fetchData, isSuperAdmin, onDataChange, showToast]) + const handleCategoryLabelChange = useCallback((fieldKey: string, value: string) => { setCategoryLabelDrafts((prev) => { const next = new Map(prev) @@ -746,6 +775,16 @@ export default function CategoriesTab({ showToast, onDataChange }: CategoriesTab > {isEditingFields ? (categoryConfigSaving ? '保存中…' : '保存') : '编辑'} + {!isEditingFields && isSuperAdmin && ( + + )} diff --git a/app/admin/page.tsx b/app/admin/page.tsx index c52e492..a666050 100644 --- a/app/admin/page.tsx +++ b/app/admin/page.tsx @@ -295,8 +295,8 @@ const departmentCollator = useMemo(() => getDepartmentCollator(), []) )} - {/* 邀请管理 - 只有管理员及以上权限才能看到 */} - {sessionUser?.role === 'ADMIN' && ( + {/* 邀请管理 - 只有最高权限账号才能看到 */} + {sessionUser?.isSuperAdmin && (