| src/views/tickets/SearchBox.vue | ●●●●● patch | view | raw | blame | history | |
| src/views/tickets/orderLog-copy1.vue | ●●●●● patch | view | raw | blame | history | |
| src/views/tickets/orderLog.vue | ●●●●● patch | view | raw | blame | history | |
| src/views/tickets/orderLog1.vue | ●●●●● patch | view | raw | blame | history | |
| src/views/tickets/orderLogCopy.vue | ●●●●● patch | view | raw | blame | history |
src/views/tickets/SearchBox.vue
New file @@ -0,0 +1,290 @@ <template> <div class="search-box-test"> <el-form :model="searchForm" inline> <div class="search-first"> <el-form-item> <el-input v-model="searchForm.key_word" placeholder="编号/名称/内容/姓名" clearable /> </el-form-item> <el-form-item label="选择日期:"> <el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :default-value="datePickerDefaultVal" /> </el-form-item> <el-form-item label="关联航线:"> <el-select :teleported="false" v-model="searchForm.file_id" placeholder="请选择关联航线" clearable @change="handleSearch" > <el-option v-for="item in lineList" :key="item.wayline_id" :label="item.name" :value="item.wayline_id" /> </el-select> </el-form-item> <el-form-item label="关联算法:"> <el-select :teleported="false" v-model="searchForm.ai_types" placeholder="请选择关联航线" clearable> <el-option v-for="item in aiTypeList" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> <el-form-item label="工单状态:"> <el-select :teleported="false" v-model="searchForm.status" placeholder="请选择关联航线" clearable> <el-option v-for="item in orderStatus" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="工单周期:"> <el-date-picker v-model="cycleDateRange" type="daterange" range-separator="至" start-placeholder="工单周期开始日期" end-placeholder="工单周期结束日期" :default-value="datePickerDefaultVal" /> </el-form-item> <el-form-item label="选择频次:"> <el-select v-model="searchForm.rep_fre_type" placeholder="请选择频次" clearable> <el-option v-for="item in cycles" :key="item" :label="item" :value="item" /> </el-select> </el-form-item> <el-form-item label="执行时间:"> <el-time-picker v-model="searchForm.deal_time" placeholder="请选择执行时间" prop="deal_time" value-format="HH:mm" :picker-options="{ selectableRange: '00:00 - 23:59'}" /> </el-form-item> <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button> <el-button icon="el-icon-refresh" @click="handleReset">清空</el-button> </div> </el-form> </div> </template> <script setup> import { pxToRem } from '@/utils/rem'; import { calculateDefaultRange } from '@/utils/util' import { newGetWorkspacesPage } from '@/api/resource/wayline' import { getDictionaryByCode } from '@/api/system/dictbiz' import dayjs from 'dayjs'; // 选择日期 const dateRange = ref('') let datePickerDefaultVal = calculateDefaultRange() // 选择周期 const cycleDateRange = ref('') const searchForm = reactive({ ai_types: [], deal_time: "", file_id: "", key_word: "", status: 0, rep_fre_type: '', }) const emit = defineEmits(['search']); // 获取航线 let lineList = ref([]) function getLines() { const formData = { name: '', waylineType: undefined, current: 1, size: 99999999, descs: 'update_time' } newGetWorkspacesPage(formData).then(res => { console.log(res, '5555'); lineList.value = res.data.data.records }) } // 获取算法 let aiTypeList = ref([]) function aitypeList() { getDictionaryByCode('SF').then(res => { aiTypeList.value = res.data.data['SF'] }) } // 周期 const cycles = ref(['每天', '周一', '周二', '周三', '周四', '周五', '周六', '周末', '周天', '工作日']) // 工单状态 const orderStatus = ref([ { label: '草稿', value: '0' }, { label: '待审核', value: '1' }, { label: '已驳回', value: '2' }, { label: '已通过', value: '3' } ]) const timeFormat = 'YYYY-MM-DD HH:mm:ss'; // 搜索 const handleSearch = () => { if (!dateRange.value) { dateRange.value = []; } // if (dateRange.value && dateRange.value.length) { // checked.value = ''; // searchForm.date_enum = ''; // } // 提交至store let params = { ...searchForm, create_start_date: dateRange.value.length ? dayjs(dateRange?.value[0]).startOf('day').format(timeFormat) : null, create_end_date: dateRange.value.length ? dayjs(dateRange?.value[1]).endOf('day').format(timeFormat) : null, start_date: cycleDateRange.value.length ? dayjs(dateRange?.value[0]).startOf('day').format(timeFormat) : null, emd_date: cycleDateRange.value.length ? dayjs(dateRange?.value[1]).startOf('day').format(timeFormat) : null, }; emit('search', params); }; onMounted(() => { aitypeList() getLines() // 查询一次 // handleSearch() }); </script> <style lang="scss" scoped> // .taskAlgorithm { // :deep() { // .task-algorithm > div { // width: 233px !important; // } // } // } .search-box-test { transition: all 0.3s; .search-first { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 20px 15px; // 设置行间距和列间距 .more { cursor: pointer; width: 32px; height: 32px; color: #1c5cff; line-height: 32px; font-size: 16px; margin: 0 28px; } .search-btn { // position: absolute; // right: 0; display: flex; justify-content: space-between; cursor: pointer; font-size: 14px; .btn { width: 80px; height: 32px; border-radius: 4px 4px 4px 4px; line-height: 32px; display: flex; justify-content: center; align-items: center; // margin-left: px; img { width: 14px; height: 14px; } } .search { background: #409eff; color: #fff; margin-right: 10px; } .clear { border: 1px solid #d2d1d1; color: #676767; margin-right: 10px; } .add { background: #ff9243; color: #fff; } } .time-card { text-align: center; background: #ffffff; border-radius: 4px 0px 0px 4px; border: 1px solid #e5e5e5; font-family: Source Han Sans CN, Source Han Sans CN; font-weight: 400; font-size: 14px; color: #7c8091; display: flex; height: 32px; .card-item { width: 60px; height: 100%; line-height: 32px; cursor: pointer; } .active { background: #ffffff; border-radius: 0px 0px 0px 0px; border: 1px solid #1c5cff; color: #1441ff; } } } :deep(.el-form) { :deep(.el-input__wrapper.is-disabled) { box-shadow: 0 0 0 1px #026ad6; } .el-form-item { margin-bottom: 0; width: 233px; margin-right: 20px; .el-form-item__label { color: #363636; line-height: 32px; } } } } </style> src/views/tickets/orderLog-copy1.vue
File was deleted src/views/tickets/orderLog.vue
@@ -1,550 +1,68 @@ <!-- 任务统计表格 --> <template> <basic-container> <div class="order-log-update"> <el-tabs v-model="activeTab" @tab-click="handleTabChange"> <el-tab-pane v-for="tab in filteredTabs" :key="tab.name" :label="`${tab.label} (${tab.count})`" :name="tab.name"> <basic-main-content> <!-- 查询条件筛选栏 --> <div class="ztzf-form-search"> <el-form :model="filters" inline> <el-row :gutter="24"> <el-col :span="4"> <el-form-item label="关键字:"> <el-input v-model="filters.key_word" placeholder="编号/名称/内容/姓名" clearable @keyup.enter="handleSearch" /> </el-form-item> <!-- <div class="search-bar-box-item">--> <!-- <el-select placeholder="请选择所属单位" v-model="filters.create_dept" clearable>--> <!-- <el-option v-for="dept in departments" :key="dept.value" :label="dept.label" :value="dept.value" />--> <!-- </el-select>--> <!-- </div>--> </el-col> <el-col :span="8"> <el-form-item label="选择日期:"> <el-date-picker @change="handleSearch" v-model="filters.dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :default-value="datePickerDefaultVal" /> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="关联航线:"> <el-select @change="handleSearch" v-model="filters.file_id" placeholder="请选择关联航线" filterable clearable> <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" :value="item.wayline_id" /> </el-select> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="关联算法:"> <el-select @change="handleSearch" v-model="filters.ai_types" placeholder="关联算法" clearable> <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> <!-- <div class="search-bar-box-item"> <el-select v-model="filters.type" placeholder="请选择工单类型" clearable> <el-option v-for="item in types" :key="item.dictValue" :label="item.dictValue" :value="item.dictKey" /> </el-select> </div> --> </el-col> <el-col :span="4"> <el-form-item label="工单状态:"> <el-select @change="handleSearch" v-model="filters.status" placeholder="请选择工单状态" clearable :disabled="activeTab !== 'all'"> <el-option v-for="item in statuses" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="24"> <el-col :span="8"> <el-form-item label="工单周期:"> <el-date-picker @change="handleSearch" v-model="filters.cycleDateRange" type="daterange" range-separator="至" start-placeholder="工单周期开始日期" end-placeholder="工单周期结束日期" :default-value="datePickerDefaultVal" /> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="选择频次:"> <el-select @change="handleSearch" v-model="filters.rep_fre_type" placeholder="请选择频次" clearable> <el-option v-for="item in cycles" :key="item" :label="item" :value="item" /> </el-select> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="执行时间:"> <el-time-picker @change="handleSearch" v-model="filters.deal_time" placeholder="请选择执行时间" prop="deal_time" value-format="HH:mm" :picker-options="{ selectableRange: '00:00 - 23:59', }" /> </el-form-item> </el-col> <el-col :span="4"> <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索 </el-button> <el-button icon="el-icon-refresh" @click="handleReset">清空</el-button> </el-col> </el-row> </el-form> </div> <!-- 表格部分 --> <avue-crud class="ztzf-public-general-avue-crud" :data="tableData" :option="option" v-model:page="page" ref="crud" :table-loading="loading" @current-change="currentChange" @refresh-change="refreshChange" @on-load="onLoad" @search-change="searchChange" @size-change="sizeChange" v-if="activeTab === tab.name"> <template #job_info_num="{ row }"> <el-tooltip-copy :content="row.job_info_num" :showCopyText="true" textAlign="left"> {{ row.job_info_num }} </el-tooltip-copy> </template> <template #name="{ row }"> <el-tooltip-copy :content="row.name" :showCopyText="true" textAlign="left"> {{ row.name }} </el-tooltip-copy> </template> <template #menu-left> <el-button v-if="hasAddBtnPermission() && activeTab != 'WAIT_AUDIT'" type="primary" icon="el-icon-plus" @click="handleAdd">新建工单 </el-button> <el-button type="success" plain icon="el-icon-download" @click="exportData">导出 </el-button> </template> <template #menu="{ row }"> <div class="menu-custom-box"> <template v-if="row.status == 1"> <el-button v-if="hasPaddingBtnPermission()" type="text" icon="el-icon-view" @click="handleCheckDetail(row)">审核 </el-button> </template> <!-- v-if=" (userInfo.user_id == row.create_user || hasRecallPaddingBtnPermission()) && row.status == 1 " --> <template v-if="row.status == 1"> <!--待审核状态--> <el-button type="text" icon="el-icon-warning" v-if="hasRecallPaddingBtnPermission()" @click="orderLogRecall(row.id)">撤回 </el-button> <!-- <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情</el-button> --> </template> <!--已驳回--> <template v-if="row.status == 2"> <el-button type="text" icon="el-icon-warning" @click="rejectDetail(row.id)">驳回原因 </el-button> <el-button v-if="userInfo.user_id == row.create_user" type="text" icon="el-icon-view" @click="handleViewDetail(row)">编辑 </el-button> <el-button v-else type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情 </el-button> </template> <!-- 已通过 --> <template v-if="row.status == 3"> <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情 </el-button> </template> <!--草稿--> <template v-if="row.status == 0"> <el-button type="text" icon="el-icon-edit" @click="handleViewDetail(row)">编辑 </el-button> <el-button type="text" icon="el-icon-position" @click="userPublishPush(row.id)">发布 </el-button> <el-button type="text" icon="el-icon-delete" @click="deleteOrderLog(row.id)">删除 </el-button> </template> </div> </template> <template #status="{ row }"> <el-tag :type="getStatusTagType(row.status)">{{ mapStatus(row.status) }}</el-tag> </template> <template #keyData="{ row }"> <el-tooltip :content="row.address" placement="top" effect="light"> <span>{{ row.keyData }}</span> </el-tooltip> </template> </avue-crud> </basic-main-content> <el-tab-pane v-for="tab in tabsList" :key="tab.name" :label="`${tab.label} (${tab.count})`" :name="tab.name"> <SearchBox @search="searchClick"></SearchBox> <el-button v-if="hasAddBtnPermission() && activeTab != 'WAIT_AUDIT'" type="primary" icon="el-icon-plus" @click="handleAdd">新建工单 </el-button> <el-button type="success" plain icon="el-icon-download" @click="exportData">导出 </el-button> <div class="task-table"> <el-table border :data="orderListTable" class="custom-header"> <el-table-column label="序号" type="index" width="60"> <template #default="{ $index }"> {{ ($index + 1 + (orderListParams.current - 1) * orderListParams.size).toString().padStart(2, '0') }} </template> </el-table-column> <el-table-column prop="job_info_num" label="工单编号" width="160"> <template #default="scope"> <el-tooltip-copy :content="scope.row.job_info_num" :showCopyText="true"> {{scope.row.job_info_num}} </el-tooltip-copy> </template> </el-table-column> <el-table-column prop="name" label="工单名称" width="160"> <template #default="scope"> <el-tooltip-copy :content="scope.row.name" :showCopyText="true"> {{scope.row.name}} </el-tooltip-copy> </template> </el-table-column> <el-table-column prop="dept_name" label="所属单位" show-overflow-tooltip/> <el-table-column prop="create_time" label="创建时间" show-overflow-tooltip/> <el-table-column prop="job_num" label="已执行次数" show-overflow-tooltip align="center" /> <el-table-column prop="content" label="工单内容" show-overflow-tooltip align="center" /> <el-table-column prop="wayline_name" label="关联航线" show-overflow-tooltip /> <el-table-column prop="ai_type_str" label="关联算法" width="200" align="center" /> <el-table-column prop="device_names" label="关联机巢" width="200" align="center" /> <el-table-column prop="creator_name" label="创建人" align="center" show-overflow-tooltip /> <el-table-column prop="cycle_time_value" label="工单周期频次" align="center" show-overflow-tooltip /> <!-- <el-table-column label="操作" width="200" align="center">--> <!-- <template #default="scope">--> <!-- <el-button icon="el-icon-back" v-if="scope.row.status === 2" type="text"@click="turnBack(scope.row)">返航</el-button>--> <!-- <el-button icon="el-icon-close" v-if="scope.row.status === 1" type="text" @click="cancelTask(scope.row)">取消任务</el-button>--> <!-- <el-button icon="el-icon-view" type="text" @click="handleDetail(scope.row)">查看</el-button>--> <!-- </template>--> <!-- </el-table-column>--> </el-table> </div> <div class="pagination"> <el-pagination class="ztzf-pagination" popper-class="custom-pagination-dropdown" background :page-sizes="[10, 20, 30, 40, 50, 100]" v-model:current-page="orderListParams.current" v-model:page-size="orderListParams.size" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </el-tab-pane> </el-tabs> <!-- 新建工单对话框 --> <el-dialog class="ztzf-dialog-mange" v-model="dialogVisible" title="新建工单" width="70%" :close-on-click-modal="false" @close="resetForm"> <el-form :model="form" :rules="rules" ref="testform" label-width="100px"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单名称" prop="name"> <el-input v-model="form.name" placeholder="请输入工单名称" maxlength="100" show-word-limit></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="关联航线" prop="file_id"> <el-select v-model="form.file_id" placeholder="请选择航线" filterable @change="getFlyingNestBy"> <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" :value="item.wayline_id" /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="安全返航真高" prop="rth_altitude" class="safe-height"> <el-input-number v-model="form.rth_altitude" :min="50" :max="500"></el-input-number> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="关联机巢" prop="device_sns"> <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple :disabled="!device_sns.length"> <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname" :value="item.device_sn" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="关联算法" prop="ai_types"> <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple> <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单内容" prop="content"> <el-input type="textarea" v-model="form.content" rows="4" placeholder="请输入工单内容" maxlength="255" show-word-limit></el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="周期频次" prop="date_range"> <el-date-picker v-model="form.date_range" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :disabled-date="disabledDate" /> </el-form-item> </el-col> <el-col :span="4"> <div class="flex"> <div class="flex-1"> <el-select v-model="form.rep_fre_type" placeholder="请选择频次"> <el-option v-for="item in cycles" :key="item" :label="item" :value="item" /> </el-select> </div> <div class="flex-1"> <el-time-picker style="width: 100px" v-model="form.deal_time" prop="deal_time" value-format="HH:mm" :picker-options="{ selectableRange: '00:00 - 23:59', }" /> </div> </div> </el-col> </el-row> <el-row :gutter="20" style="height: 400px"> <el-col :span="24"> <map-container v-if="dialogVisible" ref="MapContainer"></map-container> </el-col> </el-row> <!-- <el-row>--> <!-- <div class="add-box-btns">--> <!-- <el-button type="danger" @click="submitForm(1)">发起</el-button>--> <!-- <el-button type="primary" @click="submitForm(0)">存草稿</el-button>--> <!-- <el-button @click="dialogVisible = false">取消</el-button>--> <!-- </div>--> <!-- </el-row>--> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="danger" @click="submitForm(1)" icon="el-icon-position">发起</el-button> <el-button type="primary" @click="submitForm(0)" icon="el-icon-document-add">存草稿</el-button> <el-button @click="dialogVisible = false" icon="el-icon-circle-close">取消</el-button> </div> </template> </el-dialog> <!-- 工单详情对话框 --> <el-dialog class="ztzf-dialog-mange" align-center v-model="detailVisible" :title="detailTitle" width="70%" :close-on-click-modal="false" @close="resetForm"> <div class="event-title-center">{{ form.name }}</div> <el-form :model="form" :rules="rules" ref="testform" label-width="100px"> <div class="custom-steps-container"> <!-- 标题行 --> <div class="steps-titles" v-if="filters.status !== '0'"> <div v-for="(record, index) in form.record_list" :class="{ active: record.user_id >= 0 }" :key="index" class="step-title"> {{ record.status_str }} </div> </div> <!-- Element Steps 组件 --> <el-steps :active="form.active" align-center class="custom-steps" v-if="filters.status !== '0'"> <el-step v-for="(record, index) in form.record_list" :key="index"> <template #description> <span class="step-description" style="position: relative; display: inline-block"> {{ record.user_name }} </span> <span class="step-timer"> {{ record.interval_time_str }} </span> <div class="step-description"> {{ record.create_time_str }} </div> </template> </el-step> </el-steps> </div> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单名称" prop="name"> <el-input v-model="form.name" placeholder="请输入工单名称" :disabled="detailTitle === '工单详情'"></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="关联航线" prop="file_id"> <el-select v-model="form.file_id" placeholder="请选择航线" @change="getFlyingNestBy" filterable :disabled="detailTitle === '工单详情'"> <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" :value="item.wayline_id" /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="安全返航真高" prop="rth_altitude" class="safe-height"> <el-input-number :disabled="detailTitle === '工单详情'" v-model="form.rth_altitude" :min="50" :max="500"></el-input-number> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="关联机巢" prop="device_sns"> <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple :disabled="detailTitle === '工单详情'"> <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname" :value="item.device_sn" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="关联算法" prop="ai_types"> <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple :disabled="detailTitle === '工单详情'"> <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12" prop="statusStr"> <el-form-item label="当前状态"> {{ mapStatus(form.status) }} </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="周期频次" prop="date_range"> <el-date-picker v-model="form.date_range" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :disabled-date="disabledDate" :disabled="detailTitle === '工单详情'" /> </el-form-item> </el-col> <el-col :span="3"> <el-select v-model="form.rep_fre_type" placeholder="请选择频次" :disabled="detailTitle === '工单详情'"> <el-option v-for="item in cycles" :key="item" :label="item" :value="item" /> </el-select> </el-col> <el-col :span="3"> <el-time-picker class="timeStyle" :style="{ width: pxToRem(140) }" v-model="form.deal_time" prop="deal_time" value-format="HH:mm" :picker-options="{ selectableRange: '00:00 - 23:59', }" :disabled="detailTitle === '工单详情'" /> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单内容" prop="content"> <el-input type="textarea" v-model="form.content" rows="4" placeholder="请输入工单内容" maxlength="255" show-word-limit :disabled="detailTitle === '工单详情'"></el-input> </el-form-item> </el-col> </el-row> <el-row :gutter="20" style="height: 400px"> <el-col :span="24"> <map-container v-if="detailVisible" ref="MapContainer"></map-container> </el-col> </el-row> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="danger" v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)" @click="submitForm(1)" icon="el-icon-position">发布 </el-button> <el-button type="primary" v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)" @click="submitForm(0)" icon="el-icon-plus">保存 </el-button> <!-- <el-button type="primary" v-if="form.status == 0 || userInfo.user_id == form.create_user" @click="submitForm(0)">保存</el-button> --> <el-button type="primary" v-if="form.status == 1 && hasPaddingBtnPermission()" @click="orderLogPass(form.id)">通过 </el-button> <el-button type="danger" v-if="form.status == 1 && hasRejectionBtnPermission()" @click="orderLogReject(form.id)">驳回 </el-button> </div> </template> </el-dialog> <!-- 工单详情 --> <el-dialog class="ztzf-dialog-mange" align-center v-model="detailVisibleCopy" title="工单详情" width="70%" :close-on-click-modal="false" @close="resetForm"> <div class="event-title-center">{{ form.name }}</div> <el-form :model="form" ref="testform" label-width="100px"> <div class="custom-steps-container"> <!-- 标题行 --> <div class="steps-titles" v-if="filters.status !== '0'"> <div v-for="(record, index) in form.record_list" :class="{ active: record.user_id >= 0 }" :key="index" class="step-title"> {{ record.status_str }} </div> </div> <!-- Element Steps 组件 --> <el-steps :active="form.active" align-center class="custom-steps" v-if="filters.status !== '0'"> <el-step v-for="(record, index) in form.record_list" :key="index"> <template #description> <span class="step-description" style="position: relative; display: inline-block"> {{ record.user_name }} </span> <span class="step-timer"> {{ record.interval_time_str }} </span> <div class="step-description"> {{ record.create_time_str }} </div> </template> </el-step> </el-steps> </div> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单名称" prop="name"> <el-input v-model="form.name" placeholder="请输入工单名称" :disabled="true"></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="关联航线" prop="file_id"> <el-select v-model="form.file_id" placeholder="请选择航线" :disabled="true"> <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" :value="item.wayline_id" /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="安全返航真高" prop="rth_altitude" class="safe-height"> <el-input-number :disabled="true" v-model="form.rth_altitude" :min="50" :max="500"></el-input-number> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="关联机巢" prop="device_sns"> <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple :disabled="true"> <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname" :value="item.device_sn" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="关联算法" prop="ai_types"> <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple :disabled="true"> <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12" prop="statusStr"> <el-form-item label="当前状态"> {{ mapStatus(form.status) }} </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="周期频次" prop="date_range"> <el-date-picker v-model="form.date_range" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :disabled="true" /> </el-form-item> </el-col> <el-col :span="3"> <el-select v-model="form.rep_fre_type" placeholder="请选择频次" :disabled="true"> <el-option v-for="item in cycles" :key="item" :label="item" :value="item" /> </el-select> </el-col> <el-col :span="3"> <el-time-picker style="width: 100px" v-model="form.deal_time" prop="deal_time" :disabled="true" value-format="HH:mm" :picker-options="{ selectableRange: '00:00 - 23:59', }" /> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单内容" prop="content"> <el-input type="textarea" v-model="form.content" rows="2" placeholder="请输入工单内容" maxlength="255" show-word-limit :readonly="true" :disabled="true"></el-input> </el-form-item> </el-col> </el-row> <el-row :gutter="20" style="height: 400px"> <el-col :span="24"> <map-container v-if="detailVisibleCopy" ref="MapContainer"></map-container> </el-col> </el-row> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="danger" v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)" @click="submitForm(1)" icon="el-icon-position">发布 </el-button> <!-- <el-button type="primary" v-if="form.status == 0 || userInfo.user_id == form.create_user" @click="submitForm(0)">保存</el-button> --> <el-button type="primary" v-if="form.status == 1 && hasPaddingBtnPermission()" @click="orderLogPass(form.id)" icon="el-icon-check">通过 </el-button> <el-button type="danger" v-if="form.status == 1 && hasRejectionBtnPermission()" @click="orderLogReject(form.id)" icon="el-icon-close">驳回 </el-button> <el-button @click="detailVisibleCopy = false" icon="el-icon-circle-close">取消</el-button> </div> </template> </el-dialog> </basic-container> </div> </template> <script> import { pxToRem, pxToRemNum } from '@/utils/rem' import { calculateDefaultRange } from '@/utils/util' <script setup> import SearchBox from './SearchBox.vue' import { useStore } from 'vuex' import { getList, saveUpdateOrderLog, @@ -558,1111 +76,149 @@ deleteOrderLog, getWaylineMaxTerrainHeight } from '@/api/tickets/orderLog' import { getTicketInfo } from '@/api/tickets/ticket' import { getDictionaryByCode } from '@/api/system/dictbiz' import { getWaylineFileListByArea, newGetWorkspacesPage } from '@/api/resource/wayline' import { export_json_to_excel } from '@/utils/exportExcel' import { getFlyingNestBy } from '@/api/device/device' import { mapGetters } from 'vuex' import NProgress from 'nprogress' import { downloadXls } from '@/utils/util' import 'nprogress/nprogress.css' import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz' import dayjs from 'dayjs' import 'dayjs/locale/zh-cn' // 导入中文语言包 import weekday from 'dayjs/plugin/weekday' import elTooltipCopy from '@/components/ElTooltipCopy.vue' import { CircleClose, Promotion, Select } from '@element-plus/icons-vue' import { useStore } from 'vuex' import _ from 'lodash' // const store = useStore() dayjs.extend(weekday) dayjs.locale('zh-cn') import { cloneDeep } from 'lodash'; import { computed, onMounted } from 'vue'; // const lastHeight = computed(() => store.state.common.lastHeight) const store = useStore() export default { components: { elTooltipCopy }, name: 'TicketPage', data () { return { activeTab: 'all', getlastHeight: 0, tabs: [ { label: '全部工单', name: 'all', value: null, count: 0 }, { label: '待审核', name: 'WAIT_AUDIT', value: 1, count: 0 }, { label: '已驳回', name: 'REJECTED', value: 2, count: 0 }, { label: '已通过', name: 'PASS', value: 3, count: 0 }, { label: '草稿', name: 'DRAFT', value: 0, count: 0 } ], filters: { key_word: '', create_dept: '', start_date: null, end_date: null, file_id: '', ai_types: [], status: '', dateRange: [] }, departments: [], types: [], device_sns: [], ai_types: [], wayLineList: [], detailTitle: '编辑工单', detailVisibleCopy: false, const permission = computed(() => store.state.user.permission); statuses: [ { label: '草稿', value: '0' }, { label: '待审核', value: '1' }, { label: '已驳回', value: '2' }, { label: '已通过', value: '3' } ], //周期 cycles: ['每天', '周一', '周二', '周三', '周四', '周五', '周六', '周末', '周天', '工作日'], console.log(permission, '8888') tableData: [], option: { index: true, indexWidth: 66, indexLabel: '序号', indexFixed: true, const activeTab = ref('all') // tab切换 function handleTabChange (tab) { align: 'left', border: true, stripe: false, searchShow: true, searchBtnText: '搜索', searchMenuSpan: 6, addBtnText: '新建工单', addBtn: false, viewBtn: false, editBtn: false, delBtn: false, cancelBtn: true, cancelBtnText: '取消', menu: true, menuWidth: 210, menuClassName: 'cur-menu', height: 'auto', calcHeight: 196, column: [ { label: '工单编号', prop: 'job_info_num', width: 150 }, { label: '工单名称', prop: 'name', width: 100, ellipsis: true, overHidden: true, showOverflowTooltip: true }, { label: '工单状态', prop: 'status', width: 88, showOverflowTooltip: true }, { label: '所属单位', prop: 'dept_name', ellipsis: true, showOverflowTooltip: true }, { label: '创建时间', prop: 'create_time', width: 144, ellipsis: true, showOverflowTooltip: true }, { label: '已执行次数', prop: 'job_num', width: 70, ellipsis: true, showOverflowTooltip: true }, { label: '工单内容', prop: 'content', ellipsis: true, overHidden: true, showOverflowTooltip: true }, { label: '关联航线', prop: 'wayline_name', ellipsis: true, overHidden: true, showOverflowTooltip: true }, { label: '关联算法', prop: 'ai_type_str', width: 100, ellipsis: true, overHidden: true, showOverflowTooltip: true }, { label: '关联机巢', prop: 'device_names', width: 100, ellipsis: true, overHidden: true, showOverflowTooltip: true }, { label: '创建人', prop: 'creator_name', width: 96, ellipsis: true, overHidden: true, showOverflowTooltip: true }, // { // label: '关联机巢', prop: 'device_names', width: 112, ellipsis: true, overHidden: true, // showOverflowTooltip: true, // }, { label: '工单周期频次', prop: '', width: 110, formatter: row => this.formatCycleTime(row), html: true, ellipsis: true, showOverflowTooltip: true // overHidden: true } ] }, page: { pageSize: 10, currentPage: 1, total: 0 }, dialogVisible: false, detailVisible: false, currentDetail: {}, form: {}, rules: { name: [ { required: true, message: '请输入工单名称', trigger: 'blur' }, { max: 100, message: '工单名称不能超过100个字', trigger: 'blur' } ], file_id: [{ required: true, message: '需要选择航线', trigger: 'change' }], device_sns: [{ required: true, message: '请选择机巢', trigger: 'change' }], content: [ { required: true, message: '请输入工单内容', trigger: 'blur' }, { max: 255, message: '工单内容不能超过255个字', trigger: 'blur' } ], date_range: [{ required: true, message: '请选择时间不能为空', trigger: 'blur' }], rep_fre_type: [{ required: true, message: '请选择周期', trigger: 'blur' }], deal_time: [{ required: true, message: '请选择执行时间', trigger: 'blur' }] }, loading: false, globalCounts: {}, mapLoaded: false, // 配置时间选择器默认配置 datePickerDefaultVal: calculateDefaultRange() } }, async created () { var response = await getDictionaryByCode('SF') var word_order_typeResponse = await getDictionaryByCode('WORK_ORDER_TYPE') this.ai_types = response.data.data['SF'] this.types = word_order_typeResponse.data.data['WORK_ORDER_TYPE'] //获取航线 this.asyncgetWaylineFileListByArea() const response2 = await getTicketInfo() const { dept_data, event_type, ai_type } = response2.data.data this.departments = dept_data.map(item => ({ label: item.dept_name, value: item.id })) }, mounted () { this.fetchTableData() const id = this.$route.query.id console.log('idddddd', id) if (id) { // 确保 id 存在 this.handleViewDetail({ id }) const find = this.$store.state.tags.bsTagList.find(i => i.path === '/tickets/orderLog') find && (find.query = {}) } else { console.error('工单ID不存在!') } }, computed: { CircleClose () { return CircleClose }, ...mapGetters(['userInfo', 'permission']), safeHeight () { const safeHeight = this.$store.state.common.safeHeight return Number(safeHeight) || 0 // 确保是数字类型 }, positionsArr () { const positionsArr = this.$store.state.common.positionsArr return positionsArr || [] // 确保是数字类型 }, filteredTabs () { // rejection_and_draft 权限控制“已驳回”和“草稿”tab // console.log(this.permission, '权限信息') // console.log(this.userInfo, '权限信息22') const canShowRejectAndDraft = this.permission?.rejection_and_draft === true return this.tabs .map(tab => { if (tab.name === 'DRAFT') { return { ...tab, isShow: canShowRejectAndDraft } } if (tab.name === 'REJECTED') { return { ...tab, isShow: canShowRejectAndDraft } } return { ...tab, isShow: true } }) .filter(tab => tab.isShow) } }, methods: { handleCellClick (row, column) { if (column.no === 1) { navigator.clipboard.writeText(row.job_info_num).then(() => { this.$message.success('复制工单编号成功') }) } else if (column.no === 2) { navigator.clipboard.writeText(row.name).then(() => { this.$message.success('复制工单名称成功') }) } else if (column.no === 4) { navigator.clipboard.writeText(row.dept_name).then(() => { this.$message.success('复制所属单位成功') }) } else if (column.no === 8) { navigator.clipboard.writeText(row.wayline_name).then(() => { this.$message.success('复制关联航线成功') }) } else if (column.no === 9) { navigator.clipboard.writeText(row.ai_type_str).then(() => { this.$message.success('复制关联算法成功') }) } }, disabledDate (time) { return time.getTime() < Date.now() - 8.64e7 // 86400000 = 24 * 60 * 60 * 1000 }, searchChange (params, done) { // console.log('searchChange') this.query = params this.parentId = '' this.page.currentPage = 1 this.onLoad(this.page, params) done() }, async onLoad (page, params = {}) { this.loading = true getList( null, this.page.currentPage, this.page.pageSize, Object.assign(params, this.query) ).then(res => { this.tableData = res.data.data this.loading = false this.selectionClear() }) }, selectionClear () { this.selectionList = [] this.$refs.crud.toggleSelection() }, async loadAMapScripts () { try { // await loadAMap(); // await loadAMapUI(); this.mapLoaded = true } catch (error) { console.error('Failed to load AMap scripts:', error) this.$message.error('地图加载失败,请检查网络或API Key配置') } }, formatCycleTime (row) { return `${row.cycle_time_value}` }, async fetchTableData () { this.loading = true try { let params = this.getQueryParam() // console.log('发送的参数:', params) const response = await getList(params, this.page.currentPage, this.page.pageSize) if (!response?.data?.data?.records) { throw new Error('接口返回数据格式不正确') } const { total, records } = response.data.data this.tableData = records.map(item => { return item }) // console.log('权限检查:', this.permission) this.page.total = total || 0 this.updateGlobalCounts() } catch (error) { // console.error('获取数据失败:', error) this.$message.error(error.message || '获取数据失败') this.tableData = [] this.page.total = 0 } finally { this.loading = false } }, getQueryParam () { const currentTab = this.tabs.find(tab => tab.name === this.activeTab) if (this.filters.dateRange) { // console.log( // 'this.formatDate(this.filters.dateRange[0])', // this.formatDate(this.filters.dateRange[0]) // ) } const params = { key_word: this.filters.key_word || undefined, create_dept: this.filters.create_dept || undefined, ai_types: this.filters.ai_types && this.filters.ai_types.length > 0 ? [this.filters.ai_types] : null, file_id: this.filters.file_id || undefined, status: this.filters.status !== '' ? Number(this.filters.status) : currentTab?.value, dept_id: this.filters.department || undefined, create_start_date: this.filters.dateRange?.[0] ? this.formatDate(this.filters.dateRange[0]) : undefined, create_end_date: this.filters.dateRange?.[1] ? this.formatDate(this.filters.dateRange[1]).replace('00:00:00', '23:59:59') : undefined, start_date: this.filters.cycleDateRange?.[0] ? this.formatDate(this.filters.cycleDateRange[0]) : undefined, end_date: this.filters.cycleDateRange?.[1] ? this.formatDate(this.filters.cycleDateRange[1]).replace('00:00:00', '23:59:59') : undefined, rep_fre_type: this.filters.rep_fre_type || undefined, deal_time: this.filters.deal_time || undefined, current: this.page.currentPage, size: this.page.pageSize } return params }, sizeChange (pageSize) { this.page.pageSize = pageSize }, async submitForm (status) { this.$refs.testform.validate(async valid => { if (valid) { let dateRange = this.form.date_range // console.log('dateRange' + dateRange) this.form.begin_time = this.formatDate(dateRange[0]) this.form.end_time = this.formatDate(dateRange[1]) // 如果选中日期包含当前天,那么选中的时间点不能小于当前时间 if (this.form.deal_time) { const selectedDate = dayjs(this.form.date_range[0]).format('YYYY-MM-DD') const selectedTime = dayjs(selectedDate + ' ' + this.form.deal_time).toDate() const now = new Date() if (selectedDate === dayjs().format('YYYY-MM-DD') && selectedTime < now) { return this.$message.warning('任务时间不能小于当前时间') } } let checkedList = this.device_sns.filter(item => this.form.device_sns.includes(item.device_sn)); const maxItem = checkedList.reduce((max, item) => { return item.drone_height > max.drone_height ? item : max; }); // 返航绝对高度 let backHeight = this.form.rth_altitude // + maxItem.drone_height console.log(backHeight,'backHeight') // 安全起飞高度 let positions = this.positionsArr positions.unshift({latitude: maxItem.latitude, longitude: maxItem.longitude, height:maxItem.drone_height }) positions.push({latitude: maxItem.latitude, longitude: maxItem.longitude, height:maxItem.drone_height}) let resultHeight = 0 await getWaylineMaxTerrainHeight(positions).then(res => { resultHeight = this.safeHeight > (res.data.data + 30) ? this.safeHeight : (res.data.data + 30) }) let valueHeight = _.round(backHeight - resultHeight, 2) console.log('打印比较值', valueHeight) if (valueHeight < 0) { this.$confirm(`当前返航高度存在安全隐患,建议调整为${resultHeight}米以上后进行发布`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(async () => { const submitData = { ...this.form, status: status, ai_types: this.form.ai_types?.length ? this.form.ai_types : [] } await saveUpdateOrderLog(submitData) let id = this.form.id if (id) { this.$message.success('工单发布成功') } else { this.$message.success('工单创建成功') } this.dialogVisible = false this.detailVisible = false; (this.device_sns = []), (this.wayLineList = []), this.fetchTableData() }).catch(() => { }) } else { const submitData = { ...this.form, status: status, ai_types: this.form.ai_types?.length ? this.form.ai_types : [] } await saveUpdateOrderLog(submitData) let id = this.form.id if (id) { this.$message.success('工单发布成功') } else { this.$message.success('工单创建成功') } this.dialogVisible = false this.detailVisible = false; (this.device_sns = []), (this.wayLineList = []), this.fetchTableData() } } }) }, //驳回原因显示 async rejectDetail (id) { const response = await orderLogDetails(id) let data = response.data.data this.$confirm(data.remark, '驳回原因', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.form = { ...response.data.data } // this.detailVisible = true this.handleViewDetail(data) }) }, 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` }, mapStatus (status) { const statusTextMap = { 0: '草稿', 1: '待审核', 2: '已驳回', 3: '已通过' } return statusTextMap[status] || '未知状态' }, getStatusTagType (status) { const statusMap = { 1: 'warning', 2: 'info', 3: 'primary', 4: 'success', 5: 'danger' } return statusMap[status] || 'info' }, handleTabChange (tab) { this.activeTab = tab.props?.name || tab.name this.filters.status = '' if (tab.props?.name === 'WAIT_AUDIT') { this.filters.status = '1' } else if (tab.props?.name === 'REJECTED') { this.filters.status = '2' } else if (tab.props?.name === 'PASS') { this.filters.status = '3' } else if (tab.props?.name === 'DRAFT') { this.filters.status = '0' } this.page.currentPage = 1 this.fetchTableData() }, handleSearch () { this.page.currentPage = 1 this.fetchTableData() }, handleReset () { this.filters = { keyword: '', department: '', type: '', dateRange: [], status: '' } this.page.currentPage = 1 this.fetchTableData() }, currentChange (currentPage) { this.page.currentPage = currentPage }, async updateGlobalCounts () { const counts = { all: 0, DRAFT: 0, WAIT_AUDIT: 0, REJECTED: 0, PASS: 0 } var reponse = await jobStatusNum() // console.log('统计' + reponse.data.data) reponse.data.data.forEach(item => { const tab = this.tabs.find(t => t.name === item.dict_key) if (tab) { tab.count = item.num } }) }, handleAdd () { this.form = {} this.form.rth_altitude = 120 this.dialogVisible = true this.$nextTick(() => { if (this.$refs.MapContainer && this.$refs.MapContainer.initAddEntity) { this.$refs.MapContainer.initAddEntity('initPosition') } }) //航线列表 this.asyncgetWaylineFileListByArea() }, resetForm () { this.form = { name: '', type: '', handler: '', algorithm: '', location: '', address: '', content: '', photos: [] } if (this.$refs.testform) { this.$refs.testform.resetFields() } }, formatLocation (location) { if (!Array.isArray(location)) { return '未知位置' } return `${location[0].toFixed(6)}, ${location[1].toFixed(6)}` }, async handleViewDetail (row) { const response = await orderLogDetails(row.id) const data = response.data.data this.form = { ...data } // 更新机巢列表 this.device_sns = data.device_map_infos;// data.device_list; this.permission && (this.permission.order_log_review || this.permission.order_log_recall) && (data.status == 1 || data.status == 3 || (data.status == 2 && this.userInfo.user_id !== this.form.create_user)) ? (this.detailTitle = '工单详情') : (this.detailTitle = '编辑工单') this.detailVisible = true // 更新航线列表,追加 wayline_file_region_vo 数据 if (data.wayline_file_region_vo) { const newWayline = data.wayline_file_region_vo // 检查是否已经存在于 this.wayLineList 中 const isDuplicate = this.wayLineList.some( item => item.wayline_id === newWayline.wayline_id ) if (!isDuplicate) { this.wayLineList.push(newWayline) } } this.initMapLine(data.device_map_infos) const find = this.$store.state.tags.bsTagList.find(i => i.path === '/tickets/orderLog') find && (find.query = {}) }, async handleCheckDetail (row) { const response = await orderLogDetails(row.id) const data = response.data.data this.form = { ...data } // 更新航线列表,追加 wayline_file_region_vo 数据 // 更新航线列表,追加 wayline_file_region_vo 数据 if (data.wayline_file_region_vo) { const newWayline = data.wayline_file_region_vo // 检查是否已经存在于 this.wayLineList 中 const isDuplicate = this.wayLineList.some( item => item.wayline_id === newWayline.wayline_id ) if (!isDuplicate) { this.wayLineList.push(newWayline) } } // 更新机巢列表 this.device_sns = data.device_list this.detailVisibleCopy = true this.initMapLine(data.device_map_infos) }, //导出 async exportData () { this.$confirm('是否智飞工单数据?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { NProgress.start() let params = this.getQueryParam() orderLogExport(params).then(res => { downloadXls(res.data, `智飞工单${this.$dayjs().format('YYYY-MM-DD')}.xlsx`) NProgress.done() }) }) }, hasAddBtnPermission () { // undefined 或 false 都返回 false,只有 true 返回 true // console.log('this.permission.order_log_add :', this.permission.order_log_add) return this.permission && this.permission.order_log_add === true }, hasPaddingBtnPermission () { // undefined 或 false 都返回 false,只有 true 返回 true // console.log('权限检查:', this.permission) return this.permission && this.permission.order_log_review === true }, hasRecallPaddingBtnPermission () { // undefined 或 false 都返回 false,只有 true 返回 true // console.log('权限检查:', this.permission) // 智飞工单撤回 return this.permission && this.permission.order_log_recall === true }, //驳回按钮权限 hasRejectionBtnPermission () { // undefined 或 false 都返回 false,只有 true 返回 true // console.log('权限检查:', this.permission) return this.permission && this.permission.rejection_btn === true }, //自己点发布 userPublishPush (id) { this.$confirm('确定发布吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { let response = userPublish(id) this.$message.success('发布成功') this.fetchTableData() }) }, //删除 deleteOrderLog (id) { this.$confirm('确定删除吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { let response = deleteOrderLog(id) this.$message.success('删除') this.fetchTableData() }) }, refreshChange () { this.fetchTableData() }, //获取航线列表 async asyncgetWaylineFileListByArea (name) { const formData = { name: '', waylineType: undefined, current: 1, size: 99999999, descs: 'update_time' } var wayLineListResponse = await newGetWorkspacesPage(formData) this.wayLineList = wayLineListResponse.data.data.records this.initMapLine() }, initMapLine (infos = {}, cb = () => { }) { let currentLine = this.wayLineList.find(item => item.wayline_id == this.form.file_id) if (!currentLine) return this.$nextTick(() => { if (this.$refs.MapContainer && this.$refs.MapContainer.initAddEntity) { this.$refs.MapContainer.initAddEntity('polyline', { url: `${import.meta.env.VITE_APP_AIRLINE_URL + currentLine.object_key }?_t=${new Date().getTime()}`, type: currentLine.wayline_type, cb, infos }) } }) }, //可飞行机巢列表 async getFlyingNestBy (waylineId) { const that = this // 先清空 that.form.device_sns = [] that.device_sns = [] this.initMapLine({}, async polygon => { const currentLine = that.wayLineList.find(item => item.wayline_id === waylineId) //按照航线来 const params = { type: ['2', '4', '5'].includes(currentLine.wayline_type) ? 2 : 0, wayline_id: waylineId, polygon } var wayLineListResponse = await getFlyingNestBy(params) // 再赋值 that.device_sns = wayLineListResponse.data.data }) }, //撤回 async orderLogRecall (id) { this.$confirm('确定撤回则到草稿箱。', '是否撤回?', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(async () => { let reposne = await orderLogRecall(id) this.handleSearch() }) }, onLoad () { this.fetchTableData() }, /** * 通过 */ async orderLogPass (id) { let response = await orderLogPass(id) let data = response.data.data this.$message.success('审核通过') this.detailVisibleCopy = false this.detailVisible = false this.page.currentPage = 1 this.onLoad(this.page, this.query) // this.handleViewDetail() }, /** * 驳回 */ async orderLogReject (id) { this.$prompt('', '驳回原因', { confirmButtonText: '确定', cancelButtonText: '取消' }).then(async ({ value }) => { let response = await orderLogReject(id, value) let data = response.data.data this.$message.success('驳回成功') this.detailVisibleCopy = false // this.detailVisible = false this.page.currentPage = 1 this.onLoad(this.page, this.query) }) } }, watch: { // lastHeight(newVal, oldVal) { // console.log('lastHeight', newVal, oldVal); // this.getlastHeight = newVal; // }, tableData: { handler () { // this.updateTabCounts() }, deep: true } } } let tabsList = ref([ { label: '全部工单', name: 'all', value: null, count: 0 }, { label: '待审核', name: 'WAIT_AUDIT', value: 1, count: 0 }, { label: '已驳回', name: 'REJECTED', value: 2, count: 0 }, { label: '已通过', name: 'PASS', value: 3, count: 0 }, { label: '草稿', name: 'DRAFT', value: 0, count: 0 } ]) const total = ref(0) const orderListParams = reactive({ current: 1, size: 10, searchParams: {}, }) const orderListTable = ref([]) function getTableList() { const apiParams = { ...cloneDeep(orderListParams), searchParams: { ...cloneDeep(orderListParams.searchParams) }, } getList(apiParams).then(res => { console.log(res.data.data.records,'99999999') orderListTable.value = res.data.data.records total.value = res.data.data.total }) } // 分页大小改变 const handleSizeChange = val => { orderListParams.size = val getTableList() } // 页码改变 const handleCurrentChange = val => { orderListParams.current = val getTableList() } // 传参查询条件 const searchClick = params => { orderListParams.current = 1 orderListParams.size = 10 orderListParams.searchParams = params getTableList() } const refreshGetJobList = () => { orderListParams.current = 1 orderListParams.size = 10 getTableList() } // 新增按钮 和 导出按钮 function hasAddBtnPermission () { // undefined 或 false 都返回 false,只有 true 返回 true // console.log('this.permission.order_log_add :', this.permission.order_log_add) return permission && permission?.order_log_add === true } onMounted(() => { getTableList() }) </script> <style lang="scss" scoped> //:deep(.el-input-number) { // width: 200px; //} //:deep(.el-form-item__label) { // width: 100px !important; //} ::v-deep(.el-tabs) { height: 100%; .order-log-update { height: 0; flex: 1; margin: 0 10px 10px 10px; background-color: #ffffff; padding: 10px 20px; border-radius: 5px; display: flex; flex-direction: column; .el-tabs__header { order: 1; // 表格 .task-table { //height: 0; //flex: 1; height: 500px; margin-top: 18px; overflow: auto; } .el-tabs__content { order: 2; .btnItem { height: 27px; line-height: 27px; border-radius: 0px 0px 0px 0px; border: 1px solid #51a8ff; font-family: Segoe UI, Segoe UI; font-weight: 400; font-size: 14px; color: #1C5CFF; padding: 0 10px; display: inline-block; margin-right: 10px; cursor: pointer; &.turnBack { border: 1px solid #ffa500; color: #ffa500; } &.cancelTask { border: 1px solid #00AA2D; color: #00AA2D; } } // 分页 :deep(.custom-header th.el-table__cell) { color: rgba(0, 0, 0, 0.85); } .el-tabs__content { height: 0; flex: 1; :deep(.el-table td.el-table__cell) { color: #606266; } :deep(.el-pagination) { display: flex; flex-direction: column; .el-tab-pane { height: 0; flex: 1; display: flex; flex-direction: column; } } } .filter-bar { // align-items: center; .search-bar-box { margin-bottom: 15px; display: flex; justify-content: space-between; gap: 8px; &-item { flex: 1; &> ::v-deep(.el-date-editor) { width: 100%; box-sizing: border-box; } } .search-btn { flex: 1; display: flex; justify-content: flex-end; } .flex-2 { min-width: 454px; } } } :deep(.el-pagination .el-select) { width: 128px !important; } .step-timer { position: absolute; left: 80%; top: 50%; transform: translateY(-50%); width: 100px; margin-left: 4px; color: #666; font-size: 12px; } :deep(.el-textarea__inner) { padding: 8px 12px; } :deep(.el-input__inner), :deep(.el-select), :deep(.el-select .el-input) { width: 100%; // 确保所有输入框和选择框宽度一致 } :deep(.el-textarea__inner) { resize: none; } .action-bar { margin-bottom: 16px; } .el-tabs { :deep(.el-tabs__content) { overflow: visible; } } .el-dialog { .el-form-item { margin-bottom: 10px; } } .el-upload { width: 100%; display: flex; flex-wrap: wrap; :deep(.el-upload-list__item) { transition: all 0.3s ease; justify-content: right; } :deep(.el-upload-list__item:hover) { background-color: #f5f7fa; } } .el-upload__tip { font-size: 12px; color: #909399; margin-top: 7px; } .custom-steps-container { width: 100%; margin: 20px 0; } .steps-titles { display: flex; justify-content: space-between; margin-bottom: 16px; position: relative; } .step-title { text-align: center; flex: 1; font-size: 16px; color: #999; position: relative; padding-bottom: 10px; } .step-title.active { color: #409eff; font-weight: bold; } .custom-steps { margin-top: -20px; /* 向上移动与标题重叠 */ } .el-step__head { margin-top: 0; } .el-step__description { margin-top: 8px; padding: 0 20px; } .step-description { font-size: 14px; color: #666; line-height: 1.5; } .event-title-center { text-align: center; font-size: 20px; font-weight: bold; margin-bottom: 12px; color: #333; } .cur-menu { .menu-custom-box { display: flex; justify-content: center; flex-wrap: wrap; &> ::v-deep(.el-button) { flex: 1; margin-left: 0; margin-right: 10px; } } } .add-box-btns { width: 100%; display: flex; justify-content: center; } .safe-height { :deep(.el-form-item__label) { width: 120px !important; } :deep(.el-input-number) { width: 180px !important; } } .flex { display: flex; } .flex-1 { flex: 1; &> ::v-deep(div) { width: 100% !important; :deep(.el-pagination button) { background: center center no-repeat none !important; color: #8eb8ea !important; } } </style> src/views/tickets/orderLog1.vue
New file @@ -0,0 +1,191 @@ <!-- 任务统计表格 --> <template> <div class="order-log-update"> <el-tabs v-model="activeTab" @tab-click="handleTabChange"> <el-tab-pane v-for="tab in tabsList" :key="tab.name" :label="`${tab.label} (${tab.count})`" :name="tab.name"> <SearchBox @search="searchClick"></SearchBox> <div class="task-table"> <el-table border :data="orderListTable" class="custom-header"> <el-table-column label="序号" type="index" width="60"> <template #default="{ $index }"> {{ ($index + 1 + (orderListParams.current - 1) * orderListParams.size).toString().padStart(2, '0') }} </template> </el-table-column> <el-table-column prop="job_info_num" label="工单编号" width="160"> <template #default="scope"> <el-tooltip-copy :content="scope.row.job_info_num" :showCopyText="true"> {{scope.row.job_info_num}} </el-tooltip-copy> </template> </el-table-column> <el-table-column prop="name" label="工单名称" width="160"> <template #default="scope"> <el-tooltip-copy :content="scope.row.name" :showCopyText="true"> {{scope.row.name}} </el-tooltip-copy> </template> </el-table-column> <el-table-column prop="dept_name" label="所属单位" show-overflow-tooltip/> <el-table-column prop="create_time" label="创建时间" show-overflow-tooltip/> <el-table-column prop="job_num" label="已执行次数" show-overflow-tooltip align="center" /> <el-table-column prop="content" label="工单内容" show-overflow-tooltip align="center" /> <el-table-column prop="wayline_name" label="关联航线" show-overflow-tooltip /> <el-table-column prop="ai_type_str" label="关联算法" width="200" align="center" /> <el-table-column prop="device_names" label="关联机巢" width="200" align="center" /> <el-table-column prop="creator_name" label="创建人" align="center" show-overflow-tooltip /> <el-table-column prop="cycle_time_value" label="工单周期频次" align="center" show-overflow-tooltip /> <el-table-column label="操作" width="200" align="center"> <template #default="scope"> <el-button icon="el-icon-back" v-if="scope.row.status === 2" type="text"@click="turnBack(scope.row)">返航</el-button> <el-button icon="el-icon-close" v-if="scope.row.status === 1" type="text" @click="cancelTask(scope.row)">取消任务</el-button> <el-button icon="el-icon-view" type="text" @click="handleDetail(scope.row)">查看</el-button> </template> </el-table-column> </el-table> </div> <div class="pagination"> <el-pagination class="ztzf-pagination" popper-class="custom-pagination-dropdown" background :page-sizes="[10, 20, 30, 40, 50, 100]" :size="size" v-model:current-page="orderListParams.current" v-model:page-size="orderListParams.size" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </el-tab-pane> </el-tabs> </div> </template> <script setup> import SearchBox from './SearchBox.vue' import { getList, saveUpdateOrderLog, orderLogDetails, orderLogRecall, orderLogReject, orderLogPass, orderLogExport, jobStatusNum, userPublish, deleteOrderLog, getWaylineMaxTerrainHeight } from '@/api/tickets/orderLog' import { cloneDeep } from 'lodash'; let tabsList = ref([ { label: '全部工单', name: 'all', value: null, count: 0 }, { label: '待审核', name: 'WAIT_AUDIT', value: 1, count: 0 }, { label: '已驳回', name: 'REJECTED', value: 2, count: 0 }, { label: '已通过', name: 'PASS', value: 3, count: 0 }, { label: '草稿', name: 'DRAFT', value: 0, count: 0 } ]) const orderListParams = reactive({ current: 1, size: 10, searchParams: {}, }) const orderListTable = ref([]) function getTableList() { const apiParams = { ...cloneDeep(orderListParams), searchParams: { ...cloneDeep(orderListParams.searchParams) }, } getList(apiParams).then(res => { orderListTable.value = res.data.data }) } // 分页大小改变 const handleSizeChange = val => { orderListParams.size = val getTableList() } // 页码改变 const handleCurrentChange = val => { orderListParams.current = val getTableList() } // 传参查询条件 const searchClick = params => { orderListParams.current = 1 orderListParams.size = 10 orderListParams.searchParams = params getTableList() } const refreshGetJobList = () => { orderListParams.current = 1 orderListParams.size = 10 getTableList() } </script> <style lang="scss" scoped> .order-log-update { height: 0; flex: 1; margin: 0 10px 10px 10px; background-color: #ffffff; padding: 10px 20px; border-radius: 5px; display: flex; flex-direction: column; // 表格 .task-table { height: 0; flex: 1; margin-top: 18px; overflow: auto; } .btnItem { height: 27px; line-height: 27px; border-radius: 0px 0px 0px 0px; border: 1px solid #51a8ff; font-family: Segoe UI, Segoe UI; font-weight: 400; font-size: 14px; color: #1C5CFF; padding: 0 10px; display: inline-block; margin-right: 10px; cursor: pointer; &.turnBack { border: 1px solid #ffa500; color: #ffa500; } &.cancelTask { border: 1px solid #00AA2D; color: #00AA2D; } } // 分页 :deep(.custom-header th.el-table__cell) { color: rgba(0, 0, 0, 0.85); } :deep(.el-table td.el-table__cell) { color: #606266; } :deep(.el-pagination) { display: flex; justify-content: right; } :deep(.el-pagination button) { background: center center no-repeat none !important; color: #8eb8ea !important; } } </style> src/views/tickets/orderLogCopy.vue
New file @@ -0,0 +1,1668 @@ <template> <basic-container> <el-tabs v-model="activeTab" @tab-click="handleTabChange"> <el-tab-pane v-for="tab in filteredTabs" :key="tab.name" :label="`${tab.label} (${tab.count})`" :name="tab.name"> <basic-main-content> <!-- 查询条件筛选栏 --> <div class="ztzf-form-search"> <el-form :model="filters" inline> <el-row :gutter="24"> <el-col :span="4"> <el-form-item label="关键字:"> <el-input v-model="filters.key_word" placeholder="编号/名称/内容/姓名" clearable @keyup.enter="handleSearch" /> </el-form-item> <!-- <div class="search-bar-box-item">--> <!-- <el-select placeholder="请选择所属单位" v-model="filters.create_dept" clearable>--> <!-- <el-option v-for="dept in departments" :key="dept.value" :label="dept.label" :value="dept.value" />--> <!-- </el-select>--> <!-- </div>--> </el-col> <el-col :span="8"> <el-form-item label="选择日期:"> <el-date-picker @change="handleSearch" v-model="filters.dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :default-value="datePickerDefaultVal" /> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="关联航线:"> <el-select @change="handleSearch" v-model="filters.file_id" placeholder="请选择关联航线" filterable clearable> <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" :value="item.wayline_id" /> </el-select> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="关联算法:"> <el-select @change="handleSearch" v-model="filters.ai_types" placeholder="关联算法" clearable> <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> <!-- <div class="search-bar-box-item"> <el-select v-model="filters.type" placeholder="请选择工单类型" clearable> <el-option v-for="item in types" :key="item.dictValue" :label="item.dictValue" :value="item.dictKey" /> </el-select> </div> --> </el-col> <el-col :span="4"> <el-form-item label="工单状态:"> <el-select @change="handleSearch" v-model="filters.status" placeholder="请选择工单状态" clearable :disabled="activeTab !== 'all'"> <el-option v-for="item in statuses" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="24"> <el-col :span="8"> <el-form-item label="工单周期:"> <el-date-picker @change="handleSearch" v-model="filters.cycleDateRange" type="daterange" range-separator="至" start-placeholder="工单周期开始日期" end-placeholder="工单周期结束日期" :default-value="datePickerDefaultVal" /> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="选择频次:"> <el-select @change="handleSearch" v-model="filters.rep_fre_type" placeholder="请选择频次" clearable> <el-option v-for="item in cycles" :key="item" :label="item" :value="item" /> </el-select> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="执行时间:"> <el-time-picker @change="handleSearch" v-model="filters.deal_time" placeholder="请选择执行时间" prop="deal_time" value-format="HH:mm" :picker-options="{ selectableRange: '00:00 - 23:59', }" /> </el-form-item> </el-col> <el-col :span="4"> <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索 </el-button> <el-button icon="el-icon-refresh" @click="handleReset">清空</el-button> </el-col> </el-row> </el-form> </div> <!-- 表格部分 --> <avue-crud class="ztzf-public-general-avue-crud" :data="tableData" :option="option" v-model:page="page" ref="crud" :table-loading="loading" @current-change="currentChange" @refresh-change="refreshChange" @on-load="onLoad" @search-change="searchChange" @size-change="sizeChange" v-if="activeTab === tab.name"> <template #job_info_num="{ row }"> <el-tooltip-copy :content="row.job_info_num" :showCopyText="true" textAlign="left"> {{ row.job_info_num }} </el-tooltip-copy> </template> <template #name="{ row }"> <el-tooltip-copy :content="row.name" :showCopyText="true" textAlign="left"> {{ row.name }} </el-tooltip-copy> </template> <template #menu-left> <el-button v-if="hasAddBtnPermission() && activeTab != 'WAIT_AUDIT'" type="primary" icon="el-icon-plus" @click="handleAdd">新建工单 </el-button> <el-button type="success" plain icon="el-icon-download" @click="exportData">导出 </el-button> </template> <template #menu="{ row }"> <div class="menu-custom-box"> <template v-if="row.status == 1"> <el-button v-if="hasPaddingBtnPermission()" type="text" icon="el-icon-view" @click="handleCheckDetail(row)">审核 </el-button> </template> <!-- v-if=" (userInfo.user_id == row.create_user || hasRecallPaddingBtnPermission()) && row.status == 1 " --> <template v-if="row.status == 1"> <!--待审核状态--> <el-button type="text" icon="el-icon-warning" v-if="hasRecallPaddingBtnPermission()" @click="orderLogRecall(row.id)">撤回 </el-button> <!-- <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情</el-button> --> </template> <!--已驳回--> <template v-if="row.status == 2"> <el-button type="text" icon="el-icon-warning" @click="rejectDetail(row.id)">驳回原因 </el-button> <el-button v-if="userInfo.user_id == row.create_user" type="text" icon="el-icon-view" @click="handleViewDetail(row)">编辑 </el-button> <el-button v-else type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情 </el-button> </template> <!-- 已通过 --> <template v-if="row.status == 3"> <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情 </el-button> </template> <!--草稿--> <template v-if="row.status == 0"> <el-button type="text" icon="el-icon-edit" @click="handleViewDetail(row)">编辑 </el-button> <el-button type="text" icon="el-icon-position" @click="userPublishPush(row.id)">发布 </el-button> <el-button type="text" icon="el-icon-delete" @click="deleteOrderLog(row.id)">删除 </el-button> </template> </div> </template> <template #status="{ row }"> <el-tag :type="getStatusTagType(row.status)">{{ mapStatus(row.status) }}</el-tag> </template> <template #keyData="{ row }"> <el-tooltip :content="row.address" placement="top" effect="light"> <span>{{ row.keyData }}</span> </el-tooltip> </template> </avue-crud> </basic-main-content> </el-tab-pane> </el-tabs> <!-- 新建工单对话框 --> <el-dialog class="ztzf-dialog-mange" v-model="dialogVisible" title="新建工单" width="70%" :close-on-click-modal="false" @close="resetForm"> <el-form :model="form" :rules="rules" ref="testform" label-width="100px"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单名称" prop="name"> <el-input v-model="form.name" placeholder="请输入工单名称" maxlength="100" show-word-limit></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="关联航线" prop="file_id"> <el-select v-model="form.file_id" placeholder="请选择航线" filterable @change="getFlyingNestBy"> <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" :value="item.wayline_id" /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="安全返航真高" prop="rth_altitude" class="safe-height"> <el-input-number v-model="form.rth_altitude" :min="50" :max="500"></el-input-number> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="关联机巢" prop="device_sns"> <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple :disabled="!device_sns.length"> <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname" :value="item.device_sn" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="关联算法" prop="ai_types"> <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple> <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单内容" prop="content"> <el-input type="textarea" v-model="form.content" rows="4" placeholder="请输入工单内容" maxlength="255" show-word-limit></el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="周期频次" prop="date_range"> <el-date-picker v-model="form.date_range" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :disabled-date="disabledDate" /> </el-form-item> </el-col> <el-col :span="4"> <div class="flex"> <div class="flex-1"> <el-select v-model="form.rep_fre_type" placeholder="请选择频次"> <el-option v-for="item in cycles" :key="item" :label="item" :value="item" /> </el-select> </div> <div class="flex-1"> <el-time-picker style="width: 100px" v-model="form.deal_time" prop="deal_time" value-format="HH:mm" :picker-options="{ selectableRange: '00:00 - 23:59', }" /> </div> </div> </el-col> </el-row> <el-row :gutter="20" style="height: 400px"> <el-col :span="24"> <map-container v-if="dialogVisible" ref="MapContainer"></map-container> </el-col> </el-row> <!-- <el-row>--> <!-- <div class="add-box-btns">--> <!-- <el-button type="danger" @click="submitForm(1)">发起</el-button>--> <!-- <el-button type="primary" @click="submitForm(0)">存草稿</el-button>--> <!-- <el-button @click="dialogVisible = false">取消</el-button>--> <!-- </div>--> <!-- </el-row>--> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="danger" @click="submitForm(1)" icon="el-icon-position">发起</el-button> <el-button type="primary" @click="submitForm(0)" icon="el-icon-document-add">存草稿</el-button> <el-button @click="dialogVisible = false" icon="el-icon-circle-close">取消</el-button> </div> </template> </el-dialog> <!-- 工单详情对话框 --> <el-dialog class="ztzf-dialog-mange" align-center v-model="detailVisible" :title="detailTitle" width="70%" :close-on-click-modal="false" @close="resetForm"> <div class="event-title-center">{{ form.name }}</div> <el-form :model="form" :rules="rules" ref="testform" label-width="100px"> <div class="custom-steps-container"> <!-- 标题行 --> <div class="steps-titles" v-if="filters.status !== '0'"> <div v-for="(record, index) in form.record_list" :class="{ active: record.user_id >= 0 }" :key="index" class="step-title"> {{ record.status_str }} </div> </div> <!-- Element Steps 组件 --> <el-steps :active="form.active" align-center class="custom-steps" v-if="filters.status !== '0'"> <el-step v-for="(record, index) in form.record_list" :key="index"> <template #description> <span class="step-description" style="position: relative; display: inline-block"> {{ record.user_name }} </span> <span class="step-timer"> {{ record.interval_time_str }} </span> <div class="step-description"> {{ record.create_time_str }} </div> </template> </el-step> </el-steps> </div> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单名称" prop="name"> <el-input v-model="form.name" placeholder="请输入工单名称" :disabled="detailTitle === '工单详情'"></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="关联航线" prop="file_id"> <el-select v-model="form.file_id" placeholder="请选择航线" @change="getFlyingNestBy" filterable :disabled="detailTitle === '工单详情'"> <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" :value="item.wayline_id" /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="安全返航真高" prop="rth_altitude" class="safe-height"> <el-input-number :disabled="detailTitle === '工单详情'" v-model="form.rth_altitude" :min="50" :max="500"></el-input-number> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="关联机巢" prop="device_sns"> <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple :disabled="detailTitle === '工单详情'"> <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname" :value="item.device_sn" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="关联算法" prop="ai_types"> <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple :disabled="detailTitle === '工单详情'"> <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12" prop="statusStr"> <el-form-item label="当前状态"> {{ mapStatus(form.status) }} </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="周期频次" prop="date_range"> <el-date-picker v-model="form.date_range" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :disabled-date="disabledDate" :disabled="detailTitle === '工单详情'" /> </el-form-item> </el-col> <el-col :span="3"> <el-select v-model="form.rep_fre_type" placeholder="请选择频次" :disabled="detailTitle === '工单详情'"> <el-option v-for="item in cycles" :key="item" :label="item" :value="item" /> </el-select> </el-col> <el-col :span="3"> <el-time-picker class="timeStyle" :style="{ width: pxToRem(140) }" v-model="form.deal_time" prop="deal_time" value-format="HH:mm" :picker-options="{ selectableRange: '00:00 - 23:59', }" :disabled="detailTitle === '工单详情'" /> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单内容" prop="content"> <el-input type="textarea" v-model="form.content" rows="4" placeholder="请输入工单内容" maxlength="255" show-word-limit :disabled="detailTitle === '工单详情'"></el-input> </el-form-item> </el-col> </el-row> <el-row :gutter="20" style="height: 400px"> <el-col :span="24"> <map-container v-if="detailVisible" ref="MapContainer"></map-container> </el-col> </el-row> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="danger" v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)" @click="submitForm(1)" icon="el-icon-position">发布 </el-button> <el-button type="primary" v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)" @click="submitForm(0)" icon="el-icon-plus">保存 </el-button> <!-- <el-button type="primary" v-if="form.status == 0 || userInfo.user_id == form.create_user" @click="submitForm(0)">保存</el-button> --> <el-button type="primary" v-if="form.status == 1 && hasPaddingBtnPermission()" @click="orderLogPass(form.id)">通过 </el-button> <el-button type="danger" v-if="form.status == 1 && hasRejectionBtnPermission()" @click="orderLogReject(form.id)">驳回 </el-button> </div> </template> </el-dialog> <!-- 工单详情 --> <el-dialog class="ztzf-dialog-mange" align-center v-model="detailVisibleCopy" title="工单详情" width="70%" :close-on-click-modal="false" @close="resetForm"> <div class="event-title-center">{{ form.name }}</div> <el-form :model="form" ref="testform" label-width="100px"> <div class="custom-steps-container"> <!-- 标题行 --> <div class="steps-titles" v-if="filters.status !== '0'"> <div v-for="(record, index) in form.record_list" :class="{ active: record.user_id >= 0 }" :key="index" class="step-title"> {{ record.status_str }} </div> </div> <!-- Element Steps 组件 --> <el-steps :active="form.active" align-center class="custom-steps" v-if="filters.status !== '0'"> <el-step v-for="(record, index) in form.record_list" :key="index"> <template #description> <span class="step-description" style="position: relative; display: inline-block"> {{ record.user_name }} </span> <span class="step-timer"> {{ record.interval_time_str }} </span> <div class="step-description"> {{ record.create_time_str }} </div> </template> </el-step> </el-steps> </div> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单名称" prop="name"> <el-input v-model="form.name" placeholder="请输入工单名称" :disabled="true"></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="关联航线" prop="file_id"> <el-select v-model="form.file_id" placeholder="请选择航线" :disabled="true"> <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" :value="item.wayline_id" /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="安全返航真高" prop="rth_altitude" class="safe-height"> <el-input-number :disabled="true" v-model="form.rth_altitude" :min="50" :max="500"></el-input-number> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="关联机巢" prop="device_sns"> <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple :disabled="true"> <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname" :value="item.device_sn" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="关联算法" prop="ai_types"> <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple :disabled="true"> <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12" prop="statusStr"> <el-form-item label="当前状态"> {{ mapStatus(form.status) }} </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="周期频次" prop="date_range"> <el-date-picker v-model="form.date_range" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :disabled="true" /> </el-form-item> </el-col> <el-col :span="3"> <el-select v-model="form.rep_fre_type" placeholder="请选择频次" :disabled="true"> <el-option v-for="item in cycles" :key="item" :label="item" :value="item" /> </el-select> </el-col> <el-col :span="3"> <el-time-picker style="width: 100px" v-model="form.deal_time" prop="deal_time" :disabled="true" value-format="HH:mm" :picker-options="{ selectableRange: '00:00 - 23:59', }" /> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="工单内容" prop="content"> <el-input type="textarea" v-model="form.content" rows="2" placeholder="请输入工单内容" maxlength="255" show-word-limit :readonly="true" :disabled="true"></el-input> </el-form-item> </el-col> </el-row> <el-row :gutter="20" style="height: 400px"> <el-col :span="24"> <map-container v-if="detailVisibleCopy" ref="MapContainer"></map-container> </el-col> </el-row> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="danger" v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)" @click="submitForm(1)" icon="el-icon-position">发布 </el-button> <!-- <el-button type="primary" v-if="form.status == 0 || userInfo.user_id == form.create_user" @click="submitForm(0)">保存</el-button> --> <el-button type="primary" v-if="form.status == 1 && hasPaddingBtnPermission()" @click="orderLogPass(form.id)" icon="el-icon-check">通过 </el-button> <el-button type="danger" v-if="form.status == 1 && hasRejectionBtnPermission()" @click="orderLogReject(form.id)" icon="el-icon-close">驳回 </el-button> <el-button @click="detailVisibleCopy = false" icon="el-icon-circle-close">取消</el-button> </div> </template> </el-dialog> </basic-container> </template> <script> import { pxToRem, pxToRemNum } from '@/utils/rem' import { calculateDefaultRange } from '@/utils/util' import { getList, saveUpdateOrderLog, orderLogDetails, orderLogRecall, orderLogReject, orderLogPass, orderLogExport, jobStatusNum, userPublish, deleteOrderLog, getWaylineMaxTerrainHeight } from '@/api/tickets/orderLog' import { getTicketInfo } from '@/api/tickets/ticket' import { getDictionaryByCode } from '@/api/system/dictbiz' import { getWaylineFileListByArea, newGetWorkspacesPage } from '@/api/resource/wayline' import { export_json_to_excel } from '@/utils/exportExcel' import { getFlyingNestBy } from '@/api/device/device' import { mapGetters } from 'vuex' import NProgress from 'nprogress' import { downloadXls } from '@/utils/util' import 'nprogress/nprogress.css' import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz' import dayjs from 'dayjs' import 'dayjs/locale/zh-cn' // 导入中文语言包 import weekday from 'dayjs/plugin/weekday' import elTooltipCopy from '@/components/ElTooltipCopy.vue' import { CircleClose, Promotion, Select } from '@element-plus/icons-vue' import { useStore } from 'vuex' import _ from 'lodash' // const store = useStore() dayjs.extend(weekday) dayjs.locale('zh-cn') // const lastHeight = computed(() => store.state.common.lastHeight) export default { components: { elTooltipCopy }, name: 'TicketPage', data () { return { activeTab: 'all', getlastHeight: 0, tabs: [ { label: '全部工单', name: 'all', value: null, count: 0 }, { label: '待审核', name: 'WAIT_AUDIT', value: 1, count: 0 }, { label: '已驳回', name: 'REJECTED', value: 2, count: 0 }, { label: '已通过', name: 'PASS', value: 3, count: 0 }, { label: '草稿', name: 'DRAFT', value: 0, count: 0 } ], filters: { key_word: '', create_dept: '', start_date: null, end_date: null, file_id: '', ai_types: [], status: '', dateRange: [] }, departments: [], types: [], device_sns: [], ai_types: [], wayLineList: [], detailTitle: '编辑工单', detailVisibleCopy: false, statuses: [ { label: '草稿', value: '0' }, { label: '待审核', value: '1' }, { label: '已驳回', value: '2' }, { label: '已通过', value: '3' } ], //周期 cycles: ['每天', '周一', '周二', '周三', '周四', '周五', '周六', '周末', '周天', '工作日'], tableData: [], option: { index: true, indexWidth: 66, indexLabel: '序号', indexFixed: true, align: 'left', border: true, stripe: false, searchShow: true, searchBtnText: '搜索', searchMenuSpan: 6, addBtnText: '新建工单', addBtn: false, viewBtn: false, editBtn: false, delBtn: false, cancelBtn: true, cancelBtnText: '取消', menu: true, menuWidth: 210, menuClassName: 'cur-menu', height: 'auto', calcHeight: 196, column: [ { label: '工单编号', prop: 'job_info_num', width: 150 }, { label: '工单名称', prop: 'name', width: 100, ellipsis: true, overHidden: true, showOverflowTooltip: true }, { label: '工单状态', prop: 'status', width: 88, showOverflowTooltip: true }, { label: '所属单位', prop: 'dept_name', ellipsis: true, showOverflowTooltip: true }, { label: '创建时间', prop: 'create_time', width: 144, ellipsis: true, showOverflowTooltip: true }, { label: '已执行次数', prop: 'job_num', width: 70, ellipsis: true, showOverflowTooltip: true }, { label: '工单内容', prop: 'content', ellipsis: true, overHidden: true, showOverflowTooltip: true }, { label: '关联航线', prop: 'wayline_name', ellipsis: true, overHidden: true, showOverflowTooltip: true }, { label: '关联算法', prop: 'ai_type_str', width: 100, ellipsis: true, overHidden: true, showOverflowTooltip: true }, { label: '关联机巢', prop: 'device_names', width: 100, ellipsis: true, overHidden: true, showOverflowTooltip: true }, { label: '创建人', prop: 'creator_name', width: 96, ellipsis: true, overHidden: true, showOverflowTooltip: true }, // { // label: '关联机巢', prop: 'device_names', width: 112, ellipsis: true, overHidden: true, // showOverflowTooltip: true, // }, { label: '工单周期频次', prop: '', width: 110, formatter: row => this.formatCycleTime(row), html: true, ellipsis: true, showOverflowTooltip: true // overHidden: true } ] }, page: { pageSize: 10, currentPage: 1, total: 0 }, dialogVisible: false, detailVisible: false, currentDetail: {}, form: {}, rules: { name: [ { required: true, message: '请输入工单名称', trigger: 'blur' }, { max: 100, message: '工单名称不能超过100个字', trigger: 'blur' } ], file_id: [{ required: true, message: '需要选择航线', trigger: 'change' }], device_sns: [{ required: true, message: '请选择机巢', trigger: 'change' }], content: [ { required: true, message: '请输入工单内容', trigger: 'blur' }, { max: 255, message: '工单内容不能超过255个字', trigger: 'blur' } ], date_range: [{ required: true, message: '请选择时间不能为空', trigger: 'blur' }], rep_fre_type: [{ required: true, message: '请选择周期', trigger: 'blur' }], deal_time: [{ required: true, message: '请选择执行时间', trigger: 'blur' }] }, loading: false, globalCounts: {}, mapLoaded: false, // 配置时间选择器默认配置 datePickerDefaultVal: calculateDefaultRange() } }, async created () { var response = await getDictionaryByCode('SF') var word_order_typeResponse = await getDictionaryByCode('WORK_ORDER_TYPE') this.ai_types = response.data.data['SF'] this.types = word_order_typeResponse.data.data['WORK_ORDER_TYPE'] //获取航线 this.asyncgetWaylineFileListByArea() const response2 = await getTicketInfo() const { dept_data, event_type, ai_type } = response2.data.data this.departments = dept_data.map(item => ({ label: item.dept_name, value: item.id })) }, mounted () { this.fetchTableData() const id = this.$route.query.id console.log('idddddd', id) if (id) { // 确保 id 存在 this.handleViewDetail({ id }) const find = this.$store.state.tags.bsTagList.find(i => i.path === '/tickets/orderLog') find && (find.query = {}) } else { console.error('工单ID不存在!') } }, computed: { CircleClose () { return CircleClose }, ...mapGetters(['userInfo', 'permission']), safeHeight () { const safeHeight = this.$store.state.common.safeHeight return Number(safeHeight) || 0 // 确保是数字类型 }, positionsArr () { const positionsArr = this.$store.state.common.positionsArr return positionsArr || [] // 确保是数字类型 }, filteredTabs () { // rejection_and_draft 权限控制“已驳回”和“草稿”tab // console.log(this.permission, '权限信息') // console.log(this.userInfo, '权限信息22') const canShowRejectAndDraft = this.permission?.rejection_and_draft === true return this.tabs .map(tab => { if (tab.name === 'DRAFT') { return { ...tab, isShow: canShowRejectAndDraft } } if (tab.name === 'REJECTED') { return { ...tab, isShow: canShowRejectAndDraft } } return { ...tab, isShow: true } }) .filter(tab => tab.isShow) } }, methods: { handleCellClick (row, column) { if (column.no === 1) { navigator.clipboard.writeText(row.job_info_num).then(() => { this.$message.success('复制工单编号成功') }) } else if (column.no === 2) { navigator.clipboard.writeText(row.name).then(() => { this.$message.success('复制工单名称成功') }) } else if (column.no === 4) { navigator.clipboard.writeText(row.dept_name).then(() => { this.$message.success('复制所属单位成功') }) } else if (column.no === 8) { navigator.clipboard.writeText(row.wayline_name).then(() => { this.$message.success('复制关联航线成功') }) } else if (column.no === 9) { navigator.clipboard.writeText(row.ai_type_str).then(() => { this.$message.success('复制关联算法成功') }) } }, disabledDate (time) { return time.getTime() < Date.now() - 8.64e7 // 86400000 = 24 * 60 * 60 * 1000 }, searchChange (params, done) { // console.log('searchChange') this.query = params this.parentId = '' this.page.currentPage = 1 this.onLoad(this.page, params) done() }, async onLoad (page, params = {}) { this.loading = true getList( null, this.page.currentPage, this.page.pageSize, Object.assign(params, this.query) ).then(res => { this.tableData = res.data.data this.loading = false this.selectionClear() }) }, selectionClear () { this.selectionList = [] this.$refs.crud.toggleSelection() }, async loadAMapScripts () { try { // await loadAMap(); // await loadAMapUI(); this.mapLoaded = true } catch (error) { console.error('Failed to load AMap scripts:', error) this.$message.error('地图加载失败,请检查网络或API Key配置') } }, formatCycleTime (row) { return `${row.cycle_time_value}` }, async fetchTableData () { this.loading = true try { let params = this.getQueryParam() // console.log('发送的参数:', params) const response = await getList(params, this.page.currentPage, this.page.pageSize) if (!response?.data?.data?.records) { throw new Error('接口返回数据格式不正确') } const { total, records } = response.data.data this.tableData = records.map(item => { return item }) // console.log('权限检查:', this.permission) this.page.total = total || 0 this.updateGlobalCounts() } catch (error) { // console.error('获取数据失败:', error) this.$message.error(error.message || '获取数据失败') this.tableData = [] this.page.total = 0 } finally { this.loading = false } }, getQueryParam () { const currentTab = this.tabs.find(tab => tab.name === this.activeTab) if (this.filters.dateRange) { // console.log( // 'this.formatDate(this.filters.dateRange[0])', // this.formatDate(this.filters.dateRange[0]) // ) } const params = { key_word: this.filters.key_word || undefined, create_dept: this.filters.create_dept || undefined, ai_types: this.filters.ai_types && this.filters.ai_types.length > 0 ? [this.filters.ai_types] : null, file_id: this.filters.file_id || undefined, status: this.filters.status !== '' ? Number(this.filters.status) : currentTab?.value, dept_id: this.filters.department || undefined, create_start_date: this.filters.dateRange?.[0] ? this.formatDate(this.filters.dateRange[0]) : undefined, create_end_date: this.filters.dateRange?.[1] ? this.formatDate(this.filters.dateRange[1]).replace('00:00:00', '23:59:59') : undefined, start_date: this.filters.cycleDateRange?.[0] ? this.formatDate(this.filters.cycleDateRange[0]) : undefined, end_date: this.filters.cycleDateRange?.[1] ? this.formatDate(this.filters.cycleDateRange[1]).replace('00:00:00', '23:59:59') : undefined, rep_fre_type: this.filters.rep_fre_type || undefined, deal_time: this.filters.deal_time || undefined, current: this.page.currentPage, size: this.page.pageSize } return params }, sizeChange (pageSize) { this.page.pageSize = pageSize }, async submitForm (status) { this.$refs.testform.validate(async valid => { if (valid) { let dateRange = this.form.date_range // console.log('dateRange' + dateRange) this.form.begin_time = this.formatDate(dateRange[0]) this.form.end_time = this.formatDate(dateRange[1]) // 如果选中日期包含当前天,那么选中的时间点不能小于当前时间 if (this.form.deal_time) { const selectedDate = dayjs(this.form.date_range[0]).format('YYYY-MM-DD') const selectedTime = dayjs(selectedDate + ' ' + this.form.deal_time).toDate() const now = new Date() if (selectedDate === dayjs().format('YYYY-MM-DD') && selectedTime < now) { return this.$message.warning('任务时间不能小于当前时间') } } let checkedList = this.device_sns.filter(item => this.form.device_sns.includes(item.device_sn)); const maxItem = checkedList.reduce((max, item) => { return item.drone_height > max.drone_height ? item : max; }); // 返航绝对高度 let backHeight = this.form.rth_altitude // + maxItem.drone_height console.log(backHeight,'backHeight') // 安全起飞高度 let positions = this.positionsArr positions.unshift({latitude: maxItem.latitude, longitude: maxItem.longitude, height:maxItem.drone_height }) positions.push({latitude: maxItem.latitude, longitude: maxItem.longitude, height:maxItem.drone_height}) let resultHeight = 0 await getWaylineMaxTerrainHeight(positions).then(res => { resultHeight = this.safeHeight > (res.data.data + 30) ? this.safeHeight : (res.data.data + 30) }) let valueHeight = _.round(backHeight - resultHeight, 2) console.log('打印比较值', valueHeight) if (valueHeight < 0) { this.$confirm(`当前返航高度存在安全隐患,建议调整为${resultHeight}米以上后进行发布`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(async () => { const submitData = { ...this.form, status: status, ai_types: this.form.ai_types?.length ? this.form.ai_types : [] } await saveUpdateOrderLog(submitData) let id = this.form.id if (id) { this.$message.success('工单发布成功') } else { this.$message.success('工单创建成功') } this.dialogVisible = false this.detailVisible = false; (this.device_sns = []), (this.wayLineList = []), this.fetchTableData() }).catch(() => { }) } else { const submitData = { ...this.form, status: status, ai_types: this.form.ai_types?.length ? this.form.ai_types : [] } await saveUpdateOrderLog(submitData) let id = this.form.id if (id) { this.$message.success('工单发布成功') } else { this.$message.success('工单创建成功') } this.dialogVisible = false this.detailVisible = false; (this.device_sns = []), (this.wayLineList = []), this.fetchTableData() } } }) }, //驳回原因显示 async rejectDetail (id) { const response = await orderLogDetails(id) let data = response.data.data this.$confirm(data.remark, '驳回原因', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.form = { ...response.data.data } // this.detailVisible = true this.handleViewDetail(data) }) }, 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` }, mapStatus (status) { const statusTextMap = { 0: '草稿', 1: '待审核', 2: '已驳回', 3: '已通过' } return statusTextMap[status] || '未知状态' }, getStatusTagType (status) { const statusMap = { 1: 'warning', 2: 'info', 3: 'primary', 4: 'success', 5: 'danger' } return statusMap[status] || 'info' }, handleTabChange (tab) { this.activeTab = tab.props?.name || tab.name this.filters.status = '' if (tab.props?.name === 'WAIT_AUDIT') { this.filters.status = '1' } else if (tab.props?.name === 'REJECTED') { this.filters.status = '2' } else if (tab.props?.name === 'PASS') { this.filters.status = '3' } else if (tab.props?.name === 'DRAFT') { this.filters.status = '0' } this.page.currentPage = 1 this.fetchTableData() }, handleSearch () { this.page.currentPage = 1 this.fetchTableData() }, handleReset () { this.filters = { keyword: '', department: '', type: '', dateRange: [], status: '' } this.page.currentPage = 1 this.fetchTableData() }, currentChange (currentPage) { this.page.currentPage = currentPage }, async updateGlobalCounts () { const counts = { all: 0, DRAFT: 0, WAIT_AUDIT: 0, REJECTED: 0, PASS: 0 } var reponse = await jobStatusNum() // console.log('统计' + reponse.data.data) reponse.data.data.forEach(item => { const tab = this.tabs.find(t => t.name === item.dict_key) if (tab) { tab.count = item.num } }) }, handleAdd () { this.form = {} this.form.rth_altitude = 120 this.dialogVisible = true this.$nextTick(() => { if (this.$refs.MapContainer && this.$refs.MapContainer.initAddEntity) { this.$refs.MapContainer.initAddEntity('initPosition') } }) //航线列表 this.asyncgetWaylineFileListByArea() }, resetForm () { this.form = { name: '', type: '', handler: '', algorithm: '', location: '', address: '', content: '', photos: [] } if (this.$refs.testform) { this.$refs.testform.resetFields() } }, formatLocation (location) { if (!Array.isArray(location)) { return '未知位置' } return `${location[0].toFixed(6)}, ${location[1].toFixed(6)}` }, async handleViewDetail (row) { const response = await orderLogDetails(row.id) const data = response.data.data this.form = { ...data } // 更新机巢列表 this.device_sns = data.device_map_infos;// data.device_list; this.permission && (this.permission.order_log_review || this.permission.order_log_recall) && (data.status == 1 || data.status == 3 || (data.status == 2 && this.userInfo.user_id !== this.form.create_user)) ? (this.detailTitle = '工单详情') : (this.detailTitle = '编辑工单') this.detailVisible = true // 更新航线列表,追加 wayline_file_region_vo 数据 if (data.wayline_file_region_vo) { const newWayline = data.wayline_file_region_vo // 检查是否已经存在于 this.wayLineList 中 const isDuplicate = this.wayLineList.some( item => item.wayline_id === newWayline.wayline_id ) if (!isDuplicate) { this.wayLineList.push(newWayline) } } this.initMapLine(data.device_map_infos) const find = this.$store.state.tags.bsTagList.find(i => i.path === '/tickets/orderLog') find && (find.query = {}) }, async handleCheckDetail (row) { const response = await orderLogDetails(row.id) const data = response.data.data this.form = { ...data } // 更新航线列表,追加 wayline_file_region_vo 数据 // 更新航线列表,追加 wayline_file_region_vo 数据 if (data.wayline_file_region_vo) { const newWayline = data.wayline_file_region_vo // 检查是否已经存在于 this.wayLineList 中 const isDuplicate = this.wayLineList.some( item => item.wayline_id === newWayline.wayline_id ) if (!isDuplicate) { this.wayLineList.push(newWayline) } } // 更新机巢列表 this.device_sns = data.device_list this.detailVisibleCopy = true this.initMapLine(data.device_map_infos) }, //导出 async exportData () { this.$confirm('是否智飞工单数据?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { NProgress.start() let params = this.getQueryParam() orderLogExport(params).then(res => { downloadXls(res.data, `智飞工单${this.$dayjs().format('YYYY-MM-DD')}.xlsx`) NProgress.done() }) }) }, hasAddBtnPermission () { // undefined 或 false 都返回 false,只有 true 返回 true // console.log('this.permission.order_log_add :', this.permission.order_log_add) return this.permission && this.permission.order_log_add === true }, hasPaddingBtnPermission () { // undefined 或 false 都返回 false,只有 true 返回 true // console.log('权限检查:', this.permission) return this.permission && this.permission.order_log_review === true }, hasRecallPaddingBtnPermission () { // undefined 或 false 都返回 false,只有 true 返回 true // console.log('权限检查:', this.permission) // 智飞工单撤回 return this.permission && this.permission.order_log_recall === true }, //驳回按钮权限 hasRejectionBtnPermission () { // undefined 或 false 都返回 false,只有 true 返回 true // console.log('权限检查:', this.permission) return this.permission && this.permission.rejection_btn === true }, //自己点发布 userPublishPush (id) { this.$confirm('确定发布吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { let response = userPublish(id) this.$message.success('发布成功') this.fetchTableData() }) }, //删除 deleteOrderLog (id) { this.$confirm('确定删除吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { let response = deleteOrderLog(id) this.$message.success('删除') this.fetchTableData() }) }, refreshChange () { this.fetchTableData() }, //获取航线列表 async asyncgetWaylineFileListByArea (name) { const formData = { name: '', waylineType: undefined, current: 1, size: 99999999, descs: 'update_time' } var wayLineListResponse = await newGetWorkspacesPage(formData) this.wayLineList = wayLineListResponse.data.data.records this.initMapLine() }, initMapLine (infos = {}, cb = () => { }) { let currentLine = this.wayLineList.find(item => item.wayline_id == this.form.file_id) if (!currentLine) return this.$nextTick(() => { if (this.$refs.MapContainer && this.$refs.MapContainer.initAddEntity) { this.$refs.MapContainer.initAddEntity('polyline', { url: `${import.meta.env.VITE_APP_AIRLINE_URL + currentLine.object_key }?_t=${new Date().getTime()}`, type: currentLine.wayline_type, cb, infos }) } }) }, //可飞行机巢列表 async getFlyingNestBy (waylineId) { const that = this // 先清空 that.form.device_sns = [] that.device_sns = [] this.initMapLine({}, async polygon => { const currentLine = that.wayLineList.find(item => item.wayline_id === waylineId) //按照航线来 const params = { type: ['2', '4', '5'].includes(currentLine.wayline_type) ? 2 : 0, wayline_id: waylineId, polygon } var wayLineListResponse = await getFlyingNestBy(params) // 再赋值 that.device_sns = wayLineListResponse.data.data }) }, //撤回 async orderLogRecall (id) { this.$confirm('确定撤回则到草稿箱。', '是否撤回?', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(async () => { let reposne = await orderLogRecall(id) this.handleSearch() }) }, onLoad () { this.fetchTableData() }, /** * 通过 */ async orderLogPass (id) { let response = await orderLogPass(id) let data = response.data.data this.$message.success('审核通过') this.detailVisibleCopy = false this.detailVisible = false this.page.currentPage = 1 this.onLoad(this.page, this.query) // this.handleViewDetail() }, /** * 驳回 */ async orderLogReject (id) { this.$prompt('', '驳回原因', { confirmButtonText: '确定', cancelButtonText: '取消' }).then(async ({ value }) => { let response = await orderLogReject(id, value) let data = response.data.data this.$message.success('驳回成功') this.detailVisibleCopy = false // this.detailVisible = false this.page.currentPage = 1 this.onLoad(this.page, this.query) }) } }, watch: { // lastHeight(newVal, oldVal) { // console.log('lastHeight', newVal, oldVal); // this.getlastHeight = newVal; // }, tableData: { handler () { // this.updateTabCounts() }, deep: true } } } </script> <style lang="scss" scoped> //:deep(.el-input-number) { // width: 200px; //} //:deep(.el-form-item__label) { // width: 100px !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 { // align-items: center; .search-bar-box { margin-bottom: 15px; display: flex; justify-content: space-between; gap: 8px; &-item { flex: 1; &> ::v-deep(.el-date-editor) { width: 100%; box-sizing: border-box; } } .search-btn { flex: 1; display: flex; justify-content: flex-end; } .flex-2 { min-width: 454px; } } } :deep(.el-pagination .el-select) { width: 128px !important; } .step-timer { position: absolute; left: 80%; top: 50%; transform: translateY(-50%); width: 100px; margin-left: 4px; color: #666; font-size: 12px; } :deep(.el-textarea__inner) { padding: 8px 12px; } :deep(.el-input__inner), :deep(.el-select), :deep(.el-select .el-input) { width: 100%; // 确保所有输入框和选择框宽度一致 } :deep(.el-textarea__inner) { resize: none; } .action-bar { margin-bottom: 16px; } .el-tabs { :deep(.el-tabs__content) { overflow: visible; } } .el-dialog { .el-form-item { margin-bottom: 10px; } } .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: 7px; } .custom-steps-container { width: 100%; margin: 20px 0; } .steps-titles { display: flex; justify-content: space-between; margin-bottom: 16px; position: relative; } .step-title { text-align: center; flex: 1; font-size: 16px; color: #999; position: relative; padding-bottom: 10px; } .step-title.active { color: #409eff; font-weight: bold; } .custom-steps { margin-top: -20px; /* 向上移动与标题重叠 */ } .el-step__head { margin-top: 0; } .el-step__description { margin-top: 8px; padding: 0 20px; } .step-description { font-size: 14px; color: #666; line-height: 1.5; } .event-title-center { text-align: center; font-size: 20px; font-weight: bold; margin-bottom: 12px; color: #333; } .cur-menu { .menu-custom-box { display: flex; justify-content: center; flex-wrap: wrap; &> ::v-deep(.el-button) { flex: 1; margin-left: 0; margin-right: 10px; } } } .add-box-btns { width: 100%; display: flex; justify-content: center; } .safe-height { :deep(.el-form-item__label) { width: 120px !important; } :deep(.el-input-number) { width: 180px !important; } } .flex { display: flex; } .flex-1 { flex: 1; &> ::v-deep(div) { width: 100% !important; } } </style>