Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/@buildingai/constants/src/shared/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ export const LOGIN_TYPE = {
PHONE: 2,
/** 微信登录 */
WECHAT: 3,
/** Google登录 */
GOOGLE: 5,
} as const;
export type LoginType = (typeof LOGIN_TYPE)[keyof typeof LOGIN_TYPE];
6 changes: 6 additions & 0 deletions packages/@buildingai/db/src/entities/user.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export class User extends SoftDeleteBaseEntity {
@Column({ nullable: true, unique: true, comment: "用户unionid" })
unionid: string;

/**
* Google OAuth openid
*/
@Column({ nullable: true, comment: "Google OAuth openid" })
googleOpenid: string;

@Column({ nullable: true })
userNo: string;
/**
Expand Down
12 changes: 12 additions & 0 deletions packages/@buildingai/db/src/seeds/data/menu.json
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,18 @@
"isHidden": 0,
"type": 2,
"sourceType": 1
},
{
"name": "Google登录",
"code": "channel-google",
"path": "google",
"icon": "google",
"component": "/console/channel/google/index",
"permissionCode": "google-config:get-config",
"sort": 1,
"isHidden": 0,
"type": 2,
"sourceType": 1
}
]
},
Expand Down
6 changes: 6 additions & 0 deletions packages/@buildingai/utils/src/is.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,9 @@ export function isAsyncGenerator<T, TReturn, TNext>(
): value is AsyncGenerator<T, TReturn, TNext> {
return value != null && typeof value === "object" && Symbol.asyncIterator in value;
}

export function getFrontendBaseUrl() {
return isDevelopment()
? (process.env.CLIENT_URL || "http://localhost:4091").replace(/\/$/, "")
: (process.env.APP_DOMAIN || "http://localhost:4090").replace(/\/$/, "");
}
31 changes: 31 additions & 0 deletions packages/@buildingai/web/services/src/console/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,37 @@ export function useUpdateWxOaConfigMutation(
});
}

/** Google登录配置(接口返回) */
export type GoogleConfigResponse = {
clientId: string;
clientSecret: string;
enabled: boolean;
};

/** 更新Google登录配置 DTO */
export type UpdateGoogleConfigDto = {
clientId?: string;
clientSecret?: string;
enabled?: boolean;
};

export function useGoogleConfigQuery(options?: QueryOptionsUtil<GoogleConfigResponse>) {
return useQuery<GoogleConfigResponse>({
queryKey: ["channel", "google-config"],
queryFn: () => consoleHttpClient.get<GoogleConfigResponse>("/google-config"),
...options,
});
}

export function useUpdateGoogleConfigMutation(
options?: MutationOptionsUtil<{ success: boolean }, UpdateGoogleConfigDto>,
) {
return useMutation<{ success: boolean }, Error, UpdateGoogleConfigDto>({
mutationFn: (dto) => consoleHttpClient.patch<{ success: boolean }>("/google-config", dto),
...options,
});
}

// User subscription types
export type UserSubscriptionLevel = {
id: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ReloadWindow } from "@buildingai/ui/components/reload-windows";
import { useI18n } from "@buildingai/i18n";
import {
Breadcrumb,
BreadcrumbItem,
Expand Down Expand Up @@ -61,6 +62,7 @@ function findBreadcrumbTrail(
}

const AppNavbar = ({ menus }: { menus: ExtensionMenuItem[] }) => {
const { t } = useI18n();
const { state } = useSidebar();
const location = useLocation();
const navigate = useNavigate();
Expand All @@ -78,7 +80,7 @@ const AppNavbar = ({ menus }: { menus: ExtensionMenuItem[] }) => {
<SidebarTrigger className="size-fit bg-transparent p-0 hover:bg-transparent" />
</TooltipTrigger>
<TooltipContent>
<p>{state === "expanded" ? "收起侧边栏" : "展开侧边栏"}</p>
<p>{state === "expanded" ? t("common.collapseSidebar") : t("common.expandSidebar")}</p>
</TooltipContent>
</Tooltip>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useExtensionDetailQuery } from "@buildingai/services/console";
import { useI18n } from "@buildingai/i18n";
import { useConfigStore } from "@buildingai/stores";
import { Avatar, AvatarFallback, AvatarImage } from "@buildingai/ui/components/ui/avatar";
import {
Expand All @@ -15,6 +16,7 @@ export interface ConsoleLogoProps {
}

export function ConsoleLogo({ identifier }: ConsoleLogoProps) {
const { t } = useI18n();
const { websiteConfig } = useConfigStore((state) => state.config);
const { data: extension, isLoading } = useExtensionDetailQuery(identifier || "", {
enabled: !!identifier,
Expand Down Expand Up @@ -54,7 +56,7 @@ export function ConsoleLogo({ identifier }: ConsoleLogoProps) {
{extension?.name || websiteConfig?.webinfo.name}
</span>
<span className="text-muted-foreground line-clamp-1 text-xs">
{extension?.description || "插件管理 · 工作台"}
{extension?.description || t("extension.pluginManagementWorkspace")}
</span>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useAuthStore } from "@buildingai/stores";
import { useI18n } from "@buildingai/i18n";
import { Avatar, AvatarFallback, AvatarImage } from "@buildingai/ui/components/ui/avatar";
import {
DropdownMenu,
Expand All @@ -18,6 +19,7 @@ import { ChevronsUpDown, LogOut, User } from "lucide-react";
import { useLocation, useNavigate } from "react-router-dom";

export function NavUser() {
const { t } = useI18n();
const { isMobile } = useSidebar();
const { userInfo } = useAuthStore((state) => state.auth);
const { logout, isLogin } = useAuthStore((state) => state.authActions);
Expand Down Expand Up @@ -48,13 +50,13 @@ export function NavUser() {
</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-medium">{userInfo?.nickname || "未登录"}</span>
<span className="truncate font-medium">{userInfo?.nickname || t("common.notLoggedIn")}</span>
<span className="text-muted-foreground truncate text-xs">
{isLogin()
? isEnabled(userInfo?.isRoot)
? "超级管理员"
: userInfo?.role?.name || "未设置角色"
: "请先登录后使用"}
? t("common.superAdmin")
: userInfo?.role?.name || t("common.noRole")
: t("common.pleaseLoginFirst")}
</span>
</div>
<ChevronsUpDown className="ml-auto size-4" />
Expand All @@ -69,8 +71,10 @@ export function NavUser() {
<DropdownMenuItem
onClick={async () => {
await confirm({
title: "退出确认",
description: "确定要退出登录吗?",
title: t("common.logoutConfirm"),
description: t("common.logoutConfirmDesc"),
confirmText: t("common.action.confirm"),
cancelText: t("common.action.cancel"),
});
await logout();
const redirect = encodeURIComponent(location.pathname + location.search);
Expand All @@ -81,7 +85,7 @@ export function NavUser() {
}}
>
<LogOut />
退出登录
{t("common.logout")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";

import { useI18n } from "@buildingai/i18n";
import {
type ConversationRecord,
useConversationsQuery,
Expand Down Expand Up @@ -444,6 +445,7 @@ function ChatHistoryMenuItem({
isActive: boolean;
onOpenDialog: () => void;
}) {
const { t } = useI18n();
const { pathname } = useLocation();
const { state } = useSidebar();
const { isLogin } = useAuthStore((state) => state.authActions);
Expand All @@ -452,7 +454,7 @@ function ChatHistoryMenuItem({
return (
<SidebarMenuItem>
<SidebarMenuButton
tooltip={item.title}
tooltip={t(`sidebar.${item.id}`)}
className="group/history-chat-icon h-9"
onClick={onOpenDialog}
asChild
Expand Down Expand Up @@ -492,7 +494,7 @@ function ChatHistoryMenuItem({
"ml-6": state === "expanded",
})}
>
{item.title}
{t(`sidebar.${item.id}`) || item.title}
</span>
</div>
</SidebarMenuButton>
Expand All @@ -509,9 +511,9 @@ function ChatHistoryMenuItem({
<SidebarMenuSubItem>
<SidebarMenuSubButton onClick={onOpenDialog} className="h-9 cursor-pointer">
<span className="text-muted-foreground line-clamp-1 text-xs font-medium">
查看全部
{t("chat.viewAll")}
</span>
<span className="sr-only">查看全部</span>
<span className="sr-only">{t("chat.viewAll")}</span>
</SidebarMenuSubButton>
<SidebarMenuAction
showOnHover
Expand All @@ -533,13 +535,14 @@ function ChatHistoryMenuItem({
function CollapsibleMenuItem({ item, isActive }: { item: NavItem; isActive: boolean }) {
const { pathname } = useLocation();
const isItemActive = (path?: string) => path === pathname;
const { t } = useI18n();

return (
<SidebarMenuItem>
<CollapsibleTrigger asChild className="group/collapsible">
<SidebarMenuButton isActive={isActive} tooltip={item.title} className="h-9">
<SidebarMenuButton isActive={isActive} tooltip={t(`sidebar.${item.id}`)} className="h-9">
{item.icon && <NavIcon icon={item.icon} isActive={isActive} />}
<span>{item.title}</span>
<span>{t(`sidebar.${item.id}`)}</span>
<SidebarMenuAction>
<ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
</SidebarMenuAction>
Expand Down Expand Up @@ -570,11 +573,12 @@ function CollapsibleMenuItem({ item, isActive }: { item: NavItem; isActive: bool
*/
function LinkMenuItem({ item, isActive }: { item: NavItem; isActive: boolean }) {
const isExternal = item.target === "_blank";
const { t } = useI18n();

const content = (
<>
{item.icon && <NavIcon icon={item.icon} isActive={isActive} />}
<span className="mr-auto line-clamp-1 flex-1 whitespace-nowrap">{item.title}</span>
<span className="mr-auto line-clamp-1 flex-1 whitespace-nowrap">{t(`sidebar.${item.id}`) || item.title}</span>
{item.action}
{isExternal && (
<ExternalLink className="text-muted-foreground size-3.5 shrink-0 opacity-0 transition-opacity group-hover/link-menu-item:opacity-100" />
Expand All @@ -585,7 +589,7 @@ function LinkMenuItem({ item, isActive }: { item: NavItem; isActive: boolean })
return (
<SidebarMenuItem>
<SidebarMenuButton
tooltip={item.title}
tooltip={t(`sidebar.${item.id}`)}
className="group/link-menu-item h-9"
isActive={isActive}
asChild
Expand All @@ -609,6 +613,7 @@ export function DefaultNavMain({
items: NavItem[];
isLoading?: boolean;
}) {
const { t } = useI18n();
const { pathname } = useLocation();
const navigate = useNavigate();
const { isLogin } = useAuthStore((state) => state.authActions);
Expand Down Expand Up @@ -712,7 +717,6 @@ export function DefaultNavMain({
const renderMenuItem = (item: NavItem) => {
const hasItems = item.items && item.items.length > 0;
const isChatHistory = item.id === "menu_history_fixed";

if (isChatHistory) {
return (
<ChatHistoryMenuItem
Expand Down Expand Up @@ -745,7 +749,7 @@ export function DefaultNavMain({
isFirst = false;

groups.push(
<CommandGroup key={group} heading={TIME_GROUP_LABELS[group]}>
<CommandGroup key={group} heading={t(`sidebar.${TIME_GROUP_LABELS[group]}`)}>
{conversations.map((conversation) => (
<HistoryCommandItem
key={conversation.id}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useI18n } from "@buildingai/i18n";
import type { DecorateMenuItem } from "@buildingai/services/web";
import { useConversationsQuery, useDecorateMenuQuery } from "@buildingai/services/web";
import { useAuthStore } from "@buildingai/stores";
Expand Down Expand Up @@ -103,6 +104,7 @@ function useMenuItems(
}

export function DefaultAppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const { t } = useI18n();
const navigate = useNavigate();
const { userInfo } = useAuthStore((state) => state.auth);
const { data: menuConfig, isLoading: isMenuLoading } = useDecorateMenuQuery();
Expand All @@ -115,7 +117,7 @@ export function DefaultAppSidebar({ ...props }: React.ComponentProps<typeof Side
() =>
conversationsData?.items?.map((conversation) => ({
id: `conversation-${conversation.id}`,
title: conversation.title || "新对话",
title: conversation.title || t("chat.newConversation"),
path: `/c/${conversation.id}`,
})) || [],
[conversationsData],
Expand Down Expand Up @@ -182,7 +184,7 @@ export function DefaultAppSidebar({ ...props }: React.ComponentProps<typeof Side
<SidebarMenuButton className="h-9" asChild>
<Link to={consoleLink}>
<LayoutDashboard />
<span className="whitespace-nowrap">工作台</span>
<span className="whitespace-nowrap">{t("common.workspace")}</span>
<SidebarMenuAction asChild>
<div>
<ArrowUpRight />
Expand Down
Loading