create-weapp-vite 2.3.15 → 2.3.16
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.
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{src-D8uqfCKh.js → src-C8kzMXK7.js} +1 -1
- package/package.json +1 -1
- package/templates/wevu/README.md +3 -3
- package/templates/wevu/package.json +1 -1
- package/templates/wevu/src/app.vue +1 -60
- package/templates/wevu/src/pages/index/index.vue +26 -194
- package/templates/wevu/src/pages/layouts/index.vue +0 -18
- package/templates/wevu/weapp-vite.config.ts +0 -7
- package/templates/wevu-tdesign/README.md +3 -6
- package/templates/wevu-tdesign/package.json +1 -1
- package/templates/wevu-tdesign/project.private.config.json +0 -66
- package/templates/wevu-tdesign/src/app.vue +1 -73
- package/templates/wevu-tdesign/src/pages/index/index.vue +19 -362
- package/templates/wevu/src/components/InfoPanel/index.vue +0 -52
- package/templates/wevu/src/components/StatusPill/index.vue +0 -42
- package/templates/wevu/src/packageA/pages/workspace/index.vue +0 -137
- package/templates/wevu/src/packageB/pages/settings/index.vue +0 -131
- package/templates/wevu/src/pages/overview/index.vue +0 -149
- package/templates/wevu-tdesign/public/tabbar/ability-active.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/ability.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/data-active.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/data.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/form-active.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/form.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/home-active.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/home.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/list-active.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/list.png +0 -0
- package/templates/wevu-tdesign/src/components/EmptyState/index.vue +0 -36
- package/templates/wevu-tdesign/src/components/FilterBar/index.vue +0 -64
- package/templates/wevu-tdesign/src/components/FormRow/index.vue +0 -43
- package/templates/wevu-tdesign/src/components/FormStep/index.vue +0 -48
- package/templates/wevu-tdesign/src/components/KpiBoard/index.vue +0 -145
- package/templates/wevu-tdesign/src/components/QuickActionGrid/index.vue +0 -79
- package/templates/wevu-tdesign/src/components/ResultCard/index.vue +0 -51
- package/templates/wevu-tdesign/src/components/SectionTitle/index.vue +0 -34
- package/templates/wevu-tdesign/src/components/TrendCard/index.vue +0 -101
- package/templates/wevu-tdesign/src/components/VirtualHostClassDemo/BrokenCard.vue +0 -46
- package/templates/wevu-tdesign/src/components/VirtualHostClassDemo/FixedExternalClassCard.vue +0 -50
- package/templates/wevu-tdesign/src/components/VirtualHostClassDemo/RecommendedCard.vue +0 -53
- package/templates/wevu-tdesign/src/hooks/useDialog.ts +0 -205
- package/templates/wevu-tdesign/src/hooks/useFormBinder.ts +0 -17
- package/templates/wevu-tdesign/src/hooks/useLayoutFeedbackBridge.ts +0 -17
- package/templates/wevu-tdesign/src/hooks/usePullDownRefresh.ts +0 -12
- package/templates/wevu-tdesign/src/hooks/useToast.ts +0 -100
- package/templates/wevu-tdesign/src/layouts/admin.vue +0 -41
- package/templates/wevu-tdesign/src/layouts/default.vue +0 -23
- package/templates/wevu-tdesign/src/pages/ability/index.vue +0 -164
- package/templates/wevu-tdesign/src/pages/data/index.vue +0 -189
- package/templates/wevu-tdesign/src/pages/form/index.vue +0 -271
- package/templates/wevu-tdesign/src/pages/layout-feedback/components/FeedbackCallerCard.vue +0 -79
- package/templates/wevu-tdesign/src/pages/layout-feedback/index.vue +0 -211
- package/templates/wevu-tdesign/src/pages/layout-store/index.vue +0 -127
- package/templates/wevu-tdesign/src/pages/layouts/index.vue +0 -120
- package/templates/wevu-tdesign/src/pages/list/index.vue +0 -146
- package/templates/wevu-tdesign/src/stores/layoutInteractionDemo.ts +0 -129
- package/templates/wevu-tdesign/src/subpackages/ability/index.vue +0 -103
- package/templates/wevu-tdesign/src/subpackages/lab/class-binding/index.vue +0 -440
- package/templates/wevu-tdesign/src/subpackages/lab/index.vue +0 -169
- package/templates/wevu-tdesign/src/subpackages/lab/virtual-host-class/index.vue +0 -94
- package/templates/wevu-tdesign/src/types/action.ts +0 -14
- package/templates/wevu-tdesign/src/types/list.ts +0 -17
- package/templates/wevu-tdesign/src/utils/changeEvent.ts +0 -53
- package/templates/wevu-tdesign/src/utils/listFilters.ts +0 -34
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import type { UploadFile } from 'tdesign-miniprogram/upload/type'
|
|
3
|
-
|
|
4
|
-
import { computed, 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
|
-
import { useFormBinder } from '@/hooks/useFormBinder'
|
|
11
|
-
import { useToast } from '@/hooks/useToast'
|
|
12
|
-
import { resolveBooleanChangeValue } from '@/utils/changeEvent'
|
|
13
|
-
|
|
14
|
-
definePageJson({
|
|
15
|
-
navigationBarTitleText: '表单',
|
|
16
|
-
backgroundColor: '#f6f7fb',
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
const { changeModel } = useFormBinder()
|
|
20
|
-
const { showToast } = useToast()
|
|
21
|
-
|
|
22
|
-
const steps = [
|
|
23
|
-
{ key: 'basic', title: '基础信息', subtitle: '业务基本配置' },
|
|
24
|
-
{ key: 'strategy', title: '执行策略', subtitle: '预算与节奏' },
|
|
25
|
-
{ key: 'confirm', title: '确认提交', subtitle: '核对并提交' },
|
|
26
|
-
]
|
|
27
|
-
|
|
28
|
-
const currentStep = ref(0)
|
|
29
|
-
const submitted = ref(false)
|
|
30
|
-
|
|
31
|
-
const formState = reactive({
|
|
32
|
-
name: '',
|
|
33
|
-
owner: '',
|
|
34
|
-
category: 'growth',
|
|
35
|
-
urgent: false,
|
|
36
|
-
budget: 30,
|
|
37
|
-
pace: 'balanced',
|
|
38
|
-
description: '',
|
|
39
|
-
attachments: [] as UploadFile[],
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
const categories = [
|
|
43
|
-
{ value: 'growth', label: '增长' },
|
|
44
|
-
{ value: 'retention', label: '留存' },
|
|
45
|
-
{ value: 'brand', label: '品牌' },
|
|
46
|
-
]
|
|
47
|
-
|
|
48
|
-
const paceOptions = [
|
|
49
|
-
{ value: 'fast', label: '快速推进' },
|
|
50
|
-
{ value: 'balanced', label: '平衡' },
|
|
51
|
-
{ value: 'steady', label: '稳健' },
|
|
52
|
-
]
|
|
53
|
-
|
|
54
|
-
const riskLevel = computed(() => {
|
|
55
|
-
if (formState.urgent && formState.budget > 60) {
|
|
56
|
-
return '高风险'
|
|
57
|
-
}
|
|
58
|
-
if (formState.budget > 40) {
|
|
59
|
-
return '中风险'
|
|
60
|
-
}
|
|
61
|
-
return '可控'
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
const canGoNext = computed(() => {
|
|
65
|
-
if (currentStep.value === 0) {
|
|
66
|
-
return !!formState.name && !!formState.owner
|
|
67
|
-
}
|
|
68
|
-
if (currentStep.value === 1) {
|
|
69
|
-
return !!formState.description
|
|
70
|
-
}
|
|
71
|
-
return true
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
const summaryRows = computed(() => [
|
|
75
|
-
{ label: '项目名称', value: formState.name || '--' },
|
|
76
|
-
{ label: '负责人', value: formState.owner || '--' },
|
|
77
|
-
{ label: '类型', value: categories.find(item => item.value === formState.category)?.label ?? '--' },
|
|
78
|
-
{ label: '预算', value: `${formState.budget} 万` },
|
|
79
|
-
{ label: '节奏', value: paceOptions.find(item => item.value === formState.pace)?.label ?? '--' },
|
|
80
|
-
{ label: '风险级别', value: riskLevel.value },
|
|
81
|
-
])
|
|
82
|
-
|
|
83
|
-
watch(
|
|
84
|
-
() => formState.urgent,
|
|
85
|
-
(value) => {
|
|
86
|
-
if (value) {
|
|
87
|
-
formState.pace = 'fast'
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
const nameModel = changeModel<string>('formState.name')
|
|
93
|
-
const ownerModel = changeModel<string>('formState.owner')
|
|
94
|
-
const categoryModel = changeModel<string>('formState.category')
|
|
95
|
-
const budgetModel = changeModel<number>('formState.budget')
|
|
96
|
-
const paceModel = changeModel<string>('formState.pace')
|
|
97
|
-
const descriptionModel = changeModel<string>('formState.description')
|
|
98
|
-
const attachmentsModel = changeModel<UploadFile[], 'files'>('formState.attachments', {
|
|
99
|
-
valueProp: 'files',
|
|
100
|
-
parser: event => event?.detail?.files ?? [],
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
function setUrgent(value: boolean) {
|
|
104
|
-
formState.urgent = value
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function toggleUrgent() {
|
|
108
|
-
setUrgent(!formState.urgent)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function handleUrgentChange(event: unknown) {
|
|
112
|
-
setUrgent(resolveBooleanChangeValue(event, !formState.urgent))
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function stopUrgentTap() {
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function goNext() {
|
|
119
|
-
if (!canGoNext.value) {
|
|
120
|
-
showToast('请先完善当前步骤信息', 'warning')
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
if (currentStep.value < steps.length - 1) {
|
|
124
|
-
currentStep.value += 1
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function goPrev() {
|
|
129
|
-
if (currentStep.value > 0) {
|
|
130
|
-
currentStep.value -= 1
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function submit() {
|
|
135
|
-
submitted.value = true
|
|
136
|
-
showToast('提交成功')
|
|
137
|
-
}
|
|
138
|
-
</script>
|
|
139
|
-
|
|
140
|
-
<template>
|
|
141
|
-
<view class="min-h-screen bg-[#f6f7fb] px-[28rpx] pb-[88rpx] pt-[24rpx] text-[#1c1c3c]">
|
|
142
|
-
<view class="rounded-[28rpx] bg-linear-to-br from-[#fff7ed] via-[#ffffff] to-[#fef3c7] p-[20rpx]">
|
|
143
|
-
<SectionTitle title="项目提报" subtitle="示例多步表单与联动校验" />
|
|
144
|
-
<view class="mt-[12rpx]">
|
|
145
|
-
<t-steps :current="currentStep" layout="horizontal">
|
|
146
|
-
<t-step-item v-for="item in steps" :key="item.key" :title="item.title" />
|
|
147
|
-
</t-steps>
|
|
148
|
-
</view>
|
|
149
|
-
</view>
|
|
150
|
-
|
|
151
|
-
<view class="mt-[18rpx] space-y-[14rpx]">
|
|
152
|
-
<FormStep
|
|
153
|
-
v-if="currentStep === 0"
|
|
154
|
-
:step="1"
|
|
155
|
-
title="基础信息"
|
|
156
|
-
subtitle="填写核心字段"
|
|
157
|
-
:active="currentStep === 0"
|
|
158
|
-
>
|
|
159
|
-
<view class="flex flex-col gap-[14rpx]">
|
|
160
|
-
<FormRow label="项目名称">
|
|
161
|
-
<t-input
|
|
162
|
-
placeholder="例如:新客增长计划"
|
|
163
|
-
:value="nameModel.value"
|
|
164
|
-
@change="nameModel.onChange"
|
|
165
|
-
/>
|
|
166
|
-
</FormRow>
|
|
167
|
-
<FormRow label="负责人">
|
|
168
|
-
<t-input
|
|
169
|
-
placeholder="例如:王凯"
|
|
170
|
-
:value="ownerModel.value"
|
|
171
|
-
@change="ownerModel.onChange"
|
|
172
|
-
/>
|
|
173
|
-
</FormRow>
|
|
174
|
-
<FormRow label="类型">
|
|
175
|
-
<t-radio-group :value="categoryModel.value" @change="categoryModel.onChange">
|
|
176
|
-
<t-radio v-for="item in categories" :key="item.value" :value="item.value" :label="item.label" />
|
|
177
|
-
</t-radio-group>
|
|
178
|
-
</FormRow>
|
|
179
|
-
<view
|
|
180
|
-
class="urgent-row-toggle flex items-center justify-between rounded-[18rpx] bg-[#f8fafc] px-[18rpx] py-[16rpx]"
|
|
181
|
-
@tap="toggleUrgent"
|
|
182
|
-
>
|
|
183
|
-
<view>
|
|
184
|
-
<text class="text-[22rpx] font-semibold text-[#1f1a3f]">
|
|
185
|
-
加急
|
|
186
|
-
</text>
|
|
187
|
-
<text class="mt-[4rpx] block text-[20rpx] text-[#8a8aa5]">
|
|
188
|
-
整行可点击切换,开启后默认切到快速推进
|
|
189
|
-
</text>
|
|
190
|
-
</view>
|
|
191
|
-
<t-switch :value="formState.urgent" @tap.stop="stopUrgentTap" @change="handleUrgentChange" />
|
|
192
|
-
</view>
|
|
193
|
-
</view>
|
|
194
|
-
</FormStep>
|
|
195
|
-
|
|
196
|
-
<FormStep
|
|
197
|
-
v-if="currentStep === 1"
|
|
198
|
-
:step="2"
|
|
199
|
-
title="执行策略"
|
|
200
|
-
subtitle="预算与节奏"
|
|
201
|
-
:active="currentStep === 1"
|
|
202
|
-
>
|
|
203
|
-
<view class="flex flex-col gap-[14rpx]">
|
|
204
|
-
<FormRow label="预算规模" description="10-100 万">
|
|
205
|
-
<view class="flex items-center gap-[12rpx]">
|
|
206
|
-
<t-slider
|
|
207
|
-
:value="budgetModel.value"
|
|
208
|
-
:min="10"
|
|
209
|
-
:max="100"
|
|
210
|
-
@change="budgetModel.onChange"
|
|
211
|
-
/>
|
|
212
|
-
<text class="text-[22rpx] text-[#5c5b7a]">
|
|
213
|
-
{{ formState.budget }} 万
|
|
214
|
-
</text>
|
|
215
|
-
</view>
|
|
216
|
-
</FormRow>
|
|
217
|
-
<FormRow label="推进节奏">
|
|
218
|
-
<t-radio-group :value="paceModel.value" @change="paceModel.onChange">
|
|
219
|
-
<t-radio v-for="item in paceOptions" :key="item.value" :value="item.value" :label="item.label" />
|
|
220
|
-
</t-radio-group>
|
|
221
|
-
</FormRow>
|
|
222
|
-
<FormRow label="补充说明">
|
|
223
|
-
<t-textarea
|
|
224
|
-
placeholder="描述目标与资源安排"
|
|
225
|
-
:value="descriptionModel.value"
|
|
226
|
-
:maxlength="140"
|
|
227
|
-
@change="descriptionModel.onChange"
|
|
228
|
-
/>
|
|
229
|
-
</FormRow>
|
|
230
|
-
<FormRow label="附件">
|
|
231
|
-
<t-upload
|
|
232
|
-
:files="attachmentsModel.files"
|
|
233
|
-
:max="3"
|
|
234
|
-
@change="attachmentsModel.onChange"
|
|
235
|
-
/>
|
|
236
|
-
</FormRow>
|
|
237
|
-
</view>
|
|
238
|
-
</FormStep>
|
|
239
|
-
|
|
240
|
-
<FormStep
|
|
241
|
-
v-if="currentStep === 2"
|
|
242
|
-
:step="3"
|
|
243
|
-
title="确认提交"
|
|
244
|
-
subtitle="预览关键信息"
|
|
245
|
-
:active="currentStep === 2"
|
|
246
|
-
>
|
|
247
|
-
<ResultCard title="提交摘要" :items="summaryRows">
|
|
248
|
-
<template #action>
|
|
249
|
-
<t-tag size="small" theme="primary" variant="light">
|
|
250
|
-
{{ riskLevel }}
|
|
251
|
-
</t-tag>
|
|
252
|
-
</template>
|
|
253
|
-
</ResultCard>
|
|
254
|
-
</FormStep>
|
|
255
|
-
</view>
|
|
256
|
-
|
|
257
|
-
<view class="mt-[18rpx] flex gap-[12rpx]">
|
|
258
|
-
<t-button block variant="outline" theme="default" :disabled="currentStep === 0" @tap="goPrev">
|
|
259
|
-
上一步
|
|
260
|
-
</t-button>
|
|
261
|
-
<t-button
|
|
262
|
-
block
|
|
263
|
-
theme="primary"
|
|
264
|
-
:disabled="currentStep === steps.length - 1 && submitted"
|
|
265
|
-
@tap="currentStep === steps.length - 1 ? submit() : goNext()"
|
|
266
|
-
>
|
|
267
|
-
{{ currentStep === steps.length - 1 ? (submitted ? '已提交' : '提交') : '下一步' }}
|
|
268
|
-
</t-button>
|
|
269
|
-
</view>
|
|
270
|
-
</view>
|
|
271
|
-
</template>
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref } from 'wevu'
|
|
3
|
-
import { useDialog } from '@/hooks/useDialog'
|
|
4
|
-
import { useToast } from '@/hooks/useToast'
|
|
5
|
-
|
|
6
|
-
const props = defineProps<{
|
|
7
|
-
onReport?: (payload: string) => void
|
|
8
|
-
}>()
|
|
9
|
-
|
|
10
|
-
const actionSeed = ref(0)
|
|
11
|
-
const { showToast } = useToast({ duration: 1400 })
|
|
12
|
-
const { alert, confirm } = useDialog()
|
|
13
|
-
|
|
14
|
-
function nextLabel(prefix: string) {
|
|
15
|
-
actionSeed.value += 1
|
|
16
|
-
return `${prefix} #${actionSeed.value}`
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function triggerChildToast() {
|
|
20
|
-
const label = nextLabel('子组件 Toast')
|
|
21
|
-
showToast(`${label} 已通过 layout 宿主触发`)
|
|
22
|
-
props.onReport?.(`${label} 已触发`)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function triggerChildAlert() {
|
|
26
|
-
const label = nextLabel('子组件 Alert')
|
|
27
|
-
void alert({
|
|
28
|
-
title: label,
|
|
29
|
-
content: '当前弹窗由子组件直接调用 useDialog(),但实际宿主仍在 layout 内。',
|
|
30
|
-
confirmBtn: '知道了',
|
|
31
|
-
}).then(() => {
|
|
32
|
-
props.onReport?.(`${label} 已确认`)
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function triggerChildConfirm() {
|
|
37
|
-
const label = nextLabel('子组件 Confirm')
|
|
38
|
-
void confirm({
|
|
39
|
-
title: label,
|
|
40
|
-
content: '点击确认后会回传一条日志,证明子组件与页面都能经由同一 layout 宿主通信。',
|
|
41
|
-
confirmBtn: '确认',
|
|
42
|
-
cancelBtn: '取消',
|
|
43
|
-
}).then(() => {
|
|
44
|
-
props.onReport?.(`${label} 点击确认`)
|
|
45
|
-
}).catch(() => {
|
|
46
|
-
props.onReport?.(`${label} 点击取消`)
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
</script>
|
|
50
|
-
|
|
51
|
-
<template>
|
|
52
|
-
<view class="rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
|
|
53
|
-
<view class="flex items-center justify-between">
|
|
54
|
-
<view>
|
|
55
|
-
<text class="text-[28rpx] font-semibold text-[#1f1a3f]">
|
|
56
|
-
子组件直连 layout 宿主
|
|
57
|
-
</text>
|
|
58
|
-
<text class="mt-[6rpx] block text-[22rpx] leading-[1.7] text-[#6f6b8a]">
|
|
59
|
-
这个组件不接收 toast/dialog 实例,也不手动 selectComponent,只直接调用 useToast() / useDialog()。
|
|
60
|
-
</text>
|
|
61
|
-
</view>
|
|
62
|
-
<t-tag size="small" theme="primary" variant="light">
|
|
63
|
-
Child
|
|
64
|
-
</t-tag>
|
|
65
|
-
</view>
|
|
66
|
-
|
|
67
|
-
<view class="mt-[18rpx] flex flex-col gap-[12rpx]">
|
|
68
|
-
<t-button block theme="primary" variant="outline" @tap="triggerChildToast">
|
|
69
|
-
子组件触发 Toast
|
|
70
|
-
</t-button>
|
|
71
|
-
<t-button block theme="primary" variant="outline" @tap="triggerChildAlert">
|
|
72
|
-
子组件触发 Alert
|
|
73
|
-
</t-button>
|
|
74
|
-
<t-button block theme="danger" variant="outline" @tap="triggerChildConfirm">
|
|
75
|
-
子组件触发 Confirm
|
|
76
|
-
</t-button>
|
|
77
|
-
</view>
|
|
78
|
-
</view>
|
|
79
|
-
</template>
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed, getCurrentInstance, ref, resolveLayoutHost } from 'wevu'
|
|
3
|
-
import SectionTitle from '@/components/SectionTitle/index.vue'
|
|
4
|
-
import { useDialog } from '@/hooks/useDialog'
|
|
5
|
-
import { LAYOUT_DIALOG_BRIDGE_KEY, LAYOUT_TOAST_BRIDGE_KEY } from '@/hooks/useLayoutFeedbackBridge'
|
|
6
|
-
import { useToast } from '@/hooks/useToast'
|
|
7
|
-
import FeedbackCallerCard from './components/FeedbackCallerCard.vue'
|
|
8
|
-
|
|
9
|
-
definePageJson({
|
|
10
|
-
navigationBarTitleText: 'Layout 通信演示',
|
|
11
|
-
backgroundColor: '#f6f7fb',
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
const pageInstance = getCurrentInstance<any>()
|
|
15
|
-
const { showToast } = useToast({ duration: 1400 })
|
|
16
|
-
const { alert, confirm } = useDialog()
|
|
17
|
-
const actionSeed = ref(0)
|
|
18
|
-
const actionLogs = ref<string[]>([
|
|
19
|
-
'页面与子组件都会直接调用 useToast() / useDialog(),由 layout 统一承载宿主。',
|
|
20
|
-
])
|
|
21
|
-
|
|
22
|
-
const bridgeStatus = computed(() => {
|
|
23
|
-
const toastHost = resolveLayoutHost(LAYOUT_TOAST_BRIDGE_KEY, { context: pageInstance })
|
|
24
|
-
const dialogHost = resolveLayoutHost(LAYOUT_DIALOG_BRIDGE_KEY, { context: pageInstance })
|
|
25
|
-
|
|
26
|
-
return [
|
|
27
|
-
{
|
|
28
|
-
key: 'toast',
|
|
29
|
-
title: 'Toast Host',
|
|
30
|
-
description: toastHost ? '已解析到 layout 内的 t-toast 实例。' : '尚未解析到 toast 宿主。',
|
|
31
|
-
ready: Boolean(toastHost),
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
key: 'dialog',
|
|
35
|
-
title: 'Dialog Host',
|
|
36
|
-
description: dialogHost ? '已解析到 layout 内的 t-dialog 实例。' : '尚未解析到 dialog 宿主。',
|
|
37
|
-
ready: Boolean(dialogHost),
|
|
38
|
-
},
|
|
39
|
-
]
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
function pushLog(message: string) {
|
|
43
|
-
actionLogs.value = [`${new Date().toLocaleTimeString()} ${message}`, ...actionLogs.value].slice(0, 8)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function onChildReport(message: string) {
|
|
47
|
-
pushLog(message)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function nextLabel(prefix: string) {
|
|
51
|
-
actionSeed.value += 1
|
|
52
|
-
return `${prefix} #${actionSeed.value}`
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function triggerPageToast() {
|
|
56
|
-
const label = nextLabel('页面 Toast')
|
|
57
|
-
showToast(`${label} 已通过 layout 宿主触发`)
|
|
58
|
-
pushLog(`${label} 已触发`)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function triggerPageAlert() {
|
|
62
|
-
const label = nextLabel('页面 Alert')
|
|
63
|
-
void alert({
|
|
64
|
-
title: label,
|
|
65
|
-
content: '这是页面直接调用 useDialog() 后,由 layout 内 t-dialog 承载的弹窗。',
|
|
66
|
-
confirmBtn: '知道了',
|
|
67
|
-
}).then(() => {
|
|
68
|
-
pushLog(`${label} 已确认`)
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function triggerPageConfirm() {
|
|
73
|
-
const label = nextLabel('页面 Confirm')
|
|
74
|
-
void confirm({
|
|
75
|
-
title: label,
|
|
76
|
-
content: '确认后会写入日志,方便观察页面与 layout 宿主之间的通信。',
|
|
77
|
-
confirmBtn: '确认',
|
|
78
|
-
cancelBtn: '取消',
|
|
79
|
-
}).then(() => {
|
|
80
|
-
pushLog(`${label} 点击确认`)
|
|
81
|
-
}).catch(() => {
|
|
82
|
-
pushLog(`${label} 点击取消`)
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function inspectDialogHostE2E() {
|
|
87
|
-
const dialogHost = resolveLayoutHost<any>(LAYOUT_DIALOG_BRIDGE_KEY, { context: pageInstance })
|
|
88
|
-
return {
|
|
89
|
-
hasHost: Boolean(dialogHost),
|
|
90
|
-
visible: dialogHost?.data?.visible ?? dialogHost?.properties?.visible ?? null,
|
|
91
|
-
hasOnConfirm: typeof dialogHost?._onConfirm === 'function',
|
|
92
|
-
hasOnCancel: typeof dialogHost?._onCancel === 'function',
|
|
93
|
-
hasNativeConfirm: typeof dialogHost?.onConfirm === 'function',
|
|
94
|
-
hasNativeCancel: typeof dialogHost?.onCancel === 'function',
|
|
95
|
-
title: dialogHost?.data?.title ?? dialogHost?.properties?.title ?? '',
|
|
96
|
-
confirmBtn: dialogHost?.data?._confirm?.content ?? dialogHost?.properties?.confirmBtn ?? '',
|
|
97
|
-
cancelBtn: dialogHost?.data?._cancel?.content ?? dialogHost?.properties?.cancelBtn ?? '',
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async function runPageAlertCloseE2E() {
|
|
102
|
-
triggerPageAlert()
|
|
103
|
-
await new Promise(resolve => setTimeout(resolve, 120))
|
|
104
|
-
return inspectDialogHostE2E()
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async function runPageConfirmOpenE2E() {
|
|
108
|
-
triggerPageConfirm()
|
|
109
|
-
await new Promise(resolve => setTimeout(resolve, 120))
|
|
110
|
-
return inspectDialogHostE2E()
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function getLayoutFeedbackLogsE2E() {
|
|
114
|
-
return actionLogs.value.slice()
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async function runDialogHostConfirmE2E() {
|
|
118
|
-
const dialogHost = resolveLayoutHost<any>(LAYOUT_DIALOG_BRIDGE_KEY, { context: pageInstance })
|
|
119
|
-
dialogHost?.onConfirm?.()
|
|
120
|
-
await new Promise(resolve => setTimeout(resolve, 60))
|
|
121
|
-
return inspectDialogHostE2E()
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async function runDialogHostCancelE2E() {
|
|
125
|
-
const dialogHost = resolveLayoutHost<any>(LAYOUT_DIALOG_BRIDGE_KEY, { context: pageInstance })
|
|
126
|
-
dialogHost?.onCancel?.()
|
|
127
|
-
await new Promise(resolve => setTimeout(resolve, 60))
|
|
128
|
-
return inspectDialogHostE2E()
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
void inspectDialogHostE2E
|
|
132
|
-
void runPageAlertCloseE2E
|
|
133
|
-
void runPageConfirmOpenE2E
|
|
134
|
-
void getLayoutFeedbackLogsE2E
|
|
135
|
-
void runDialogHostConfirmE2E
|
|
136
|
-
void runDialogHostCancelE2E
|
|
137
|
-
</script>
|
|
138
|
-
|
|
139
|
-
<template>
|
|
140
|
-
<view class="min-h-screen bg-[#f6f7fb] px-[28rpx] pb-[88rpx] pt-[24rpx] text-[#1c1c3c]">
|
|
141
|
-
<view class="rounded-[28rpx] bg-linear-to-br from-[#eef2ff] via-[#ffffff] to-[#ede9fe] p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.06)]">
|
|
142
|
-
<SectionTitle title="Layout 反馈宿主通信" subtitle="页面与子组件都直接调用 hooks,由 layout 持有 toast / dialog 组件实例" />
|
|
143
|
-
<text class="mt-[12rpx] block text-[22rpx] leading-[1.7] text-[#5b5b7b]">
|
|
144
|
-
推荐用法是业务侧只关心 useToast() / useDialog(),layout 负责注册宿主;页面和组件都不需要关心 id、selector,也不需要直接拿 layout 实例。
|
|
145
|
-
</text>
|
|
146
|
-
</view>
|
|
147
|
-
|
|
148
|
-
<view class="mt-[18rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
|
|
149
|
-
<SectionTitle title="Bridge 状态" subtitle="当前页面是否成功解析到 layout 宿主" />
|
|
150
|
-
<view class="mt-[16rpx] flex flex-col gap-[12rpx]">
|
|
151
|
-
<view
|
|
152
|
-
v-for="item in bridgeStatus"
|
|
153
|
-
:key="item.key"
|
|
154
|
-
class="rounded-[18rpx] bg-[#f7f7fb] p-[16rpx]"
|
|
155
|
-
>
|
|
156
|
-
<view class="flex items-center justify-between">
|
|
157
|
-
<text class="text-[24rpx] font-semibold text-[#1f1a3f]">
|
|
158
|
-
{{ item.title }}
|
|
159
|
-
</text>
|
|
160
|
-
<t-tag :theme="item.ready ? 'success' : 'warning'" size="small" variant="light">
|
|
161
|
-
{{ item.ready ? 'Ready' : 'Pending' }}
|
|
162
|
-
</t-tag>
|
|
163
|
-
</view>
|
|
164
|
-
<text class="mt-[8rpx] block text-[20rpx] leading-[1.7] text-[#6f6b8a]">
|
|
165
|
-
{{ item.description }}
|
|
166
|
-
</text>
|
|
167
|
-
</view>
|
|
168
|
-
</view>
|
|
169
|
-
</view>
|
|
170
|
-
|
|
171
|
-
<view class="mt-[18rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
|
|
172
|
-
<SectionTitle title="页面直接调用" subtitle="页面本身直接触发 layout 内的 toast / dialog 方法" />
|
|
173
|
-
<view class="mt-[16rpx] flex flex-col gap-[12rpx]">
|
|
174
|
-
<view id="layout-feedback-page-toast-trigger">
|
|
175
|
-
<t-button block theme="primary" @tap="triggerPageToast">
|
|
176
|
-
页面触发 Toast
|
|
177
|
-
</t-button>
|
|
178
|
-
</view>
|
|
179
|
-
<view id="layout-feedback-page-alert-trigger">
|
|
180
|
-
<t-button block theme="primary" variant="outline" @tap="triggerPageAlert">
|
|
181
|
-
页面触发 Alert
|
|
182
|
-
</t-button>
|
|
183
|
-
</view>
|
|
184
|
-
<view id="layout-feedback-page-confirm-trigger">
|
|
185
|
-
<t-button block theme="danger" variant="outline" @tap="triggerPageConfirm">
|
|
186
|
-
页面触发 Confirm
|
|
187
|
-
</t-button>
|
|
188
|
-
</view>
|
|
189
|
-
</view>
|
|
190
|
-
</view>
|
|
191
|
-
|
|
192
|
-
<view class="mt-[18rpx]">
|
|
193
|
-
<FeedbackCallerCard :on-report="onChildReport" />
|
|
194
|
-
</view>
|
|
195
|
-
|
|
196
|
-
<view class="mt-[18rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
|
|
197
|
-
<SectionTitle title="通信日志" subtitle="观察页面与子组件调用 layout 宿主后的反馈结果" />
|
|
198
|
-
<view class="mt-[16rpx] flex flex-col gap-[10rpx]">
|
|
199
|
-
<view
|
|
200
|
-
v-for="(item, index) in actionLogs"
|
|
201
|
-
:key="`${item}-${index}`"
|
|
202
|
-
class="rounded-[16rpx] bg-[#f7f7fb] px-[16rpx] py-[14rpx]"
|
|
203
|
-
>
|
|
204
|
-
<text class="block text-[20rpx] leading-[1.7] text-[#4c4b6c]">
|
|
205
|
-
{{ item }}
|
|
206
|
-
</text>
|
|
207
|
-
</view>
|
|
208
|
-
</view>
|
|
209
|
-
</view>
|
|
210
|
-
</view>
|
|
211
|
-
</template>
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { onUnload, setPageLayout, storeToRefs, watch } from 'wevu'
|
|
3
|
-
import SectionTitle from '@/components/SectionTitle/index.vue'
|
|
4
|
-
import { useLayoutInteractionDemoStore } from '@/stores/layoutInteractionDemo'
|
|
5
|
-
|
|
6
|
-
definePageJson({
|
|
7
|
-
navigationBarTitleText: 'Store 调用 Layout',
|
|
8
|
-
backgroundColor: '#f6f7fb',
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
const store = useLayoutInteractionDemoStore()
|
|
12
|
-
const { activeLayout, adminLayoutProps, commandStatus, lastResult, logs } = storeToRefs(store)
|
|
13
|
-
|
|
14
|
-
watch([activeLayout, adminLayoutProps], ([layout, props]) => {
|
|
15
|
-
if (layout === 'admin') {
|
|
16
|
-
setPageLayout('admin', props)
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
setPageLayout('default')
|
|
20
|
-
}, { immediate: true })
|
|
21
|
-
|
|
22
|
-
function useDefaultLayout() {
|
|
23
|
-
store.setLayout('default')
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function useAdminLayout() {
|
|
27
|
-
store.setLayout('admin')
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function openToastByStore() {
|
|
31
|
-
store.triggerToast()
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function openAlertByStore() {
|
|
35
|
-
store.triggerAlert()
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function openConfirmByStore() {
|
|
39
|
-
store.triggerConfirm()
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function clearLogs() {
|
|
43
|
-
store.resetLogs()
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
onUnload(() => {
|
|
47
|
-
setPageLayout('default')
|
|
48
|
-
})
|
|
49
|
-
</script>
|
|
50
|
-
|
|
51
|
-
<template>
|
|
52
|
-
<view class="min-h-screen bg-[#f6f7fb] px-[28rpx] pb-[88rpx] pt-[24rpx] text-[#1c1c3c]">
|
|
53
|
-
<view class="rounded-[28rpx] bg-linear-to-br from-[#e8f1ff] via-[#ffffff] to-[#eef2ff] p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.06)]">
|
|
54
|
-
<SectionTitle title="Store 驱动 Layout 交互" subtitle="wevu/store 发起意图,页面上下文消费后命中 layout 内的 toast / dialog 宿主" />
|
|
55
|
-
<text class="mt-[12rpx] block text-[22rpx] leading-[1.7] text-[#5b5b7b]">
|
|
56
|
-
推荐边界是 store 只保存布局状态和交互意图,真正调用 useToast() / useDialog() / setPageLayout() 仍由页面执行,这样不会把 page runtime hook 直接塞进 store。
|
|
57
|
-
</text>
|
|
58
|
-
</view>
|
|
59
|
-
|
|
60
|
-
<view class="mt-[18rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
|
|
61
|
-
<SectionTitle title="当前状态" subtitle="观察 store 对布局和宿主交互的描述" />
|
|
62
|
-
<view class="mt-[16rpx] flex flex-col gap-[12rpx]">
|
|
63
|
-
<view class="rounded-[18rpx] bg-[#f7f7fb] p-[16rpx]">
|
|
64
|
-
<text class="text-[24rpx] font-semibold text-[#1f1a3f]">
|
|
65
|
-
当前布局:{{ activeLayout }}
|
|
66
|
-
</text>
|
|
67
|
-
<text class="mt-[8rpx] block text-[20rpx] leading-[1.7] text-[#6f6b8a]">
|
|
68
|
-
command 状态:{{ commandStatus }}
|
|
69
|
-
</text>
|
|
70
|
-
</view>
|
|
71
|
-
<view class="rounded-[18rpx] bg-[#f7f7fb] p-[16rpx]">
|
|
72
|
-
<text class="text-[24rpx] font-semibold text-[#1f1a3f]">
|
|
73
|
-
最近结果
|
|
74
|
-
</text>
|
|
75
|
-
<text class="mt-[8rpx] block text-[20rpx] leading-[1.7] text-[#6f6b8a]">
|
|
76
|
-
{{ lastResult }}
|
|
77
|
-
</text>
|
|
78
|
-
</view>
|
|
79
|
-
</view>
|
|
80
|
-
</view>
|
|
81
|
-
|
|
82
|
-
<view class="mt-[18rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
|
|
83
|
-
<SectionTitle title="切换 Layout" subtitle="store 修改布局状态,页面 watch 后调用 setPageLayout()" />
|
|
84
|
-
<view class="mt-[16rpx] flex flex-col gap-[12rpx]">
|
|
85
|
-
<t-button block theme="primary" @tap="useDefaultLayout">
|
|
86
|
-
Store 切到 default 布局
|
|
87
|
-
</t-button>
|
|
88
|
-
<t-button block theme="primary" variant="outline" @tap="useAdminLayout">
|
|
89
|
-
Store 切到 admin 布局
|
|
90
|
-
</t-button>
|
|
91
|
-
</view>
|
|
92
|
-
</view>
|
|
93
|
-
|
|
94
|
-
<view class="mt-[18rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
|
|
95
|
-
<SectionTitle title="触发 Layout 宿主" subtitle="store 直接调用 toast / dialog,命中当前 layout 内的反馈宿主" />
|
|
96
|
-
<view class="mt-[16rpx] flex flex-col gap-[12rpx]">
|
|
97
|
-
<t-button block theme="primary" @tap="openToastByStore">
|
|
98
|
-
Store 触发 Toast
|
|
99
|
-
</t-button>
|
|
100
|
-
<t-button block theme="primary" variant="outline" @tap="openAlertByStore">
|
|
101
|
-
Store 触发 Alert
|
|
102
|
-
</t-button>
|
|
103
|
-
<t-button block theme="danger" variant="outline" @tap="openConfirmByStore">
|
|
104
|
-
Store 触发 Confirm
|
|
105
|
-
</t-button>
|
|
106
|
-
</view>
|
|
107
|
-
</view>
|
|
108
|
-
|
|
109
|
-
<view class="mt-[18rpx] rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
|
|
110
|
-
<SectionTitle title="通信日志" subtitle="记录 store 发出的布局切换与交互命令" />
|
|
111
|
-
<t-button class="mt-[16rpx]" size="small" theme="default" variant="outline" @tap="clearLogs">
|
|
112
|
-
清空日志
|
|
113
|
-
</t-button>
|
|
114
|
-
<view class="mt-[16rpx] flex flex-col gap-[10rpx]">
|
|
115
|
-
<view
|
|
116
|
-
v-for="(item, index) in logs"
|
|
117
|
-
:key="`${item}-${index}`"
|
|
118
|
-
class="rounded-[16rpx] bg-[#f7f7fb] px-[16rpx] py-[14rpx]"
|
|
119
|
-
>
|
|
120
|
-
<text class="block text-[20rpx] leading-[1.7] text-[#4c4b6c]">
|
|
121
|
-
{{ item }}
|
|
122
|
-
</text>
|
|
123
|
-
</view>
|
|
124
|
-
</view>
|
|
125
|
-
</view>
|
|
126
|
-
</view>
|
|
127
|
-
</template>
|