<template>
|
<basic-container>
|
<el-tabs v-model="activeTab" @tab-click="handleTabChange">
|
<el-tab-pane
|
v-for="tab in filteredTabs"
|
:key="tab.name"
|
:label="tab.name === 'myTickets' ? tab.label : `${tab.label} (${tab.count})`"
|
:name="tab.name"
|
>
|
<basic-main-content>
|
<!-- 查询条件筛选栏 -->
|
<div class="command-form-search">
|
<el-form :model="filters" inline>
|
<div class="searchBox">
|
<el-form-item label="关键字:">
|
<el-input
|
v-model="filters.keyword"
|
placeholder="请输入关键字"
|
class="filter-item"
|
clearable
|
@clear="handleKeyWords"
|
@keyup.enter="handleSearch"
|
/>
|
</el-form-item>
|
<el-form-item label="选择日期:">
|
<el-date-picker
|
clearable
|
@clear="handleKeyWords"
|
@change="handleSearch"
|
v-model="filters.dateRange"
|
type="daterange"
|
class="filter-item"
|
range-separator="至"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
:default-value="datePickerDefaultVal"
|
>
|
</el-date-picker>
|
</el-form-item>
|
<el-form-item label="选择状态:">
|
<el-select
|
:disabled="activeTab !== 'all'"
|
v-model="filters.status"
|
placeholder="请选择状态"
|
class="filter-item"
|
clearable
|
@change="handleSearch"
|
>
|
<el-option
|
v-for="item in statuses"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="选择机巢:">
|
<el-select
|
v-model="filters.device_sn"
|
placeholder="请选择机巢"
|
class="filter-item"
|
clearable
|
@change="handleSearch"
|
>
|
<el-option
|
v-for="item in machineData"
|
:key="item.device_sn"
|
:label="item.nickname"
|
:value="item.device_sn"
|
/>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="选择算法:">
|
<el-tree-select
|
style="z-index: 1200"
|
:teleported="false"
|
class="custom-tree-select"
|
|
v-model="dictKey"
|
:data="dataList"
|
:default-expanded-keys="[dictKey]"
|
:props="treePropsSF"
|
:render-after-expand="false"
|
:default-checked-keys="checkedKeys"
|
node-key="id"
|
multiple
|
show-checkbox
|
collapse-tags
|
collapse-tags-tooltip
|
clearable
|
@check="handleCheck"
|
@clear="handleClear"
|
/>
|
</el-form-item>
|
<el-form-item label="复核状态:" v-if="activeTab === 'completed'">
|
<el-select
|
v-model="filters.isReview"
|
placeholder="请选择复核状态"
|
class="filter-item"
|
clearable
|
@change="handleSearch"
|
>
|
<el-option
|
v-for="item in reviewStatuses"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
<div class="btnGroup">
|
<el-button type="primary" icon="el-icon-search" @click="handleSearch"
|
>搜索</el-button
|
>
|
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
</div>
|
</div>
|
</el-form>
|
</div>
|
<!-- 表格部分 -->
|
<div class="table-operations">
|
<div class="left-operations">
|
<el-button
|
v-if="(activeTab === 'all' || activeTab === 'myTickets') && permissionList.addBtn"
|
type="primary"
|
icon="el-icon-plus"
|
@click="handleAdd"
|
>
|
新建工单
|
</el-button>
|
<el-button
|
v-if="activeTab === 'pending' && permissionList.reviewBtn"
|
type="success"
|
icon="el-icon-check"
|
@click="openReviewDialog"
|
>
|
批量审核
|
</el-button>
|
|
<el-button
|
v-if="permissionList.exportBtn"
|
type="success"
|
plain
|
icon="el-icon-download"
|
@click="exportData"
|
>
|
导出
|
</el-button>
|
</div>
|
</div>
|
<div class="titketBox">
|
<div class="dataTable">
|
<el-table
|
class="command-public-general-el-table custom-header"
|
ref="elTable"
|
:data="tableData"
|
v-loading="loading"
|
@selection-change="handleSelectionChange"
|
border
|
style="width: 100%"
|
v-if="activeTab === tab.name"
|
>
|
<el-table-column type="selection" width="55" v-if="permissionList.reviewBtn || permissionList.exportBtn" />
|
<el-table-column type="index" label="序号" width="60" />
|
<el-table-column prop="orderNumber" label="工单编号" width="170">
|
<template #default="{ row }">
|
<el-tooltip-copy :content="row.orderNumber" :showCopyText="true" textAlign="left">
|
{{ row.orderNumber }}
|
</el-tooltip-copy>
|
</template>
|
</el-table-column>
|
<el-table-column prop="orderName" label="工单名称" width="150" show-overflow-tooltip>
|
<template #default="{ row }">
|
<el-tooltip-copy :content="row.orderName" :showCopyText="true" textAlign="left">
|
{{ row.orderName }}
|
</el-tooltip-copy>
|
</template>
|
</el-table-column>
|
|
<el-table-column prop="department" label="所属部门" width="120" show-overflow-tooltip />
|
|
|
<el-table-column prop="startTime" label="发起任务时间" width="160" show-overflow-tooltip />
|
|
<el-table-column prop="aiType" label="关联算法" width="120" show-overflow-tooltip />
|
|
<el-table-column prop="type" label="工单类型" width="110" show-overflow-tooltip>
|
<template #default="{ row }">
|
{{ getTypeLabel(row.type) }}
|
</template>
|
</el-table-column>
|
<el-table-column prop="device_names" label="所属机巢" width="120" show-overflow-tooltip />
|
<el-table-column prop="dataSources" label="工单来源" width="90">
|
</el-table-column>
|
<el-table-column prop="content" label="工单内容" width="132" show-overflow-tooltip>
|
<template #default="{ row }">
|
{{ row.address || row.content }}
|
</template>
|
</el-table-column>
|
|
<el-table-column prop="creator" label="创建人" width="120" show-overflow-tooltip />
|
|
<el-table-column prop="handler" label="处理人" width="120" show-overflow-tooltip />
|
|
<el-table-column
|
v-if="['all', 'completed', 'myTickets'].includes(activeTab)"
|
label="复核状态"
|
prop="isReview"
|
width="90"
|
>
|
<template #default="{ row }">
|
<span>{{ showIsReviewText(row) }}</span>
|
</template>
|
</el-table-column>
|
|
<el-table-column label="工单状态" prop="status" width="90">
|
<template #default="{ row }">
|
<span :style="getStatusTagType(row.status) ? 'color:' + getStatusTagType(row.status) : ''">
|
{{ mapStatus(row.status) }}
|
</span>
|
</template>
|
</el-table-column>
|
|
<!-- 操作列 -->
|
<el-table-column label="操作" width="200" align="center">
|
<template #default="{ row }">
|
<template v-if="row.status === -1">
|
<el-button type="text" icon="el-icon-edit" @click="handleEdit(row)">编辑</el-button>
|
<el-button type="text" icon="el-icon-delete" class="danger-button" @click="handleDelete(row)">
|
删除
|
</el-button>
|
</template>
|
|
<template v-else>
|
<el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情</el-button>
|
</template>
|
|
<!-- <template v-if="row.status === 4 && !isProd">
|
<el-button type="text" icon="el-icon-download" @click="exportTheTick(row)">导出</el-button>
|
</template> -->
|
|
<template v-if="permission.tickets_repeat_review">
|
<el-button
|
v-if="row.status === 4 && row.isReview !== 1"
|
type="text"
|
icon="el-icon-check"
|
@click="reCheck(row)"
|
>
|
复核
|
</el-button>
|
</template>
|
</template>
|
</el-table-column>
|
<template #empty>
|
<el-empty
|
class="custom-empty"
|
:image-size="100"
|
>
|
<template #description>
|
<span class="custom-text">暂无数据</span>
|
</template>
|
</el-empty>
|
</template>
|
</el-table>
|
</div>
|
<div class="pagination" v-if="tableData.length > 0">
|
<el-pagination
|
class="table-pagination"
|
v-model:current-page="page.currentPage"
|
v-model:page-size="page.pageSize"
|
:page-sizes="[10, 20, 30, 40]"
|
:total="page.total"
|
background
|
layout="total, sizes, prev, pager, next, jumper"
|
@size-change="sizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
</div>
|
</basic-main-content>
|
</el-tab-pane>
|
</el-tabs>
|
|
<!-- 新建工单对话框 -->
|
<create-ticket-dialog
|
v-model="dialogVisible"
|
:departments="departments"
|
:department-users="departmentUsers"
|
:types="types"
|
:all-algorithms="allAlgorithms"
|
:edit-data="editFormData"
|
:map-center="inputMapShowDefaultCenter"
|
@create-success="handleCreateSuccess"
|
@draft-success="handleDraftSuccess"
|
@create-error="handleCreateError"
|
/>
|
<!-- 工单详情对话框 -->
|
<ticket-detail-dialog
|
v-model="detailVisible"
|
:current-detail="currentDetail"
|
:current-index="currentIndex"
|
:total-items="tableData.length"
|
:algorithms="algorithms2"
|
:types="types"
|
:permission="permission"
|
:step-status-list="stepStatusList"
|
:work-type="workType"
|
@detail-success="handleDetailSuccess"
|
@detail-error="handleDetailError"
|
@prev-item="handlePrevItem"
|
@next-item="handleNextItem"
|
@update:current-detail="handleCurrentDetailUpdate"
|
@approve-and-dispatch="handleApproveAndDispatch"
|
/>
|
|
<!-- 派发工单对话框 -->
|
<dispatch-dialog
|
v-model="dispatchDialogVisible"
|
:current-detail="currentDetail"
|
:department-users="departmentUsers"
|
:algorithms="algorithms"
|
:types="types"
|
@dispatch-success="handleDispatchSuccess"
|
@dispatch-error="handleDispatchError"
|
/>
|
|
<!-- 批量审核对话框 -->
|
<el-dialog
|
v-model="reviewDialogVisible"
|
title="批量审核"
|
width="1100"
|
align-center
|
append-to-body
|
class="command-dialog-mange"
|
custom-class="review-dialog"
|
@close="cancleBatchReject"
|
>
|
<div class="review-container">
|
<div class="review-image-wrapper">
|
<!-- 修改左右箭头的显示条件 -->
|
<el-button
|
v-if="selections.length > 1 && currentReviewImage"
|
class="arrow-button left"
|
@click="handlePrevImage"
|
icon="el-icon-arrow-left"
|
>
|
</el-button>
|
|
<div class="review-image-container">
|
<!-- <el-image v-if="currentReviewImage" :src="getThumbUrl(currentReviewImage)" fit="fill"
|
:preview-src-list="getImageList()" :initial-index="currentImageIndex - 1" class="preview-image"
|
style="cursor: pointer"> -->
|
<el-image
|
v-if="currentReviewImage"
|
:src="getPreviewUrl(currentReviewImage)"
|
fit="fill"
|
:initial-index="currentImageIndex - 1"
|
class="preview-image"
|
style="cursor: pointer"
|
>
|
<template #error>
|
<div class="image-error">
|
<i class="el-icon-picture-outline"></i>
|
<span>图片加载失败</span>
|
</div>
|
</template>
|
</el-image>
|
<div v-else class="no-image">暂无图片</div>
|
</div>
|
|
<!-- 修改右箭头的显示条件 -->
|
<el-button
|
v-if="selections.length > 1 && currentReviewImage"
|
class="arrow-button right"
|
@click="handleNextImage"
|
icon="el-icon-arrow-right"
|
>
|
</el-button>
|
</div>
|
|
<!-- 修改分页器的显示条件 -->
|
<div class="review-pagination" v-if="selections.length > 1 && currentReviewImage">
|
<el-pagination
|
small
|
layout="prev, pager, next"
|
hide-on-single-page
|
:total="selections.length"
|
:current-page="currentImageIndex"
|
:page-size="1"
|
@current-change="handleImagePageChange"
|
>
|
</el-pagination>
|
</div>
|
</div>
|
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary" @click="handleBatchApprove" icon="el-icon-check"
|
>通过
|
</el-button>
|
<el-button type="danger" @click="handleBatchReject" icon="el-icon-close"
|
>不通过
|
</el-button>
|
<el-button @click="cancleBatchReject" icon="el-icon-circle-close">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
<!-- 复核弹出层 -->
|
<recheck-dialog
|
v-model="reCheckDialog"
|
:recheck-data="reCheckData"
|
@recheck-success="handleRecheckSuccess"
|
/>
|
</basic-container>
|
</template>
|
|
<script setup>
|
import {ALL_WORK_ORDER_TYPE_OPTIONS} from '@ztzf/constants'
|
import { getDateRange } from '@/utils/date'
|
import { getDeviceRegion } from '@/api/job/task';
|
import { ElMessage} from 'element-plus';
|
import { useRoute, useRouter } from 'vue-router'
|
import { useStore } from 'vuex'
|
import { pxToRem, pxToRemNum } from '@/utils/rem';
|
import { getSmallImg, getShowImg } from '@/utils/util';
|
import { calculateDefaultRange } from '@/utils/util';
|
import { gcj02ToWgs84, wgs84ToGcj02 } from '@/utils/coordinateTransformation';
|
import _ from 'lodash';
|
import {
|
getList,
|
getTicketInfo,
|
flowEvent,
|
getstatusCount,
|
getStepInfo,
|
exportTheTicket
|
} from '@/api/tickets/ticket';
|
import { getSFDictionaryTree } from '@/api/job/task';
|
import { export_json_to_excel } from '@/utils/exportExcel';
|
import geoJson from '@/assets/geoJson.json';
|
import { mapGetters } from 'vuex';
|
import { getAdcodeObj } from '@/utils/disposeData';
|
import elTooltipCopy from '@/components/ElTooltipCopy.vue';
|
import getBaseConfig from '@/buildConfig/config';
|
import RecheckDialog from '@/views/tickets/ticketComponent/RecheckDialog.vue';
|
import DispatchDialog from '@/views/tickets/ticketComponent/DispatchDialog.vue';
|
import CreateTicketDialog from '@/views/tickets/ticketComponent/CreateTicketDialog.vue';
|
import TicketDetailDialog from '@/views/tickets/ticketComponent/TicketDetailDialog.vue';
|
const { envName } = getBaseConfig();
|
const isProd = import.meta.env.VITE_APP_ENV === 'production'
|
const route = useRoute()
|
const router = useRouter()
|
const store = useStore()
|
const userAreaCode = computed(() => store.getters.userInfo.detail.areaCode);
|
const currentIndex = ref(null)
|
const finalizeLoading = ref(false)
|
const activeTab = ref('all')
|
let machineData = ref([]);
|
const tabs = ref([
|
{ label: '我的工单', name: 'myTickets', value: null, count: 0 },
|
{ label: '全部工单', name: 'all', value: null, count: 0 },
|
{ label: '待审核', name: 'pending', value: 2, count: 0 },
|
{ label: '待处理', name: 'processing', value: 0, count: 0 },
|
{ label: '处理中', name: 'inProgress', value: 3, count: 0 },
|
{ label: '已完成', name: 'completed', value: 4, count: 0 },
|
])
|
const dateRanges = {
|
today: getDateRange('today').map(d => new Date(d)), // 转为 Date 对象
|
week: getDateRange('week').map(d => new Date(d)),
|
month: getDateRange('month').map(d => new Date(d)),
|
year: getDateRange('year').map(d => new Date(d)),
|
}
|
const filters = reactive({
|
keyword: '',
|
department: '',
|
type: '',
|
dateRange: [],
|
status: '',
|
algorithm: '',
|
isReview: '',
|
device_sn:''
|
})
|
const departments = ref([])
|
const types = ref([])
|
const allAlgorithms = ref([])
|
const handlers = ref([
|
{ label: '处理人A', value: 'handlerA' },
|
{ label: '处理人B', value: 'handlerB' },
|
])
|
const algorithms = ref([])
|
const algorithms2 = ref([])
|
const statuses = ref([
|
{ label: '待审核', value: '2' },
|
{ label: '待处理', value: '0' },
|
{ label: '处理中', value: '3' },
|
{ label: '已完成', value: '4' },
|
])
|
const reviewStatuses = ref([
|
{ label: '否', value: 0 },
|
{ label: '是', value: 1 },
|
])
|
const tableData = ref([])
|
const page = reactive({
|
pageSize: 10,
|
currentPage: 1,
|
total: 0,
|
})
|
const dialogVisible = ref(false)
|
const editFormData = ref(null)
|
const detailVisible = ref(false)
|
const currentDetail = ref({})
|
const departmentUsers = ref({})
|
const loading = ref(true)
|
const globalCounts = ref({})
|
const mapLoaded = ref(false)
|
const isFetching = ref(false)
|
const mapParams = reactive({
|
zoom: 15,
|
center: null,
|
})
|
const dispatchDialogVisible = ref(false)
|
const stepInfos = ref([])
|
const userNameToIdMap = ref({})
|
const workType = ref(0)
|
const selections = ref([])
|
const reviewDialogVisible = ref(false)
|
const currentReviewImage = ref('')
|
const currentImageIndex = ref(1)
|
const totalTime = ref('')
|
const isShowInfo = ref(false)
|
const datePickerDefaultVal = ref(calculateDefaultRange())
|
const reCheckDialog = ref(false)
|
const reCheckData = ref({})
|
const treePropsSF = reactive({
|
label: 'dictValue',
|
value: 'id',
|
children: 'children',
|
})
|
const dictKey = ref('')
|
const dataList = ref([])
|
const checkedKeys = ref([])
|
const inputMapShowDefaultCenter = ref(null)
|
const userInfo = computed(() => store.state.user.userInfo)
|
const permission = computed(() => store.state.user.permission);
|
|
// 计算属性
|
const firstRowData = computed(() => {
|
return tableData.value.length > 0 ? tableData.value[0] : null
|
})
|
// 动态过滤tabs,保证isShow为true/false
|
const filteredTabs = computed(() => {
|
const tabPending = permission.value?.tickets_tab_pending === true//待审核
|
const tabMyTickets = permission.value?.tickets_tab_mytickets === true //我的工单
|
const tabALL = permission.value?.tickets_allWorkOrders === true //全部工单
|
const tabInProgress= permission.value?.tickets_inProgress === true //处理中
|
const tabProcessing= permission.value?.tickets_pending === true //待处理
|
const tabCompleted= permission.value?.tickets_wasDone === true //已完成
|
return tabs.value
|
.map(tab => {
|
switch (tab.name) {
|
case 'all':
|
return { ...tab, isShow: tabALL } // 全部工单
|
case 'pending':
|
return { ...tab, isShow: tabPending } // 待审核
|
case 'myTickets':
|
return { ...tab, isShow: tabMyTickets } // 我的工单
|
case 'processing':
|
return { ...tab, isShow: tabProcessing } // 待处理
|
case 'inProgress':
|
return { ...tab, isShow: tabInProgress } // 处理中
|
case 'completed':
|
return { ...tab, isShow: tabCompleted } // 已完成
|
default:
|
return { ...tab, isShow: false } // 其他标签默认隐藏
|
}
|
})
|
.filter(tab => tab.isShow)
|
})
|
// 可根据实际后端权限key调整
|
const permissionList = computed(() => {
|
return {
|
addBtn: validData(permission.value.tickets_add, false),
|
delBtn: validData(permission.value.tickets_delete, false),
|
exportBtn: validData(permission.value.tickets_export, false),
|
reviewBtn: validData(permission.value.tickets_review_btn, false),
|
}
|
})
|
// 计算默认激活的标签(无全部工单时优先激活待审核)
|
const defaultActiveTab = computed(() => {
|
const hasAllTab = filteredTabs.value.some(tab => tab.name === 'all')
|
const hasPendingTab = filteredTabs.value.some(tab => tab.name === 'pending')
|
if (!hasAllTab && hasPendingTab) {
|
return 'pending'
|
}
|
else if (hasAllTab) {
|
return 'all'
|
}
|
else {
|
return filteredTabs.value[0]?.name || 'all'
|
}
|
})
|
|
|
const handleNodeClick = async data => {
|
const droneList = await getDeviceRegion({ areaCode: userAreaCode.value });
|
machineData.value = droneList?.data?.data;
|
|
};
|
// 提取状态列表计算属性
|
const statusList = computed(() => {
|
const visibleTabs = filteredTabs.value;
|
return visibleTabs
|
.filter(tab => tab.name !== 'all' && tab.name !== 'myTickets' && tab.value !== undefined)
|
.map(tab => String(tab.value));
|
});
|
const stepStatusList = computed(() => {
|
return stepInfos.value.map(step => String(step.status))
|
})
|
const showIsReviewText = computed(() => (row) => {
|
if (['4'].includes(String(row.status))) return row.isReview === 1 ? '是' : '否'
|
return '/'
|
})
|
const popupShowImage = computed(() => (list) => {
|
return list.map(item => ({
|
...item,
|
url: getShowImg(item.url),
|
}))
|
})
|
// 方法
|
function validData(value, defaultValue) {
|
return value !== undefined ? value : defaultValue
|
}
|
// 获取表格数据
|
async function fetchTableData() {
|
if (isFetching.value) return
|
isFetching.value = true
|
loading.value = true
|
const statusListVal = statusList.value;
|
try {
|
const currentTab = tabs.value.find(tab => tab.name === activeTab.value)
|
const params = {
|
ai_types: filters.type || undefined,
|
status: currentTab?.name === 'myTickets'
|
? undefined
|
: filters.status !== ''
|
? Number(filters.status)
|
: currentTab?.value,
|
event_name: filters.keyword || undefined,
|
dept_id: filters.department || undefined,
|
start_date: filters.dateRange?.[0]
|
? formatDate(filters.dateRange[0])
|
: undefined,
|
end_date: filters.dateRange?.[1]
|
? formatDate(filters.dateRange[1]).replace('00:00:00', '23:59:59')
|
: undefined,
|
current: Number(page.currentPage),
|
size: Number(page.pageSize),
|
ai_type: filters.algorithm || undefined,
|
is_draft: currentTab?.name === 'myTickets' ? 1 : undefined,
|
user_id: currentTab?.name === 'myTickets' ? userInfo.value.user_id : undefined,
|
is_review: filters.isReview === '' ? undefined : filters.isReview,
|
source: 1,
|
status_list:currentTab?.name !== 'myTickets'? statusListVal : undefined,
|
device_sn:filters.device_sn,
|
work_types: ALL_WORK_ORDER_TYPE_OPTIONS
|
}
|
|
const response = await getList(params)
|
if (!response?.data?.data?.records) {
|
throw new Error('接口返回数据格式不正确')
|
}
|
const { total, records } = response.data.data
|
let filteredRecords = records
|
tableData.value = filteredRecords.map(item => {
|
const longitude = Number(item.longitude) || 0
|
const latitude = Number(item.latitude) || 0
|
const matchedMachine = machineData.value.find(m => m.device_sn === item.device_sn);
|
const deviceNickname = matchedMachine?.nickname || ''
|
return {
|
id: item.id,
|
orderNumber: item.event_num,
|
orderName: item.event_name,
|
department: departments.value.find(d => d.value === item.dept_id)?.label || item.dept_name,
|
startTime: item.job_create_time || '/',
|
aiType: item.ai_types,
|
content: item.content,
|
type: item.work_order_type_dict_key,
|
keyData: !isNaN(longitude) && !isNaN(latitude)
|
? `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`
|
: '未知位置',
|
address: item.address,
|
creator: item.event_num?.slice(0, 2) === 'AI' ? '智飞agent' : item.create_user,
|
handler: item.update_user || '未分配',
|
status: Number(item.status || 0),
|
photo_url: item.photo_url || '',
|
video_url: item.video_url || '',
|
location: !isNaN(longitude) && !isNaN(latitude) ? [longitude, latitude] : null,
|
processing_details: item.processing_details || '',
|
update_photo_url: item.update_photo_url || '',
|
work_type: item.work_type !== undefined ? Number(item.work_type) : 0,
|
job_name: item.job_name || '',
|
job_create_time: item.job_create_time || '',
|
isReview: item.is_review,
|
handle_user_id:item.handle_user_id,
|
dataSources:item.work_type === '0' ? '巡检任务' :
|
item.work_type === '1' ? '人工上报' :
|
item.work_type === '2' ? '识别分析' :
|
item.work_type === '3' ? '变化检测' :
|
'',
|
device_names:deviceNickname ? deviceNickname :''
|
|
}
|
|
})
|
|
page.total = total || 0
|
if (isShowInfo.value) {
|
handleViewDetail(firstRowData.value)
|
isShowInfo.value = false
|
}
|
await fetchTabCounts()
|
} catch (error) {
|
console.error('获取数据失败:', error)
|
tableData.value = []
|
page.total = 0
|
} finally {
|
loading.value = false
|
isFetching.value = false
|
}
|
}
|
// 获取工单类型标签
|
function getTypeLabel(typeValue) {
|
const typeObj = types.value.find(item => item.value === typeValue)
|
return typeObj ? typeObj.label : typeValue
|
}
|
function handleCheck(data, { checkedKeys: keys, checkedNodes }) {
|
checkedKeys.value = keys
|
const selectedDictKeys = checkedNodes.map(node => node.dictKey).filter(Boolean)
|
filters.type = selectedDictKeys
|
fetchTableData()
|
}
|
// 算法
|
function getAlgorithmList() {
|
getSFDictionaryTree({ code: 'SF' }).then(res => {
|
if (res.data.code === 200) {
|
const result = res.data.data[0].children
|
const filteredData = result.map(item => {
|
const children = item.children?.map(child => ({
|
...child,
|
children: [],
|
}))
|
return {
|
...item,
|
children: children || [],
|
}
|
})
|
dataList.value = filteredData
|
|
}
|
})
|
}
|
function handleSFNodeClick(data) {
|
filters.type = ''
|
filters.algorithm = ''
|
filters.type = data.dictKey
|
fetchTableData()
|
}
|
function handleClear() {
|
dictKey.value = ''
|
filters.algorithm = ''
|
filters.type = ''
|
fetchTableData()
|
}
|
// 上一项
|
function handlePrevItem() {
|
currentIndex.value = Math.max(0, currentIndex.value - 1)
|
updateCurrentDetail()
|
}
|
|
// 下一项
|
function handleNextItem() {
|
currentIndex.value = Math.min(tableData.value.length - 1, currentIndex.value + 1)
|
updateCurrentDetail()
|
}
|
|
// 更新当前详情
|
function updateCurrentDetail() {
|
currentDetail.value = tableData.value[currentIndex.value]
|
currentDetail.value.mediaUrl = currentDetail.value.photo_url
|
currentDetail.value.updatePhotoUrl = currentDetail.value.update_photo_url
|
currentDetail.value.processingDetail = currentDetail.value.processing_details
|
currentDetail.value.showQR = false
|
currentDetail.value.latAndLon = _.round(currentDetail.value.location[0], 6) + ',' + _.round(currentDetail.value.location[1], 6)
|
getStepInfoData(currentDetail.value.orderNumber)
|
}
|
|
// 更新当前详情数据
|
function handleCurrentDetailUpdate(updatedDetail) {
|
currentDetail.value = updatedDetail
|
}
|
// 受理并派发
|
function handleApproveAndDispatch(detail) {
|
if(!detail.orderName){
|
ElMessage.warning('请填写工单名称');
|
return;
|
}
|
if(!detail.aiType){
|
ElMessage.warning('请选择关联算法');
|
return;
|
}
|
|
if(!detail.content){
|
ElMessage.warning('请填写工单内容');
|
return;
|
}
|
currentDetail.value = detail
|
dispatchDialogVisible.value = true
|
}
|
async function loadAMapScripts() {
|
try {
|
const areaCode = userInfo.value.detail.areaCode
|
const subAreaCode = areaCode ? areaCode.substring(0, 6) : ''
|
const adcodeObj = getAdcodeObj(geoJson, 'adcode', subAreaCode)
|
|
const center = adcodeObj?.payload?.objects?.collection?.geometries?.[0]?.properties?.center
|
|
if (Array.isArray(center) && center.length === 2) {
|
inputMapShowDefaultCenter.value = center
|
} else {
|
const bbox = adcodeObj?.payload?.bbox
|
if (Array.isArray(bbox) && bbox.length === 4) {
|
const centerX = (bbox[0] + bbox[2]) / 2
|
const centerY = (bbox[1] + bbox[3]) / 2
|
inputMapShowDefaultCenter.value = [centerX, centerY]
|
} else {
|
inputMapShowDefaultCenter.value = [115.861365, 28.621311]
|
}
|
}
|
mapParams.center = [...inputMapShowDefaultCenter.value]
|
mapLoaded.value = true
|
} catch (error) {
|
console.error('地图加载失败:', error)
|
}
|
}
|
async function fetchDropdownData() {
|
try {
|
const response = await getTicketInfo()
|
const { dept_data, event_type, ai_type, info } = response.data.data
|
departments.value = dept_data.map(item => ({
|
label: item.dept_name,
|
value: item.id,
|
}))
|
|
departmentUsers.value = dept_data.reduce((acc, dept) => {
|
acc[dept.id] = dept.user_data || []
|
return acc
|
}, {})
|
|
types.value = Object.entries(event_type).map(([key, value]) => ({
|
label: value,
|
value: key,
|
}))
|
allAlgorithms.value = info
|
|
algorithms.value = ai_type?.map(item => ({
|
dict_key: item.dict_key,
|
dict_value: item.dict_value,
|
label: item.dict_value,
|
value: item.dict_key,
|
})) || []
|
|
algorithms2.value = _.cloneDeep(algorithms.value)
|
|
userNameToIdMap.value = {}
|
dept_data.forEach(dept => {
|
(dept.user_data || []).forEach(user => {
|
userNameToIdMap.value[user.name] = user.id
|
})
|
})
|
} catch (error) {
|
console.error('加载下拉框数据失败:', error)
|
}
|
}
|
|
function handleTypeChange(typeValue) {
|
if (!typeValue) {
|
algorithms2.value = []
|
return
|
}
|
const matchedCategory = allAlgorithms.value.find(category => category.dict_key === typeValue)
|
if (!matchedCategory || !matchedCategory.algorithms || matchedCategory.algorithms.length === 0) {
|
algorithms2.value = []
|
return
|
}
|
algorithms2.value = matchedCategory.algorithms.map(algo => ({
|
label: algo.dict_value,
|
value: algo.dict_key,
|
dict_key: algo.dict_key,
|
dict_value: algo.dict_value,
|
}))
|
}
|
function formatDate(date) {
|
if (!date) return undefined
|
const d = new Date(date)
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(
|
d.getDate()
|
).padStart(2, '0')} 00:00:00`
|
}
|
|
function mapStatus(status) {
|
const statusTextMap = {
|
|
2: '待审核',
|
0: '待处理',
|
3: '处理中',
|
4: '已完成',
|
}
|
return statusTextMap[status] || '未知状态'
|
}
|
function getStatusTagType(status) {
|
if (status === -1 || status === '-1') return ''
|
const colorMap = {
|
0: '#FF7411',
|
3: '#FFC300',
|
2: '#FF472F',
|
4: '#0291A1',
|
}
|
return colorMap[String(status)] || ''
|
}
|
// 获取tab数据
|
async function fetchTabCounts() {
|
const statusListVal = statusList.value;
|
const params = {
|
status_list: statusListVal,
|
work_types: ALL_WORK_ORDER_TYPE_OPTIONS
|
}
|
try {
|
const response = await getstatusCount(params)
|
const statusCount = response.data.data || {}
|
const totalCount = Object.entries(statusCount).reduce((sum, [key, count]) => {
|
if (key === '6') return sum
|
return sum + (count || 0)
|
}, 0)
|
tabs.value.forEach(tab => {
|
if (tab.name === 'all') {
|
tab.count = totalCount
|
} else if (tab.name === 'myTickets') {
|
tab.count = 0
|
} else {
|
tab.count = statusCount[String(tab.value)] || 0
|
}
|
})
|
} catch (error) {
|
console.error('获取标签页计数失败:', error)
|
tabs.value.forEach(tab => {
|
tab.count = 0
|
})
|
}
|
}
|
|
function handleTabChange(tab) {
|
activeTab.value = tab.props?.name || tab.name
|
fetchTabCounts()
|
handleReset()
|
page.currentPage = 1
|
fetchTableData()
|
}
|
|
// 跳转后触发的Tab切换
|
function handleTabChangeAfterJump() {
|
// handleReset()
|
page.currentPage = 1
|
handleSearch()
|
fetchTableData()
|
fetchTabCounts()
|
}
|
function handleSearch() {
|
page.currentPage = 1
|
fetchTableData()
|
fetchTabCounts()
|
}
|
function handleReset() {
|
dictKey.value = ''
|
Object.assign(filters, {
|
keyword: '',
|
department: '',
|
type: '',
|
dateRange: [],
|
status: '',
|
algorithm: '',
|
isReview: '',
|
device_sn:''
|
})
|
page.currentPage = 1
|
router.replace({})
|
fetchTableData()
|
}
|
|
function handleKeyWords() {
|
router.replace({})
|
}
|
|
// 分页
|
async function handleCurrentChange(val) {
|
page.currentPage = val
|
await nextTick()
|
await fetchTableData()
|
}
|
|
async function sizeChange(val) {
|
page.pageSize = val
|
page.currentPage = 1
|
await nextTick()
|
await fetchTableData()
|
}
|
|
function handleAdd() {
|
editFormData.value = null
|
dialogVisible.value = true
|
}
|
|
async function getStepInfoData(val) {
|
const orderNum = val
|
const stepResponse = await getStepInfo(orderNum)
|
const steps = Array.isArray(stepResponse.data.data)
|
? stepResponse.data.data
|
: stepResponse.data.data?.steps || []
|
const finishedStep = steps.find(s => String(s.status) === '4')
|
totalTime.value = finishedStep && finishedStep.total_time ? finishedStep.total_time : ''
|
stepInfos.value = steps.map(step => ({
|
status: String(step.status),
|
name: step.name,
|
time: step.time,
|
create_time: step.create_time,
|
}))
|
}
|
// 详情
|
async function handleViewDetail(row) {
|
console.log('row',row);
|
|
currentIndex.value = tableData.value.findIndex(item => item.id === row.id)
|
workType.value = row.work_type !== undefined ? Number(row.work_type) : 0
|
const detailData = {
|
...row,
|
processingDetail: row.processing_details || '',
|
mediaUrl: row.photo_url || row.video_url || '',
|
updatePhotoUrl: row.update_photo_url || '',
|
photos: [],
|
job_name: row.job_name || '',
|
}
|
|
await getStepInfoData(row.orderNumber)
|
currentDetail.value.status = row.status
|
|
currentDetail.value = {
|
...detailData,
|
showQR: false,
|
latAndLon: _.round(detailData.location[0], 6) + ',' + _.round(detailData.location[1], 6),
|
}
|
// console.log('currentDetail.value',currentDetail.value);
|
|
detailVisible.value = true
|
handleTypeChange(currentDetail.value.type)
|
}
|
|
// 详情成功回调
|
function handleDetailSuccess() {
|
fetchTableData()
|
}
|
|
// 详情错误回调
|
function handleDetailError(error) {
|
console.error('工单操作失败:', error)
|
}
|
|
function refreshChange() {
|
if (isFetching.value) return
|
fetchTableData()
|
}
|
|
function onLoad() {
|
if (isFetching.value) return
|
fetchTableData()
|
}
|
// 导出数据
|
async function exportData() {
|
try {
|
loading.value = true
|
let exportData = []
|
|
if (selections.value.length > 0) {
|
exportData = selections.value.map(item => formatExportItem(item))
|
} else {
|
exportData = tableData.value.map(item => formatExportItem(item))
|
}
|
|
if (exportData.length === 0) {
|
console.warn('没有数据可供导出')
|
ElMessage.warning('没有数据可供导出');
|
return
|
}
|
|
const headers = [
|
'工单编号',
|
'工单名称',
|
'所属部门',
|
'发起时间',
|
'关联算法',
|
'工单内容',
|
'工单类型',
|
'经纬度',
|
'创建人',
|
'处理人',
|
'工单状态',
|
]
|
|
export_json_to_excel(headers, exportData, '工单数据')
|
} catch (error) {
|
console.error('导出失败:', error)
|
} finally {
|
loading.value = false
|
}
|
}
|
|
function formatExportItem(item) {
|
const longitude = Number(item.longitude) || Number(item.location?.[0]) || 0
|
const latitude = Number(item.latitude) || Number(item.location?.[1]) || 0
|
|
return {
|
工单编号: item.orderNumber || item.event_num || '',
|
工单名称: item.orderName || item.event_name || '',
|
所属部门: item.department || item.dept_name || '',
|
发起时间: item.startTime || item.create_time || '',
|
关联算法: item.aiType || item.ai_types || '',
|
工单内容: item.address || item.content || '',
|
工单类型: types.value.find(t => t.value === (item.type || item.work_order_type_dict_key))?.label || '',
|
经纬度: !isNaN(longitude) && !isNaN(latitude)
|
? `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`
|
: '',
|
创建人: item.creator || item.create_user || '',
|
处理人: item.handler || item.update_user || '',
|
工单状态: mapStatus(Number(item.status || 0)),
|
}
|
}
|
// 派发成功回调
|
function handleDispatchSuccess() {
|
detailVisible.value = false
|
fetchTableData()
|
}
|
// 派发错误回调
|
function handleDispatchError(error) {
|
console.error('派发失败:', error)
|
}
|
// 编辑工单
|
function handleEdit(row) {
|
editFormData.value = row
|
dialogVisible.value = true
|
}
|
|
// 创建成功回调
|
function handleCreateSuccess() {
|
fetchTableData()
|
}
|
|
// 草稿保存成功回调
|
function handleDraftSuccess() {
|
fetchTableData()
|
}
|
|
// 创建失败回调
|
function handleCreateError(error) {
|
console.error('工单操作失败:', error)
|
}
|
|
// 删除方法
|
function handleDelete(row) {
|
|
}
|
|
// 添加选择变化处理方法
|
function handleSelectionChange(selection) {
|
selections.value = selection
|
}
|
|
// 打开审核对话框
|
function openReviewDialog() {
|
if (selections.value.length === 0) {
|
ElMessage.warning('请先选择要审核的工单');
|
return
|
}
|
currentImageIndex.value = 1
|
updateCurrentReviewImage()
|
reviewDialogVisible.value = true
|
}
|
|
// 更新当前审核图片
|
function updateCurrentReviewImage() {
|
if (!selections.value || selections.value.length === 0) {
|
currentReviewImage.value = ''
|
currentImageIndex.value = 1
|
return
|
}
|
if (currentImageIndex.value > selections.value.length) {
|
currentImageIndex.value = selections.value.length
|
}
|
if (currentImageIndex.value < 1) {
|
currentImageIndex.value = 1
|
}
|
const index = currentImageIndex.value - 1
|
if (index >= 0 && index < selections.value.length) {
|
const currentItem = selections.value[index]
|
currentReviewImage.value = currentItem.photo_url || ''
|
} else {
|
currentReviewImage.value = ''
|
}
|
}
|
|
// 处理图片分页变化
|
function handleImagePageChange(page) {
|
if (page > 0 && page <= selections.value.length) {
|
currentImageIndex.value = page
|
updateCurrentReviewImage()
|
}
|
}
|
|
// 批量审核通过
|
async function handleBatchApprove() {
|
try {
|
if (selections.value.length === 0) {
|
console.warn('没有选中的工单')
|
return
|
}
|
|
const currentItem = selections.value[currentImageIndex.value - 1]
|
if (!currentItem) {
|
console.warn('当前工单数据无效')
|
return
|
}
|
|
// 在Vue 3中需要使用ElMessageBox.confirm
|
|
const data = {
|
id: currentItem.id,
|
status: currentItem.status,
|
isPass: 0,
|
eventNum: currentItem.orderNumber,
|
}
|
|
const response = await flowEvent(data)
|
if (response.data.code === 0) {
|
|
|
const newSelections = [...selections.value]
|
newSelections.splice(currentImageIndex.value - 1, 1)
|
|
if (newSelections.length > 0) {
|
if (currentImageIndex.value > selections.value.length) {
|
currentImageIndex.value = selections.value.length
|
}
|
updateCurrentReviewImage()
|
} else {
|
reviewDialogVisible.value = false
|
currentImageIndex.value = 1
|
currentReviewImage.value = ''
|
fetchTableData()
|
}
|
|
selections.value = newSelections
|
} else {
|
throw new Error(response.data.msg || '审核失败')
|
}
|
} catch (error) {
|
console.error('审核失败:', error)
|
}
|
}
|
|
function cancleBatchReject() {
|
reviewDialogVisible.value = false
|
selections.value = []
|
currentImageIndex.value = 1
|
currentReviewImage.value = ''
|
fetchTableData()
|
}
|
|
// 批量审核不通过
|
async function handleBatchReject() {
|
try {
|
if (selections.value.length === 0) {
|
console.warn('没有选中的工单')
|
return
|
}
|
|
const currentItem = selections.value[currentImageIndex.value - 1]
|
if (!currentItem) {
|
console.warn('当前工单数据无效')
|
return
|
}
|
|
// 在Vue 3中需要使用ElMessageBox.confirm
|
const data = {
|
id: currentItem.id,
|
status: currentItem.status,
|
isPass: 1,
|
eventNum: currentItem.orderNumber,
|
eventName: currentItem.orderName,
|
}
|
|
const response = await flowEvent(data)
|
if (response.data.code === 0) {
|
|
|
const newSelections = [...selections.value]
|
newSelections.splice(currentImageIndex.value - 1, 1)
|
selections.value = newSelections
|
|
if (selections.value.length > 0) {
|
if (currentImageIndex.value > selections.value.length) {
|
currentImageIndex.value = selections.value.length
|
}
|
updateCurrentReviewImage()
|
} else {
|
reviewDialogVisible.value = false
|
currentImageIndex.value = 1
|
currentReviewImage.value = ''
|
fetchTableData()
|
}
|
} else {
|
throw new Error(response.data.msg || '驳回失败')
|
}
|
} catch (error) {
|
console.error('驳回失败:', error)
|
}
|
}
|
|
// 获取所有图片列表用于预览
|
function getImageList() {
|
return selections.value.map(item => getPreviewUrl(item.photo_url)).filter(url => url)
|
}
|
|
// 处理上一张图片
|
function handlePrevImage() {
|
if (currentImageIndex.value > 1) {
|
currentImageIndex.value--
|
updateCurrentReviewImage()
|
}
|
}
|
|
// 处理下一张图片
|
function handleNextImage() {
|
if (currentImageIndex.value < selections.value.length) {
|
currentImageIndex.value++
|
updateCurrentReviewImage()
|
}
|
}
|
|
/**
|
* 获取缩略图地址
|
*/
|
function getThumbUrl(url) {
|
if (!url) return ''
|
const lastDot = url.lastIndexOf('.')
|
if (lastDot === -1) return url
|
return url.slice(0, lastDot) + '_small' + url.slice(lastDot)
|
}
|
|
// 获取预览图地址
|
function getPreviewUrl(url) {
|
if (!url) return ''
|
const lastDot = url.lastIndexOf('.')
|
if (lastDot === -1) return url
|
return url.slice(0, lastDot) + '_show' + url.slice(lastDot)
|
}
|
|
/**
|
* 坐标转换方法处理
|
*/
|
function disposeLocation(goWgs84 = false, data) {
|
let lng = ''
|
let lat = ''
|
|
if (Array.isArray(data.location) && data.location.length > 0) {
|
if (goWgs84) {
|
lng = data.location?.[0] ? String(data.location[0]) : undefined
|
lat = data.location?.[1] ? String(data.location[1]) : undefined
|
|
if (lng && lat) {
|
[lng, lat] = gcj02ToWgs84(Number(lng), Number(lat))
|
}
|
} else {
|
lng = Number(data.location[0])
|
lat = Number(data.location[1])
|
|
if (lng && lat) {
|
[lng, lat] = wgs84ToGcj02(Number(lng), Number(lat))
|
}
|
}
|
}
|
|
return [String(lng), String(lat)]
|
}
|
|
// 复核按钮
|
function reCheck(row) {
|
reCheckData.value = row
|
reCheckDialog.value = true
|
}
|
|
// 复核成功回调
|
function handleRecheckSuccess() {
|
page.currentPage = 1
|
fetchTableData()
|
fetchTabCounts()
|
}
|
|
// 导出工单报表
|
function exportTheTick(row) {
|
const params = {
|
num: row.orderNumber
|
}
|
exportTheTicket(params).then(res => {
|
const elink = document.createElement('a')
|
elink.download = row.orderName + '.docx'
|
elink.style.display = 'none'
|
const blob = new Blob([res.data])
|
elink.href = URL.createObjectURL(blob)
|
document.body.appendChild(elink)
|
elink.click()
|
document.body.removeChild(elink)
|
})
|
|
}
|
|
// 生命周期
|
onMounted(() => {
|
handleNodeClick()
|
inputMapShowDefaultCenter.value = null
|
loadAMapScripts()
|
fetchDropdownData()
|
getAlgorithmList()
|
// 设置默认activeTab
|
activeTab.value = defaultActiveTab.value
|
const href = window.location.href;
|
if (route?.query?.status !== undefined && route?.query?.status !== null) {
|
filters.status = route?.query?.status + ''
|
router.replace({})
|
}
|
|
let curQueryParams = {}
|
|
if (href?.indexOf('?') != -1 && href?.split('?').length > 0) {
|
curQueryParams = href
|
.split('?')[1]
|
.split('&')
|
.reduce((pre, cur) => {
|
let newArr = cur.split('=')
|
pre[newArr[0]] = newArr[1]
|
return pre
|
}, {})
|
|
const { orderNumber = undefined, day = undefined, tab = undefined,enumerateDates=undefined } = curQueryParams
|
|
if (day) {
|
const date = new Date(day + 'T00:00:00+08:00')
|
const dateArray = [date, date]
|
const handler = {
|
get(target, prop) {
|
if (typeof prop === 'string' && /^\d+$/.test(prop)) {
|
const index = parseInt(prop)
|
const dateObj = target[index]
|
return dateObj.toDateString() + ' 00:00:00 GMT+0800 (中国标准时间)'
|
}
|
return Reflect.get(target, prop)
|
},
|
}
|
|
const proxyArray = new Proxy(dateArray, handler)
|
filters.dateRange = proxyArray
|
}
|
|
if (orderNumber) {
|
filters.keyword = orderNumber
|
nextTick(() => {
|
isShowInfo.value = true
|
const find = store.state.tags.bsTagList.find(i => i.path === '/tickets/ticket')
|
if (find) {
|
find.query = {}
|
}
|
})
|
}
|
|
if (tab) {
|
|
if(enumerateDates === 'CURRENT_WEEK') {
|
filters.dateRange = [...dateRanges['week']]
|
} else if(enumerateDates === 'CURRENT_MONTH') {
|
filters.dateRange = [...dateRanges['month']]
|
} else {
|
filters.dateRange = [...dateRanges['year']]
|
}
|
const isTabValid = filteredTabs.value.some(t => t.name === tab)
|
if (isTabValid) {
|
activeTab.value = tab
|
handleTabChangeAfterJump()
|
const find = store.state.tags.bsTagList.find(i => i.path === '/tickets/ticket')
|
if (find) {
|
find.query = {}
|
}
|
}
|
}
|
}
|
|
fetchTabCounts()
|
fetchTableData()
|
})
|
|
onActivated(() => {
|
handleReset()
|
})
|
</script>
|
|
<style lang="scss" scoped>
|
.searchBox {
|
display: flex;
|
align-items: center;
|
flex-wrap: wrap;
|
margin-bottom: 15px;
|
gap: 15px 15px;
|
|
:deep() {
|
.el-form-item__label {
|
width: 80px;
|
}
|
.el-form-item {
|
width: 350px;
|
margin-bottom: 0 !important;
|
margin-right: 20px !important;
|
.el-form-item__label {
|
color: #363636;
|
line-height: 32px;
|
}
|
// .el-form-item__content{
|
// width: 280px;
|
// }
|
}
|
}
|
.btnGroup {
|
display: flex;
|
align-items: center;
|
}
|
}
|
.el-card__body {
|
height: 100%;}
|
.titketBox {
|
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
}
|
.dataTable {
|
// height: 0;
|
// flex: 1;
|
height: calc(100vh - 374px);
|
:deep(.el-scrollbar__view) {
|
height: 100%;
|
}
|
:deep(.el-table--fit,.el-scrollbar__view) {
|
height: 100%;
|
}
|
}
|
|
.pagination {
|
display: flex;
|
justify-content: flex-end;
|
margin-top: 20px;
|
position: fixed;
|
bottom: 20px;
|
left: 0;
|
right: 0;
|
padding: 0 30px;
|
|
z-index: 1000;
|
}
|
:deep(.custom-header th.el-table__cell) {
|
color: rgba(0, 0, 0, 0.85);
|
background: #fafafa;
|
height: 55px !important;
|
}
|
/* 表格操作区域样式 */
|
.table-operations {
|
margin-bottom: 16px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
}
|
|
.left-operations {
|
display: flex;
|
gap: 8px;
|
}
|
|
/* 表格样式 */
|
.command-public-general-el-table {
|
margin-bottom: 16px;
|
}
|
|
/* 分页样式 */
|
.table-pagination {
|
display: flex;
|
justify-content: flex-end;
|
margin-top: 10px;
|
}
|
.command-public-general-el-table {
|
:deep(.el-table__header-wrapper) {
|
background-color: #f5f7fa;
|
}
|
|
:deep(.el-table th) {
|
background-color: #f5f7fa;
|
color: #606266;
|
font-weight: 600;
|
}
|
|
:deep(.el-table--border) {
|
border: 1px solid #ebeef5;
|
}
|
|
:deep(.el-table__empty-block) {
|
height: calc(100vh - 400px) !important;
|
}
|
}
|
::v-deep(.el-tabs) {
|
height: 100%;
|
display: flex;
|
flex-direction: column;
|
|
.el-tabs__header {
|
order: 1;
|
}
|
|
.el-tabs__content {
|
order: 2;
|
}
|
|
.el-tabs__content {
|
height: 0;
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
|
.el-tab-pane {
|
height: 0;
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
}
|
}
|
}
|
|
.filter-bar {
|
display: flex;
|
align-items: center;
|
margin-bottom: 15px;
|
flex-wrap: wrap;
|
gap: 8px; // 使用 gap 统一设置间距
|
|
.filter-item {
|
width: 280px; // 减小宽度
|
}
|
|
.date-picker {
|
// width: 240px; // 日期选择器宽度适当调整
|
}
|
|
.el-button {
|
margin-left: 0; // 覆盖 element-ui 默认的按钮间距
|
}
|
}
|
|
.uploadImg {
|
margin-bottom: 32px;
|
}
|
|
|
.action-bar {
|
margin-bottom: 16px;
|
}
|
|
.el-dialog {
|
.el-form-item {
|
margin-bottom: 20px;
|
}
|
}
|
|
.el-upload {
|
width: 100%;
|
display: flex;
|
flex-wrap: wrap;
|
|
:deep(.el-upload-list__item) {
|
transition: all 0.3s ease;
|
}
|
|
:deep(.el-upload-list__item:hover) {
|
background-color: #f5f7fa;
|
}
|
}
|
|
.el-upload__tip {
|
font-size: 12px;
|
color: #909399;
|
margin-top: 12px;
|
}
|
|
.create-ticket-form {
|
padding: 20px 10px;
|
|
.form-section {
|
background-color: #fff;
|
border-radius: 4px;
|
|
.el-row {
|
margin-bottom: 16px;
|
|
&:last-child {
|
margin-bottom: 0;
|
}
|
}
|
}
|
|
.location-wrapper {
|
width: 100%; // 修改为100%以适应父容器
|
height: auto; // 修改为auto以自适应内容
|
|
.map-button {
|
width: 100%; // 让按钮填满容器宽度
|
height: 36px; // 与其他输入框保持一致的高度
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
|
i {
|
margin-right: 4px;
|
}
|
}
|
|
.location-text {
|
margin-top: 8px;
|
padding: 8px 12px;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
color: #606266;
|
font-size: 13px;
|
line-height: 1.4;
|
}
|
}
|
|
.upload-wrapper {
|
.uploader {
|
:deep(.el-upload--picture-card) {
|
width: 120px;
|
height: 100px;
|
line-height: 128px;
|
}
|
|
:deep(.el-upload-list__item) {
|
width: 120px;
|
height: 120px;
|
}
|
}
|
|
.upload-tip {
|
font-size: 12px;
|
color: #909399;
|
line-height: 1.4;
|
margin-top: 8px;
|
}
|
}
|
|
.el-form-item {
|
margin-bottom: 18px;
|
|
&:last-child {
|
margin-bottom: 0;
|
}
|
}
|
|
:deep(.el-form-item__label) {
|
font-weight: 500;
|
color: #606266;
|
}
|
|
// :deep(.el-input__inner) {
|
// height: 36px;
|
// line-height: 36px;
|
// }
|
|
:deep(.el-textarea__inner) {
|
padding: 8px 12px;
|
}
|
|
// :deep(.el-input__inner),
|
// :deep(.el-select),
|
// :deep(.el-select .el-input) {
|
// width: 100%; // 确保所有输入框和选择框宽度一致
|
// }
|
|
.full-width {
|
width: 100%;
|
}
|
}
|
|
:deep(.el-dialog__body) {
|
border-top: 0.1rem solid #f0f0f0;
|
}
|
|
.dialog-footer-new {
|
text-align: right;
|
padding-top: 16px;
|
border-top: 1px solid #ebeef5;
|
|
.el-button + .el-button {
|
margin-left: 12px;
|
}
|
|
.el-button {
|
padding: 9px 20px;
|
|
&:last-child {
|
margin-left: 12px;
|
}
|
}
|
}
|
|
.dialog-footer1-new {
|
position: sticky;
|
bottom: 28px;
|
left: 0;
|
right: 0;
|
background: white;
|
z-index: 10;
|
padding: 16px 20px;
|
border-top: 1px solid #ebeef5;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
.el-button + .el-button {
|
margin-left: 12px;
|
}
|
|
.btngroups {
|
margin-left: 12px;
|
}
|
|
.el-button {
|
padding: 9px 20px;
|
|
&:last-child {
|
margin-left: 12px;
|
margin-right: 12px;
|
}
|
}
|
}
|
|
.map-container {
|
width: 100%;
|
height: 400px;
|
margin-bottom: 15px;
|
border: 1px solid #dcdfe6;
|
border-radius: 4px;
|
overflow: hidden;
|
|
:deep(.el-input-map) {
|
height: 100%;
|
}
|
}
|
|
.location-info {
|
margin-top: 10px;
|
padding: 10px;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
|
p {
|
margin: 5px 0;
|
color: #606266;
|
font-size: 14px;
|
}
|
}
|
|
.map-select {
|
display: flex;
|
align-items: flex-start;
|
gap: 15px;
|
|
.selected-location {
|
flex: 1;
|
padding: 5px 10px;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
|
p {
|
margin: 5px 0;
|
color: #606266;
|
font-size: 14px;
|
}
|
}
|
}
|
|
.preview-image {
|
border-radius: 4px;
|
overflow: hidden;
|
background-color: #f5f7fa;
|
}
|
|
.image-placeholder,
|
.image-error,
|
.no-media {
|
height: 200px;
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
color: #909399;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
|
i {
|
font-size: 32px;
|
margin-bottom: 8px;
|
}
|
}
|
|
.no-media {
|
border: 1px dashed #d9d9d9;
|
}
|
|
.detail-container {
|
padding: 0 20px;
|
|
.detail-top-title {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
|
.event-orderNumber {
|
margin-right: 10px;
|
}
|
}
|
}
|
|
.status-flow {
|
margin-bottom: 20px;
|
|
.custom-steps {
|
.el-step__description {
|
position: relative;
|
margin: 0;
|
padding: 0;
|
}
|
|
// 添加发起任务步骤的特殊样式
|
.init-step-info {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
text-align: center;
|
width: 130px;
|
|
.creator-name {
|
font-size: 14px;
|
font-weight: bold;
|
color: #303133;
|
margin-bottom: 4px;
|
}
|
|
.create-time {
|
font-size: 10px;
|
color: #909399;
|
}
|
}
|
|
// 保持其他步骤的原有样式
|
.step-info {
|
display: flex;
|
margin: 0;
|
padding: 0;
|
justify-content: space-between;
|
align-items: center;
|
width: 200px;
|
|
.process-time {
|
font-size: 10px;
|
color: #909399;
|
text-align: left;
|
margin-left: -50%;
|
padding-left: 0%;
|
flex: 1;
|
}
|
|
.handler-name {
|
font-size: 14px;
|
font-weight: bold;
|
color: #303133;
|
text-align: left;
|
flex: 1;
|
}
|
}
|
}
|
}
|
|
.basic-info {
|
margin-bottom: 20px;
|
}
|
|
.media-section {
|
// margin-bottom: 20px;
|
|
.el-row {
|
display: flex;
|
align-items: center;
|
}
|
}
|
|
.leftBtn {
|
width: 70px;
|
height: 32px;
|
background-color: #999;
|
border-radius: 5px;
|
text-align: center;
|
line-height: 32px;
|
color: #fff;
|
cursor: pointer;
|
opacity: 0.8;
|
}
|
|
.disableds {
|
background: #999 !important;
|
cursor: not-allowed !important;
|
pointer-events: none;
|
opacity: 0.3 !important;
|
}
|
|
.PopUpTableScrolls {
|
max-height: 600px;
|
overflow-y: scroll;
|
overflow-x: hidden;
|
}
|
|
.media-box {
|
width: 100%;
|
border: 1px solid #dcdfe6;
|
border-radius: 4px;
|
padding: 10px;
|
background: #fff;
|
box-sizing: border-box;
|
|
.media-title {
|
font-weight: bold;
|
margin-bottom: 5px;
|
display: flex;
|
align-items: center;
|
|
.QRCodeImg {
|
width: 18px;
|
height: 18px;
|
cursor: pointer;
|
padding-bottom: 1px;
|
}
|
}
|
|
.media-content {
|
position: relative;
|
height: 500px;
|
|
:deep(.el-image) {
|
width: 100% !important;
|
max-width: 100%;
|
max-height: 100%;
|
|
.el-image__inner {
|
width: 100%;
|
height: 100%;
|
object-fit: cover !important;
|
}
|
}
|
}
|
}
|
|
.image-placeholder,
|
.image-error,
|
.no-media {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
height: 100%;
|
color: #909399;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
}
|
|
.image-placeholder i,
|
.image-error i {
|
font-size: 32px;
|
margin-bottom: 8px;
|
}
|
|
.no-media {
|
border: 1px dashed #d9d9d9;
|
}
|
|
.info-table {
|
margin-bottom: 20px;
|
}
|
|
.info-item {
|
display: flex;
|
margin-bottom: 10px;
|
}
|
|
.info-label {
|
font-weight: bold;
|
width: 120px;
|
color: #606266;
|
}
|
|
.info-value {
|
flex: 1;
|
color: #303133;
|
word-break: break-word;
|
}
|
|
|
|
// 添加删除按钮样式
|
.danger-button {
|
color: #f56c6c;
|
}
|
|
.danger-button:hover {
|
color: #f78989;
|
}
|
|
.custom-steps-container {
|
width: 100%;
|
margin: 10px 0;
|
}
|
|
.steps-titles {
|
display: flex;
|
justify-content: space-between;
|
margin-bottom: 14px;
|
position: relative;
|
}
|
|
.step-title {
|
text-align: center;
|
flex: 1;
|
font-size: 14px;
|
color: #999;
|
position: relative;
|
padding-bottom: 5px;
|
}
|
|
.step-title.active {
|
color: #409eff;
|
font-weight: bold;
|
}
|
|
.event-title-center {
|
text-align: center;
|
font-size: 20px;
|
font-weight: bold;
|
margin-bottom: 5px;
|
color: #333;
|
}
|
|
.custom-steps {
|
margin-top: -20px;
|
|
:deep(.el-step__description) {
|
margin-top: 8px;
|
padding: 0 20px;
|
}
|
}
|
|
.step-description {
|
font-size: 14px;
|
color: #666;
|
line-height: 1.5;
|
display: block;
|
text-align: center;
|
|
&:first-child {
|
font-weight: bold;
|
margin-bottom: 4px;
|
}
|
}
|
|
// 覆盖其他相关样式
|
.status-flow {
|
.custom-steps {
|
.el-step__description {
|
position: relative;
|
margin: 0;
|
padding: 0;
|
}
|
|
// 移除之前的样式
|
.init-step-info,
|
.step-info {
|
display: block;
|
width: auto;
|
text-align: center;
|
}
|
}
|
}
|
|
// 添加新的样式
|
.review-dialog {
|
:deep(.el-dialog__body) {
|
padding: 0;
|
background-color: #f5f7fa;
|
border-top: 0.1rem solid #f0f0f0;
|
}
|
}
|
|
.re-check-dialog {
|
:deep(.el-dialog__body) {
|
padding: 0;
|
background-color: #f5f7fa;
|
border-top: 0.1rem solid #f0f0f0;
|
}
|
}
|
|
.review-container {
|
position: relative;
|
|
.review-image-wrapper {
|
position: relative;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
height: 600px;
|
background-color: #f5f7fa;
|
}
|
|
.review-image-container {
|
width: 100%;
|
height: 100%;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
|
:deep(.el-image) {
|
width: 100%;
|
height: 100%;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
|
.el-image__inner {
|
max-height: 100%;
|
max-width: 100%;
|
object-fit: contain;
|
}
|
}
|
}
|
|
.arrow-button {
|
position: absolute;
|
top: 50%;
|
transform: translateY(-50%);
|
width: 44px;
|
height: 44px;
|
background: rgba(0, 0, 0, 0.3);
|
border-radius: 50%;
|
border: none;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
cursor: pointer;
|
transition: all 0.3s;
|
z-index: 100;
|
|
&:hover {
|
background: rgba(0, 0, 0, 0.6);
|
}
|
|
i {
|
color: #fff;
|
font-size: 24px;
|
}
|
|
&.left {
|
left: 20px;
|
color: #ffffff;
|
}
|
|
&.right {
|
right: 20px;
|
color: #ffffff;
|
}
|
}
|
|
.preview-image {
|
max-width: 100%;
|
max-height: 100%;
|
}
|
|
.review-pagination {
|
padding: 16px 0;
|
display: flex;
|
justify-content: center;
|
background-color: #fff;
|
|
:deep(.el-pagination) {
|
.btn-prev,
|
.btn-next {
|
display: none;
|
}
|
|
.el-pager {
|
.number {
|
margin: 0 4px;
|
}
|
}
|
}
|
}
|
|
.image-error {
|
height: 100%;
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
color: #909399;
|
|
i {
|
font-size: 48px;
|
margin-bottom: 16px;
|
}
|
|
span {
|
font-size: 16px;
|
}
|
}
|
}
|
|
|
/* 原有图片预览的样式 */
|
.el-image-viewer__wrapper {
|
:deep(.el-image-viewer__img) {
|
max-width: 100%;
|
max-height: 100%;
|
object-fit: contain;
|
}
|
}
|
</style>
|