<template>
|
<el-dialog
|
class="custom-dialog"
|
align-center
|
v-model="dialogVisible"
|
:title="isEditMode ? '编辑工单' : '工单详情'"
|
width="80%"
|
append-to-body
|
@close="handleClose"
|
>
|
<div class="detail-container">
|
<div class="detail-top-title">
|
<div class="event-title-center event-orderNumber">
|
{{ currentDetail.orderNumber || '工单编号' }}
|
</div>
|
<div class="event-title-center">{{ currentDetail.orderName || '事件名称' }}</div>
|
</div>
|
<div v-if="totalTime" class="event-total-time">总耗时:{{ totalTime }}</div>
|
<!-- 工单状态流程 -->
|
<div class="custom-steps-container">
|
<!-- 标题行 -->
|
<div class="steps-titles">
|
<div
|
v-for="(status, index) in stepStatusList"
|
:key="index"
|
:class="{
|
'step-title': true,
|
active: index <= stepStatusList.indexOf(String(currentDetail.status)),
|
}"
|
>
|
{{ mapStatus(status) }}
|
</div>
|
</div>
|
|
<!-- Element Steps 组件 -->
|
<el-steps :active="getActiveStep() - 1" align-center class="custom-steps">
|
<el-step v-for="(status, index) in stepStatusList" :key="index">
|
<template #description>
|
<span class="step-description">
|
{{ getStepHandler(status) }}
|
</span>
|
<div class="step-description" v-if="getStepTime(status)">
|
<span class="step-timer"> 耗时:{{ getStepTime(status) }} </span>
|
</div>
|
<div class="step-description">
|
{{ getStepCreateTime(status) }}
|
</div>
|
</template>
|
</el-step>
|
</el-steps>
|
</div>
|
|
<div class="PopUpTableScrolls">
|
<!-- 基本信息表格 -->
|
<el-table :show-header="false" :data="formattedDetailFields" border class="tableCss">
|
<el-table-column prop="label1" label="基本信息" width="150">
|
<template #default="{ row }">
|
<span
|
v-if="
|
currentDetail.status === 0 &&
|
(row.label1 === '关联算法' || row.label1 === '工单名称')
|
"
|
class="required-label"
|
>
|
<span class="required-star">*</span>{{ row.label1 }}
|
</span>
|
<span v-else>{{ row.label1 }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column>
|
<template #default="{ row }">
|
<template
|
v-if="
|
currentDetail.status === 0 &&
|
row.label1 === '工单名称' &&
|
hasProcessingBtnPermission()
|
"
|
>
|
<el-input
|
v-model="currentDetail.orderName"
|
placeholder="请输入工单名称"
|
class="required-input"
|
/>
|
</template>
|
<template
|
v-else-if="
|
currentDetail.status === 0 &&
|
row.label1 === '关联算法' &&
|
hasProcessingBtnPermission()
|
"
|
>
|
<el-select
|
v-model="currentDetail.aiType"
|
placeholder="请选择关联算法"
|
class="required-input"
|
>
|
<el-option
|
v-for="item in algorithms"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</template>
|
<template v-else>{{ row.value1 }}</template>
|
</template>
|
</el-table-column>
|
<el-table-column prop="label2" label="基本信息" width="150">
|
<template #default="{ row }">
|
<span
|
v-if="currentDetail.status === 0 && row.label2 === '工单内容'"
|
class="required-label"
|
>
|
<span class="required-star">*</span>{{ row.label2 }}
|
</span>
|
<span v-else>{{ row.label2 }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column>
|
<template #default="{ row }">
|
<template
|
v-if="
|
currentDetail.status === 0 &&
|
row.label2 === '工单内容' &&
|
hasProcessingBtnPermission()
|
"
|
>
|
<el-input
|
type="textarea"
|
:maxlength="200"
|
show-word-limit
|
v-model="currentDetail.content"
|
placeholder="请输入工单内容"
|
class="required-input"
|
/>
|
</template>
|
<template v-else>{{ row.value2 }}</template>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<!-- 事件处理详情 -->
|
<div v-if="[3, 4].includes(currentDetail.status)" class="form-section">
|
<div class="section-title">
|
<template v-if="currentDetail.status === 3">
|
<span class="required-label">
|
<span class="required-star">*</span>事件处理详情
|
</span>
|
</template>
|
<template v-else> 事件处理详情</template>
|
</div>
|
<!-- 处理中状态显示输入框 -->
|
<template v-if="currentDetail.status === 3 && hasProcessedAndOverBtnPermission()">
|
<el-input
|
type="textarea"
|
v-model="currentDetail.processingDetail"
|
placeholder="请输入事件处理详情"
|
:rows="4"
|
:maxlength="200"
|
show-word-limit
|
style="width: 100%; margin-bottom: 10px"
|
:disabled="!isCurrentUserAssigned"
|
/>
|
</template>
|
<!-- 已完成和已完结状态显示只读文本 -->
|
<template v-else>
|
<div class="readonly-processing-detail">
|
{{ currentDetail.processingDetail }}
|
</div>
|
</template>
|
</div>
|
|
<!-- 上传图片 -->
|
<div v-if="[3].includes(currentDetail.status)" class="form-section uploadImg">
|
<div class="section-title" v-if="hasProcessedAndOverBtnPermission()">
|
<template v-if="currentDetail.status === 3">
|
<span class="required-label"> <span class="required-star">*</span>上传图片 </span>
|
</template>
|
<template v-else> 上传图片</template>
|
</div>
|
<el-upload
|
:disabled="!isCurrentUserAssigned"
|
v-if="hasProcessedAndOverBtnPermission()"
|
ref="uploadRef"
|
:action="'#'"
|
:auto-upload="false"
|
list-type="picture-card"
|
:on-change="handleFileChange"
|
:on-remove="handleUploadRemove"
|
:before-upload="beforeUpload"
|
:file-list="currentDetail.photos || []"
|
:limit="1"
|
accept="image/*"
|
class="detail-upload"
|
>
|
<template v-if="!currentDetail.photos || currentDetail.photos.length < 1">
|
<div class="el-icon-plus">
|
<span>+</span>
|
</div>
|
</template>
|
</el-upload>
|
<div class="el-upload__tip" v-if="hasProcessedAndOverBtnPermission()">
|
(上传照片即可完结工单,只能上传jpg、jpeg、png照片,且不超过5M)
|
</div>
|
</div>
|
|
<!-- 图片和地图部分 -->
|
<div class="media-section">
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<div class="media-box">
|
<div class="media-title">事件图片</div>
|
<div class="media-content">
|
<el-image
|
v-if="currentDetail.mediaUrl"
|
:src="getThumbUrl(currentDetail.mediaUrl)"
|
:preview-src-list="[getPreviewUrl(currentDetail.mediaUrl)]"
|
fit="contain"
|
style="cursor: pointer"
|
>
|
<template #placeholder>
|
<div class="image-placeholder">
|
<i class="el-icon-picture-outline"></i>
|
<span>加载中...</span>
|
</div>
|
</template>
|
<template #error>
|
<div class="image-error">
|
<i class="el-icon-picture-outline"></i>
|
<span>加载失败</span>
|
</div>
|
</template>
|
</el-image>
|
<div v-else class="no-media">暂无图片/视频</div>
|
</div>
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="media-box">
|
<template v-if="currentDetail.status === 4">
|
<div class="media-title">工单处理图片</div>
|
<div class="media-content">
|
<el-image
|
v-if="currentDetail.updatePhotoUrl"
|
:src="getThumbUrl(currentDetail.updatePhotoUrl)"
|
:preview-src-list="[getPreviewUrl(currentDetail.updatePhotoUrl)]"
|
fit="fill"
|
>
|
<template #placeholder>
|
<div class="image-placeholder">
|
<i class="el-icon-picture-outline"></i>
|
<span>加载中...</span>
|
</div>
|
</template>
|
<template #error>
|
<div class="image-error">
|
<i class="el-icon-picture-outline"></i>
|
<span>加载失败</span>
|
</div>
|
</template>
|
</el-image>
|
<div v-else class="no-media">暂无处理图片</div>
|
</div>
|
</template>
|
<template v-else>
|
<div class="media-title">
|
地图标记事件点
|
<el-popover
|
v-if="currentDetail.status === 3 || currentDetail.status === 0"
|
popper-class="custom-qrcode-popover"
|
:width="120"
|
:visible="currentDetail.showQR && dialogVisible"
|
placement="top"
|
title=""
|
trigger="click"
|
>
|
<template #reference>
|
<img
|
@click.stop="handleQRCode(currentDetail)"
|
class="QRCodeImg"
|
src="@/assets/images/dataCenter/qrCode.svg"
|
alt=""
|
title="事件导航"
|
/>
|
</template>
|
<div class="qrcode-content">
|
<div class="close-btn" @click.stop="currentDetail.showQR = false">×</div>
|
<CreateQRcode
|
v-if="currentDetail.showQR && dialogVisible"
|
:lat-and-lon="currentDetail.location"
|
/>
|
</div>
|
</el-popover>
|
</div>
|
<div class="media-content">
|
<map-container v-if="dialogVisible" ref="mapContainerRef" />
|
</div>
|
</template>
|
</div>
|
</el-col>
|
</el-row>
|
</div>
|
</div>
|
|
<!-- 操作按钮 -->
|
<div class="dialog-footer1-new">
|
<div
|
:class="currentIndex === 0 ? 'disableds' : ''"
|
class="leftBtn"
|
@click="handlePrev"
|
>
|
上一页
|
</div>
|
<div class="btngroups">
|
<template v-if="currentDetail.status === 2">
|
<!-- 待审核 -->
|
<el-button
|
v-if="hasReviewBtnPermission()"
|
type="primary"
|
:loading="approveLoading"
|
@click="handleApprove"
|
icon="el-icon-check"
|
>
|
通过
|
</el-button>
|
<el-button
|
v-if="hasReviewBtnPermission()"
|
type="danger"
|
:loading="rejectLoading"
|
@click="handleReject"
|
icon="el-icon-close"
|
>
|
不通过
|
</el-button>
|
<el-button @click="handleClose" icon="el-icon-circle-close">取消</el-button>
|
</template>
|
<template v-else-if="currentDetail.status === 0">
|
<el-button
|
v-if="hasProcessingBtnPermission()"
|
type="primary"
|
:loading="dispatchLoading"
|
@click="handleApproveAndDispatch"
|
icon="el-icon-check"
|
>
|
受理
|
</el-button>
|
<el-button
|
v-if="hasProcessingBtnPermission()"
|
type="danger"
|
:loading="rejectLoading"
|
@click="handleReject"
|
icon="el-icon-close"
|
>
|
不受理
|
</el-button>
|
<el-button @click="handleClose" icon="el-icon-circle-close">取消</el-button>
|
</template>
|
<template v-if="currentDetail.status === 3">
|
<!-- 处理中 -->
|
<el-button
|
v-if="hasProcessedAndOverBtnPermission()"
|
type="primary"
|
:loading="completeLoading"
|
@click="handleComplete"
|
icon="el-icon-circle-check"
|
:disabled="!isCurrentUserAssigned"
|
>
|
完成工单
|
</el-button>
|
<el-button @click="handleClose" icon="el-icon-circle-close">取消</el-button>
|
</template>
|
<template v-else-if="currentDetail.status === 4">
|
<!-- 已完成 -->
|
<el-button @click="handleClose" icon="el-icon-circle-close">取消</el-button>
|
</template>
|
</div>
|
<div
|
:class="currentIndex === totalItems - 1 ? 'disableds' : ''"
|
class="leftBtn"
|
@click="handleNext"
|
>
|
下一页
|
</div>
|
</div>
|
</div>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import { useStore } from 'vuex'
|
import { ref, computed, watch, nextTick } from 'vue';
|
import { flowEvent, getStepInfo } from '@/api/tickets/ticket';
|
import { getSmallImg, getShowImg } from '@/utils/util';
|
import CreateQRcode from '@/components/CreateQRcode/CreateQRcode.vue';
|
import { ElMessage} from 'element-plus';
|
const store = useStore()
|
const userInfo = computed(() => store.state.user.userInfo)
|
const isLoading = ref(false);
|
// console.log('userInfo',userInfo.value);
|
// 定义props
|
const props = defineProps({
|
modelValue: {
|
type: Boolean,
|
default: false
|
},
|
currentDetail: {
|
type: Object,
|
default: () => ({})
|
},
|
currentIndex: {
|
type: Number,
|
default: 0
|
},
|
totalItems: {
|
type: Number,
|
default: 0
|
},
|
algorithms: {
|
type: Array,
|
default: () => []
|
},
|
types: {
|
type: Array,
|
default: () => []
|
},
|
permission: {
|
type: Object,
|
default: () => ({})
|
},
|
stepStatusList: {
|
type: Array,
|
default: () => []
|
},
|
workType: {
|
type: Number,
|
default: 0
|
}
|
});
|
|
// 定义emits
|
|
const emit = defineEmits([
|
'update:modelValue',
|
'detail-success',
|
'detail-error',
|
'prev-item',
|
'next-item',
|
'update:currentDetail',
|
'approve-and-dispatch'
|
]);
|
|
// 响应式数据
|
const stepInfos = ref([]);
|
const totalTime = ref('');
|
const approveLoading = ref(false);
|
const rejectLoading = ref(false);
|
const dispatchLoading = ref(false);
|
const completeLoading = ref(false);
|
const finalizeLoading = ref(false);
|
const uploadRef = ref(null);
|
const mapContainerRef = ref(null);
|
|
// 计算属性
|
const dialogVisible = computed({
|
get() {
|
return props.modelValue;
|
},
|
set(value) {
|
emit('update:modelValue', value);
|
}
|
});
|
|
const isEditMode = computed(() => {
|
return props.currentDetail.status === -1;
|
});
|
// 是否有权限完成工单
|
const isCurrentUserAssigned =computed(()=>{
|
const handleUserId = props.currentDetail?.handle_user_id;
|
const currentUserId = userInfo.value?.user_id;
|
return !!handleUserId && !!currentUserId && String(handleUserId) === String(currentUserId);
|
})
|
const formattedDetailFields = computed(() => {
|
const fields = [
|
{ label: '工单名称', value: props.currentDetail.orderName },
|
{
|
label: '工单类型',
|
value: props.types.find(t => t.value === props.currentDetail.type)?.label || props.currentDetail.type,
|
},
|
{ label: '关联任务', value: props.currentDetail.job_name || '/' },
|
{ label: '工单创建人', value: props.currentDetail.creator },
|
{ label: '当前状态', value: mapStatus(props.currentDetail.status) },
|
{ label: '事件地址', value: props.currentDetail.address || props.currentDetail.latAndLon },
|
{
|
label: '关联算法',
|
value: props.algorithms.find(t => t.value === props.currentDetail.aiType)?.label || props.currentDetail.aiType,
|
},
|
{ label: '发起单位', value: props.currentDetail.department },
|
{ label: '发起任务时间', value: props.currentDetail.startTime },
|
{ label: '所属机巢', value: props.currentDetail.device_names },
|
{ label: '工单来源', value: props.currentDetail.dataSources },
|
{ label: '工单内容', value: props.currentDetail.content },
|
];
|
|
const filteredFields = fields.filter(field => field.value !== '/');
|
const formattedFields = [];
|
for (let i = 0; i < filteredFields.length; i += 2) {
|
formattedFields.push({
|
label1: filteredFields[i]?.label || '',
|
value1: filteredFields[i]?.value || (filteredFields[i]?.label ? '暂无数据' : ''),
|
label2: filteredFields[i + 1]?.label || '',
|
value2: filteredFields[i + 1]?.value || (filteredFields[i + 1]?.label ? '暂无数据' : ''),
|
});
|
}
|
|
return formattedFields;
|
});
|
|
// 监听
|
watch(
|
() => props.modelValue,
|
(newVal) => {
|
if (newVal) {
|
loadStepInfo();
|
initMap();
|
}
|
}
|
);
|
|
watch(
|
() => props.currentDetail,
|
(newVal) => {
|
if (newVal && dialogVisible.value) {
|
isLoading.value = true;
|
setTimeout(() => {
|
loadStepInfo();
|
initMap();
|
isLoading.value = false;
|
}, 50);
|
|
}
|
},
|
{ deep: true }
|
);
|
|
// 方法
|
const handleClose = () => {
|
dialogVisible.value = false;
|
};
|
|
const handlePrev = () => {
|
if (props.currentIndex > 0) {
|
emit('prev-item');
|
}
|
};
|
|
const handleNext = () => {
|
if (props.currentIndex < props.totalItems - 1) {
|
emit('next-item');
|
}
|
};
|
|
const loadStepInfo = async () => {
|
try {
|
const stepResponse = await getStepInfo(props.currentDetail.orderNumber);
|
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,
|
}));
|
} catch (error) {
|
stepInfos.value = [];
|
}
|
};
|
|
const initMap = () => {
|
nextTick(() => {
|
if (mapContainerRef.value && mapContainerRef.value.initAddEntity && props.currentDetail.location) {
|
mapContainerRef.value.initAddEntity('point', props.currentDetail.location);
|
}
|
});
|
};
|
|
const mapStatus = (status) => {
|
const statusTextMap = {
|
2: '待审核',
|
0: '待处理',
|
3: '处理中',
|
4: '已完成',
|
};
|
return statusTextMap[status] || '未知状态';
|
};
|
|
const getStepHandler = (status) => {
|
const step = stepInfos.value.find(step => step.status === status);
|
return step ? step.name : '';
|
};
|
|
const getStepTime = (status) => {
|
const step = stepInfos.value.find(step => step.status === status);
|
return step && step.time && step.time !== '0' ? step.time : false;
|
};
|
|
const getStepCreateTime = (status) => {
|
const step = stepInfos.value.find(step => step.status === status);
|
return step ? step.create_time : null;
|
};
|
|
const getActiveStep = () => {
|
const arr = props.stepStatusList;
|
const index = arr.indexOf(String(props.currentDetail.status));
|
return index !== -1 ? index + 2 : 1;
|
};
|
|
const handleQRCode = (val) => {
|
emit('update:currentDetail', {
|
...props.currentDetail,
|
showQR: !val.showQR
|
});
|
};
|
|
const getThumbUrl = (url) => {
|
if (!url) return '';
|
return getSmallImg(url);
|
};
|
|
const getPreviewUrl = (url) => {
|
if (!url) return '';
|
return getShowImg(url);
|
};
|
|
const hasProcessingBtnPermission = () => {
|
return props.permission && props.permission.tickets_processing_btn === true;
|
};
|
|
const hasProcessedAndOverBtnPermission = () => {
|
return props.permission && props.permission.tickets_view_processedAndOver === true;
|
};
|
// 通过不通过
|
const hasReviewBtnPermission = () => {
|
return props.permission && props.permission.tickets_review_btn === true;
|
};
|
|
// 文件操作方法
|
const handleFileChange = (file, fileList) => {
|
emit('update:currentDetail', {
|
...props.currentDetail,
|
photos: fileList
|
});
|
};
|
|
const handleUploadRemove = (file, fileList) => {
|
emit('update:currentDetail', {
|
...props.currentDetail,
|
photos: fileList
|
});
|
};
|
|
const beforeUpload = (file) => {
|
const isImage = file.type.includes('image');
|
const isLt5M = file.size / 1024 / 1024 < 5;
|
|
if (!isImage) {
|
ElMessage.error('只能上传图片文件!');
|
return false;
|
}
|
if (!isLt5M) {
|
ElMessage.error('图片大小不能超过5MB!');
|
return false;
|
}
|
return true;
|
};
|
|
// 工单操作方法
|
const handleApprove = async () => {
|
if (approveLoading.value) return;
|
approveLoading.value = true;
|
|
try {
|
const data = {
|
id: props.currentDetail.id,
|
status: props.currentDetail.status,
|
isPass: 0,
|
eventNum: props.currentDetail.orderNumber,
|
};
|
|
const response = await flowEvent(data);
|
if (response.data.code === 0) {
|
ElMessage.success('工单已通过');
|
emit('detail-success');
|
handleClose();
|
} else {
|
throw new Error(response.data.msg || '操作失败');
|
}
|
} catch (error) {
|
ElMessage.error(error.message || '操作失败,请稍后重试');
|
emit('detail-error', error);
|
} finally {
|
approveLoading.value = false;
|
}
|
};
|
|
const handleReject = async () => {
|
if (rejectLoading.value) return;
|
rejectLoading.value = true;
|
|
try {
|
const data = {
|
id: props.currentDetail.id,
|
status: props.currentDetail.status,
|
isPass: 1,
|
};
|
|
const response = await flowEvent(data);
|
if (response.data.code === 0) {
|
ElMessage.success('工单未通过');
|
emit('detail-success');
|
handleClose();
|
} else {
|
throw new Error(response.data.msg || '操作失败');
|
}
|
} catch (error) {
|
ElMessage.error(error.message || '操作失败,请稍后重试');
|
emit('detail-error', error);
|
} finally {
|
rejectLoading.value = false;
|
}
|
};
|
|
const handleApproveAndDispatch = () => {
|
// 触发派发工单操作,由父组件处理
|
emit('approve-and-dispatch', props.currentDetail);
|
};
|
|
const handleComplete = async () => {
|
if (completeLoading.value) return;
|
completeLoading.value = true;
|
if (!props.currentDetail.processingDetail) {
|
ElMessage.warning('请先填写事件处理详情');
|
completeLoading.value = false;
|
return;
|
}
|
|
if (!props.currentDetail.photos || props.currentDetail.photos.length === 0) {
|
ElMessage.warning('请选择上传图片');
|
completeLoading.value = false;
|
return;
|
}
|
try {
|
const data = {
|
id: props.currentDetail.id,
|
status: props.currentDetail.status,
|
processingDetails: props.currentDetail.processingDetail,
|
eventNum: props.currentDetail.orderNumber,
|
};
|
const file = props.currentDetail.photos?.[0]?.raw || null;
|
const response = await flowEvent(data, file);
|
if (response.data.code === 0) {
|
ElMessage.success('工单已完成');
|
emit('detail-success');
|
handleClose();
|
} else {
|
throw new Error(response.data.msg || '操作失败');
|
}
|
handleClose();
|
} catch (error) {
|
console.error('完成工单失败:', error);
|
ElMessage.error(error.message || '操作失败,请稍后重试');
|
emit('detail-error', error);
|
handleClose();
|
} finally {
|
completeLoading.value = false;
|
handleClose();
|
}
|
};
|
</script>
|
|
<style lang="scss">
|
.custom-dialog {
|
height: 96vh;
|
// min-height: 50vh;
|
.el-dialog__body {
|
border-top: 0.1rem solid #f0f0f0;
|
}
|
}
|
|
.custom-qrcode-popover {
|
min-width: 160px !important;
|
min-height: 140px !important;
|
position: relative;
|
|
.qrcode-content {
|
margin-top: 8px;
|
|
.close-btn {
|
position: absolute;
|
top: 2px;
|
right: 2px;
|
width: 16px;
|
height: 16px;
|
line-height: 16px;
|
text-align: center;
|
cursor: pointer;
|
color: #999;
|
font-size: 16px;
|
z-index: 10;
|
}
|
}
|
}
|
</style>
|
<style lang="scss" scoped>
|
.uploadImg {
|
margin-bottom: 32px;
|
}
|
|
.tableCss {
|
width: 100%;
|
margin-bottom: 10px;
|
}
|
|
.step-timer {
|
position: absolute;
|
right: 92%;
|
top: 50%;
|
transform: translateY(-50%);
|
width: 100px;
|
margin-left: 4px;
|
color: #666;
|
font-size: 12px;
|
white-space: nowrap;
|
}
|
|
.event-total-time {
|
text-align: center;
|
color: #666;
|
font-size: 15px;
|
margin-bottom: 12px;
|
}
|
|
.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-textarea__inner) {
|
padding: 8px 12px;
|
}
|
.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;
|
}
|
|
.readonly-processing-detail {
|
background-color: #f5f7fa;
|
padding: 12px;
|
border-radius: 4px;
|
min-height: 30px;
|
color: #606266;
|
line-height: 1.5;
|
display: block;
|
text-align: left;
|
margin-bottom: 5px;
|
|
&:first-child {
|
font-weight: bold;
|
margin-bottom: 4px;
|
}
|
}
|
|
// 添加删除按钮样式
|
.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;
|
}
|
}
|
}
|
/* 新建工单和处理工单的上传组件样式 */
|
.create-upload,
|
.detail-upload {
|
:deep(.el-upload--picture-card) {
|
width: 120px;
|
height: 100px;
|
line-height: 100px;
|
}
|
|
/* 隐藏额外的上传按钮 */
|
:deep(.el-upload.el-upload--picture-card) {
|
display: none;
|
}
|
|
/* 当没有图片时显示上传按钮 */
|
:deep(.el-upload.el-upload--picture-card:first-child) {
|
display: flex;
|
}
|
|
/* 上传组件的预览图片样式 */
|
:deep(.el-upload-list--picture-card .el-upload-list__item) {
|
width: 120px;
|
height: 100px;
|
}
|
}
|
|
/* 原有图片预览的样式 */
|
.el-image-viewer__wrapper {
|
:deep(.el-image-viewer__img) {
|
max-width: 100%;
|
max-height: 100%;
|
object-fit: contain;
|
}
|
}
|
|
/* 必填项样式 */
|
.required-label {
|
position: relative;
|
display: inline-block;
|
|
.required-star {
|
color: #f56c6c;
|
margin-right: 4px;
|
}
|
}
|
|
/* 必填输入框样式 */
|
.required-input {
|
width: 100%;
|
|
:deep(.el-input__inner),
|
:deep(.el-textarea__inner) {
|
&:focus {
|
border-color: #409eff;
|
}
|
}
|
}
|
</style>
|