ソースを参照

feat(frontend): 新增AI内容生成页面

- 新增 /pages/ai-content/index 页面
- 实现5步骤引导:基础设置→大纲预览→角色设定→内容生成→质量检测
- 支持选择内容类型(小说/培训/营销等)和行业
- 支持生成大纲、角色设定、分步生成内容
- 集成敏感词检测、合规检查、质量评分功能
- create页面新增"AI 内容"按钮跳转

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MyFramework User 5 ヶ月 前
コミット
56ebf9abb9

+ 6 - 0
my-uniapp-vue3/src/pages.json

@@ -49,6 +49,12 @@
         "navigationStyle": "custom"
       }
     },
+    {
+      "path": "pages/ai-content/index",
+      "style": {
+        "navigationStyle": "custom"
+      }
+    },
     {
       "path": "pages/favorites/index",
       "style": {

+ 1042 - 0
my-uniapp-vue3/src/pages/ai-content/index.vue

@@ -0,0 +1,1042 @@
+<template>
+  <view class="page">
+    <!-- 顶部导航栏 -->
+    <view class="nav-bar">
+      <view class="nav-content">
+        <view class="nav-left" @click="goBack">
+          <text class="back-icon">←</text>
+        </view>
+        <text class="page-title">AI 内容生成</text>
+        <view class="nav-right">
+          <text class="nav-btn" @click="showHelp = true">?</text>
+        </view>
+      </view>
+    </view>
+
+    <!-- 主内容区 -->
+    <view class="main-content">
+      <!-- 步骤指示器 -->
+      <view class="steps-indicator">
+        <view
+          v-for="(step, index) in steps"
+          :key="index"
+          class="step-item"
+          :class="{ active: currentStep >= index, current: currentStep === index }"
+        >
+          <view class="step-circle">{{ index + 1 }}</view>
+          <text class="step-text">{{ step }}</text>
+        </view>
+      </view>
+
+      <!-- 步骤1:基础设置 -->
+      <view v-if="currentStep === 0" class="card">
+        <view class="card-header">
+          <text class="card-title">📋 内容设置</text>
+        </view>
+
+        <!-- 内容类型 -->
+        <view class="form-item">
+          <text class="form-label">内容类型</text>
+          <view class="type-grid">
+            <view
+              v-for="cat in contentCategories"
+              :key="cat.name"
+              class="type-category"
+            >
+              <view class="category-header">{{ cat.name }}</view>
+              <view class="type-items">
+                <view
+                  v-for="type in cat.types"
+                  :key="type"
+                  class="type-item"
+                  :class="{ active: selectedType === type }"
+                  @click="selectedType = type"
+                >
+                  {{ type }}
+                </view>
+              </view>
+            </view>
+          </view>
+        </view>
+
+        <!-- 行业选择 -->
+        <view class="form-item">
+          <text class="form-label">所属行业</text>
+          <scroll-view scroll-x class="industry-scroll">
+            <view class="industry-list">
+              <view
+                v-for="ind in industries"
+                :key="ind"
+                class="industry-item"
+                :class="{ active: selectedIndustry === ind }"
+                @click="selectedIndustry = ind"
+              >
+                {{ ind }}
+              </view>
+            </view>
+          </scroll-view>
+        </view>
+
+        <!-- 主题输入 -->
+        <view class="form-item">
+          <text class="form-label">创作主题</text>
+          <input
+            v-model="theme"
+            class="theme-input"
+            placeholder="输入创作主题,如:都市爱情、励志故事"
+          />
+        </view>
+
+        <!-- 目标字数 -->
+        <view class="form-item">
+          <text class="form-label">目标字数:{{ targetLength }} 字</text>
+          <slider
+            :value="targetLength"
+            :min="500"
+            :max="10000"
+            :step="500"
+            @change="(e: any) => targetLength = e.detail.value"
+            activeColor="#4F46E5"
+            backgroundColor="#e5e7eb"
+            block-size="20"
+          />
+          <view class="slider-range">
+            <text>500字</text>
+            <text>10000字</text>
+          </view>
+        </view>
+
+        <button class="next-btn" @click="goToStep2">下一步:生成大纲 →</button>
+      </view>
+
+      <!-- 步骤2:大纲预览 -->
+      <view v-if="currentStep === 1" class="card">
+        <view class="card-header">
+          <text class="card-title">📑 内容大纲</text>
+          <text class="header-action" @click="regenerateOutline">🔄 重新生成</text>
+        </view>
+
+        <view v-if="generatingOutline" class="loading-state">
+          <text>正在生成大纲...</text>
+        </view>
+
+        <view v-else class="outline-content">
+          <view class="outline-stats">
+            <text class="stat-item">总章节:{{ outline.length }}</text>
+            <text class="stat-item">预计字数:{{ targetLength }}</text>
+          </view>
+
+          <view
+            v-for="(chapter, index) in outline"
+            :key="index"
+            class="chapter-item"
+          >
+            <view class="chapter-header">
+              <text class="chapter-title">{{ chapter.title }}</text>
+              <text class="chapter-words">{{ chapter.wordCount }}字</text>
+            </view>
+            <text class="chapter-desc">{{ chapter.description }}</text>
+          </view>
+        </view>
+
+        <view class="btn-row">
+          <button class="back-btn" @click="currentStep = 0">← 上一步</button>
+          <button class="next-btn" @click="goToStep3">下一步:生成内容 →</button>
+        </view>
+      </view>
+
+      <!-- 步骤3:角色设定 -->
+      <view v-if="currentStep === 2" class="card">
+        <view class="card-header">
+          <text class="card-title">👥 角色设定</text>
+          <text class="header-action" @click="generateCharacters">🔄 重新生成</text>
+        </view>
+
+        <view class="characters-list">
+          <view
+            v-for="char in characters"
+            :key="char.id"
+            class="character-card"
+          >
+            <view class="char-avatar">{{ char.gender === '男' ? '👨' : '👩' }}</view>
+            <view class="char-info">
+              <text class="char-name">{{ char.name }}</text>
+              <text class="char-detail">年龄:{{ char.age }}</text>
+              <text class="char-detail">性格:{{ char.personality }}</text>
+              <text class="char-detail">角色:{{ char.role }}</text>
+            </view>
+          </view>
+        </view>
+
+        <view class="btn-row">
+          <button class="back-btn" @click="currentStep = 1">← 上一步</button>
+          <button class="next-btn" @click="currentStep = 3">下一步:生成内容 →</button>
+        </view>
+      </view>
+
+      <!-- 步骤4:内容生成 -->
+      <view v-if="currentStep === 3" class="card">
+        <view class="card-header">
+          <text class="card-title">✍️ 内容生成</text>
+          <view class="header-actions">
+            <text class="header-action" @click="saveDraft">💾 保存</text>
+            <text class="header-action" @click="showQualityScore">📊 评分</text>
+          </view>
+        </view>
+
+        <!-- 生成进度 -->
+        <view v-if="generating" class="progress-section">
+          <view class="progress-header">
+            <text>正在生成第 {{ currentChapter + 1 }} 章...</text>
+            <text>{{ Math.round((currentChapter + 1) / outline.length * 100) }}%</text>
+          </view>
+          <progress
+            :percent="Math.round((currentChapter + 1) / outline.length * 100)"
+            activeColor="#4F46E5"
+            backgroundColor="#e5e7eb"
+            stroke-width="8"
+          />
+        </view>
+
+        <!-- 生成的内容 -->
+        <view class="generated-content">
+          <view
+            v-for="(chapter, index) in generatedChapters"
+            :key="index"
+            class="content-chapter"
+          >
+            <view class="chapter-badge">{{ index + 1 }}</view>
+            <text class="chapter-text">{{ chapter }}</text>
+          </view>
+        </view>
+
+        <view v-if="!generating && generatedChapters.length === 0" class="empty-state">
+          <text>点击下方按钮开始生成内容</text>
+        </view>
+
+        <view class="btn-row">
+          <button class="back-btn" @click="currentStep = 2">← 上一步</button>
+          <button class="generate-btn" :disabled="generating" @click="startGeneration">
+            {{ generating ? '生成中...' : '🚀 开始生成' }}
+          </button>
+        </view>
+      </view>
+
+      <!-- 步骤5:质量检测 -->
+      <view v-if="currentStep === 4" class="card">
+        <view class="card-header">
+          <text class="card-title">✅ 质量检测</text>
+        </view>
+
+        <!-- 敏感词检测 -->
+        <view class="quality-item">
+          <view class="quality-header">
+            <text class="quality-title">🔍 敏感词检测</text>
+            <text class="quality-status pass">通过</text>
+          </view>
+          <view v-if="sensitiveResult.foundWords.length > 0" class="sensitive-words">
+            <text v-for="word in sensitiveResult.foundWords" :key="word" class="sensitive-tag">
+              {{ word }}
+            </text>
+          </view>
+        </view>
+
+        <!-- 合规检查 -->
+        <view class="quality-item">
+          <view class="quality-header">
+            <text class="quality-title">📋 合规检查</text>
+            <text class="quality-status pass">通过</text>
+          </view>
+          <view v-if="complianceResult.warnings.length > 0" class="compliance-warnings">
+            <text v-for="warn in complianceResult.warnings" :key="warn" class="warning-tag">
+              {{ warn }}
+            </text>
+          </view>
+        </view>
+
+        <!-- 质量评分 -->
+        <view v-if="qualityScore" class="quality-item">
+          <view class="quality-header">
+            <text class="quality-title">📊 内容评分</text>
+            <text class="quality-score">{{ qualityScore.overall }}分</text>
+          </view>
+          <view class="score-dimensions">
+            <view
+              v-for="(value, key) in qualityScore.dimensions"
+              :key="key"
+              class="dimension-item"
+            >
+              <text class="dimension-name">{{ getDimensionName(key) }}</text>
+              <view class="dimension-bar">
+                <view class="dimension-fill" :style="{ width: value + '%' }"></view>
+              </view>
+              <text class="dimension-value">{{ Math.round(value) }}</text>
+            </view>
+          </view>
+        </view>
+
+        <view class="btn-row">
+          <button class="back-btn" @click="currentStep = 3">← 上一步</button>
+          <button class="primary-btn" @click="useContent">📝 使用此内容</button>
+        </view>
+      </view>
+    </view>
+
+    <!-- 帮助弹窗 -->
+    <view v-if="showHelp" class="modal-overlay" @click="showHelp = false">
+      <view class="modal-content" @click.stop>
+        <view class="modal-header">
+          <text class="modal-title">使用帮助</text>
+          <text class="modal-close" @click="showHelp = false">✕</text>
+        </view>
+        <view class="modal-body">
+          <text class="help-text">1. 选择内容类型和行业</text>
+          <text class="help-text">2. 输入创作主题</text>
+          <text class="help-text">3. 生成并预览大纲</text>
+          <text class="help-text">4. 查看角色设定</text>
+          <text class="help-text">5. 一键生成完整内容</text>
+          <text class="help-text">6. 质量检测后使用</text>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup lang="ts">
+import { ref, computed } from 'vue';
+import { get, post } from '../../utils/request';
+
+const steps = ['基础设置', '大纲预览', '角色设定', '内容生成', '质量检测'];
+const currentStep = ref(0);
+
+// 基础设置
+const contentCategories = [
+  { name: '创作类', types: ['小说', '故事', '剧本', '诗歌', '散文'] },
+  { name: '营销类', types: ['产品介绍', '广告文案', '朋友圈', '小红书', '抖音脚本'] },
+  { name: '教育类', types: ['课件', '培训', '教程', '知识科普'] },
+  { name: '商务类', types: ['销售话术', '客服话术', '商务邮件'] },
+  { name: '媒体类', types: ['新闻播报', '天气预报', '体育解说'] },
+];
+
+const industries = ['通用', '医疗健康', '教育培训', '金融服务', '电子商务', '餐饮美食'];
+const selectedType = ref('小说');
+const selectedIndustry = ref('通用');
+const theme = ref('');
+const targetLength = ref(2000);
+
+// 大纲
+const generatingOutline = ref(false);
+const outline = ref<{ title: string; description: string; wordCount: number }[]>([]);
+
+// 角色
+const characters = ref<any[]>([]);
+
+// 内容生成
+const generating = ref(false);
+const currentChapter = ref(0);
+const generatedChapters = ref<string[]>([]);
+
+// 质量检测
+const sensitiveResult = ref<{ isClean: boolean; foundWords: string[] }>({ isClean: true, foundWords: [] });
+const complianceResult = ref<{ passed: boolean; warnings: string[] }>({ passed: true, warnings: [] });
+const qualityScore = ref<any>(null);
+
+// UI状态
+const showHelp = ref(false);
+
+const fullContent = computed(() => generatedChapters.value.join('\n\n'));
+
+const dimensionNames: Record<string, string> = {
+  fluency: '流畅度',
+  naturalness: '自然度',
+  emotion_consistency: '情感一致',
+  topic_adherence: '主题相关',
+  structural_integrity: '结构完整',
+};
+
+function getDimensionName(key: string) {
+  return dimensionNames[key] || key;
+}
+
+function goBack() {
+  uni.navigateBack();
+}
+
+async function goToStep2() {
+  if (!theme.value.trim()) {
+    uni.showToast({ title: '请输入创作主题', icon: 'none' });
+    return;
+  }
+  await generateOutline();
+  currentStep.value = 1;
+}
+
+async function goToStep3() {
+  await generateCharacters();
+  currentStep.value = 2;
+}
+
+async function generateOutline() {
+  generatingOutline.value = true;
+  try {
+    const result = await post<any>('/ai-content/outline/generate', {
+      type: selectedType.value,
+      theme: theme.value,
+      chapters: Math.ceil(targetLength.value / 1500),
+    });
+    outline.value = result.outline || [];
+  } catch (e: any) {
+    uni.showToast({ title: '生成大纲失败', icon: 'none' });
+  } finally {
+    generatingOutline.value = false;
+  }
+}
+
+async function regenerateOutline() {
+  await generateOutline();
+}
+
+async function generateCharacters() {
+  try {
+    const result = await post<any>('/ai-content/characters/generate', {
+      type: selectedType.value,
+      genre: theme.value,
+    });
+    characters.value = result.characters || [];
+  } catch (e) {
+    characters.value = [
+      { id: 'char-1', name: '张三', age: 30, gender: '男', personality: '正直勇敢', role: '主角' },
+      { id: 'char-2', name: '李四', age: 28, gender: '女', personality: '聪明机智', role: '女主' },
+    ];
+  }
+}
+
+async function startGeneration() {
+  generating.value = true;
+  currentChapter.value = 0;
+  generatedChapters.value = [];
+
+  try {
+    for (let i = 0; i < outline.value.length; i++) {
+      currentChapter.value = i;
+      const result = await post<any>('/ai-content/chunk/generate', {
+        outlineId: `outline-${Date.now()}`,
+        chapterIndex: i,
+      });
+      generatedChapters.value.push(result.content || `这是第${i + 1}章的内容...\n\n[模拟生成的内容]`);
+    }
+
+    // 自动进行质量检测
+    await checkQuality();
+    currentStep.value = 4;
+  } catch (e: any) {
+    uni.showToast({ title: '生成失败', icon: 'none' });
+  } finally {
+    generating.value = false;
+  }
+}
+
+async function checkQuality() {
+  const content = fullContent.value;
+
+  // 敏感词检测
+  try {
+    const sensitive = await post<any>('/ai-content/sensitive/check', { text: content });
+    sensitiveResult.value = sensitive;
+  } catch (e) {}
+
+  // 合规检查
+  try {
+    const compliance = await post<any>('/ai-content/compliance/check', {
+      text: content,
+      industry: selectedIndustry.value,
+    });
+    complianceResult.value = compliance;
+  } catch (e) {}
+
+  // 质量评分
+  try {
+    qualityScore.value = await post<any>('/ai-content/quality/score', { text: content });
+  } catch (e) {}
+}
+
+function showQualityScore() {
+  checkQuality();
+}
+
+function saveDraft() {
+  uni.showToast({ title: '已保存草稿', icon: 'success' });
+}
+
+function useContent() {
+  uni.setStorageSync('ai_generated_text', fullContent.value);
+  uni.navigateBack();
+}
+</script>
+
+<style scoped>
+.page {
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+
+.nav-bar {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 88rpx;
+  background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
+  z-index: 100;
+  padding-top: 44rpx;
+}
+
+.nav-content {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 32rpx;
+  height: 88rpx;
+}
+
+.nav-left, .nav-right {
+  width: 80rpx;
+}
+
+.back-icon {
+  font-size: 40rpx;
+  color: #fff;
+}
+
+.nav-btn {
+  font-size: 32rpx;
+  color: #fff;
+}
+
+.page-title {
+  font-size: 34rpx;
+  font-weight: 600;
+  color: #ffffff;
+}
+
+.main-content {
+  padding: 140rpx 32rpx 32rpx;
+}
+
+/* 步骤指示器 */
+.steps-indicator {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 32rpx;
+  padding: 24rpx;
+  background: #fff;
+  border-radius: 16rpx;
+}
+
+.step-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  flex: 1;
+  opacity: 0.4;
+}
+
+.step-item.active {
+  opacity: 1;
+}
+
+.step-item.current .step-circle {
+  background: #4F46E5;
+  color: #fff;
+}
+
+.step-circle {
+  width: 48rpx;
+  height: 48rpx;
+  border-radius: 50%;
+  background: #e5e7eb;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 24rpx;
+  font-weight: 600;
+  color: #6b7280;
+  margin-bottom: 8rpx;
+}
+
+.step-text {
+  font-size: 20rpx;
+  color: #6b7280;
+}
+
+.card {
+  background: #fff;
+  border-radius: 24rpx;
+  padding: 32rpx;
+  margin-bottom: 24rpx;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 24rpx;
+}
+
+.card-title {
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #1f2937;
+}
+
+.header-action {
+  font-size: 26rpx;
+  color: #4F46E5;
+}
+
+.header-actions {
+  display: flex;
+  gap: 24rpx;
+}
+
+/* 表单 */
+.form-item {
+  margin-bottom: 32rpx;
+}
+
+.form-label {
+  font-size: 28rpx;
+  color: #6b7280;
+  margin-bottom: 16rpx;
+  display: block;
+}
+
+/* 内容类型网格 */
+.type-grid {
+  display: flex;
+  flex-direction: column;
+  gap: 16rpx;
+}
+
+.type-category {
+  background: #f9fafb;
+  border-radius: 12rpx;
+  padding: 16rpx;
+}
+
+.category-header {
+  font-size: 26rpx;
+  font-weight: 600;
+  color: #4F46E5;
+  margin-bottom: 12rpx;
+}
+
+.type-items {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 12rpx;
+}
+
+.type-item {
+  font-size: 24rpx;
+  padding: 8rpx 16rpx;
+  background: #fff;
+  border-radius: 8rpx;
+  color: #6b7280;
+  border: 2rpx solid transparent;
+}
+
+.type-item.active {
+  background: #4F46E5;
+  color: #fff;
+}
+
+/* 行业选择 */
+.industry-scroll {
+  white-space: nowrap;
+}
+
+.industry-list {
+  display: flex;
+  gap: 16rpx;
+  padding: 8rpx 0;
+}
+
+.industry-item {
+  font-size: 26rpx;
+  padding: 12rpx 24rpx;
+  background: #f3f4f6;
+  border-radius: 32rpx;
+  color: #6b7280;
+  white-space: nowrap;
+}
+
+.industry-item.active {
+  background: linear-gradient(135deg, #4f46e5 0%, #6366f1 100%);
+  color: #fff;
+}
+
+/* 主题输入 */
+.theme-input {
+  width: 100%;
+  height: 80rpx;
+  background: #f9fafb;
+  border-radius: 12rpx;
+  padding: 0 24rpx;
+  font-size: 28rpx;
+}
+
+/* 滑块 */
+.slider-range {
+  display: flex;
+  justify-content: space-between;
+  margin-top: 8rpx;
+}
+
+.slider-range text {
+  font-size: 22rpx;
+  color: #9ca3af;
+}
+
+/* 大纲内容 */
+.outline-stats {
+  display: flex;
+  gap: 24rpx;
+  margin-bottom: 24rpx;
+}
+
+.stat-item {
+  font-size: 24rpx;
+  color: #6b7280;
+  background: #f3f4f6;
+  padding: 8rpx 16rpx;
+  border-radius: 8rpx;
+}
+
+.chapter-item {
+  background: #f9fafb;
+  border-radius: 12rpx;
+  padding: 20rpx;
+  margin-bottom: 16rpx;
+}
+
+.chapter-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 8rpx;
+}
+
+.chapter-title {
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #1f2937;
+}
+
+.chapter-words {
+  font-size: 22rpx;
+  color: #9ca3af;
+}
+
+.chapter-desc {
+  font-size: 24rpx;
+  color: #6b7280;
+}
+
+/* 角色列表 */
+.characters-list {
+  display: flex;
+  flex-direction: column;
+  gap: 16rpx;
+}
+
+.character-card {
+  display: flex;
+  background: #f9fafb;
+  border-radius: 16rpx;
+  padding: 24rpx;
+}
+
+.char-avatar {
+  font-size: 64rpx;
+  margin-right: 24rpx;
+}
+
+.char-info {
+  flex: 1;
+}
+
+.char-name {
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #1f2937;
+  margin-bottom: 8rpx;
+}
+
+.char-detail {
+  font-size: 24rpx;
+  color: #6b7280;
+  display: block;
+  margin-bottom: 4rpx;
+}
+
+/* 生成进度 */
+.progress-section {
+  background: #f9fafb;
+  border-radius: 12rpx;
+  padding: 20rpx;
+  margin-bottom: 24rpx;
+}
+
+.progress-header {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 12rpx;
+}
+
+.progress-header text {
+  font-size: 26rpx;
+  color: #6b7280;
+}
+
+/* 生成的内容 */
+.generated-content {
+  max-height: 500rpx;
+  overflow-y: auto;
+  margin-bottom: 24rpx;
+}
+
+.content-chapter {
+  display: flex;
+  background: #f9fafb;
+  border-radius: 12rpx;
+  padding: 20rpx;
+  margin-bottom: 16rpx;
+}
+
+.chapter-badge {
+  width: 40rpx;
+  height: 40rpx;
+  background: #4F46E5;
+  color: #fff;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 22rpx;
+  margin-right: 16rpx;
+  flex-shrink: 0;
+}
+
+.chapter-text {
+  font-size: 26rpx;
+  color: #374151;
+  line-height: 1.6;
+  white-space: pre-wrap;
+}
+
+/* 质量检测 */
+.quality-item {
+  background: #f9fafb;
+  border-radius: 12rpx;
+  padding: 20rpx;
+  margin-bottom: 16rpx;
+}
+
+.quality-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 12rpx;
+}
+
+.quality-title {
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #1f2937;
+}
+
+.quality-status {
+  font-size: 24rpx;
+  padding: 4rpx 12rpx;
+  border-radius: 8rpx;
+}
+
+.quality-status.pass {
+  background: #d1fae5;
+  color: #059669;
+}
+
+.quality-score {
+  font-size: 32rpx;
+  font-weight: 700;
+  color: #4F46E5;
+}
+
+.sensitive-words, .compliance-warnings {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 12rpx;
+}
+
+.sensitive-tag, .warning-tag {
+  font-size: 22rpx;
+  padding: 4rpx 12rpx;
+  background: #fee2e2;
+  color: #dc2626;
+  border-radius: 6rpx;
+}
+
+.score-dimensions {
+  display: flex;
+  flex-direction: column;
+  gap: 12rpx;
+}
+
+.dimension-item {
+  display: flex;
+  align-items: center;
+  gap: 12rpx;
+}
+
+.dimension-name {
+  font-size: 24rpx;
+  color: #6b7280;
+  width: 120rpx;
+}
+
+.dimension-bar {
+  flex: 1;
+  height: 12rpx;
+  background: #e5e7eb;
+  border-radius: 6rpx;
+  overflow: hidden;
+}
+
+.dimension-fill {
+  height: 100%;
+  background: linear-gradient(135deg, #4f46e5 0%, #6366f1 100%);
+  border-radius: 6rpx;
+}
+
+.dimension-value {
+  font-size: 24rpx;
+  color: #4F46E5;
+  width: 50rpx;
+  text-align: right;
+}
+
+/* 按钮 */
+.btn-row {
+  display: flex;
+  gap: 16rpx;
+  margin-top: 24rpx;
+}
+
+.next-btn, .primary-btn {
+  flex: 1;
+  height: 88rpx;
+  background: linear-gradient(135deg, #4f46e5 0%, #818cf8 100%);
+  border-radius: 16rpx;
+  border: none;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #fff;
+}
+
+.back-btn {
+  flex: 1;
+  height: 88rpx;
+  background: #f3f4f6;
+  border-radius: 16rpx;
+  border: none;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 28rpx;
+  color: #6b7280;
+}
+
+.generate-btn {
+  flex: 1;
+  height: 88rpx;
+  background: linear-gradient(135deg, #10b981 0%, #34d399 100%);
+  border-radius: 16rpx;
+  border: none;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #fff;
+}
+
+.generate-btn[disabled] {
+  background: #e5e7eb;
+  color: #9ca3af;
+}
+
+.next-btn::after, .back-btn::after, .generate-btn::after, .primary-btn::after {
+  border: none;
+}
+
+.empty-state, .loading-state {
+  text-align: center;
+  padding: 48rpx;
+  color: #9ca3af;
+  font-size: 28rpx;
+}
+
+/* 弹窗 */
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  z-index: 1000;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.modal-content {
+  width: 600rpx;
+  background: #fff;
+  border-radius: 24rpx;
+  padding: 32rpx;
+}
+
+.modal-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 24rpx;
+}
+
+.modal-title {
+  font-size: 34rpx;
+  font-weight: 600;
+}
+
+.modal-close {
+  font-size: 40rpx;
+  color: #9ca3af;
+}
+
+.modal-body {
+  display: flex;
+  flex-direction: column;
+  gap: 16rpx;
+}
+
+.help-text {
+  font-size: 28rpx;
+  color: #374151;
+  line-height: 1.6;
+}
+</style>

+ 9 - 1
my-uniapp-vue3/src/pages/create/index.vue

@@ -26,7 +26,10 @@
         />
         <view class="input-actions">
           <button class="action-btn ai-btn" @click="goToAIPage">
-            <text>🤖 AI 生成</text>
+            <text>🤖 AI 对话</text>
+          </button>
+          <button class="action-btn ai-btn" @click="goToAIContentPage">
+            <text>📝 AI 内容</text>
           </button>
           <button class="action-btn template-btn" @click="showTemplatePanel = true">
             <text>📝 模板</text>
@@ -280,6 +283,11 @@ function goToAIPage() {
   uni.navigateTo({ url: '/pages/ai/index' });
 }
 
+// 跳转到 AI 内容生成页面
+function goToAIContentPage() {
+  uni.navigateTo({ url: '/pages/ai-content/index' });
+}
+
 // 生成音频
 async function handleGenerate() {
   if (!canGenerate.value) return;