This commit is contained in:
zhangjianjun 2026-07-20 16:33:37 +08:00
parent 96869761e2
commit 226eeabece
3 changed files with 243 additions and 72 deletions

View File

@ -1,5 +1,5 @@
export default definePageConfig({
navigationBarTitleText: '门店企业标注快办',
navigationBarTitleText: '企业经营咨询',
navigationBarBackgroundColor: '#ffffff',
navigationBarTextStyle: 'black',
backgroundColor: '#f2f7fb',

View File

@ -205,6 +205,97 @@
line-height: 1.75;
}
.landing-page__document-mask {
position: fixed;
z-index: 40;
inset: 0;
display: flex;
align-items: flex-end;
padding-top: 80px;
box-sizing: border-box;
background: rgb(0 0 0 / 48%);
}
.landing-page__document {
display: flex;
width: 100%;
max-height: 88vh;
padding-bottom: env(safe-area-inset-bottom);
overflow: hidden;
border-radius: 28px 28px 0 0;
box-sizing: border-box;
flex-direction: column;
background: var(--landing-surface);
}
.landing-page__document-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 28px 30px 22px;
border-bottom: 1px solid #e5e7e9;
}
.landing-page__document-title,
.landing-page__document-date,
.landing-page__document-heading,
.landing-page__document-copy {
display: block;
}
.landing-page__document-title {
font-size: 34px;
font-weight: 700;
line-height: 1.4;
}
.landing-page__document-date {
margin-top: 4px;
color: var(--landing-muted);
font-size: 20px;
line-height: 1.4;
}
.landing-page__document-close {
height: 60px;
margin: 0;
padding: 0 24px;
border: 0;
border-radius: 10px;
color: var(--landing-green-dark);
font-size: 24px;
line-height: 60px;
background: rgb(7 193 96 / 8%);
}
.landing-page__document-close::after {
border: 0;
}
.landing-page__document-body {
height: 860px;
padding: 4px 30px 36px;
box-sizing: border-box;
}
.landing-page__document-section {
padding-top: 26px;
}
.landing-page__document-heading {
font-size: 27px;
font-weight: 600;
line-height: 1.5;
}
.landing-page__document-copy {
margin-top: 10px;
color: var(--landing-muted);
font-size: 24px;
line-height: 1.75;
text-align: justify;
}
@media (prefers-reduced-motion: reduce) {
.landing-page__input,
.landing-page__textarea,

View File

@ -1,37 +1,104 @@
import { Button, Checkbox, CheckboxGroup, Input, Radio, RadioGroup, Text, Textarea, View } from '@tarojs/components'
import { Button, Checkbox, CheckboxGroup, Input, Radio, RadioGroup, ScrollView, Text, Textarea, View } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useState } from 'react'
import './index.scss'
type ServiceType = 'new' | 'update'
type ConsultationType = 'operation' | 'brand'
type DocumentType = 'privacy' | 'service'
type ApplicationForm = {
serviceType: ServiceType
storeName: string
storeAddress: string
type ConsultationForm = {
consultationType: ConsultationType
businessName: string
businessCategory: string
contactName: string
contactPhone: string
description: string
}
type FormErrors = Partial<Record<keyof ApplicationForm | 'agreement', string>>
type FormErrors = Partial<Record<keyof ConsultationForm | 'agreement', string>>
const INITIAL_FORM: ApplicationForm = {
serviceType: 'new',
storeName: '',
storeAddress: '',
type DocumentSection = {
heading: string
content: string
}
const CONTACT_PHONE = '4001166311'
const INITIAL_FORM: ConsultationForm = {
consultationType: 'operation',
businessName: '',
businessCategory: '',
contactName: '',
contactPhone: '',
description: '',
}
const DOCUMENTS: Record<DocumentType, { title: string, updatedAt: string, sections: DocumentSection[] }> = {
privacy: {
title: '隐私政策',
updatedAt: '更新日期2026年7月20日',
sections: [
{
heading: '一、我们处理的信息',
content: '当您使用咨询信息填写功能时,页面会处理您主动填写的企业或门店名称、经营类别、联系人姓名、联系电话和咨询内容。我们不会要求您提供身份证件、精确位置、通讯录、相册或其他与咨询无关的信息。',
},
{
heading: '二、处理目的和方式',
content: '上述信息仅用于在当前页面核对咨询资料是否填写完整。当前版本没有服务器提交接口,不会将表单内容上传、保存或提供给第三方。关闭或刷新页面后,已填写内容不会由本小程序留存。',
},
{
heading: '三、权限与第三方共享',
content: '本页面不会申请位置、相机、相册、麦克风或通讯录权限,也不会通过本页面向任何第三方共享、转让或公开披露您填写的信息。',
},
{
heading: '四、您的权利',
content: '您可以随时修改或清空尚未提交的内容,也可以不填写表单并直接退出页面。若您对个人信息保护有疑问,可在工作时间拨打页面底部客服电话联系我们。',
},
{
heading: '五、政策更新',
content: '如后续开通在线提交或存储功能,我们会在收集信息前更新本政策,明确告知收集范围、使用目的、保存期限和保护措施,并重新取得您的同意。',
},
],
},
service: {
title: '用户服务协议',
updatedAt: '生效日期2026年7月20日',
sections: [
{
heading: '一、服务内容',
content: '本页面提供门店经营信息梳理、品牌展示建议和宣传资料制作等企业咨询信息填写服务。本服务不提供任何平台的官方认证、官方代办或结果承诺。',
},
{
heading: '二、使用方式',
content: '您应根据实际需求填写企业或门店信息。页面校验完成后,您可自行选择是否拨打客服电话进行正式咨询。当前版本不会在线提交或保存表单内容。',
},
{
heading: '三、用户责任',
content: '您应保证提供的信息真实、合法且不侵犯他人权益,不得利用本服务提交违法、虚假、侵权或与企业咨询无关的内容。',
},
{
heading: '四、服务费用',
content: '信息填写和电话咨询不收取费用。如后续服务产生费用,工作人员会在服务开始前说明具体项目、价格和退款规则,由您自主决定是否购买。',
},
{
heading: '五、免责声明',
content: '咨询建议仅供经营决策参考,实际执行效果会受到经营环境、市场变化和用户自身情况影响。我们不会承诺特定经营结果。',
},
{
heading: '六、联系我们',
content: '如您对服务内容或本协议有疑问可在工作日9:00-18:00拨打客服电话400-116-6311。',
},
],
},
}
const PHONE_PATTERN = /^1[3-9]\d{9}$/
const validateForm = (form: ApplicationForm, agreed: boolean) => {
const validateForm = (form: ConsultationForm, agreed: boolean) => {
const errors: FormErrors = {}
if (!form.storeName.trim()) errors.storeName = '请输入门店名称'
if (!form.storeAddress.trim()) errors.storeAddress = '请输入门店地址'
if (!form.businessName.trim()) errors.businessName = '请输入企业或门店名称'
if (!form.businessCategory.trim()) errors.businessCategory = '请输入经营类别'
if (!form.contactName.trim()) errors.contactName = '请输入联系人姓名'
if (!form.contactPhone.trim()) {
@ -40,36 +107,24 @@ const validateForm = (form: ApplicationForm, agreed: boolean) => {
errors.contactPhone = '请输入正确的手机号码'
}
if (!form.description.trim()) errors.description = '请描述需要办理的内容'
if (!agreed) errors.agreement = '请阅读并同意隐私政策和服务说明'
if (!form.description.trim()) errors.description = '请描述您的咨询需求'
if (!agreed) errors.agreement = '请阅读并同意隐私政策和用户服务协议'
return errors
}
export default function Landing () {
const [form, setForm] = useState<ApplicationForm>(INITIAL_FORM)
const [form, setForm] = useState<ConsultationForm>(INITIAL_FORM)
const [agreed, setAgreed] = useState(false)
const [errors, setErrors] = useState<FormErrors>({})
const [activeDocument, setActiveDocument] = useState<DocumentType | null>(null)
const updateField = <K extends keyof ApplicationForm>(field: K, value: ApplicationForm[K]) => {
const updateField = <K extends keyof ConsultationForm>(field: K, value: ConsultationForm[K]) => {
setForm((current) => ({ ...current, [field]: value }))
setErrors((current) => ({ ...current, [field]: undefined }))
}
const showPolicy = (type: 'privacy' | 'service') => {
const isPrivacy = type === 'privacy'
Taro.showModal({
title: isPrivacy ? '隐私政策' : '服务说明',
content: isPrivacy
? '您填写的信息仅用于本次门店标注服务的联系与确认,我们将妥善保护您的个人信息。'
: '提交申请后,工作人员将在服务时间内联系您核对资料。具体办理结果以实际审核情况为准。',
showCancel: false,
confirmText: '我知道了',
})
}
const handleSubmit = () => {
const handleSubmit = async () => {
const validationErrors = validateForm(form, agreed)
const firstError = Object.values(validationErrors)[0]
@ -80,64 +135,71 @@ export default function Landing () {
return
}
Taro.showModal({
title: '提交成功',
content: '您的申请已提交,工作人员将在服务时间内联系您确认。',
showCancel: false,
confirmText: '我知道了',
const result = await Taro.showModal({
title: '信息填写完成',
content: '当前版本不会上传或保存表单信息。如需正式咨询请拨打客服电话400-116-6311。',
cancelText: '稍后联系',
confirmText: '拨打客服',
confirmColor: '#07c160',
})
if (result.confirm) {
await Taro.makePhoneCall({ phoneNumber: CONTACT_PHONE })
}
}
const document = activeDocument ? DOCUMENTS[activeDocument] : null
return (
<View className='landing-page'>
<View className='landing-page__intro'>
<Text className='landing-page__title'>线</Text>
<Text className='landing-page__title'>线</Text>
<Text className='landing-page__description'>
线
</Text>
<Text className='landing-page__notice'></Text>
<Text className='landing-page__notice'></Text>
</View>
<View className='landing-page__form'>
<View className='landing-page__field'>
<Text className='landing-page__label'></Text>
<Text className='landing-page__label'></Text>
<RadioGroup
className='landing-page__service-types'
onChange={(event) => updateField('serviceType', event.detail.value as ServiceType)}
onChange={(event) => updateField('consultationType', event.detail.value as ConsultationType)}
>
<View className={`landing-page__service-type ${form.serviceType === 'new' ? 'landing-page__service-type--selected' : ''}`}>
<Radio className='landing-page__radio' value='new' checked={form.serviceType === 'new'} color='#07c160'></Radio>
<View className={`landing-page__service-type ${form.consultationType === 'operation' ? 'landing-page__service-type--selected' : ''}`}>
<Radio className='landing-page__radio' value='operation' checked={form.consultationType === 'operation'} color='#07c160'></Radio>
</View>
<View className={`landing-page__service-type ${form.serviceType === 'update' ? 'landing-page__service-type--selected' : ''}`}>
<Radio className='landing-page__radio' value='update' checked={form.serviceType === 'update'} color='#07c160'></Radio>
<View className={`landing-page__service-type ${form.consultationType === 'brand' ? 'landing-page__service-type--selected' : ''}`}>
<Radio className='landing-page__radio' value='brand' checked={form.consultationType === 'brand'} color='#07c160'></Radio>
</View>
</RadioGroup>
</View>
<View className='landing-page__field'>
<Text className='landing-page__label'></Text>
<Text className='landing-page__label'></Text>
<Input
className={`landing-page__input ${errors.storeName ? 'landing-page__input--error' : ''}`}
value={form.storeName}
className={`landing-page__input ${errors.businessName ? 'landing-page__input--error' : ''}`}
value={form.businessName}
maxlength={50}
placeholder='请输入营业执照上的门店名称'
placeholder='请输入企业或门店名称'
placeholderClass='landing-page__placeholder'
onInput={(event) => updateField('storeName', event.detail.value)}
onInput={(event) => updateField('businessName', event.detail.value)}
/>
{errors.storeName && <Text className='landing-page__error'>{errors.storeName}</Text>}
{errors.businessName && <Text className='landing-page__error'>{errors.businessName}</Text>}
</View>
<View className='landing-page__field'>
<Text className='landing-page__label'></Text>
<Text className='landing-page__label'></Text>
<Input
className={`landing-page__input ${errors.storeAddress ? 'landing-page__input--error' : ''}`}
value={form.storeAddress}
maxlength={100}
placeholder='请输入完整经营地址'
className={`landing-page__input ${errors.businessCategory ? 'landing-page__input--error' : ''}`}
value={form.businessCategory}
maxlength={40}
placeholder='例如:餐饮、零售、生活服务'
placeholderClass='landing-page__placeholder'
onInput={(event) => updateField('storeAddress', event.detail.value)}
onInput={(event) => updateField('businessCategory', event.detail.value)}
/>
{errors.storeAddress && <Text className='landing-page__error'>{errors.storeAddress}</Text>}
{errors.businessCategory && <Text className='landing-page__error'>{errors.businessCategory}</Text>}
</View>
<View className='landing-page__field'>
@ -168,12 +230,12 @@ export default function Landing () {
</View>
<View className='landing-page__field'>
<Text className='landing-page__label'></Text>
<Text className='landing-page__label'></Text>
<Textarea
className={`landing-page__textarea ${errors.description ? 'landing-page__input--error' : ''}`}
value={form.description}
maxlength={300}
placeholder='请描述需要办理的内容'
placeholder='请描述希望咨询的经营问题或资料制作需求'
placeholderClass='landing-page__placeholder'
onInput={(event) => updateField('description', event.detail.value)}
/>
@ -190,25 +252,43 @@ export default function Landing () {
>
<Checkbox className='landing-page__checkbox' value='agreed' checked={agreed} color='#07c160' />
<Text className='landing-page__agreement-text'></Text>
<Text className='landing-page__link' onClick={() => showPolicy('privacy')}></Text>
<Text className='landing-page__link' onClick={() => setActiveDocument('privacy')}></Text>
<Text className='landing-page__agreement-text'></Text>
<Text className='landing-page__link' onClick={() => showPolicy('service')}></Text>
<Text className='landing-page__link' onClick={() => setActiveDocument('service')}></Text>
</CheckboxGroup>
{errors.agreement && <Text className='landing-page__agreement-error'>{errors.agreement}</Text>}
<Button
className='landing-page__submit'
hoverClass='landing-page__submit--pressed'
onClick={handleSubmit}
>
<Button className='landing-page__submit' hoverClass='landing-page__submit--pressed' onClick={handleSubmit}>
</Button>
<View className='landing-page__footer'>
<Text> 9:00-18:00</Text>
<Text>400-800-1234</Text>
<Text></Text>
<Text>400-116-6311</Text>
<Text></Text>
</View>
{document && (
<View className='landing-page__document-mask'>
<View className='landing-page__document'>
<View className='landing-page__document-header'>
<View>
<Text className='landing-page__document-title'>{document.title}</Text>
<Text className='landing-page__document-date'>{document.updatedAt}</Text>
</View>
<Button className='landing-page__document-close' onClick={() => setActiveDocument(null)}></Button>
</View>
<ScrollView className='landing-page__document-body' scrollY>
{document.sections.map((section) => (
<View className='landing-page__document-section' key={section.heading}>
<Text className='landing-page__document-heading'>{section.heading}</Text>
<Text className='landing-page__document-copy'>{section.content}</Text>
</View>
))}
</ScrollView>
</View>
</View>
)}
</View>
)
}