Prechádzať zdrojové kódy

fix:初始化页面接口联调

韩洋 3 týždňov pred
rodič
commit
ce85a33b45

+ 3 - 3
default/rsbuild.config.ts

@@ -14,9 +14,9 @@ export default defineConfig(({ envMode }) => {
     process.env.VITE_REACT_APP_SERVER_URL ||
     env.rawPublicVars.VITE_REACT_APP_SERVER_URL ||
     // 'http://192.168.100.26:3000',
-    // 'http://47.117.92.63:8081',
-    // 'http://192.168.100.184:3000',
-    'http://192.168.20.70:3000'
+    // 'http://47.117.92.63:8081'
+    'http://192.168.100.184:3000'
+    // 'http://192.168.20.70:3000'
 
   const isProd = envMode === 'production'
   const devProxy = Object.fromEntries(

+ 4 - 1
default/src/features/auth/hooks/use-auth-redirect.ts

@@ -23,6 +23,7 @@ import { getCurrentPermissionsWithRole } from '@/features/permissions/api'
 import type { User } from '@/features/users/types'
 import { getSelf } from '@/lib/api'
 import { resolveLandingPath } from '@/lib/landing-page'
+import { ROLE } from '@/lib/roles'
 import { type AuthUser, useAuthStore } from '@/stores/auth-store'
 
 import { saveUserId } from '../lib/storage'
@@ -71,7 +72,9 @@ export function useAuthRedirect() {
       const self = await getSelf()
       if (self?.success && self.data) {
         const user = self.data as AuthUser
-        const permissionSnapshot = await getCurrentPermissionsWithRole()
+        const permissionSnapshot = await getCurrentPermissionsWithRole(
+          user.role === ROLE.SUPER_ADMIN
+        )
         auth.setUser({
           ...user,
           permissions: {

+ 4 - 1
default/src/features/auth/otp/components/otp-form.tsx

@@ -56,6 +56,7 @@ import {
   cleanBackupCode,
 } from '@/features/auth/lib/validation'
 import { getCurrentPermissionsWithRole } from '@/features/permissions/api'
+import { ROLE } from '@/lib/roles'
 import { cn } from '@/lib/utils'
 import { type AuthUser, useAuthStore } from '@/stores/auth-store'
 
@@ -108,8 +109,10 @@ export function OtpForm({ className, ...props }: OtpFormProps) {
       }
 
       // Update auth store
-      const permissionSnapshot = await getCurrentPermissionsWithRole()
       const user = userData as AuthUser
+      const permissionSnapshot = await getCurrentPermissionsWithRole(
+        user.role === ROLE.SUPER_ADMIN
+      )
       auth.setUser({
         ...user,
         permissions: {

+ 29 - 14
default/src/features/permissions/api.ts

@@ -46,6 +46,7 @@ export interface PermissionItem {
   has_permission?: boolean
   checked?: boolean
   selected?: boolean
+  is_only_open_for_root?: number
   children?: PermissionItem[]
   actions?: PermissionItem[]
   permissions?: PermissionItem[]
@@ -79,13 +80,14 @@ function normalizePermissionList(
   )
 }
 
-function permissionHasRole(permission: PermissionItem) {
-  return (
-    permission.has_permission ??
-    permission.checked ??
-    permission.selected ??
-    false
-  )
+function permissionHasRole(permission: PermissionItem, isSuperAdmin: boolean) {
+  if (isSuperAdmin) {
+    // 超级管理员:is_only_open_for_root=1 直接显示,否则看 has_permission
+    if (permission.is_only_open_for_root === 1) return true
+    return permission.has_permission ?? false
+  }
+  // 其余角色:只看 has_permission
+  return permission.has_permission ?? false
 }
 
 function getPermissionCode(permission: PermissionItem) {
@@ -104,6 +106,7 @@ function getPermissionCode(permission: PermissionItem) {
 
 function collectPermissionCodes(
   permissions: PermissionItem[],
+  isSuperAdmin: boolean,
   codes = new Set<string>()
 ) {
   for (const permission of permissions) {
@@ -117,14 +120,20 @@ function collectPermissionCodes(
 
     for (const relation of childPermissions) {
       const target = relation.ExtPermission ?? relation
-      if (permissionHasRole(relation) || permissionHasRole(target)) {
+      if (
+        permissionHasRole(relation, isSuperAdmin) ||
+        permissionHasRole(target, isSuperAdmin)
+      ) {
         const code = getPermissionCode(target)
         if (code) codes.add(code)
       }
-      collectPermissionCodes([target], codes)
+      collectPermissionCodes([target], isSuperAdmin, codes)
     }
 
-    if (permissionHasRole(permission) || codes.size > beforeSize) {
+    if (
+      permissionHasRole(permission, isSuperAdmin) ||
+      codes.size > beforeSize
+    ) {
       const code = getPermissionCode(permission)
       if (code) codes.add(code)
     }
@@ -134,10 +143,11 @@ function collectPermissionCodes(
 }
 
 export function toCurrentPermissionSnapshot(
-  permissions: PermissionItem[]
+  permissions: PermissionItem[],
+  isSuperAdmin = false
 ): CurrentPermissionSnapshot {
   return {
-    codes: [...collectPermissionCodes(permissions)],
+    codes: [...collectPermissionCodes(permissions, isSuperAdmin)],
   }
 }
 
@@ -158,6 +168,11 @@ export async function getPermissionsWithRole(
   return normalizePermissionList(res.data)
 }
 
-export async function getCurrentPermissionsWithRole(): Promise<CurrentPermissionSnapshot> {
-  return toCurrentPermissionSnapshot(await getPermissionsWithRole())
+export async function getCurrentPermissionsWithRole(
+  isSuperAdmin = false
+): Promise<CurrentPermissionSnapshot> {
+  return toCurrentPermissionSnapshot(
+    await getPermissionsWithRole(),
+    isSuperAdmin
+  )
 }

+ 14 - 5
default/src/features/roles/index.tsx

@@ -18,7 +18,7 @@ For commercial licensing, please contact support@quantumnous.com
 */
 import { zodResolver } from '@hookform/resolvers/zod'
 import { useQuery, useQueryClient } from '@tanstack/react-query'
-import type { ColumnDef } from '@tanstack/react-table'
+import type { ColumnDef, PaginationState } from '@tanstack/react-table'
 import { Eye, Loader2, Pencil, Trash2, Plus } from 'lucide-react'
 import { useState } from 'react'
 import { useForm } from 'react-hook-form'
@@ -571,6 +571,10 @@ export function RolesSettings() {
   const [currentRole, setCurrentRole] = useState<Role | null>(null)
   const [isSubmitting, setIsSubmitting] = useState(false)
   const [refreshTrigger, setRefreshTrigger] = useState(0)
+  const [pagination, setPagination] = useState<PaginationState>({
+    pageIndex: 0,
+    pageSize: 20,
+  })
   const canViewRole = hasPermissionCode(currentUser, PERMISSION_CODES.ROLE_VIEW)
   const canCreateRole = hasPermissionCode(
     currentUser,
@@ -915,12 +919,15 @@ export function RolesSettings() {
     isLoading,
     isFetching,
   } = useQuery({
-    queryKey: ['roles', refreshTrigger],
+    queryKey: ['roles', refreshTrigger, pagination.pageIndex, pagination.pageSize],
     queryFn: async () => {
       let result
 
       try {
-        result = await getRoles({ p: 1, page_size: 20 })
+        result = await getRoles({
+          p: pagination.pageIndex + 1,
+          page_size: pagination.pageSize,
+        })
       } catch {
         return { items: localRoles, total: localRoles.length }
       }
@@ -950,8 +957,10 @@ export function RolesSettings() {
   const { table } = useDataTable({
     data: roles,
     columns,
-    pagination: { pageIndex: 0, pageSize: 10 },
-    totalCount: roles.length,
+    pagination,
+    onPaginationChange: setPagination,
+    totalCount: rolesData?.total ?? roles.length,
+    manualPagination: true,
   })
 
   const onSubmit = async (data: RoleFormValues) => {

+ 26 - 14
default/src/features/setup/api.ts

@@ -42,22 +42,34 @@ export function buildSetupPayload(
   values: SetupFormValues,
   rootInitialized: boolean
 ) {
-  const { usageMode, resource, role, ...rest } = values
+  const { resource, role, ...rest } = values
+
+  const ROLE_TYPE_MAP: Record<string, string> = {
+    root: 'root',
+    admin: 'admin',
+    common: 'user',
+  }
 
   const basePayload = {
-    SelfUseModeEnabled: usageMode === 'self',
-    DemoSiteEnabled: usageMode === 'demo',
-    QuotaForNewUser: resource.quotaForNewUser,
-    PreConsumedQuota: resource.preConsumedQuota,
-    QuotaPerUnit: resource.quotaPerUnit,
-    EnabledModules: resource.enabledModules,
-    DefaultRoles: role.roles.map((r) => ({
-      key: r.key,
-      name: r.name,
-      description: r.description,
-      is_locked: r.isLocked,
-      permission_codes: Object.values(r.permissions).flat(),
-    })),
+    enabled_modules: resource.enabledModules,
+    custom_roles: role.roles.map((r) => {
+      const roleType = ROLE_TYPE_MAP[r.key] ?? 'customize'
+      const entry: Record<string, unknown> = {
+        role_type: roleType,
+        role_name: r.name,
+      }
+      if (r.description) {
+        entry.role_desc = r.description
+      }
+      if (roleType !== 'root') {
+        entry.permission_codes = Object.entries(r.permissions)
+          .filter(([moduleCode]) =>
+            resource.enabledModules.includes(moduleCode)
+          )
+          .flatMap(([, codes]) => codes)
+      }
+      return entry
+    }),
   }
 
   if (rootInitialized) {

+ 2 - 1
default/src/hooks/use-sidebar-data.ts

@@ -86,6 +86,7 @@ export function useSidebarData(): SidebarData {
             title: t('Quota Management'),
             url: '/quota',
             icon: Gauge,
+            permissionCode: PERMISSION_CODES.QUOTA_VIEW,
           },
         ],
       },
@@ -152,7 +153,7 @@ export function useSidebarData(): SidebarData {
             title: t('Models'),
             url: '/pricing',
             icon: Box,
-            permissionCode: PERMISSION_CODES.PRICING_VIEW,
+            permissionCode: PERMISSION_CODES.MODELS_LIST_VIEW,
           },
           // {
           //   title: t('Wallet'),

+ 3 - 2
default/src/lib/admin-permissions.ts

@@ -19,6 +19,7 @@ export const ADMIN_PERMISSION_ACTIONS = {
 
 export const PERMISSION_CODES = {
   DASHBOARD_VIEW: 'dashboard.view',
+  QUOTA_VIEW: 'quota.view',
   CHANNEL_VIEW: 'channel.view',
   CHANNEL_CREATE: 'channel.create',
   CHANNEL_UPDATE: 'channel.update',
@@ -52,7 +53,8 @@ export const PERMISSION_CODES = {
   KEYS_UPDATE: 'keys.update',
   KEYS_DELETE: 'keys.delete',
   KEYS_DISABLE: 'keys.disable',
-  PRICING_VIEW: 'pricing.view',
+  MODELS_LIST_VIEW: 'pricing.view',
+  PRICING_VIEW: 'model-pricing.view',
   USAGE_LOGS_VIEW: 'usage-logs.view',
   USAGE_LOGS_ALL: 'usage-logs.all',
   AUDIT_LOGS_VIEW: 'audit-logs.view',
@@ -112,7 +114,6 @@ export function hasPermissionCode(
   code: string
 ): boolean {
   if (!user) return false
-  if (user.role === ROLE.SUPER_ADMIN) return true
   return user.permissions?.codes?.includes(code) === true
 }
 

+ 1 - 1
default/src/lib/landing-page.ts

@@ -36,7 +36,7 @@ export const LANDING_PAGE_CANDIDATES: ReadonlyArray<{
   { url: '/tenants', code: PERMISSION_CODES.TENANT_VIEW },
   { url: '/profile', code: PERMISSION_CODES.PROFILE_VIEW },
   { url: '/keys', code: PERMISSION_CODES.KEYS_VIEW },
-  { url: '/pricing', code: PERMISSION_CODES.PRICING_VIEW },
+  { url: '/pricing', code: PERMISSION_CODES.MODELS_LIST_VIEW },
   { url: '/usage-logs/common', code: PERMISSION_CODES.USAGE_LOGS_VIEW },
   { url: '/usage-logs/audit', code: PERMISSION_CODES.AUDIT_LOGS_VIEW },
   { url: '/system-settings/site', code: PERMISSION_CODES.SETTINGS_VIEW },

+ 4 - 1
default/src/routes/_authenticated/route.tsx

@@ -21,6 +21,7 @@ import { createFileRoute, redirect } from '@tanstack/react-router'
 import { AuthenticatedLayout } from '@/components/layout'
 import { getCurrentPermissionsWithRole } from '@/features/permissions/api'
 import { getSelf } from '@/lib/api'
+import { ROLE } from '@/lib/roles'
 import { useAuthStore } from '@/stores/auth-store'
 
 // 内存中的验证标记,避免同一会话中重复验证
@@ -48,7 +49,9 @@ export const Route = createFileRoute('/_authenticated')({
       )
       if (res?.success && res.data) {
         // 验证成功,更新用户信息(可能有变化)
-        const permissions = await getCurrentPermissionsWithRole().catch(() =>
+        const permissions = await getCurrentPermissionsWithRole(
+          res.data.role === ROLE.SUPER_ADMIN
+        ).catch(() =>
           auth.user?.permissions?.codes
             ? { codes: auth.user.permissions.codes }
             : { codes: [] }

+ 1 - 1
default/src/routes/pricing/index.tsx

@@ -52,7 +52,7 @@ export const Route = createFileRoute('/pricing/')({
         search: { redirect: location.href },
       })
     }
-    if (!hasPermissionCode(auth.user, PERMISSION_CODES.PRICING_VIEW)) {
+    if (!hasPermissionCode(auth.user, PERMISSION_CODES.MODELS_LIST_VIEW)) {
       throw redirect({ to: '/403' })
     }
   },