|
|
@@ -0,0 +1,342 @@
|
|
|
+<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></text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 主内容区 -->
|
|
|
+ <view class="main-content">
|
|
|
+ <!-- 输入提示词 -->
|
|
|
+ <view class="card input-card">
|
|
|
+ <view class="card-header">
|
|
|
+ <text class="card-title">🤖 输入问题</text>
|
|
|
+ </view>
|
|
|
+ <textarea
|
|
|
+ v-model="prompt"
|
|
|
+ class="prompt-input"
|
|
|
+ placeholder="输入你想了解的内容,例如:计算机原理是什么?什么是人工智能?"
|
|
|
+ :maxlength="500"
|
|
|
+ />
|
|
|
+ <view class="prompt-hint">
|
|
|
+ <text>AI 将根据你的输入生成相关文本内容</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 生成按钮 -->
|
|
|
+ <button
|
|
|
+ class="generate-btn"
|
|
|
+ :disabled="!prompt.trim() || generating"
|
|
|
+ @click="handleGenerate"
|
|
|
+ >
|
|
|
+ <text class="btn-text">{{ generating ? '生成中...' : '生成文本' }}</text>
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <!-- 生成结果 -->
|
|
|
+ <view v-if="generatedText" class="card result-card">
|
|
|
+ <view class="card-header">
|
|
|
+ <text class="card-title">📝 生成的文本</text>
|
|
|
+ <view class="result-actions">
|
|
|
+ <text class="action-text" @click="copyText">复制</text>
|
|
|
+ <text class="action-text use-text" @click="useText">使用此文本</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="result-content">
|
|
|
+ <text class="result-text">{{ generatedText }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="result-footer">
|
|
|
+ <text class="word-count">{{ generatedText.length }} 字</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 历史记录 -->
|
|
|
+ <view v-if="historyList.length > 0" class="card history-card">
|
|
|
+ <view class="card-header">
|
|
|
+ <text class="card-title">📜 历史记录</text>
|
|
|
+ </view>
|
|
|
+ <view class="history-list">
|
|
|
+ <view
|
|
|
+ v-for="(item, index) in historyList"
|
|
|
+ :key="index"
|
|
|
+ class="history-item"
|
|
|
+ @click="useHistoryItem(item)"
|
|
|
+ >
|
|
|
+ <text class="history-prompt">{{ item.prompt }}</text>
|
|
|
+ <text class="history-text">{{ item.text.slice(0, 50) }}...</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref } from 'vue';
|
|
|
+import { post } from '../../utils/request';
|
|
|
+
|
|
|
+const prompt = ref('');
|
|
|
+const generating = ref(false);
|
|
|
+const generatedText = ref('');
|
|
|
+const historyList = ref<{ prompt: string; text: string }[]>([]);
|
|
|
+
|
|
|
+// 生成文本
|
|
|
+async function handleGenerate() {
|
|
|
+ if (!prompt.value.trim() || generating.value) return;
|
|
|
+
|
|
|
+ generating.value = true;
|
|
|
+ try {
|
|
|
+ const result = await post<{ text: string }>('/ai/generate', {
|
|
|
+ prompt: prompt.value,
|
|
|
+ });
|
|
|
+
|
|
|
+ generatedText.value = result.text;
|
|
|
+
|
|
|
+ // 添加到历史记录
|
|
|
+ historyList.value.unshift({
|
|
|
+ prompt: prompt.value,
|
|
|
+ text: result.text,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 保留最多 10 条历史
|
|
|
+ if (historyList.value.length > 10) {
|
|
|
+ historyList.value.pop();
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.showToast({ title: '生成成功', icon: 'success' });
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('AI 生成失败:', error);
|
|
|
+ uni.showToast({ title: error.message || '生成失败', icon: 'none' });
|
|
|
+ } finally {
|
|
|
+ generating.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 复制文本
|
|
|
+function copyText() {
|
|
|
+ uni.setClipboardData({
|
|
|
+ data: generatedText.value,
|
|
|
+ success: () => {
|
|
|
+ uni.showToast({ title: '已复制', icon: 'success' });
|
|
|
+ },
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+// 使用文本 - 跳转到生成音频页面
|
|
|
+function useText() {
|
|
|
+ // 将生成的文本存入本地存储,供下一个页面使用
|
|
|
+ uni.setStorageSync('ai_generated_text', generatedText.value);
|
|
|
+ uni.navigateBack();
|
|
|
+}
|
|
|
+
|
|
|
+// 使用历史记录
|
|
|
+function useHistoryItem(item: { prompt: string; text: string }) {
|
|
|
+ prompt.value = item.prompt;
|
|
|
+ generatedText.value = item.text;
|
|
|
+}
|
|
|
+
|
|
|
+// 返回上一页
|
|
|
+function goBack() {
|
|
|
+ // 如果有生成的文本,带回去
|
|
|
+ if (generatedText.value) {
|
|
|
+ uni.setStorageSync('ai_generated_text', generatedText.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: #ffffff;
|
|
|
+ z-index: 100;
|
|
|
+ padding-top: 44rpx;
|
|
|
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
|
|
+}
|
|
|
+
|
|
|
+.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: #1f2937;
|
|
|
+}
|
|
|
+
|
|
|
+.page-title {
|
|
|
+ font-size: 34rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1f2937;
|
|
|
+}
|
|
|
+
|
|
|
+.main-content {
|
|
|
+ padding: 132rpx 32rpx 180rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.card {
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ padding: 32rpx;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
|
|
+}
|
|
|
+
|
|
|
+.card-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.card-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1f2937;
|
|
|
+}
|
|
|
+
|
|
|
+.prompt-input {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 200rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+ background: #f9fafb;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #1f2937;
|
|
|
+ line-height: 1.6;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.prompt-hint {
|
|
|
+ margin-top: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.prompt-hint text {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #9ca3af;
|
|
|
+}
|
|
|
+
|
|
|
+.generate-btn {
|
|
|
+ width: 100%;
|
|
|
+ height: 96rpx;
|
|
|
+ background: linear-gradient(135deg, #4f46e5 0%, #818cf8 100%);
|
|
|
+ border-radius: 24rpx;
|
|
|
+ border: none;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.generate-btn::after {
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+
|
|
|
+.generate-btn[disabled] {
|
|
|
+ background: #e5e7eb;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-text {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #ffffff;
|
|
|
+}
|
|
|
+
|
|
|
+.result-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 24rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.action-text {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #6b7280;
|
|
|
+ padding: 8rpx 16rpx;
|
|
|
+ background: #f3f4f6;
|
|
|
+ border-radius: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.use-text {
|
|
|
+ color: #4f46e5;
|
|
|
+ background: #eef2ff;
|
|
|
+}
|
|
|
+
|
|
|
+.result-content {
|
|
|
+ max-height: 600rpx;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding: 24rpx;
|
|
|
+ background: #f9fafb;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.result-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #1f2937;
|
|
|
+ line-height: 1.8;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+
|
|
|
+.result-footer {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+}
|
|
|
+
|
|
|
+.word-count {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #9ca3af;
|
|
|
+}
|
|
|
+
|
|
|
+.history-list {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.history-item {
|
|
|
+ padding: 20rpx;
|
|
|
+ background: #f9fafb;
|
|
|
+ border-radius: 12rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.history-prompt {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #4f46e5;
|
|
|
+ font-weight: 500;
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.history-text {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #6b7280;
|
|
|
+ display: block;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+</style>
|