feat: 营销页面结果旁显示中文翻译 + 朗读按钮
This commit is contained in:
@@ -114,8 +114,10 @@
|
||||
<view class="results-list" v-if="activeTab !== 'keywords'">
|
||||
<view class="result-item" v-for="(item, index) in filteredResults" :key="index">
|
||||
<text class="result-text">{{ item.content || item }}</text>
|
||||
<text class="result-translation" v-if="item.translation">📖 {{ item.translation }}</text>
|
||||
<view class="result-actions">
|
||||
<text class="copy-btn" @click="copyText(item.content || item)">复制</text>
|
||||
<text class="play-btn" @click="playTts(item.content || item)">朗读</text>
|
||||
<text class="send-btn" @click="sendToWhatsapp(item.content || item)" v-if="activeTab !== 'product'">发送</text>
|
||||
<text class="competitor-btn" @click="runCompetitorAnalysis" v-if="activeTab === 'copy'">竞品分析</text>
|
||||
</view>
|
||||
@@ -146,7 +148,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { marketingApi, interactionApi } from '@/utils/api.js'
|
||||
import { marketingApi, interactionApi, translateApi, BASE_URL } from '@/utils/api.js'
|
||||
|
||||
const tabConfig = {
|
||||
copy: {
|
||||
@@ -302,6 +304,15 @@ const generateContent = async () => {
|
||||
resultsMap[tab] = res.results || []
|
||||
if (res.results && res.results.length > 0) {
|
||||
selectedStyle.value = res.results[0].style || formData.value.style
|
||||
const items = res.results.filter(r => (r.content || r).match(/[a-zA-Z]{3,}/))
|
||||
if (items.length > 0) {
|
||||
Promise.all(items.map(async (r) => {
|
||||
try {
|
||||
const t = await translateApi.translate(r.content || r, 'zh')
|
||||
r.translation = t.translated || t.translated_text || ''
|
||||
} catch {}
|
||||
}))
|
||||
}
|
||||
}
|
||||
loadStats()
|
||||
}
|
||||
@@ -373,6 +384,43 @@ const sendToWhatsapp = (text) => {
|
||||
uni.showToast({ title: '请先选择客户', icon: 'none' })
|
||||
}
|
||||
|
||||
const playTts = (text) => {
|
||||
if (!text) return
|
||||
const hasChinese = /[\u4e00-\u9fa5]/.test(text)
|
||||
const lang = hasChinese ? 'zh' : 'en'
|
||||
const token = uni.getStorageSync('token')
|
||||
|
||||
uni.showLoading({ title: '语音生成中...' })
|
||||
if (typeof window !== 'undefined' && window.Audio) {
|
||||
uni.request({
|
||||
url: `${BASE_URL}/translate/tts?text=${encodeURIComponent(text)}&lang=${lang}`,
|
||||
method: 'GET',
|
||||
header: { Authorization: `Bearer ${token}` },
|
||||
responseType: 'arraybuffer',
|
||||
success: (res) => {
|
||||
uni.hideLoading()
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
const blob = new Blob([res.data], { type: 'audio/mpeg' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const audio = new Audio(url)
|
||||
audio.onended = () => { URL.revokeObjectURL(url) }
|
||||
audio.play().catch(() => {
|
||||
uni.showToast({ title: '播放失败', icon: 'none' })
|
||||
})
|
||||
} else {
|
||||
uni.showToast({ title: '语音生成失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '语音生成失败', icon: 'none' })
|
||||
},
|
||||
})
|
||||
} else {
|
||||
uni.showToast({ title: '当前环境不支持朗读', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
const runCompetitorAnalysis = async () => {
|
||||
if (!formData.value.product_name) {
|
||||
uni.showToast({ title: '请先输入产品名称', icon: 'none' })
|
||||
@@ -620,7 +668,18 @@ const runCompetitorAnalysis = async () => {
|
||||
font-size: 26rpx;
|
||||
line-height: 1.6;
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.result-translation {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
line-height: 1.5;
|
||||
display: block;
|
||||
margin-bottom: 16rpx;
|
||||
padding: 12rpx;
|
||||
background: #f0f5ff;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.result-actions {
|
||||
@@ -628,7 +687,7 @@ const runCompetitorAnalysis = async () => {
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.copy-btn, .send-btn, .competitor-btn {
|
||||
.copy-btn, .send-btn, .competitor-btn, .play-btn {
|
||||
font-size: 24rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 6rpx;
|
||||
@@ -639,6 +698,11 @@ const runCompetitorAnalysis = async () => {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.play-btn {
|
||||
background: #fff7e6;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
background: #07c160;
|
||||
color: #fff;
|
||||
|
||||
Reference in New Issue
Block a user