吉安感知网项目-前端
张含笑
2026-02-03 77a2c94e6e208b7b8064bbd67a4828d4faaf509b
feat:app嵌套页调整
1 files modified
1023 ■■■■■ changed files
applications/mobile-web-view/src/appPages/work/workDetail/index.vue 1023 ●●●●● patch | view | raw | blame | history
applications/mobile-web-view/src/appPages/work/workDetail/index.vue
@@ -10,641 +10,82 @@
                </van-swipe>
                <van-image-preview v-model:show="previewShow" :images="getImageList" :initial-index="previewIndex" />
                <div class="detailTitle">
                    <div class="titleText">
                        <div class="itemStatus">
                            <span v-if="currentDetail.status === 0" style="background-color: #ff7411"></span>
                            <span v-else-if="currentDetail.status === 2" style="background-color: #ff472f"></span>
                            <span v-else-if="currentDetail.status === 3" style="background-color: #ffc300"></span>
                            <span v-else-if="currentDetail.status === 4" style="background-color: #06d957"></span>
                            <div>{{ currentDetail.event_name }}</div>
                        </div>
                        <div class="timeNavigation">
                            <p>{{ formatDate(currentDetail.create_time) }}</p>
                            <img @click="jumpMap(currentDetail)" src="/src/appDataSource/appwork/navigation.svg"
                                alt="" />
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <!-- 步骤条 -->
        <div class="stepBox">
            <div class="stepContainer">
                <van-steps direction="vertical" :active="currentStep">
                    <van-step v-for="(step, index) in displayedSteps" :key="step.status">
                        <div class="horizontal-step">
                            <span class="step-title" :class="getStatusClass(index)">{{ step.title }}</span>
    <!-- 工单内容 -->
    <div class="worderContainer">
      <div class="workOrderContent">
        <div class="workOrderTitle">工单内容</div>
        <div class="workOrderContainer">
          <div class="orderRow">
            <div class="rowTitle">工单编号</div>
            <div>{{ workDetailData.eventNum }}</div>
          </div>
          <div class="orderRow">
            <div class="rowTitle">工单处置人</div>
            <div>{{ workDetailData.disposeUserName }}</div>
          </div>
          <div class="orderRow">
            <div class="rowTitle">处置部门</div>
            <div>{{ workDetailData.disposeDeptName }}</div>
          </div>
          <div class="orderRow">
            <div class="rowTitle">拍摄时间</div>
            <div>{{ workDetailData.shootTime }}</div>
          </div>
          <div class="orderRow">
            <div class="rowTitle">分发人员</div>
            <div>{{ workDetailData.distributeUserName }}</div>
          </div>
          <div class="orderRow">
            <div class="rowTitle">分发部门</div>
            <div>{{ workDetailData.distributeDeptName }}</div>
          </div>
                            <div class="step-desc" v-if="stepResponse[index]">
                                <span>{{ stepResponse[index].name || '' }}</span>
                                <span>{{ stepResponse[index].create_time || '' }}</span>
                            </div>
                        </div>
                    </van-step>
                </van-steps>
            </div>
        </div>
        <!-- 工单内容 -->
        <div class="worderContainer">
            <div class="workOrderContent">
                <div class="workOrderTitle">工单内容</div>
                <div class="workOrderContainer">
                    <div class="orderRow">
                        <span class="required-mark" v-if="isEditable">*</span>
                        <div class="rowTitle">工单名称</div>
                        <div v-if="!isEditable">{{ currentDetail.event_name }}</div>
                        <van-field v-else v-model="currentDetail.event_name" name="event_name" required
                            input-align="right" placeholder="请输入" class="custom-field" />
                    </div>
                    <div class="orderRow">
                        <div class="rowTitle">工单编号</div>
                        <div>{{ currentDetail.event_num }}</div>
                    </div>
                    <div class="orderRow">
                        <div class="rowTitle">工单类型</div>
                        <div>{{ workOrderTypeName }}</div>
                    </div>
                    <div class="orderRow" v-if="currentDetail.work_type == '0'">
                        <div class="rowTitle">关联任务</div>
                        <div>{{ currentDetail.job_name }}</div>
                    </div>
                    <div class="orderRow">
                        <div class="rowTitle">工单创建人</div>
                        <div>{{ currentDetail.event_num?.slice(0, 2) === 'AI' ? '智飞agent' : currentDetail.create_user }}
                        </div>
                    </div>
                    <div class="orderRow">
                        <div class="rowTitle">事件地址</div>
                        <div class="addressBox" @click="jumpMap(currentDetail)">
                            <div class="rowAddress">{{ currentDetail.address }}</div>
                            <img class="pointing" src="/src/appDataSource/appwork/pointing.svg" alt="" />
                        </div>
                    </div>
                    <div class="orderRow">
                        <div class="guanlian">
                            <span class="required-mark" v-if="isEditable">*</span>
                            <div class="rowTitle">关联算法</div>
                        </div>
                        <div v-if="!isEditable">{{ currentDetail.ai_types }}</div>
                        <div v-else>
                            <span @click="openselect" class="selectTrigger">
                                {{ currentDetail.ai_types }}
                                <img class="downpointing" src="/src/appDataSource/appwork/downpointing.svg" alt="" />
                            </span>
                            <van-popup v-model:show="showPicker" destroy-on-close position="bottom"
                                :close-on-click-overlay="true">
                                <van-picker v-model="selectedValues" title="选择关联算法" :columns="columns"
                                    @confirm="onConfirm" @cancel="onCancel" />
                            </van-popup>
                        </div>
                    </div>
                    <div class="orderRow">
                        <div class="rowTitle">发起部门</div>
                        <div>{{ currentDetail.dept_name }}</div>
                    </div>
                    <div class="orderRow">
                        <div class="rowTitle">发起任务时间</div>
                        <div>{{ currentDetail.create_time }}</div>
                    </div>
                    <div class="orderRow">
                        <div class="rowTitle">所属机巢</div>
                        <div>{{ currentDetail.device_names }}</div>
                    </div>
                    <div class="orderRow">
                        <span class="required-mark" v-if="isEditable">*</span>
                        <div class="rowTitle">工单内容</div>
                        <div v-if="!isEditable">{{ currentDetail.content }}</div>
                        <van-field v-else class="custom-field" input-align="right" v-model="currentDetail.content"
                            name="remark" required placeholder="请输入" />
                    </div>
                    <div class="rowCard" v-if="isEditableProcess">
                        <div class="guanlian">
                            <span class="required-mark">*</span>
                            <div class="rowTitle">
                                上传图片
                                <span>(只能上传jpg、jpeg、png照片,且不超过5M)</span>
                            </div>
                        </div>
                        <div>
                            <van-field name="uploader">
                                <template #input>
                                    <van-uploader :disabled="!isCurrentUserAssigned" v-model="fileList"
                                        :after-read="afterRead" :max-count="1" :max-size="5 * 1024 * 1024"
                                        @oversize="onOversize" :before-read="beforeRead" @delete="handleDelete"
                                        accept="image/jpeg,image/jpg,image/png" />
                                </template>
                            </van-field>
                        </div>
                    </div>
                    <div class="orderRow" v-if="isEditableProcess">
                        <span class="required-mark">*</span>
                        <div class="rowTitle">事件处理详情</div>
                        <van-field class="custom-field" input-align="right" v-model="currentDetail.processingDetail"
                            name="event_name" required placeholder="请输入" :disabled="!isCurrentUserAssigned" />
                    </div>
                    <div class="orderRow" v-if="isComplent">
                        <div class="rowTitle">事件处理详情</div>
                        <div>{{ currentDetail.processingDetail }}</div>
                    </div>
                </div>
            </div>
        </div>
        <!-- 操作按钮 -->
        <div class="actionButton">
            <div class="floatingBtn leftFloatingBtn" @click="leftClick">
                <img src="/src/appDataSource/appwork/leftBtn1.svg" alt="" />
            </div>
            <div class="paginationInfo">
                <span>{{ currentPage }} / {{ totalRecords }}</span>
            </div>
            <div class="btngroups" v-if="currentDetail.status === 2">
                <van-button type="primary" color="#FF452C" round text="不通过" @click="rejectTicket"></van-button>
                <van-button type="primary" color="#1D6FE9" round text="通过" @click="approveTicket"></van-button>
            </div>
            <div class="btngroups" v-else-if="currentDetail.status === 0">
                <van-button type="primary" color="#FF452C" round text="不受理" @click="rejectTicket"></van-button>
                <van-button type="primary" color="#1D6FE9" round text="受理" @click="approveAndDispatch"></van-button>
            </div>
            <div class="btngroups" v-else-if="currentDetail.status === 3">
                <van-button type="primary" color="#FF452C" round text="取消" @click="cancellation"></van-button>
                <van-button :disabled="!isCurrentUserAssigned" type="primary" color="#1D6FE9" round text="完成工单"
                    @click="completeTicket"></van-button>
            </div>
            <div class="btngroups back-btn" v-else>
                <van-button type="primary" round color="#FF730F" text="返回" @click="cancellation"></van-button>
            </div>
            <div class="floatingBtn rightFloatingBtn" @click="rightClick">
                <img src="/src/appDataSource/appwork/rightBtn1.svg" alt="" />
            </div>
        </div>
        <!--派发工单对话框-->
        <van-dialog v-model:show="isshowDispatch" title="派发工单" show-cancel-button @confirm="submitDispatch"
            @cancel="dispatchCancel">
            <van-field v-model="dispatchForm.departmentName" is-link readonly label="选择部门" placeholder="请选择部门"
                @click="openPicker('department')" />
            <van-field v-model="dispatchForm.handlerName" is-link readonly label="选择处理人" placeholder="请选择处理人"
                @click="openPicker('processor')" :disabled="!dispatchForm.department" />
        </van-dialog>
        <teleport to="body">
            <van-popup v-model:show="showGlobalPicker" position="bottom">
                <!-- 部门选择器 -->
                <van-picker v-if="currentPickerType === 'department'" v-model="selectedDepartment" title="选择部门"
                    :columns="departments" @confirm="onDepartmentConfirm" @cancel="onPickerCancel" />
                <!-- 处理人选择器 -->
                <van-picker v-if="currentPickerType === 'processor'" v-model="selectedProcessor" title="选择处理人"
                    :columns="availableDispatchHandlers" @confirm="onProcessorConfirm" @cancel="onPickerCancel" />
            </van-popup>
        </teleport>
          <div class="orderRow">
            <div class="rowTitle">分发时间</div>
            <div>{{ workDetailData.distributeTime }}</div>
          </div>
          <div class="orderRow">
            <div class="rowTitle">工单位置</div>
            <div class="rowAddress" @click="jumpMap(workDetailData)">{{ workDetailData.eventLocation }}</div>
          </div>
        </div>
      </div>
    </div>
    </div>
</template>
<script setup>
import {ALL_WORK_ORDER_TYPE_OPTIONS} from '@ztzf/constants'
import { getDeviceRegion } from '@/api/home/aggregation'
import { usePermission } from '@/appPages/work/usePermission'
import { showToast, showNotify, showImagePreview } from 'vant'
import { getShowImg, getSmallImg } from '@/utils/util'
import { useRoute } from 'vue-router'
import { getStepInfo, getList, flowEvent, getTicketInfo } from '/src/api/work/index.js'
import { showToast, showNotify, showImagePreview } from 'vant'
import dayjs from 'dayjs'
import _ from 'lodash'
import { useStore } from 'vuex'
const store = useStore()
const userInfo = computed(() => store?.state?.user?.userInfo)
const { permission, getButtonsApi } = usePermission()
const showPicker = ref(false)
const selectedValues = ref([])
const columns = ref([])
const allAlgorithms = ref([])
const algorithms = ref([])
const types = ref([]) //工单类型
const eventNum = ref('')
const currentStatus = ref(0)
const stepResponse = ref([])
const currentStep = ref(0)
const route = useRoute()
const currentDetail = ref({ status: 0 })
const currentIndex = ref(null) //当前显示数据索引
const departments = ref([]) //部门
const departmentUsers = ref({})
const fileList = ref([])
// 机巢数据
let machineData = ref([])
// 处理人选择相关
const processorColumns = ref([])
// 可编辑状态
const isEditable = computed(() => currentDetail.value.status === 0)
const isEditableProcess = computed(() => currentDetail.value.status === 3)
const isComplent = computed(() => currentDetail.value.status === 4)
// 工单内容
const workDetailData = ref({})
// 分页相关
const currentPage = ref(1)
const pageSize = ref(1)
const totalRecords = ref(0)
const formatDate = dateString => {
    return dayjs(dateString).format('MM/DD HH:mm')
}
const allStepConfigs = ref([
    { title: '待审核', status: 2 },
    { title: '待处理', status: 0 },
    { title: '处理中', status: 3 },
    { title: '已完成', status: 4 },
])
const hasProcessingBtnPermission = () => {
    return permission.value && permission.value.tickets_processing_btn === true
}
// 完成工单
const hasProcessedAndOverBtnPermission = () => {
    return permission.value && permission.value.tickets_view_processedAndOver === true
}
// 通过不通过
const hasReviewBtnPermission = () => {
    return permission.value && permission.value.tickets_review_btn === true
}
// 是否有权限完成工单
const isCurrentUserAssigned = computed(() => {
    const handleUserId = currentDetail.value?.handle_user_id
    const currentUserId = userInfo.value?.user_id
    return !!handleUserId && !!currentUserId && String(handleUserId) === String(currentUserId)
// 预览图片
const previewShow = ref(false)
const previewIndex = ref(0)
const getImageList = computed(() => {
    const imageArr = []
    const detail = workDetailData.value
    if (detail.eventImageUrl) {
        const smallUrl = getSmallImg(detail.eventImageUrl)
        imageArr.push(smallUrl)
    }
    return imageArr
})
const getStatusClass = index => {
    if (index <= currentStep.value) {
        const status = Number(stepResponse.value[index]?.status) || 0
        const statusClasses = {
            2: 'status-pending', // 待审核
            0: 'status-waiting', // 待处理
            3: 'status-processing', // 处理中
            4: 'status-completed', // 已完成
        }
        return statusClasses[status] || ''
    }
    return 'status-default'
}
// 关联算法
const getTicketInfoData = async () => {
    const response = await getTicketInfo()
    const { dept_data, event_type, ai_type, info } = response.data.data
    allAlgorithms.value = info
    types.value = Object.entries(event_type).map(([key, value]) => ({
        label: value,
        value: key,
    }))
    departments.value = dept_data.map(item => ({
        text: item.dept_name,
        value: item.id,
    }))
    departmentUsers.value = dept_data.reduce((acc, dept) => {
        acc[dept.id] = dept.user_data || []
        return acc
    }, {})
}
// 处理人
const availableDispatchHandlers = computed(() => {
    if (!dispatchForm.value.department) return []
    const users = departmentUsers.value[dispatchForm.value.department]
    if (!users) return []
    return users.map(user => ({
        text: user.name,
        value: user.id,
    }))
})
// 关联算法选择
const handleTypeChange = typeValue => {
    const matchedCategory = allAlgorithms.value.find(category => category.dict_key === typeValue)
    if (!matchedCategory || !matchedCategory.algorithms || matchedCategory.algorithms.length === 0) {
        // 无匹配的算法时清空
        algorithms.value = []
        return
    }
    algorithms.value = matchedCategory.algorithms.map(algo => ({
        label: algo.dict_value,
        value: algo.dict_key,
        dict_key: algo.dict_key,
        dict_value: algo.dict_value,
    }))
    columns.value = algorithms.value.map(item => ({
        text: item.label,
        value: item.value,
    }))
}
// 机巢数据
const handleNodeClick = async data => {
    const droneList = await getDeviceRegion({ areaCode: userInfo.value.detail.areaCode })
    machineData.value = droneList?.data?.data
}
const tableData = ref([])
const fetchWorkData = async (val) => {
    const params = {
        current: Number(currentPage.value) || 1,
        size: pageSize.value,
        source: 1,
        // event_name: val.keyword || val.eventNum,
        ai_types: val.aiType,
        way_line_job_info_id: val.wLJobInfoId,
        work_types: ALL_WORK_ORDER_TYPE_OPTIONS
    }
    if (val.status !== 'undefined') {
        params.status = val.status
    }
    const res = await getList(params)
    const response = res.data.data.records
    totalRecords.value = res.data.data.total || 0
  console.log(totalRecords.value,res.data.data.total,2222)
    if (response && response.length > 0) {
        const item = response[0]
        const matchedMachine = machineData.value.find(m => m.device_sn === item.device_sn)
        const deviceNickname = matchedMachine?.nickname || ''
        currentDetail.value = {
            ...item,
            processingDetail: item.processing_details,
            update_photo_url: item.update_photo_url,
            photos: [],
            aiType: item.ai_type_key_list?.join(',') || '',
            status: Number(item.status) || 0,
            device_names: deviceNickname ? deviceNickname : ''
        }
        currentStatus.value = currentDetail.value.status
        handleTypeChange(currentDetail.value.work_order_type_dict_key)
        await getStepInfoData(currentDetail.value.event_num)
    }
}
// 计算要显示的步骤
const displayedSteps = computed(() => {
    return allStepConfigs.value.filter(stepConfig => {
        return stepResponse.value.some(stepData => Number(stepData?.status) === stepConfig.status)
const openPreview = index => {
    const detail = workDetailData.value
    const showUrl = getShowImg(detail.eventImageUrl)
    showImagePreview({
        images: [showUrl],
        startPosition: 0,
    })
})
// 计算工单类型显示名称
const workOrderTypeName = computed(() => {
    const type = types.value.find(item => item.value === currentDetail.value.work_order_type_dict_key)
    return type ? type.label : currentDetail.value.work_order_type_dict_key
})
// 步骤条
const calculateCurrentStep = status => {
    const stepIndex = displayedSteps.value.findIndex(step => step.status === status)
    return stepIndex !== -1 ? stepIndex : 0
}
const getStepInfoData = async val => {
    const res = await getStepInfo(val)
    stepResponse.value = res.data.data.map(item => ({
        ...item,
        status: Number(item.status) || 0,
    }))
    currentStep.value = calculateCurrentStep(currentStatus.value)
}
// 通过
const approveTicket = async () => {
    const data = {
        id: currentDetail.value.id,
        status: currentDetail.value.status,
        isPass: 0, // 0 表示通过
        eventNum: currentDetail.value.event_num,
    }
    const file = currentDetail.value.file || null
    const response = await flowEvent(data, file)
    if (response.data.code === 0) {
        showToast('工单已通过')
    }
    const transmitData = { data: { type: 'workback', fun: 'add' } }
    wx.miniProgram.switchTab({ url: `/pages/work/index?addLog=111` })
    wx.miniProgram.postMessage(transmitData)
    uni.postMessage(transmitData)
}
// 不通过/不受理
const rejectTicket = async () => {
    const data = {
        id: currentDetail.value.id,
        status: currentDetail.value.status,
        isPass: 1,
    }
    const response = await flowEvent(data)
    if (response.data.code === 0) {
        showToast('工单未通过')
    }
    const transmitData = { data: { type: 'workback', fun: 'add' } }
    wx.miniProgram.switchTab({ url: `/pages/work/index?addLog=111` })
    wx.miniProgram.postMessage(transmitData)
    uni.postMessage(transmitData)
}
const isshowDispatch = ref(false)
// 受理
const approveAndDispatch = () => {
    if (!currentDetail.value.event_name) {
        showToast('请填写工单名称')
        return
    }
    if (!currentDetail.value.ai_types) {
        showToast('请选择关联算法')
        return
    }
    if (!currentDetail.value.content) {
        showToast('请填写工单内容')
        return
    }
    isshowDispatch.value = true
}
const dispatchCancel = () => {
    // 重置表单
    dispatchForm.value = {
        department: '',
        departmentName: '',
        handler: '',
        handlerName: '',
    }
    isshowDispatch.value = false
}
const dispatchForm = ref({
    department: '', // 存储部门ID (value)
    departmentName: '', // 显示部门名称 (text)
    handler: '', // 存储处理人ID (value)
    handlerName: '', // 显示处理人名称 (text)
})
const selectedDepartment = ref([])
const selectedProcessor = ref([])
const showGlobalPicker = ref(false)
const currentPickerType = ref('')
const openPicker = type => {
    currentPickerType.value = type
    showGlobalPicker.value = true
}
// 部门选择确认
const onDepartmentConfirm = value => {
    dispatchForm.value.department = value.selectedValues[0]
    dispatchForm.value.departmentName = value.selectedOptions[0].text
    showGlobalPicker.value = false
}
// 处理人选择确认
const onProcessorConfirm = value => {
    if (!dispatchForm.value.department) {
        showToast('请先选择部门')
        return
    }
    dispatchForm.value.handler = value.selectedValues[0]
    dispatchForm.value.handlerName = value.selectedOptions[0].text
    showGlobalPicker.value = false
}
// 取消选择
const onPickerCancel = () => {
    showGlobalPicker.value = false
}
// 派发工单
const submitDispatch = async () => {
    if (!dispatchForm.value.department) {
        showToast('请选择部门')
        return
    }
    if (!dispatchForm.value.handler) {
        showToast('请选择处理人')
        return
    }
    try {
        const data = {
            id: currentDetail.value.id,
            status: currentDetail.value.status,
            isPass: 0,
            eventName: currentDetail.value.event_name,
            eventNum: currentDetail.value.event_num,
            workOrderTypeDictKey: currentDetail.value.work_order_type_dict_key,
            content: currentDetail.value.content,
            createDept: dispatchForm.value.department,
            updateUser: dispatchForm.value.handler,
            aiType: currentDetail.value.aiType,
        }
        const file = currentDetail.value.file || null
        const response = await flowEvent(data, file)
        if (response.data.code === 0) {
            showToast('工单派发成功')
            const transmitData = { data: { type: 'workback', fun: 'add' } }
            wx.miniProgram.switchTab({ url: `/pages/work/index?addLog=111` })
            wx.miniProgram.postMessage(transmitData)
            uni.postMessage(transmitData)
            isshowDispatch.value = false
        }
    } catch (error) {
        showToast('工单派发失败')
    }
}
// 完成工单
const completeTicket = async () => {
    if (!currentDetail.value.processingDetail) {
        showToast('请先填写事件处理详情')
        return
    }
    if (!currentDetail.value.photos || currentDetail.value.photos.length === 0) {
        showToast('请选择上传图片')
        return
    }
    const data = {
        id: currentDetail.value.id,
        status: currentDetail.value.status,
        processingDetails: currentDetail.value.processingDetail,
        eventNum: currentDetail.value.event_num,
    }
    const file = currentDetail.value.photos?.[0] || null
    const response = await flowEvent(data, file)
    if (response.data.code === 0) {
        showToast('工单已完成')
    }
    const transmitData = { data: { type: 'workback', fun: 'add' } }
    wx.miniProgram.switchTab({ url: `/pages/work/index?addLog=111` })
    wx.miniProgram.postMessage(transmitData)
    uni.postMessage(transmitData)
}
// 取消
const cancellation = () => {
    const transmitData = { data: { type: 'workback', fun: 'add' } }
    wx.miniProgram.switchTab({ url: `/pages/work/index?addLog=111` })
    wx.miniProgram.postMessage(transmitData)
    uni.postMessage(transmitData)
}
// 下拉选择
const openselect = () => {
    showPicker.value = true
}
// 选择器确认方法
const onConfirm = val => {
    currentDetail.value.ai_types = val.selectedOptions.map(option => option.text).join(',')
    currentDetail.value.aiType = val.selectedValues.join(',')
    showPicker.value = false
}
// 选择器取消方法
const onCancel = () => {
    showPicker.value = false
}
// 文件上传前的校验
const beforeRead = file => {
    const ext = file.name.split('.').pop().toLowerCase()
    const allowedExts = ['jpg', 'jpeg', 'png']
    if (!allowedExts.includes(ext)) {
        showToast('请上传 jpg/jpeg/png 格式图片')
        return false
    }
    return true
}
// 文件大小超过限制时的回调
const onOversize = file => {
    showToast('文件大小不能超过 5MB')
}
// 文件读取完成后的回调
const afterRead = file => {
    currentDetail.value.photos = [file.file]
}
// 处理图片删除
const handleDelete = () => {
    currentDetail.value.photos = []
}
// 更新当前显示的工单详情
const updateCurrentDetail = () => {
    currentDetail.value = tableData.value[currentIndex.value]
    if (currentDetail.value.status !== undefined) {
        currentDetail.value.status = Number(currentDetail.value.status) || 0
    }
    currentStatus.value = currentDetail.value.status
    getStepInfoData(currentDetail.value.event_num)
}
// 上一页
const leftClick = () => {
    if (currentPage.value > 1) {
        currentPage.value--
        fetchWorkData(route.query)
    } else {
        showToast('已经是第一页')
    }
}
// 下一页
const rightClick = () => {
    if (currentPage.value < totalRecords.value) {
        currentPage.value++
        fetchWorkData(route.query)
    } else {
        showToast('已经是最后一页')
    }
    previewIndex.value = index
    previewShow.value = true
}
// 跳转地图
const jumpMap = item => {
@@ -653,57 +94,15 @@
    wx.miniProgram.postMessage(transmitData)
    uni.postMessage(transmitData)
}
// 预览图片
const previewShow = ref(false)
const previewIndex = ref(0)
const getImageList = computed(() => {
    const imageArr = []
    const detail = currentDetail.value
    if (detail.photo_url) {
        const smallUrl = getSmallImg(detail.photo_url)
        imageArr.push(smallUrl)
    }
    if (detail.update_photo_url) {
        const smallUrl = getSmallImg(detail.update_photo_url)
        imageArr.push(smallUrl)
    }
    return imageArr
})
const openPreview = index => {
    const detail = currentDetail.value
    const showUrl = getShowImg(detail.photo_url || detail.update_photo_url)
    showImagePreview({
        images: [showUrl],
        startPosition: 0,
    })
    previewIndex.value = index
    previewShow.value = true
}
onMounted(async () => {
    handleNodeClick()
    eventNum.value = route.query.eventNum || ''
    await getTicketInfoData()
  currentPage.value = route.query.current
    await fetchWorkData(route.query)
    await getStepInfoData(eventNum.value)
    currentIndex.value = tableData.value.findIndex(item => item.event_num === currentDetail.value.event_num)
workDetailData.value = JSON.parse(route.query.workDetailData)
console.log('route.query',workDetailData.value);
})
</script>
<style lang="scss" scoped>
.workDetailContainer {
    position: relative;
    .required-mark {
        color: #ff4d4f; // 红色
        margin-left: 4px;
    }
  padding-top: 44px;
    .detailTop {
        .image-container {
            position: relative;
@@ -716,255 +115,6 @@
                display: block;
                object-fit: cover;
            }
            .detailTitle {
                position: absolute;
                left: 0;
                top: 0;
                width: 100%;
                padding: 5px;
                height: 30px;
                background: rgba(7, 7, 7, 0.4);
            }
            .titleText {
                display: flex;
                width: 100%;
                justify-content: space-between;
                align-items: center;
                font-family: Source Han Sans CN, Source Han Sans CN;
                font-weight: 400;
                font-size: 13px;
                color: #ffffff;
                .itemStatus {
                    display: flex;
                    align-items: center;
                    font-family: Source Han Sans CN, Source Han Sans CN;
                    font-weight: 400;
                    font-size: 13px;
                    color: #ffffff;
                    span {
                        display: inline-block;
                        width: 10px;
                        height: 10px;
                        border-radius: 50%;
                        margin-right: 7px;
                    }
                }
            }
            .timeNavigation {
                display: flex;
                align-items: center;
                font-family: Source Han Sans CN, Source Han Sans CN;
                font-weight: 400;
                font-size: 13px;
                color: #ffffff;
                img {
                    width: 20px;
                    height: 20px;
                    margin-left: 5px;
                }
            }
        }
    }
    .stepBox {
        padding: 0 12px;
    }
    .stepContainer {
        margin-top: 10px;
        display: flex;
        border-radius: 5px;
        padding: 10px;
        background: #fff;
        :deep() {
            .van-step__circle-container {
                font-size: 20px;
            }
            .van-step__circle {
                width: 15px;
                height: 15px;
            }
            .van-step--vertical {
                padding: 20px 20px 20px 0;
            }
            .van-step__circle-container,
            .van-step__line {
                top: 50%;
            }
            .van-step--vertical:not(:last-child):after {
                border-bottom-width: 0;
            }
        }
        .horizontal-step {
            display: flex;
            align-items: center;
            gap: 12px;
            .step-title {
                min-width: 60px;
                background: #e8e8e8;
                padding: 5px;
                border-radius: 5px;
                text-align: center;
                &.status-pending {
                    background-color: #ffebeb; // 待审核
                    color: #ff1414;
                }
                &.status-waiting {
                    background-color: #fff1e6; // 待处理
                    color: #ff7411;
                }
                &.status-processing {
                    background-color: #fff6d8; // 处理中
                    color: #ffbb00;
                }
                &.status-completed {
                    background-color: #e5fcff; // 已完成
                    color: #0291a1;
                }
                &.status-default {
                    background-color: #e8e8e8; // 默认背景色
                    color: #191919;
                }
            }
            .step-desc {
                display: flex;
                justify-content: space-between;
                gap: 28px;
                color: #222324;
                font-size: 14px;
            }
            .step-desc span:first-child {
                width: 60px;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }
            span:last-child {
                margin-left: auto;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }
        }
    }
    :deep(.van-step__circle) {
        width: 8px;
        height: 8px;
    }
    /* 悬浮左右按钮样式 */
    .floatingBtn {
        position: fixed;
        top: 50%;
        width: 46px;
        height: 46px;
        z-index: 9;
        transform: translateY(-50%);
        background: rgba(17, 17, 17, 0.28);
        backdrop-filter: blur(3px);
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
    }
    .leftFloatingBtn {
        left: 5px;
        /* 左边距离 */
    }
    .rightFloatingBtn {
        right: 5px;
        /* 右边距离 */
    }
    .floatingBtn img {
        width: 10px;
        height: 18px;
    }
    .paginationInfo {
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
        font-size: 14px;
        color: #666;
        background: rgba(255, 255, 255, 0.9);
        padding: 4px 12px;
        border-radius: 12px;
    }
    .actionButton {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 61px;
        background: #ffffff;
        border-radius: 6px 6px 6px 6px;
        padding: 0 18px;
        .btngroups {
            display: flex;
            justify-content: space-between;
            align-items: center;
            .van-button {
                padding: 9px 20px;
                height: 38px;
                width: 156px;
                &:last-child {
                    margin-left: 12px;
                }
            }
        }
        .back-btn :deep(.van-button) {
            width: 100%;
            width: 324px;
            margin-left: 0px !important;
        }
        .leftBtn {
            width: 27px;
            height: 27px;
            cursor: pointer;
            img {
                width: 27px;
                height: 27px;
            }
        }
        .disableds {
            background: #999 !important;
            cursor: not-allowed !important;
            pointer-events: none;
            opacity: 0.3 !important;
        }
    }
@@ -986,12 +136,10 @@
            font-weight: bold;
            font-size: 16px;
            color: #222324;
            // margin-bottom: 16px;
        }
        .workOrderContainer {
            .orderRow {
                // margin-bottom: 10px;
                display: flex;
                justify-content: space-between;
                align-items: center;
@@ -1034,35 +182,16 @@
            }
            .rowAddress {
                font-family: Source Han Sans CN, Source Han Sans CN;
                font-weight: 400;
                font-size: 14px;
                color: #1d6fe9;
                white-space: nowrap;
                /* 禁止换行 */
                overflow: hidden;
                text-overflow: ellipsis;
                // max-width: 74%;
                text-decoration: underline;
                text-align: right;
                padding-top: 1px;
                padding-left: 5px;
                padding-right: 2px;
            }
            .selectTrigger {
                font-family: Source Han Sans CN, Source Han Sans CN;
                font-weight: 400;
                font-size: 14px;
                color: #222324;
            }
            .pointing {
                width: 8px;
                height: 12px;
            }
            .downpointing {
                width: 12px;
                height: 7px;
            }
            :deep(.custom-field) {
                padding: 0 !important;
                padding-left: 10px !important;
@@ -1072,20 +201,8 @@
                padding: 0 !important;
            }
            .titketName {
                display: flex;
                align-items: center;
            }
        }
    }
    .upload-link {
        font-family: Source Han Sans CN, Source Han Sans CN;
        font-weight: 400;
        font-size: 12px;
        color: #1d6fe9;
        cursor: pointer;
        text-decoration: underline;
    }
}
</style>