You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
8.6 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="page-container">
<view class="fixed-header">
<NavBar :title="t('equipmentInspectionTasks.detailTitle')" />
</view>
<scroll-view scroll-y class="detail-scroll">
<view class="content-section">
<view class="info-card">
<view class="card-title">{{ t('equipmentInspectionTasks.basicInfo') }}</view>
<view class="info-row">
<text class="info-label">{{ t('equipmentInspectionTasks.name') }}</text>
<text class="info-value">{{ textValue(detailData.name) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('equipmentInspectionTasks.taskType') }}</text>
<text class="info-value">{{ taskTypeText }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('equipmentInspectionTasks.deviceList') }}</text>
<text class="info-value">{{ deviceListText }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('equipmentInspectionTasks.projectFormName') }}</text>
<text class="info-value">{{ textValue(detailData.projectFormName) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('equipmentInspectionTasks.dateRange') }}</text>
<text class="info-value">{{ formatDate(detailData.startDate) }} ~ {{ formatDate(detailData.endDate) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('equipmentInspectionTasks.cronExpression') }}</text>
<text class="info-value">{{ textValue(detailData.cronExpression) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('equipmentInspectionTasks.operableUsers') }}</text>
<text class="info-value">{{ textValue(detailData.operableUsers) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('equipmentInspectionTasks.enabled') }}</text>
<text :class="['info-value', isEnabled(detailData.enabled) ? 'text-success' : 'text-danger']">{{ enabledText(detailData.enabled) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('equipmentInspectionTasks.creatorName') }}</text>
<text class="info-value">{{ textValue(detailData.creatorName) }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('equipmentInspectionTasks.createTime') }}</text>
<text class="info-value">{{ formatDateTime(detailData.createTime) }}</text>
</view>
<view class="info-row no-border">
<text class="info-label">{{ t('equipmentInspectionTasks.updateTime') }}</text>
<text class="info-value">{{ formatDateTime(detailData.updateTime) }}</text>
</view>
</view>
</view>
</scroll-view>
<view class="action-bar">
<view :class="['action-btn', ticketLoading ? 'action-btn-disabled' : '']" @click="handleCreateTicket">
{{ t('equipmentInspectionTasks.createTicket') }}
</view>
</view>
</view>
</template>
<script setup>
import { computed, reactive, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { createTaskManagementTicket } from '@/api/mes/taskManagement'
import { getDeviceLedgerList } from '@/api/mes/deviceLedger'
const { t } = useI18n()
const detailData = reactive({})
const ticketLoading = ref(false)
const deviceOptions = ref([])
const taskTypeText = computed(() => {
const normalized = Number(detailData.taskType)
if (normalized === 1) return t('equipmentInspectionTasks.taskTypeInspect')
if (normalized === 2) return t('equipmentInspectionTasks.taskTypeMaintain')
return textValue(detailData.taskType)
})
async function ensureDeviceOptionsLoaded() {
try {
const res = await getDeviceLedgerList()
const root = res && res.data !== undefined ? res.data : res
const data = Array.isArray(root) ? root : (Array.isArray(root?.data) ? root.data : root?.list || [])
deviceOptions.value = (Array.isArray(data) ? data : [])
.filter((item) => item && item.id !== undefined && item.id !== null)
.map((item) => ({
id: item.id,
label: `${item.deviceCode || ''} ${item.deviceName || ''}`.trim(),
deviceName: item.deviceName || '',
raw: item
}))
} catch (error) {
deviceOptions.value = []
}
}
const deviceListText = computed(() => {
const value = detailData.deviceListText || detailData.deviceList
/* if (Array.isArray(value)) return value.join('') || '-'
return textValue(value)*/
const ids = parseIdsValue(value)
if (!ids.length) return '-'
const names = ids
.map((id) => {
const matched = deviceOptions.value.find((item) => String(item.id) === id)
return matched?.deviceName || matched?.label || id
})
.filter(Boolean)
return names.length ? names.join('') : '-'
})
function parseIdsValue(value) {
if (!value) return []
if (Array.isArray(value)) return value.map((item) => String(item).trim()).filter(Boolean)
return String(value).split(',').map((item) => item.trim()).filter(Boolean)
}
onLoad(async () => {
try {
const cached = uni.getStorageSync('equipmentInspectionTasksDetail')
if (cached) {
Object.assign(detailData, JSON.parse(cached))
uni.removeStorageSync('equipmentInspectionTasksDetail')
}
await Promise.all([ensureDeviceOptionsLoaded()])
} catch (error) {
}
})
async function handleCreateTicket() {
if (!detailData.id || ticketLoading.value) return
ticketLoading.value = true
try {
await createTaskManagementTicket(detailData.id)
uni.showToast({ title: t('equipmentInspectionTasks.createTicketSuccess'), icon: 'success' })
} catch (error) {
uni.showToast({ title: t('equipmentInspectionTasks.createTicketFail'), icon: 'none' })
} finally {
ticketLoading.value = false
}
}
function isEnabled(value) {
return value === true || value === 1 || value === '1' || value === 'true'
}
function enabledText(value) {
return isEnabled(value) ? t('functionCommon.yes') : t('functionCommon.no')
}
function textValue(value) {
if (value === 0) return '0'
if (value === null || value === undefined) return '-'
const text = String(value).trim()
return text || '-'
}
function formatDate(value) {
if (!value) return '-'
if (Array.isArray(value) && value.length >= 3) {
const [year, month, day] = value
const pad = (num) => String(num).padStart(2, '0')
return `${year}-${pad(month)}-${pad(day)}`
}
return String(value).trim().substring(0, 10) || '-'
}
function formatDateTime(value) {
if (!value) return '-'
if (Array.isArray(value) && value.length >= 3) {
const [year, month, day, hour = 0, minute = 0, second = 0] = value
const pad = (num) => String(num).padStart(2, '0')
return `${year}-${pad(month)}-${pad(day)} ${pad(hour)}:${pad(minute)}:${pad(second)}`
}
const date = new Date(Number(value))
if (Number.isNaN(date.getTime())) return textValue(value)
const pad = (num) => String(num).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`
}
</script>
<style lang="scss" scoped>
.page-container { min-height: 100vh; background-color: #f0f2f5; }
.fixed-header { position: sticky; top: 0; z-index: 20; }
.detail-scroll { height: calc(100vh - 200rpx); }
.content-section { padding: 0 24rpx 24rpx; }
.info-card { margin-top: 20rpx; background: #fff; border-radius: 20rpx; padding: 28rpx; box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); }
.card-title { font-size: 32rpx; color: #1a3a5c; font-weight: 700; margin-bottom: 18rpx; }
.info-row { display: flex; justify-content: space-between; align-items: flex-start; padding: 18rpx 0; border-bottom: 1rpx solid #edf0f3; }
.no-border { border-bottom: none; }
.info-label { width: 220rpx; font-size: 27rpx; color: #8a9099; }
.info-value { flex: 1; text-align: right; font-size: 28rpx; color: #303133; line-height: 1.45; }
.text-success { color: #18bc37; }
.text-danger { color: #e34d59; }
.action-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 24rpx calc(20rpx + env(safe-area-inset-bottom));
background: #f0f2f5;
}
.action-btn {
height: 88rpx;
border-radius: 16rpx;
background: #1f4b79;
color: #ffffff;
font-size: 30rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
}
.action-btn-disabled {
background: #94a3b8;
}
</style>