You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
crmeb/app/pages/supply_chain/repair_handle/index.vue

368 lines
8.7 KiB

<template>
<z-paging ref="paging" v-model="records" @query="queryList">
<!-- 故障列表 -->
<view class="record-list">
<view
class="record-card"
v-for="item in records"
:key="item.id"
>
<view class="card-header">
<view class="left">
<text class="type">
{{ item.houseName || '报修单' }}
</text>
<text
class="status"
:class="statusClassMap[item.status] || statusClassMap['__default__']"
>
{{ statusText(item.status, item.remark) }}
</text>
</view>
<view class="header-right">
<text class="time">
{{ item.reportTime || item.createTime || '' }}
</text>
</view>
</view>
<view class="card-body">
<view class="row" v-if="item.faultType">
<text class="label">故障类型</text>
<text class="value">
{{ getFaultTypeLabel(item.faultType) }}
</text>
</view>
<view class="row" v-if="item.faultDesc">
<text class="label">报修内容</text>
<text class="value">
{{ item.faultDesc }}
</text>
</view>
<view class="image-section" v-if="item.files && item.files.length">
<text class="image-title">故障图片</text>
<view class="image-grid">
<view
class="image-item"
v-for="(file, imgIndex) in item.files"
:key="imgIndex"
@click="previewRecordImages(item.files, imgIndex)"
>
<image
:src="HTTP_ADMIN_URL + '/' + (file.url || file.attDir)"
mode="aspectFill"
></image>
</view>
</view>
</view>
<view
class="image-section"
v-if="item.afterProcessFiles && item.afterProcessFiles.length"
>
<text class="image-title">处理结果图片</text>
<view class="image-grid">
<view
class="image-item"
v-for="(file, imgIndex) in item.afterProcessFiles"
:key="imgIndex"
@click="previewRecordImages(item.afterProcessFiles, imgIndex)"
>
<image
:src="HTTP_ADMIN_URL + '/' + (file.url || file.attDir)"
mode="aspectFill"
></image>
</view>
</view>
</view>
</view>
<!-- 操作按钮 -->
<view class="card-footer">
<text class="action-btn dispatch-btn" @click="goDispatch(item)">查看派单</text>
<text class="action-btn handle-btn" v-if="checkPermi('send_order') && item.status !== '99'" @click="openFinishPopup(item)">去办结</text>
</view>
</view>
</view>
</z-paging>
</template>
<script>
import { listMaintenanceOrder, updateMaintenanceOrderStatus } from '@/api/property.js';
import { HTTP_ADMIN_URL } from '@/config/app';
import { checkPermi } from '@/utils/auth/permission.js';
export default {
dicts: ['fault_type'],
data() {
return {
checkPermi,
HTTP_ADMIN_URL,
records: [],
statusClassMap: {
0: 'status-pending',
1: 'status-doing',
2: 'status-done',
99: 'status-done',
'__default__': 'status-pending'
}
};
},
onLoad() {
// 页面加载时自动刷新列表
},
methods: {
// 获取故障列表
queryList(pageNo, pageSize) {
listMaintenanceOrder({
page: pageNo,
limit: pageSize,
uid: '',
}).then((res) => {
const list = res?.data?.list || [];
this.$refs.paging.complete(list);
}).catch((err) => {
console.error('获取故障列表失败:', err);
this.$refs.paging.complete(false);
});
},
// 状态文本
statusText(status, remark) {
if (status === 0 || status === '0') return '待处理';
if (status === 1 || status === '1') return '处理中';
if (status === 2 || status === '2') return '已处理';
if (status === 99 || status === '99') return remark || '已撤销';
return '待处理';
},
// 获取故障类型标签
getFaultTypeLabel(value) {
const types = this.dict.get('fault_type');
if (types) {
const type = types.find(t => t.dictValue === value);
return type ? type.dictLabel : value;
}
return value;
},
// 预览图片
previewRecordImages(files, index) {
if (!files || !files.length) return;
const urls = files.map(file => {
const path = file.url || file.attDir || file.filePath;
return this.HTTP_ADMIN_URL + '/' + path;
});
uni.previewImage({
current: index,
urls
});
},
// 跳转到派单页面
goDispatch(item) {
uni.navigateTo({
url: `/pages/supply_chain/dispatch/index?orderId=${item.id}&status=${item.status}`
});
},
// 打开办结弹窗
openFinishPopup(item) {
uni.showModal({
title: '办结',
editable: true,
placeholderText: '已办结',
content: '已办结',
success: async (res) => {
if (res.confirm) {
const remark = res.content || '已办结';
await this.handleFinish(item, remark);
}
}
});
},
// 处理办结
async handleFinish(item, remark) {
try {
uni.showLoading({ title: '提交中...', mask: true });
await updateMaintenanceOrderStatus({
id: item.id,
status: '99',
remark: remark
});
uni.showToast({ title: '办结成功', icon: 'success' });
this.$refs.paging.reload();
} catch (e) {
console.error('办结失败:', e);
uni.showToast({ title: typeof e === 'string' ? e : '办结失败', icon: 'none' });
} finally {
uni.hideLoading();
}
}
}
};
</script>
<style lang="scss">
.page {
min-height: 100vh;
background: #f6f7fb;
padding: 24rpx;
}
.tabs {
display: flex;
background: #fff;
border-radius: 16rpx;
padding: 8rpx;
margin-bottom: 20rpx;
.tab {
flex: 1;
text-align: center;
padding: 20rpx 0;
font-size: 28rpx;
color: #6b7280;
border-radius: 12rpx;
&.active {
background: #3b82f6;
color: #fff;
font-weight: 600;
}
}
}
.record-list {
padding: 0 4rpx;
}
.record-card {
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.06);
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16rpx;
.left {
display: flex;
align-items: center;
.type {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-right: 16rpx;
max-width: 280rpx;
}
.status {
padding: 6rpx 18rpx;
border-radius: 20rpx;
font-size: 22rpx;
}
.status-pending {
background-color: #E6F7FF;
color: #409EFF;
}
.status-doing {
background-color: #FFF7E6;
color: #FA8C16;
}
.status-done {
background-color: #F6FFED;
color: #52C41A;
}
}
.header-right {
.time {
font-size: 22rpx;
color: #999;
}
}
}
.card-body {
.row {
display: flex;
margin-bottom: 10rpx;
.label {
width: 160rpx;
font-size: 24rpx;
color: #666;
}
.value {
flex: 1;
font-size: 24rpx;
color: #333;
}
}
.image-section {
margin-top: 12rpx;
.image-title {
display: block;
font-size: 22rpx;
color: #666;
margin-bottom: 10rpx;
}
.image-grid {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
.image-item {
width: calc((100% - 24rpx) / 3);
aspect-ratio: 1 / 1;
border-radius: 8rpx;
overflow: hidden;
background-color: #f5f5f5;
image {
width: 100%;
height: 100%;
}
}
}
}
}
.card-footer {
display: flex;
justify-content: flex-end;
gap: 20rpx;
margin-top: 20rpx;
padding-top: 20rpx;
border-top: 1rpx solid #f0f0f0;
.action-btn {
padding: 12rpx 32rpx;
border-radius: 24rpx;
font-size: 26rpx;
font-weight: 500;
}
.dispatch-btn {
background: #E6F7FF;
color: #409EFF;
}
.handle-btn {
background: #F6FFED;
color: #52C41A;
}
}
}
</style>