feat: add frontend analytics tracking

This commit is contained in:
2026-05-17 10:18:56 +08:00
parent 3decff526a
commit 1016111d19
11 changed files with 583 additions and 10 deletions
+47 -6
View File
@@ -148,7 +148,7 @@
<view v-if="mode !== 'custom'" class="recent-section">
<view class="section-line">
<text class="section-title">最近生成</text>
<text class="refresh" @click="mode = 'list'">查看全部 </text>
<text class="refresh" @click="mode = 'list'">查看全部 </text>
</view>
<view v-if="scripts.length === 0" class="empty-panel kos-card">
<text>还没有剧本先用一句灵感生成第一段平行人生</text>
@@ -181,8 +181,10 @@
<script setup>
import { computed, reactive, ref } from 'vue'
import { useAppStore } from '../../stores/app.js'
import analytics from '../../services/analytics.js'
const store = useAppStore()
const pagePath = '/pages/main/ScriptView'
const mode = ref('inspiration')
const prompt = ref('')
const generating = ref(false)
@@ -191,10 +193,10 @@ const style = ref('career')
const randomRecommendations = ref([])
const promptPlaceholder = [
'例如:',
'如果我没有分手,现在会怎样?',
'我成为顶级作曲家的人生',
'重生回18岁改变一切',
'从小镇做题家到世界首富'
'如果我没有分手,现在会怎样?',
'我成为顶级作曲家的人生',
'重生回18岁改变一切',
'从小镇做题家到世界首富'
].join('\n')
const custom = reactive({
theme: '',
@@ -249,17 +251,28 @@ const lengthText = (value) => {
}
const useRecommendation = (text) => {
analytics.track('script_inspiration_click', {
source: 'recommendation'
}, { eventType: 'script', pagePath })
prompt.value = text
mode.value = 'inspiration'
}
const shuffleInspirations = async () => {
analytics.track('script_inspiration_view', {
source: 'shuffle'
}, { eventType: 'script', pagePath })
const list = await store.fetchRandomInspirations(4)
randomRecommendations.value = list.length ? list : fallbackRecommendations
}
const generateByPrompt = async () => {
if (!prompt.value.trim()) return
analytics.track('script_generate_start', {
style: style.value,
length: 'medium',
source: 'inspiration'
}, { eventType: 'script', pagePath })
generating.value = true
const res = await store.generateScriptFromInspiration({
prompt: prompt.value.trim(),
@@ -269,10 +282,19 @@ const generateByPrompt = async () => {
generating.value = false
if (!res.success) {
analytics.track('script_generate_fail', {
style: style.value,
length: 'medium',
error: res.error || 'unknown'
}, { eventType: 'script', pagePath })
uni.showToast({ title: res.error || '生成失败', icon: 'none' })
return
}
analytics.track('script_generate_success', {
style: style.value,
length: 'medium'
}, { eventType: 'script', pagePath })
prompt.value = ''
if (typeof res.data?.remainingCount === 'number') remainingCount.value = res.data.remainingCount
mode.value = 'list'
@@ -281,6 +303,11 @@ const generateByPrompt = async () => {
const generateCustom = async () => {
if (!custom.theme.trim()) return
analytics.track('script_generate_start', {
style: custom.style,
length: custom.length,
source: 'custom'
}, { eventType: 'script', pagePath })
generating.value = true
const res = await store.createScript({
title: custom.theme,
@@ -292,10 +319,19 @@ const generateCustom = async () => {
generating.value = false
if (!res.success) {
analytics.track('script_generate_fail', {
style: custom.style,
length: custom.length,
error: res.error || 'unknown'
}, { eventType: 'script', pagePath })
uni.showToast({ title: res.error || '生成失败', icon: 'none' })
return
}
analytics.track('script_generate_success', {
style: custom.style,
length: custom.length
}, { eventType: 'script', pagePath })
mode.value = 'list'
}
@@ -305,6 +341,12 @@ const viewScriptDetail = (script) => {
}
const selectScript = async (id) => {
const selected = scripts.value.find(item => item.id === id)
analytics.track('path_select', {
script_id: id,
style: selected?.style || '',
length: selected?.length || ''
}, { eventType: 'script', pagePath })
const res = await store.selectScript(id)
if (!res.success) {
uni.showToast({ title: res.error || '映射失败', icon: 'none' })
@@ -327,7 +369,6 @@ const handleVoiceInput = () => {
})
}
</script>
<style scoped>
.script-view {
display: flex;