create-weapp-vite 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/{chunk-CP2T5O3U.js → chunk-KDUDSVZ5.js} +2 -2
  2. package/dist/cli.cjs +2 -2
  3. package/dist/cli.js +1 -1
  4. package/dist/index.cjs +2 -2
  5. package/dist/index.js +1 -1
  6. package/package.json +1 -1
  7. package/templates/wevu-tdesign/README.md +5 -0
  8. package/templates/wevu-tdesign/components.d.ts +1 -1
  9. package/templates/wevu-tdesign/public/tabbar/ability-active.png +0 -0
  10. package/templates/wevu-tdesign/public/tabbar/ability.png +0 -0
  11. package/templates/wevu-tdesign/public/tabbar/data-active.png +0 -0
  12. package/templates/wevu-tdesign/public/tabbar/data.png +0 -0
  13. package/templates/wevu-tdesign/public/tabbar/form-active.png +0 -0
  14. package/templates/wevu-tdesign/public/tabbar/form.png +0 -0
  15. package/templates/wevu-tdesign/public/tabbar/home-active.png +0 -0
  16. package/templates/wevu-tdesign/public/tabbar/home.png +0 -0
  17. package/templates/wevu-tdesign/public/tabbar/list-active.png +0 -0
  18. package/templates/wevu-tdesign/public/tabbar/list.png +0 -0
  19. package/templates/wevu-tdesign/src/app.vue +60 -2
  20. package/templates/wevu-tdesign/src/components/EmptyState/index.vue +36 -0
  21. package/templates/wevu-tdesign/src/components/FilterBar/index.vue +63 -0
  22. package/templates/wevu-tdesign/src/components/FormRow/index.vue +43 -0
  23. package/templates/wevu-tdesign/src/components/FormStep/index.vue +48 -0
  24. package/templates/wevu-tdesign/src/components/KpiBoard/index.vue +146 -0
  25. package/templates/wevu-tdesign/src/components/QuickActionGrid/index.vue +90 -0
  26. package/templates/wevu-tdesign/src/components/ResultCard/index.vue +51 -0
  27. package/templates/wevu-tdesign/src/components/SectionTitle/index.vue +34 -0
  28. package/templates/wevu-tdesign/src/components/TrendCard/index.vue +101 -0
  29. package/templates/wevu-tdesign/src/pages/ability/index.vue +177 -0
  30. package/templates/wevu-tdesign/src/pages/data/index.vue +188 -0
  31. package/templates/wevu-tdesign/src/pages/form/index.vue +249 -0
  32. package/templates/wevu-tdesign/src/pages/index/index.vue +228 -126
  33. package/templates/wevu-tdesign/src/pages/list/index.vue +178 -0
  34. package/templates/wevu-tdesign/src/subpackages/ability/index.vue +106 -0
  35. package/templates/wevu-tdesign/src/subpackages/lab/index.vue +136 -0
  36. package/templates/wevu-tdesign/src/vite-env.d.ts +4 -0
  37. package/templates/wevu-tdesign/tsconfig.app.json +6 -1
  38. package/templates/wevu-tdesign/vite.config.ts +11 -1
  39. package/templates/wevu-tdesign/src/components/HelloWorld/index.vue +0 -23
@@ -0,0 +1,249 @@
1
+ <script setup lang="ts">
2
+ import Toast from 'tdesign-miniprogram/toast/index'
3
+
4
+ import { computed, getCurrentInstance, reactive, ref, watch } from 'wevu'
5
+
6
+ import FormRow from '@/components/FormRow/index.vue'
7
+ import FormStep from '@/components/FormStep/index.vue'
8
+ import ResultCard from '@/components/ResultCard/index.vue'
9
+ import SectionTitle from '@/components/SectionTitle/index.vue'
10
+
11
+ definePageJson({
12
+ navigationBarTitleText: '表单',
13
+ backgroundColor: '#f6f7fb',
14
+ })
15
+
16
+ const mpContext = getCurrentInstance()
17
+
18
+ const steps = [
19
+ { key: 'basic', title: '基础信息', subtitle: '业务基本配置' },
20
+ { key: 'strategy', title: '执行策略', subtitle: '预算与节奏' },
21
+ { key: 'confirm', title: '确认提交', subtitle: '核对并提交' },
22
+ ]
23
+
24
+ const currentStep = ref(0)
25
+ const submitted = ref(false)
26
+
27
+ const formState = reactive({
28
+ name: '',
29
+ owner: '',
30
+ category: 'growth',
31
+ urgent: false,
32
+ budget: 30,
33
+ pace: 'balanced',
34
+ description: '',
35
+ attachments: [] as Array<{ url: string, name: string }>,
36
+ })
37
+
38
+ const categories = [
39
+ { value: 'growth', label: '增长' },
40
+ { value: 'retention', label: '留存' },
41
+ { value: 'brand', label: '品牌' },
42
+ ]
43
+
44
+ const paceOptions = [
45
+ { value: 'fast', label: '快速推进' },
46
+ { value: 'balanced', label: '平衡' },
47
+ { value: 'steady', label: '稳健' },
48
+ ]
49
+
50
+ const riskLevel = computed(() => {
51
+ if (formState.urgent && formState.budget > 60) {
52
+ return '高风险'
53
+ }
54
+ if (formState.budget > 40) {
55
+ return '中风险'
56
+ }
57
+ return '可控'
58
+ })
59
+
60
+ const canGoNext = computed(() => {
61
+ if (currentStep.value === 0) {
62
+ return !!formState.name && !!formState.owner
63
+ }
64
+ if (currentStep.value === 1) {
65
+ return !!formState.description
66
+ }
67
+ return true
68
+ })
69
+
70
+ const summaryRows = computed(() => [
71
+ { label: '项目名称', value: formState.name || '--' },
72
+ { label: '负责人', value: formState.owner || '--' },
73
+ { label: '类型', value: categories.find(item => item.value === formState.category)?.label ?? '--' },
74
+ { label: '预算', value: `${formState.budget} 万` },
75
+ { label: '节奏', value: paceOptions.find(item => item.value === formState.pace)?.label ?? '--' },
76
+ { label: '风险级别', value: riskLevel.value },
77
+ ])
78
+
79
+ watch(
80
+ () => formState.urgent,
81
+ (value) => {
82
+ if (value) {
83
+ formState.pace = 'fast'
84
+ }
85
+ },
86
+ )
87
+
88
+ function showToast(message: string, theme: 'success' | 'warning' = 'success') {
89
+ if (!mpContext) {
90
+ return
91
+ }
92
+ Toast({
93
+ selector: '#t-toast',
94
+ context: mpContext as any,
95
+ message,
96
+ theme,
97
+ duration: 1200,
98
+ })
99
+ }
100
+
101
+ function goNext() {
102
+ if (!canGoNext.value) {
103
+ showToast('请先完善当前步骤信息', 'warning')
104
+ return
105
+ }
106
+ if (currentStep.value < steps.length - 1) {
107
+ currentStep.value += 1
108
+ }
109
+ }
110
+
111
+ function goPrev() {
112
+ if (currentStep.value > 0) {
113
+ currentStep.value -= 1
114
+ }
115
+ }
116
+
117
+ function submit() {
118
+ submitted.value = true
119
+ showToast('提交成功')
120
+ }
121
+
122
+ function onUploadChange(e: WechatMiniprogram.CustomEvent<{ files: Array<{ url: string, name: string }> }>) {
123
+ formState.attachments = e.detail.files
124
+ }
125
+ </script>
126
+
127
+ <template>
128
+ <view class="min-h-screen bg-[#f6f7fb] px-[28rpx] pb-[88rpx] pt-[24rpx] text-[#1c1c3c]">
129
+ <view class="rounded-[28rpx] bg-gradient-to-br from-[#fff7ed] via-[#ffffff] to-[#fef3c7] p-[20rpx]">
130
+ <SectionTitle title="项目提报" subtitle="示例多步表单与联动校验" />
131
+ <view class="mt-[12rpx]">
132
+ <t-steps :current="currentStep" layout="horizontal">
133
+ <t-step-item v-for="item in steps" :key="item.key" :title="item.title" />
134
+ </t-steps>
135
+ </view>
136
+ </view>
137
+
138
+ <view class="mt-[18rpx] space-y-[14rpx]">
139
+ <FormStep
140
+ v-if="currentStep === 0"
141
+ :step="1"
142
+ title="基础信息"
143
+ subtitle="填写核心字段"
144
+ :active="currentStep === 0"
145
+ >
146
+ <view class="flex flex-col gap-[14rpx]">
147
+ <FormRow label="项目名称">
148
+ <t-input
149
+ placeholder="例如:新客增长计划"
150
+ :value="formState.name"
151
+ @change="(e) => (formState.name = e.detail.value)"
152
+ />
153
+ </FormRow>
154
+ <FormRow label="负责人">
155
+ <t-input
156
+ placeholder="例如:王凯"
157
+ :value="formState.owner"
158
+ @change="(e) => (formState.owner = e.detail.value)"
159
+ />
160
+ </FormRow>
161
+ <FormRow label="类型">
162
+ <t-radio-group :value="formState.category" @change="(e) => (formState.category = e.detail.value)">
163
+ <t-radio v-for="item in categories" :key="item.value" :value="item.value" :label="item.label" />
164
+ </t-radio-group>
165
+ </FormRow>
166
+ <FormRow label="加急">
167
+ <t-switch :value="formState.urgent" @change="(e) => (formState.urgent = e.detail.value)" />
168
+ </FormRow>
169
+ </view>
170
+ </FormStep>
171
+
172
+ <FormStep
173
+ v-if="currentStep === 1"
174
+ :step="2"
175
+ title="执行策略"
176
+ subtitle="预算与节奏"
177
+ :active="currentStep === 1"
178
+ >
179
+ <view class="flex flex-col gap-[14rpx]">
180
+ <FormRow label="预算规模" description="10-100 万">
181
+ <view class="flex items-center gap-[12rpx]">
182
+ <t-slider
183
+ :value="formState.budget"
184
+ :min="10"
185
+ :max="100"
186
+ @change="(e) => (formState.budget = e.detail.value)"
187
+ />
188
+ <text class="text-[22rpx] text-[#5c5b7a]">
189
+ {{ formState.budget }} 万
190
+ </text>
191
+ </view>
192
+ </FormRow>
193
+ <FormRow label="推进节奏">
194
+ <t-radio-group :value="formState.pace" @change="(e) => (formState.pace = e.detail.value)">
195
+ <t-radio v-for="item in paceOptions" :key="item.value" :value="item.value" :label="item.label" />
196
+ </t-radio-group>
197
+ </FormRow>
198
+ <FormRow label="补充说明">
199
+ <t-textarea
200
+ placeholder="描述目标与资源安排"
201
+ :value="formState.description"
202
+ :maxlength="140"
203
+ @change="(e) => (formState.description = e.detail.value)"
204
+ />
205
+ </FormRow>
206
+ <FormRow label="附件">
207
+ <t-upload
208
+ :files="formState.attachments"
209
+ :max="3"
210
+ @change="onUploadChange"
211
+ />
212
+ </FormRow>
213
+ </view>
214
+ </FormStep>
215
+
216
+ <FormStep
217
+ v-if="currentStep === 2"
218
+ :step="3"
219
+ title="确认提交"
220
+ subtitle="预览关键信息"
221
+ :active="currentStep === 2"
222
+ >
223
+ <ResultCard title="提交摘要" :items="summaryRows">
224
+ <template #action>
225
+ <t-tag size="small" theme="primary" variant="light">
226
+ {{ riskLevel }}
227
+ </t-tag>
228
+ </template>
229
+ </ResultCard>
230
+ </FormStep>
231
+ </view>
232
+
233
+ <view class="mt-[18rpx] flex gap-[12rpx]">
234
+ <t-button block variant="outline" theme="default" :disabled="currentStep === 0" @tap="goPrev">
235
+ 上一步
236
+ </t-button>
237
+ <t-button
238
+ block
239
+ theme="primary"
240
+ :disabled="currentStep === steps.length - 1 && submitted"
241
+ @tap="currentStep === steps.length - 1 ? submit() : goNext()"
242
+ >
243
+ {{ currentStep === steps.length - 1 ? (submitted ? '已提交' : '提交') : '下一步' }}
244
+ </t-button>
245
+ </view>
246
+
247
+ <t-toast id="t-toast" />
248
+ </view>
249
+ </template>
@@ -1,171 +1,273 @@
1
1
  <script setup lang="ts">
2
- import Dialog from 'tdesign-miniprogram/dialog/index'
3
2
  import Toast from 'tdesign-miniprogram/toast/index'
4
3
 
5
- import { computed, getCurrentInstance, ref, watch } from 'wevu'
4
+ import { computed, getCurrentInstance, onPullDownRefresh, ref, watch } from 'wevu'
6
5
 
7
- import HelloWorld from '@/components/HelloWorld/index.vue'
6
+ import KpiBoard from '@/components/KpiBoard/index.vue'
7
+ import QuickActionGrid from '@/components/QuickActionGrid/index.vue'
8
8
 
9
9
  definePageJson({
10
10
  navigationBarTitleText: '首页',
11
+ enablePullDownRefresh: true,
12
+ backgroundColor: '#f6f7fb',
11
13
  })
12
14
 
13
15
  const mpContext = getCurrentInstance()
14
16
 
15
- const count = ref(0)
16
- const message = ref('Hello WeVU!')
17
- const todos = ref([
18
- '用 Vue SFC 写页面/组件',
19
- '用 wevu API(ref/computed/watch)写逻辑',
20
- '用 v-for / v-if / @tap / v-model 写模板',
17
+ const noticeText = ref('欢迎体验 wevu + weapp-vite + TDesign 模板,已启用分包与多页面导航。')
18
+ const lastUpdated = ref('刚刚')
19
+ const refreshSeed = ref(1)
20
+
21
+ const kpiItems = computed(() => {
22
+ const seed = refreshSeed.value
23
+ return [
24
+ {
25
+ key: 'visits',
26
+ label: '今日访问',
27
+ value: 1280 + seed * 3,
28
+ unit: '次',
29
+ delta: 6 + seed,
30
+ footnote: '较昨日',
31
+ },
32
+ {
33
+ key: 'conversion',
34
+ label: '转化率',
35
+ value: 24 + seed,
36
+ unit: '%',
37
+ delta: 2,
38
+ footnote: '近 7 日',
39
+ },
40
+ {
41
+ key: 'tickets',
42
+ label: '待处理',
43
+ value: 18 - seed,
44
+ unit: '单',
45
+ delta: -1,
46
+ footnote: '来自清单',
47
+ },
48
+ {
49
+ key: 'satisfaction',
50
+ label: '满意度',
51
+ value: 4.8,
52
+ unit: '分',
53
+ delta: 0.2,
54
+ footnote: '客服评分',
55
+ },
56
+ ]
57
+ })
58
+
59
+ const quickActions = ref([
60
+ {
61
+ key: 'data',
62
+ title: '数据洞察',
63
+ description: '仪表盘与趋势',
64
+ icon: 'chart-analytics',
65
+ tag: 'KPI',
66
+ tone: 'brand',
67
+ path: '/pages/data/index',
68
+ type: 'tab',
69
+ },
70
+ {
71
+ key: 'form',
72
+ title: '流程表单',
73
+ description: '多步录入',
74
+ icon: 'edit-1',
75
+ tag: 'Flow',
76
+ tone: 'neutral',
77
+ path: '/pages/form/index',
78
+ type: 'tab',
79
+ },
80
+ {
81
+ key: 'list',
82
+ title: '清单看板',
83
+ description: '筛选与列表',
84
+ icon: 'view-list',
85
+ tag: 'List',
86
+ tone: 'neutral',
87
+ path: '/pages/list/index',
88
+ type: 'tab',
89
+ },
90
+ {
91
+ key: 'ability',
92
+ title: '能力中心',
93
+ description: '小程序 API',
94
+ icon: 'app',
95
+ tag: 'API',
96
+ tone: 'brand',
97
+ path: '/pages/ability/index',
98
+ type: 'tab',
99
+ },
100
+ {
101
+ key: 'lab',
102
+ title: '组件实验室',
103
+ description: 'TDesign 组件',
104
+ icon: 'grid-view',
105
+ tag: 'Lab',
106
+ tone: 'neutral',
107
+ path: '/subpackages/lab/index',
108
+ type: 'sub',
109
+ },
110
+ {
111
+ key: 'ability-lab',
112
+ title: 'API 场景',
113
+ description: '系统信息',
114
+ icon: 'share',
115
+ tag: 'Sub',
116
+ tone: 'neutral',
117
+ path: '/subpackages/ability/index',
118
+ type: 'sub',
119
+ },
21
120
  ])
22
- const checkedTodos = ref<Array<string | number>>([])
23
- const newTodo = ref('')
24
-
25
- const doubled = computed(() => count.value * 2)
26
- const todoOptions = computed(() =>
27
- todos.value.map((todo, index) => ({
28
- label: todo,
29
- value: index,
30
- })),
31
- )
32
- const checkedCount = computed(() => checkedTodos.value.length)
33
-
34
- function showToast(options: Parameters<typeof Toast>[0]) {
121
+
122
+ const featureTags = [
123
+ 'Composition API',
124
+ 'SubPackages',
125
+ 'Auto Import',
126
+ 'Tailwind',
127
+ ]
128
+
129
+ watch(refreshSeed, () => {
130
+ lastUpdated.value = `更新于 ${new Date().toLocaleTimeString()}`
131
+ })
132
+
133
+ onPullDownRefresh(() => {
134
+ refreshDashboard()
135
+ wx.stopPullDownRefresh()
136
+ })
137
+
138
+ function showToast(message: string) {
35
139
  if (!mpContext) {
36
140
  return
37
141
  }
38
142
  Toast({
39
143
  selector: '#t-toast',
40
- ...options,
41
144
  context: mpContext as any,
42
- })
43
- }
44
-
45
- function increment() {
46
- count.value += 1
47
- showToast({
145
+ message,
48
146
  theme: 'success',
49
- message: `+1,当前:${count.value}`,
50
147
  duration: 1200,
51
148
  })
52
149
  }
53
150
 
54
- async function reset() {
55
- if (!mpContext) {
56
- count.value = 0
151
+ function refreshDashboard() {
152
+ refreshSeed.value = Math.max(1, Math.floor(Math.random() * 9))
153
+ showToast('指标已刷新')
154
+ }
155
+
156
+ function onQuickAction(action: { path?: string, type?: 'tab' | 'sub', title: string }) {
157
+ if (!action.path) {
158
+ showToast('该入口暂未配置')
57
159
  return
58
160
  }
59
-
60
- try {
61
- await Dialog.confirm({
62
- context: mpContext as any,
63
- selector: '#t-dialog',
64
- title: '重置计数器',
65
- content: `当前计数为 ${count.value},确定要重置吗?`,
66
- confirmBtn: '重置',
67
- cancelBtn: '取消',
161
+ if (action.type === 'tab') {
162
+ wx.switchTab({
163
+ url: action.path,
68
164
  })
69
- count.value = 0
70
- showToast({ theme: 'success', message: '已重置', duration: 1200 })
71
- }
72
- catch {
73
- showToast({ theme: 'warning', message: '已取消', duration: 1000 })
74
- }
75
- }
76
-
77
- watch(count, (newValue, oldValue) => {
78
- console.log(`[wevu] count changed: ${oldValue} -> ${newValue}`)
79
- })
80
-
81
- function onMessageChange(e: WechatMiniprogram.CustomEvent<{ value: string }>) {
82
- message.value = e.detail.value
83
- }
84
-
85
- function onMessageClear() {
86
- message.value = ''
87
- }
88
-
89
- function onNewTodoChange(e: WechatMiniprogram.CustomEvent<{ value: string }>) {
90
- newTodo.value = e.detail.value
91
- }
92
-
93
- function onNewTodoClear() {
94
- newTodo.value = ''
95
- }
96
-
97
- function addTodo() {
98
- const value = newTodo.value.trim()
99
- if (!value) {
100
- showToast({ theme: 'warning', message: '请输入内容', duration: 1000 })
101
165
  return
102
166
  }
103
- todos.value.push(value)
104
- newTodo.value = ''
105
- showToast({ theme: 'success', message: '已添加', duration: 1000 })
106
- }
107
-
108
- function onTodoChange(e: WechatMiniprogram.CustomEvent<{ value: Array<string | number> }>) {
109
- checkedTodos.value = e.detail.value
167
+ wx.navigateTo({
168
+ url: action.path,
169
+ })
110
170
  }
111
171
  </script>
112
172
 
113
173
  <template>
114
- <view class="box-border min-h-screen bg-[#f6f7fb] px-[32rpx] pb-[64rpx] pt-[48rpx] text-[#1c1c3c]">
115
- <HelloWorld :title="message" :subtitle="`count=${count}, doubled=${doubled}`" />
116
-
117
- <view
118
- class="mt-[24rpx] rounded-[24rpx] bg-white p-[32rpx] shadow-[0_12rpx_32rpx_rgb(44_44_84_/_10%)]"
119
- >
120
- <t-cell-group title="计数器" theme="card">
121
- <t-cell title="当前计数" :note="`${count}`" />
122
- <t-cell title="双倍" :note="`${doubled}`" />
123
- </t-cell-group>
124
-
125
- <view class="mt-[24rpx] flex gap-[16rpx]">
126
- <t-button block size="large" theme="primary" style="flex: 1" @tap="increment">
127
- +1
128
- </t-button>
129
- <t-button block size="large" theme="danger" variant="outline" style="flex: 1" @tap="reset">
130
- 重置
174
+ <view class="min-h-screen bg-[#f6f7fb] px-[28rpx] pb-[88rpx] pt-[32rpx] text-[#1c1c3c]">
175
+ <view class="rounded-[28rpx] bg-gradient-to-br from-[#2f2b5f] via-[#3b3573] to-[#5a48c5] p-[24rpx] text-white shadow-[0_24rpx_48rpx_rgba(47,43,95,0.35)]">
176
+ <text class="text-[38rpx] font-semibold">
177
+ Weapp Studio
178
+ </text>
179
+ <text class="mt-[8rpx] block text-[22rpx] text-white/80">
180
+ 以场景驱动的模板,展示 wevu、weapp-vite TDesign。
181
+ </text>
182
+ <view class="mt-[12rpx] flex flex-wrap gap-[8rpx]">
183
+ <t-tag v-for="tag in featureTags" :key="tag" size="small" theme="primary" variant="dark">
184
+ {{ tag }}
185
+ </t-tag>
186
+ </view>
187
+ <view class="mt-[16rpx] flex items-center justify-between">
188
+ <text class="text-[20rpx] text-white/70">
189
+ {{ lastUpdated }}
190
+ </text>
191
+ <t-button size="small" theme="default" variant="outline" @tap="refreshDashboard">
192
+ 刷新指标
131
193
  </t-button>
132
194
  </view>
195
+ </view>
133
196
 
134
- <view class="mt-[24rpx]">
135
- <t-input
136
- label="标题"
137
- placeholder="输入标题…"
138
- clearable
139
- :value="message"
140
- @change="onMessageChange"
141
- @clear="onMessageClear"
142
- />
143
- </view>
197
+ <view class="mt-[16rpx]">
198
+ <t-notice-bar theme="info" :content="noticeText" />
199
+ </view>
144
200
 
145
- <view class="mt-[24rpx]">
146
- <t-input
147
- label="新增待办"
148
- placeholder="输入一条待办…"
149
- clearable
150
- :value="newTodo"
151
- @change="onNewTodoChange"
152
- @clear="onNewTodoClear"
153
- />
154
- <view class="mt-[16rpx]">
155
- <t-button block size="large" theme="primary" variant="dashed" @tap="addTodo">
156
- 添加
201
+ <view class="mt-[20rpx]">
202
+ <KpiBoard title="今日概览" subtitle="实时跟踪业务健康度" :items="kpiItems">
203
+ <template #action>
204
+ <t-button size="small" theme="primary" variant="outline" @tap="refreshDashboard">
205
+ 重新计算
157
206
  </t-button>
158
- </view>
159
- </view>
207
+ </template>
208
+ <template #items="{ items }">
209
+ <view v-for="card in items" :key="card.key" class="rounded-[18rpx] bg-[#f4f6ff] p-[16rpx]">
210
+ <view class="flex items-center justify-between">
211
+ <text class="text-[22rpx] text-[#51517c]">
212
+ {{ card.item.label }}
213
+ </text>
214
+ <t-tag v-if="card.isLeading" size="small" theme="warning" variant="light">
215
+ 热点
216
+ </t-tag>
217
+ </view>
218
+ <view class="mt-[12rpx] flex items-end justify-between">
219
+ <view class="flex items-baseline gap-[6rpx]">
220
+ <text class="text-[32rpx] font-semibold text-[#1f1a3f]">
221
+ {{ card.item.value }}
222
+ </text>
223
+ <text v-if="card.item.unit" class="text-[20rpx] text-[#7a7aa0]">
224
+ {{ card.item.unit }}
225
+ </text>
226
+ </view>
227
+ <text
228
+ class="text-[20rpx] font-semibold"
229
+ :class="card.tone === 'positive' ? 'text-[#1b7a3a]' : card.tone === 'negative' ? 'text-[#b42318]' : 'text-[#64748b]'"
230
+ >
231
+ {{ card.tone === 'positive' ? '↑' : card.tone === 'negative' ? '↓' : '→' }}
232
+ {{ card.item.delta ?? '--' }}
233
+ </text>
234
+ </view>
235
+ <text v-if="card.item.footnote" class="mt-[6rpx] block text-[20rpx] text-[#7a7aa0]">
236
+ {{ card.item.footnote }}
237
+ </text>
238
+ </view>
239
+ </template>
240
+ </KpiBoard>
241
+ </view>
160
242
 
161
- <view class="mt-[24rpx]">
162
- <t-cell-group :title="`Checklist(已完成 ${checkedCount}/${todos.length})`" theme="card">
163
- <t-checkbox-group :options="todoOptions" :value="checkedTodos" @change="onTodoChange" />
243
+ <view class="mt-[20rpx]">
244
+ <QuickActionGrid
245
+ title="快速入口"
246
+ subtitle="覆盖主包与分包页面"
247
+ :items="quickActions"
248
+ @select="onQuickAction"
249
+ />
250
+ </view>
251
+
252
+ <view class="mt-[20rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
253
+ <view class="flex items-center justify-between">
254
+ <text class="text-[26rpx] font-semibold text-[#1f1a3f]">
255
+ 体验清单
256
+ </text>
257
+ <t-tag size="small" theme="primary" variant="light">
258
+ 指南
259
+ </t-tag>
260
+ </view>
261
+ <view class="mt-[12rpx]">
262
+ <t-cell-group>
263
+ <t-cell title="多页面 TabBar" note="首页/数据/表单/清单/能力" />
264
+ <t-cell title="分包加载" note="组件实验室与 API 场景" />
265
+ <t-cell title="Composition API" note="ref/computed/watch 驱动" />
266
+ <t-cell title="TDesign 组件" note="表单、列表、反馈" />
164
267
  </t-cell-group>
165
268
  </view>
166
269
  </view>
167
270
 
168
271
  <t-toast id="t-toast" />
169
- <t-dialog id="t-dialog" />
170
272
  </view>
171
273
  </template>