306 lines
8.0 KiB
Vue
306 lines
8.0 KiB
Vue
![]() |
<template>
|
|||
|
<view class="order-card" @click="handleDetail">
|
|||
|
<view class="order-header">
|
|||
|
<image :src="parseLocalUrl(task.userAvatar)" class="avatar"/>
|
|||
|
<view class="user-info">
|
|||
|
<text class="user-name">{{ task.createName | dv}}</text>
|
|||
|
</view>
|
|||
|
<view :class="['order-status', getStatusClass(task.status)]">
|
|||
|
{{ TaskStatus.parseNameForUser(task.status) | dv}}
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view class="order-body">
|
|||
|
<view class="order-row"><text>下单时间:</text>{{ task.createTime | dv}}</view>
|
|||
|
<view class="order-row"><text>订单编号:</text>{{ task.no | dv}}</view>
|
|||
|
<view class="order-row"><text>任务类型:</text>{{ TaskType.parseName(task.type) | dv}}</view>
|
|||
|
<view class="order-row"><text>完善信息:</text>
|
|||
|
<text class="text-success" v-if="task.carId">已完善</text>
|
|||
|
<text class="text-danger" v-else>未完善</text>
|
|||
|
</view>
|
|||
|
<template v-if="showMore">
|
|||
|
<view class="order-row phone-row" @click.stop="handleCall">
|
|||
|
<text>手机联系:</text>
|
|||
|
<view class="phone-content">
|
|||
|
<text class="phone-number">{{ task.createMobile | dv}}</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view class="order-row"><text>下单地址:</text>{{ task.createAddress | dv}}</view>
|
|||
|
</template>
|
|||
|
</view>
|
|||
|
<!-- 商户模式下显示操作按钮 -->
|
|||
|
<view v-if="mode === 'mch'" class="order-actions">
|
|||
|
<button class="accept-btn" v-if="TaskStatus.canReceive().includes(task.status)" @click.stop="handleReceive">¥{{ task.receiveAmount | fix2 | dv}} 立即接单</button>
|
|||
|
<button class="accept-btn" v-if="TaskStatus.canComplete().includes(task.status)" @click.stop="handleComplete">完成任务</button>
|
|||
|
</view>
|
|||
|
<!-- 用户模式下显示操作按钮 -->
|
|||
|
<view v-if="mode === 'user'" class="order-actions">
|
|||
|
<button class="accept-btn" v-if="task.mchId" @click.stop="handleContact">联系客服</button>
|
|||
|
<button class="accept-btn" v-if="TaskStatus.canCancel().includes(task.status)" @click.stop="handleCancel">取消任务</button>
|
|||
|
<button class="accept-btn" v-if="TaskStatus.CANCEL === task.status" @click.stop="handleReorder">重新下单</button>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
import { TaskType, TaskStatus } from '@/utils/enums';
|
|||
|
import { parseLocalUrl } from '@/utils/index';
|
|||
|
import { mchReceiveTask, mchCompleteTask } from '@/api/mch/task';
|
|||
|
import { appCancelTask } from '@/api/app/task';
|
|||
|
import { mapGetters } from 'vuex';
|
|||
|
|
|||
|
export default {
|
|||
|
name: 'TaskCard',
|
|||
|
props: {
|
|||
|
task: {
|
|||
|
type: Object,
|
|||
|
required: true
|
|||
|
},
|
|||
|
mode: {
|
|||
|
type: String,
|
|||
|
default: 'user'
|
|||
|
},
|
|||
|
preview: {
|
|||
|
type: Boolean,
|
|||
|
default: false
|
|||
|
}
|
|||
|
},
|
|||
|
data() {
|
|||
|
return {
|
|||
|
TaskType,
|
|||
|
TaskStatus
|
|||
|
}
|
|||
|
},
|
|||
|
computed: {
|
|||
|
...mapGetters(['mchId', 'userId']),
|
|||
|
showMore() {
|
|||
|
return this.mode === 'user' || this.task.mchId === this.mchId;
|
|||
|
}
|
|||
|
},
|
|||
|
methods: {
|
|||
|
handleReorder() {
|
|||
|
uni.navigateTo({ url: `/pages/task/edit?sourceId=${this.task.id}` })
|
|||
|
},
|
|||
|
handleContact() {
|
|||
|
uni.navigateTo({ url: `/pages/mchCustom/index?mchId=${this.task.mchId}&mode=user` })
|
|||
|
},
|
|||
|
parseLocalUrl,
|
|||
|
getStatusClass(status) {
|
|||
|
switch (status) {
|
|||
|
case TaskStatus.WAIT_RECEIVE:
|
|||
|
return 'status-waiting';
|
|||
|
case TaskStatus.RECEIVED:
|
|||
|
return 'status-received';
|
|||
|
case TaskStatus.FINISHED:
|
|||
|
return 'status-finished';
|
|||
|
case TaskStatus.CANCEL:
|
|||
|
return 'status-cancel';
|
|||
|
case TaskStatus.AFTER_SALE:
|
|||
|
return 'status-after-sale';
|
|||
|
default:
|
|||
|
return '';
|
|||
|
}
|
|||
|
},
|
|||
|
handleDetail() {
|
|||
|
this.$emit('detail', this.task.id);
|
|||
|
},
|
|||
|
handleReceive() {
|
|||
|
uni.showModal({
|
|||
|
title: '提示',
|
|||
|
content: '确定要接单吗?',
|
|||
|
confirmText: '确认',
|
|||
|
cancelText: '取消',
|
|||
|
success: (res) => {
|
|||
|
if (res.confirm) {
|
|||
|
const params = { id: this.task.id, mchId: this.$store.getters.mchId };
|
|||
|
mchReceiveTask(params).then(res => {
|
|||
|
if (res.code === 200) {
|
|||
|
uni.showToast({ title: '接单成功', icon: 'success' });
|
|||
|
this.$emit('refresh');
|
|||
|
} else {
|
|||
|
uni.showToast({ title: res.msg || '操作失败', icon: 'none' });
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
},
|
|||
|
handleComplete() {
|
|||
|
uni.showModal({
|
|||
|
title: '提示',
|
|||
|
content: '确定要完成任务吗?',
|
|||
|
confirmText: '确认',
|
|||
|
cancelText: '取消',
|
|||
|
success: (res) => {
|
|||
|
if (res.confirm) {
|
|||
|
const params = { id: this.task.id };
|
|||
|
mchCompleteTask(params).then(res => {
|
|||
|
if (res.code === 200) {
|
|||
|
uni.showToast({ title: '完成成功', icon: 'success' });
|
|||
|
this.$emit('refresh');
|
|||
|
} else {
|
|||
|
uni.showToast({ title: res.msg || '操作失败', icon: 'none' });
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
},
|
|||
|
handleCancel() {
|
|||
|
uni.showModal({
|
|||
|
title: '提示',
|
|||
|
content: '确定要取消任务吗?',
|
|||
|
confirmText: '确认',
|
|||
|
cancelText: '取消',
|
|||
|
success: (res) => {
|
|||
|
if (res.confirm) {
|
|||
|
const params = { id: this.task.id };
|
|||
|
appCancelTask(params).then(res => {
|
|||
|
if (res.code === 200) {
|
|||
|
uni.showToast({ title: '取消成功', icon: 'success' });
|
|||
|
this.$emit('refresh');
|
|||
|
} else {
|
|||
|
uni.showToast({ title: res.msg || '操作失败', icon: 'none' });
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
})
|
|||
|
},
|
|||
|
handleCall() {
|
|||
|
if (this.task.createMobile) {
|
|||
|
uni.makePhoneCall({
|
|||
|
phoneNumber: this.task.createMobile,
|
|||
|
success: () => {
|
|||
|
console.log('拨打电话成功');
|
|||
|
},
|
|||
|
fail: (err) => {
|
|||
|
console.error('拨打电话失败', err);
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang="scss" scoped>
|
|||
|
.order-card {
|
|||
|
background: #fff;
|
|||
|
border-radius: 16rpx;
|
|||
|
margin-top: 24rpx;
|
|||
|
margin-bottom: 0;
|
|||
|
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04);
|
|||
|
padding: 24rpx;
|
|||
|
}
|
|||
|
.order-header {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
margin-bottom: 16rpx;
|
|||
|
}
|
|||
|
.avatar {
|
|||
|
width: 64rpx;
|
|||
|
height: 64rpx;
|
|||
|
border-radius: 50%;
|
|||
|
margin-right: 16rpx;
|
|||
|
background: #eee;
|
|||
|
}
|
|||
|
.user-info {
|
|||
|
flex: 1;
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
}
|
|||
|
.user-name {
|
|||
|
font-size: 32rpx;
|
|||
|
font-weight: bold;
|
|||
|
color: #333;
|
|||
|
}
|
|||
|
.order-status {
|
|||
|
font-size: 26rpx;
|
|||
|
padding: 4rpx 16rpx;
|
|||
|
border-radius: 24rpx;
|
|||
|
font-weight: 500;
|
|||
|
|
|||
|
&.status-waiting {
|
|||
|
color: #E6A23C;
|
|||
|
background-color: #fdf6ec;
|
|||
|
}
|
|||
|
|
|||
|
&.status-received {
|
|||
|
color: #409EFF;
|
|||
|
background-color: #ecf5ff;
|
|||
|
}
|
|||
|
|
|||
|
&.status-finished {
|
|||
|
color: #67C23A;
|
|||
|
background-color: #f0f9eb;
|
|||
|
}
|
|||
|
|
|||
|
&.status-cancel {
|
|||
|
color: #909399;
|
|||
|
background-color: #f4f4f5;
|
|||
|
}
|
|||
|
|
|||
|
&.status-after-sale {
|
|||
|
color: #F56C6C;
|
|||
|
background-color: #fef0f0;
|
|||
|
}
|
|||
|
}
|
|||
|
.order-body {
|
|||
|
font-size: 28rpx;
|
|||
|
color: #444;
|
|||
|
.order-row {
|
|||
|
display: flex;
|
|||
|
justify-content: space-between;
|
|||
|
align-items: flex-start;
|
|||
|
text-align: right;
|
|||
|
line-height: 2em;
|
|||
|
.text-success {
|
|||
|
color: #67C23A;
|
|||
|
}
|
|||
|
.text-danger {
|
|||
|
color: #F56C6C;
|
|||
|
}
|
|||
|
text {
|
|||
|
flex-shrink: 0;
|
|||
|
color: #999;
|
|||
|
}
|
|||
|
}
|
|||
|
.phone-row {
|
|||
|
cursor: pointer;
|
|||
|
.phone-content {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
gap: 8rpx;
|
|||
|
.phone-number {
|
|||
|
color: #007aff;
|
|||
|
font-weight: 500;
|
|||
|
text-decoration: underline;
|
|||
|
}
|
|||
|
.icon-phone {
|
|||
|
color: #007aff;
|
|||
|
font-size: 32rpx;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
.order-actions {
|
|||
|
display: flex;
|
|||
|
justify-content: flex-end;
|
|||
|
gap: 24rpx;
|
|||
|
margin-top: 16rpx;
|
|||
|
width: 100%;
|
|||
|
}
|
|||
|
.accept-btn {
|
|||
|
background: #007aff;
|
|||
|
color: #fff;
|
|||
|
border-radius: 40rpx;
|
|||
|
font-size: 28rpx;
|
|||
|
padding: 0 40rpx;
|
|||
|
height: 64rpx;
|
|||
|
line-height: 64rpx;
|
|||
|
border: none;
|
|||
|
width: fit-content;
|
|||
|
margin: 0;
|
|||
|
}
|
|||
|
</style>
|