Files
SmartParks_uniapp/pages/sys/workbench/order/orderDetail.vue
liyuanchao 85a1ce799a
Some checks failed
Uniapp 自动化打包 CI/CD / 打包 Uniapp 项目 (push) Failing after 56s
工单
2025-08-26 17:31:30 +08:00

263 lines
9.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-container">
<view class="top-line" />
<view class="item-bg"><text class="detail-key">工单编号</text>{{ detail.orderNo }}</view>
<view class="item-bg">
<view class="item-title">上报人信息</view>
<view class="detail-key">发起人{{ detail.initiatorPeople }}</view>
<view class="detail-key">联系电话{{ detail.initiatorPhone }}</view>
</view>
<view class="item-bg">
<view class="item-title">保修信息</view>
<view class="detail-key">工单名称{{ detail.orderName }}</view>
<view class="detail-key">工单类型{{ detail.typeName }}</view>
<view class="detail-key">处理地点{{ detail.location }}</view>
<view class="detail-key">备注{{ detail.remark }}</view>
<view class="detail-value"><text class="detail-key">工单图片</text></view>
<view class="image-list" v-if="orderImgUrls.length > 0">
<u-image
v-for="(imgUrl, index) in orderImgUrls"
:key="index"
:src="imgUrl"
width="200rpx"
height="200rpx"
border-radius="10rpx"
@click="previewImage(orderImgUrls, index)"
style="margin-right: 20rpx; margin-bottom: 20rpx;"
mode="aspectFill"
></u-image>
</view>
</view>
<view v-if="detail.status>1" class="item-bg">
<view class="item-title">负责人信息</view>
<view class="detail-key">负责人{{ detail.handlerText }}</view>
<view class="detail-key">联系电话{{ detail.handlerPhone }}</view>
</view>
<!-- 纵向进度条 -->
<view class="item-bg">
<view class="item-title">进度跟踪</view>
<view v-for="(status, index) in detail.recordVoList" :key="index" class="repair-detail-step">
<view class="step-left">
<text class="step-date">{{ status.createTime.substring(0,11)}}</text>
<text class="step-time">{{ status.createTime.substring(11,16) }}</text>
</view>
<view class="step-dot-container">
<view class="repair-detail-dot" ></view>
<!-- 固定高度连线 -->
<view
v-if="index < detail.recordVoList.length - 1" class="repair-detail-line"
></view>
</view>
<view class="step-right">
<text class="step-name">{{ getStatusLabel(status.status) }}</text>
</view>
</view>
</view>
<!-- 底部操作按钮 -->
<view
v-if="((!isManager && detailStep != 0) || (isManager && detailStep == 0)) && detailStep != 3&&!isNaomalUser"
class="btn-group">
<button class="btn ghost"
@click="transfer(1)">{{ isManager ? '指派' : (detailStep == 2 ? '完成' : '开始') }}</button>
<button v-if="detailStep == 1" class="btn primary" @click="transfer(2)">转派</button>
</view>
<view class="kg">
</view>
<SelectUser :visible.sync="showSelect" :list="users" :multiple="false" @confirm="onConfirm" />
</view>
</template>
<script>
import SelectUser from '@/components/SelectUser.vue'
export default {
components: { SelectUser },
data() {
return {
detailStep: 0,
detailStatus: '',
currentStatus: 2,
detail: {},
isManager: false,
isNaomalUser:true,
showSelect: false,
users: [],
orderImgUrls: []
};
},
onLoad(options) {
this.isManager = this.vuex_user?.roles?.[0]?.roleId < 3
this.isNaomalUser = this.vuex_user?.roles?.[0]?.roleId >10
if (options.item) {
const item = JSON.parse(decodeURIComponent(options.item));
this.detail = item;
this.getStepInfo()
this.getImageUrl()
}
if ((this.isManager && this.detailStep == 0) || (!this.isManager && this.detailStep == 1)) {
this.getHandler()
}
},
methods: {
goBack() { uni.navigateBack(); },
async getImageUrl() {
if (!this.detail.orderImgUrl) return;
const imgIds = this.detail.orderImgUrl.split(',');
const res = await this.$u.api.getImageUrl({}, imgIds.join(','));
if (res.code == 200 && res.data) this.orderImgUrls = res.data.map(item => item.url);
},
async getHandler() {
let handlers = await this.$u.api.getHandler3({}, this.detail.type);
if (handlers.code === 200) this.users = [...this.users, ...handlers.data];
},
getStepInfo() {
let currentIndex = 0;
if (this.detail.status == 0) currentIndex = 0;
else if (this.detail.status == 1) currentIndex = 1;
else if (this.detail.status == 3) currentIndex = 2;
else if (this.detail.status == 4) currentIndex = 3;
this.detailStep = currentIndex;
},
getStatusLabel(status) {
const statusMap = {
0: "创建工单",
1: "已接单",
2: "已接单",
3: "处理中",
4: "已完成",
};
return statusMap[status] || "";
},
previewImage(urls, index) {
const validUrls = urls.filter(url => url && url.trim() !== '');
const currentIndex = validUrls.indexOf(urls[index]);
uni.previewImage({
urls: validUrls,
current: currentIndex >= 0 ? currentIndex : 0,
indicator: 'number',
backgroundColor: '#000'
})
},
async onConfirm(selected) {
let params = this.detail
params.handler = selected[0].value
params.status = 1
let res = await this.$u.api.updateOrder2(params);
if (res.code == '200') {
uni.$emit('refreshData', '');
if(!this.isManager){
uni.navigateBack();
return
}
this.detail.handler = selected.value
this.detail.status = 1
const d = new Date();
const z = n => n.toString().padStart(2, '0');
let time = `${d.getFullYear()}-${z(d.getMonth()+1)}-${z(d.getDate())} ${z(d.getHours())}:${z(d.getMinutes())}:${z(d.getSeconds())}`;
let step = {}
step.id= this.detail.recordVoList[0].id,
step.orderId= this.detail.recordVoList[0].orderId,
step.status= '1',
step.handler='',
step.handlerName='',
step.createTime= time
this.detail.recordVoList.push(step)
this.getStepInfo()
}
},
async submit() {
let params = this.detail
if (this.detail.status == 1 || this.detail.status == 2) params.status = 3
else params.status = 4
let res = await this.$u.api.updateOrder2(params);
if (res.code == 200) {
uni.$emit('refreshData', '');
this.detail.status = params.status
if(params.status ==3){
this.detail.handlerText = this.vuex_user.nickName
this.detail.handlerPhone = this.vuex_user.phonenumber
}
const d = new Date();
const z = n => n.toString().padStart(2, '0');
let time = `${d.getFullYear()}-${z(d.getMonth()+1)}-${z(d.getDate())} ${z(d.getHours())}:${z(d.getMinutes())}:${z(d.getSeconds())}`;
let step = {}
step.id= this.detail.recordVoList[0].id,
step.orderId= this.detail.recordVoList[0].orderId,
step.status= params.status,
step.handler='',
step.handlerName='',
step.createTime= time
this.detail.recordVoList.push(step)
this.getStepInfo()
}
},
transfer(type) {
if (this.isManager || type == 2) this.showSelect = true
else this.submit()
}
}
}
</script>
<style scoped>
.page-container { background: #f7f7f7; height: 100vh; }
.top-line { width: 100vw; height: 3rpx; background: #ECECEC; }
.item-bg{ background: #fff; border-radius: 20rpx; margin-top: 10px; margin-left: 25rpx; margin-right: 25rpx; padding: 25rpx; }
.item-title{ color: #000; font-size: 28rpx; font-weight: 600; margin-bottom: 20rpx; }
.repair-detail-step-container { display: flex; flex-direction: column; }
.repair-detail-step {
display: flex;
flex-direction: row;
margin-bottom: 20rpx;
}
.step-left { flex: 1; display: flex; flex-direction: column; align-items: flex-end; padding-right: 20rpx; }
.step-date { font-size: 24rpx; color: #333; }
.step-time { font-size: 24rpx; color: #666; margin-top: 10rpx; }
.step-dot-container {
display: flex;
flex-direction: column;
align-items: center;
width: 40rpx;
}
.repair-detail-dot {
width: 22rpx;
height: 22rpx;
border-radius: 50%;
background: #BDBDBD;
border: 2rpx solid #BDBDBD;
z-index: 2;
background: #2186FF;
border-color: #2186FF;
}
/* 固定高度连线 */
.repair-detail-line {
width: 4rpx;
height: 80rpx; /* 每条线的高度 */
background: #BDBDBD;
margin-top: 2rpx;
background: #2186FF;
}
.step-right { flex: 1; display: flex; flex-direction: column; padding-left: 20rpx; }
.step-name { font-size: 28rpx; color: #333; font-weight: bold; margin-bottom: 6rpx; }
.step-desc { font-size: 24rpx; color: #666; }
.detail-key { color: #222; font-size: 28rpx; margin-bottom: 20rpx; }
.detail-value { margin-bottom: 30rpx; color: #2F2F2F; }
.image-list { display: flex; flex-wrap: wrap; margin-top: 20rpx; }
.btn-group { display: flex; justify-content: space-around; margin-top: 60rpx; }
.btn { width: 276rpx; height: 88rpx; padding: 20rpx; font-size: 30rpx; border-radius: 50rpx; display: flex; align-items: center; justify-content: center; }
.primary { background-color: #1890ff; color: #fff; }
.ghost { background-color: #fff; color: #1890ff; border: 2rpx solid #1890ff; }
.kg{
height: 60rpx;
}
</style>