一日千里

This commit is contained in:
aiShuiJiaoDeXioShou 2024-09-19 13:57:28 +08:00
parent 7e716b5a1d
commit d508838a11
15 changed files with 427 additions and 148 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,42 @@
var __wxsModules={};
__wxsModules["2f992f8c"] = (() => {
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
// <stdin>
var require_stdin = __commonJS({
"<stdin>"(exports, module) {
var inlineTags = {
abbr: true,
b: true,
big: true,
code: true,
del: true,
em: true,
i: true,
ins: true,
label: true,
q: true,
small: true,
span: true,
strong: true,
sub: true,
sup: true
};
module.exports = {
isInline: function(tagName, style) {
return inlineTags[tagName] || (style || "").indexOf("display:inline") !== -1;
}
};
}
});
return require_stdin();
})();
__wxsModules.bca0bb86 = (() => {
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
@ -347,40 +384,3 @@ __wxsModules.bca0bb86 = (() => {
});
return require_stdin();
})();
__wxsModules["2f992f8c"] = (() => {
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
// <stdin>
var require_stdin = __commonJS({
"<stdin>"(exports, module) {
var inlineTags = {
abbr: true,
b: true,
big: true,
code: true,
del: true,
em: true,
i: true,
ins: true,
label: true,
q: true,
small: true,
span: true,
strong: true,
sub: true,
sup: true
};
module.exports = {
isInline: function(tagName, style) {
return inlineTags[tagName] || (style || "").indexOf("display:inline") !== -1;
}
};
}
});
return require_stdin();
})();

View File

@ -28,6 +28,7 @@
},
"SQLite": {},
"Payment": {},
"Webview-x5": {},
"UniNView": {
"description": "UniNView原生渲染"
}

8
env/.env vendored
View File

@ -11,8 +11,8 @@ VITE_FALLBACK_LOCALE=zh-Hans
# VITE_SERVER_BASEURL = 'http://47.99.70.12:28184/api'
# VITE_UPLOAD_BASEURL = 'http://47.99.70.12:28184'
# VITE_SERVER_BASEURL = 'http://localhost:28184/api'
# VITE_SERVER_BASEURL = 'http://localhost:48080/app-api'
VITE_SERVER_BASEURL = 'http://47.99.70.12:48080/app-api'
VITE_SERVER_BASEURL = 'http://127.0.0.1:48080/app-api'
# VITE_SERVER_BASEURL = 'http://47.99.70.12:48080/app-api'
# VITE_WS_BASEURL = 'ws://47.99.70.12:28184/api'
VITE_UPLOAD_BASEURL = 'http://localhost:28184'
VITE_OSS_BASEURL = 'http://116.204.119.171:9000/linghe'
@ -28,8 +28,8 @@ SHOPRO_VERSION = v1.8.3
SHOPRO_BASE_URL = http://api-dashboard.yudao.iocoder.cn
# 后端接口 - 测试环境(通过 process.env.NODE_ENV = development
# SHOPRO_DEV_BASE_URL = http://127.0.0.1:48080
SHOPRO_DEV_BASE_URL = http://47.99.70.12:48080
SHOPRO_DEV_BASE_URL = http://127.0.0.1:48080
# SHOPRO_DEV_BASE_URL = http://47.99.70.12:48080
### SHOPRO_DEV_BASE_URL = http://yunai.natapp1.cc
# 后端接口前缀(一般不建议调整)

View File

@ -37,11 +37,20 @@ export default defineManifestConfig({
"appkey_android" : "92219e40234c2046f50cb72a1a86e4f7"
}
},
"amap" : {
"name" : "amapCIxLx5gHo",
"appkey_ios" : "92219e40234c2046f50cb72a1a86e4f7",
"appkey_android" : "92219e40234c2046f50cb72a1a86e4f7",
"key" : "5a270020f3c6b67887c493a416ebd3ad",
"securityJsCode" : "3eabbc7e073e650ae2b1f213f8357422"
},
"maps" : {
"amap" : {
"name" : "amapCIxLx5gHo",
"appkey_ios" : "92219e40234c2046f50cb72a1a86e4f7",
"appkey_android" : "92219e40234c2046f50cb72a1a86e4f7"
"appkey_android" : "92219e40234c2046f50cb72a1a86e4f7",
"key" : "5a270020f3c6b67887c493a416ebd3ad",
"securityJsCode" : "3eabbc7e073e650ae2b1f213f8357422"
}
},
"oauth" : {},
@ -76,7 +85,8 @@ export default defineManifestConfig({
"Geolocation" : {},
"Maps" : {},
"SQLite" : {},
"Payment" : {}
"Payment" : {},
"Webview-x5" : {}
},
/* 应用发布信息 */
distribute: {

View File

@ -2,6 +2,8 @@
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
import { notificationService } from './service/notificationService'
import { ShoproInit } from './sheep'
import { useUserStore } from "@/store";
import { toPath } from "@/utils/commUtils";
onLoad(() => {
//
@ -12,9 +14,16 @@ onLoad(() => {
onLaunch(() => {
console.log('应用正在运行...')
uni.hideTabBar()
//
const userInfo = useUserStore()
notificationService.startPollingUnreadMessages()
//
ShoproInit()
if (userInfo.userInfo.token == '' || !userInfo.userInfo.token) {
//
toPath('/pages/login/index')
return
}
})
//

View File

@ -32,7 +32,8 @@
"Geolocation": {},
"Maps": {},
"SQLite": {},
"Payment": {}
"Payment": {},
"Webview-x5": {}
},
"distribute": {
"android": {
@ -187,11 +188,20 @@
"appkey_android": "92219e40234c2046f50cb72a1a86e4f7"
}
},
"amap": {
"name": "amapCIxLx5gHo",
"appkey_ios": "92219e40234c2046f50cb72a1a86e4f7",
"appkey_android": "92219e40234c2046f50cb72a1a86e4f7",
"key": "5a270020f3c6b67887c493a416ebd3ad",
"securityJsCode": "3eabbc7e073e650ae2b1f213f8357422"
},
"maps": {
"amap": {
"name": "amapCIxLx5gHo",
"appkey_ios": "92219e40234c2046f50cb72a1a86e4f7",
"appkey_android": "92219e40234c2046f50cb72a1a86e4f7"
"appkey_android": "92219e40234c2046f50cb72a1a86e4f7",
"key": "5a270020f3c6b67887c493a416ebd3ad",
"securityJsCode": "3eabbc7e073e650ae2b1f213f8357422"
}
},
"oauth": {},

View File

@ -11,7 +11,7 @@
<image :src="imgUrl('@/static/home/pb.png')" class="quick-service-image" />
<text class="quick-service-text">宠物陪伴</text>
</view>
<view class="quick-service-card" @click="toPath('/mall/index/index')">
<view class="quick-service-card" @click="toPath('/modules/mall/index/index')">
<image :src="imgUrl('@/static/home/yl.png')" class="quick-service-image" />
<text class="quick-service-text">定制商城</text>
</view>

View File

@ -39,6 +39,7 @@ import { httpGet, httpPost } from '@/utils/http'
import { useUserStore } from '@/store/user'
import TopBar from '@/components/TopBar.vue'
import { imgUrl, toast, toPath } from "@/utils/commUtils";
import sheep from "@/sheep";
const userStore = useUserStore()
@ -84,6 +85,7 @@ const login = async () => {
})
return
}
const res = await httpPost('/public/login', {}, { phone: phoneNumber.value, code: code.value })
if (res.code === 200) {
toast(res.message)
@ -94,6 +96,8 @@ const login = async () => {
expiresTime: data.expiresTime,
refreshToken: data.refreshToken
})
// token
sheep.$store("user").setToken(data.accessToken, data.refreshToken);
const userRes = await httpGet('/user/userinfo')
if (userRes.code === 200) {
userStore.setUserInfo(userRes.data)

View File

@ -0,0 +1,281 @@
<template>
<view class="order-item p-4 mb-4 bg-white shadow rounded-lg">
<!-- 订单头部,包含标题和状态 -->
<view class="order-header flex justify-between items-center mb-2">
<text v-if="serviceInfo && serviceInfo.serviceName" class="order-title font-bold text-lg">
{{ serviceInfo.serviceName }}
</text>
<text class="order-status text-sm text-gray-500">{{ state }}</text>
</view>
<!-- 服务信息 -->
<view class="order-info text-sm text-gray-700 mb-4">
<view>
<text>服务类型:</text>
<text v-if="serviceInfo && serviceInfo.type">{{ serviceInfo.type }}</text>
</view>
<view>
<text>服务地址:</text>
<text v-if="serviceInfo && serviceInfo.address">{{ serviceInfo.address }}</text>
</view>
<view>
<text>预约时间:</text>
{{ reservationTime }}
</view>
<view>
<text>服务时长:</text>
{{ serviceHours }} 小时
</view>
</view>
<!-- 宠物信息 -->
<view class="pet-info flex items-center mb-4">
<image
:src="imgUrl(pet.profileUrl)"
mode="aspectFill"
class="w-16 h-16 rounded-full mr-4"
></image>
<view>
<view>
<text>宠物名称:</text>
{{ pet.name }}
</view>
<view>
<text>宠物品种:</text>
{{ pet.breed }}
</view>
</view>
</view>
<!-- 用户信息 -->
<view class="user-info text-sm text-gray-700 mb-4">
<view>
<text>下单用户:</text>
{{ user.nickname }} ({{ user.phone }})
</view>
<view v-if="address">
<text>用户地址:</text>
{{ address.province }} {{ address.city }} {{ address.district }}
{{ address.detailAddress }}
</view>
</view>
<!-- 支付信息 -->
<view class="payment-info text-sm text-gray-700 mb-4">
<view>
<text>支付方式:</text>
{{ paymentMethod }}
</view>
<view>
<text>支付状态:</text>
{{ isPay ? '已支付' : '未支付' }}
</view>
<view>
<text>总价:</text>
¥{{ price }}
</view>
</view>
<!-- 操作按钮 -->
<view class="flex justify-between items-center">
<text class="text-lg text-red-500">¥{{ price }} 共{{ serviceHours }}小时</text>
<view class="flex">
<button v-if="!isTake" class="btn" @click="toOrderDetail">查看详情</button>
<button v-if="!isTake" class="btn ml-2" @click="cancel">取消订单</button>
<button v-if="!isTake" class="btn-primary ml-2" @click="orderPay">支付</button>
<button v-if="isTake" @click="bookingCancel">取消订单</button>
<button v-if="isTake" @click="confirm">确认订单</button>
<button
v-if="state && state.includes('已预约') && user.userInfo.isPetNursery"
@click="scan"
>
扫描二维码
</button>
</view>
</view>
</view>
</template>
<script setup>
import { payOrder } from '@/logic/pay'
import { imgUrl, scanCodeAsync, showModalAsync, toast } from '@/utils/commUtils'
import { httpPost } from '@/utils/http'
import { defineProps } from 'vue'
const props = defineProps({
id: String,
userId: String,
reservationTime: String,
serviceHours: String,
personalServiceId: String,
personalServiceUserId: String,
price: Number,
isPay: Boolean,
feedback: String,
star: Number,
state: String,
paymentMethod: String,
qrcode: String,
createTime: String,
updateTime: String,
address: Object,
pet: Object,
user: Object,
psUser: Object,
serviceInfo: Object,
isTake: false,
})
const shopRemark = ref('')
const scan = async () => {
// 扫描二维码,获取扫描信息发送给后端
const scan = await scanCodeAsync()
if (scan.result) {
try {
// 发送请求给后端
const res = await httpPost('/order/scan/' + props.id, {}, { qrcode: scan.result })
if (res.code == 200) {
toast('支付成功')
// 刷新数据
uni.$emit('refresh')
} else {
toast(res.message)
}
} catch (e) {
toast(e.data.codeStr)
}
} else {
toast('扫码失败')
}
}
const orderPay = async () => {
try {
const res = await payOrder(props.id)
if (res.code == 200) {
toast('支付成功')
} else {
toast(res.message)
}
} catch (e) {
console.log(e)
toast(e.data.codeStr)
}
}
const cancel = async () => {
const res = await httpPost('/order/cancel/' + props.id)
if (res.code == 200) {
toast('取消成功')
// 刷新数据
uni.$emit('refresh')
} else {
toast(res.message)
}
}
const toOrderDetail = () => {
uni.navigateTo({
url: `/pages/order/order-detail?id=${props.id}`,
})
}
const bookingCancel = async () => {
try {
// 弹出对话框让用户输入取消原因
const res = await showModalAsync({
title: '取消订单',
content: '',
editable: true,
placeholderText: '请输入取消原因!',
})
if (res.confirm) {
// 用户点击确定
shopRemark.value = res.content
// 进行订单取消操作
const response = await httpPost(
'/order/bookingCancel/' + props.id,
{},
{ shopRemark: shopRemark.value },
)
if (response.code == 200) {
toast('取消订单成功!')
// 刷新数据
uni.$emit('refresh')
} else {
toast(response.message)
}
} else if (res.cancel) {
// 用户点击取消
toast('取消操作已取消')
}
} catch (e) {
toast('请求失败,请稍后再试')
console.error(e)
}
}
const confirm = async () => {
try {
const res = await httpPost('/order/confirm/' + props.id)
if (res.code == 200) {
toast('确认订单成功!')
// 刷新数据
uni.$emit('refresh')
} else {
toast(res.message)
}
} catch (e) {
toast(e.data.message)
}
}
</script>
<style scoped>
.order-item {
@apply p-4 mb-4 bg-white shadow rounded-lg;
}
.order-header {
@apply flex justify-between items-center mb-2;
}
.order-title {
@apply font-bold text-lg;
}
.order-status {
@apply text-sm text-gray-500;
}
.order-info {
@apply text-sm text-gray-700 mb-4;
}
.pet-info {
@apply flex items-center mb-4;
}
.user-info {
@apply text-sm text-gray-700 mb-4;
}
.payment-info {
@apply text-sm text-gray-700 mb-4;
}
.btn {
@apply px-2 py-1 bg-gray-100 rounded text-xs;
}
.btn-primary {
@apply px-2 py-1 bg-[#ffc107] text-white rounded text-xs;
}
.text-red-500 {
@apply text-red-500;
}
</style>

View File

@ -1,84 +1,28 @@
<template>
<view class="order-item p-4 mb-4 bg-white shadow rounded-lg">
<!-- 订单头部包含标题和状态 -->
<view class="order-header flex justify-between items-center mb-2">
<text v-if="serviceInfo && serviceInfo.serviceName" class="order-title font-bold text-lg">
{{ serviceInfo.serviceName }}
</text>
<text class="order-status text-sm text-gray-500">{{ state }}</text>
</view>
<!-- 服务信息 -->
<view class="order-info text-sm text-gray-700 mb-4">
<view>
<text>服务类型:</text>
<text v-if="serviceInfo && serviceInfo.type">{{ serviceInfo.type }}</text>
</view>
<view>
<text>服务地址:</text>
<text v-if="serviceInfo && serviceInfo.address">{{ serviceInfo.address }}</text>
</view>
<view>
<text>预约时间:</text>
{{ reservationTime }}
</view>
<view>
<text>服务时长:</text>
{{ serviceHours }} 小时
</view>
</view>
<!-- 宠物信息 -->
<view class="pet-info flex items-center mb-4">
<image
:src="imgUrl(pet.profileUrl)"
mode="aspectFill"
class="w-16 h-16 rounded-full mr-4"
></image>
<view>
<view>
<text>宠物名称:</text>
{{ pet.name }}
<view class="order-header flex mb-2 gap-2">
<image class="rounded-2 w-[44vw] mt--2" :src="imgUrl(serviceInfo.url)" mode="widthFix" />
<view class="flex flex-col gap-3">
<view class="flex gap-2 w-full justify-between items-center">
<view v-if="serviceInfo && serviceInfo.serviceName" class="order-title font-bold text-lg">
{{ serviceInfo.serviceName }}
</view>
<view
class="content-center w-[50px] h-[20px] bg-[#ffc107] text-black rounded-1 text-center items-center"
>
<view class="text-size-[12px]">{{ state }}</view>
</view>
</view>
<view>{{ serviceInfo.description }}</view>
<view>
<text>宠物品种:</text>
{{ pet.breed }}
<text>总价:</text>
¥{{ price }}
</view>
</view>
</view>
<!-- 用户信息 -->
<view class="user-info text-sm text-gray-700 mb-4">
<view>
<text>下单用户:</text>
{{ user.nickname }} ({{ user.phone }})
</view>
<view v-if="address">
<text>用户地址:</text>
{{ address.province }} {{ address.city }} {{ address.district }}
{{ address.detailAddress }}
</view>
</view>
<!-- 支付信息 -->
<view class="payment-info text-sm text-gray-700 mb-4">
<view>
<text>支付方式:</text>
{{ paymentMethod }}
</view>
<view>
<text>支付状态:</text>
{{ isPay ? '已支付' : '未支付' }}
</view>
<view>
<text>总价:</text>
¥{{ price }}
</view>
</view>
<!-- 操作按钮 -->
<view class="flex justify-between items-center">
<text class="text-lg text-red-500">¥{{ price }} {{ serviceHours }}小时</text>
<view class="flex items-center flex-content-end flex-row-reverse">
<view class="flex">
<button v-if="!isTake" class="btn" @click="toOrderDetail">查看详情</button>
<button v-if="!isTake" class="btn ml-2" @click="cancel">取消订单</button>
@ -268,11 +212,11 @@ const confirm = async () => {
}
.btn {
@apply px-2 py-1 bg-gray-100 rounded text-xs;
@apply px-2 py-1 bg-gray-100 rounded text-xs w-[25vw] text-size-[15px] py-5px rounded-36;
}
.btn-primary {
@apply px-2 py-1 bg-[#ffc107] text-white rounded text-xs;
@apply px-2 py-1 bg-[#ffc107] text-black text-xs text-center w-[25vw] text-size-[15px] py-5px rounded-36;
}
.text-red-500 {

View File

@ -12,11 +12,7 @@
<view class="bg-[#F5F5F5] h-[135vh]">
<!-- 顶部背景和头像 -->
<view class="relative">
<image
:src="serviceData.bgUrl"
class="w-full h-40 object-cover"
mode="widthFix"
></image>
<image :src="serviceData.bgUrl" class="w-full h-40 object-cover" mode="widthFix"></image>
<view class="absolute left-4 bottom-[-20px]">
<image
:src="serviceData.userAvatar"
@ -105,6 +101,7 @@
<text class="text-lg font-bold mb-2 w-full pl-[20px]" style="text-align: left">服务位置</text>
<view class="w-full h-[20vh]">
<Map
v-show="mapShow"
:locationName="'服务位置'"
:initialLatitude="serviceData.latitude"
:initialLongitude="serviceData.longitude"
@ -113,18 +110,13 @@
</view>
<!-- 底部操作栏 -->
<view
class="fixed bottom-0 w-full bg-white flex justify-between items-center mt-4 z-10 py-3"
>
<view class="fixed bottom-0 w-full bg-white flex justify-between items-center mt-4 z-10 py-3">
<text class="text-red-500 text-lg">¥{{ serviceData.price }}/ </text>
<view class="flex space-x-4 pr-10px">
<button @click="message" class="bg-gray-200 text-gray-600 rounded-full w-100px">
消息
</button>
<button
class="bg-[#ffc107] text-white rounded-full"
@click="openReservationModal"
>
<button class="bg-[#ffc107] text-white rounded-full" @click="openReservationModal">
预约宠托师
</button>
</view>
@ -146,10 +138,7 @@
@click="selectPet(pet.id)"
:class="selectedPetId == pet.id ? 'border-4 border-[#ffc107] color-[#ffc107]' : ''"
>
<image
:src="imgUrl(pet.profileUrl)"
class="w-20 h-20 rounded-full object-cover"
></image>
<image :src="imgUrl(pet.profileUrl)" class="w-20 h-20 rounded-full object-cover"></image>
<text class="text-sm">{{ pet.name }}</text>
</view>
</view>
@ -216,7 +205,7 @@
<script lang="js" setup>
import { ref } from 'vue'
import { httpGet } from '@/utils/http'
import { baseUrl, imgUrl, toast, toPath } from "@/utils/commUtils";
import { baseUrl, imgUrl, toast, toPath } from '@/utils/commUtils'
import { pay } from '@/logic/pay'
import TopBar from '@/components/TopBar.vue'
import Map from '@/components/Map.vue'
@ -239,6 +228,7 @@ const weekFromToday = ref('')
const personalServiceId = ref('')
const hours = ref(1)
const selectedAddress = ref({})
const mapShow = ref(true)
const hoursHandleChange = ({ value }) => {
if (value >= 1 && value <= 12) {
@ -288,11 +278,13 @@ const handleAddressChange = (e) => {
//
const openReservationModal = () => {
showReservationModal.value = true
mapShow.value = false
}
//
const closeReservationModal = () => {
showReservationModal.value = false
mapShow.value = true
}
//
@ -313,6 +305,16 @@ const confirmReservation = async () => {
//
onLoad(async (options) => {
loading.value = true
mapShow.value = false
//
setTimeout(() => {
if (!loading.value && mapShow.value) {
loading.value = false
mapShow.value = true
}
}, 5000)
try {
if (!options.id) {
toast('该服务不存在!')
@ -358,6 +360,7 @@ onLoad(async (options) => {
}
loading.value = false
mapShow.value = true
})
</script>

View File

@ -1,4 +1,3 @@
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist-uni'
// 自动注入所有pinia模块

View File

@ -19,7 +19,7 @@ const initState = {
}
export const useUserStore = defineStore(
'user',
'acdrUser',
() => {
const userInfo = ref({ ...initState })

View File

@ -17,6 +17,7 @@ import UnoCSS from 'unocss/vite'
import AutoImport from 'unplugin-auto-import/vite'
import { visualizer } from 'rollup-plugin-visualizer'
import ViteRestart from 'vite-plugin-restart'
// @ts-ignore
import uniReadPagesV3Plugin from './src/sheep/router/utils/uni-read-pages-v3'
import mpliveMainfestPlugin from './src/sheep/libs/mplive-manifest-plugin'