mrr.sj.front/pages/shop/create-order.vue

802 lines
18 KiB
Vue
Raw Normal View History

2026-03-24 11:45:13 +08:00
<template>
<view class="submit-order">
<!-- 自定义导航栏 -->
<custom-navbar
title="提交订单"
:showBack="true"
backgroundColor="#FFFFFF"
></custom-navbar>
<!-- 地址信息 -->
<view class="address-section" v-if="service.server_kind == 1">
<image
src="/static/images/gohome_location.png"
class="positon-icon"
mode="aspectFit"
></image>
<view class="address-info">
<view class="user-info">
<text class="name">{{ shopInfo.name }}</text>
<text class="phone">{{ shopInfo.account }}</text>
</view>
<view class="address"
>{{ shopInfo.dependency }}{{ shopInfo.address }}</view
>
</view>
<image
src="/static/images/arrow_right.png"
class="arrow-icon"
mode="aspectFit"
></image>
</view>
<!-- v-if="service.server_kind==1" -->
<view class="section-cont" v-if="service.server_kind == 1">
<!-- 时间选择 -->
<view class="time-section" @click="openTimePicker">
<text class="time-label">到家时间</text>
<view class="time-value">
<text class="time">{{ selectedTime || '请选择时间' }}</text>
<image
src="/static/images/arrow_right.png"
class="arrow-icon"
mode="aspectFit"
></image>
</view>
</view>
<!-- 师傅信息 -->
<view class="master-section">
<text class="master-name">手艺人</text>
<text class="master-info">{{ syrorsjInfo.name }}</text>
</view>
</view>
<!-- 预约服务 -->
<view class="service-section">
<view class="section-title">
<view class="icon"></view>
<text class="section-lable">预约服务</text>
</view>
<view class="service-item" @click="goToDetail(service.id)">
<image
class="service-image"
v-if="service.photo && service.photo.length != 0"
:src="service.photo[0]"
mode="aspectFill"
></image>
<view class="service-info">
<text class="service-name text-overflow">{{ service.title }}</text>
<view class="service-count">
<text class="count-lable">服务数量</text>
<text class="count-num">x1</text>
</view>
</view>
</view>
<view class="price-info">
<text class="price-label">原始价格:</text>
<text class="price-value">¥{{ service.server_price }}</text>
</view>
<view class="total-price">
<text class="total-label">订单小计:</text>
<text class="total-value">¥{{ service.server_price }}</text>
</view>
</view>
<!-- 备注 -->
<!-- <view class="remark-section">
<text class="remark-title">备注(选填)</text>
<textarea
class="remark-input"
v-model="remark"
placeholder="请您输入需要备注的内容,如现场情况等"
placeholder-class="placeholder"
></textarea>
</view> -->
<!-- 底部结算栏 -->
<view class="footer">
<view class="price-total">
<text class="price">¥{{ service.server_price }}</text>
<text class="amount-lable">订单小计</text>
</view>
<view class="submit-btn" @click="submitOrder">提交订单</view>
</view>
<!-- 时间选择弹框 -->
<select-time-page
ref="selecTime"
:timeOptions="timeOptions"
:service="service"
@sureTime="sureTime"
@closeTime="closeTime"
></select-time-page>
</view>
</template>
<script>
import customNavbar from "@/components/custom-navbar/custom-navbar.vue";
import selectTimePage from "@/components/select-time-page/select-time-page.vue";
import { debounce } from "../../utils/debounce";
import request from "@/utils/request";
import _public from "../../utils/public";
export default {
components: {
customNavbar,
selectTimePage
},
data() {
return {
shopInfo: {},
serviceId: "",
syrorsjInfo: {}, // 手艺人或商家信息
// 地址信息
reservation_address: {},
s1: "",
s2: "",
s3: "",
selected_date: "",
selected_time: "",
// 时间信息
selectedTime: null,
dateList: ["今天", "明天", "后天"],
timeOptions: [],
selectedDateIndex: 0,
selectedTimeIndex: 0,
showTimePicker: false,
// 服务信息
service: {
photo: [],
server_kind: "",
title: "",
server_price: "",
},
// 备注
remark: "",
// 订单信息
orderInfo: {
originalPrice: 0.01,
totalPrice: 0.01,
},
isSubmit: false,
};
},
async onLoad(options) {
try {
if (options.id) {
this.name = options.name;
// 获取服务详情
const serverdetail = await request.post("/sj/serverdetail", {
id: options.id,
});
const sjdiscount = await request.post("/sj/getsjdiscount", {
id: serverdetail.data.first_class_id,
});
serverdetail.data.server_price = _public.roundUpToTwoDecimals(
Number(serverdetail.data.server_price),
sjdiscount.data.ratio
);
if (serverdetail.state === 1) {
this.service = serverdetail.data;
const syrorsjInfo = await request.post("/sj/syrdetail", {
id: serverdetail.data.publish_user_id,
});
this.syrorsjInfo = syrorsjInfo.data;
if (serverdetail.data.server_kind == 1) {
//今天的时间
let today = this.getDateStr(0);
this.getyestimearrFirst(today, "today");
// 获取当前商家地址
await this.getDefaultAddress(options.id);
}
}
}
} catch (err) {
console.log("报错", err);
}
},
methods: {
// 获取默认地址
async getDefaultAddress(id) {
try {
const beforeShopInfo = await request.post("/user/getuser", { type: 3 });
const nowShopInfo = await request.post("/sj/sjdetail", {
id: beforeShopInfo.data.id,
});
this.shopInfo = nowShopInfo.data;
console.log(this.shopInfo, nowShopInfo.data);
} catch (err) {
console.log("err", err);
}
},
// 进入时获取预约时间
getyestimearrFirst(date, type) {
let that = this;
that.timeOptions = [];
request
.post("/sj/reserve/timeList", {
user_syr_id: this.service.publish_user_id,
})
.then(async (res) => {
that.timeOptions = [
...that.timeOptions,
res.data.today,
res.data.tomorrow,
res.data.after,
];
let stateMap = {
1: "可约",
2: "约满",
3: "休息",
4: "锁定",
5: "不可用",
};
that.timeOptions.forEach((item) => {
item.forEach((ClipboardItem) => {
ClipboardItem.stateName = stateMap[ClipboardItem.state];
});
});
})
.catch((err) => {
console.log("报错", err);
});
},
// 获取预约时间
async getyestimearr(date, type) {
let that = this;
that.timeOptions = [];
await request
.post("/sj/reserve/timeList", {
user_syr_id: this.service.publish_user_id,
})
.then((res) => {
that.timeOptions = [
...that.timeOptions,
res.data.today,
res.data.tomorrow,
res.data.after,
];
let stateMap = {
1: "可约",
2: "约满",
3: "休息",
4: "锁定",
5: "不可用",
};
that.timeOptions.forEach((item) => {
item.forEach((ClipboardItem) => {
ClipboardItem.stateName = stateMap[ClipboardItem.state];
});
});
})
.catch((err) => {
console.log("报错", err);
});
},
// 打开时间选择弹框
async openTimePicker() {
console.log("打开时间选择弹框", this.selected_date);
await this.getyestimearr(this.selected_date);
this.$refs.selecTime.openTime();
},
// 获取日期字符串
getDateStr(days) {
const date = new Date();
date.setDate(date.getDate() + days);
return `${date.getFullYear()}-${(date.getMonth() + 1)
.toString()
.padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
},
goToDetail(id) {
uni.navigateTo({
url: "/pages/shop/service-detail?id=" + id,
});
},
// 确认时间
sureTime(date) {
console.log("选择时间", date);
if (Object.keys(date).length) {
this.selectedTime = `${this.dateList[date.selectedDateIndex]} ${
date.time.show_time
}`;
this.selected_date = this.getDateStr(date.selectedDateIndex);
this.selected_time = date.time.show_time;
this.selectedTimeIndex = date.selectedTimeIndex;
this.selectedDateIndex = date.selectedDateIndex;
}
},
closeTime() {
console.log("关闭时间选择弹框");
},
// 选择到家地址结果
// addReservation(item) {
// this.reservation_address_id = item.id;
// this.reservation_address = item;
// },
// 提交订单
submitOrder: debounce(async function () {
if(this.selected_time.length == 0){
uni.showToast({
title: `请选择时间`,
icon: "none",
});
return
}
if (this.isSubmit) return;
try {
// 判断当前时间是否可用
// const timeavailable = request.post('/user/servertimeavailable');
uni.showLoading({
title: "提交中...",
});
let orderData = {};
orderData = {
server_id: this.service.id, // 测试ID
server_title: this.service.title, // 测试ID
server_type_first_id: this.service.first_class_id, // 测试ID
server_type_secod_id: this.service.second_class_id, // 测试ID
order_type: 3, // 测试ID
order_money: this.service.server_price, // 测试ID
reservation_time: `${this.selected_date} ${this.selected_time}:00`,
order_userid: this.shopInfo.id,
remark: this.remark,
};
const res = await request.post("/sj/creatorder", orderData);
uni.hideLoading();
if (res.state === 1) {
uni.showToast({
title: "提交成功",
icon: "none",
duration: 2000,
});
this.isSubmit = true;
uni.redirectTo({
url: `/pages/shop/pay-order?id=${res.data.id}&money=${this.service.server_price}&title=${this.service.title}&number=${res.data.number}`,
});
} else {
uni.showToast({
title: res.msg || "提交失败",
icon: "none",
});
this.isSubmit = false;
}
} catch (error) {
uni.hideLoading();
uni.showToast({
title: "提交失败,请重试",
icon: "none",
});
console.error("提交订单失败:", error);
this.isSubmit = false;
}
}, 500),
},
};
</script>
<style>
.submit-order {
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
}
/* 地址信息 */
.address-section {
background-color: #ffffff;
padding: 32rpx 24rpx;
margin: 32rpx 24rpx 0;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx 0 rgba(210, 213, 224, 0.5);
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
}
.address-choice,
.address-info {
flex: 1;
}
.positon-icon {
width: 60rpx;
height: 60rpx;
margin-right: 24rpx;
}
.user-info {
display: flex;
align-items: center;
margin-bottom: 8rpx;
}
.name {
font-size: 32rpx;
color: #3d3d3d;
font-weight: 500;
margin-right: 24rpx;
}
.phone {
font-size: 32rpx;
color: #3d3d3d;
font-weight: 500;
}
.address {
font-size: 28rpx;
color: #999999;
}
.section-cont {
margin: 24rpx 24rpx 0;
padding: 0 24rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx 0 rgba(210, 213, 224, 0.5);
background-color: #fff;
}
/* 时间选择 */
.time-section {
padding: 32rpx 0;
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: space-between;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
}
.time-label {
font-size: 24rpx;
color: #666666;
}
.time-value {
display: flex;
align-items: center;
}
.time {
font-size: 24rpx;
color: #333333;
margin-right: 8rpx;
}
/* 师傅信息 */
.master-section {
padding: 32rpx 0;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
}
.master-name {
font-size: 24rpx;
color: #666666;
}
.master-info {
font-size: 24rpx;
color: #333333;
}
/* 预约服务 */
.service-section {
background-color: #ffffff;
padding: 0 24rpx;
margin: 24rpx 24rpx 0;
box-shadow: 0 4rpx 16rpx 0 rgba(210, 213, 224, 0.5);
border-radius: 16rpx;
}
.section-title {
padding: 24rpx 0;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
}
.icon {
width: 6rpx;
height: 28rpx;
border: 3rpx;
margin-right: 16rpx;
background-color: #E8101E;
}
.service-item {
padding-top: 24rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: stretch;
margin-bottom: 24rpx;
}
.section-lable {
font-size: 28rpx;
font-weight: 500;
color: #3d3d3d;
}
.service-image {
width: 160rpx;
height: 160rpx;
border-radius: 16rpx;
margin-right: 24rpx;
background-color: #e2e2e2;
}
.service-info {
flex: 1;
display: flex;
flex-flow: column nowrap;
justify-content: space-between;
align-items: stretch;
}
.service-name {
font-size: 28rpx;
color: #3d3d3d;
font-weight: 500;
}
.service-count {
flex-shrink: 0;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
}
.count-lable {
font-size: 24rpx;
color: #666666;
}
.count-num {
font-size: 32rpx;
color: #333333;
}
.price-info {
margin-top: 32rpx;
margin-bottom: 24rpx;
}
.total-price {
padding-bottom: 32rpx;
}
.price-info,
.total-price {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
}
.price-label,
.total-label {
color: #666666;
font-size: 24rpx;
}
.price-value,
.total-value {
color: #333333;
font-size: 24rpx;
font-weight: 500;
}
/* 备注 */
.remark-section {
background-color: #ffffff;
padding: 32rpx 24rpx;
margin: 24rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx 0 rgba(210, 213, 224, 0.5);
}
.remark-title {
font-size: 28rpx;
color: #333333;
margin-bottom: 24rpx;
display: block;
}
.remark-input {
width: 100%;
height: 160rpx;
font-size: 28rpx;
color: #333333;
}
.placeholder {
color: #999999;
font-size: 28rpx;
}
/* 底部结算栏 */
.footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 150rpx;
background-color: #ffffff;
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
padding: 0 24rpx;
padding-bottom: env(safe-area-inset-bottom);
}
.price-total {
flex: 1;
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
align-items: flex-start;
}
.price-total .price {
font-size: 28rpx;
font-weight: 500;
color: #E8101E;
}
.amount-lable {
font-size: 24rpx;
color: #999999;
}
.submit-btn {
width: 492rpx;
height: 64rpx;
background: #E8101E;
border-radius: 32rpx;
color: #ffffff;
font-size: 28rpx;
display: flex;
align-items: center;
justify-content: center;
}
.arrow-icon {
width: 32rpx;
height: 32rpx;
}
/* 弹框遮罩 */
.popup {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 998;
}
.popup-mask {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
}
/* 时间选择弹框 */
.time-popup {
position: absolute;
left: 0;
right: 0;
bottom: 0;
background-color: #ffffff;
border-radius: 24rpx 24rpx 0 0;
overflow: hidden;
padding-bottom: env(safe-area-inset-bottom);
transform: translateY(0);
transition: transform 0.3s;
z-index: 999;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx;
border-bottom: 1rpx solid #eeeeee;
}
.popup-title {
font-size: 32rpx;
color: #333333;
font-weight: 500;
flex: 1;
text-align: center;
}
.close-icon {
width: 32rpx;
height: 32rpx;
padding: 20rpx;
margin: -20rpx;
}
.time-picker-content {
display: flex;
padding: 32rpx;
}
.date-list {
width: 200rpx;
height: 600rpx;
border-right: 1rpx solid #eeeeee;
}
.date-item {
height: 88rpx;
line-height: 88rpx;
text-align: center;
font-size: 32rpx;
color: #333333;
position: relative;
}
.date-item.active {
color: #ff3e3e;
font-weight: 500;
}
.date-item.active::after {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 32rpx;
background-color: #ff3e3e;
border-radius: 0 4rpx 4rpx 0;
}
.time-list {
flex: 1;
height: 600rpx;
padding-left: 32rpx;
}
.time-item {
height: 88rpx;
line-height: 88rpx;
font-size: 32rpx;
color: #333333;
padding: 0 32rpx;
border-radius: 8rpx;
}
.time-item.active {
background-color: #fff0f0;
color: #ff3e3e;
font-weight: 500;
}
.time-item.noselected {
/* background-color: #FFF0F0; */
color: #999999;
font-weight: 500;
}
/* 多端适配 */
/* #ifdef H5 */
.time-popup {
max-height: 85vh;
}
/* #endif */
/* #ifdef APP-PLUS */
.time-popup {
max-height: 90vh;
}
/* #endif */
/* #ifdef MP-WEIXIN */
.time-popup {
max-height: 95vh;
}
/* #endif */
</style>