feat(webDev): add inquiry modal for pricing plans

This commit introduces a 'Contact Sales' modal on the web development page, allowing users to inquire about specific service plans.

- The pricing plan buttons now trigger this modal, pre-filled with the selected plan's details.
- Users can add custom remarks to their inquiry.
- On submission, a pre-formatted message is generated and opened in WhatsApp using a new `useWhatsAppMsgSender` composable.
- Adds `NUXT_PUBLIC_WHATSAPP_NUMBER` to the runtime configuration.
- Refactors content validation by introducing Zod schemas for `PricingPlan` and `Button` props to improve type safety.
- Adds new i18n keys for the modal interface and message templates.
This commit is contained in:
xiaomai
2025-11-07 11:04:14 +08:00
parent 40b3ee147f
commit ccfd268682
14 changed files with 393 additions and 40 deletions

View File

@@ -4,20 +4,44 @@
<p class="text-muted py-4 text-center">{{ page?.remarks }}</p>
<UTabs :items="page?.services.map((s) => ({ ...s, slot: s.id }))">
<template
v-for="service in page?.services"
:key="service.id"
#[service.id]
>
<UTabs :items="serviceTabs">
<template v-for="service in serviceTabs" :key="service.id" #[service.id]>
<UPricingPlans :plans="service.plans" />
</template>
</UTabs>
<WebDevContactSalesModal ref="webDevContactSalesModal" />
</UContainer>
</template>
<script lang="ts" setup>
import WebDevContactSalesModal from "~/components/webDev/ContactSalesModal.vue";
const { data: page } = await useLocalizedCollection("webDev");
const webDevContactSalesModal = ref<InstanceType<
typeof WebDevContactSalesModal
> | null>(null);
const serviceTabs = computed(() =>
page.value?.services.map((srv) => ({
...srv,
plans: srv.plans.map((pln) => ({
...pln,
button: {
label: "立刻咨询", // TODO: i18n 适配
onClick: () => {
webDevContactSalesModal.value?.openModal({
serviceTitle: srv.label,
planTitle: pln.title,
startingPrice: pln.price,
features: pln.features ?? [],
});
},
},
})),
slot: srv.id,
}))
);
</script>
<style></style>