宠物详情页面更新,优化了这个页面的动画效果,新增小刷新动画
This commit is contained in:
parent
10335b8b2c
commit
7638324bb9
16
.idea/addr.iml
Normal file
16
.idea/addr.iml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_FOLDERS">
|
||||
<list>
|
||||
<option value="$MODULE_DIR$/acdr-ui/node_modules/conventional-changelog-angular/templates" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</module>
|
7
.idea/codeStyles/Project.xml
Normal file
7
.idea/codeStyles/Project.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<ScalaCodeStyleSettings>
|
||||
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
|
||||
</ScalaCodeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
@ -2,7 +2,7 @@
|
||||
<view
|
||||
:class="[
|
||||
'pos-fixed z-999 left-[1px] flex gap-[5px] items-center content-center justify-center',
|
||||
isH5 ? 'top-[20px]' : 'top-[40px]',
|
||||
isH5 ? 'top-[3vw]' : 'top-[6vw]',
|
||||
]"
|
||||
>
|
||||
<image src="/static/addresscell/location.png" class="w-[30px]" mode="widthFix" />
|
||||
|
@ -1,10 +1,6 @@
|
||||
<template>
|
||||
<view
|
||||
class="loading-overlay"
|
||||
:catchtouchmove="modelValue"
|
||||
@click.stop="stopEvent"
|
||||
v-if="modelValue"
|
||||
>
|
||||
<wd-overlay :show="modelValue">
|
||||
<view class="flex flex-col items-center justify-center content-center w-full h-full">
|
||||
<view class="loading-animation">
|
||||
<view
|
||||
v-for="color in colors"
|
||||
@ -14,53 +10,53 @@
|
||||
></view>
|
||||
</view>
|
||||
</view>
|
||||
</wd-overlay>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, watchEffect } from 'vue'
|
||||
import { defineProps } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Boolean,
|
||||
timeout: {
|
||||
// 添加timeout属性来控制加载时间
|
||||
type: Number,
|
||||
default: 5000, // 默认5秒后自动关闭
|
||||
},
|
||||
})
|
||||
|
||||
const stopEvent = (event) => {
|
||||
event.preventDefault() // 阻止默认行为
|
||||
event.stopPropagation() // 阻止事件冒泡
|
||||
}
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const preventTouchMove = (event) => {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
// H5和APP端清除点击事件
|
||||
// #ifdef H5 || APP-PLUS
|
||||
watchEffect(() => {
|
||||
if (props.modelValue) {
|
||||
document.addEventListener('touchmove', preventTouchMove, { passive: false })
|
||||
} else {
|
||||
document.removeEventListener('touchmove', preventTouchMove)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
let timer = null
|
||||
|
||||
const colors = ['#FF6347', '#4682B4', '#32CD32', '#FFD700', '#FF69B4', '#00FA9A']
|
||||
|
||||
// 定时器函数,超过指定时间自动关闭加载界面
|
||||
const startTimeout = () => {
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
stopLoading() // 超时后关闭加载
|
||||
}, props.timeout)
|
||||
}
|
||||
|
||||
const stopLoading = () => {
|
||||
// 触发关闭加载的逻辑,可以通过 emit 事件或者父组件控制
|
||||
clearTimeout(timer)
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
// 开始加载时启动定时器
|
||||
startTimeout()
|
||||
})
|
||||
|
||||
onUnload(() => {
|
||||
// 清理定时器,防止内存泄漏
|
||||
clearTimeout(timer)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
pointer-events: auto; /* 添加这行代码 */
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.loading-animation {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
|
68
acdr-ui/src/components/LocalLoader.vue
Normal file
68
acdr-ui/src/components/LocalLoader.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<view class="w-full h-[20px] flex flex-col items-center" v-if="modelValue">
|
||||
<view class="loading-animation">
|
||||
<view
|
||||
v-for="color in colors"
|
||||
:key="color"
|
||||
:style="{ backgroundColor: color }"
|
||||
class="ball"
|
||||
></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Boolean,
|
||||
})
|
||||
|
||||
const colors = ['#FF6347', '#4682B4', '#32CD32', '#FFD700', '#FF69B4', '#00FA9A']
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.loading-animation {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
justify-content: space-around;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.ball {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 50%;
|
||||
animation: bounce 1.2s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.ball:nth-child(1) {
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
.ball:nth-child(2) {
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
.ball:nth-child(3) {
|
||||
animation-delay: -0.13s;
|
||||
}
|
||||
.ball:nth-child(4) {
|
||||
animation-delay: -0.07s;
|
||||
}
|
||||
.ball:nth-child(5) {
|
||||
animation-delay: -0.04s;
|
||||
}
|
||||
.ball:nth-child(6) {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
transform: scale(0);
|
||||
}
|
||||
40% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -94,7 +94,7 @@ const clickmap = () => {
|
||||
|
||||
// 获取自己的地理位置
|
||||
const getLocation = () => {
|
||||
uni.showLoading({ title: '正在获取定位' })
|
||||
// uni.showLoading({ title: '正在获取定位' })
|
||||
uni.getLocation({
|
||||
type: 'gcj02',
|
||||
timeout: 1000,
|
||||
@ -114,7 +114,7 @@ const getLocation = () => {
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log(err)
|
||||
uni.hideLoading()
|
||||
// uni.hideLoading()
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '位置信息获取失败(请确定定位功能是否打开)',
|
||||
|
@ -11,7 +11,8 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<EmptyState v-else />
|
||||
<LocalLoader v-model="loading" />
|
||||
<EmptyState v-if="services.length == 0 && !loading" />
|
||||
</template>
|
||||
|
||||
<script lang="js" setup>
|
||||
@ -21,12 +22,14 @@ import { imgUrl } from '@/utils/commUtils'
|
||||
import { getNearbyServices } from '@/service/personalService'
|
||||
import { getLocation } from '@/service/mapService'
|
||||
import EmptyState from '@/components/EmptyState.vue'
|
||||
import LocalLoader from '@/components/LocalLoader.vue'
|
||||
|
||||
const toDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/service/detail?id=' + item.id,
|
||||
})
|
||||
}
|
||||
const loading = ref(false)
|
||||
|
||||
const services = ref([])
|
||||
|
||||
@ -39,7 +42,9 @@ const getQuickServices = async () => {
|
||||
}
|
||||
|
||||
onLoad(async () => {
|
||||
loading.value = true
|
||||
await getQuickServices()
|
||||
loading.value = false
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
<Banner />
|
||||
<AddressCell />
|
||||
<!-- 这里放搜索框 -->
|
||||
<view class="w-[70vw] pos-absolute top-[3vw] right-0">
|
||||
<view :class="['w-[70vw] pos-absolute right-0', isH5 ? 'top-[1vw]' : 'top-[3vw]']">
|
||||
<Search />
|
||||
</view>
|
||||
<loading-animation v-model="isLoading" />
|
||||
@ -86,6 +86,7 @@ import { httpGet } from '@/utils/http'
|
||||
import Tabbar from '@/components/Tabbar.vue'
|
||||
import AddressCell from '@/components/AddressCell.vue'
|
||||
import Search from '@/components/Search.vue'
|
||||
import { isH5 } from '@/utils/platform'
|
||||
|
||||
const isLoading = ref(false)
|
||||
const petInfo = ref({})
|
||||
|
@ -30,8 +30,8 @@
|
||||
<view class="bg-white p-4">
|
||||
<text class="text-2xl font-bold">{{ serviceData.userName }}</text>
|
||||
<view class="flex items-center mt-2">
|
||||
<text class="text-sm text-gray-500 mr-2">认证1年10个月</text>
|
||||
<text class="text-sm text-gray-500">服务过200+次</text>
|
||||
<text class="text-sm text-gray-500 mr-2">认证{{ serviceData.certificationTime }}</text>
|
||||
<text class="text-sm text-gray-500">服务过 {{ serviceData.serviceNumber }} 次</text>
|
||||
</view>
|
||||
<view class="flex items-center mt-2">
|
||||
<wd-icon name="location" size="20" class="text-[#ffc107]"></wd-icon>
|
||||
@ -82,20 +82,22 @@
|
||||
<!-- 用户评价 -->
|
||||
<view class="bg-white p-4">
|
||||
<text class="text-lg font-bold mb-2">用户评价</text>
|
||||
<view class="mb-4">
|
||||
<view class="mb-4" v-if="serviceData.comment">
|
||||
<view class="flex items-center mb-2">
|
||||
<text class="text-pink-500 text-lg">5.0</text>
|
||||
<text class="text-pink-500 text-lg">{{ serviceData.comment.star }}</text>
|
||||
<view class="flex items-center ml-2">
|
||||
<wd-icon name="star-on" size="20" class="text-[#ffc107]"></wd-icon>
|
||||
<wd-icon name="star-on" size="20" class="text-[#ffc107]"></wd-icon>
|
||||
<wd-icon name="star-on" size="20" class="text-[#ffc107]"></wd-icon>
|
||||
<wd-icon name="star-on" size="20" class="text-[#ffc107]"></wd-icon>
|
||||
<wd-icon name="star-on" size="20" class="text-[#ffc107]"></wd-icon>
|
||||
<wd-icon
|
||||
v-for="num in serviceData.comment.star"
|
||||
name="star-on"
|
||||
size="20"
|
||||
class="text-[#ffc107]"
|
||||
></wd-icon>
|
||||
</view>
|
||||
<text class="text-gray-500 ml-2">(14条评论)</text>
|
||||
<text class="text-gray-500 ml-2">({{ serviceData.comment.commentNum }}条评论)</text>
|
||||
</view>
|
||||
<text class="text-gray-600">阿落超级细心!!下次一定还找阿落!!超级安心!</text>
|
||||
<text class="text-gray-600">{{ serviceData.comment.comment }}</text>
|
||||
</view>
|
||||
<view class="text-gray-500 pt-2 w-full text-center" v-else>暂无评论</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部地图展示 -->
|
||||
@ -132,14 +134,14 @@
|
||||
<!-- 预约弹窗 -->
|
||||
<view
|
||||
v-if="showReservationModal"
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"
|
||||
class="z-999 fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"
|
||||
>
|
||||
<view class="bg-white rounded-lg p-4 w-11/12">
|
||||
<view class="text-lg font-bold mb-4">选择预约信息</view>
|
||||
|
||||
<!-- 服务宠物选择 -->
|
||||
<text class="text-sm text-gray-500 mb-2">服务宠物</text>
|
||||
<view class="flex space-x-4 mb-4 scroll-x overflow-x-auto" scroll-x>
|
||||
<view v-if="pets.length > 0" class="flex space-x-4 mb-4 scroll-x overflow-x-auto" scroll-x>
|
||||
<view
|
||||
v-for="pet in pets"
|
||||
:key="pet.id"
|
||||
@ -154,6 +156,11 @@
|
||||
<text class="text-sm">{{ pet.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="pet-item add-pet" @click="toPath('/pages/pet/pet-add-page')">
|
||||
<w-avatar :size="80" class="pet-avatar add-avatar">
|
||||
<view class="add-icon">+</view>
|
||||
</w-avatar>
|
||||
</view>
|
||||
|
||||
<!-- 预约时间 -->
|
||||
<text class="text-sm text-gray-500 mb-2">预约时间</text>
|
||||
@ -180,7 +187,11 @@
|
||||
{{ selectedAddress.display || '请选择地址' }}
|
||||
</view>
|
||||
</picker>
|
||||
<view v-else>请选择地址</view>
|
||||
<view v-else class="pet-item add-pet" @click="toPath('/pages/address/index')">
|
||||
<w-avatar :size="80" class="pet-avatar add-avatar">
|
||||
<view class="add-icon">+</view>
|
||||
</w-avatar>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="fixed bottom-0 left-0 w-full p-4 bg-white shadow-up">
|
||||
@ -201,15 +212,18 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<LoadingAnimation v-model="loading" />
|
||||
</template>
|
||||
|
||||
<script lang="js" setup>
|
||||
import { ref } from 'vue'
|
||||
import { httpGet } from '@/utils/http'
|
||||
import { baseUrl, toast } from '@/utils/commUtils'
|
||||
import { baseUrl, toast, toPath } from '@/utils/commUtils'
|
||||
import { pay } from '@/logic/pay'
|
||||
import TopBar from '@/components/TopBar.vue'
|
||||
import Map from '@/components/Map.vue'
|
||||
import LoadingAnimation from '@/components/LoadingAnimation.vue'
|
||||
|
||||
// 获取当前日期
|
||||
const nowday = new Date()
|
||||
@ -217,7 +231,7 @@ const year = nowday.getFullYear()
|
||||
const month = (nowday.getMonth() + 1).toString().padStart(2, '0') // 月份从0开始,需加1
|
||||
const day = nowday.getDate().toString().padStart(2, '0')
|
||||
const reservationDate = ref(`${year}-${month}-${day}`)
|
||||
|
||||
const loading = ref(false)
|
||||
const serviceData = ref({})
|
||||
const pets = ref([])
|
||||
const addressList = ref([])
|
||||
@ -264,12 +278,12 @@ const setDateRange = () => {
|
||||
weekFromToday.value = weekLater.toISOString().split('T')[0]
|
||||
}
|
||||
|
||||
// Handle the date change event
|
||||
// 选择时间
|
||||
const handleDateChange = (e) => {
|
||||
reservationDate.value = e.detail.value
|
||||
}
|
||||
|
||||
// Handle the address change event
|
||||
// 选择地址
|
||||
const handleAddressChange = (e) => {
|
||||
selectedAddress.value = addressList.value[e.detail.value]
|
||||
}
|
||||
@ -301,6 +315,8 @@ const confirmReservation = async () => {
|
||||
|
||||
// 页面加载时获取服务详情数据、宠物信息和地址信息并初始化地图
|
||||
onLoad(async (options) => {
|
||||
loading.value = true
|
||||
try {
|
||||
if (!options.id) {
|
||||
toast('该服务不存在!')
|
||||
// 返回到上一级页面
|
||||
@ -316,16 +332,16 @@ onLoad(async (options) => {
|
||||
if (serviceResponse.code === 200) {
|
||||
serviceData.value = serviceResponse.data
|
||||
} else {
|
||||
uni.showToast({ title: '加载服务数据失败', icon: 'none' })
|
||||
toast(serviceResponse.message)
|
||||
}
|
||||
|
||||
// 获取宠物信息
|
||||
const petsResponse = await httpGet('/petInfo/my')
|
||||
if (petsResponse.code === 200) {
|
||||
pets.value = petsResponse.data
|
||||
selectedPetId.value = pets.value[0].id
|
||||
if (pets.value.length !== 0) selectedPetId.value = pets.value[0].id
|
||||
} else {
|
||||
uni.showToast({ title: '加载宠物数据失败', icon: 'none' })
|
||||
toast(petsResponse.message)
|
||||
}
|
||||
|
||||
// 获取地址信息
|
||||
@ -337,12 +353,47 @@ onLoad(async (options) => {
|
||||
})
|
||||
selectedAddress.value = addressList.value[0]
|
||||
} else {
|
||||
uni.showToast({ title: '加载地址数据失败', icon: 'none' })
|
||||
toast(addressResponse.message)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
toast('获取服务详情失败!')
|
||||
}
|
||||
|
||||
loading.value = false
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.pet-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.pet-avatar {
|
||||
border: 2px solid #fcd038;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.add-avatar {
|
||||
width: 102rpx;
|
||||
height: 102rpx;
|
||||
background-color: #fff;
|
||||
border: 2px dashed #fcd038;
|
||||
}
|
||||
|
||||
.pet-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
font-size: 36px;
|
||||
line-height: 45px;
|
||||
color: #fcd038;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.options {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
|
@ -94,4 +94,5 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
return this.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -7,10 +7,15 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.yskj.acdr.common.response.GlobalResponse;
|
||||
import com.yskj.acdr.master.address.service.ServiceAddressService;
|
||||
import com.yskj.acdr.master.order.entity.Order;
|
||||
import com.yskj.acdr.master.order.orderenum.OrderState;
|
||||
import com.yskj.acdr.master.order.service.OrderService;
|
||||
import com.yskj.acdr.master.personal.entity.PersonalService;
|
||||
import com.yskj.acdr.master.personal.service.PersonalServiceService;
|
||||
import com.yskj.acdr.master.pet.entity.PetInfo;
|
||||
import com.yskj.acdr.master.pet.entity.PetSpecialistCertificate;
|
||||
import com.yskj.acdr.master.pet.service.PetInfoService;
|
||||
import com.yskj.acdr.master.pet.service.PetSpecialistCertificateService;
|
||||
import com.yskj.acdr.master.user.entity.Users;
|
||||
import com.yskj.acdr.master.user.service.UsersService;
|
||||
import io.swagger.annotations.*;
|
||||
@ -21,6 +26,9 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -51,6 +59,12 @@ public class PersonalServiceController {
|
||||
@Resource
|
||||
private ServiceAddressService mapService;
|
||||
|
||||
@Resource
|
||||
private PetSpecialistCertificateService pscs;
|
||||
|
||||
@Resource
|
||||
private OrderService orderService;
|
||||
|
||||
|
||||
@PostMapping("/push")
|
||||
public GlobalResponse<Boolean> push(
|
||||
@ -140,6 +154,30 @@ public class PersonalServiceController {
|
||||
* @param id 查询服务id
|
||||
* @author linghe
|
||||
* 展示宠物个人服务详细信息
|
||||
* 返回如下数据:
|
||||
* // 将这些数据都打散装配到Map当中
|
||||
* var map = MapUtil.<String, Object>builder()
|
||||
* .put("serviceId", p.getId())
|
||||
* .put("serviceName", p.getServiceName())
|
||||
* .put("bgUrl", p.getUrl())
|
||||
* .put("description", p.getDescription())
|
||||
* .put("serviceType", p.getType())
|
||||
* .put("latitude", p.getLatitude())
|
||||
* .put("longitude", p.getLongitude())
|
||||
* .put("address", p.getAddress())
|
||||
* .put("serviceState", p.getState())
|
||||
* .put("createTime", p.getCreateTime())
|
||||
* .put("updateTime", p.getUpdateTime())
|
||||
* .put("price", p.getPrice())
|
||||
* .put("serviceUserId", p.getUserId()) // 服务者ID
|
||||
* .put("userName", user.getNickname())
|
||||
* .put("userAvatar", user.getAvatar())
|
||||
* .put("pets", pets)
|
||||
* // 添加认证时间
|
||||
* .put("certificationTime", calculateTimeDifference(LocalDateTime.now(), psc.getCreateTime()))
|
||||
* .put("serviceNumber", psc.getServiceNumber())
|
||||
* .put("comments", comments)
|
||||
* .map();
|
||||
*/
|
||||
@GetMapping("/service/{id}")
|
||||
public GlobalResponse<Map<String, Object>> personalDetail(@PathVariable Long id) {
|
||||
@ -160,6 +198,49 @@ public class PersonalServiceController {
|
||||
"profileUrl", petInfo.getProfileUrl()))
|
||||
.toList();
|
||||
|
||||
// 获取该宠托师其他信息(服务次数、认证年龄)
|
||||
PetSpecialistCertificate psc = pscs.getOne(new LambdaQueryWrapper<PetSpecialistCertificate>()
|
||||
.eq(PetSpecialistCertificate::getUserId, userId)
|
||||
// 小于过期时间
|
||||
.gt(PetSpecialistCertificate::getExpiredTime, LocalDateTime.now()));
|
||||
if (psc == null) {
|
||||
return GlobalResponse.failure("该用户没有宠物师证书,或者宠物师证书被吊销!");
|
||||
}
|
||||
|
||||
// 获取该宠托师以往的订单评论信息, 只获取历史数据的前一条
|
||||
// 获取服务次数
|
||||
long commitNums = orderService.count(new LambdaQueryWrapper<Order>()
|
||||
.eq(Order::getPersonalServiceUserId, userId)
|
||||
.eq(Order::getState, OrderState.EVALUATED)
|
||||
.isNotNull(Order::getFeedback)
|
||||
.isNotNull(Order::getStar));
|
||||
|
||||
// 获取之后获取该用户的评论信息
|
||||
Order commentsOrder = null;
|
||||
if(commitNums > 0) {
|
||||
commentsOrder = orderService.lambdaQuery()
|
||||
.eq(Order::getPersonalServiceUserId, userId)
|
||||
.eq(Order::getState, OrderState.EVALUATED)
|
||||
.isNotNull(Order::getFeedback)
|
||||
.isNotNull(Order::getStar)
|
||||
.orderByDesc(Order::getStar)
|
||||
.orderByDesc(Order::getCreateTime)
|
||||
.last("LIMIT 1")
|
||||
.one();
|
||||
}
|
||||
|
||||
Map<String, Object> comments = null;
|
||||
if (commentsOrder != null) {
|
||||
comments = new HashMap<>();
|
||||
Users users = usersService.getById(commentsOrder.getUserId());
|
||||
comments.put("star", commentsOrder.getStar());
|
||||
comments.put("comment", commentsOrder.getFeedback());
|
||||
comments.put("commentNum", commitNums);
|
||||
comments.put("userName", users.getNickname());
|
||||
comments.put("userAvatar", users.getAvatar());
|
||||
}
|
||||
|
||||
|
||||
// 将这些数据都打散装配到Map当中
|
||||
var map = MapUtil.<String, Object>builder()
|
||||
.put("serviceId", p.getId())
|
||||
@ -175,14 +256,43 @@ public class PersonalServiceController {
|
||||
.put("updateTime", p.getUpdateTime())
|
||||
.put("price", p.getPrice())
|
||||
.put("serviceUserId", p.getUserId()) // 服务者ID
|
||||
.put("userName", user.getName())
|
||||
.put("userName", user.getNickname())
|
||||
.put("userAvatar", user.getAvatar())
|
||||
.put("pets", pets)
|
||||
// 添加认证时间
|
||||
.put("certificationTime", calculateTimeDifference(LocalDateTime.now(), psc.getCreateTime()))
|
||||
.put("serviceNumber", psc.getServiceNumber())
|
||||
.put("comments", comments)
|
||||
.map();
|
||||
|
||||
return GlobalResponse.success(map);
|
||||
}
|
||||
|
||||
public static String calculateTimeDifference(LocalDateTime startDate, LocalDateTime endDate) {
|
||||
// 计算年差
|
||||
long years = ChronoUnit.YEARS.between(startDate, endDate);
|
||||
LocalDateTime tempDateTime = startDate.plusYears(years);
|
||||
|
||||
// 计算月差
|
||||
long months = ChronoUnit.MONTHS.between(tempDateTime, endDate);
|
||||
tempDateTime = tempDateTime.plusMonths(months);
|
||||
|
||||
// 计算天差
|
||||
long days = ChronoUnit.DAYS.between(tempDateTime, endDate);
|
||||
|
||||
// 如果天数小于一个月,按一个月计算
|
||||
if (days >= 0 && days < 30) {
|
||||
months++;
|
||||
}
|
||||
|
||||
if (years == 0) {
|
||||
return months + "个月";
|
||||
}
|
||||
|
||||
// 返回 xx年xx月 格式
|
||||
return years + "年" + months + "个月";
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户的位置获取附近服务的位置。
|
||||
*
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.yskj.acdr.master.pet.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@ -162,6 +163,7 @@ public class PetController {
|
||||
public GlobalResponse<PetInfo> index() {
|
||||
List<PetInfo> one = petInfoService.list(new LambdaQueryWrapper<PetInfo>()
|
||||
.eq(PetInfo::getUserId, StpUtil.getLoginIdAsLong()));
|
||||
if (one == null || one.isEmpty()) return GlobalResponse.success();
|
||||
return GlobalResponse.success(one.getFirst());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user