<route lang="json5" type="page">
|
{
|
layout: 'default',
|
needLogin: true,
|
style: { navigationBarTitleText: '保养工单', navigationStyle: 'custom' },
|
}
|
</route>
|
|
<template>
|
<z-paging
|
ref="paging"
|
v-model="dataList"
|
@query="queryList"
|
:auto="false"
|
show-refresher-update-time
|
>
|
<template #top>
|
<wd-navbar
|
title="保养工单"
|
left-arrow
|
@click-left="goBack"
|
right-text="提交"
|
@click-right="handleClickRight"
|
custom-style="background: #4D80F0;"
|
safeAreaInsetTop
|
>
|
<template #right>
|
<text v-if="isOperatorOrRepair()" class="text-white">提交</text>
|
</template>
|
</wd-navbar>
|
<wd-cell>
|
<template #title>
|
<text class="text-color-gray">设备</text>
|
</template>
|
</wd-cell>
|
<view class="h-[2px] w-full bg-base"></view>
|
<wd-card type="rectangle">
|
<template #title>
|
<view class="flex justify-between">
|
<view class="flex items-center menu-title-box">
|
<view class="menu-indicator"></view>
|
<view class="ml-1 text-lg align-center">{{ maintSt.equName }}</view>
|
<view class="text-color-gray ml-2 text-sm">{{ maintSt.assetNo }}</view>
|
</view>
|
|
<view class="flex items-center">
|
<text class="text-color-gray text-sm">{{ maintSt.planTime }}</text>
|
</view>
|
</view>
|
</template>
|
<view class="flex h-[140rpx]" items-center>
|
<image class="slot-img text-center" src="/static/images/camera.png" />
|
<view class="flex-1">
|
<view class="text-color-gray text-sm mt-1 flex">
|
<text class="mr-3">工单总数: {{ maintSt.orderCount }}</text>
|
|
|
<text class="mx-3">已完成: {{ maintSt.wcCount }}</text>
|
</view>
|
<view class="text-color-gray text-sm mt-2 flex">
|
<text class="mr-3">待保养: {{ maintSt.dbyCount }}</text>
|
|
|
<text class="mx-3">保养中: {{ maintSt.byCount }}</text>
|
|
|
<text class="ml-3">待验证: {{ maintSt.dyzCount }}</text>
|
</view>
|
<view class="text-color-gray text-sm mt-2 flex">
|
<text>状态:</text>
|
<template v-if="maintSt.status === '1'">
|
<wd-icon class="icon-color-success" name="check-outline" size="34rpx"></wd-icon>
|
<text class="ml-1">已完成</text>
|
</template>
|
<template v-else>
|
<wd-icon class="icon-color-base" name="detection" size="40rpx"></wd-icon>
|
<text class="ml-1">进行中</text>
|
</template>
|
</view>
|
|
<view class="text-color-gray text-sm mt-2 flex">
|
创建时间: {{ maintSt.createTime }}
|
</view>
|
</view>
|
</view>
|
</wd-card>
|
</template>
|
|
<view class="bg-base">
|
<view class="w-full h-[24rpx]"></view>
|
<wd-cell class="mb-[2px]">
|
<template #title>
|
<text class="text-color-gray text-sm">保养项</text>
|
</template>
|
</wd-cell>
|
|
<wd-card type="rectangle" v-for="(item, index) in dataList" :key="item.id" :class="['status-' + item.maintFun]">
|
<template #title>
|
<view class="flex items-center">
|
<view class="menu-indicator"></view>
|
<view class="ml-1 text-sm align-center">
|
<wd-text color="black" :text="item.maintName"></wd-text>
|
</view>
|
<!-- 新增状态显示,绑定点击事件 -->
|
<view
|
v-if="item.status === '2'"
|
class="ml-auto text-sm"
|
style="width: 60px; text-align: end"
|
:style="{ color: getStatusColor(item.maintFun) }"
|
@click.stop="handleUndoAction(item)"
|
>
|
{{ getStatusText(item.maintFun) }}
|
</view>
|
</view>
|
</template>
|
|
<!-- 按钮区域 -->
|
<view v-if="item.maintFun == null" class="flex justify-around mt-2">
|
<wd-button
|
type="primary"
|
size="small"
|
class="mr-2"
|
@click.stop="handleAction(item, '0')"
|
>
|
检查
|
</wd-button>
|
<wd-button
|
type="success"
|
size="small"
|
class="mr-2"
|
@click.stop="handleAction(item, '1')"
|
>
|
保养
|
</wd-button>
|
<wd-button type="warning" size="small" @click.stop="handleAction(item, '2')">
|
维修
|
</wd-button>
|
</view>
|
|
<!-- 正文区域 -->
|
<view v-else class="mt-2">
|
<!-- 保养说明区域 -->
|
<view v-if="item.maintFun === '1'" class="mt-2">
|
<wd-input
|
v-model="item.maintDesc"
|
placeholder="请输入保养说明"
|
clearable
|
:maxlength="200"
|
/>
|
</view>
|
|
<!-- 维修说明区域 -->
|
<view v-if="item.maintFun === '2'" class="mt-2">
|
<wd-input
|
v-model="item.repairDesc"
|
placeholder="请输入维修说明"
|
clearable
|
:maxlength="200"
|
/>
|
</view>
|
|
|
<!-- 备件信息录入区域 -->
|
<view v-if="item.spareParts && item.spareParts.length > 0" class="mt-2">
|
<view
|
v-for="(part, partIndex) in item.spareParts"
|
:key="partIndex"
|
class="flex justify-between mt-1"
|
>
|
<wd-input
|
v-model="part.name"
|
label="名称"
|
label-width="100rpx"
|
placeholder="备件名称"
|
|
|
/>
|
<wd-input
|
v-model="part.quantity"
|
label="数量" label-width="100rpx"
|
placeholder="数量" type="number" :maxlength="5" />
|
</view>
|
</view>
|
<!-- 维修说明区域 -->
|
<view v-if="item.maintFun === '2'" class="mt-2">
|
<wd-button type="info" size="small" @click.stop="addSparePart(item, index)">
|
添加备件
|
</wd-button>
|
</view>
|
|
|
<!-- 保养人和保养时间区域 -->
|
<view class="flex justify-between mt-2">
|
<text>保养人: {{ item.maintUserName }}</text>
|
<text>保养时间: {{ item.endTime }}</text>
|
</view>
|
</view>
|
</wd-card>
|
|
<wd-textarea
|
label="特记事项"
|
label-width="200rpx"
|
type="textarea"
|
v-model="specialNote"
|
auto-height
|
:maxlength="200"
|
show-word-limit
|
placeholder="请输入特记事项"
|
clearable
|
/>
|
</view>
|
<!-- 新增提交按钮 -->
|
<view class="flex justify-center mt-4">
|
<wd-button type="primary" block size="large" @click="handleClickRight">提交</wd-button>
|
</view>
|
</z-paging>
|
|
<!-- 备件选择弹出层 -->
|
<wd-popup v-model="showSparePopup" position="bottom" height="33.33vh">
|
<view class="flex justify-between p-2 bg-white">
|
<wd-button type="text" @click="closeSparePopup">取消</wd-button>
|
<wd-button type="text" @click="addOtherSparePart">其他</wd-button>
|
|
</view>
|
<wd-input
|
v-model="searchKeyword"
|
placeholder="请输入备件名称或型号"
|
clearable
|
@input="filterSpareParts"
|
/>
|
<view class="p-2">
|
<view
|
v-for="(part, index) in sparePartsList"
|
:key="index"
|
class="flex justify-between items-center p-2 border-b"
|
@click="selectFilteredSparePart(part)"
|
>
|
<text>{{ part.name }} ({{ part.code }})</text>
|
<text>剩余: {{ part.actualStock }}</text>
|
</view>
|
</view>
|
</wd-popup>
|
|
|
</template>
|
|
<script setup lang="ts">
|
import type { MaintStVO } from '@/service/maint.d'
|
import { getMaintSt, getMaintStOrderList, updateMaintOrder, updateMaintSt, updateMaintOrderBatch } from '@/service/maint'
|
import { ref, reactive } from 'vue'
|
import { useToast, useMessage } from 'wot-design-uni'
|
import { isLeader, isOperatorOrRepair } from '@/utils/RoleUtils'
|
import { formatDate } from '@/utils/DateUtils'
|
import { useUserStore } from "@/store";
|
import { getSpareList } from '@/service/spare'
|
|
const message = useMessage()
|
const toast = useToast()
|
const userStore = useUserStore()
|
const paging = ref(null)
|
const dataList = ref([])
|
const maintStId = ref('')
|
const showSparePopup = ref(false)
|
const selectedPartIndex = ref(-1)
|
const sparePartsList = ref([])
|
const searchKeyword = ref('')
|
const dataChange = ref(false)
|
const specialNote = ref('')
|
interface QueryParams {
|
pageNum: number
|
pageSize: number
|
maintCode: string
|
status?: string
|
}
|
|
const maintSt = reactive<MaintStVO>({
|
id: '',
|
equName: '',
|
assetNo: '',
|
planTime: '',
|
createTime: '',
|
orderCount: null,
|
wcCount: null,
|
dbyCount: null,
|
byCount: null,
|
dyzCount: null,
|
specialNote: '',
|
})
|
const queryList = (pageNum?: number, pageSize?: number) => {
|
const params: QueryParams = {
|
pageNum,
|
pageSize: 30,
|
maintCode: maintCode.value,
|
}
|
getMaintStOrderList(params)
|
.then((res: any) => {
|
// 请勿在网络请求回调中给dataList赋值!!只需要调用complete就可以了
|
paging.value.completeByTotal(res.rows, res.total)
|
})
|
.catch((res) => {
|
// 如果请求失败写paging.value.complete(false),会自动展示错误页面
|
// 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
// 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
paging.value.complete(false)
|
})
|
}
|
function initMaintSt(id: any) {
|
getMaintSt(id)
|
.then((res: any) => {
|
Object.assign(maintSt, res)
|
paging.value.reload()
|
})
|
.catch((res) => {
|
console.error(res)
|
toast.error(res?.data?.msg || '请求失败')
|
})
|
}
|
|
function itemClick(item) {
|
goToOrderDetail(item)
|
}
|
|
function goToOrderDetail(item) {
|
uni.navigateTo({
|
url: `/pages/maint/order-detail?id=${item.id}`,
|
})
|
}
|
|
// 备件选择相关逻辑
|
function addSparePart(item: any, index: number) {
|
if (!item.spareParts) {
|
item.spareParts = []
|
}
|
selectedPartIndex.value = index
|
// item.spareParts.push({ name: '', quantity: '' })
|
selectSparePart(item)
|
}
|
|
function selectSparePart(item: any) {
|
showSparePopup.value = true
|
|
loadSpareParts()
|
}
|
|
function loadSpareParts(value?: string) {
|
getSpareList({ name: value }).then((res: any) => {
|
sparePartsList.value = res.rows
|
|
})
|
}
|
|
function filterSpareParts() {
|
if (!searchKeyword.value) {
|
loadSpareParts()
|
} else {
|
loadSpareParts(searchKeyword.value)
|
}
|
}
|
|
function selectFilteredSparePart(part: any) {
|
dataList.value[selectedPartIndex.value].spareParts.push({
|
id: part.id,
|
name: part.name,
|
quantity: '',
|
})
|
closeSparePopup()
|
}
|
|
function closeSparePopup() {
|
showSparePopup.value = false
|
selectedPartIndex.value = -1
|
searchKeyword.value = ''
|
}
|
|
function confirmSpareSelection() {
|
closeSparePopup()
|
}
|
|
function addOtherSparePart() {
|
dataList.value[selectedPartIndex.value].spareParts.push({
|
id: '',
|
name: '',
|
quantity: '',
|
})
|
closeSparePopup();
|
}
|
|
/**
|
* 开始保养
|
* @param item
|
*/
|
function handleStartMaint(item) {
|
// 确认开始修改状态为1-保养中
|
const data = Object.assign({}, item)
|
data.status = '1'
|
message
|
.confirm({
|
msg: '确定开始保养?',
|
title: '提示',
|
beforeConfirm: ({ resolve }) => {
|
updateOrder(data, resolve)
|
},
|
})
|
.then(() => {})
|
.catch((error) => {
|
console.log(error)
|
})
|
}
|
|
|
/**
|
* 一键保养
|
* @param item
|
*/
|
function handleMaintFinish(item) {
|
// 一键保养
|
const data = Object.assign({}, item)
|
data.status = '2'
|
data.startTime = formatDate(new Date())
|
data.endTime = formatDate(new Date())
|
message
|
.confirm({
|
msg: '确定使用一键保养?',
|
title: '提示',
|
beforeConfirm: ({ resolve }) => {
|
updateOrder(data, resolve)
|
},
|
})
|
.then(() => {})
|
.catch((error) => {
|
console.log(error)
|
})
|
}
|
|
/**
|
* 更新保养工单
|
* @param item
|
* @param resolve
|
*/
|
function updateOrder(data: any, resolve: any) {
|
|
updateMaintOrder(data)
|
.then((res: any) => {
|
resolve(true)
|
if (res?.code === 200) {
|
reloadData()
|
// 保养状态才需要跳转
|
if(data?.status === '1'){
|
goToOrderDetail(data)
|
}
|
}
|
})
|
.catch((res) => {
|
console.error(res)
|
})
|
}
|
|
function handleUpdateMaintSt() {
|
// if (maintSt.orderCount !== maintSt.wcCount) {
|
// toast.info('请先完成所有保养项!')
|
// return false
|
// }
|
// 先判断保养项是否有更改
|
console.log('handleUPdateMaintst', dataChange.value)
|
if (!dataChange.value) {
|
message.alert('请操作后提交!')
|
return false
|
}
|
// 过滤掉 maintFun为空的保养项
|
const submitList = dataList.value.filter((item) => item.maintFun != null)
|
// 如果maintFun为1的则判断保养说明不能为空,如果为2则判断维修说明不能为空
|
if (submitList.some((item) => item.maintFun === '1' && !item.maintDesc)) {
|
toast.info('请填写保养说明!')
|
return false
|
} else if (submitList.some((item) => item.maintFun === '2' && !item.repairDesc)) {
|
toast.info('请填写维修说明!')
|
return false
|
}
|
|
|
const data: any = Object.assign(
|
{},
|
{
|
id: maintSt.id,
|
orderCount: maintSt.orderCount,
|
wcCount: submitList.length,
|
status: maintSt.status,
|
specialNote: specialNote.value,
|
},
|
)
|
if (data.orderCount === data.wcCount) {
|
data.status = '1'
|
}
|
message
|
.confirm({
|
msg: '确定更新工单汇总数据?',
|
title: '提示',
|
beforeConfirm: ({ resolve }) => {
|
updateMaintOrderBatch({maintOrderList:submitList})
|
updateMaintSt(data)
|
.then((res: any) => {
|
resolve(true)
|
if (res?.code === 200) {
|
reloadData()
|
toastSucces()
|
}
|
})
|
.catch((res) => {
|
console.error(res)
|
})
|
},
|
})
|
.then(() => {})
|
.catch((error) => {
|
console.log(error)
|
})
|
}
|
|
function toastSucces() {
|
toast.success('操作成功')
|
}
|
|
function reloadData() {
|
initMaintSt(maintStId.value)
|
}
|
|
const goBack = () => {
|
uni.navigateBack()
|
}
|
|
function handleClickRight() {
|
if(isOperatorOrRepair()){
|
handleUpdateMaintSt()
|
}
|
|
}
|
|
onLoad(() => {
|
uni.$on('maint-order-refresh', reloadData)
|
})
|
onUnload(() => {
|
uni.$off('maint-order-refresh', reloadData)
|
})
|
|
/**
|
* 查询保养明细需要的code
|
*/
|
const maintCode = computed(() => `${maintSt.equId}_${maintSt.planTime}`)
|
|
onLoad((options) => {
|
maintStId.value = options.id
|
reloadData()
|
})
|
watch(
|
() => [...dataList.value, specialNote.value ], // 使用扩展运算符创建新数组以触发监听
|
(newVal, oldVal) => {
|
if (oldVal.length > 0) {
|
console.log('dataChange',oldVal, newVal)
|
dataChange.value = true
|
}
|
},
|
{ deep: true },
|
)
|
/**
|
* 处理按钮点击事件
|
* @param item 保养项
|
* @param action 操作类型(check/check/maintain/repair)
|
*/
|
function handleAction(item: any, action: number) {
|
// 设置当前选中的操作类型
|
item.maintFun = action
|
item.status = '2'
|
// 自动填充保养人和时间
|
item.maintUserName = userStore?.userInfo?.realName || ''
|
const now = new Date()
|
item.endTime = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
|
console.log('handleAction', item)
|
}
|
|
/**
|
* 撤销保养操作
|
* @param item 保养项
|
*/
|
function handleUndoAction(item: any) {
|
message
|
.confirm({
|
msg: '确定撤销当前操作?',
|
title: '提示',
|
beforeConfirm: ({ resolve }) => {
|
// 重置状态和相关字段
|
item.maintFun = null;
|
item.status = '0';
|
item.maintDesc = '';
|
item.repairDesc = '';
|
item.spareParts = [];
|
item.maintUserName = '';
|
item.endTime = '';
|
resolve(true);
|
},
|
})
|
.then(() => {
|
toast.success('操作已撤销');
|
dataChange.value = true;
|
})
|
.catch((error) => {
|
console.log(error);
|
});
|
}
|
|
// 新增方法:获取状态文本
|
function getStatusText(maintFun: string): string {
|
switch (maintFun) {
|
case '0':
|
return '已检查';
|
case '1':
|
return '已保养';
|
case '2':
|
return '已维修';
|
default:
|
return '';
|
}
|
}
|
|
// 新增方法:获取状态颜色
|
function getStatusColor(maintFun: string): string {
|
switch (maintFun) {
|
case '0':
|
return '#007bff'; // 检查按钮颜色
|
case '1':
|
return '#28a745'; // 保养按钮颜色
|
case '2':
|
return '#ffc107'; // 维修按钮颜色
|
default:
|
return '#000';
|
}
|
}
|
|
</script>
|
|
<style scoped lang="scss">
|
.menu-title-box {
|
height: 30rpx;
|
line-height: 30rpx;
|
}
|
|
.slot-img {
|
width: 72rpx;
|
height: 72rpx;
|
margin-right: 24rpx;
|
}
|
|
.text-mini {
|
font-size: 24rpx;
|
}
|
|
.menu-indicator {
|
width: 6rpx;
|
height: 22rpx;
|
border-radius: 10rpx;
|
background-color: $uni-color-primary;
|
}
|
|
:deep(.wd-card__footer) {
|
padding: 10rpx !important;
|
}
|
|
.col-title-box {
|
}
|
|
.bg-primary {
|
background: $uni-color-primary;
|
}
|
|
:deep(.wd-navbar__text) {
|
font-size: 28rpx;
|
color: white;
|
}
|
|
:deep(.wd-icon-arrow-left:before),
|
:deep(.wd-navbar__title) {
|
color: white;
|
font-weight: 0;
|
font-size: 34rpx;
|
}
|
|
// 新增样式:动态设置卡片背景色
|
:deep(.wd-card) {
|
transition: background-color 0.3s ease;
|
&.status-0 {
|
background-color: #e6f7ff; // 检查状态背景色
|
}
|
&.status-1 {
|
background-color: #f6ffed; // 保养状态背景色
|
}
|
&.status-2 {
|
background-color: #fffbe6; // 维修状态背景色
|
}
|
}
|
</style>
|