无人机管理后台前端(已迁走)
xiebin
2025-04-24 142878cdca997ab014d8ce98f9d8d617087191f6
Merge branch 'test' into prod
3 files modified
325 ■■■■ changed files
src/api/device-setting/index.js 4 ●●●● patch | view | raw | blame | history
src/views/tickets/orderLog.vue 87 ●●●● patch | view | raw | blame | history
src/views/tickets/ticket.vue 234 ●●●● patch | view | raw | blame | history
src/api/device-setting/index.js
@@ -27,12 +27,12 @@
 * @param {*} body 
 * @returns 
 */
export const setThermalCurrentPaletteStyle = (deviceSn, workspaceId, body) => {
export const setThermalCurrentPaletteStyle = (deviceSn, workspaceId, param) => {
  return request({
    // /manage/api/v1/devices/selectDevicePage
    // url: `/localApi/manage/api/v1/devices/${workspaceId}/devices/${deviceSn}/setThermalCurrentPaletteStyle`,
    url: `/drone-device-core/manage/api/v1/devices/${workspaceId}/devices/${deviceSn}/setThermalCurrentPaletteStyle`,
    method: 'put',
    body,
    data: param,
  })
}
src/views/tickets/orderLog.vue
@@ -125,7 +125,7 @@
                <el-row :gutter="20">
                    <el-col :span="12">
                        <el-form-item label="工单名称" prop="name">
                            <el-input v-model="form.name" placeholder="请输入工单名称"></el-input>
                            <el-input v-model="form.name" placeholder="请输入工单名称"  maxlength="100" show-word-limit></el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
@@ -140,9 +140,14 @@
                <el-row :gutter="20">
                    <el-col :span="12">
                        <el-form-item label="关联机巢" prop="device_sns">
                            <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple>
                                <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname"
                                    :value="item.device_sn" />
                                <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>
@@ -159,7 +164,14 @@
                <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="请输入工单内容"></el-input>
                            <el-input
                                type="textarea"
                                v-model="form.content"
                                rows="4"
                                placeholder="请输入工单内容"
                                maxlength="255"
                                show-word-limit
                            ></el-input>
                        </el-form-item>
                    </el-col>
@@ -197,7 +209,8 @@
        </el-dialog>
        <!-- 工单详情对话框 -->
        <el-dialog v-model="detailVisible" title="编辑工单" width="70%" :close-on-click-modal="false" @close="resetForm" >
        <el-dialog 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" ref="testform" label-width="100px">
                <div class="custom-steps-container">
                    <!-- 标题行 -->
@@ -255,8 +268,12 @@
                    <el-col :span="12">
                        <el-form-item label="关联机巢" prop="device_sns">
                            <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple>
                                <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname"
                                    :value="item.device_sn" />
                                <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>
@@ -273,7 +290,14 @@
                <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="请输入工单内容"></el-input>
                            <el-input
                                type="textarea"
                                v-model="form.content"
                                rows="4"
                                placeholder="请输入工单内容"
                                maxlength="255"
                                show-word-limit
                            ></el-input>
                        </el-form-item>
                    </el-col>
@@ -287,8 +311,8 @@
                        <el-button type="danger"
                            v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)"
                            @click="submitForm(1)">发布</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 == 0 || userInfo.user_id == form.create_user"
                            @click="submitForm(0)">保存</el-button> -->
                        <el-button type="primary" v-if="form.status == 1 && this.permission.orderLogpass"
                            @click="orderLogPass(form.id)">通过</el-button>
@@ -373,6 +397,7 @@
            device_sns: [],
            ai_types: [],
            wayLineList: [],
            detailTitle:"编辑工单",
            statuses: [
                { label: '草稿', value: '0' },
@@ -437,11 +462,16 @@
            currentDetail: {},
            form: {},
            rules: {
                name: [{ required: true, message: '请输入工单名称', trigger: 'blur' }],
                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' }],
                ai_types: [{ required: true, message: '请选择算法', trigger: 'change' }],
                content: [{ required: true, message: '请输入工单内容', trigger: 'blur' }],
                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' }],
@@ -751,15 +781,21 @@
            return `${location[0].toFixed(6)}, ${location[1].toFixed(6)}`
        },
        async handleViewDetail(row) {
            const response = await orderLogDetails(row.id)
            this.form = {
                ...response.data.data,
            }
            this.detailVisible = true
             console.log("工单名称1111:");
            const response = await orderLogDetails(row.id);
            const data = response.data.data;
            //航线列表
            this.asyncgetWaylineFileListByArea()
            this.device_sns = response.data.data.deviceList
            this.form = {
                ...data,
            };
            this.detailVisible = true;
            // 更新机巢列表
            this.device_sns = 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.detailTitle="工单详情":this.detailTitle="编辑工单";
          console.log("工单名称:"+this.detailTitle);
        },
        //导出
        async exportData() {
@@ -1061,4 +1097,13 @@
    color: #666;
    line-height: 1.5;
}
</style>
.event-title-center {
  text-align: center;
  font-size: 20px;
  font-weight: bold;
  margin-bottom: 12px;
  color: #333;
}
</style>
`
src/views/tickets/ticket.vue
@@ -131,13 +131,22 @@
            </el-col>
            <el-col :span="12">
              <el-form-item label="附件图片" prop="photos" required class="upload-wrapper">
                <el-upload ref="upload" :action="'#'" :auto-upload="false" list-type="picture-card"
                  :on-change="handleFileChange" :on-remove="handleUploadRemove" :before-upload="beforeUpload"
                  :file-list="form.photos" :limit="1" accept="image/*" class="uploader">
                  <span
                    style="font-size: 32px; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">+</span>
                <el-upload ref="upload"
                  :action="'#'"
                  :auto-upload="false"
                  list-type="picture-card"
                  :on-change="handleFileChange"
                  :on-remove="handleUploadRemove"
                  :before-upload="beforeUpload"
                  :file-list="form.photos"
                  :limit="1"
                  accept="image/*"
                  class="create-upload">
                  <template v-if="form.photos.length < 1">
                    <i class="el-icon-plus">+</i>
                  </template>
                </el-upload>
                <div class="upload-tip">支持jpg/png格式图片,单张不超过5MB</div>
                <div class="upload-tip">需上传含有地址信息的照片(jpg、jpeg、png),且不超过5M</div>
              </el-form-item>
            </el-col>
          </el-row>
@@ -213,41 +222,42 @@
        <!-- 基本信息表格 -->
        <el-table :show-header="false" :data="formattedDetailFields" border style="width: 100%; margin-bottom: 20px;">
          <el-table-column prop="label1" label="基本信息" width="150" />
          <el-table-column prop="label1" label="基本信息" width="150">
            <template #default="{ row }">
              <!-- 添加必填星号的标签 -->
              <span v-if="currentDetail.status === 0 && row.label1 === '工单名称'" class="required-label">
                <span class="required-star">*</span>{{ row.label1 }}
              </span>
              <span v-else>{{ row.label1 }}</span>
            </template>
          </el-table-column>
          <el-table-column>
            <template #default="{ row }">
              <!-- 修复工单名称可编辑 -->
              <template v-if="currentDetail.status === 0 && row.label1 === '工单名称' && hasProcessingBtnPermission()">
                <el-input v-model="currentDetail.orderName" placeholder="请输入工单名称" />
              </template>
              <!-- 修复任务接收单位为下拉框 -->
              <template v-else-if="currentDetail.status === 0 && row.label1 === '发起单位'">
                <el-select v-model="currentDetail.department" placeholder="请选择任务接收单位" @change="handleDepartmentChange">
                  <el-option v-for="item in departments" :key="item.value" :label="item.label" :value="item.value" />
                </el-select>
                <el-input v-model="currentDetail.orderName" placeholder="请输入工单名称" class="required-input" />
              </template>
              <template v-else>{{ row.value1 }}</template>
            </template>
          </el-table-column>
          <el-table-column prop="label2" label="基本信息" width="150" />
          <el-table-column prop="label2" label="基本信息" width="150">
            <template #default="{ row }">
              <!-- 添加必填星号的标签 -->
              <span v-if="currentDetail.status === 0 && (row.label2 === '工单类型' || row.label2 === '工单内容')" class="required-label">
                <span class="required-star">*</span>{{ row.label2 }}
              </span>
              <span v-else>{{ row.label2 }}</span>
            </template>
          </el-table-column>
          <el-table-column>
            <template #default="{ row }">
              <!-- 修复工单内容可编辑 -->
              <template v-if="currentDetail.status === 0 && row.label2 === '工单内容' && hasProcessingBtnPermission()">
                <el-input type="textarea" v-model="currentDetail.content" placeholder="请输入工单内容" />
              </template>
              <!-- 修复工单类型为下拉框 -->
              <template v-else-if="currentDetail.status === 0 && row.label2 === '工单类型' && hasProcessingBtnPermission()">
                <el-select v-model="currentDetail.type" placeholder="请选择工单类型">
              <!-- 修改工单类型和工单内容的显示 -->
              <template v-if="currentDetail.status === 0 && row.label2 === '工单类型' && hasProcessingBtnPermission()">
                <el-select v-model="currentDetail.type" placeholder="请选择工单类型" class="required-input">
                  <el-option v-for="item in types" :key="item.value" :label="item.label" :value="item.value" />
                </el-select>
              </template>
              <!-- 修复任务处理人为下拉框 -->
              <template v-else-if="currentDetail.status === 0 && row.label2 === '任务处理人'">
                <el-select v-model="currentDetail.handler" placeholder="请选择任务处理人" @change="handleHandlerChange">
                  <el-option v-for="user in departmentUsers[currentDetail.department] || []" :key="user.id"
                    :label="user.name" :value="user.id" />
                </el-select>
              <template v-else-if="currentDetail.status === 0 && row.label2 === '工单内容' && hasProcessingBtnPermission()">
                <el-input type="textarea" v-model="currentDetail.content" placeholder="请输入工单内容" class="required-input" />
              </template>
              <template v-else>{{ row.value2 }}</template>
            </template>
@@ -256,7 +266,17 @@
        <!-- 事件处理详情 -->
        <div v-if="[3, 4, 5].includes(currentDetail.status)" class="form-section">
          <div class="section-title">事件处理详情</div>
          <div class="section-title">
            <!-- 处理中状态显示必填星号 -->
            <template v-if="currentDetail.status === 3">
              <span class="required-label">
                <span class="required-star">*</span>事件处理详情
              </span>
            </template>
            <template v-else>
              事件处理详情
            </template>
          </div>
          <!-- 处理中状态显示输入框 -->
          <template v-if="currentDetail.status === 3 && hasProcessedAndOverBtnPermission()">
            <el-input type="textarea" v-model="currentDetail.processingDetail" placeholder="请输入事件处理详情" :rows="4"
@@ -272,17 +292,38 @@
        <!-- 上传图片 -->
        <div v-if="[3, 4].includes(currentDetail.status)" class="form-section" style="margin-bottom: 32px;">
          <div class="section-title" v-if="hasProcessedAndOverBtnPermission()">上传图片</div>
          <el-upload v-if="hasProcessedAndOverBtnPermission()" ref="upload" :action="'#'" :auto-upload="false"
            list-type="picture-card" :on-change="handleFileChange" :on-remove="handleUploadRemove"
            :before-upload="beforeUpload" :file-list="[]" :limit="1" accept="image/*">
            <span
              style="font-size: 32px; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">+</span>
          <div class="section-title" v-if="hasProcessedAndOverBtnPermission()">
            <!-- 已完成状态显示必填星号 -->
            <template v-if="currentDetail.status === 4">
              <span class="required-label">
                <span class="required-star">*</span>上传图片
              </span>
            </template>
            <template v-else>
              上传图片
            </template>
          </div>
          <el-upload v-if="hasProcessedAndOverBtnPermission()"
            ref="upload"
            :action="'#'"
            :auto-upload="false"
            list-type="picture-card"
            :on-change="handleFileChange"
            :on-remove="handleUploadRemove"
            :before-upload="beforeUpload"
            :file-list="currentDetail.photos || []"
            :limit="1"
            accept="image/*"
            class="detail-upload">
            <template v-if="!currentDetail.photos || currentDetail.photos.length < 1">
              <i class="el-icon-plus">+</i>
            </template>
          </el-upload>
          <div class="el-upload__tip" style="margin-top: 12px;" v-if="hasProcessedAndOverBtnPermission()">
            支持 jpg/png 格式图片,单张不超过 5MB
            (上传照片即可完结工单,只能上传jpg、jpeg、png照片,且不超过5M)
          </div>
        </div>
        <!-- 图片和地图部分 -->
        <div class="media-section">
          <el-row :gutter="20">
@@ -291,7 +332,7 @@
                <div class="media-title">事件图片</div>
                <div class="media-content">
                  <el-image v-if="currentDetail.mediaUrl" :src="getThumbUrl(currentDetail.mediaUrl)"
                    :preview-src-list="[currentDetail.mediaUrl]" fit="contain"
                    :preview-src-list="[getPreviewUrl(currentDetail.mediaUrl)]" fit="contain"
                    style="width: 700px; height: 520px; cursor: pointer;">
                    <template #placeholder>
                      <div class="image-placeholder">
@@ -317,7 +358,7 @@
                  <div class="media-title">工单处理图片</div>
                  <div class="media-content">
                    <el-image v-if="currentDetail.updatePhotoUrl" :src="getThumbUrl(currentDetail.updatePhotoUrl)"
                      :preview-src-list="[currentDetail.updatePhotoUrl]" fit="fill"
                      :preview-src-list="[getPreviewUrl(currentDetail.updatePhotoUrl)]" fit="fill"
                      style="width: 700px; height: 520px; cursor: pointer;">
                      <template #placeholder>
                        <div class="image-placeholder">
@@ -524,7 +565,7 @@
        column: [
          // { label: "序号", prop: "id", width: 70 },
          { label: "工单编号", prop: "orderNumber", width: 150 },
          { label: "工单名称", prop: "orderName", width: 150 },
          { label: "工单名称", prop: "orderName", width: 170, overHidden: true, tooltip: true },
          { label: "所属单位", prop: "department", width: 100 },
          { label: "发起时间", prop: "startTime", width: 160 },
          { label: "关联算法", prop: "aiType", width: 160 },
@@ -722,7 +763,7 @@
      const fields = [
        { label: "工单名称", value: this.currentDetail.orderName },
        { label: "工单类型", value: this.currentDetail.type },
        { label: "关联任务", value: this.currentDetail.job_name || '暂无关联航线' },
        { label: "关联任务", value: this.currentDetail.job_name || '/' },
        { label: "任务发起人", value: this.currentDetail.creator },
        { label: "当前状态", value: this.mapStatus(this.currentDetail.status) },
        { label: "事件地址", value: this.currentDetail.address }, // 包含经纬度信息
@@ -847,7 +888,6 @@
          isPass: 0,
          eventNum: currentItem.orderNumber,
          eventName: currentItem.orderName,
          eventType: currentItem.type,
        };
        const response = await flowEvent(data);
@@ -1533,10 +1573,6 @@
          status: this.currentDetail.status,
          isPass: 0, // 0 表示通过
          eventNum: this.currentDetail.orderNumber,
          eventName: this.currentDetail.orderName, // 工单名称
          eventType: this.currentDetail.type, // 工单类型
          departmentId: this.dispatchForm.department, // 派发部门 ID
          handlerId: this.dispatchForm.handler, // 处理人 ID
        };
        const file = this.currentDetail.file || null; // 如果没有文件,则为 null
@@ -1649,8 +1685,23 @@
    },
    async approveAndDispatch() {
      if (this.dispatchLoading) return;
      // this.dispatchLoading = true;
      this.dispatchDialogVisible = true; // 打开派发对话框
      // 添加必填项检查
      if (!this.currentDetail.orderName || !this.currentDetail.orderName.trim()) {
        this.$message.warning('请填写工单名称');
        return;
      }
      if (!this.currentDetail.type) {
        this.$message.warning('请选择工单类型');
        return;
      }
      if (!this.currentDetail.content || !this.currentDetail.content.trim()) {
        this.$message.warning('请填写工单内容');
        return;
      }
      // 通过验证后,打开派发对话框
      this.dispatchDialogVisible = true;
    },
    hasProcessingBtnPermission() {
      // undefined 或 false 都返回 false,只有 true 返回 true
@@ -1965,7 +2016,6 @@
          status: currentItem.status,
          isPass: 0,
          eventNum: currentItem.orderNumber,
          eventName: currentItem.orderName,
        };
        console.log('删除前:', this.selections)
        const response = await flowEvent(data);
@@ -2073,7 +2123,7 @@
    // 获取所有图片列表用于预览
    getImageList() {
      return this.selections
        .map(item => item.photo_url)
        .map(item => this.getPreviewUrl(item.photo_url))
        .filter(url => url); // 过滤掉空值
    },
@@ -2108,6 +2158,14 @@
      const lastDot = url.lastIndexOf('.');
      if (lastDot === -1) return url;
      return url.slice(0, lastDot) + '_small' + url.slice(lastDot);
    },
    // 添加新方法:获取预览图地址
    getPreviewUrl(url) {
      if (!url) return '';
      const lastDot = url.lastIndexOf('.');
      if (lastDot === -1) return url;
      return url.slice(0, lastDot) + '_show' + url.slice(lastDot);
    },
  },
};
@@ -2489,6 +2547,10 @@
  margin-bottom: 8px;
}
.no-media {
  border: 1px dashed #d9d9d9;
}
.info-table {
  margin-bottom: 20px;
}
@@ -2729,4 +2791,76 @@
    }
  }
}
/* 新建工单和处理工单的上传组件样式 */
.create-upload,
.detail-upload {
  :deep(.el-upload--picture-card) {
    width: 120px;
    height: 100px;
    line-height: 100px;
  }
  /* 隐藏额外的上传按钮 */
  :deep(.el-upload.el-upload--picture-card) {
    display: none;
  }
  /* 当没有图片时显示上传按钮 */
  :deep(.el-upload.el-upload--picture-card:first-child) {
    display: flex;
  }
  /* 上传组件的预览图片样式 */
  :deep(.el-upload-list--picture-card .el-upload-list__item) {
    width: 120px;
    height: 100px;
  }
}
/* 事件图片和处理图片的预览样式 */
.media-content {
  :deep(.el-image) {
    width: 700px !important;
    height: 520px !important;
    .el-image__inner {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
  }
}
/* 原有图片预览的样式 */
.el-image-viewer__wrapper {
  :deep(.el-image-viewer__img) {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
  }
}
/* 必填项样式 */
.required-label {
  position: relative;
  display: inline-block;
  .required-star {
    color: #F56C6C;
    margin-right: 4px;
  }
}
/* 必填输入框样式 */
.required-input {
  width: 100%;
  :deep(.el-input__inner),
  :deep(.el-textarea__inner) {
    &:focus {
      border-color: #409EFF;
    }
  }
}
</style>