| | |
| | | @clear="handleKeyWords" |
| | | @keyup.enter="handleSearch" |
| | | /> |
| | | <el-select |
| | | <!-- <el-select |
| | | v-model="filters.department" |
| | | placeholder="请选择所属单位" |
| | | class="filter-item" |
| | |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-select> --> |
| | | <el-select |
| | | v-model="filters.type" |
| | | placeholder="请选择工单类型" |
| | |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工单类型" prop="type"> |
| | | <el-select v-model="form.type" placeholder="请选择工单类型" class="full-width"> |
| | | |
| | | <el-select @change="handleTypeChange" v-model="form.type" placeholder="请选择工单类型" class="full-width" > |
| | | <el-option |
| | | v-for="item in types" |
| | | :key="item.value" |
| | |
| | | multiple |
| | | placeholder="请选择关联算法" |
| | | class="full-width" |
| | | :disabled="!form.type" |
| | | > |
| | | <el-option |
| | | v-for="item in algorithms" |
| | |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | |
| | | <el-button type="danger" :loading="submitLoading" @click="submitForm">发布</el-button> |
| | | <el-button type="infoprimary" plain :loading="draftLoading" @click="saveDraft" |
| | | >存草稿</el-button |
| | | > |
| | | <el-button @click="dialogVisible = false">取 消</el-button> |
| | | |
| | | |
| | | <el-button @click="handleCancel">取 消</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 工单详情对话框 --> |
| | | <el-dialog v-model="detailVisible" title="工单详情" width="80%" append-to-body> |
| | | <el-dialog class="custom-dialog" align-center v-model="detailVisible" title="工单详情" width="80%" append-to-body> |
| | | <div class="detail-container"> |
| | | <div class="detail-top-title"> |
| | | <div class="event-title-center event-orderNumber"> |
| | |
| | | </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 === '工单名称'" |
| | | v-if="currentDetail.status === 0 &&(row.label1 === '关联算法' || row.label1 === '工单名称')" |
| | | class="required-label" |
| | | > |
| | | <span class="required-star">*</span>{{ row.label1 }} |
| | |
| | | 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 === '工单类型' || row.label2 === '工单内容') |
| | | row.label2 === '工单内容' |
| | | " |
| | | class="required-label" |
| | | > |
| | |
| | | <el-table-column> |
| | | <template #default="{ row }"> |
| | | <!-- 修改工单类型和工单内容的显示 --> |
| | | |
| | | |
| | | <template |
| | | v-if=" |
| | | currentDetail.status === 0 && |
| | | row.label2 === '工单类型' && |
| | | hasProcessingBtnPermission() |
| | | " |
| | | > |
| | | <el-select |
| | | v-model="currentDetail.type" |
| | | placeholder="请选择工单类型" |
| | | class="required-input" |
| | | > |
| | | <el-option |
| | | v-for="item in types" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </template> |
| | | <template |
| | | v-else-if=" |
| | | currentDetail.status === 0 && |
| | | row.label2 === '工单内容' && |
| | | hasProcessingBtnPermission() |
| | |
| | | <!-- 图片和地图部分 --> |
| | | <div class="media-section"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="1"> |
| | | <div |
| | | class="leftBtn" |
| | | :class="currentIndex === 0 ? 'disableds' : ''" |
| | | @click="leftClick" |
| | | > |
| | | < |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="11"> |
| | | |
| | | <el-col :span="12"> |
| | | <div class="media-box"> |
| | | <div class="media-title">事件图片</div> |
| | | <div class="media-content"> |
| | |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="11"> |
| | | <el-col :span="12"> |
| | | <div class="media-box"> |
| | | <!-- 根据状态显示不同的标题和内容 --> |
| | | |
| | |
| | | </template> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="1"> |
| | | <div |
| | | :class="currentIndex === tableData.length - 1 ? 'disableds' : ''" |
| | | class="leftBtn" |
| | | @click="rightClick" |
| | | > |
| | | > |
| | | </div> |
| | | </el-col> |
| | | |
| | | |
| | | </el-row> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 操作按钮 --> |
| | | <div class="dialog-footer"> |
| | | <template v-if="currentDetail.status === 2"> |
| | | <div |
| | | class="leftBtn" |
| | | :class="currentIndex === 0 ? 'disableds' : ''" |
| | | @click="leftClick" |
| | | > |
| | | 上一页 |
| | | </div> |
| | | <div class="btngroups"> |
| | | <template v-if="currentDetail.status === 2"> |
| | | <!-- 待审核 --> |
| | | <el-button |
| | | v-if="hasReviewBtnPermission()" |
| | |
| | | @click="finalizeTicket">完结工单</el-button> --> |
| | | <el-button @click="detailVisible = false">取消</el-button> |
| | | </template> |
| | | </div> |
| | | <div |
| | | :class="currentIndex === tableData.length - 1 ? 'disableds' : ''" |
| | | class="leftBtn" |
| | | @click="rightClick" |
| | | > |
| | | 下一页 |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | |
| | | import { mapGetters } from 'vuex' |
| | | import { getAdcodeObj } from '@/utils/disposeData' |
| | | import elTooltipCopy from '@/components/ElTooltipCopy.vue' |
| | | import getBaseConfig from '@/buildConfig/config' |
| | | const { envName } = getBaseConfig() |
| | | function regExp (label, name) { |
| | | var reg = new RegExp(label + '=([^&]*)(&|$)', 'g') |
| | | return name.match(reg)[0].split('=')[1] |
| | |
| | | }, |
| | | departments: [], |
| | | types: [], |
| | | allAlgorithms: [], |
| | | handlers: [ |
| | | { label: '处理人A', value: 'handlerA' }, |
| | | { label: '处理人B', value: 'handlerB' }, |
| | |
| | | { label: '处理人', prop: 'handler', width: 70 }, |
| | | { |
| | | slot: true, |
| | | hide: false, |
| | | hide: envName === 'jiangwu'? true : false, |
| | | label: '复核状态', |
| | | prop: 'isReview', |
| | | width: 90, |
| | |
| | | }, |
| | | |
| | | mounted() { |
| | | |
| | | const href = this.$route.href; |
| | | if (this.$route?.query?.status !== undefined && this.$route?.query?.status !== null) { |
| | | this.filters.status = this.$route?.query?.status + ''; |
| | |
| | | |
| | | if (orderNumber) { |
| | | this.filters.keyword = orderNumber; |
| | | |
| | | this.$nextTick(() => { |
| | | this.isShowInfo = true; |
| | | const find = this.$store.state.tags.bsTagList.find(i => i.path === '/tickets/ticket') |
| | | find && (find.query = {}) |
| | | }); |
| | | |
| | | console.log('orderNumber', orderNumber); |
| | | } |
| | | } |
| | | |
| | |
| | | { label: '任务发起人', value: this.currentDetail.creator }, |
| | | { label: '当前状态', value: this.mapStatus(this.currentDetail.status) }, |
| | | { label: '事件地址', value: this.currentDetail.address || this.currentDetail.latAndLon }, // 包含经纬度信息 |
| | | { label: '关联算法', value: this.currentDetail.aiType }, |
| | | { label: '关联算法', |
| | | // value: this.currentDetail.aiType |
| | | value: |
| | | this.algorithms.find(t => t.value === this.currentDetail.aiType)?.label || |
| | | this.currentDetail.aiType || |
| | | '/', |
| | | |
| | | }, |
| | | { label: '发起单位', value: this.currentDetail.department }, |
| | | { label: '发起任务时间', value: this.currentDetail.startTime }, |
| | | { label: '工单内容', value: this.currentDetail.content }, |
| | |
| | | const subAreaCode = areaCode ? areaCode.substring(0, 6) : ''; |
| | | const adcodeObj = getAdcodeObj(geoJson, 'adcode', subAreaCode); |
| | | |
| | | console.log('区域代码:', subAreaCode); |
| | | // console.log('区域代码:', subAreaCode); |
| | | |
| | | // 直接从返回对象中获取正确的路径 |
| | | const center = adcodeObj?.payload?.objects?.collection?.geometries?.[0]?.properties?.center; |
| | |
| | | async fetchDropdownData() { |
| | | try { |
| | | const response = await getTicketInfo(); |
| | | const { dept_data, event_type, ai_type } = response.data.data; |
| | | |
| | | const { dept_data, event_type, ai_type,info } = response.data.data; |
| | | |
| | | this.departments = dept_data.map(item => ({ |
| | | label: item.dept_name, |
| | |
| | | |
| | | const columnType = this.findObject(this.option.column, 'type'); |
| | | columnType.dicData = this.types; |
| | | this.allAlgorithms = info |
| | | |
| | | console.log('工单类型',this.types); |
| | | console.log('关联算法',this.allAlgorithms ); |
| | | // 确保算法数据的映射一致 |
| | | this.algorithms = |
| | | ai_type?.map(item => ({ |
| | | dict_key: item.dict_key, |
| | | dict_value: item.dict_value, |
| | | // 同时添加 label 和 value 以兼容两处使用 |
| | | label: item.dict_value, |
| | | value: item.dict_key, |
| | | })) || []; |
| | | // this.algorithms = |
| | | // ai_type?.map(item => ({ |
| | | // dict_key: item.dict_key, |
| | | // dict_value: item.dict_value, |
| | | // // 同时添加 label 和 value 以兼容两处使用 |
| | | // label: item.dict_value, |
| | | // value: item.dict_key, |
| | | // })) || []; |
| | | |
| | | // 构建用户ID和名称的映射关系 |
| | | this.userNameToIdMap = {}; |
| | |
| | | } catch (error) { |
| | | this.$message.error('加载下拉框数据失败'); |
| | | } |
| | | }, |
| | | // 工单类型变化时触发 |
| | | handleTypeChange(typeValue) { |
| | | if (!typeValue) { |
| | | // 未选择类型时清空算法列表 |
| | | this.algorithms = []; |
| | | return; |
| | | } |
| | | |
| | | const matchedCategory = this.allAlgorithms.find( |
| | | category => category.dict_key === typeValue |
| | | ); |
| | | |
| | | if (!matchedCategory || !matchedCategory.algorithms || matchedCategory.algorithms.length === 0) { |
| | | // 无匹配的算法时清空 |
| | | this.algorithms = []; |
| | | this.$message.info('该工单类型暂无关联算法'); |
| | | return; |
| | | } |
| | | // console.log('matchedCategory',matchedCategory); |
| | | |
| | | this.algorithms = matchedCategory.algorithms.map(algo => ({ |
| | | label: algo.dict_value, |
| | | value: algo.dict_key, |
| | | dict_key: algo.dict_key, |
| | | dict_value: algo.dict_value |
| | | })); |
| | | |
| | | }, |
| | | |
| | | async fetchTableData() { |
| | |
| | | this.draftLoading = false; |
| | | } |
| | | }, |
| | | |
| | | handleCancel (){ |
| | | this.resetForm(); |
| | | this.dialogVisible = false; |
| | | }, |
| | | handleLocationChange(val) { |
| | | let locationValue = val.value; |
| | | if (locationValue && locationValue.length >= 2) { |
| | |
| | | this.page.currentPage = 1; |
| | | this.$router.replace({}); //清除url参数 |
| | | this.fetchTableData(); |
| | | console.log('handleSearch', this.$router); |
| | | |
| | | }, |
| | | handleKeyWords(){ |
| | | this.$router.replace({}); //清除url参数 |
| | |
| | | |
| | | console.log('this.currentDetail', this.currentDetail); |
| | | this.detailVisible = true; |
| | | this.handleTypeChange(this.currentDetail.type) |
| | | this.$nextTick(() => { |
| | | if (this.$refs.MapContainer && this.$refs.MapContainer.initAddEntity) { |
| | | this.$refs.MapContainer.initAddEntity('point', this.currentDetail.location); |
| | |
| | | }, |
| | | hasProcessingBtnPermission() { |
| | | // undefined 或 false 都返回 false,只有 true 返回 true |
| | | // console.log('权限检查:', this.permission) |
| | | // console.log('权限检查:', this.permission.tickets_processing_btn) |
| | | return this.permission && this.permission.tickets_processing_btn === true; |
| | | }, |
| | | hasProcessedAndOverBtnPermission() { |
| | |
| | | |
| | | // 获取工单类型值 - 从types中找到匹配的值 |
| | | const typeValue = |
| | | this.types.find(t => t.label === row.type)?.value || row.work_order_type_dict_key; |
| | | |
| | | this.types.find(t => t.value === row.type)?.value || row.work_order_type_dict_key; |
| | | // 获取处理人ID - 使用userNameToIdMap映射 |
| | | const handlerId = this.userNameToIdMap[row.handler] || row.handler; |
| | | |
| | |
| | | }, |
| | | activated() { |
| | | this.handleReset(); |
| | | } |
| | | }, |
| | | |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .custom-dialog { height: 96vh; /* 80% 视口高度 */} |
| | | </style> |
| | | <style lang="scss" scoped> |
| | | |
| | | ::v-deep(.el-tabs) { |
| | | height: 100%; |
| | | display: flex; |
| | |
| | | |
| | | .tableCss { |
| | | width: 100%; |
| | | margin-bottom: 20px; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .step-timer { |
| | |
| | | } |
| | | |
| | | .dialog-footer { |
| | | text-align: center; |
| | | padding-top: 16px; |
| | | border-top: 1px solid #ebeef5; |
| | | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | .detail-container { |
| | | padding: 20px; |
| | | padding:0 20px; |
| | | |
| | | .detail-top-title { |
| | | display: flex; |
| | |
| | | } |
| | | |
| | | .media-section { |
| | | margin-bottom: 20px; |
| | | // margin-bottom: 20px; |
| | | |
| | | .el-row { |
| | | display: flex; |
| | |
| | | } |
| | | |
| | | .leftBtn { |
| | | width: 36px; |
| | | height: 36px; |
| | | width: 70px; |
| | | height: 32px; |
| | | background-color: #999; |
| | | border-radius: 50%; |
| | | border-radius: 5px; |
| | | text-align: center; |
| | | line-height: 36px; |
| | | line-height: 32px; |
| | | color: #fff; |
| | | cursor: pointer; |
| | | opacity: 0.8; |
| | | |
| | | } |
| | | |
| | | .disableds { |
| | |
| | | pointer-events: none; |
| | | opacity: 0.3 !important; |
| | | } |
| | | |
| | | .PopUpTableScrolls{ |
| | | height: 600px; |
| | | overflow-y: scroll; |
| | | overflow-x: hidden; |
| | | } |
| | | .media-box { |
| | | width: 100%; |
| | | border: 1px solid #dcdfe6; |
| | |
| | | |
| | | .media-title { |
| | | font-weight: bold; |
| | | margin-bottom: 10px; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .media-content { |
| | |
| | | .el-image__inner { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | object-fit: cover !important; |
| | | } |
| | | } |
| | | } |
| | |
| | | background-color: #f5f7fa; |
| | | padding: 12px; |
| | | border-radius: 4px; |
| | | min-height: 40px; |
| | | 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; |
| | |
| | | |
| | | .custom-steps-container { |
| | | width: 100%; |
| | | margin: 20px 0; |
| | | margin: 10px 0; |
| | | } |
| | | |
| | | .steps-titles { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 16px; |
| | | margin-bottom: 14px; |
| | | position: relative; |
| | | } |
| | | |
| | | .step-title { |
| | | text-align: center; |
| | | flex: 1; |
| | | font-size: 16px; |
| | | font-size: 14px; |
| | | color: #999; |
| | | position: relative; |
| | | padding-bottom: 10px; |
| | | padding-bottom: 5px; |
| | | } |
| | | |
| | | .step-title.active { |
| | |
| | | text-align: center; |
| | | font-size: 20px; |
| | | font-weight: bold; |
| | | margin-bottom: 12px; |
| | | margin-bottom: 5px; |
| | | color: #333; |
| | | } |
| | | |