490 lines
9.3 KiB
Plaintext
490 lines
9.3 KiB
Plaintext
<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>
|