diff --git a/.claude/skills/shadcn-theme/SKILL.md b/.claude/skills/shadcn-theme/SKILL.md
new file mode 100644
index 0000000000..c6534a25a6
--- /dev/null
+++ b/.claude/skills/shadcn-theme/SKILL.md
@@ -0,0 +1,98 @@
+---
+name: shadcn-theming
+description: Design tokens and theming for shadcn/ui. Covers CSS variables, OKLCH colors, dark/light mode, and theme configuration for both Radix and Base UI primitives.
+versions:
+ shadcn-ui: "2.x"
+ tailwindcss: "4.1"
+user-invocable: true
+allowed-tools: Read, Write, Edit, Glob, Grep
+references: references/theming-guide.md, references/templates/theme-setup.md
+related-skills: shadcn-registries, shadcn-components
+---
+
+# shadcn Theming
+
+## Agent Workflow (MANDATORY)
+
+Before theming work, use `TeamCreate`:
+
+1. **fuse-ai-pilot:explore-codebase** - Find existing theme tokens
+2. **fuse-ai-pilot:research-expert** - Verify OKLCH patterns via Context7
+
+After: Run **fuse-ai-pilot:sniper** for validation.
+
+## Overview
+
+| Feature | Description |
+|---------|-------------|
+| **CSS Variables** | `--background`, `--foreground`, `--primary` |
+| **OKLCH Colors** | Wide-gamut P3 color space |
+| **Dark Mode** | `.dark` class or `prefers-color-scheme` |
+| **Tailwind v4** | `@theme` directive integration |
+
+## Critical Rules
+
+1. **ALWAYS use OKLCH** color space for all tokens
+2. **ALWAYS define dark mode** overrides for every token
+3. **NEVER hard-code** hex or rgb in components
+4. **USE @theme** directive for Tailwind v4 integration
+5. **MAP semantic tokens** to primitive OKLCH values
+
+## Architecture
+
+```
+app/
+├── globals.css # :root + .dark token definitions
+└── tailwind.config.ts # Optional (v3) or @theme (v4)
+```
+
+-> See [theme-setup.md](references/templates/theme-setup.md) for complete theme
+
+## Token Hierarchy
+
+```
+Component: --card, --card-foreground, --button-*
+ ↑
+Semantic: --primary, --secondary, --accent, --muted
+ ↑
+Primitive: oklch(55% 0.20 260), oklch(98% 0.01 260)
+```
+
+## Validation Checklist
+
+```
+[ ] CSS variables defined in :root
+[ ] Dark mode overrides in .dark
+[ ] OKLCH color space used
+[ ] Chart variables (--chart-1 to --chart-5)
+[ ] Sidebar variables if applicable
+[ ] No hard-coded hex in components
+```
+
+## Best Practices
+
+### DO
+- Use OKLCH for all colors
+- Define semantic tokens mapped to primitives
+- Provide dark mode overrides for all tokens
+- Use `@theme` for Tailwind v4 integration
+
+### DON'T
+- Hard-code hex or rgb values
+- Skip dark mode definitions
+- Mix color spaces (hex + oklch)
+- Define tokens only in Tailwind config
+
+## Reference Guide
+
+### Concepts
+
+| Topic | Reference | When to Consult |
+|-------|-----------|-----------------|
+| **Theming Guide** | [theming-guide.md](references/theming-guide.md) | CSS variables and OKLCH setup |
+
+### Templates
+
+| Template | When to Use |
+|----------|-------------|
+| [theme-setup.md](references/templates/theme-setup.md) | Complete theme configuration |
diff --git a/.claude/skills/shadcn-theme/references/templates/theme-setup.md b/.claude/skills/shadcn-theme/references/templates/theme-setup.md
new file mode 100644
index 0000000000..20ec0b734a
--- /dev/null
+++ b/.claude/skills/shadcn-theme/references/templates/theme-setup.md
@@ -0,0 +1,109 @@
+---
+name: theme-setup
+description: Complete shadcn/ui theme with CSS variables, dark mode, and Tailwind v4 integration
+keywords: theme, setup, css, oklch, dark-mode, tailwind
+---
+
+# Theme Setup
+
+## Complete Light + Dark Theme
+
+```css
+/* app/globals.css */
+@import "tailwindcss";
+
+:root {
+ --background: oklch(100% 0 0);
+ --foreground: oklch(14.1% 0.005 285.82);
+ --card: oklch(100% 0 0);
+ --card-foreground: oklch(14.1% 0.005 285.82);
+ --popover: oklch(100% 0 0);
+ --popover-foreground: oklch(14.1% 0.005 285.82);
+ --primary: oklch(20.5% 0.016 285.94);
+ --primary-foreground: oklch(98.5% 0 0);
+ --secondary: oklch(96.7% 0.001 286.38);
+ --secondary-foreground: oklch(20.5% 0.016 285.94);
+ --accent: oklch(96.7% 0.001 286.38);
+ --accent-foreground: oklch(20.5% 0.016 285.94);
+ --muted: oklch(96.7% 0.001 286.38);
+ --muted-foreground: oklch(55.6% 0.01 285.94);
+ --destructive: oklch(57.7% 0.245 27.33);
+ --destructive-foreground: oklch(98.5% 0 0);
+ --border: oklch(92.2% 0.004 286.32);
+ --input: oklch(92.2% 0.004 286.32);
+ --ring: oklch(87.1% 0.006 286.29);
+ --radius: 0.625rem;
+ --chart-1: oklch(64.6% 0.222 41.12);
+ --chart-2: oklch(60% 0.19 160);
+ --chart-3: oklch(55% 0.18 230);
+ --chart-4: oklch(70% 0.15 300);
+ --chart-5: oklch(75% 0.12 60);
+ --sidebar: oklch(98.5% 0 0);
+ --sidebar-foreground: oklch(14.1% 0.005 285.82);
+ --sidebar-primary: oklch(20.5% 0.016 285.94);
+ --sidebar-accent: oklch(96.7% 0.001 286.38);
+ --sidebar-border: oklch(92.2% 0.004 286.32);
+ --sidebar-ring: oklch(87.1% 0.006 286.29);
+}
+
+.dark {
+ --background: oklch(14.1% 0.005 285.82);
+ --foreground: oklch(98.5% 0 0);
+ --card: oklch(14.1% 0.005 285.82);
+ --card-foreground: oklch(98.5% 0 0);
+ --popover: oklch(14.1% 0.005 285.82);
+ --popover-foreground: oklch(98.5% 0 0);
+ --primary: oklch(92.2% 0 0);
+ --primary-foreground: oklch(20.5% 0.016 285.94);
+ --secondary: oklch(26.9% 0.006 286.03);
+ --secondary-foreground: oklch(98.5% 0 0);
+ --accent: oklch(26.9% 0.006 286.03);
+ --accent-foreground: oklch(98.5% 0 0);
+ --muted: oklch(26.9% 0.006 286.03);
+ --muted-foreground: oklch(71.1% 0.013 286.07);
+ --destructive: oklch(57.7% 0.245 27.33);
+ --border: oklch(26.9% 0.006 286.03);
+ --input: oklch(26.9% 0.006 286.03);
+ --ring: oklch(36.2% 0.014 285.88);
+ --sidebar: oklch(14.1% 0.005 285.82);
+ --sidebar-foreground: oklch(98.5% 0 0);
+ --sidebar-primary: oklch(48.8% 0.243 264.05);
+ --sidebar-accent: oklch(26.9% 0.006 286.03);
+ --sidebar-border: oklch(26.9% 0.006 286.03);
+}
+```
+
+## Tailwind v4 @theme Bridge
+
+```css
+@theme {
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-accent: var(--accent);
+ --color-muted: var(--muted);
+ --color-destructive: var(--destructive);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --radius-lg: var(--radius);
+}
+```
+
+## Theme Switching (React)
+
+```tsx
+// components/theme-provider.tsx
+"use client"
+import { ThemeProvider as NextThemesProvider } from "next-themes"
+
+export function ThemeProvider({ children }: { children: React.ReactNode }) {
+ return (
+
+ {children}
+
+ )
+}
+```
diff --git a/.claude/skills/shadcn-theme/references/theming-guide.md b/.claude/skills/shadcn-theme/references/theming-guide.md
new file mode 100644
index 0000000000..24d6ccc3f3
--- /dev/null
+++ b/.claude/skills/shadcn-theme/references/theming-guide.md
@@ -0,0 +1,90 @@
+---
+name: theming-guide
+description: CSS variables, OKLCH colors, chart/sidebar tokens, and Tailwind integration
+when-to-use: When configuring theme tokens or color system
+keywords: theme, oklch, css-variables, dark-mode, tailwind, tokens, colors
+priority: high
+related: ../SKILL.md
+---
+
+# Theming Guide
+
+## Overview
+
+shadcn/ui uses CSS custom properties with OKLCH color space for wide-gamut P3 support and perceptual uniformity. Tokens follow a 3-level hierarchy: primitive -> semantic -> component.
+
+---
+
+## Key Concepts
+
+| Concept | Description |
+|---------|-------------|
+| **OKLCH** | `oklch(L% C H)` - perceptually uniform, P3 gamut |
+| **Semantic tokens** | `--primary`, `--secondary`, `--accent` |
+| **Dark mode** | `.dark` class or `prefers-color-scheme` |
+| **@theme** | Tailwind v4 custom property bridge |
+
+## Layout Variables
+
+| Variable | Purpose |
+|----------|---------|
+| `--background` | Page background |
+| `--foreground` | Default text |
+| `--card` / `--card-foreground` | Card surfaces |
+| `--popover` / `--popover-foreground` | Popover surfaces |
+
+## Interactive Variables
+
+| Variable | Purpose |
+|----------|---------|
+| `--primary` / `--primary-foreground` | Primary buttons, links |
+| `--secondary` | Secondary elements |
+| `--accent` | Hover backgrounds |
+| `--muted` / `--muted-foreground` | Muted backgrounds |
+| `--destructive` | Danger/delete actions |
+
+## Utility Variables
+
+| Variable | Purpose |
+|----------|---------|
+| `--border` | Default border color |
+| `--input` | Input border color |
+| `--ring` | Focus ring color |
+| `--radius` | Default border radius (0.625rem) |
+
+## OKLCH Color Space
+
+```
+oklch(Lightness% Chroma Hue)
+ L: 0-100% (0 = black, 100 = white)
+ C: 0-0.4 (0 = gray, 0.4 = vivid)
+ H: 0-360 (hue angle)
+```
+
+Benefits: perceptual uniformity, P3 gamut, predictable contrast.
+
+## Theme Switching
+
+Use `.dark` class on `` or CSS media query:
+
+```tsx
+
+```
+
+For full setup with next-themes, see [theme-setup.md](templates/theme-setup.md).
+
+---
+
+## Common Mistakes
+
+| Mistake | Fix |
+|---------|-----|
+| Mixing hex and OKLCH | Use OKLCH consistently |
+| Forgetting dark overrides | Every :root token needs .dark equivalent |
+| Defining colors in Tailwind config | Use CSS variables with @theme bridge |
+
+---
+
+## Related Templates
+
+- [theme-setup.md](templates/theme-setup.md) - Complete theme configuration
diff --git a/frontend/app/web-gold/src/layouts/MainLayout.vue b/frontend/app/web-gold/src/layouts/MainLayout.vue
index 4298cd05b3..33f5c21168 100644
--- a/frontend/app/web-gold/src/layouts/MainLayout.vue
+++ b/frontend/app/web-gold/src/layouts/MainLayout.vue
@@ -12,7 +12,7 @@ import SidebarNav from '@/components/SidebarNav.vue'
-
+
diff --git a/frontend/app/web-gold/src/theme.css b/frontend/app/web-gold/src/theme.css
index c6287260b4..66ea28880d 100644
--- a/frontend/app/web-gold/src/theme.css
+++ b/frontend/app/web-gold/src/theme.css
@@ -341,6 +341,28 @@
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
+ /* 品牌色阶 */
+ --color-primary-50: var(--color-primary-50);
+ --color-primary-100: var(--color-primary-100);
+ --color-primary-200: var(--color-primary-200);
+ --color-primary-300: var(--color-primary-300);
+ --color-primary-400: var(--color-primary-400);
+ --color-primary-500: var(--color-primary-500);
+ --color-primary-600: var(--color-primary-600);
+ --color-primary-700: var(--color-primary-700);
+
+ /* 灰色系 */
+ --color-gray-50: var(--color-gray-50);
+ --color-gray-100: var(--color-gray-100);
+ --color-gray-200: var(--color-gray-200);
+ --color-gray-300: var(--color-gray-300);
+ --color-gray-400: var(--color-gray-400);
+ --color-gray-500: var(--color-gray-500);
+ --color-gray-600: var(--color-gray-600);
+ --color-gray-700: var(--color-gray-700);
+ --color-gray-800: var(--color-gray-800);
+ --color-gray-900: var(--color-gray-900);
+
--font-sans: var(--font-sans);
--font-mono: var(--font-mono);
--font-serif: var(--font-serif);
diff --git a/frontend/app/web-gold/src/views/content-style/components/BenchmarkForm.vue b/frontend/app/web-gold/src/views/content-style/components/BenchmarkForm.vue
index 06586cf694..4cfb063d26 100644
--- a/frontend/app/web-gold/src/views/content-style/components/BenchmarkForm.vue
+++ b/frontend/app/web-gold/src/views/content-style/components/BenchmarkForm.vue
@@ -43,7 +43,7 @@ function handleReset() {
-
+
@@ -66,28 +66,6 @@ function handleReset() {
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/app/web-gold/src/views/content-style/components/BenchmarkTable.vue b/frontend/app/web-gold/src/views/content-style/components/BenchmarkTable.vue
index d7251236d3..bb24890f53 100644
--- a/frontend/app/web-gold/src/views/content-style/components/BenchmarkTable.vue
+++ b/frontend/app/web-gold/src/views/content-style/components/BenchmarkTable.vue
@@ -46,6 +46,12 @@ const isAllSelected = computed(() => {
return props.data.length > 0 && props.selectedRowKeys.length === props.data.length
})
+// 半选状态(部分选中)
+const isIndeterminate = computed(() => {
+ const selectedLen = props.selectedRowKeys.length
+ return selectedLen > 0 && selectedLen < props.data.length
+})
+
// 切换排序
function handleSort(key) {
if (sortKey.value === key) {
@@ -59,10 +65,10 @@ function handleSort(key) {
// 选择切换
function handleSelectAll(checked) {
- if (isAllSelected.value) {
- emit('update:selectedRowKeys', [])
- } else {
+ if (checked) {
emit('update:selectedRowKeys', props.data.map(item => String(item.id)))
+ } else {
+ emit('update:selectedRowKeys', [])
}
}
@@ -133,6 +139,7 @@ function formatNumber(value) {
diff --git a/frontend/app/web-gold/src/views/dh/VoiceCopy.vue b/frontend/app/web-gold/src/views/dh/VoiceCopy.vue
index 52e0311422..063f284083 100644
--- a/frontend/app/web-gold/src/views/dh/VoiceCopy.vue
+++ b/frontend/app/web-gold/src/views/dh/VoiceCopy.vue
@@ -3,7 +3,6 @@ import { ref, reactive, computed, onMounted } from 'vue'
import { toast } from 'vue-sonner'
import { Icon } from '@iconify/vue'
import dayjs from 'dayjs'
-import BasicLayout from '@/layouts/components/BasicLayout.vue'
import { MaterialService } from '@/api/material'
import { VoiceService } from '@/api/voice'
import { useUpload } from '@/composables/useUpload'
@@ -42,6 +41,7 @@ import {
} from '@/components/ui/alert-dialog'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { Progress } from '@/components/ui/progress'
+import TaskPageLayout from '@/views/system/task-management/components/TaskPageLayout.vue'
// ========== 常量 ==========
const MAX_FILE_SIZE = 5 * 1024 * 1024
@@ -369,32 +369,41 @@ onMounted(() => loadVoiceList())
-
-
-