fix: merge后14个测试修复+前端TS编译修复 - 895/895通过+前端零错误

This commit is contained in:
logan committed 2026-05-23 17:50:13 +08:00
1 parent 58eb78c987
commit b39c426317
24 files changed
+3918 -760

No files matched your search

+6
View File
@@ -9,6 +9,9 @@ export interface LoginResponse {
display_name: string;
role: string;
email: string | null;
data_source_permissions?: string;
custom_permissions?: string;
group_ids?: number[];
};
}
@@ -18,6 +21,9 @@ export interface MeResponse {
display_name: string;
role: string;
email: string | null;
data_source_permissions?: string;
custom_permissions?: string;
group_ids?: number[];
}
export const authApi = {
-2
View File
@@ -13,7 +13,6 @@ import {
} from '@codemirror/language';
import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
import { searchKeymap, highlightSelectionMatches } from '@codemirror/search';
import { rectangularSelection } from '@codemirror/rectangular-selection';
// ---------------------------------------------------------------------------
// Types
@@ -296,7 +295,6 @@ const SqlEditor: React.FC<SqlEditorProps> = ({
bracketMatching(),
closeBrackets(),
highlightSelectionMatches(),
rectangularSelection(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
appTheme,
oneDark,
+25 -28
View File
@@ -335,7 +335,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
table?: string
): boolean => {
if (!isLoggedIn) return false;
if (isAdmin) return true; // 管理员拥有所有数据源权限
if (user.role === 'admin') return true; // 管理员拥有所有数据源权限
const cache = permissionCacheRef.current;
const cacheKey = `${instanceId}:${action}:${database || '*'}:${table || '*'}`;
@@ -368,7 +368,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
cache.dataSource.set(cacheKey, hasPerm);
cache.timestamp = Date.now();
return hasPerm;
}, [user.dataSourcePermissions, user.role, isAdmin, isLoggedIn, isCacheValid]);
}, [user.dataSourcePermissions, user.role, isLoggedIn, isCacheValid]);
/** 批量检查数据源权限 */
const checkDataSourcePermissions = useCallback((
@@ -387,34 +387,31 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
/** 从服务器刷新用户权限 */
const refreshPermissions = useCallback(async (): Promise<void> => {
try {
const res = await authApi.getCurrentUser();
if (res.user) {
const u = res.user;
const role = u.role as UserRole;
const dataSourcePermissions: DataSourcePermission[] = u.data_source_permissions
? JSON.parse(u.data_source_permissions)
: [];
const customPermissions: Record<string, boolean> = u.custom_permissions
? JSON.parse(u.custom_permissions)
: {};
const u = await authApi.getMe();
const role = u.role as UserRole;
const dataSourcePermissions: DataSourcePermission[] = u.data_source_permissions
? JSON.parse(u.data_source_permissions)
: [];
const customPermissions: Record<string, boolean> = u.custom_permissions
? JSON.parse(u.custom_permissions)
: {};
const newUser: AuthUser = {
...user,
id: u.id,
username: u.username,
email: u.email || '',
role,
roleName: roleNameMap[role] || role,
groupIds: u.group_ids || [],
dataSourcePermissions,
customPermissions,
permissionsUpdatedAt: Date.now(),
};
const newUser: AuthUser = {
...user,
id: u.id,
username: u.username,
email: u.email || '',
role,
roleName: roleNameMap[role] || role,
groupIds: u.group_ids || [],
dataSourcePermissions,
customPermissions,
permissionsUpdatedAt: Date.now(),
};
setUser(newUser);
clearPermissionCache();
emitPermissionChange(newUser);
}
setUser(newUser);
clearPermissionCache();
emitPermissionChange(newUser);
} catch (error) {
console.error('刷新权限失败:', error);
}
+2 -2
View File
@@ -1,6 +1,6 @@
import { useState, useEffect, useCallback, useMemo } from 'react';
import {
Search, Download, Filter, X, ChevronDown, ChevronRight,
Search, Download, Filter, ChevronDown, ChevronRight,
FileText, User, Globe, CheckCircle2, XCircle, AlertTriangle,
BarChart3, Clock, RotateCcw,
} from 'lucide-react';
@@ -131,7 +131,7 @@ function exportLogsToCSV(logs: AuditLog[]) {
export default function AuditLogsPage() {
const [logs, setLogs] = useState<AuditLog[]>([]);
const [total, setTotal] = useState(0);
const [, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(true);
const pageSize = 20;
+3 -3
View File
@@ -2,8 +2,8 @@ import { useState, useEffect, useCallback, useMemo } from 'react';
import request from '../api/request';
import {
Search, Filter, ChevronDown, ChevronUp, AlertTriangle,
Info, CheckCircle, XCircle, Database, Table, FileSearch,
Shield, Loader2, Save, RotateCcw, Leaf, Server,
Info, XCircle, Database, Table, FileSearch,
Shield, Loader2, Leaf, Server,
} from 'lucide-react';
/* ------------------------------------------------------------------ */
@@ -136,7 +136,7 @@ export default function AuditRulesPage() {
const res = await request.get('/audit-rules', {
params: { db_type: dbType },
});
const data = (res as { data?: unknown[] }).data ?? (res as unknown[]);
const data = (res as { data?: unknown[] }).data ?? (res as unknown as unknown[]);
setRules(Array.isArray(data) ? data as AuditRule[] : []);
} catch {
setRules([]);
+2 -2
View File
@@ -2,9 +2,9 @@ import { useEffect, useRef, useState, useCallback, useMemo } from 'react';
import {
ClipboardList, Clock, CheckCircle, AlertTriangle,
Database, ChevronRight, X, AlertCircle, Info, Bell,
Activity, TrendingUp, Zap, Server, Plus, Search,
Activity, TrendingUp, Zap, Server, Search,
FileText, ArrowUpRight, ArrowDownRight, Minus,
Filter, Eye, Loader2, BarChart3,
Filter, Eye, BarChart3,
} from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { dbInstances, statusMap, statusColorMap, dbTypeColorMap, tickets, announcements } from '@/lib/mock';
+1 -2
View File
@@ -1,7 +1,7 @@
import { useState, useEffect, useCallback, useMemo } from 'react';
import {
BookOpen, Database, Table2, Search, Download, Columns3, Key, Code2, RefreshCw,
ChevronRight, ChevronDown, Hash, AlignLeft, Gauge, FolderOpen, ArrowRight,
ChevronRight, Hash, AlignLeft, Gauge, FolderOpen, ArrowRight,
FileJson, TableProperties, Info,
} from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
@@ -173,7 +173,6 @@ export default function DataDictionaryPage() {
const [activeTab, setActiveTab] = useState<TabKey>('columns');
const [loading, setLoading] = useState(false);
const [expandedDbs, setExpandedDbs] = useState<Set<string>>(new Set());
const [dbTreeExpanded, setDbTreeExpanded] = useState(true);
// Load instances
useEffect(() => {
+2 -2
View File
@@ -1,8 +1,8 @@
import { useState, useEffect, useCallback, useMemo } from 'react';
import {
Plus, Search, Edit2, Trash2, Server, Users, ChevronRight, X,
XCircle, Shield, Grid3x3, BarChart3, Clock, CheckCircle2,
Database, HardDrive, Cpu, Activity, Filter, RotateCcw, ChevronDown,
Shield, Grid3x3, Clock, CheckCircle2,
Database, HardDrive, Activity,
} from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { instanceGroupApi, type InstanceGroup } from '@/api/instanceGroup';
+3 -3
View File
@@ -2,8 +2,8 @@ import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
import {
Plus, X, AlertTriangle, CheckCircle, Play, Loader2,
ChevronDown, Clock, FileText, Sparkles, Star,
StarOff, Download, Search, RotateCcw, ArrowUpDown,
ArrowUp, ArrowDown, Eye, Hash, PanelLeftClose, PanelLeft,
StarOff, Download, Search, ArrowUpDown,
ArrowUp, ArrowDown, Eye, Hash, PanelLeftClose,
} from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { useActionPermission } from '@/hooks/useAuth';
@@ -12,7 +12,7 @@ import EmptyState from '@/components/EmptyState';
import { queryApi } from '@/api/query';
import { instanceApi } from '@/api/instance';
import SqlEditor from '@/components/SqlEditor';
import { queryTemplates, getTemplateSQL, getTemplatesForType } from '@/lib/queryTemplates';
import { getTemplateSQL, getTemplatesForType } from '@/lib/queryTemplates';
import type { DBType, QueryTemplate } from '@/lib/queryTemplates';
/* ------------------------------------------------------------------ */
+1 -1
View File
@@ -2,7 +2,7 @@ import { useState, useEffect, useCallback, useMemo } from 'react';
import {
Search, Clock, Database, AlertTriangle, ChevronDown, ChevronRight,
BarChart3, Play, Loader2, RefreshCw, Download, Lightbulb, X,
GitCompare, XCircle, FileText, Skull, Zap, CheckCircle2,
GitCompare, XCircle, Skull, Zap, CheckCircle2,
} from 'lucide-react';
import {
BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid,
+1 -34
View File
@@ -174,7 +174,7 @@ export default function TicketCreatePage() {
return;
}
setLoadingDatabases(true);
instanceApi.getDatabases?.(Number(instanceId))
instanceApi.listDatabases(Number(instanceId))
.then((res: unknown) => {
const data = (res as { databases?: string[] })?.databases
|| (res as string[])
@@ -240,39 +240,6 @@ export default function TicketCreatePage() {
}
}, [sqlContent, instanceId, database]);
/* ---------------------------------------------------------------- */
/* Pre-submit audit check */
/* ---------------------------------------------------------------- */
const handlePreSubmitAudit = useCallback(async () => {
if (!title.trim() || !sqlContent.trim() || !instanceId || !database || !reason.trim()) {
setError('请填写所有必填项');
return;
}
// If already audited and SQL hasn't changed, go directly to step 3
if (auditResult) {
setStep(3);
return;
}
// Auto-audit before submission
setAuditing(true);
setError('');
try {
const result = await ticketApi.audit({
sql_content: sqlContent,
instance_id: Number(instanceId),
database,
}) as unknown as AuditResult;
setAuditResult(result);
setStep(3);
} catch (e: unknown) {
const err = e as { response?: { data?: { detail?: string } } };
setError(err?.response?.data?.detail || '预审核失败,请检查 SQL 语法');
} finally {
setAuditing(false);
}
}, [title, sqlContent, instanceId, database, reason, auditResult]);
/* ---------------------------------------------------------------- */
/* Submit handler */
/* ---------------------------------------------------------------- */
+2 -4
View File
@@ -198,15 +198,13 @@ export default function TicketDetailPage() {
/* Permission checks */
/* ---------------------------------------------------------------- */
const { isAdminOrDba, isApplicant, canApprove, canExecute, canRollback, canCancel } = useMemo(() => {
const { canApprove, canExecute, canRollback, canCancel } = useMemo(() => {
if (!ticket) {
return { isAdminOrDba: false, isApplicant: false, canApprove: false, canExecute: false, canRollback: false, canCancel: false };
return { canApprove: false, canExecute: false, canRollback: false, canCancel: false };
}
const adminOrDba = auth.user.role === 'admin' || auth.user.role === 'dba';
const applicant = ticket.applicant_id === auth.user.id;
return {
isAdminOrDba: adminOrDba,
isApplicant: applicant,
canApprove: adminOrDba && (ticket.status === 'pending' || ticket.status === 'reviewing'),
canExecute: adminOrDba && ticket.status === 'approved',
canRollback: adminOrDba && (ticket.status === 'success' || ticket.status === 'failed'),
+3 -2
View File
@@ -1,9 +1,9 @@
import { useState, useEffect, useCallback, useMemo } from 'react';
import {
Plus, Search, Eye, CheckCircle, XCircle, Play, RotateCcw,
ChevronRight, FileCode, History, Undo2, XCircle as XIcon,
FileCode, History, Undo2, XCircle as XIcon,
Clock, AlertTriangle, AlertCircle, Info, ChevronLeft,
Download, Filter, X, Loader2, BarChart3, Users, Calendar,
Filter, X, Loader2, Users, Calendar,
CheckSquare, Square, ArrowUpDown, FileDown, Ban,
} from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
@@ -540,6 +540,7 @@ export default function TicketsPage() {
? <CheckSquare className="w-4 h-4 text-blue-400" />
: <Square className="w-4 h-4 text-[var(--dg-text-muted)]" />
}
</button>
</th>
<th className="text-left px-4 py-3 font-semibold">工单号</th>
<th className="text-left px-4 py-3 font-semibold">标题</th>
+2 -2
View File
@@ -2,10 +2,10 @@ import { useState, useEffect, useCallback, useMemo } from 'react';
import {
Plus, Search, Edit2, Trash2, XCircle, Eye, Download, Upload,
CheckSquare, Square, X, RotateCcw, KeyRound, ChevronDown,
UserCheck, UserX, Filter, MoreHorizontal, Lock,
UserCheck, UserX, Filter,
} from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { roles, users as mockUsers } from '@/lib/mock';
import { users as mockUsers } from '@/lib/mock';
import { userApi } from '@/api/user';
/* ───────── Types ───────── */
+1 -1
View File
@@ -3,7 +3,7 @@ import {
Plus, Edit2, Eye, ToggleLeft, ToggleRight, GitBranch, Users, CheckCircle,
ArrowRight, Shield, Trash2, X, ChevronDown, ChevronUp,
Save, Play, Copy, History, TestTube, AlertTriangle,
Loader2, Check, XCircle, MessageSquare,
Loader2, Check, XCircle,
} from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { workflows as initialWorkflows, dbTypeColorMap } from '@/lib/mock';