fix: dynamic loading status during AI gen; navigator.clipboard copy; competitor analysis fallback

This commit is contained in:
TradeMate Dev
2026-05-15 22:38:49 +08:00
parent 98e2542c52
commit 8a3acbd4ee
3 changed files with 88 additions and 15 deletions
+62 -7
View File
@@ -88,7 +88,7 @@
</view>
</view>
<button class="generate-btn" @click="generateContent" :disabled="loading">
{{ loading ? '生成中...' : tabConfig[activeTab].btnText }}
{{ loading ? statusMessage || '生成中...' : tabConfig[activeTab].btnText }}
</button>
</view>
@@ -201,6 +201,7 @@ const tabConfig = {
const activeTab = ref('copy')
const loading = ref(false)
const statusMessage = ref('')
const resultsMap = reactive({ copy: [], whatsapp: [], product: [], keywords: [] })
const competitorResult = ref(null)
const stats = ref(null)
@@ -270,10 +271,12 @@ const generateContent = async () => {
}
loading.value = true
statusMessage.value = 'AI 准备中...'
const tab = activeTab.value
try {
if (tab === 'keywords') {
statusMessage.value = '正在提取关键词...'
const res = await marketingApi.getKeywords(
formData.value.product_name,
formData.value.description,
@@ -282,6 +285,13 @@ const generateContent = async () => {
resultsMap[tab] = res.keywords || []
} else {
const cfg = tabConfig[tab]
statusMessage.value = 'AI 正在生成文案(约15-30秒)...'
setTimeout(() => {
if (loading.value) statusMessage.value = 'AI 处理中,请稍候...'
}, 8000)
setTimeout(() => {
if (loading.value) statusMessage.value = '即将完成...'
}, 20000)
const res = await marketingApi.generate(
formData.value.product_name,
formData.value.description,
@@ -299,18 +309,42 @@ const generateContent = async () => {
uni.showToast({ title: err.message || '生成失败', icon: 'none' })
} finally {
loading.value = false
statusMessage.value = ''
}
}
const copyText = (text) => {
uni.setClipboardData({
data: text,
success: () => {
if (!text) {
uni.showToast({ title: '内容为空', icon: 'none' })
return
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(() => {
interactionApi.trackMarketingEffect({ action: 'copy', content_preview: text.slice(0, 100) }).catch(() => {})
loadStats()
uni.showToast({ title: '已复制', icon: 'success' })
},
})
}).catch(() => fallbackCopy(text))
} else {
fallbackCopy(text)
}
}
const fallbackCopy = (text) => {
const ta = document.createElement('textarea')
ta.value = text
ta.style.position = 'fixed'
ta.style.opacity = '0'
document.body.appendChild(ta)
ta.select()
try {
document.execCommand('copy')
interactionApi.trackMarketingEffect({ action: 'copy', content_preview: text.slice(0, 100) }).catch(() => {})
loadStats()
uni.showToast({ title: '已复制', icon: 'success' })
} catch {
uni.showToast({ title: '复制失败,请手动选择复制', icon: 'none' })
}
document.body.removeChild(ta)
}
const exportCsv = () => {
@@ -340,6 +374,10 @@ const sendToWhatsapp = (text) => {
}
const runCompetitorAnalysis = async () => {
if (!formData.value.product_name) {
uni.showToast({ title: '请先输入产品名称', icon: 'none' })
return
}
try {
uni.showLoading({ title: '分析中...' })
const res = await marketingApi.competitorAnalysis(
@@ -349,7 +387,24 @@ const runCompetitorAnalysis = async () => {
formData.value.target
)
uni.hideLoading()
competitorResult.value = typeof res.analysis === 'string' ? res.analysis : JSON.stringify(res.analysis, null, 2)
const analysis = res.analysis
if (!analysis || Object.keys(analysis).length === 0) {
competitorResult.value = '暂无分析结果,请确认产品信息后重试'
return
}
const lines = []
if (analysis.price_range) lines.push(`💰 价格范围:${analysis.price_range}`)
if (analysis.market_trends) lines.push(`📈 市场趋势:${analysis.market_trends}`)
if (analysis.key_selling_points && analysis.key_selling_points.length) {
lines.push(`\n🏆 核心卖点:\n ${analysis.key_selling_points.map(p => `${p}`).join('\n ')}`)
}
if (analysis.common_keywords && analysis.common_keywords.length) {
lines.push(`\n🔑 常见关键词:\n ${analysis.common_keywords.map(k => `${k}`).join('\n ')}`)
}
if (analysis.suggestions && analysis.suggestions.length) {
lines.push(`\n💡 建议:\n ${analysis.suggestions.map(s => `${s}`).join('\n ')}`)
}
competitorResult.value = lines.length ? lines.join('\n') : '暂无分析结果'
} catch (err) {
uni.hideLoading()
uni.showToast({ title: err.message || '分析失败', icon: 'none' })