Browse Source

feat(地址管理): 新增地址经纬度字段并完善位置信息校验

- 在地址信息模型中添加latitude、longitude和selectAddress字段
- 地址选择和使用时增加经纬度校验逻辑
- 优化地址显示格式,使用拼接后的selectAddress字段
- 当地址缺少位置信息时提示用户完善

refactor(订单服务): 重构服务项目显示逻辑

- 按服务日期分组显示服务项目
- 优化服务项目列表的UI样式
- 添加服务天数统计显示
- 简化服务项目名称显示逻辑

style(宠物服务): 调整宠物服务卡片样式

- 增加卡片背景和圆角
- 调整宠物头像尺寸
- 优化布局和间距
master
前端-胡立永 1 month ago
parent
commit
f162317742
7 changed files with 236 additions and 104 deletions
  1. +16
    -4
      pages/newOrder/address.vue
  2. +20
    -0
      pages/newOrder/addressList.vue
  3. +8
    -0
      pages/personalCenter/addressInfo.vue
  4. +90
    -48
      pages_order/components/order/ServiceItems.vue
  5. +23
    -3
      pages_order/components/order/ServicePets.vue
  6. +68
    -46
      pages_order/order/orderDetail.vue
  7. +11
    -3
      pages_order/order/orderList.vue

+ 16
- 4
pages/newOrder/address.vue View File

@ -28,7 +28,7 @@
<u-form-item label="所在地区" prop="addressInfo.city" labelWidth="120" borderBottom> <u-form-item label="所在地区" prop="addressInfo.city" labelWidth="120" borderBottom>
<view style="display: flex;justify-content: space-between;" @click="selectAddress"> <view style="display: flex;justify-content: space-between;" @click="selectAddress">
<u--input :value="addressInfo.city"
<u--input :value="addressInfo.selectAddress"
disabled disabledColor="#ffffff" placeholder="请选择所在地区" disabled disabledColor="#ffffff" placeholder="请选择所在地区"
placeholderStyle="text-align:right;color:#AAA" border="none" inputAlign="right"> placeholderStyle="text-align:right;color:#AAA" border="none" inputAlign="right">
</u--input> </u--input>
@ -75,7 +75,10 @@
district:'', district:'',
detailAddress:"", detailAddress:"",
openId:"", openId:"",
isDefault:0
isDefault:0,
latitude:"",
longitude:"",
selectAddress:""
}, },
multiArray: [], multiArray: [],
cityList:[], cityList:[],
@ -106,7 +109,9 @@
district, district,
detailAddress, detailAddress,
openId, openId,
isDefault
isDefault,
latitude,
longitude,
} = res; } = res;
this.addressInfo = { this.addressInfo = {
name, name,
@ -117,7 +122,10 @@
district, district,
detailAddress, detailAddress,
openId, openId,
isDefault
isDefault,
latitude,
longitude,
selectAddress: `${province}${city}${district}`,
}; };
}else{ }else{
this.$modal.showToast('获取地址详情失败') this.$modal.showToast('获取地址详情失败')
@ -187,6 +195,8 @@
city:params.city, city:params.city,
district:params.district, district:params.district,
detailAddress:params.detailAddress, detailAddress:params.detailAddress,
latitude:params.latitude,
longitude:params.longitude,
} }
this.loading=false this.loading=false
uni.redirectTo({ uni.redirectTo({
@ -208,6 +218,8 @@
city:params.city, city:params.city,
district:params.district, district:params.district,
detailAddress:params.detailAddress, detailAddress:params.detailAddress,
latitude:params.latitude,
longitude:params.longitude,
} }
this.loading=false this.loading=false
uni.redirectTo({ uni.redirectTo({


+ 20
- 0
pages/newOrder/addressList.vue View File

@ -123,6 +123,24 @@
this.deleteId=''; this.deleteId='';
}, },
useAddress(params){ useAddress(params){
//
if(!params.latitude || !params.longitude) {
uni.showModal({
title: '提示',
content: '该地址缺少位置信息,请先编辑地址完善位置信息',
showCancel: true,
cancelText: '取消',
confirmText: '去编辑',
success: (res) => {
if (res.confirm) {
//
this.editAddress(params);
}
}
});
return;
}
this.$globalData.newOrderData.currentAddress={ this.$globalData.newOrderData.currentAddress={
id:params.id, id:params.id,
name:params.name, name:params.name,
@ -130,6 +148,8 @@
province:params.province, province:params.province,
city:params.city, city:params.city,
detailAddress:params.detailAddress, detailAddress:params.detailAddress,
latitude:params.latitude,
longitude:params.longitude,
} }
let len = getCurrentPages().length; let len = getCurrentPages().length;
this.loading=false this.loading=false


+ 8
- 0
pages/personalCenter/addressInfo.vue View File

@ -75,6 +75,9 @@
detailAddress:"", detailAddress:"",
openId:"", openId:"",
isDefault:0, isDefault:0,
latitude:"",
longitude:"",
selectAddress:""
}, },
multiArray: [], multiArray: [],
cityList:[], cityList:[],
@ -106,6 +109,8 @@
detailAddress, detailAddress,
openId, openId,
isDefault, isDefault,
latitude,
longitude,
} = res; } = res;
this.addressInfo = { this.addressInfo = {
name, name,
@ -117,6 +122,9 @@
detailAddress, detailAddress,
openId, openId,
isDefault, isDefault,
latitude,
longitude,
selectAddress: `${province}${city}${district}`,
}; };
}else{ }else{
this.$modal.showToast('获取地址详情失败') this.$modal.showToast('获取地址详情失败')


+ 90
- 48
pages_order/components/order/ServiceItems.vue View File

@ -8,12 +8,18 @@
<view class="service-items-list"> <view class="service-items-list">
<view class="service-item" v-for="(item, index) in items" :key="index"> <view class="service-item" v-for="(item, index) in items" :key="index">
<view class="item-header"> <view class="item-header">
<view class="item-id">{{item.id}}</view>
<view class="item-name">{{item.name}}</view>
<view class="item-id">{{item.day}}</view>
<text style="margin: 0 10rpx;">|</text>
<view class="item-name">
<text>{{ item.itemsText[0] }}</text>
<text v-if="item.itemsText.length >= 2">
{{ item.itemsText[0] }}+{{ item.itemsText[item.itemsText.length - 1] }}{{ item.itemsText.length }}
</text>
</view>
<view class="item-price-action"> <view class="item-price-action">
<view class="item-price">¥{{item.price.toFixed(2)}}</view> <view class="item-price">¥{{item.price.toFixed(2)}}</view>
<!-- 展开按钮 --> <!-- 展开按钮 -->
<view class="expand-btn" @click="toggleExpand(index)" v-if="item.pet || (item.customServices && item.customServices.length > 0)">
<view class="expand-btn" @click="toggleExpand(index)" v-if="item.pet || (item.pets && item.pets.length > 0)">
<!-- <text>{{ expandedItems.includes(index) ? '收起' : '展开' }}</text> --> <!-- <text>{{ expandedItems.includes(index) ? '收起' : '展开' }}</text> -->
<view class="expand-icon" :class="{'expanded': expandedItems.includes(index)}"> <view class="expand-icon" :class="{'expanded': expandedItems.includes(index)}">
<text class="icon-arrow">{{ expandedItems.includes(index) ? '∧' : '∨' }}</text> <text class="icon-arrow">{{ expandedItems.includes(index) ? '∧' : '∨' }}</text>
@ -23,22 +29,24 @@
</view> </view>
<!-- 详细信息区域 --> <!-- 详细信息区域 -->
<view class="detail-area" v-show="expandedItems.includes(index)">
<!-- 宠物名称和头像 -->
<view class="item-pet" v-if="item.pet">
<view class="pet-avatar">
<image :src="item.petAvatar || '/static/images/default-pet.png'" mode="aspectFill"></image>
</view>
<text>{{item.pet}}</text>
</view>
<!-- 定制服务 -->
<view class="custom-services" v-if="item.customServices && item.customServices.length > 0">
<view class="custom-service-item" v-for="(service, serviceIndex) in item.customServices" :key="serviceIndex">
<view class="service-name">{{service.name}}</view>
<view class="service-price">¥{{service.price.toFixed(2)}} × {{service.quantity}} </view>
</view>
</view>
<view class="detail-area" v-if="expandedItems.includes(index)">
<view class="detail-area-item" v-for="(pet, petIndex) in item.pets" :key="petIndex">
<!-- 宠物名称和头像 -->
<view class="item-pet" v-if="pet">
<view class="pet-avatar">
<image :src="pet.photo" mode="aspectFill"></image>
</view>
<text>{{pet.name}}</text>
</view>
<!-- 定制服务 -->
<view class="custom-services-list" v-if="pet.itemList && pet.itemList.length > 0">
<view class="custom-service-item" v-for="(t, itemIndex) in pet.itemList" :key="itemIndex">
<view class="service-name">{{t.productName}}</view>
<view class="service-price">¥{{ t.salePrice && t.salePrice.toFixed(2) }} × {{t.quantity}} </view>
</view>
</view>
</view>
</view> </view>
</view> </view>
</view> </view>
@ -119,7 +127,7 @@
} }
.card-title { .card-title {
font-size: 32rpx;
font-size: 30rpx;
font-weight: bold; font-weight: bold;
color: #333; color: #333;
margin-bottom: 20rpx; margin-bottom: 20rpx;
@ -153,14 +161,14 @@
.item-id { .item-id {
font-size: 24rpx; font-size: 24rpx;
color: #999;
margin-right: 10rpx; margin-right: 10rpx;
} }
.item-name { .item-name {
font-size: 28rpx;
font-size: 24rpx;
color: #333; color: #333;
flex: 1; flex: 1;
display: flex;
} }
.item-price-action { .item-price-action {
@ -170,7 +178,6 @@
.item-price { .item-price {
font-size: 28rpx; font-size: 28rpx;
color: #FF5252;
font-weight: bold; font-weight: bold;
} }
} }
@ -207,34 +214,69 @@
// //
.detail-area { .detail-area {
padding: 15rpx;
animation: fadeIn 0.3s ease; animation: fadeIn 0.3s ease;
background-color: #F8F8F8;
border-radius: 10rpx;
margin-top: 10rpx;
display: flex;
flex-direction: column;
gap: 10rpx;
.detail-area-item{
background-color: #F8F8F8;
border-radius: 10rpx;
margin-top: 10rpx;
padding: 15rpx;
}
.item-pet {
font-size: 28rpx;
color: #333;
margin-bottom: 20rpx;
display: flex;
align-items: center;
.pet-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 20rpx;
image {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
text {
font-weight: 500;
font-size: 32rpx;
}
}
.custom-services-list {
.custom-service-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1px solid #F0F0F0;
&:last-child {
border-bottom: none;
}
.service-name {
font-size: 28rpx;
color: #333;
font-weight: 400;
}
.service-price {
font-size: 28rpx;
color: #999;
font-weight: 400;
}
}
}
} }
.item-pet {
font-size: 24rpx;
color: #666;
margin-bottom: 10rpx;
display: flex;
align-items: center;
.pet-avatar {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 10rpx;
border: 1px solid #EEEEEE;
image {
width: 100%;
height: 100%;
}
}
}
.custom-services { .custom-services {
padding: 10rpx 0 10rpx 20rpx; padding: 10rpx 0 10rpx 20rpx;


+ 23
- 3
pages_order/components/order/ServicePets.vue View File

@ -18,7 +18,10 @@
<image :src="pet.gender=='男生'?'/static/images/details/boy.svg':'/static/images/details/girl.svg'" style="width: 24rpx; height: 24rpx;" alt="sex"></image> <image :src="pet.gender=='男生'?'/static/images/details/boy.svg':'/static/images/details/girl.svg'" style="width: 24rpx; height: 24rpx;" alt="sex"></image>
</view> </view>
</view> </view>
<text class="pet-service">{{pet.services.join(',')}}: {{pet.serviceDates.join(',')}}</text>
<text class="pet-service">{{pet.serviceDates.join(',')}}</text>
</view>
<view class="count">
<text>{{ pet.serviceDates.length }}</text>
</view> </view>
</view> </view>
</view> </view>
@ -65,10 +68,16 @@
} }
.pets-list { .pets-list {
flex-direction: column;
display: flex;
gap: 20rpx;
.pet-item { .pet-item {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 20rpx; margin-bottom: 20rpx;
background-color: #f7f7f7;
padding: 20rpx;
border-radius: 20rpx;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
@ -76,8 +85,8 @@
.pet-avatar { .pet-avatar {
position: relative; position: relative;
width: 80rpx;
height: 80rpx;
width: 100rpx;
height: 100rpx;
margin-right: 20rpx; margin-right: 20rpx;
image { image {
@ -115,6 +124,17 @@
margin-top: 4rpx; margin-top: 4rpx;
} }
} }
.count{
margin-left: auto;
margin-right: 20rpx;
font-size: 26rpx;
color: #999;
text{
font-size: 34rpx;
color: #333;
}
}
} }
} }
</style> </style>

+ 68
- 46
pages_order/order/orderDetail.vue View File

@ -62,7 +62,7 @@
import { getOpenIdKey } from '@/utils/auth' import { getOpenIdKey } from '@/utils/auth'
import { getOrderDetail } from '@/api/order/order.js' import { getOrderDetail } from '@/api/order/order.js'
import { getOrderServiceText, getProductNameText } from '@/utils/serviceTime.js' import { getOrderServiceText, getProductNameText } from '@/utils/serviceTime.js'
import dayjs from '@/utils/lib/dayjs.min.js'
// //
const timeSlotMap = { const timeSlotMap = {
'MORNING': '上午', 'MORNING': '上午',
@ -83,7 +83,8 @@
data() { data() {
return { return {
orderId: null, orderId: null,
orderDetail: {},
orderDetail: {},//
detail : {},//
}; };
}, },
onLoad(options) { onLoad(options) {
@ -110,6 +111,70 @@
pet.productNameText = getProductNameText(pet.id, data.orderItemList, data.orderServiceList) // pet.productNameText = getProductNameText(pet.id, data.orderItemList, data.orderServiceList) //
}) })
//==========================================
let items = []
//1
let days = [...new Set(data.orderServiceList.map(item => item.serviceDate))]
days.forEach(day => {
let price = 0;
let itemsText = []
//2
let dayItems = data.orderServiceList.filter(item => item.serviceDate === day)
//3
let pets = data.petVOList.filter(item => dayItems.some(dayItem => dayItem.petId === item.id))
//pets
pets = JSON.parse(JSON.stringify(pets))
//4
pets.forEach(pet => {
pet.serviceList = dayItems.filter(item => item.petId === pet.id)
let itemList = []
//5
pet.serviceList.forEach(item => {
itemList.push(...(data.orderItemList.filter(n => n.orderServiceId == item.id)))
})
itemList.forEach(p => {
price += p.salePrice
itemsText = [...new Set([...itemsText, p.productName])]
})
pet.itemList = itemList
})
//6items
items.push({
price,
pets,
day,
itemsText,
})
})
//
items = items.sort((a, b) => dayjs(a.day).valueOf() - dayjs(b.day).valueOf())
console.log(items);
//==========================================
// //
this.orderDetail = { this.orderDetail = {
// //
@ -132,50 +197,7 @@
}) : [], }) : [],
// //
items: data.orderItemList.map((item, index) => {
//
let spData = {};
try {
spData = JSON.parse(item.spData || '{}');
} catch (e) {
console.error('解析商品附加数据失败', e);
}
//
const pet = data.petVOList && data.petVOList[index] ? {
name: data.petVOList[index].name,
avatar: data.petVOList[index].photo
} : null;
//
const customServices = [
// {
// name: '',
// price: 50,
// quantity: 2
// },
// {
// name: '',
// price: 100,
// quantity: 1
// },
// {
// name: '',
// price: 80,
// quantity: 1
// }
];
return {
id: index + 1,
name: item.productName,
price: item.salePrice,
quantity: item.quantity,
pet: pet ? pet.name : null,
petAvatar: pet ? pet.avatar : null,
customServices: customServices
};
}),
items,
// //
totalAmount: data.totalAmount, totalAmount: data.totalAmount,


+ 11
- 3
pages_order/order/orderList.vue View File

@ -45,14 +45,14 @@
</view> </view>
</view> </view>
<text class="pet-service"> <text class="pet-service">
{{ pet.productNameText.join(',') }} | {{ pet.orderServiceText.length }} {{ pet.orderServiceText.join(',') }}</text>
{{ handleText(pet.productNameText) }} | {{ pet.orderServiceText.length }} {{ handleText(pet.orderServiceText) }}</text>
</view> </view>
</view> </view>
<!-- 订单信息 --> <!-- 订单信息 -->
<view class="order-info"> <view class="order-info">
<text class="order-time">下单时间: {{order.createTime}}</text> <text class="order-time">下单时间: {{order.createTime}}</text>
<view class="companion-info">
<view class="companion-info" v-if="order.companionName">
<text>伴宠师: {{order.companionName}}</text> <text>点击查看伴宠师详情</text> <text>伴宠师: {{order.companionName}}</text> <text>点击查看伴宠师详情</text>
</view> </view>
</view> </view>
@ -203,7 +203,7 @@
this.hasMore = true; this.hasMore = true;
this.getOrderList(); this.getOrderList();
}, },
// //
refresh() { refresh() {
this.refreshing = true; this.refreshing = true;
@ -329,8 +329,11 @@
this.orderList.forEach(item => { this.orderList.forEach(item => {
item.petVOList.forEach(pet => { item.petVOList.forEach(pet => {
pet.orderServiceText = getOrderServiceText(pet.id, item.orderServiceList || []) || [] pet.orderServiceText = getOrderServiceText(pet.id, item.orderServiceList || []) || []
pet.productNameText = getProductNameText(pet.id, item.orderItemList, item.orderServiceList || []) || [] pet.productNameText = getProductNameText(pet.id, item.orderItemList, item.orderServiceList || []) || []
}) })
}) })
@ -344,6 +347,10 @@
this.loading = false; this.loading = false;
}); });
}, },
handleText(list){
return list && (list.length > 2 ? `${list[0]}...${list[list.length - 1]}` : list.join(','))
},
// //
handleReorder(order) { handleReorder(order) {
@ -467,6 +474,7 @@
width: 80rpx; width: 80rpx;
height: 80rpx; height: 80rpx;
margin-right: 20rpx; margin-right: 20rpx;
flex-shrink: 0;
image { image {
width: 100%; width: 100%;


Loading…
Cancel
Save