diff --git a/apps/web/eslint.config.mjs b/apps/web/eslint.config.mjs index 119310b..fb2f31b 100644 --- a/apps/web/eslint.config.mjs +++ b/apps/web/eslint.config.mjs @@ -19,12 +19,7 @@ const eslintConfig = defineConfig([ "react-hooks/refs": "off", }, }, - globalIgnores([ - ".next/**", - "out/**", - "build/**", - "next-env.d.ts", - ]), + globalIgnores([".next/**", "out/**", "build/**", "next-env.d.ts"]), ]); -export default eslintConfig; \ No newline at end of file +export default eslintConfig; diff --git a/apps/web/src/app/(admin)/apps/page.tsx b/apps/web/src/app/(admin)/apps/page.tsx index 1d6c2c5..fae5fef 100644 --- a/apps/web/src/app/(admin)/apps/page.tsx +++ b/apps/web/src/app/(admin)/apps/page.tsx @@ -113,10 +113,7 @@ export default function AdminAppsPage() { return (
{/* 操作确认弹窗 */} - !open && setActionTarget(null)} - > + !open && setActionTarget(null)}> @@ -195,7 +192,11 @@ export default function AdminAppsPage() {
- +
{app.name}
@@ -211,9 +212,7 @@ export default function AdminAppsPage() { {app.creator_name} - - {statusLabels[app.status]} - + {statusLabels[app.status]} {visibilityLabels[app.visibility] || app.visibility} diff --git a/apps/web/src/app/(admin)/audit/page.tsx b/apps/web/src/app/(admin)/audit/page.tsx index 94f241c..d12b49e 100644 --- a/apps/web/src/app/(admin)/audit/page.tsx +++ b/apps/web/src/app/(admin)/audit/page.tsx @@ -90,9 +90,7 @@ export default function AuditPage() { {log.user_name || log.user_id.slice(0, 8)} - - {log.action} - + {log.action} {log.resource_type}/{log.resource_id.slice(0, 8)} diff --git a/apps/web/src/app/(admin)/dashboard/page.tsx b/apps/web/src/app/(admin)/dashboard/page.tsx index 2c0dc37..bb01845 100644 --- a/apps/web/src/app/(admin)/dashboard/page.tsx +++ b/apps/web/src/app/(admin)/dashboard/page.tsx @@ -4,7 +4,15 @@ import { useQuery } from "@tanstack/react-query"; import api from "@/lib/api"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; -import { Users, AppWindow, Activity, MessageCircle, Target, DollarSign, type LucideIcon } from "lucide-react"; +import { + Users, + AppWindow, + Activity, + MessageCircle, + Target, + DollarSign, + type LucideIcon, +} from "lucide-react"; interface OverviewStats { total_users: number; @@ -15,7 +23,15 @@ interface OverviewStats { monthly_cost: number; } -function StatCard({ title, value, icon: Icon }: { title: string; value: string | number; icon: LucideIcon }) { +function StatCard({ + title, + value, + icon: Icon, +}: { + title: string; + value: string | number; + icon: LucideIcon; +}) { return ( @@ -63,7 +79,11 @@ export default function DashboardPage() { - +
diff --git a/apps/web/src/app/(admin)/layout.tsx b/apps/web/src/app/(admin)/layout.tsx index 534a182..692744e 100644 --- a/apps/web/src/app/(admin)/layout.tsx +++ b/apps/web/src/app/(admin)/layout.tsx @@ -75,9 +75,11 @@ export default function AdminLayout({ children }: { children: React.ReactNode }) /> )} -
); } diff --git a/apps/web/src/app/(auth)/login/page.tsx b/apps/web/src/app/(auth)/login/page.tsx index c2cf982..89c40fd 100644 --- a/apps/web/src/app/(auth)/login/page.tsx +++ b/apps/web/src/app/(auth)/login/page.tsx @@ -57,18 +57,12 @@ export default function LoginPage() { const user = useAuthStore.getState().user; // 平台管理员不绑定机构,登录后保留 super_admin 身份; // 仅机构管理员在所选机构与自身归属不一致时才触发切换 - if ( - user && - user.role === "admin" && - user.org_id !== selectedOrg - ) { + if (user && user.role === "admin" && user.org_id !== selectedOrg) { await switchOrg(selectedOrg); } router.push(user?.role === "super_admin" ? "/platform/overview" : "/store"); } catch (err) { - setErrorMsg( - err instanceof Error ? err.message : "登录失败,请检查账号和密码" - ); + setErrorMsg(err instanceof Error ? err.message : "登录失败,请检查账号和密码"); } finally { setLoading(false); } @@ -85,162 +79,144 @@ export default function LoginPage() { return (
- {/* 左侧品牌区 - 桌面端显示 */} -
-
-
-
- -
-
-

- AI 智能应用平台 -

-

- 提升效能 · 赋能智慧办公 -

-
-
- -

- 面向政务与高校场景的一站式 AI - 应用平台,集成文档生成、智能问答、数据分析等核心能力,助力组织数智化转型。 -

- -
- {features.map(({ icon: Icon, text }) => ( -
-
- -
- {text} + {/* 左侧品牌区 - 桌面端显示 */} +
+
+
+
+
- ))} +
+

AI 智能应用平台

+

提升效能 · 赋能智慧办公

+
+
+ +

+ 面向政务与高校场景的一站式 AI + 应用平台,集成文档生成、智能问答、数据分析等核心能力,助力组织数智化转型。 +

+ +
+ {features.map(({ icon: Icon, text }) => ( +
+
+ +
+ {text} +
+ ))} +
-
- {/* 右侧登录区 */} -
-
- {/* 移动端标题 - 仅在小屏显示 */} -
- -

AI 智能应用平台

-

- 提升效能 · 赋能智慧办公 -

-
+ {/* 右侧登录区 */} +
+
+ {/* 移动端标题 - 仅在小屏显示 */} +
+ +

AI 智能应用平台

+

提升效能 · 赋能智慧办公

+
- {/* 表单区域 */} -
-

- 欢迎登录 -

-

- 请选择机构并输入账号密码 -

+ {/* 表单区域 */} +
+

+ 欢迎登录 +

+

请选择机构并输入账号密码

-
- {errorMsg && ( -
- {errorMsg} -
- )} - -
- - {orgs.length > 0 ? ( - - ) : ( - + + {errorMsg && ( +
+ {errorMsg} +
)} -
-
-
+ +
+ + setEmail(e.target.value)} + autoComplete="email" + required + className="h-11 rounded-xl border-gray-200 bg-gray-50/50 px-4 focus:ring-2 focus:ring-blue-500/40 focus:border-blue-400 hover:border-gray-300" + /> +
+ +
+ + setPassword(e.target.value)} + autoComplete="current-password" + required + className="h-11 rounded-xl border-gray-200 bg-gray-50/50 px-4 focus:ring-2 focus:ring-blue-500/40 focus:border-blue-400 hover:border-gray-300" + /> +
+ +
+ {loading ? "登录中..." : "登 录"} + + -
- - setPassword(e.target.value)} - autoComplete="current-password" - required - className="h-11 rounded-xl border-gray-200 bg-gray-50/50 px-4 focus:ring-2 focus:ring-blue-500/40 focus:border-blue-400 hover:border-gray-300" - /> + 申请注册 +
- - - -
- 还没有账号?{" "} - - 申请注册 - -
- -
- 本系统仅限授权人员使用 · 数据安全等级:机构内部 +
+ 本系统仅限授权人员使用 · 数据安全等级:机构内部 +
-
); } diff --git a/apps/web/src/app/(auth)/register/page.tsx b/apps/web/src/app/(auth)/register/page.tsx index 0f084c3..b641fa0 100644 --- a/apps/web/src/app/(auth)/register/page.tsx +++ b/apps/web/src/app/(auth)/register/page.tsx @@ -39,7 +39,12 @@ export default function RegisterPage() { setLoading(true); try { const res = await api.post<{ - user: { id: string; name: string; email: string; role: "user" | "super_admin" | "admin" | "creator" }; + user: { + id: string; + name: string; + email: string; + role: "user" | "super_admin" | "admin" | "creator"; + }; access_token: string; }>("/api/v1/auth/register", { name, email, password }); diff --git a/apps/web/src/app/(portal)/chat/[appId]/page.tsx b/apps/web/src/app/(portal)/chat/[appId]/page.tsx index 7da9ab3..24cfb7d 100644 --- a/apps/web/src/app/(portal)/chat/[appId]/page.tsx +++ b/apps/web/src/app/(portal)/chat/[appId]/page.tsx @@ -18,10 +18,7 @@ const ANALYSIS_SLUGS = new Set(["analysis-agent"]); export default function AppPage() { const { appId: slugOrId } = useParams<{ appId: string }>(); - const isUUID = - /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test( - slugOrId - ); + const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(slugOrId); const { data: appBySlug, isLoading: slugLoading } = useQuery({ queryKey: ["chatApp", slugOrId], @@ -32,9 +29,7 @@ export default function AppPage() { const { data: appById, isLoading: idLoading } = useQuery({ queryKey: ["chatAppById", slugOrId], queryFn: async () => { - const results = await api.get<{ items: App[] }>( - `/api/v1/store/apps?page_size=50` - ); + const results = await api.get<{ items: App[] }>(`/api/v1/store/apps?page_size=50`); return results.items?.find((a) => a.id === slugOrId) || null; }, enabled: isUUID, diff --git a/apps/web/src/app/(portal)/create/page.tsx b/apps/web/src/app/(portal)/create/page.tsx index b04427a..6543fdf 100644 --- a/apps/web/src/app/(portal)/create/page.tsx +++ b/apps/web/src/app/(portal)/create/page.tsx @@ -10,12 +10,7 @@ import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { AlertDialog, AlertDialogAction, @@ -35,16 +30,7 @@ import { } from "@/components/ui/select"; import type { App, Category, KnowledgeBase } from "@/lib/types"; import { toast } from "sonner"; -import { - Plus, - Pencil, - Trash2, - Send, - Eye, - BookOpen, - Settings2, - BarChart3, -} from "lucide-react"; +import { Plus, Pencil, Trash2, Send, Eye, BookOpen, Settings2, BarChart3 } from "lucide-react"; const statusLabels: Record = { draft: "草稿", @@ -54,10 +40,7 @@ const statusLabels: Record = { archived: "已归档", }; -const statusColors: Record< - string, - "default" | "secondary" | "destructive" | "outline" -> = { +const statusColors: Record = { draft: "outline", pending_review: "secondary", approved: "default", @@ -68,11 +51,11 @@ const statusColors: Record< import { appTypeConfigs } from "@/lib/app-type-config"; const appTypeLabels: Record = Object.fromEntries( - Object.entries(appTypeConfigs).map(([k, v]) => [k, v.label]) + Object.entries(appTypeConfigs).map(([k, v]) => [k, v.label]), ); const appTypeColors: Record = Object.fromEntries( - Object.entries(appTypeConfigs).map(([k, v]) => [k, v.badgeColor]) + Object.entries(appTypeConfigs).map(([k, v]) => [k, v.badgeColor]), ); const visibilityLabels: Record = { @@ -165,9 +148,7 @@ export default function CreatePage() { id: string; name: string; } | null>(null); - const [activeTab, setActiveTab] = useState< - "basic" | "prompt" | "runtime" | "advanced" - >("basic"); + const [activeTab, setActiveTab] = useState<"basic" | "prompt" | "runtime" | "advanced">("basic"); const { data: myApps } = useQuery({ queryKey: ["creatorApps"], @@ -182,7 +163,9 @@ export default function CreatePage() { const { data: knowledgeBases } = useQuery({ queryKey: ["knowledgeBases", user?.org_id], queryFn: () => - api.get(`/api/v1/knowledge${user?.org_id ? `?org_id=${user.org_id}` : ""}`).catch(() => []), + api + .get(`/api/v1/knowledge${user?.org_id ? `?org_id=${user.org_id}` : ""}`) + .catch(() => []), }); const createApp = useMutation({ @@ -206,8 +189,7 @@ export default function CreatePage() { }); const submitReview = useMutation({ - mutationFn: (id: string) => - api.post(`/api/v1/creator/apps/${id}/submit-review`), + mutationFn: (id: string) => api.post(`/api/v1/creator/apps/${id}/submit-review`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["creatorApps"] }); toast.success("已提交审核"); @@ -216,8 +198,7 @@ export default function CreatePage() { }); const withdrawReview = useMutation({ - mutationFn: (id: string) => - api.post(`/api/v1/creator/apps/${id}/withdraw`), + mutationFn: (id: string) => api.post(`/api/v1/creator/apps/${id}/withdraw`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["creatorApps"] }); toast.success("已撤回审核"); @@ -226,8 +207,7 @@ export default function CreatePage() { }); const requestDelist = useMutation({ - mutationFn: (id: string) => - api.post(`/api/v1/creator/apps/${id}/request-delist`), + mutationFn: (id: string) => api.post(`/api/v1/creator/apps/${id}/request-delist`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["creatorApps"] }); toast.success("已下架"); @@ -263,42 +243,39 @@ export default function CreatePage() { setShowForm(true); }, []); - const openEdit = useCallback( - async (appId: string) => { - try { - const app = await api.get(`/api/v1/creator/apps/${appId}`); - const config = parseAppConfig(app.app_config); - setEditingId(appId); - setForm({ - name: app.name || "", - description: app.description || "", - long_description: app.long_description || "", - system_prompt: (config.system_prompt as string) || "", - welcome_message: app.welcome_message || "", - suggested_prompts: parseSuggestedPrompts(app.suggested_prompts), - category_id: app.category_id || "", - visibility: app.visibility || "private", - app_type: app.dify_app_type || "chatbot", - model: (config.model as string) || "", - temperature: app.temperature ?? 0.7, - max_tokens: app.max_tokens ?? 4096, - knowledge_base_id: app.knowledge_base_id || "", - tools: Array.isArray(config.tools) ? (config.tools as string[]) : [], - data_sources: Array.isArray(config.data_sources) ? (config.data_sources as string[]) : [], - template_set: (config.template_set as string) || "", - input_label: (config.input_label as string) || "", - output_label: (config.output_label as string) || "", - input_placeholder: (config.input_placeholder as string) || "", - format_templates: (config.format_templates as AppForm["format_templates"]) || {}, - }); - setActiveTab("basic"); - setShowForm(true); - } catch { - toast.error("获取应用详情失败"); - } - }, - [] - ); + const openEdit = useCallback(async (appId: string) => { + try { + const app = await api.get(`/api/v1/creator/apps/${appId}`); + const config = parseAppConfig(app.app_config); + setEditingId(appId); + setForm({ + name: app.name || "", + description: app.description || "", + long_description: app.long_description || "", + system_prompt: (config.system_prompt as string) || "", + welcome_message: app.welcome_message || "", + suggested_prompts: parseSuggestedPrompts(app.suggested_prompts), + category_id: app.category_id || "", + visibility: app.visibility || "private", + app_type: app.dify_app_type || "chatbot", + model: (config.model as string) || "", + temperature: app.temperature ?? 0.7, + max_tokens: app.max_tokens ?? 4096, + knowledge_base_id: app.knowledge_base_id || "", + tools: Array.isArray(config.tools) ? (config.tools as string[]) : [], + data_sources: Array.isArray(config.data_sources) ? (config.data_sources as string[]) : [], + template_set: (config.template_set as string) || "", + input_label: (config.input_label as string) || "", + output_label: (config.output_label as string) || "", + input_placeholder: (config.input_placeholder as string) || "", + format_templates: (config.format_templates as AppForm["format_templates"]) || {}, + }); + setActiveTab("basic"); + setShowForm(true); + } catch { + toast.error("获取应用详情失败"); + } + }, []); const addPrompt = useCallback(() => { const v = promptInput.trim(); @@ -331,10 +308,7 @@ export default function CreatePage() { return (
{/* 删除确认 */} - !open && setDeleteTarget(null)} - > + !open && setDeleteTarget(null)}> 确认删除 @@ -359,9 +333,7 @@ export default function CreatePage() {

应用管理

- {isAdmin - ? "管理全部AI应用(管理员模式)" - : "创建、编辑和管理你的AI应用"} + {isAdmin ? "管理全部AI应用(管理员模式)" : "创建、编辑和管理你的AI应用"}

@@ -468,11 +433,12 @@ export default function CreatePage() { {/* 创建/编辑对话框 */} !open && closeForm()}> - + - - {editingId ? "编辑应用" : "创建AI应用"} - + {editingId ? "编辑应用" : "创建AI应用"} {/* Tab切换 */} @@ -520,9 +486,7 @@ export default function CreatePage() { - setForm({ ...form, name: e.target.value }) - } + onChange={(e) => setForm({ ...form, name: e.target.value })} placeholder="例如:政策法规问答" />
@@ -530,9 +494,7 @@ export default function CreatePage() { - setForm({ ...form, description: e.target.value }) - } + onChange={(e) => setForm({ ...form, description: e.target.value })} placeholder="一句话描述应用功能" />
@@ -540,9 +502,7 @@ export default function CreatePage() {