feat:接口对接,功能实现

This commit is contained in:
faiz 2024-10-23 09:48:48 +08:00
parent fe4d817b42
commit 8ad2b0296e
15 changed files with 756 additions and 261 deletions

View File

@ -3,7 +3,8 @@ type ServiceEnv = Record<ServiceEnvType, ServiceEnvConfig>
const serviceEnv: ServiceEnv = {
dev: {
url: 'http://192.168.0.100:8787',
// url: 'https://hex.jipinq.cn',
url: '/api',
json: 'http://localhost:8080',
},
test: {
@ -11,7 +12,7 @@ const serviceEnv: ServiceEnv = {
json: 'http://localhost:8080',
},
prod: {
url: 'http://localhost:8080',
url: 'https://hex.jipinq.cn',
json: 'http://localhost:8080',
},
}

View File

@ -1,5 +1,5 @@
{
"name" : "452",
"name" : "旅游度假预约出行系统",
"appid" : "__UNI__FAB99D9",
"description" : "",
"versionName" : "1.0.0",
@ -50,7 +50,7 @@
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx56a1f8716a60996d",
"appid" : "wx2e8b2af5ed5b28b4",
"setting" : {
"urlCheck" : false
},

View File

@ -1,21 +1,28 @@
<template>
<view class="home-head" :style="{ paddingTop: safeAreaInsets?.top + 'px' }">
<view class="nav">
<wd-icon @click='onBack' name="thin-arrow-left" size="35rpx"></wd-icon>
<text class='nav_title'>旅游度假 预约出行系统</text>
<wd-icon @click="onBack" name="thin-arrow-left" size="35rpx"></wd-icon>
<text class="nav_title">旅游度假 预约出行系统</text>
</view>
<view class="main" v-if="status">
<view class="list flex">
<view class="lable">出游日期 </view>
<view class="">2024年09月2日-2024年09月13日</view>
</view>
<wd-form ref="form" :model="model">
<wd-cell-group>
<wd-picker prop='num' :rules="[{ required: true, message: '请选择出游人数' }]" :columns="columns" label="出游人数" v-model="model.num" @confirm="handleConfirm" />
<view class="list flex">
<view class="lable">出游日期</view>
<view class="">{{ travelDate }}</view>
</view>
<wd-form ref="form" :model="model">
<wd-cell-group>
<wd-picker
prop="num"
:rules="[{ required: true, message: '请选择出游人数' }]"
:columns="columns"
label="出游人数"
v-model="model.num"
@confirm="handleConfirm"
/>
<!-- <wd-icon name="camera" size="22px"></wd-icon> -->
<view class="mist" v-for="(item, index) in model.num">
<wd-input
<!-- <wd-icon name="camera" size="22px"></wd-icon> -->
<view class="mist list flex">
<!-- <wd-input
:key="index"
:label="'出游券码截图' + (index+1)"
:prop="'voucher.' + index + '.value'"
@ -24,89 +31,110 @@
disabled
no-border
suffixIcon='camera'
@clicksuffixicon='handleUpdat(index)'
v-model="model.code_pic[index]"
placeholder="出游券码截图"
:rules="[{ required: true, message: '请填写出游券码截图' + (index+1) }]"
/>
<view class='tip flex' @click="handleVoucherCode">
<view class="tip-bor flex items-center">
<image src="../../static/home/tip.png" mode=""></image>
</view>
<view style="color: #2A8AFF;font-size: 22rpx;">如何查看券码</view>
/> -->
<view style="font-size: 28rpx; width: 200rpx">出游券码截图</view>
<wd-upload
v-model:file-list="fileList"
:limit="model.num"
:upload-method="customUpload"
@change="handleChange"
></wd-upload>
<view class="tip flex" @click="handleVoucherCode">
<view class="tip-bor flex items-center">
<image src="../../static/home/tip.png" mode=""></image>
</view>
<view style="color: #2a8aff; font-size: 22rpx">如何查看券码</view>
</view>
<wd-input
label="出游人姓名"
label-width="200rpx"
prop="name"
clearable
no-border
v-model="model.name"
placeholder="请输入用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
<wd-input
label="出游人电话"
label-width="200rpx"
prop="mobile"
no-border
clearable
v-model="model.mobile"
placeholder="请输入出游人电话"
:rules="[{ required: true, message: '请填写出游人电话' }]"
/>
<wd-textarea no-border size="large" label-width="100rpx" label="备注" v-model="model.note" placeholder="请填写备注" />
</wd-cell-group>
<view class="footer">
<view class="btn" @click="handleSubmit">立刻预约</view>
</view>
</wd-form>
<wd-input
label="出游人姓名"
label-width="200rpx"
prop="name"
clearable
no-border
v-model="model.name"
placeholder="请输入用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
<wd-input
label="出游人电话"
label-width="200rpx"
prop="mobile"
no-border
clearable
v-model="model.mobile"
placeholder="请输入出游人电话"
:rules="[
{ required: true, message: '请填写出游人电话' },
{ validator: checkPhone, message: '请填写正确的电话' }
]"
/>
<wd-textarea
no-border
size="large"
label-width="100rpx"
label="备注"
v-model="model.note"
placeholder="请填写备注"
/>
</wd-cell-group>
<view class="footer">
<view class="btn" @click="handleSubmit">立刻预约</view>
</view>
</wd-form>
</view>
<view class="main" v-else>
<view class="status-icon">
<image src="../../static/home/scuss.png" mode=""></image>
<view style="margin-top: 28rpx;">
预约成功
</view>
<view style="margin-top: 28rpx">预约成功</view>
</view>
</view>
<view class="main" v-if="showQuan">
<!-- <view class="main" v-if="showQuan">
<image class="quan" src="../../static/home/quan.png"></image>
</view>
<wd-popup v-model="show" position='center' custom-style='border-radius: 25rpx;width:525rpx' @close="handleClose">
</view> -->
<wd-popup
v-model="show"
position="center"
custom-style="border-radius: 25rpx;width:525rpx"
@close="handleClose"
>
<view class="pop">
<view class="pop-title">确认预约</view>
<view class="pop-tip">预约成功后取消或修改需联系商家</view>
<view class="pop-list flex items-center">
<view class="pop-icon flex items-center justify-center">
<wd-icon color='#1096FD' name="check" size="22rpx"></wd-icon>
<wd-icon color="#1096FD" name="check" size="22rpx"></wd-icon>
</view>
<view class="pop-desc overflow"> 欧洲13国12天9晚双飞游</view>
<view class="pop-desc overflow">{{ productName }}</view>
</view>
<view class="pop-list flex items-center">
<view class="pop-icon flex items-center justify-center">
<wd-icon color='#1096FD' name="check" size="22rpx"></wd-icon>
<wd-icon color="#1096FD" name="check" size="22rpx"></wd-icon>
</view>
<view class="pop-desc overflow"> 2024.09.02(周一)-2024.09.13(周五)</view>
<view class="pop-desc overflow">{{ travelDate }}</view>
</view>
<view class="pop-list flex items-center">
<view class="pop-icon flex items-center justify-center">
<wd-icon color='#1096FD' name="check" size="22rpx"></wd-icon>
<wd-icon color="#1096FD" name="check" size="22rpx"></wd-icon>
</view>
<view class="pop-desc overflow"> 1</view>
<view class="pop-desc overflow">{{ model.num }}</view>
</view>
<view class="pop-list flex items-center">
<view class="pop-icon flex items-center justify-center">
<wd-icon color='#1096FD' name="check" size="22rpx"></wd-icon>
<wd-icon color="#1096FD" name="check" size="22rpx"></wd-icon>
</view>
<view class="pop-desc overflow"> 吴生</view>
<view class="pop-desc overflow">{{ model.name }}</view>
</view>
<view class="pop-list flex items-center">
<view class="pop-icon flex items-center justify-center">
<wd-icon color='#1096FD' name="check" size="22rpx"></wd-icon>
<wd-icon color="#1096FD" name="check" size="22rpx"></wd-icon>
</view>
<view class="pop-desc overflow"> 13588779988</view>
<view class="pop-desc overflow">{{ model.mobile }}</view>
</view>
</view>
<view class="bottom flex items-center">
@ -118,180 +146,277 @@
</template>
<script lang="ts" setup>
// import {uploadImageOne} from '@/utils'
import { getServiceEnvConfig } from "@/config";
import { orderBook } from "@/service/api/user/index";
import { orderDetail } from "@/service/api/user/index";
import { showToast, checkPhone } from "@/utils";
const config = getServiceEnvConfig(import.meta.env);
import type {
UploadMethod,
UploadFile
} from "@/uni_modules/wot-design-uni/components/wd-upload/types";
const fileList = ref<UploadFile[]>([]);
//
const { safeAreaInsets } = uni.getSystemInfoSync()
const { safeAreaInsets } = uni.getSystemInfoSync();
// const { success: showSuccess } = useToast()
const status = ref(1)
const showQuan = ref(false)
const status = ref(1);
const showQuan = ref(false);
const show = ref(false);
const show = ref(false)
const handleVoucherCode = ()=>{
// status.value = 0
// showQuan.value = true
const handleVoucherCode = () => {
uni.navigateTo({
url:'/pages/appointment-quan/index'
})
url: "/pages/appointment-quan/index"
});
};
// const handleUpdat =(event:any)=>{
// uploadImageOne('/api/upload/index', res => {
// console.log(res)
// })
// }
//
const customUpload: UploadMethod = (file, formData, options) => {
const uploadTask = uni.uploadFile({
url: config.url + "/api/upload/index",
header: options.header,
name: options.name,
fileName: options.name,
fileType: options.fileType,
formData,
filePath: file.url,
success(res) {
if (res.statusCode === options.statusCode) {
//
options.onSuccess(res, file, formData);
} else {
//
options.onError({ ...res, errMsg: res.errMsg || "" }, file, formData);
}
},
fail(err) {
//
options.onError(err, file, formData);
}
});
//
uploadTask.onProgressUpdate(res => {
options.onProgress(res, file);
});
};
//
const handleChange = ({ fileList }) => {
fileList.value = fileList;
};
//
const handleClose = () => {
show.value = false;
};
//
const handleSave = () => {
orderBook(model).then((res: any) => {
if (res.msg == "ok") {
show.value = false;
status.value = 0;
} else {
show.value = false;
showToast({
icon: "none",
title: res.error
});
setTimeout(() => {
uni.switchTab({
url: "/pages/index/index"
});
}, 1000);
}
});
};
const travelDate = ref("");
const detailData = ref({});
const productName = ref("");
//
onLoad(async ({ date, start, order_id }) => {
travelDate.value = decodeURIComponent(date);
model.travel_date = start;
model.order_id = order_id;
let res: any = await orderDetail({ order_id });
if (res.msg == "ok") {
productName.value = res.data.product_name;
console.log(productName.value);
}
});
const model = reactive<{
num: number;
code_pic: Array;
name: String;
mobile: String;
note: String;
travel_date: String;
order_id: String;
}>({
num: 1,
code_pic: [],
name: "",
mobile: "",
note: "",
travel_date: "",
order_id: ""
});
const form = ref();
const columns = ref([1, 2, 3, 4, 5, 6, 7]);
//
function handleConfirm({ value }) {
model.num = value;
let count = fileList.value.length - value;
fileList.value.splice(-count, count);
}
const handleClose = ()=>{
show.value = false
}
const handleSave = ()=>{
const handleSubmit = () => {
console.log(fileList.value);
if (!fileList.value.length) {
return showToast({
icon: "none",
title: "请上传出游券码截图"
});
}
model.code_pic = fileList.value.map(item => {
return JSON.parse(item.response).data;
});
// if(model.code_pic.length<model.num){
// return showToast({
// icon: "none",
// title: ""
// });
// }
form.value
.validate()
.then(({ valid, errors }) => {
if (valid) {
// showSuccess({
// msg: ''
// })
show.value = false
show.value = true;
}
})
.catch((error) => {
console.log(error, 'error')
})
}
onLoad(() => {
console.log(safeAreaInsets)
})
const model = reactive<{
num: number,
code_pic: Array,
name:string,
mobile:string,
note:string
}>({
num: 1,
code_pic: [],
name:'',
mobile:'',
note:''
})
.catch(error => {
console.log(error, "error");
});
};
const form = ref()
const columns = ref([1, 2, 3, 4, 5, 6, 7])
function handleConfirm({ value }) {
model.num = value
}
const handleSubmit = ()=> {
show.value = true
// form.value
// .validate()
// .then(({ valid, errors }) => {
// if (valid) {
// // showSuccess({
// // msg: ''
// // })
// }
// })
// .catch((error) => {
// console.log(error, 'error')
// })
}
const handleAppointment = ()=>{
uni.navigateTo({
url:'/pages/appointment-time/index'
})
}
const onBack = ()=>{
uni.navigateBack({ delta: 1 })
}
const handleAppointment = () => {
uni.navigateTo({
url: "/pages/appointment-time/index"
});
};
const onBack = () => {
if (status.value) {
uni.navigateBack({ delta: 1 });
} else {
uni.switchTab({
url: "/pages/index/index"
});
}
};
</script>
<style lang="scss" scoped>
.txt{
.txt {
font-size: 30rpx;
font-weight: bold;
color: #181818;
}
.pdf{
color: #0095FF;
.pdf {
color: #0095ff;
font-size: 24rpx;
font-weight: bold;
}
.overflow {
white-space: nowrap; /* 文本不换行 */
overflow: hidden; /* 隐藏超出的内容 */
text-overflow: ellipsis; /* 当文本溢出时显示省略号 */
white-space: nowrap; /* 文本不换行 */
overflow: hidden; /* 隐藏超出的内容 */
text-overflow: ellipsis; /* 当文本溢出时显示省略号 */
}
.footer{
.footer {
margin-top: 222rpx;
}
.btn{
// margin-top: 160rpx;
background: #1170FF;
border-radius: 50rpx;
padding: 20rpx 230rpx;
text-align: center;
color: #fff;
font-size: 32rpx;
.btn {
// margin-top: 160rpx;
background: #1170ff;
border-radius: 50rpx;
padding: 20rpx 230rpx;
text-align: center;
color: #fff;
font-size: 32rpx;
}
.pop{
.pop {
padding: 40rpx 30rpx 0 30rpx;
.pop-title{
.pop-title {
font-size: 32rpx;
font-weight: bold;
color: #181818;
text-align: center;
}
.pop-icon{
.pop-icon {
border-radius: 50%;
background: #E7F4FE;
background: #e7f4fe;
width: 36rpx;
height: 36rpx;
}
.pop-tip{
.pop-tip {
font-size: 24rpx;
color: #878585;
margin-top: 14rpx;
text-align: center;
}
.pop-list{
.pop-list {
margin-top: 25rpx;
& + .pop-list{
& + .pop-list {
margin-top: 10rpx;
}
}
.pop-desc{
.pop-desc {
margin-left: 10rpx;
font-size: 26rpx;
color: #181818;
}
}
.bottom{
.bottom {
width: 100%;
margin-top: 45rpx;
border-top: 1px solid #D8D8D8;
border-top: 1px solid #d8d8d8;
justify-content: space-between;
.bottom-btn-left,.bottom-btn-right{
.bottom-btn-left,
.bottom-btn-right {
padding: 25rpx 0;
width: 50%;
text-align: center;
}
.bottom-btn-right{
border-left: 1px solid #D8D8D8;
.bottom-btn-right {
border-left: 1px solid #d8d8d8;
}
}
.status-icon{
.status-icon {
padding-top: 90rpx;
margin: 0 270rpx;
text-align: center;
image{
width: 160rpx;
height: 160rpx;
}
image {
width: 160rpx;
height: 160rpx;
}
}
.mist{
.tip{
margin-left: 28rpx;
.tip-bor{
.mist {
position: relative;
.tip {
position: absolute;
left: 28rpx;
top: 80rpx;
// margin-left: 28rpx;
.tip-bor {
margin-right: 10rpx;
image{
image {
width: 18rpx;
height: 18rpx;
}
@ -303,42 +428,42 @@ const onBack = ()=>{
height: 574rpx;
background: linear-gradient(180deg, #92deeb 0%, rgba(216, 216, 216, 0) 100%);
border-radius: 0px 0px 0px 0px;
.nav{
.nav {
padding: 16rpx 0 16rpx 20rpx;
.nav_title{
.nav_title {
font-size: 36rpx;
color: #181818;
font-weight: bold;
margin-left: 75rpx;
}
}
.main{
.main {
margin: 54rpx 26rpx 0 26rpx;
background: #fff;
border-radius: 20rpx;
min-height: 894rpx;
// padding: 40rpx 30rpx;
.quan{
.quan {
height: 3502rpx;
}
.list{
.list {
padding: 40rpx 30rpx;
padding-bottom: 10rpx;
color: #181818;
font-size: 28rpx;
.lable{
.lable {
font-weight: bold;
}
.box{
.box {
font-weight: 400;
margin-left: 20rpx;
}
}
::v-deep.wd-textarea__inner{
::v-deep.wd-textarea__inner {
border: 1px solid #444444;
}
::v-deep.wd-input__icon{
color: #1170FF;
::v-deep.wd-input__icon {
color: #1170ff;
}
// ::v-deep.wd-picker__cell{
// padding: 0;

View File

@ -7,7 +7,7 @@
</view>
<view class="main">
<image class="quan" src="../../static/home/quan.png"></image>
<image class="quan" src="http://hex.jipinq.cn/quan.png"></image>
</view>
</view>
</template>

View File

@ -8,13 +8,13 @@
<view class="head-title">
<text class="txt">选择出行日期</text>
<text class="data">可选</text>
<text class="rde">12天9</text>
<text class="rde">{{maxRange}}{{nights}}</text>
<text class="desc">·所选日期为北京时间</text>
</view>
<wd-calendar-view custom-class='data' :panel-height='500' :formatter="formatter" :max-range="7" type="daterange" :show-panel-title='false' v-model="dataTime" @change="handleChange" />
<wd-calendar-view custom-class='data' :panel-height='500' :min-date='getProductId()' :formatter="formatter" :max-range="maxRange" type="daterange" :show-panel-title='false' v-model="dataTime" @change="handleChange" />
</view>
<view class="bottom">
<view class="desc">09.02-09.13 共12天9晚</view>
<view class="desc">{{dataDesc}}</view>
<view class="btn" @click="handleMise">
下一步
</view>
@ -23,9 +23,26 @@
</template>
<script lang="ts" setup>
import { showToast } from '@/utils'
//
const { safeAreaInsets } = uni.getSystemInfoSync()
const dataTime = ref([])
const maxRange = ref(0)
const order_id = ref('')
const nights = ref(0)
onLoad(({day,id,night}) => {
maxRange.value = Number(day)
nights.value = night
order_id.value = id
})
const getProductId =()=>{
//
const yesterday = new Date();
const timestamp = yesterday.getTime(); //
return timestamp
}
const dataTime = ref([0,0])
const dataDesc = ref('')
//
const formatter = (day) => {
@ -40,10 +57,9 @@ const formatter = (day) => {
const nowDa = now.getDate()
day.bottomInfo = '可约'
// if (year === nowYear && month === nowMonth && da === nowDa) {
// day.topInfo = ''
// }
if (year === nowYear && month === nowMonth && da === nowDa) {
day.topInfo = '今天'
}
if (month === 5 && da === 18) {
day.topInfo = '618大促'
}
@ -73,34 +89,110 @@ const formatter = (day) => {
const onBack = ()=>{
uni.navigateBack({ delta: 1 })
}
const handleMise = ()=>{
uni.navigateTo({
url:'/pages/appointment-form/index'
})
function isArrayOfNonEmptyValues(arr) {
// 使 every
return arr.every(item => item !== null && item !== undefined && item !== ''&& item);
}
const handleMise = ()=>{
let {days} = calculateDaysAndNights(travelStartDate.value,travelEndDate.value)
if(isArrayOfNonEmptyValues(dataTime.value)){
if(days<maxRange.value){
return showToast({
icon: 'none',
title: '出发与结束日期不能小于7天',
})
}
uni.navigateTo({
url:`/pages/appointment-form/index?date=${encodeURIComponent(travelDate.value)}&start=${travelStartDate.value}&order_id=${order_id.value}`
})
}else{
return showToast({
icon: 'none',
title: '选择出发与结束日期',
})
}
}
function getEndDateAfterNDays(startTimestamp:any, n:any) {
//
if (isNaN(startTimestamp) || typeof n !== 'number' || n < 0) {
throw new Error('Invalid input');
}
// Date
const start = new Date(startTimestamp * 1000);
// n
const end = new Date(start);
end.setDate(start.getDate() + n);
//
const endTimestamp = end.getTime() / 1000;
return endTimestamp;
}
function calculateDaysAndNights(startDate, endDate) {
// Date
const start = new Date(startDate);
const end = new Date(endDate);
//
const diffInMilliseconds = end - start;
//
const diffInDays = Math.floor(diffInMilliseconds / (1000 * 60 * 60 * 24));
//
const nights = diffInDays;
// 1
const days = diffInDays + 1;
return { days, nights };
}
function padZero(num) {
return num < 10 ? '0' + num : num;
}
const travelDate = ref('')
const travelStartDate = ref('')
const travelEndDate = ref('')
const handleChange = ({ value })=>{
const date = new Date(value[0])
// console.log(getEndDateAfterNDays(value[0],maxRange.value));
console.log(dataTime.value);
// dataTime.value[1] = getEndDateAfterNDays(value[0],maxRange.value)
// console.log(dataTime.value);
const now = new Date(value[1])
// const year = date.getFullYear()
const month = date.getMonth()
const year = date.getFullYear()
const month = date.getMonth()+1
const da = date.getDate()
// const nowYear = now.getFullYear()
const nowMonth = now.getMonth()
const nowYear = now.getFullYear()
const nowMonth = now.getMonth()+1
const nowDa = now.getDate()
let {days,nights} = calculateDaysAndNights(`${year}-${padZero(month)}-${padZero(da)}`,`${nowYear}-${padZero(nowMonth)}-${padZero(nowDa)}`)
let wth = value[1]?`${days}${nights}`:''
// console.log(nowDa-da);
dataDesc.value = `${month}.${da}-${nowMonth}.${nowDa}`
console.log(dataDesc.value)
dataDesc.value = `${padZero(month)}.${padZero(da)}-${value[1]?padZero(nowMonth):''}${value[1]?'.':''}${value[1]?padZero(nowDa):''} ${wth}`
travelDate.value = `${year}${padZero(month)}${padZero(da)}日-${nowYear}${padZero(nowMonth)}${padZero(nowDa)}`
travelStartDate.value = `${year}-${padZero(month)}-${padZero(da)}`
travelEndDate.value = `${nowYear}-${padZero(nowMonth)}-${padZero(nowDa)}`
}
</script>
<style lang="scss" scoped>
::v-deep .wd-month-panel__weeks,::v-deep .wd-month__day,::v-deep .wd-month__title,::v-deep .wd-month__day-text{
font-weight: 700;
}
::v-deep .wd-month__day{
height: var(--wot-calendar-day-height, 54px);
// line-height: var(--wot-calendar-day-height, 54px);
}
.txt{
color: #181818;
font-size: 32rpx;

View File

@ -11,7 +11,7 @@
<view class="phone_input">
<wd-input no-border use-suffix-slot type="text" v-model="phone" center>
<template #suffix>
<view class="phone_btn">查询</view>
<view class="phone_btn" @click="handleServe">查询</view>
</template >
</wd-input>
</view>
@ -19,55 +19,27 @@
<view class="home-list">
<view class="list_title">查询结果:</view>
<view class="list_main">
<view class="list_item">
<view class="list_item" v-for="(item) in serveOrderList">
<view class="order flex items-center">
<view class="id">订单编号4566888888</view>
<!-- <view class="btn">去预约</view> -->
<view class="id">订单编号{{item.sn}}</view>
<view v-if="item.can_book||item.is_book" class="btn" :class="item.is_book?'is-disabled':''" @click="handleAppointment(item.id)">{{item.is_book?'已提交':'去预约'}}</view>
</view>
<view class="stroke">
<text class="stroke_lable">行程</text>
<text class="stroke_desc">欧洲12天纯玩</text>
<text class="stroke_desc">{{item.product_name}}</text>
</view>
<view class="content flex items-center">
<view class="content_item">
<view class="title">订单金额</view>
<view class="desc">6800</view>
<view class="desc">{{item.actual_price}}</view>
</view>
<view class="content_item">
<view class="title">状态</view>
<wd-text size="24rpx" type="success" text="已使用"></wd-text>
<!-- <wd-text type="error" text="错误"></wd-text>
<wd-text text="默认"></wd-text>
<view class="desc">已使用</view> -->
<wd-text size="24rpx" bold :type="item.can_book||item.is_book?'success':'error'" :text="item.h5_os_status_name"></wd-text>
</view>
<view class="content_item">
<view class="title">下单平台</view>
<view class="desc">美团官方视频号直播</view>
</view>
</view>
</view>
<view class="list_item">
<view class="order flex items-center">
<view class="id">订单编号4566888888</view>
<view class="btn" @click="handleAppointment">去预约</view>
</view>
<view class="stroke">
<text class="stroke_lable">行程</text>
<text class="stroke_desc">欧洲12天纯玩</text>
</view>
<view class="content flex items-center">
<view class="content_item">
<view class="title">订单金额</view>
<view class="desc">6800</view>
</view>
<view class="content_item">
<view class="title">状态</view>
<wd-text type="error" size="24rpx" text="未预约"></wd-text>
<!-- <view class="desc">未预约</view> -->
</view>
<view class="content_item">
<view class="title">下单平台</view>
<view class="desc">美团官方视频号直播</view>
<view class="desc">{{item.h5_os_name}}</view>
</view>
</view>
</view>
@ -77,7 +49,10 @@
</view>
</template>
<script lang="ts" setup>
import {orderList} from '@/service/api/user/index'
import { getErrorMsg, hideLoading, showErrorModal, showLoading, showToast } from '@/utils'
//
const { safeAreaInsets } = uni.getSystemInfoSync()
@ -87,14 +62,35 @@ onLoad(() => {
})
const phone = ref('')
const handleAppointment = ()=>{
const handleAppointment = (id:[string,number])=>{
uni.navigateTo({
url:'/pages/user-info/index'
url:`/pages/user-info/index?id=${id}`
})
}
const serveOrderList = ref([])
const handleServe = async()=>{
let res = await orderList({mobile:phone.value})
if(res.msg =='ok'){
serveOrderList.value = res.data.data
}else{
showToast({
icon: 'none',
title: res.error,
})
}
}
</script>
<style lang="scss" scoped>
.is-disabled{
background: #D0D0D0 !important;
pointer-events: none;
// color: #181818 !important;
}
::v-deep .uni-input-input{
font-weight: 700;
}
.main-title-color {
color: #d14328;
}
@ -208,6 +204,7 @@ const handleAppointment = ()=>{
.desc{
margin-top: 14rpx;
font-size: 24rpx;
font-weight: 700;
}
}
}

View File

@ -8,23 +8,20 @@
<view class="main-item txt">
<view class="main-title">下单行程</view>
<view class="main-desc">欧洲12天纯玩</view>
<view class="main-desc overflow">{{detailData.product_name}}</view>
</view>
<view class="main-item">
<view class="main-title txt">查看详细行程</view>
<view class="flex items-center main_pdf flex-wrap">
<view class="main-desc pdf overflow">出境旅游合同.pdf</view>
<view class="main-desc pdf overflow" @click="previewWechat(detailData.product.trip_info)">出境旅游合同.pdf</view>
</view>
</view>
<view class="main-item">
<view class="main-title txt">查看旅游合同</view>
<view class="flex items-center main_pdf flex-wrap">
<view class="main-desc pdf overflow">出境旅游合同.pdf</view>
<view class="main-desc pdf overflow">出境旅游合同.pdf</view>
<view class="main-desc pdf overflow">出境旅游合同.pdf</view>
<view class="main-desc pdf overflow">出境旅游合同.pdf</view>
<view class="main-desc pdf overflow" @click="previewWechat(detailData.travel_contract)">出境旅游合同.pdf</view>
</view>
</view>
@ -34,27 +31,28 @@
<view class="main_content_left">
<view class="list">
<text class="lable">姓名:</text>
<text class="box">李达</text>
<text class="box">{{detailData.admin&&detailData.admin.name}}</text>
</view>
<view class="list">
<text class="lable">手机号:</text>
<text class="box">13355558888</text>
<text class="box">{{detailData.mobile}}</text>
</view>
<view class="list">
<text class="lable">微信号:</text>
<text class="box">13355558888</text>
<text class="box">{{detailData.admin&&detailData.admin.wechat}}</text>
</view>
<view class="list">
<text class="lable">职位:</text>
<text class="box">金牌管家</text>
<text class="box">{{detailData.admin&&detailData.admin.job}}</text>
</view>
<view class="list">
<text class="lable">服务承诺:</text>
<text class="box">顾客是上帝</text>
<text class="box">{{detailData.admin&&detailData.admin.service_promise}}</text>
</view>
</view>
<view class="main_content_right">
<image src="../../static/home/user.png" mode=""></image>
<image v-if="detailData.admin&&detailData.admin.wechat_pic" :src="detailData.admin.wechat_pic" mode=""></image>
<image v-else src="../../static/home/user.png" mode=""></image>
</view>
</view>
<view class="btn" @click="handleAppointment"> 预约出行 </view>
@ -65,18 +63,50 @@
</template>
<script lang="ts" setup>
import {orderDetail} from '@/service/api/user/index'
//
const { safeAreaInsets } = uni.getSystemInfoSync()
onLoad(() => {
console.log(safeAreaInsets)
const detailData = ref({})
const order_id = ref('')
onLoad(async({id}) => {
order_id.value = id
let res:any = await orderDetail({order_id:id})
if(res.msg == 'ok'){
detailData.value = res.data
// console.log(res.data);
}
console.log(detailData.value)
})
const handleAppointment = ()=>{
uni.navigateTo({
url:'/pages/appointment-time/index'
url:`/pages/appointment-time/index?day=${detailData.value.product.day}&night=${detailData.value.product.night}&id=${order_id.value}`
})
}
//,.doc,.docx,.xls,.xlsx,.pdf
const previewWechat=(urlPdf:String)=> {
uni.showLoading({
title: '正在加载中..'
})
uni.downloadFile({
url: urlPdf,
success: function(res) {
var filePath = res.tempFilePath;
uni.openDocument({
filePath: filePath,
showMenu: true,
success: function(res) {
console.log('打开文档成功');
uni.hideLoading()
},
});
},
complete: function(r) {
uni.hideLoading()
}
});
}
const onBack = ()=>{
uni.navigateBack({ delta: 1 })
}

View File

@ -10,6 +10,27 @@ export function fetchUserInfo() {
url: 'xxxxxxxxxxxx/user',
})
}
// 订单预约
export function orderBook(data:any) {
return apiResquest.post({
url: 'order/book',
data
})
}
// 查询列表
export function orderList(data:any) {
return apiResquest.get({
url: 'order/index',
data
})
}
// 订单详情
export function orderDetail(data:any) {
return apiResquest.get({
url: 'order/detail',
data
})
}
// async () => {
// const { age, name } = await fetchUserInfo()

View File

@ -12,7 +12,7 @@ export const apiResquest = createRequest(
},
},
{
requestInterceptors: [tokenRequestInterceptor],
// requestInterceptors: [tokenRequestInterceptor],
responseInterceptors: [statusResponseInterceptor, resultResponseInterceptor],
})

View File

@ -35,12 +35,13 @@ export function createRequest(baseRequestConfig: RequestConfig, interceptorConfi
return new Promise<T>((resolve, reject) => {
uni.request({
url: `${baseURL}${url}`,
url: `${baseURL}/api/${url}`,
method,
header,
timeout,
data,
success(result) {
success(result:any) {
// console.log(result)
try {
// 响应拦截器
result = invokeArrayFns(responseInterceptors as Function[], result)
@ -55,9 +56,10 @@ export function createRequest(baseRequestConfig: RequestConfig, interceptorConfi
reject(msg)
return
}
// console.log(result.data)
resolve(result.data)
// 自定义返回数据
resolve(returnData(result.data) as T)
// resolve(returnData(result.data) as T)
// 显示成功toast
if (successMsg) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

View File

@ -2,3 +2,5 @@ export * from './error'
export * from './modal'
export * from './route'
export * from './storage'
export * from './updataImg'
export * from './validate'

View File

@ -0,0 +1,139 @@
import { getServiceEnvConfig } from '@/config'
const config = getServiceEnvConfig(import.meta.env)
/**
* toast
*/
const msg = (params:any, callback:any) => {
setTimeout(() => {
uni.showToast({
title: typeof params === 'string' ? params : params.title,
duration: params.item || 1500,
mask: params.mask || true,
icon: params.icon || 'none'
})
setTimeout(() => {
if (typeof callback === "function") { callback() };
}, params.item || 1500)
}, 0)
}
/*
*
* @param object opt
* @param callable successCallback data
* @param callable errorCallback
*/
export const uploadImageOne = function (opt:any, successCallback:Function, errorCallback:Function) {
if (typeof opt === "string") {
let url = opt;
opt = {};
opt.url = url;
}
let count = opt.count || 1,
sizeType = opt.sizeType || ["compressed"],
sourceType = opt.sourceType || ["album", "camera"],
is_load = opt.is_load || true,
uploadUrl = opt.url || "";
// inputName = opt.name || "field";
uni.chooseImage({
count: count, //最多可以选择的图片总数
sizeType: sizeType, // 可以指定是原图还是压缩图,默认二者都有
sourceType: sourceType, // 可以指定来源是相册还是相机,默认二者都有
success: async (res:any) => {
let image = [];
let filesLen = res.tempFiles.length;
let exceeded_list = [];
let uploadMaxSize = 10;
let imageList = [];
let urlPath = config.url + uploadUrl;
if (count === 1) {
console.log(await uploadFile(urlPath, res.tempFilePaths[0], opt, "图片上传中"));
successCallback &&
successCallback(await uploadFile(urlPath, res.tempFilePaths[0], opt, "图片上传中"));
} else {
for (let i = 0; i < res.tempFiles.length; i++) {
if (Math.ceil(res.tempFiles[i].size / 1024) < uploadMaxSize * 1024) {
image.push(res.tempFiles[i].path);
} else {
exceeded_list.push(i + 1);
filesLen = filesLen - 1;
// #ifdef APP-PLUS
plus.nativeUI.alert(
`${[...new Set(exceeded_list)].join(",")}张图片超出限制${uploadMaxSize}MB,已过滤`
);
// #endif
// #ifndef APP-PLUS
uni.showModal({
content: `${[...new Set(exceeded_list)].join(
","
)}${uploadMaxSize}MB,`,
});
// #endif
continue;
}
}
for (const key in image) {
let data = await uploadFile(urlPath, image[key], opt, "图片上传中");
imageList.push(data.data.url);
}
successCallback && successCallback(imageList);
}
},
});
}
const uploadFile = (urlPath:any, localPath:any, opt:any, message:any) => {
console.log(urlPath);
console.log(localPath);
return new Promise(async resolve => {
//启动上传等待中...
if (message)
uni.showLoading({
title: message,
});
uni.uploadFile({
url: urlPath,
filePath: localPath,
name: opt.name || "file",
header: {
// 'Authorization': 'Bearer ' + uni.getStorageSync('access-token'),
'accept': 'application/json',
},
// header: {
// // #ifdef MP
// "Content-Type": "multipart/form-data",
// // #endif
// // [TOKENNAME]: "Bearer " + store.state.app.token,
// },
success: function (res) {
uni.hideLoading();
if (res.statusCode == 403) {
// uni.showToast({
// title: res.data,
// duration:1500,
// icon: 'none'
// })
} else {
let data = res.data ? JSON.parse(res.data) : {};
if (data.status == 'success') {
resolve(data);
} else {
// uni.showToast({
// title: data.message,
// duration:1500,
// icon: 'none'
// })
}
}
},
fail: function (res:any) {
uni.hideLoading();
// uni.showToast({
// title: res.errMsg,
// duration:1500,
// icon: 'none'
// })
},
});
});
}

View File

@ -0,0 +1,69 @@
/**
* 验证小数点后两位及多个小数
* money 金额
*/
export function isMoney(money) {
var reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/;
if (reg.test(money)) {
return true;
} else {
return false;
}
}
/**
* 验证手机号码
*/
export function checkPhone(phone) {
var reg = /^1(3|4|5|6|7|8|9)\d{9}$/;
if (reg.test(phone)) {
return true;
} else {
return false;
}
}
/**
* 验证名字 中国
*/
export function checkCname(cn) {
var reg = /^[\u4e00-\u9fa5]{2,5}$/;
if (reg.test(cn)) {
return true;
} else {
return false;
}
}
/**
* 验证名字银行卡
*/
export function checkBank(card) {
var reg = /^\d{16,19}$/;
if (reg.test(card)) {
return true;
} else {
return false;
}
}
/**
* 验证邮箱
*/
export function isEmailAvailable(emailInput) {
var myreg =
/^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/;
if (!myreg.test(emailInput)) {
return false;
} else {
return true;
}
}
/**
* 验证身份证
*/
export function isIDcardAvailable(idCard) {
var myreg = /^[1-9]\d{14}(\d{2}(\d|X|x))?$/;
if (!myreg.test(idCard)) {
return false;
} else {
return true;
}
}

View File

@ -36,4 +36,21 @@ export default defineConfig({
}
}
},
server: {
port: 9529,
open: false,
proxy: {
"/api": {
target: "https://hex.jipinq.cn",
changeOrigin: true,
// pathRewrite: {
// '^/api': '/'
// },
rewrite: (path) => {
console.log(path)
return path.replace(/^\/api/, "")
},
},
},
}
})