代码修改

This commit is contained in:
董宏凯 committed 2026-07-22 15:43:06 +08:00
1 parent b93b82fcaf
commit 055523bf33
28 files changed
+483 -92

No files matched your search

@@ -21,7 +21,13 @@ export default function LightAppIframeView() {
// 把新主题色传给被嵌套应用(不依赖 <html> 的 dark class,避免时序读旧值)。
// 深色=dark-blue,浅蓝=blue,其余(红白)=red。
const themeColor: AppThemeColor =
theme === "dark" ? "dark-blue" : theme === "lightblue" ? "blue" : "red";
theme === "dark"
? "dark-blue"
: theme === "lightgreen"
? "green"
: theme === "lightblue"
? "blue"
: "red";
const src = useMemo(
() => (app ? buildLightAppUrl(app, undefined, themeColor) : ""),
[app, themeColor],
+46 -12
View File
@@ -34,7 +34,7 @@ import { toast } from "sonner";
import { Pagination } from "@/components/ui/pagination";
import { cn } from "@/lib/utils";
import { useTheme } from "@/contexts/ThemeContext";
import { useTheme, type ThemeType } from "@/contexts/ThemeContext";
import { useLightApps, type LightApp } from "@/strategy-components/api/light-apps";
import { buildLightAppUrl } from "@/strategy-components/lib/light-app";
@@ -64,12 +64,46 @@ function hashIndex(str: string, mod: number): number {
return mod > 0 ? h % mod : 0;
}
function getLightAccent(theme: ThemeType) {
if (theme === "lightgreen") {
return {
dot: "bg-[#07C05F]",
badge: "border-[#07C05F]/15 bg-[#E9F8EC] text-[#049B38]",
focus: "focus:border-[#07C05F]/60 focus:ring-[#07C05F]/20",
text: "text-[#049B38]",
hoverText: "group-hover:text-[#049B38]",
link: "text-[#049B38] hover:text-[#038626]",
button: "bg-[#07C05F] shadow-[0_1px_3px_rgba(7,192,95,0.2)] hover:bg-[#08DD6E]",
};
}
if (theme === "lightblue") {
return {
dot: "bg-[#0062D9]",
badge: "border-[#0062D9]/15 bg-[#EAF4FF] text-[#0062D9]",
focus: "focus:border-[#0062D9]/60 focus:ring-[#0062D9]/20",
text: "text-[#0062D9]",
hoverText: "group-hover:text-[#0062D9]",
link: "text-[#0062D9] hover:text-[#0056C6]",
button: "bg-[#0062D9] shadow-[0_1px_3px_rgba(0,98,217,0.2)] hover:bg-[#0079FE]",
};
}
return {
dot: "bg-[#CF1322]",
badge: "border-[#CF1322]/15 bg-[#FFF1F0] text-[#CF1322]",
focus: "focus:border-[#CF1322]/60 focus:ring-[#CF1322]/20",
text: "text-[#CF1322]",
hoverText: "group-hover:text-[#CF1322]",
link: "text-[#CF1322] hover:text-[#A8071A]",
button: "bg-[#CF1322] shadow-[0_1px_3px_rgba(207,19,34,0.2)] hover:bg-[#A8071A]",
};
}
export default function LightAppListPage() {
const [search, setSearch] = useState("");
const [page, setPage] = useState(1);
const [copiedId, setCopiedId] = useState<string | null>(null);
const { theme } = useTheme();
const isLightBlue = theme === 'lightblue';
const lightAccent = getLightAccent(theme);
const { data: apps = [], isLoading } = useLightApps({
appType: "window_open",
@@ -118,13 +152,13 @@ export default function LightAppListPage() {
<div className="space-y-1">
<div className="flex items-center gap-2.5">
<span className="relative flex size-3">
<span className={cn("absolute inline-flex size-full animate-ping rounded-full opacity-75", isLightBlue ? "bg-[#0062D9]" : "bg-[#CF1322]", "dark:bg-[#1677FF]")} />
<span className={cn("relative inline-flex size-3 rounded-full", isLightBlue ? "bg-[#0062D9]" : "bg-[#CF1322]", "dark:bg-[#1677FF]")} />
<span className={cn("absolute inline-flex size-full animate-ping rounded-full opacity-75", lightAccent.dot, "dark:bg-[#1677FF]")} />
<span className={cn("relative inline-flex size-3 rounded-full", lightAccent.dot, "dark:bg-[#1677FF]")} />
</span>
<h1 className="text-2xl font-bold tracking-tight text-zinc-900 dark:text-[#E8EDF5]">
应用列表
</h1>
<span className={cn("rounded-[5px] border px-2 py-0.5 font-mono text-xs font-medium dark:border-[#1677FF]/30 dark:bg-[#1677FF]/15 dark:text-[#4096FF]", isLightBlue ? "border-[#0062D9]/15 bg-[#EAF4FF] text-[#0062D9]" : "border-[#CF1322]/15 bg-[#FFF1F0] text-[#CF1322]")}>
<span className={cn("rounded-[5px] border px-2 py-0.5 font-mono text-xs font-medium dark:border-[#1677FF]/30 dark:bg-[#1677FF]/15 dark:text-[#4096FF]", lightAccent.badge)}>
导航工作台
</span>
</div>
@@ -142,7 +176,7 @@ export default function LightAppListPage() {
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="键入应用名称、目标地址、或描述,实时过滤检索…"
className={cn("w-full rounded-[5px] border border-zinc-200 bg-zinc-50/50 py-3 pl-10 pr-10 text-sm transition focus:bg-white focus:outline-none focus:ring-2 dark:border-[#1A2F5A] dark:bg-[#0C1836] dark:text-[#C5CFE0] dark:placeholder-[#4A6491] dark:focus:border-[#1677FF]/60 dark:focus:bg-[#122347] dark:focus:ring-[#1677FF]/25", isLightBlue ? "focus:border-[#0062D9]/60 focus:ring-[#0062D9]/20" : "focus:border-[#CF1322]/60 focus:ring-[#CF1322]/20")}
className={cn("w-full rounded-[5px] border border-zinc-200 bg-zinc-50/50 py-3 pl-10 pr-10 text-sm transition focus:bg-white focus:outline-none focus:ring-2 dark:border-[#1A2F5A] dark:bg-[#0C1836] dark:text-[#C5CFE0] dark:placeholder-[#4A6491] dark:focus:border-[#1677FF]/60 dark:focus:bg-[#122347] dark:focus:ring-[#1677FF]/25", lightAccent.focus)}
/>
{search && (
<button
@@ -161,13 +195,13 @@ export default function LightAppListPage() {
<div className="-mt-2 flex items-center justify-between">
<div className="text-xs font-medium text-zinc-500 dark:text-[#6E88B0]">
检索到最终结果:{" "}
<span className={cn("font-bold dark:text-[#4096FF]", isLightBlue ? "text-[#0062D9]" : "text-[#CF1322]")}>{apps.length}</span> 个关联应用
<span className={cn("font-bold dark:text-[#4096FF]", lightAccent.text)}>{apps.length}</span> 个关联应用
</div>
{search && (
<button
type="button"
onClick={() => setSearch("")}
className={cn("text-xs font-medium underline dark:text-[#4096FF] dark:hover:text-[#1677FF]", isLightBlue ? "text-[#0062D9] hover:text-[#0056C6]" : "text-[#CF1322] hover:text-[#A8071A]")}
className={cn("text-xs font-medium underline dark:text-[#4096FF] dark:hover:text-[#1677FF]", lightAccent.link)}
>
重置过滤条件
</button>
@@ -239,7 +273,7 @@ function AppCard({
onOpen: () => void;
}) {
const { theme } = useTheme();
const isLightBlue = theme === 'lightblue';
const lightAccent = getLightAccent(theme);
const Icon = ICON_POOL[hashIndex(app.appId, ICON_POOL.length)];
const cardTheme = THEME_POOL[hashIndex(app.appId, THEME_POOL.length)];
@@ -256,7 +290,7 @@ function AppCard({
</div>
</div>
<h4 className={cn("mb-2 line-clamp-1 text-base font-bold leading-snug text-zinc-900 transition-colors dark:text-[#E8EDF5] dark:group-hover:text-[#4096FF]", isLightBlue ? "group-hover:text-[#0062D9]" : "group-hover:text-[#CF1322]")}>
<h4 className={cn("mb-2 line-clamp-1 text-base font-bold leading-snug text-zinc-900 transition-colors dark:text-[#E8EDF5] dark:group-hover:text-[#4096FF]", lightAccent.hoverText)}>
{app.name}
</h4>
@@ -270,7 +304,7 @@ function AppCard({
<div className="mb-4 rounded-[5px] bg-zinc-50/70 p-3 dark:bg-[#0C1836]">
<div className="mb-1 flex items-center justify-between text-[10px] font-semibold text-zinc-400 dark:text-[#6E88B0]">
<span>拼接后目标路由终端:</span>
<span className={cn("text-[9px] font-bold uppercase tracking-wider dark:text-[#4096FF]", isLightBlue ? "text-[#0062D9]" : "text-[#CF1322]")}>
<span className={cn("text-[9px] font-bold uppercase tracking-wider dark:text-[#4096FF]", lightAccent.text)}>
自动拼接已激活参
</span>
</div>
@@ -312,7 +346,7 @@ function AppCard({
<button
type="button"
onClick={onOpen}
className={cn("flex items-center justify-center gap-1.5 rounded-[5px] px-3 py-2 text-xs font-semibold text-white transition active:scale-[0.98] dark:bg-[#1677FF] dark:shadow-none dark:hover:bg-[#0958D9]", isLightBlue ? "bg-[#0062D9] shadow-[0_1px_3px_rgba(0,98,217,0.2)] hover:bg-[#0079FE]" : "bg-[#CF1322] shadow-[0_1px_3px_rgba(207,19,34,0.2)] hover:bg-[#A8071A]")}
className={cn("flex items-center justify-center gap-1.5 rounded-[5px] px-3 py-2 text-xs font-semibold text-white transition active:scale-[0.98] dark:bg-[#1677FF] dark:shadow-none dark:hover:bg-[#0958D9]", lightAccent.button)}
>
<span>进入应用</span>
<ArrowUpRight className="size-3.5" />
@@ -93,7 +93,7 @@ const newParam = (): LightAppRouteParam => ({
paramType: "login",
source: "access_token",
customValue: "",
themeValue: "red=red;blue=blue;dark-blue=dark-blue",
themeValue: "red=red;green=green;blue=blue;dark-blue=dark-blue",
});
function formFromApp(app: LightApp): FormState {
@@ -10,6 +10,7 @@ export default function LightAppNoteQAPage() {
const { theme } = useTheme();
const isDark = theme === "dark";
const isLightBlue = theme === 'lightblue';
const isLightGreen = theme === "lightgreen";
const [question, setQuestion] = useState("");
const handleSubmit = () => {
@@ -112,7 +113,9 @@ export default function LightAppNoteQAPage() {
"flex h-7 w-7 shrink-0 items-center justify-center rounded-full transition-colors",
isDark
? "bg-sky-500 text-white hover:bg-sky-400"
: isLightBlue
: isLightGreen
? "bg-[#07C05F] text-white hover:bg-[#08DD6E]"
: isLightBlue
? "bg-[#0062D9] text-white hover:bg-[#0079FE]"
: "bg-[#F5222D] text-white hover:bg-[#CF1322]",
)}
@@ -4,7 +4,7 @@ import AIWritingPage from '@/open-canvas/pages/AIWritingPage';
import { getNotebookApiBaseURL } from '@/core/config';
import { useTheme, type ThemeType } from '@/contexts/ThemeContext';
const VALID_THEMES: ThemeType[] = ['dark', 'light', 'lightblue'];
const VALID_THEMES: ThemeType[] = ['dark', 'light', 'lightblue', 'lightgreen'];
interface NotebookTokenData {
doc_ids: number[];
+12 -2
View File
@@ -16,6 +16,7 @@ import { useTheme } from "@/contexts/ThemeContext";
import { useLocation } from "react-router-dom";
import { useActiveThirdLevel } from "@/core/page-layout/use-sidebar-menu";
import { useLayoutMode } from "@/core/system-settings/hooks";
import { env } from "@/env";
import WorkspaceRoutes from "./WorkspaceRoutes";
import StrategyRoutes from "./StrategyRoutes";
@@ -27,6 +28,7 @@ import { RoundtableJobNotifier } from "@/roundtable-planning/components/Roundtab
function PageLayout() {
const [collapsed, setCollapsed] = useState(false);
const forceCollapsedSidebar = env.FORCE_COLLAPSED_SIDEBAR;
const sidebarEnabled = useMemo(() => readSidebarEnabled(), []);
const location = useLocation();
const { theme } = useTheme();
@@ -42,7 +44,13 @@ function PageLayout() {
// 登录时置位)这一旧默认。这样无论是否走门户登录,「全量↔简洁」都能真正控制顶栏+侧边栏。
const [layoutMode] = useLayoutMode();
const chromeByPreference =
layoutMode === "full" ? true : layoutMode === "compact" ? false : sidebarEnabled;
forceCollapsedSidebar
? false
: layoutMode === "full"
? true
: layoutMode === "compact"
? false
: sidebarEnabled;
// iframe 嵌入模式(外部系统 `&embed=1`,按标签页 sessionStorage):去掉全局导航栏 + 侧边栏,
// 只留问答/会商工作区本体。按 location 重算以跟随页内导航;非嵌入标签页恒为 false,不受影响。
const embedActive = useMemo(
@@ -60,7 +68,8 @@ function PageLayout() {
// 但它常被深链「上一步」从去 chrome 的工作区/新标签打开——那里 chromeByPreference 可能为 false
// (界面模式非全量、或会话级 sidebar 未置位),导致整页没有顶栏/侧栏。故对该路由**强制全局 chrome**
// (仍尊重 embed=1 嵌入态:外部 iframe 套用时仍隐藏)。
const forceChromeForDashboardAgent = location.pathname.includes("/strategy/dashboard-agent");
const forceChromeForDashboardAgent =
!forceCollapsedSidebar && location.pathname.includes("/strategy/dashboard-agent");
const pageSidebarAllowed =
(forceChromeForDashboardAgent || chromeByPreference) &&
!isChatsIframeWorkspacePath(location.pathname) &&
@@ -114,6 +123,7 @@ function PageLayout() {
headerHidden={!pageSidebarAllowed}
compactWorkspaceSidebar={pageSidebarAllowed}
pageSidebarDark={isDark}
forceWorkspaceSidebarCollapsed={forceCollapsedSidebar}
/>
}
/>
+17 -2
View File
@@ -122,6 +122,7 @@ export function WorkspaceLayout({
wrapperOverflowHidden = false,
insetOverflowHidden = false,
pageSidebarDark = false,
forceWorkspaceSidebarCollapsed = false,
}: {
children: ReactNode;
pageSidebarCollapsed: boolean;
@@ -134,6 +135,8 @@ export function WorkspaceLayout({
wrapperOverflowHidden?: boolean;
insetOverflowHidden?: boolean;
pageSidebarDark?: boolean;
/** Deployment-level compact mode: keep only the icon menu rail. */
forceWorkspaceSidebarCollapsed?: boolean;
}) {
// 全量模式下通用问答(/page/workspace/chats*)的历史侧栏默认展开;其余紧凑页
// (如智能体对话,为聊天区更宽而默认收起)维持原默认。
@@ -169,11 +172,19 @@ export function WorkspaceLayout({
key={String(compactWorkspaceSidebar)}
data-page-sidebar-collapsed={pageSidebarCollapsed}
defaultOpen={
defaultHistorySidebarOpen ?? (isGeneralQa || !compactWorkspaceSidebar)
forceWorkspaceSidebarCollapsed
? false
: (defaultHistorySidebarOpen ?? (isGeneralQa || !compactWorkspaceSidebar))
}
open={forceWorkspaceSidebarCollapsed ? false : undefined}
onOpenChange={forceWorkspaceSidebarCollapsed ? () => undefined : undefined}
disableToggle={forceWorkspaceSidebarCollapsed}
>
{!workspaceSidebarHidden && (
<WorkspaceSidebar compactChrome={compactWorkspaceSidebar} />
<WorkspaceSidebar
compactChrome={compactWorkspaceSidebar}
forceCollapsed={forceWorkspaceSidebarCollapsed}
/>
)}
<SidebarInset
className={cn('min-w-0', insetOverflowHidden && 'overflow-hidden')}
@@ -227,6 +238,7 @@ function NewChatEntryRoute({
headerHidden: boolean;
compactWorkspaceSidebar: boolean;
pageSidebarDark: boolean;
forceWorkspaceSidebarCollapsed: boolean;
};
}) {
if (isInIframe()) {
@@ -248,12 +260,14 @@ export default function WorkspaceRoutes({
headerHidden = false,
compactWorkspaceSidebar = false,
pageSidebarDark = false,
forceWorkspaceSidebarCollapsed = false,
}: {
pageSidebarCollapsed?: boolean;
pageSidebarHidden?: boolean;
headerHidden?: boolean;
compactWorkspaceSidebar?: boolean;
pageSidebarDark?: boolean;
forceWorkspaceSidebarCollapsed?: boolean;
}) {
const layoutProps = {
pageSidebarCollapsed,
@@ -261,6 +275,7 @@ export default function WorkspaceRoutes({
headerHidden,
compactWorkspaceSidebar,
pageSidebarDark,
forceWorkspaceSidebarCollapsed,
};
return (
@@ -689,6 +689,58 @@
background-color: #0056C6;
}
/* WeKnora green theme. */
[data-theme="lightgreen"] .light-app-management-page .lam-primary-btn,
[data-theme="lightgreen"] .light-app-management-page .lam-dialog-save,
[data-theme="lightgreen"] .light-app-management-page .lam-switch-on {
background-color: #07C05F;
}
[data-theme="lightgreen"] .light-app-management-page .lam-primary-btn,
[data-theme="lightgreen"] .light-app-management-page .lam-dialog-save {
box-shadow: 0 2px 6px rgba(7, 192, 95, 0.2);
}
[data-theme="lightgreen"] .light-app-management-page .lam-primary-btn:hover,
[data-theme="lightgreen"] .light-app-management-page .lam-dialog-save:hover {
background-color: #08DD6E;
}
[data-theme="lightgreen"] .light-app-management-page .lam-primary-btn:active,
[data-theme="lightgreen"] .light-app-management-page .lam-dialog-save:active {
background-color: #049B38;
}
[data-theme="lightgreen"] .light-app-management-page .lam-search-input:focus {
border-color: rgba(7, 192, 95, 0.4);
box-shadow: 0 0 0 4px rgba(7, 192, 95, 0.1);
}
[data-theme="lightgreen"] .light-app-management-page .lam-view-toggle-btn.is-active,
[data-theme="lightgreen"] .light-app-management-page .lam-cat-toggle-btn.is-active,
[data-theme="lightgreen"] .light-app-management-page .lam-count strong,
[data-theme="lightgreen"] .light-app-management-page .lam-table tr:hover .lam-row-name,
[data-theme="lightgreen"] .light-app-management-page .lam-param-popover-close,
[data-theme="lightgreen"] .light-app-management-page .lam-param-key,
[data-theme="lightgreen"] .light-app-management-page .lam-card:hover .lam-card-title,
[data-theme="lightgreen"] .light-app-management-page .lam-dialog-close:hover,
[data-theme="lightgreen"] .light-app-management-page .lam-add-param-btn:hover {
color: #049B38;
}
[data-theme="lightgreen"] .light-app-management-page .lam-add-param-btn:hover {
border-color: #07C05F;
}
[data-theme="lightgreen"] .light-app-management-page .lam-dialog-icon {
background-color: #E9F8EC;
color: #049B38;
}
[data-theme="lightgreen"] .light-app-management-page .lam-input:focus,
[data-theme="lightgreen"] .light-app-management-page .lam-dialog input[type="text"]:focus,
[data-theme="lightgreen"] .light-app-management-page .t-select.t-is-focused .t-input,
[data-theme="lightgreen"] .light-app-management-page .t-select.t-is-focused .t-input__wrap {
border-color: #07C05F;
box-shadow: 0 0 0 2px rgba(7, 192, 95, 0.16);
}
[data-theme="lightgreen"] .light-app-management-page .t-select:hover .t-input,
[data-theme="lightgreen"] .light-app-management-page .t-select:hover .t-input__wrap {
border-color: rgba(7, 192, 95, 0.5);
}
/* ── iframe 菜单排序:拖拽行 + 拖拽手柄 ───────────────────────────────── */
.light-app-management-page .lam-reorder-row {
cursor: grab;
@@ -7,6 +7,11 @@
background-color: #F9FCFF;
}
[data-theme="lightgreen"] .light-app-management-page,
[data-theme="lightgreen"] .light-app-list-page {
background-color: #F9FDF9;
}
.dark .light-app-management-page,
.dark .light-app-list-page {
background-color: var(--color-bg-page);