feat(ECR-012–016): 合规、题库、时辰刷新、头像、MBTI OEJTS 与埋点
落地输入合规、探索题库、报告日/时辰刷新、账号头像、OEJTS 量表,并补齐 H5 埋点与 Admin 漏斗;同步 ESS 工件、切至自建 Git、清理 GitHub Actions。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<PageShell>
|
||||
<template #hero>
|
||||
<BackButton />
|
||||
<div class="head">
|
||||
<HomeToolIcon name="growth" :size="48" />
|
||||
<div>
|
||||
@@ -16,7 +15,7 @@
|
||||
<label class="lbl">新计划标题</label>
|
||||
<input class="inp" v-model="title" maxlength="40" placeholder="例如:每晚 11 点前放下手机" />
|
||||
<label class="lbl">焦点(可选)</label>
|
||||
<input class="inp" v-model="focus" maxlength="80" placeholder="例如:保护睡眠与情绪" />
|
||||
<input class="inp" v-model="focus" maxlength="40" placeholder="例如:保护睡眠与情绪" />
|
||||
<button class="cta" type="button" :disabled="saving || !title.trim()" @click="create">创建计划</button>
|
||||
<p v-if="err" class="err">{{ err }}</p>
|
||||
</div>
|
||||
@@ -42,11 +41,12 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { validateUserText } from '@yuxingu/utils'
|
||||
import { api } from '../api/client'
|
||||
import BackButton from '../components/BackButton.vue'
|
||||
import HomeToolIcon from '../components/HomeToolIcon.vue'
|
||||
import PageShell from '../components/PageShell.vue'
|
||||
import { ensureAccount } from '../lib/authSession'
|
||||
import { AnalyticsEvent, track } from '../lib/analytics'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
@@ -59,7 +59,7 @@ const saving = ref(false)
|
||||
const checking = ref('')
|
||||
const err = ref('')
|
||||
|
||||
async function load() {
|
||||
async function load(opts?: { trackView?: boolean }) {
|
||||
loading.value = true
|
||||
if (!(await ensureAccount(router, route.fullPath))) {
|
||||
loading.value = false
|
||||
@@ -76,6 +76,7 @@ async function load() {
|
||||
err.value = e instanceof Error ? e.message : '加载失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
if (opts?.trackView) track(AnalyticsEvent.GrowthPlanViewed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,9 +84,17 @@ async function create() {
|
||||
saving.value = true
|
||||
err.value = ''
|
||||
try {
|
||||
await api.createGrowthPlan({ title: title.value.trim(), focus: focus.value.trim() || undefined })
|
||||
const titleCheck = validateUserText('title', title.value)
|
||||
if (!titleCheck.ok) throw new Error(titleCheck.message)
|
||||
const focusCheck = validateUserText('focus', focus.value)
|
||||
if (!focusCheck.ok) throw new Error(focusCheck.message)
|
||||
await api.createGrowthPlan({
|
||||
title: titleCheck.value,
|
||||
focus: focusCheck.value || undefined,
|
||||
})
|
||||
title.value = ''
|
||||
focus.value = ''
|
||||
track(AnalyticsEvent.GrowthPlanCreated)
|
||||
await load()
|
||||
} catch (e) {
|
||||
err.value = e instanceof Error ? e.message : '创建失败'
|
||||
@@ -101,6 +110,7 @@ async function checkin(id: string) {
|
||||
await api.createGrowthCheckin(id, {})
|
||||
const ck = await api.listGrowthCheckins(id)
|
||||
checkins.value[id] = ck.items || []
|
||||
track(AnalyticsEvent.GrowthPlanCheckin)
|
||||
} catch (e) {
|
||||
err.value = e instanceof Error ? e.message : '打卡失败'
|
||||
} finally {
|
||||
@@ -108,7 +118,9 @@ async function checkin(id: string) {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
onMounted(() => {
|
||||
void load({ trackView: true })
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user