|
@@ -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>
|