Files
ShaFaFanXin/前端/pages/booking/index.uvue
2026-01-27 18:06:04 +08:00

490 lines
9.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page">
<scroll-view class="page-scroll" scroll-y>
<!-- 表单头部 -->
<view class="header-section">
<text class="header-title">预约翻新服务</text>
<text class="header-desc">填写以下信息,我们会尽快与您联系</text>
</view>
<!-- 表单内容 -->
<view class="form-section">
<!-- 姓名 -->
<view class="form-item">
<text class="form-label">
<text class="required">*</text>
您的姓名
</text>
<input
class="form-input"
type="text"
v-model="formData.userName"
placeholder="请输入您的姓名"
placeholder-class="placeholder"
/>
</view>
<!-- 电话 -->
<view class="form-item">
<text class="form-label">
<text class="required">*</text>
联系电话
</text>
<input
class="form-input"
type="number"
v-model="formData.phone"
placeholder="请输入您的手机号"
placeholder-class="placeholder"
maxlength="11"
/>
</view>
<!-- 地址 -->
<view class="form-item">
<text class="form-label">
<text class="required">*</text>
您的地址
</text>
<input
class="form-input"
type="text"
v-model="formData.address"
placeholder="请输入详细地址"
placeholder-class="placeholder"
/>
</view>
<!-- 沙发类型 -->
<view class="form-item">
<text class="form-label">沙发类型</text>
<view class="type-grid">
<view
class="type-item"
:class="{ 'type-active': formData.sofaType == item.id }"
v-for="item in sofaTypes"
:key="item.id"
@click="selectSofaType(item.id)"
>
<text
class="type-text"
:class="{ 'type-text-active': formData.sofaType == item.id }"
>{{ item.name }}</text>
</view>
</view>
</view>
<!-- 问题描述 -->
<view class="form-item">
<text class="form-label">问题描述</text>
<textarea
class="form-textarea"
v-model="formData.problem"
placeholder="请描述沙发的问题(如:皮面开裂、褪色、塌陷等)"
placeholder-class="placeholder"
maxlength="500"
></textarea>
<text class="textarea-count">{{ formData.problem.length }}/500</text>
</view>
<!-- 上传图片 -->
<view class="form-item">
<text class="form-label">上传图片(可选)</text>
<view class="upload-grid">
<view
class="upload-item"
v-for="(item, index) in imageList"
:key="index"
>
<image class="upload-image" :src="item" mode="aspectFill"></image>
<view class="upload-delete" @click="deleteImage(index)">
<text class="delete-icon">×</text>
</view>
</view>
<view class="upload-add" v-if="imageList.length < 9" @click="chooseImage">
<text class="add-icon">+</text>
<text class="add-text">添加图片</text>
</view>
</view>
<text class="upload-tip">最多可上传9张图片</text>
</view>
</view>
<!-- 底部间距 -->
<view class="bottom-space"></view>
</scroll-view>
<!-- 提交按钮 -->
<view class="submit-bar">
<view class="submit-btn" @click="handleSubmit">
<text class="submit-text">提交预约</text>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { submitBooking } from '@/api/index.uts'
import { SOFA_CATEGORIES } from '@/utils/config.uts'
// 表单类型
type FormData = {
userName : string
phone : string
address : string
sofaType : string
problem : string
}
// 沙发类型
type SofaType = {
id : string
name : string
}
// 表单数据
const formData = ref<FormData>({
userName: '',
phone: '',
address: '',
sofaType: '',
problem: ''
})
// 图片列表
const imageList = ref<string[]>([])
// 沙发类型列表
const sofaTypes = ref<SofaType[]>([])
// 提交中
const submitting = ref(false)
// 初始化沙发类型
const initSofaTypes = () => {
sofaTypes.value = SOFA_CATEGORIES.filter((item) : boolean => item.id != 'all').map((item) : SofaType => {
return {
id: item.id,
name: item.name
} as SofaType
})
}
// 选择沙发类型
const selectSofaType = (id : string) => {
formData.value.sofaType = id
}
// 选择图片
const chooseImage = () => {
uni.chooseImage({
count: 9 - imageList.value.length,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
imageList.value = [...imageList.value, ...res.tempFilePaths]
}
})
}
// 删除图片
const deleteImage = (index : number) => {
imageList.value.splice(index, 1)
}
// 验证表单
const validateForm = () : boolean => {
if (formData.value.userName.trim() == '') {
uni.showToast({
title: '请输入您的姓名',
icon: 'none'
})
return false
}
const phone = formData.value.phone.trim()
if (phone == '') {
uni.showToast({
title: '请输入联系电话',
icon: 'none'
})
return false
}
// 简单验证手机号
if (phone.length != 11) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
})
return false
}
if (formData.value.address.trim() == '') {
uni.showToast({
title: '请输入您的地址',
icon: 'none'
})
return false
}
return true
}
// 提交预约
const handleSubmit = async () => {
if (!validateForm()) return
if (submitting.value) return
submitting.value = true
try {
const data = {
userName: formData.value.userName,
phone: formData.value.phone,
address: formData.value.address,
sofaType: formData.value.sofaType,
problem: formData.value.problem,
images: imageList.value
} as UTSJSONObject
const res = await submitBooking(data)
const result = res.data as UTSJSONObject
uni.showModal({
title: '预约成功',
content: result['message'] as string,
showCancel: false,
success: () => {
// 返回上一页或首页
uni.navigateBack({
fail: () => {
uni.switchTab({
url: '/pages/index/index'
})
}
})
}
})
} catch (e) {
console.error('提交预约失败', e)
uni.showToast({
title: '提交失败,请重试',
icon: 'none'
})
}
submitting.value = false
}
onLoad(() => {
initSofaTypes()
})
</script>
<style lang="scss">
.page {
flex: 1;
background-color: #f5f5f5;
}
.page-scroll {
flex: 1;
}
/* 头部 */
.header-section {
background: linear-gradient(135deg, #D4A574 0%, #B8895A 100%);
padding: 48rpx 32rpx;
align-items: center;
}
.header-title {
font-size: 40rpx;
font-weight: 600;
color: #ffffff;
margin-bottom: 12rpx;
}
.header-desc {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.8);
}
/* 表单区域 */
.form-section {
background-color: #ffffff;
margin: 24rpx;
border-radius: 16rpx;
padding: 32rpx;
}
.form-item {
margin-bottom: 32rpx;
}
.form-label {
font-size: 28rpx;
font-weight: 600;
color: #333333;
margin-bottom: 16rpx;
}
.required {
color: #F56C6C;
margin-right: 4rpx;
}
.form-input {
background-color: #f5f5f5;
border-radius: 12rpx;
padding: 24rpx;
font-size: 28rpx;
height:40px;
}
.placeholder {
color: #C0C4CC;
}
/* 沙发类型选择 */
.type-grid {
flex-direction: row;
flex-wrap: wrap;
}
.type-item {
padding: 16rpx 32rpx;
background-color: #f5f5f5;
border-radius: 8rpx;
margin-right: 16rpx;
margin-bottom: 16rpx;
}
.type-active {
background-color: #D4A574;
}
.type-text {
font-size: 26rpx;
color: #606266;
}
.type-text-active {
color: #ffffff;
}
/* 文本域 */
.form-textarea {
background-color: #f5f5f5;
border-radius: 12rpx;
padding: 24rpx;
font-size: 28rpx;
height: 200rpx;
width: 100%;
}
.textarea-count {
font-size: 24rpx;
color: #909399;
text-align: right;
margin-top: 8rpx;
}
/* 图片上传 */
.upload-grid {
flex-direction: row;
flex-wrap: wrap;
}
.upload-item {
width: 200rpx;
height: 200rpx;
margin-right: 16rpx;
margin-bottom: 16rpx;
position: relative;
}
.upload-image {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.upload-delete {
position: absolute;
top: -16rpx;
right: -16rpx;
width: 40rpx;
height: 40rpx;
background-color: #F56C6C;
border-radius: 50%;
align-items: center;
justify-content: center;
}
.delete-icon {
font-size: 28rpx;
color: #ffffff;
}
.upload-add {
width: 200rpx;
height: 200rpx;
background-color: #f5f5f5;
border-radius: 12rpx;
align-items: center;
justify-content: center;
border-width: 2rpx;
border-style: dashed;
border-color: #DCDFE6;
}
.add-icon {
font-size: 48rpx;
color: #909399;
}
.add-text {
font-size: 24rpx;
color: #909399;
margin-top: 8rpx;
}
.upload-tip {
font-size: 24rpx;
color: #909399;
margin-top: 16rpx;
}
/* 底部间距 */
.bottom-space {
height: 160rpx;
}
/* 提交按钮 */
.submit-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #ffffff;
padding: 24rpx 32rpx;
padding-bottom: 48rpx;
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.submit-btn {
background-color: #D4A574;
border-radius: 999rpx;
padding: 28rpx 0;
align-items: center;
}
.submit-text {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
</style>