Skip to content
Merged
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
6 changes: 4 additions & 2 deletions ui/src/api/chat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ Chat 业务接口统一调用后端 v3 路由(`/chat/api/v3/...`);文件
可选进度回调及取消,统一返回 `{ request, abort }`。`request` 解包得到文件地址;
取消仍拒绝 Promise,但不弹出通用错误提示。loading 由调用方管理。

`auth.ts` 维护门户与单应用的认证:`getApplicationAuthProfile(accessToken)` 请求 `/profile`,
`getPortalAuthProfile()` 请求 `/portal/profile`,两者返回结构相同的 `AuthProfile`,差异字段在 `meta`。
`auth.ts` 维护门户与单应用的认证:`getApplicationAuthProfile(accessToken)` 请求 `/v3/profile`,
`getPortalAuthProfile()` 请求 `/v3/portal/profile`,两者返回结构相同的 `AuthProfile`,差异字段在 `meta`。
主题配置位于响应顶层 `custom_theme`,不在 `meta` 内;Chat Auth Store 获取或复用该配置后,
显式应用 `custom_theme.theme_color`,登录页与正式对话共用此主题。
`postAnonymousAuth(accessToken?)` 与 `postLogin(loginRequest, accessToken?)` 传入 accessToken 时为应用认证,
否则为门户认证。`getCaptcha(username, accessToken)` 获取应用登录验证码,后端以 `accessToken`
查询参数接收应用令牌,暂不支持门户。`chat-user.ts` 的 `getChatUserProfile()` 获取当前对话用户。
Expand Down
1 change: 1 addition & 0 deletions ui/src/api/types/chat-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface AuthProfile<Meta = Record<string, never>> {
login_value: LoginMethod[]
rsa_key: string
logo: string
custom_theme?: { theme_color?: string; header_font_color?: string } | null
meta: Meta
}

Expand Down
11 changes: 4 additions & 7 deletions ui/src/conversation-panel/components/content/items/form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MkDynamicsForm } from '@/components/mk-dynamics-form'
import type { DynamicFormValue, FormField } from '@/components/mk-dynamics-form'
import type { Dict } from '@/api/types'
import { useSendMessageOptional } from '@/conversation-panel/components/message-list/index'
import { useViewType, VIEW_TYPE, type ViewType } from "@/conversation-panel/view/index"
import { useViewType, VIEW_TYPE, type ViewType } from '@/conversation-panel/view/index'
defineOptions({ name: 'ConversationFormContent' })
const viewType = useViewType()
// 发送能力由消息列表或外部宿主 provide;拿不到 → 只读降级
Expand Down Expand Up @@ -57,17 +57,14 @@ const submit = async () => {
}
}
const READONLY_VIEWS: readonly ViewType[] = [VIEW_TYPE.LOG, VIEW_TYPE.SHARE]

</script>

<template>
<div class="mk-gray-card-lg space-y-4 border border-N300">
<div class="mk-gray-card-lg space-y-4 border">
<MdPreview class="!h-auto" editorId="conversation-text" :modelValue="leadingText || ''"></MdPreview>
<MkDynamicsForm ref="dynamicsFormRef" :view="is_submit || READONLY_VIEWS.includes(viewType)"
:render-data="form_field_list" v-model="form_data" />
<MkDynamicsForm ref="dynamicsFormRef" :view="is_submit || READONLY_VIEWS.includes(viewType)" :render-data="form_field_list" v-model="form_data" />
<MdPreview class="!h-auto" editorId="conversation-text" :modelValue="trailingText || ''"></MdPreview>
<el-button :type="is_submit ? 'info' : 'primary'"
:disabled="is_submit || READONLY_VIEWS.includes(viewType) || !sendMessage" @click="submit">
<el-button :type="is_submit ? 'info' : 'primary'" :disabled="is_submit || READONLY_VIEWS.includes(viewType) || !sendMessage" @click="submit">
{{ is_submit ? '已提交' : '提交' }}
</el-button>
</div>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, the diff is mostly formatting/import-style cleanup and does not change the main logic. However, there are a few points worth checking:

Potential issues

  1. border-N300 was removed

    - <div class="mk-gray-card-lg space-y-4 border border-N300">
    + <div class="mk-gray-card-lg space-y-4 border">
    • If border-N300 was a valid design token, this is a visual regression: the border color will change to the default/inherited color.
    • If border-N300 was invalid or no longer used, this is fine, but prefer using a valid token such as border-neutral-300 or the project’s actual token.
    • Recommendation: Restore border-N300 unless the color change is intentional.
  2. Long template lines may conflict with the formatter/linter

    <MkDynamicsForm ref="dynamicsFormRef" :view="..." :render-data="..." v-model="form_data" />
    <el-button :type="..." :disabled="..." @click="submit">
    • The original code was wrapped across multiple lines; this diff makes the lines longer.
    • If the project uses Prettier or vue/max-attributes-per-line, this may fail formatting/lint checks.
    • Recommendation: Run the project formatter and keep the formatted output.
  3. Duplicate readonly condition

    :view="is_submit || READONLY_VIEWS.includes(viewType)"
    :disabled="is_submit || READONLY_VIEWS.includes(viewType) || !sendMessage"
    • The same logic is repeated. Extracting it into a computed property reduces duplication and keeps the form and button in sync.
    • Assuming is_submit and viewType are refs:
    const isReadonly = computed(
      () => is_submit.value || READONLY_VIEWS.includes(viewType.value)
    )

    Then:

    <MkDynamicsForm :view="isReadonly" ... />
    <el-button :disabled="isReadonly || !sendMessage" ...>
    • This is a readability/maintainability improvement, not a functional bug.
  4. Duplicate editorId on two MdPreview components

    <MdPreview editorId="conversation-text" ... />
    ...
    <MdPreview editorId="conversation-text" ... />
    • If editorId is used as a DOM id or editor instance key, using it twice may cause conflicts.
    • Recommendation: Use unique IDs, for example:
    editorId="conversation-leading-text"
    editorId="conversation-trailing-text"
    • This issue already existed, but it is worth fixing.
  5. submit should also guard against readonly/duplicate submission

    • The button is disabled, but defensive code inside submit is still useful:
    if (isReadonly.value || !sendMessage) return
    • If submit performs an async request, ensure it cannot be triggered twice while pending. Set a submitting flag before await and reset it in finally.

Minor suggestions

  • The import quote change from " to ' is fine and likely consistent with project style.
  • Removing the blank line before </script> is harmless.
  • Snake_case names such as is_submit, form_data, and form_field_list are inconsistent with typical TS/Vue camelCase style, but this is only a style issue if the project enforces it.
  • READONLY_VIEWS.includes(...) is fine for two items. If the list grows significantly, consider a Set<ViewType>:
    const READONLY_VIEWS = new Set<ViewType>([VIEW_TYPE.LOG, VIEW_TYPE.SHARE])
    // READONLY_VIEWS.has(viewType.value)

Most important action

Check whether removing border-N300 is intentional. If not, restore it. Then run the project formatter and consider extracting the repeated readonly condition into a computed property.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ watch(
</script>

<template>
<div ref="diffScrollRef" class="max-h-[400px] overflow-y-auto rounded-md border border-N300">
<div ref="diffScrollRef" class="max-h-[400px] overflow-y-auto rounded-md border">
<FileDiff :file="file" />
</div>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const debug = useDebugHeaderStore()
</script>

<template>
<header class="mk-conversation-debug-header flex-align-center h-header shrink-0 border-b border-N300 px-3">
<header class="mk-conversation-debug-header flex-align-center h-header shrink-0 border-b px-3">
<!-- 左侧收起时才在顶部显示:展开左侧 + 新建对话 -->
<template v-if="!leftSideOpen">
<MkTooltip content="展开侧边栏">
Expand Down
6 changes: 3 additions & 3 deletions ui/src/conversation-panel/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@
&.drawer,
&.push.open {
&.left {
border-right: 1px solid var(--mk-N350);
border-right: 1px solid var(--mk-N300);
}

&.right {
border-left: 1px solid var(--mk-N350);
border-left: 1px solid var(--mk-N300);
}
}
}
Expand All @@ -112,7 +112,7 @@

/* 对话输入区:边框颜色随内部焦点平滑切换。 */
.mk-conversation-message-input {
border: 1px solid rgb(var(--mk-N350-rgb) / 60%);
border: 1px solid var(--mk-N300);
transition: border-color 150ms cubic-bezier(0.4, 0, 0.2, 1);

&:focus-within {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useStore } from '@/stores/chat'
import { MsgConfirm } from '@/utils/message'
import RenameConversation from '../../components/rename/index.vue'
import { relativeTimeFormat } from '@/utils/time'
Expand All @@ -14,6 +15,8 @@ import { useViewType, VIEW_TYPE } from '../../view/index'
defineOptions({ name: 'ConversationList' })

const viewType = useViewType()
const { auth } = useStore()
const authProfile = computed(() => (viewType === VIEW_TYPE.CHAT ? auth.authProfile : null))
const msgs = useMessageListStore()
// 会话菜单分享不针对某一轮,进入后不预先勾选
const shareLink = useShareLinkStoreOptional()
Expand Down Expand Up @@ -53,15 +56,15 @@ function handleClearConversations() {
<template>
<div class="flex-column h-full overflow-hidden p-4">
<!-- 应用信息与收起侧栏 -->
<div class="mb-4 flex-between shrink-0 gap-2">
<div class="mb-4 flex-between shrink-0 gap-2" :style="{ color: authProfile?.custom_theme?.header_font_color || undefined }">
<div class="min-w-0 flex-align-center gap-2">
<ApplicationIcon :icon="appInfo?.icon" :size="24" class="shrink-0" />
<h4 class="truncate" :title="appInfo?.name || 'AI 助手'">{{ appInfo?.name || 'AI 助手' }}</h4>
</div>
<!-- 收起左侧 -->
<MkTooltip content="收起侧边栏">
<el-button text @click="toggleLeftSide()" class="-mr-1">
<MkIcon name="icon_sidebar_outlined" :size="18" class="text-N900!" />
<MkIcon name="icon_sidebar_outlined" :size="18" :color="authProfile?.custom_theme?.header_font_color || 'var(--mk-N900)'" />
</el-button>
</MkTooltip>
</div>
Expand Down
4 changes: 2 additions & 2 deletions ui/src/conversation-panel/view/debug/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ provide(CONVERSATION_LIST_KEY, bundle.list)
provide(MESSAGE_LIST_KEY, bundle.msgs)
provide(MESSAGE_INPUT_KEY, bundle.input)
provide(EXECUTION_DETAIL_KEY, bundle.detail)
provide(VIEW_KEY,VIEW_TYPE.DEBUG)
provide(VIEW_KEY, VIEW_TYPE.DEBUG)
const debug = createDebugHeaderStore()
provide(DEBUG_HEADER_KEY, debug)
// open/close 暴露给工作流页通过 ref 调用
Expand Down Expand Up @@ -79,7 +79,7 @@ watch([() => bundle.list.currentChatId.value, () => bundle.list.composerResetSig
<transition name="debug-panel">
<div
v-if="debug.visible.value"
class="workflow-debug-panel overflow-hidden border border-N300 bg-white shadow-lg rounded-xl"
class="workflow-debug-panel overflow-hidden border bg-white shadow-lg rounded-xl"
:class="{ expanded: debug.expanded.value }"
>
<ConversationLayout
Expand Down
17 changes: 13 additions & 4 deletions ui/src/stores/chat/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { defineStore } from 'pinia'
import ChatAuthApi from '@/api/chat/auth'
import type { ApplicationAuthProfileMeta, AuthProfile, ChatLoginRequest } from '@/api/types'
import { useChatUserStore } from './user'
import { useChatThemeStore } from './theme'

/** 门户的认证场景;accessToken 为 16 位十六进制字符串,不会与之重名。 */
export const PORTAL_AUTH_SCOPE = 'portal'
Expand Down Expand Up @@ -81,11 +82,19 @@ export const useChatAuthStore = defineStore('chat-auth', {
return token === this.expiredToken ? '' : token
},

/** 获取指定场景的认证前置配置;与当前场景相同时复用。 */
/** 获取并应用指定场景的认证前置主题;与当前场景相同时复用配置。 */
fetchAuthProfile(scope: string): Promise<AuthProfile<unknown>> {
if (scope === this.scope && this.authProfile) return Promise.resolve(this.authProfile)

return isPortalScope(scope) ? ChatAuthApi.getPortalAuthProfile() : ChatAuthApi.getApplicationAuthProfile(scope)
const profileRequest =
scope === this.scope && this.authProfile
? Promise.resolve(this.authProfile)
: isPortalScope(scope)
? ChatAuthApi.getPortalAuthProfile()
: ChatAuthApi.getApplicationAuthProfile(scope)

return profileRequest.then((authProfile) => {
useChatThemeStore().setTheme(authProfile.custom_theme?.theme_color)
return authProfile
})
},

/** 切换当前场景,由守卫在放行前调用。 */

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main concern: fetchAuthProfile now mixes data fetching with a theme side effect. That makes the action less predictable and can create race conditions.

Potential issues

  1. Side effect in a fetch action

    • fetchAuthProfile is named/typed like a pure fetch, but now mutates global theme state.
    • Any caller that only needs the profile will also accidentally change the theme.
    • Prefer applying the theme in the guard after the scope is confirmed, or add an explicit option such as applyTheme.
  2. Race condition / out-of-order responses

    • If fetchAuthProfile('A') is started, then fetchAuthProfile('B') starts and resolves first, A can resolve later and overwrite the theme with A’s theme.
    • Guard the side effect, e.g. only apply when the requested scope is still the current scope:
      if (scope === this.scope) {
        useChatThemeStore().setTheme(authProfile.custom_theme?.theme_color)
      }
    • If this.scope is updated after this call, move the theme application to the guard after setScope.
  3. Repeated cached calls still reapply the theme

    • Even when scope === this.scope && this.authProfile reuses the cached profile, the theme is applied again.
    • If the user can manually change the theme, later calls to fetchAuthProfile may unexpectedly reset it.
    • Consider applying the theme only when the profile is first loaded or when the scope changes.
  4. Undefined theme value

    • authProfile.custom_theme?.theme_color may be undefined.
    • Check setTheme behavior:
      • If it ignores undefined, stale themes from the previous scope may remain.
      • If it resets to default, make that behavior explicit.
    • Safer:
      const themeColor = authProfile.custom_theme?.theme_color
      if (themeColor) {
        useChatThemeStore().setTheme(themeColor)
      }
      or explicitly apply a default/reset value if that is intended.
  5. Possible circular dependency

    • auth now imports theme. Verify that theme does not import auth, otherwise circular imports can cause initialization issues.
  6. No in-flight request deduplication

    • Concurrent calls for the same scope before authProfile is cached will trigger multiple API requests.
    • Optional optimization: cache the pending promise per scope.
  7. Readability

    • The nested ternary is harder to read. async/await would be clearer:
      async fetchAuthProfile(scope: string): Promise<AuthProfile<unknown>> {
        const authProfile =
          scope === this.scope && this.authProfile
            ? this.authProfile
            : isPortalScope(scope)
              ? await ChatAuthApi.getPortalAuthProfile()
              : await ChatAuthApi.getApplicationAuthProfile(scope)
      
        if (scope === this.scope) {
          useChatThemeStore().setTheme(authProfile.custom_theme?.theme_color)
        }
      
        return authProfile
      }

Recommendation

Keep fetchAuthProfile focused on fetching/caching, and apply the theme in the caller/guard where the current scope is known. If the side effect must stay here, guard it by current scope, handle undefined theme explicitly, and avoid reapplying it on cached calls unless that is intentional.

Expand Down
4 changes: 4 additions & 0 deletions ui/src/stores/chat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { createPinia } from 'pinia'
import { useChatAuthStore } from './auth'
import { useChatUserStore } from './user'
import { useChatThemeStore } from './theme'

export const pinia = createPinia()

Expand All @@ -13,6 +14,9 @@ const stores = {
get user() {
return useChatUserStore(pinia)
},
get theme() {
return useChatThemeStore(pinia)
},
}

/** 在 Router、Axios 等组件外代码中按需访问 Chat Store。 */
Expand Down
34 changes: 34 additions & 0 deletions ui/src/stores/chat/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/** 管理 Chat 入口的智能体主题色,并按需应用到当前文档。 */

import { defineStore } from 'pinia'
import { DEFAULT_THEME_COLOR } from '@/constants'

export const useChatThemeStore = defineStore('chat-theme', {
state: () => ({ themeColor: DEFAULT_THEME_COLOR }),

actions: {
/** 配置缺失或非法时使用默认色;主题只保存在内存中。 */
setTheme(themeColor?: string) {
const normalizedColor = themeColor?.trim().toLowerCase()
this.themeColor = normalizedColor && /^#[\da-f]{6}$/.test(normalizedColor) ? normalizedColor : DEFAULT_THEME_COLOR

const rootStyle = document.documentElement.style
const hexColor = this.themeColor.slice(1)
const rgbChannels = [0, 2, 4].map((index) => Number.parseInt(hexColor.slice(index, index + 2), 16)).join(' ')
rootStyle.setProperty('--mk-primary', this.themeColor)
rootStyle.setProperty('--mk-primary-rgb', rgbChannels)
if (this.themeColor === DEFAULT_THEME_COLOR) {
rootStyle.removeProperty('--mk-primary-gradient')
rootStyle.removeProperty('--mk-primary-gradient-end')
} else {
rootStyle.setProperty('--mk-primary-gradient', this.themeColor)
rootStyle.setProperty('--mk-primary-gradient-end', this.themeColor)
}
},

/** 恢复默认主题色与默认蓝紫渐变。 */
resetTheme() {
this.setTheme()
},
},
})

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, the code is functionally reasonable, but there are a few edge cases and architectural concerns worth addressing.

Potential issues

  1. SSR / non-browser safety

    • document.documentElement.style is accessed directly inside the store action.
    • This will throw in SSR, some tests, or non-browser environments.
    • Add a guard:
      if (typeof document === 'undefined') return
  2. DEFAULT_THEME_COLOR is assumed valid

    • User input is validated with /^#[\da-f]{6}$/, but the default constant is not validated.
    • If DEFAULT_THEME_COLOR is ever shorthand like #fff, uppercase, or invalid, the RGB parsing can produce NaN, and the default-gradient comparison can behave inconsistently.
    • Safer approach: normalize/validate the default too, or enforce that it is always a lowercase 6-digit hex string.
  3. Case-sensitive default comparison

    • Input is lowercased, but DEFAULT_THEME_COLOR is compared directly:
      if (this.themeColor === DEFAULT_THEME_COLOR)
    • If DEFAULT_THEME_COLOR is uppercase, e.g. #0052D9, and the user sets #0052d9, the code will treat it as non-default and set gradient variables even though it is the same color.
    • Compare normalized values:
      const defaultColor = DEFAULT_THEME_COLOR.toLowerCase()
  4. Gradient behavior for custom colors may be intentional but is worth confirming

    • For custom colors, both gradient variables are set to the same color:
      rootStyle.setProperty('--mk-primary-gradient', this.themeColor)
      rootStyle.setProperty('--mk-primary-gradient-end', this.themeColor)
    • This effectively removes the “blue-purple” gradient.
    • If the intent is to keep a gradient, you may want to derive a gradient or only override the primary color. If the intent is to flatten the gradient, this is fine.
  5. Initial CSS variables are not applied on store creation

    • The store initializes themeColor, but setTheme is not called automatically.
    • If the application relies on these CSS variables and has no CSS fallback, the initial theme may not be applied until setTheme is called.
    • Call it during app initialization or ensure CSS defines fallback values.
  6. Store has direct DOM side effects

    • This makes the store harder to unit test and couples state management to the DOM.
    • Consider extracting DOM application into a helper, composable, plugin, or store subscription. This is not a bug, but it improves separation of concerns.
  7. Only supports 6-digit hex colors

    • #fff, #ffffffff, rgb(...), hsl(...), etc. are rejected.
    • That may be intentional, but it should be documented as a contract.

Optimization suggestions

  • Extract a color-normalization helper.
  • Extract the hex-to-RGB conversion.
  • Normalize/validate DEFAULT_THEME_COLOR.
  • Use a named regex constant.
  • Keep the DOM guard.
  • resetTheme() is fine, but for clarity you could write:
    this.setTheme(DEFAULT_THEME_COLOR)

Example refactor sketch

const HEX_COLOR_RE = /^#[0-9a-f]{6}$/
const DEFAULT_COLOR = DEFAULT_THEME_COLOR.toLowerCase()

function normalizeColor(color?: string): string {
  const normalized = color?.trim().toLowerCase()
  return normalized && HEX_COLOR_RE.test(normalized) ? normalized : DEFAULT_COLOR
}

function hexToRgbChannels(hex: string): string {
  const value = hex.slice(1)
  const r = Number.parseInt(value.slice(0, 2), 16)
  const g = Number.parseInt(value.slice(2, 4), 16)
  const b = Number.parseInt(value.slice(4, 6), 16)
  return `${r} ${g} ${b}`
}

export const useChatThemeStore = defineStore('chat-theme', {
  state: () => ({ themeColor: DEFAULT_COLOR }),

  actions: {
    setTheme(themeColor?: string) {
      const color = normalizeColor(themeColor)
      this.themeColor = color

      if (typeof document === 'undefined') return

      const rootStyle = document.documentElement.style
      rootStyle.setProperty('--mk-primary', color)
      rootStyle.setProperty('--mk-primary-rgb', hexToRgbChannels(color))

      if (color === DEFAULT_COLOR) {
        rootStyle.removeProperty('--mk-primary-gradient')
        rootStyle.removeProperty('--mk-primary-gradient-end')
      } else {
        rootStyle.setProperty('--mk-primary-gradient', color)
        rootStyle.setProperty('--mk-primary-gradient-end', color)
      }
    },

    resetTheme() {
      this.setTheme(DEFAULT_COLOR)
    },
  },
})

No major functional bug is present if DEFAULT_THEME_COLOR is guaranteed to be a lowercase #rrggbb value and the store is only used client-side. The main improvements are SSR safety, default-color normalization, and separating DOM side effects from store state management.

8 changes: 8 additions & 0 deletions ui/src/styles/STYLE_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,14 @@ Tailwind 类。
不要直接写这些变量,也不要绕过项目变量写入 Element Plus 的 `--el-*` 主题变量。Element Plus
色阶继续由 `element-plus.scss` 基于 `--mk-primary` 映射生成。

Chat 的主题能力由独立的 `src/stores/chat/theme.ts` 提供,通过 Chat 的 `useStore().theme`
访问。`setTheme(themeColor)` 接收六位十六进制颜色,空值或非法值回退到默认色;
`resetTheme()` 恢复默认主题。仅显式调用时更新当前文档根节点的项目颜色变量,不持久化,
不加载 Admin 外观配置。Chat Auth Store 的 `fetchAuthProfile()` 在获取或复用认证前置配置后,
显式应用顶层 `custom_theme.theme_color`,登录页和正式对话共用当前认证场景的主题。
对话装配不从智能体 profile 设置主题,门户内切换智能体沿用门户认证配置中的主题。
Admin 不调用该 Store。

普通 CSS 使用 `color: var(--mk-primary)`。

### Tailwind
Expand Down
6 changes: 3 additions & 3 deletions ui/src/styles/element-plus.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
--el-color-success-dark-2: color-mix(in srgb, var(--mk-success) 85%, black);
--el-color-warning: var(--mk-warning);
--el-color-warning-dark-2: color-mix(in srgb, var(--mk-warning) 85%, black);
--el-border-color: var(--mk-N350);
--el-border-color: var(--mk-N300);
--el-border-radius-base: 6px;
--el-border-radius-round: 16px;
--el-border-radius-small: 4px;
Expand Down Expand Up @@ -1147,7 +1147,7 @@
--el-table-header-bg-color: var(--mk-N100);
--el-table-text-color: var(--el-text-color-primary);
--el-table-row-hover-bg-color: color-mix(in srgb, var(--el-color-primary) 4%, white);
--el-table-border-color: var(--mk-N300);
--el-table-border-color: var(--el-border-color);
border-radius: var(--radius-xl) var(--radius-xl) 0 0;

thead th {
Expand Down Expand Up @@ -1268,7 +1268,7 @@
}
&--plain {
&.el-tag--info {
--el-tag-border-color: rgb(var(--mk-N900-rgb) / 15%) !important;
--el-tag-border-color: var(--el-border-color) !important;
--el-tag-text-color: var(--mk-N600);
font-weight: 500 !important;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ const previewHeaderStyle = computed<CSSProperties>(() => ({

<template>
<div class="mk-gray-card-lg flex h-full items-end gap-2 overflow-hidden">
<div class="flex-column h-full min-w-0 flex-1 overflow-hidden border border-N300 bg-white shadow-lg rounded-xl">
<header class="flex-between h-header shrink-0 gap-4 border-b border-N300 p-4" :style="previewHeaderStyle">
<div class="flex-column h-full min-w-0 flex-1 overflow-hidden border bg-white shadow-lg rounded-xl">
<header class="flex-between h-header shrink-0 gap-4 border-b p-4" :style="previewHeaderStyle">
<div class="flex-align-center min-w-0 flex-1 gap-2">
<MkIcon name="icon_sidebar_outlined" :size="18" class="mr-2 shrink-0" />
<ApplicationIcon :icon="previewImages.icon" :size="24" class="shrink-0" />
Expand Down Expand Up @@ -68,7 +68,7 @@ const previewHeaderStyle = computed<CSSProperties>(() => ({
<div class="h-8.5 w-2/3 rounded-xl bg-N100"></div>
</div>
<div class="mt-auto space-y-2">
<div class="mk-input-box flex h-23 items-end justify-end border border-N350/60 shadow-lg">
<div class="mk-input-box flex h-23 items-end justify-end border shadow-lg">
<!-- 预览发送按钮 -->
<el-button circle disabled type="primary">
<MkIcon name="icon_arrow-up_outlined" :size="18" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ function handleRefresh() {
</template>
<div class="min-w-0">
<p>简易智能体</p>
<p class="text-sm text-N500 whitespace-normal">通过表单设置方式,快速搭建基础功能的智能体</p>
<p class="text-sm text-N600 whitespace-normal">通过表单设置方式,快速搭建基础功能的智能体</p>
</div>
</MkDropdownItem>
<MkDropdownItem class="py-2! items-start!" @click="handleOpenAdvancedApplicationCreate">
Expand All @@ -119,7 +119,7 @@ function handleRefresh() {
</template>
<div class="min-w-0">
<p class="leading-5">高级智能体</p>
<p class="text-sm text-N500 whitespace-normal">使用低代码拖拉拽方式,灵活编排复杂逻辑、功能丰富的智能体</p>
<p class="text-sm text-N600 whitespace-normal">使用低代码拖拉拽方式,灵活编排复杂逻辑、功能丰富的智能体</p>
</div>
</MkDropdownItem>

Expand Down
8 changes: 4 additions & 4 deletions ui/src/views/knowledge/components/ButtonCreateKnowledge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -139,31 +139,31 @@ function handleImportCreate(file: UploadFile) {
<template #icon><KnowledgeIcon :type="KNOWLEDGE_TYPE.BASE" /></template>
<div class="min-w-0">
<p>通用知识库</p>
<p class="text-sm text-N500 whitespace-normal">通过上传文件或手动录入构建知识库</p>
<p class="text-sm text-N600 whitespace-normal">通过上传文件或手动录入构建知识库</p>
</div>
</MkDropdownItem>
<!-- 创建 Web 知识库 -->
<MkDropdownItem class="py-2!" @click="handleCreateWebKnowledge">
<template #icon><KnowledgeIcon :type="KNOWLEDGE_TYPE.WEB" /></template>
<div class="min-w-0">
<p>Web 知识库</p>
<p class="text-sm text-N500 whitespace-normal">通过网站链接构建知识库</p>
<p class="text-sm text-N600 whitespace-normal">通过网站链接构建知识库</p>
</div>
</MkDropdownItem>
<!-- 创建飞书知识库 -->
<MkDropdownItem class="py-2!" @click="handleCreateLarkKnowledge">
<template #icon><KnowledgeIcon :type="KNOWLEDGE_TYPE.LARK" /></template>
<div class="min-w-0">
<p>飞书知识库</p>
<p class="text-sm text-N500 whitespace-normal">通过飞书文档构建知识库</p>
<p class="text-sm text-N600 whitespace-normal">通过飞书文档构建知识库</p>
</div>
</MkDropdownItem>
<!-- 创建工作流知识库 -->
<MkDropdownItem class="py-2!" @click="handleCreateWorkflowKnowledge">
<template #icon><KnowledgeIcon :type="KNOWLEDGE_TYPE.WORKFLOW" /></template>
<div class="min-w-0">
<p>工作流知识库</p>
<p class="text-sm text-N500 whitespace-normal">通过自定义工作流方式构建知识库</p>
<p class="text-sm text-N600 whitespace-normal">通过自定义工作流方式构建知识库</p>
</div>
</MkDropdownItem>
<!-- 导入创建 -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ defineExpose({ open, close })
</div>
</el-scrollbar>

<div class="mk-input-box m-4 mt-0 border border-N350/60 shadow-lg transition-colors focus-within:border-primary/60">
<div class="mk-input-box m-4 mt-0 border shadow-lg transition-colors focus-within:border-primary/60">
<el-input
v-model="requirement"
type="textarea"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const showContent = computed(() => isSuccess.value || props.showContentOnError)
</script>

<template>
<el-card shadow="hover" class="border-N300! cursor-pointer" @click="show = !show">
<el-card shadow="hover" class="cursor-pointer" @click="show = !show">
<MkCollapse v-model:expanded="show" trigger="indicator">
<template #label>
<slot name="header" />
Expand Down
2 changes: 1 addition & 1 deletion ui/src/workflow-canvas/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function renderGraphData(data: LogicFlow.GraphConfigData = props.data ?? {}) {
lf.value.setTheme({
bezier: { stroke: '#afafaf', strokeWidth: 1 },
edgeOutline: {
stroke: 'var(--mk-N350)',
stroke: 'var(--mk-N300)',
strokeWidth: 1.5,
strokeDasharray: '4,4', // 虚线长度和间隔
hover: { stroke: 'var(--mk-primary)' },
Expand Down
Loading