Browse Source

feat(订单): 实现新版日订单打卡功能

- 新增frequency.js接口文件,包含日订单列表查询、详情获取和打卡功能
- 修改myOrdersManage页面,使用新版日订单接口替代旧接口
- 更新timelineService组件,适配新版数据结构和展示逻辑
- 重构打卡页面,支持多宠物和多服务项目的打卡记录
- 调整环境配置,将默认环境改为develop并更新本地开发地址
master
前端-胡立永 1 week ago
parent
commit
7b92f61721
9 changed files with 1313 additions and 122 deletions
  1. +40
    -0
      api/order/frequency.js
  2. +1
    -0
      api/order/order.js
  3. +462
    -0
      otherPages/myOrdersManage/clock/index - 副本.vue
  4. +112
    -27
      otherPages/myOrdersManage/clock/index.vue
  5. +636
    -0
      pages/myOrdersManage/components/timelineService - 副本.vue
  6. +22
    -80
      pages/myOrdersManage/components/timelineService.vue
  7. +34
    -10
      pages/myOrdersManage/index.vue
  8. +2
    -2
      pages/workbenchManage/index.vue
  9. +4
    -3
      utils/getUrl.js

+ 40
- 0
api/order/frequency.js View File

@ -0,0 +1,40 @@
import request from '@/utils/request'
// 新版本日订单查询日订单列表
export function appletOrderDateFrequencyList(params) {
return request({
headers: {
"isToken": true
},
url: "/applet/appletOrderDateFrequency/list",
method: 'get',
params
})
}
// 新版本日订单查询详情
export function appletOrderDateFrequencyById(id) {
return request({
headers: {
"isToken": true
},
url: "/applet/appletOrderDateFrequency/" + id,
method: 'get',
})
}
// 新版本日订单打卡
export function appletOrderDateFrequencyCheck(data) {
return request({
headers: {
"isToken": true
},
url: "/applet/appletOrderDateFrequency/check",
method: 'post',
data
})
}
export default {
appletOrderDateFrequencyList,
appletOrderDateFrequencyById,
appletOrderDateFrequencyCheck,
}

+ 1
- 0
api/order/order.js View File

@ -79,6 +79,7 @@ export function getPetCareByPetId(petId) {
})
}
export default {
getAppOrderList,
orderItemLogGetByOrderId,


+ 462
- 0
otherPages/myOrdersManage/clock/index - 副本.vue View File

@ -0,0 +1,462 @@
<template>
<!-- <view>打卡</view> -->
<view class="box box-size">
<view class="top box-size" :style="{borderRadius:'16rpx'}">
<view class="form-title">
个人准备
</view>
<view class="mt32 ml10">
<span :style="{fontSize:'30rpx',fontWeight:'400'}">手套照片</span>
<span :style="{fontSize:'26rpx',color:'#C7C7C7'}">(至少1张)</span>
</view>
<view class="level">
<view class="mt20 ml10">
<up-upload :fileList="fileList.glove" @afterRead="afterRead" @delete="deletePic" name="glove"
multiple :maxCount="2" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
</view>
</view>
<view class="mt32 ml10">
<span :style="{fontSize:'30rpx',fontWeight:'400'}">鞋套照片</span>
<span :style="{fontSize:'26rpx',color:'#C7C7C7'}">(至少1张)</span>
</view>
<view class="level">
<view class="mt20 ml10">
<up-upload :fileList="fileList.ShoeCover" @afterRead="afterRead" @delete="deletePic"
name="ShoeCover" multiple :maxCount="2" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
</view>
</view>
</view>
<view class="top mt24 box-size" :style="{borderRadius:'16rpx'}">
<view class="form-title">
宠物状态记录
</view>
<view v-for="(pet, index) in petList" :key="index">
<view class="mt32 ml10">
<span :style="{fontSize:'30rpx',fontWeight:'400'}">{{ pet.title }}照片</span>
<span :style="{fontSize:'26rpx',color:'#C7C7C7'}">(至少2张)</span>
</view>
<view class="level">
<view class="mt20 ml10 mr20">
<up-upload :fileList="fileList['pet' + index]" @afterRead="afterRead" @delete="deletePic"
:name="'pet' + index" multiple :maxCount="2" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode=""
:style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
</view>
</view>
</view>
</view>
<view class="top mt24 box-size" :style="{borderRadius:'16rpx'}">
<view class="form-title">
基础服务记录
</view>
<view class="mt32 ml10" :style="{fontSize:'30rpx',fontWeight:'400'}">粮碗前后对比 </view>
<view class="level">
<view class="mt20 ml10">
<up-upload :fileList="fileList.foodA" @afterRead="afterRead" @delete="deletePic" name="foodA"
multiple :maxCount="1" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
<view class="jus-center level" :style="{color:'#999999',fontSize:'22rpx',width:'131rpx'}"></view>
</view>
<view class="mt20 ml10 ml28">
<up-upload :fileList="fileList.foodB" @afterRead="afterRead" @delete="deletePic" name="foodB"
multiple :maxCount="1" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
<view class="jus-center level" :style="{color:'#999999',fontSize:'22rpx',width:'131rpx'}"></view>
</view>
</view>
<view class="mt32 ml10" :style="{fontSize:'30rpx',fontWeight:'400'}">水碗前后对比 </view>
<view class="level">
<view class="mt20 ml10">
<up-upload :fileList="fileList.waterA" @afterRead="afterRead" @delete="deletePic" name="waterA"
multiple :maxCount="1" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
<view class="jus-center level" :style="{color:'#999999',fontSize:'22rpx',width:'131rpx'}"></view>
</view>
<view class="mt20 ml10 ml28">
<up-upload :fileList="fileList.waterB" @afterRead="afterRead" @delete="deletePic" name="waterB"
multiple :maxCount="1" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
<view class="jus-center level" :style="{color:'#999999',fontSize:'22rpx',width:'131rpx'}"></view>
</view>
</view>
<view class="mt32 ml10" :style="{fontSize:'30rpx',fontWeight:'400'}">猫砂盆尿垫前后对比 </view>
<view class="level">
<view class="mt20 ml10">
<up-upload :fileList="fileList.urinalA" @afterRead="afterRead" @delete="deletePic" name="urinalA"
multiple :maxCount="1" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
<view class="jus-center level" :style="{color:'#999999',fontSize:'22rpx',width:'131rpx'}"></view>
</view>
<view class="mt20 ml10 ml28">
<up-upload :fileList="fileList.urinalB" @afterRead="afterRead" @delete="deletePic" name="urinalB"
multiple :maxCount="1" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
<view class="jus-center level" :style="{color:'#999999',fontSize:'22rpx',width:'131rpx'}"></view>
</view>
</view>
</view>
<view class="top mt24 box-size" :style="{borderRadius:'16rpx'}">
<view class="form-title">
定制服务记录
</view>
<view class="mt32 ml10">
<span :style="{fontSize:'30rpx',fontWeight:'400'}">遛狗</span>
<span :style="{fontSize:'26rpx',color:'#C7C7C7'}">(2-3)</span>
</view>
<view class="level">
<view class="mt20 ml10 mr20">
<up-upload :fileList="fileList.testa" @afterRead="afterRead" @delete="deletePic" name="testa"
multiple :maxCount="3" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
</view>
</view>
<view class="mt32 ml10">
<span :style="{fontSize:'30rpx',fontWeight:'400'}">陪玩</span>
<span :style="{fontSize:'26rpx',color:'#C7C7C7'}">(2-3)</span>
</view>
<view class="level">
<view class="mt20 ml10 mr20">
<up-upload :fileList="fileList.testb" @afterRead="afterRead" @delete="deletePic" name="testb"
multiple :maxCount="3" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
</view>
</view>
</view>
<view class="top mt24 box-size" :style="{borderRadius:'16rpx'}">
<view class="form-title">
其他补充信息(必填)
</view>
<view class="mt32 ml10" :style="{color:'#999999',fontSize:'30rpx'}">
可记录一下今日趣事宠物状况提醒事项等
</view>
<view class="mt24">
<textarea cols="30" rows="10"
placeholder="请输入内容"
v-model="content"
:style="{color:'#999999',fontSize:'30rpx',backgroundColor:'#F5F5F5',borderRadius:'16rpx',width:'681rpx',height:'180rpx'}"
class="pd20 box-size" :disabled="isRead"></textarea>
</view>
</view>
<view class="buttom mt60 box-size"
v-if="!isRead"
style="display: flex;gap: 20rpx;"
>
<view class="buttom-item buttom-item-2 level size-30"
@click="saveDraft(false)"
:style="{borderRadius:'41rpx',color:'#ff842c'}">
保存草稿
</view>
<view class="buttom-item level size-30"
@click="submit"
:style="{borderRadius:'41rpx',color:'#fff'}">
确定提交
</view>
</view>
</view>
</template>
<script setup>
import {
onMounted,
reactive,
ref,
} from "vue";
import {
onLoad
} from '@dcloudio/uni-app'
import {
ossUpload
} from '@/utils/oss-upload/oss/index.js'
import { orderItemLogGetByOrderId } from '@/api/order/order.js'
import {
getOrderPetById,
orderItemLogAddOrUpdate,
} from "@/api/order/order.js";
onLoad((options) => {
orderId.value = options.id || null;
isRead.value = options.isRead || false;
itemOrderID.value = options.itemID
serviceId.value = options.serviceId;
GetByOrderId()
});
const orderId = ref(0)
const itemOrderID = ref(0)
const serviceId = ref(0)
const isRead = ref(false)
const content = ref('')
const fileList = reactive({
// glove: [],//
// ShoeCover: [],//
// food: [],//
// water: [],//
// urinal: [],//尿
})
const form = ref({})
const petList = ref([
// {
// title: ''
// },
// {
// title: ''
// },
])
//
const deletePic = (event) => {
if (fileList[event.name]) {
fileList[event.name].splice(event.index, 1);
}
};
//
const afterRead = (event) => {
if (!fileList[event.name]) {
fileList[event.name] = []
}
event.file.forEach(n => {
ossUpload(n.url)
.then(url => {
fileList[event.name].push({
url
})
})
})
};
function submit() {
//
if (!fileList.glove || fileList.glove.length == 0) {
return msg('请上传鞋套照片')
}
if (!fileList.ShoeCover || fileList.ShoeCover.length == 0) {
return msg('请上传鞋套照片')
}
for (let i = 0; i < petList.value.length; i++) {
if (!fileList['pet' + i] || fileList['pet' + i].length < 2) {
return msg(`请上传${petList.value[i].title}照片`)
}
}
if (!fileList.foodA || fileList.foodA.length < 1 ||
!fileList.foodB || fileList.foodB.length < 1) {
return msg('请上传粮碗前后照片')
}
if (!fileList.waterA || fileList.waterA.length < 1 ||
!fileList.waterB || fileList.waterB.length < 1) {
return msg('请上传水碗前后照片')
}
if (!fileList.urinalA || fileList.urinalA.length < 1 ||
!fileList.urinalB || fileList.urinalB.length < 1) {
return msg('请上传猫砂盆、尿盆照片')
}
if(!content.value){
return msg('请填写补充信息')
}
saveDraft(true)
}
function GetByOrderId(){
orderItemLogGetByOrderId(serviceId.value)
.then(res => {
if(res.code == 200 && res.data) {
const data = res.data;
form.value = data
//
if(data.glovePhoto) {
fileList.glove = data.glovePhoto.split(',').map(url => ({ url }));
}
//
if(data.shoeCoverPhoto) {
fileList.ShoeCover = data.shoeCoverPhoto.split(',').map(url => ({ url }));
}
//
if(data.petPhoto) {
const pets = JSON.parse(data.petPhoto);
petList.value = pets;
pets.forEach((pet, index) => {
if(pet.fileList) {
fileList['pet' + index] = pet.fileList.split(',').map(url => ({ url }));
}
});
}
//
if(data.grainBowlFront) fileList.foodA = data.grainBowlFront.split(',').map(url => ({ url }));
if(data.grainBowlAfter) fileList.foodB = data.grainBowlAfter.split(',').map(url => ({ url }));
//
if(data.waterBowlFront) fileList.waterA = data.waterBowlFront.split(',').map(url => ({ url }));
if(data.waterBowlAfter) fileList.waterB = data.waterBowlAfter.split(',').map(url => ({ url }));
// /尿
if(data.basinFront) fileList.urinalA = data.basinFront.split(',').map(url => ({ url }));
if(data.basinAfter) fileList.urinalB = data.basinAfter.split(',').map(url => ({ url }));
//
if(data.workDogImage) fileList.testa = data.workDogImage.split(',').map(url => ({ url }));
if(data.workPalyImage) fileList.testb = data.workPalyImage.split(',').map(url => ({ url }));
}else{
getOrderPetByIdFN()
}
})
}
function getOrderPetByIdFN(){
getOrderPetById(orderId.value)
.then(res => {
if(res.code == 200){
res.data.forEach((n, i) => {
fileList['pet' + i] = []
})
res.data.forEach((n, i) => {
petList.value.push({
title : n.name,
id : n.id,
})
})
}
})
}
function saveDraft(flag) {
//
const params = {
orderId: orderId.value,
itemOrderId : itemOrderID.value,
itemDateId : serviceId.value,
glovePhoto: fileList.glove?.map(item => item.url).join(',') || '',
shoeCoverPhoto: fileList.ShoeCover?.map(item => item.url).join(',') || '',
//
petPhoto: JSON.stringify(
petList.value.map((pet, index) => {
return {
id : pet.id,
title : pet.title,
fileList: fileList['pet' + index]?.map(item => item.url).join(',') || ''
};
})
),
//
grainBowlFront: fileList.foodA?.map(item => item.url).join(',') || '',
grainBowlAfter: fileList.foodB?.map(item => item.url).join(',') || '',
//
waterBowlFront: fileList.waterA?.map(item => item.url).join(',') || '',
waterBowlAfter: fileList.waterB?.map(item => item.url).join(',') || '',
// /尿
basinFront: fileList.urinalA?.map(item => item.url).join(',') || '',
basinAfter: fileList.urinalB?.map(item => item.url).join(',') || '',
//
workDogImage: fileList.testa?.map(item => item.url).join(',') || '',
workPalyImage: fileList.testb?.map(item => item.url).join(',') || '',
//
notes: form.value.notes || '',
}
if(form.value.id) {
params.id = form.value.id
}
if(flag) {
params.submitFlag = 2
}
orderItemLogAddOrUpdate(params)
.then(res => {
if(res.code === 200) {
uni.showToast({
title: '提交成功',
icon: 'success'
})
// 稿
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
uni.showToast({
title: res.msg || '提交失败',
icon: 'none'
})
}
})
.catch(err => {
uni.showToast({
title: '提交失败',
icon: 'none'
})
})
}
function msg(content) {
uni.showToast({
title: content,
icon: 'none'
})
}
</script>
<style scoped lang="scss">
@import"index.scss"
</style>

+ 112
- 27
otherPages/myOrdersManage/clock/index.vue View File

@ -140,7 +140,28 @@
<view class="form-title">
定制服务记录
</view>
<view class="mt32 ml10">
<view v-for="(product, pindex) in projectList"
:key="pindex">
<view class="mt32 ml10">
<span :style="{fontSize:'30rpx',fontWeight:'400'}">{{ product.title }}</span>
<span :style="{fontSize:'26rpx',color:'#C7C7C7'}">(2-3)</span>
</view>
<view class="level">
<view class="mt20 ml10 mr20">
<up-upload :fileList="fileList['project' + pindex]" @afterRead="afterRead" @delete="deletePic"
:name="'project' + pindex"
multiple :maxCount="3" width="131rpx" height="131rpx" :disabled="isRead">
<image src="/static/images/ydd/add_photo.png" mode="" :style="{width:'131rpx',height:'131rpx'}">
</image>
</up-upload>
</view>
</view>
</view>
<!-- <view class="mt32 ml10">
<span :style="{fontSize:'30rpx',fontWeight:'400'}">遛狗</span>
<span :style="{fontSize:'26rpx',color:'#C7C7C7'}">(2-3)</span>
</view>
@ -154,8 +175,8 @@
</up-upload>
</view>
</view>
<view class="mt32 ml10">
</view> -->
<!-- <view class="mt32 ml10">
<span :style="{fontSize:'30rpx',fontWeight:'400'}">陪玩</span>
<span :style="{fontSize:'26rpx',color:'#C7C7C7'}">(2-3)</span>
</view>
@ -169,7 +190,7 @@
</up-upload>
</view>
</view>
</view> -->
</view>
<view class="top mt24 box-size" :style="{borderRadius:'16rpx'}">
<view class="form-title">
@ -181,12 +202,13 @@
<view class="mt24">
<textarea cols="30" rows="10"
placeholder="请输入内容"
v-model="content"
v-model="form.notes"
:style="{color:'#999999',fontSize:'30rpx',backgroundColor:'#F5F5F5',borderRadius:'16rpx',width:'681rpx',height:'180rpx'}"
class="pd20 box-size" :disabled="isRead"></textarea>
</view>
</view>
<view class="buttom mt60 box-size"
v-if="!isRead"
style="display: flex;gap: 20rpx;"
>
<view class="buttom-item buttom-item-2 level size-30"
@ -218,20 +240,17 @@
ossUpload
} from '@/utils/oss-upload/oss/index.js'
import { orderItemLogGetByOrderId } from '@/api/order/order.js'
import {
getOrderPetById,
orderItemLogAddOrUpdate,
} from "@/api/order/order.js";
appletOrderDateFrequencyById,
appletOrderDateFrequencyCheck,
} from "@/api/order/frequency.js"
onLoad((options) => {
orderId.value = options.id || null;
isRead.value = options.isRead || false;
itemOrderID.value = options.itemID
serviceId.value = options.serviceId;
checkId.value = options.id || null;
GetByOrderId()
});
const checkId = ref(0)
const orderId = ref(0)
const itemOrderID = ref(0)
const serviceId = ref(0)
@ -257,6 +276,15 @@
// title: ''
// },
])
//
const projectList = ref([
// {
// title: ''
// },
// {
// title: ''
// },
])
@ -312,7 +340,13 @@
return msg('请上传猫砂盆、尿盆照片')
}
if(!content.value){
for (let i = 0; i < projectList.value.length; i++) {
if (!fileList['project' + i] || fileList['project' + i].length < 2) {
return msg(`请上传${projectList.value[i].title}照片`)
}
}
if(!form.value.notes){
return msg('请填写补充信息')
}
@ -320,10 +354,12 @@
}
function GetByOrderId(){
orderItemLogGetByOrderId(serviceId.value)
appletOrderDateFrequencyById(checkId.value)
.then(res => {
if(res.code == 200 && res.data) {
const data = res.data;
const data = res.data.check;
const frequency = res.data.frequency;
isRead.value = frequency.status == 2
if(res.code == 200 && data) {
form.value = data
//
if(data.glovePhoto) {
@ -343,6 +379,16 @@
}
});
}
//
if(data.workDogImage) {
const pList = JSON.parse(data.workDogImage);
projectList.value = pList;
pList.forEach((pet, index) => {
if(pet.fileList) {
fileList['project' + index] = pet.fileList.split(',').map(url => ({ url }));
}
});
}
//
if(data.grainBowlFront) fileList.foodA = data.grainBowlFront.split(',').map(url => ({ url }));
if(data.grainBowlAfter) fileList.foodB = data.grainBowlAfter.split(',').map(url => ({ url }));
@ -353,10 +399,39 @@
if(data.basinFront) fileList.urinalA = data.basinFront.split(',').map(url => ({ url }));
if(data.basinAfter) fileList.urinalB = data.basinAfter.split(',').map(url => ({ url }));
//
if(data.workDogImage) fileList.testa = data.workDogImage.split(',').map(url => ({ url }));
if(data.workPalyImage) fileList.testb = data.workPalyImage.split(',').map(url => ({ url }));
// if(data.workDogImage) fileList.testa = data.workDogImage.split(',').map(url => ({ url }));
// if(data.workPalyImage) fileList.testb = data.workPalyImage.split(',').map(url => ({ url }));
}else{
getOrderPetByIdFN()
// getOrderPetByIdFN()
let projectNameList = []
frequency.pets.forEach((n, i) => {
fileList['pet' + i] = []
n.orderItemList.forEach((item, inde) => {
fileList['project' + inde] = []
})
})
frequency.pets.forEach((n, i) => {
petList.value.push({
title : n.name,
id : n.id,
})
n.orderItemList.forEach((item, inde) => {
if(!projectNameList.includes(item.productName)){
projectNameList.push(item.productName)
projectList.value.push({
title : item.productName,
ids : [item.id]
})
}else{
projectList.value[projectNameList.indexOf(item.productName)].ids.push(item.id)
}
})
})
}
})
}
@ -382,9 +457,9 @@
function saveDraft(flag) {
//
const params = {
orderId: orderId.value,
itemOrderId : itemOrderID.value,
itemDateId : serviceId.value,
// orderId: orderId.value,
// itemOrderId : itemOrderID.value,
itemDateId : checkId.value,
glovePhoto: fileList.glove?.map(item => item.url).join(',') || '',
shoeCoverPhoto: fileList.ShoeCover?.map(item => item.url).join(',') || '',
//
@ -396,6 +471,15 @@
fileList: fileList['pet' + index]?.map(item => item.url).join(',') || ''
};
})
),
workDogImage: JSON.stringify(
projectList.value.map((pet, index) => {
return {
id : pet.id,
title : pet.title,
fileList: fileList['project' + index]?.map(item => item.url).join(',') || ''
};
})
),
//
grainBowlFront: fileList.foodA?.map(item => item.url).join(',') || '',
@ -407,10 +491,11 @@
basinFront: fileList.urinalA?.map(item => item.url).join(',') || '',
basinAfter: fileList.urinalB?.map(item => item.url).join(',') || '',
//
workDogImage: fileList.testa?.map(item => item.url).join(',') || '',
workPalyImage: fileList.testb?.map(item => item.url).join(',') || '',
// workDogImage: fileList.testa?.map(item => item.url).join(',') || '',
// workPalyImage: fileList.testb?.map(item => item.url).join(',') || '',
//
notes: form.value.notes || '',
submitFlag : 1,//稿
}
if(form.value.id) {
@ -418,10 +503,10 @@
}
if(flag) {
params.submitFlag = 1
params.submitFlag = 2
}
orderItemLogAddOrUpdate(params)
appletOrderDateFrequencyCheck(params)
.then(res => {
if(res.code === 200) {
uni.showToast({


+ 636
- 0
pages/myOrdersManage/components/timelineService - 副本.vue View File

@ -0,0 +1,636 @@
<template>
<view class="timeline-container">
<!-- 日期和状态标签 -->
<view class="date-header">
<view class="date-box">
<view class="date-box-color" :style="{'background-color': getTopBgColor()}"></view>
<view class="date-month-day">{{ formatDate(date).month }}-{{ formatDate(date).day }}</view>
</view>
<view class="status-tag" :class="{'status-tag-pending': status}">
<image src="/static/images/ydd/icon1.png"
mode="aspectFit"
v-if="status"
class="status-icon"></image>
<image src="/static/images/order/success.png"
mode="aspectFit"
v-else
class="status-icon"></image>
{{ status ? '待上门' : '已完成' }}
</view>
</view>
<!-- 空状态显示 -->
<view v-if="!processedList || processedList.length === 0" class="empty-state">
<text class="empty-text">暂无订单数据</text>
</view>
<!-- 时间线主体 -->
<view v-else class="timeline-body" v-for="(item, index) in processedList" :key="index">
<view class="timeline-line"></view>
<view class="time-point">
<view class="time-icon">
<image src="/static/images/order/address.png" mode="aspectFit" class="time-image"></image>
</view>
<view class="time-text">{{ item.address }}</view>
<view class="collapse-icon" @click="toggleServiceCard(index)">
{{ serviceCardCollapsed[index] ? '展开' : '收起' }} <text class="arrow" :class="{'arrow-up': !serviceCardCollapsed[index]}"></text>
</view>
</view>
<!-- 服务内容卡片 -->
<view v-if="!serviceCardCollapsed[index]" class="service-card">
<!-- 服务日期 -->
<view class="service-section">
<view class="section-title">
<view class="title-indicator"></view>
<text>服务日期</text>
<text style="margin-left: auto;font-weight: 500;font-size: 24rpx;">订单编号{{ item.orderId }}</text>
</view>
<view class="section-content date-content" :class="{bgSuccessQ : item.status}">
{{ item.fullDate }}
</view>
</view>
<!-- 陪伴对象 -->
<view class="service-section">
<view class="section-title">
<view class="title-indicator"></view>
<text>陪伴对象</text>
<view class="collapse-icon" @click="togglePetList(index)">
{{ petListCollapsed[index] ? '展开' : '收起' }} <text class="arrow" :class="{'arrow-up': !petListCollapsed[index]}"></text>
</view>
</view>
<view class="section-content pet-list" :class="{bgSuccessQ : item.status}" v-if="!petListCollapsed[index]">
<view v-for="(pet, i) in item.petList" :key="i" class="pet-item">
<view class="pet-avatar">
<image :src="pet.avatar" mode="aspectFill" class="avatar-image"></image>
</view>
<view class="pet-info">
<view class="pet-name">
{{ pet.name }}
<text class="pet-gender" :class="{'pet-gender-male': pet.gender === 'male', 'pet-gender-female': pet.gender === 'female'}">
{{ pet.gender === 'male' ? '♂' : '♀' }}
</text>
</view>
<view class="pet-description">
{{ pet.breed }}{{ pet.bodyType }} | {{ pet.services.join('+') }}
</view>
</view>
</view>
</view>
</view>
<!-- 上门地址 -->
<view class="service-section">
<view class="section-title">
<view class="title-indicator"></view>
<text>上门地址</text>
</view>
<view class="section-content address-content" :class="{bgSuccessQ : item.status}">
{{ item.addressDetail }}
</view>
</view>
<!-- 操作按钮 -->
<view class="action-buttons">
<view class="btn btn-clock" :class="{bgSuccess : item.status}" @click="handleClock(item)">{{ item.status ? '打卡记录' : '打卡' }}</view>
<view class="btn btn-clock" :class="{bgSuccess : item.status}" @click="handlePetFile(item)">宠物档案</view>
<view class="btn btn-clock" :class="{bgSuccess : item.status}" @click="handleServiceFile(item)">服务档案</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import { getOrderServiceText, getProductNameText } from '@/utils/serviceTime.js';
//
const props = defineProps({
date: {
type: String,
default: '2024-12-08'
},
orderCount: {
type: Number,
default: 2
},
status : {
type: Boolean,
default: true
},
current: {
type: Number,
default: 0
},
list: {
type: Array,
default: () => []
}
});
// - 使
const petListCollapsed = ref([]);
// - 使
const serviceCardCollapsed = ref([]);
//
const togglePetList = (index) => {
if (petListCollapsed.value[index] === undefined) {
petListCollapsed.value[index] = true;
} else {
petListCollapsed.value[index] = !petListCollapsed.value[index];
}
};
//
const toggleServiceCard = (index) => {
if (serviceCardCollapsed.value[index] === undefined) {
serviceCardCollapsed.value[index] = true;
} else {
serviceCardCollapsed.value[index] = !serviceCardCollapsed.value[index];
}
};
//
const formatDate = (dateString) => {
const date = new Date(dateString);
return {
day: date.getDate().toString().padStart(2, '0'),
month: (date.getMonth() + 1).toString().padStart(2, '0')
};
};
//
const processedList = computed(() => {
return props.list.map(order => {
//
const petList = [];
let orderId = 0
let serviceId = 0
let status = 1
if (order.appletOrderItemDate && order.appletOrderItemDate.length > 0) {
order.appletOrderItemDate.forEach(item => {
if (item.orderServiceList && item.orderServiceList.petVo) {
const pet = item.orderServiceList.petVo;
const services = [];
//
if (item.orderItemList && item.orderItemList.length > 0) {
item.orderItemList.forEach(orderItem => {
services.push(orderItem.productName);
orderId = orderItem.orderId
});
}
serviceId = item.id
if(item.status == 0){
status = 0
}
petList.push({
name: pet.name,
serviceId : item.id,
gender: pet.gender === '男生' ? 'male' : 'female',
breed: pet.breed,
bodyType: `(${pet.bodyType})`,
services: services,
avatar: pet.photo || (pet.petType === 'dog' ? '/static/images/ydd/dog.png' : '/static/images/ydd/cat.png')
});
}
});
}
return {
id: order.orderId,
orderId,
serviceId,
status,
address: order.cityAddress,
addressDetail: order.address,
fullDate: props.date.replace(/-/g, '/'),
petList: petList
};
});
});
//
const handleClock = (item) => {
console.log(item);
//
const paths = [
`/otherPages/myOrdersManage/clock/index?id=${item.orderId}&itemID=${item.id}&serviceId=${item.serviceId}`,
`/otherPages/myOrdersManage/clock/index?isRead=true&id=${item.orderId}&itemID=${item.id}&serviceId=${item.serviceId}`,
];
uni.navigateTo({
url: props.status ? paths[0] : paths[1]
});
};
const handlePetFile = (item) => {
uni.navigateTo({
url: "/otherPages/orderTakingManage/pet/index?id=" + item.orderId
});
};
const handleServiceFile = (item) => {
uni.navigateTo({
url: "/otherPages/myOrdersManage/service/index?id=" + item.orderId
});
};
function getTopBgColor(){
return props.status ? '#FFAA48' : '#4CD964';
}
</script>
<style lang="scss" scoped>
.bgSuccess{
background-color: #4CD964 !important;
}
.bgSuccessQ{
background-color: #4CD96422 !important;
}
.timeline-container {
position: relative;
padding: 20rpx;
margin-bottom: 30rpx;
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80rpx 40rpx;
.empty-image {
width: 200rpx;
height: 200rpx;
margin-bottom: 20rpx;
}
.empty-text {
color: #999;
font-size: 28rpx;
}
}
.date-header {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.date-box {
width: 80rpx;
background-color: #ffffff;
border: 2px solid #333;
border-radius: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-right: 20rpx;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
border-radius: 14rpx;
.date-box-color{
height: 20rpx;
width: 100%;
border-top-left-radius: 14rpx;
border-top-right-radius: 14rpx;
position: relative;
&::before{
content: '';
display: block;
background-color: #ddd;
width: 100%;
height: 26rpx;
top: 100%;
left: 0;
position: absolute;
}
}
.date-month-day {
position: relative;
font-size: 26rpx;
font-weight: bold;
color: #333;
height: 50rpx;
display: flex;
flex-direction: column;
justify-content: center;
}
}
.status-tag {
background-color: #4CD96422;
color: #4CD964;
border: 4rpx solid #4CD964;
padding: 16rpx 26rpx;
border-radius: 14rpx;
font-size: 26rpx;
display: flex;
align-items: center;
position: relative;
margin-left: 20rpx;
.status-icon {
width: 32rpx;
height: 32rpx;
margin-right: 8rpx;
}
&::after{
content: '';
display: block;
position: absolute;
width: 0;
height: 0;
top: 50%;
transform: translateY(-50%);
left: -16rpx;
border-top: 16rpx solid transparent;
border-bottom: 16rpx solid transparent;
border-right: 16rpx solid #4CD964;
}
&::before{
content: '';
display: block;
position: absolute;
width: 0;
height: 0;
top: 50%;
transform: translateY(-50%);
left: -12rpx;
border-top: 12rpx solid transparent;
border-bottom: 12rpx solid transparent;
border-right: 12rpx solid #4CD96422;
z-index: 1;
}
}
.status-tag-pending {
background-color: #FFAA4822;
color: #FFAA48;
border-color: #FFAA48;
&::after{
border-right-color: #FFAA48;
}
&::before{
border-right-color: #FFAA4822;
}
}
}
.timeline-body {
position: relative;
padding-left: 40rpx;
padding-bottom: 40rpx;
.timeline-line {
position: absolute;
left: 40rpx;
top: 0;
height: 100%;
width: 0;
border-left: 2rpx dashed #707070;
border-left-style: dashed;
border-image: repeating-linear-gradient(to bottom, #707070 0, #707070 8rpx, transparent 8rpx, transparent 20rpx) 1;
z-index: 0;
&::after{
content: '';
display: block;
position: absolute;
width: 8rpx;
height: 8rpx;
background-color: #000;
border: 2rpx solid #707070;
border-radius: 50%;
left: -7rpx;
top: 30rpx;
}
}
.time-point {
display: flex;
align-items: center;
margin-bottom: 20rpx;
position: relative;
z-index: 1;
.time-icon {
width: 60rpx;
height: 60rpx;
background-color: #fff;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
position: relative;
left: 20rpx;
.time-image {
width: 40rpx;
height: 40rpx;
}
}
.time-text {
font-size: 28rpx;
color: #333;
margin-left: 20rpx;
flex: 1;
}
.collapse-icon {
font-size: 24rpx;
color: #999;
padding: 0 20rpx;
.arrow {
transition: transform 0.3s;
display: inline-block;
}
.arrow-up {
transform: rotate(180deg);
}
}
}
.service-card {
background-color: #fff;
border-radius: 12rpx;
padding: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
margin-left: 20rpx;
.service-section {
margin-bottom: 30rpx;
.section-title {
display: flex;
align-items: center;
margin-bottom: 15rpx;
.title-indicator {
width: 6rpx;
height: 30rpx;
background-color: #FFAA48;
margin-right: 15rpx;
}
text {
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.collapse-icon {
margin-left: auto;
font-size: 24rpx;
color: #999;
.arrow {
transition: transform 0.3s;
display: inline-block;
}
.arrow-up {
transform: rotate(180deg);
}
}
}
.section-content {
padding: 0 15rpx;
background-color: #FFF9F0;
}
.date-content {
background-color: #FFF9F0;
padding: 20rpx;
border-radius: 8rpx;
font-size: 28rpx;
color: #333;
}
.pet-list {
padding: 15rpx;
.pet-item {
display: flex;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
.pet-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 20rpx;
.avatar-image {
width: 100%;
height: 100%;
}
}
.pet-info {
flex: 1;
.pet-name {
font-size: 28rpx;
color: #333;
margin-bottom: 8rpx;
.pet-gender {
display: inline-block;
width: 32rpx;
height: 32rpx;
line-height: 32rpx;
text-align: center;
border-radius: 50%;
color: #fff;
font-size: 20rpx;
margin-left: 10rpx;
}
.pet-gender-male {
background-color: #4A90E2;
}
.pet-gender-female {
background-color: #FF6B9A;
}
}
.pet-description {
font-size: 24rpx;
color: #7D8196;
}
}
}
}
.address-content {
padding: 20rpx;
border-radius: 8rpx;
font-size: 28rpx;
color: #7D8196;
}
}
.action-buttons {
display: flex;
justify-content: space-between;
.btn {
width: 30%;
height: 80rpx;
line-height: 80rpx;
text-align: center;
border-radius: 40rpx;
font-size: 28rpx;
}
.btn-clock {
background-color: #FFAA48;
color: #fff;
}
.btn-pet-file, .btn-service-file {
background-color: #F6F7FB;
color: #333;
border: 1px solid #E5E6EB;
}
}
}
}
}
</style>

+ 22
- 80
pages/myOrdersManage/components/timelineService.vue View File

@ -4,9 +4,9 @@
<view class="date-header">
<view class="date-box">
<view class="date-box-color" :style="{'background-color': getTopBgColor()}"></view>
<view class="date-month-day">{{ formatDate(date).month }}-{{ formatDate(date).day }}</view>
<view class="date-month-day">{{ formatDate(props.date).month }}-{{ formatDate(props.date).day }}</view>
</view>
<view class="status-tag" :class="{'status-tag-pending': status}">
<view class="status-tag" :class="{'status-tag-pending': props.status}">
<image src="/static/images/ydd/icon1.png"
mode="aspectFit"
@ -23,19 +23,19 @@
</view>
<!-- 空状态显示 -->
<view v-if="!processedList || processedList.length === 0" class="empty-state">
<view v-if="!props.list || props.list.length === 0" class="empty-state">
<text class="empty-text">暂无订单数据</text>
</view>
<!-- 时间线主体 -->
<view v-else class="timeline-body" v-for="(item, index) in processedList" :key="index">
<view v-else class="timeline-body" v-for="(item, index) in props.list" :key="index">
<view class="timeline-line"></view>
<view class="time-point">
<view class="time-icon">
<image src="/static/images/order/address.png" mode="aspectFit" class="time-image"></image>
</view>
<view class="time-text">{{ item.address }}</view>
<view class="time-text">{{ item.receiverCity }}</view>
<view class="collapse-icon" @click="toggleServiceCard(index)">
{{ serviceCardCollapsed[index] ? '展开' : '收起' }} <text class="arrow" :class="{'arrow-up': !serviceCardCollapsed[index]}"></text>
</view>
@ -50,8 +50,8 @@
<text>服务日期</text>
<text style="margin-left: auto;font-weight: 500;font-size: 24rpx;">订单编号{{ item.orderId }}</text>
</view>
<view class="section-content date-content" :class="{bgSuccessQ : item.status}">
{{ item.fullDate }}
<view class="section-content date-content" :class="{bgSuccessQ : item.status == '2'}">
{{ dayjs(item.serviceDate).format('YYYY/MM/DD') }}
</view>
</view>
@ -64,10 +64,10 @@
{{ petListCollapsed[index] ? '展开' : '收起' }} <text class="arrow" :class="{'arrow-up': !petListCollapsed[index]}"></text>
</view>
</view>
<view class="section-content pet-list" :class="{bgSuccessQ : item.status}" v-if="!petListCollapsed[index]">
<view v-for="(pet, i) in item.petList" :key="i" class="pet-item">
<view class="section-content pet-list" :class="{bgSuccessQ : item.status == '2'}" v-if="!petListCollapsed[index]">
<view v-for="(pet, i) in item.pets" :key="i" class="pet-item">
<view class="pet-avatar">
<image :src="pet.avatar" mode="aspectFill" class="avatar-image"></image>
<image :src="pet.photo" mode="aspectFill" class="avatar-image"></image>
</view>
<view class="pet-info">
<view class="pet-name">
@ -77,7 +77,7 @@
</text>
</view>
<view class="pet-description">
{{ pet.breed }}{{ pet.bodyType }} | {{ pet.services.join('+') }}
{{ pet.breed }}{{ pet.bodyType }} | {{ pet.orderItemList.map(n => n.productName).join(',') }}
</view>
</view>
</view>
@ -90,16 +90,16 @@
<view class="title-indicator"></view>
<text>上门地址</text>
</view>
<view class="section-content address-content" :class="{bgSuccessQ : item.status}">
{{ item.addressDetail }}
<view class="section-content address-content" :class="{bgSuccessQ : item.status == '2'}">
{{ item.receiverDetailAddress }}
</view>
</view>
<!-- 操作按钮 -->
<view class="action-buttons">
<view class="btn btn-clock" :class="{bgSuccess : item.status}" @click="handleClock(item)">{{ item.status ? '打卡记录' : '打卡' }}</view>
<view class="btn btn-clock" :class="{bgSuccess : item.status}" @click="handlePetFile(item)">宠物档案</view>
<view class="btn btn-clock" :class="{bgSuccess : item.status}" @click="handleServiceFile(item)">服务档案</view>
<view class="btn btn-clock" :class="{bgSuccess : item.status == '2'}" @click="handleClock(item)">{{ '打卡' }}</view>
<view class="btn btn-clock" :class="{bgSuccess : item.status == '2'}" @click="handlePetFile(item)">宠物档案</view>
<view class="btn btn-clock" :class="{bgSuccess : item.status == '2'}" @click="handleServiceFile(item)">服务档案</view>
</view>
</view>
</view>
@ -109,6 +109,8 @@
<script setup>
import { ref, computed } from 'vue';
import { getOrderServiceText, getProductNameText } from '@/utils/serviceTime.js';
import dayjs from 'dayjs';
import list from '../../../uni_modules/uview-plus/components/u-list/list';
//
const props = defineProps({
@ -167,75 +169,18 @@
};
};
//
const processedList = computed(() => {
return props.list.map(order => {
//
const petList = [];
let orderId = 0
let serviceId = 0
let status = 1
if (order.appletOrderItemDate && order.appletOrderItemDate.length > 0) {
order.appletOrderItemDate.forEach(item => {
if (item.orderServiceList && item.orderServiceList.petVo) {
const pet = item.orderServiceList.petVo;
const services = [];
//
if (item.orderItemList && item.orderItemList.length > 0) {
item.orderItemList.forEach(orderItem => {
services.push(orderItem.productName);
orderId = orderItem.orderId
});
}
serviceId = item.id
if(item.status == 0){
status = 0
}
petList.push({
name: pet.name,
serviceId : item.id,
gender: pet.gender === '男生' ? 'male' : 'female',
breed: pet.breed,
bodyType: `(${pet.bodyType})`,
services: services,
avatar: pet.photo || (pet.petType === 'dog' ? '/static/images/ydd/dog.png' : '/static/images/ydd/cat.png')
});
}
});
}
return {
id: order.orderId,
orderId,
serviceId,
status,
address: order.cityAddress,
addressDetail: order.address,
fullDate: props.date.replace(/-/g, '/'),
petList: petList
};
});
});
//
const handleClock = (item) => {
console.log(item);
//
const paths = [
`/otherPages/myOrdersManage/clock/index?id=${item.orderId}&itemID=${item.id}&serviceId=${item.serviceId}`,
`/otherPages/myOrdersManage/clock/index?isRead=true&id=${item.orderId}&itemID=${item.id}`,
`/otherPages/myOrdersManage/clock/index?id=${item.id}`,
];
uni.navigateTo({
url: props.status ? paths[0] : paths[1]
url: `/otherPages/myOrdersManage/clock/index?id=${item.id}`,
});
};
@ -246,9 +191,6 @@
};
const handleServiceFile = (item) => {
uni.navigateTo({
url: "/otherPages/myOrdersManage/service/index?id=" + item.orderId
});


+ 34
- 10
pages/myOrdersManage/index.vue View File

@ -53,10 +53,9 @@
<timelineService
v-for="(item,index) in dateOrderList"
:key="index"
:date="item.serviceDate"
:orderCount="item.num"
:status="current === 0"
:list="item.orderList"
:date="item.date"
:status="current == 0"
:list="item.list"
:current="current"
/>
</view>
@ -93,8 +92,11 @@
myList
} from "@/api/receivingHall/index.js"
import {
getOrderDateList
getOrderDateList,
} from "@/api/order/order.js"
import {
appletOrderDateFrequencyList,
} from "@/api/order/frequency.js"
import {
useStore
} from "vuex"
@ -181,17 +183,18 @@ import { getOrderServiceText, getProductNameText } from '@/utils/serviceTime.js'
})
}else{
dateOrderList.value = []
getOrderDateList({
status: index,
userId: userInfo.value.userId
})
appletOrderDateFrequencyList({
status: index == 0 ? '0,1' : '2',
masterId: userInfo.value.userId
})
.then(res => {
if (res.code == 200) {
dateOrderList.value = res.data
//
let totalOrders = 0;
dateOrderList.value.forEach(item => {
totalOrders += item.num || 0;
totalOrders += item.list.length || 0;
});
tabList2[index].badge.value = totalOrders;
}
@ -201,6 +204,27 @@ import { getOrderServiceText, getProductNameText } from '@/utils/serviceTime.js'
loading.value = false; //
}
})
// getOrderDateList({
// status: index,
// userId: userInfo.value.userId
// })
// .then(res => {
// if (res.code == 200) {
// dateOrderList.value = res.data
// //
// let totalOrders = 0;
// dateOrderList.value.forEach(item => {
// totalOrders += item.num || 0;
// });
// tabList2[index].badge.value = totalOrders;
// }
// })
// .finally(() => {
// if(activeIndex.value == 2){
// loading.value = false; //
// }
// })
}
}


+ 2
- 2
pages/workbenchManage/index.vue View File

@ -64,11 +64,11 @@
<view>{{ item.name }}</view>
</view>
<view class="icon-list"@click="handleGoto1()">
<!-- <view class="icon-list"@click="handleGoto1()">
<up-image class="mb20" :show-loading="true" width="68rpx"
height="68rpx"></up-image>
<view>123</view>
</view>
</view> -->
</view>
</view>
</view>


+ 4
- 3
utils/getUrl.js View File

@ -1,11 +1,12 @@
let current = "release";
let current = "develop";
const accountInfo = wx.getAccountInfoSync();
// current = accountInfo.miniProgram.envVersion;
const api = {
develop:"http://h5.xzaiyp.top",
develop:"http://127.0.0.1:8002",
// develop:"http://h5.xzaiyp.top",
// develop:"https://api.catmdogd.com/prod-api",
// develop:"http://pet-admin.hhlm1688.com/api",
// develop:"https://pet-admin.hhlm1688.com/api",
// develop: "http://youyi-test.natapp1.cc/prod-api", // 开发
trial: "https://api.catmdogd.com/prod-api", //测试
release: "https://api.catmdogd.com/prod-api",


Loading…
Cancel
Save