无人机管理后台前端(已迁走)
shuishen
2025-04-10 126bde584b7a925650df0183325cff5094bd8ac3
示例---获取当前登录账号行政区划对应对象
1 files modified
418 ■■■■■ changed files
src/views/tickets/orderLog.vue 418 ●●●●● patch | view | raw | blame | history
src/views/tickets/orderLog.vue
@@ -5,112 +5,45 @@
        <div class="tab-content">
          <!-- 查询条件筛选栏 -->
          <div class="filter-bar">
            <el-input
              v-model="filters.key_word"
              placeholder="输入工单编号/名称/内容/姓名"
              class="filter-item"
              clearable
              @keyup.enter="handleSearch"
            />
            <el-select
              v-model="filters.create_dept"
              placeholder="请选择所属单位"
              class="filter-item"
              clearable
            >
                <el-option
                v-for="item in departments"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              />
              <el-date-picker
              v-model="filters.dateRange"
              type="daterange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              class="date-picker"
              value-format="yyyy-MM-dd"
            />
                        <el-input v-model="filters.key_word" placeholder="输入工单编号/名称/内容/姓名" class="filter-item" clearable
                            @keyup.enter="handleSearch" />
                        <el-select v-model="filters.create_dept" placeholder="请选择所属单位" class="filter-item" clearable>
                            <el-option v-for="item in departments" :key="item.value" :label="item.label"
                                :value="item.value" />
                            <el-date-picker v-model="filters.dateRange" type="daterange" range-separator="至"
                                start-placeholder="开始日期" end-placeholder="结束日期" class="date-picker"
                                value-format="yyyy-MM-dd" />
          
            </el-select>
               <el-select
              v-model="filters.ai_types"
              placeholder="关联算法"
              class="filter-item"
              clearable
            >
              <el-option
                v-for="item in ai_types"
                :key="item.dictKey"
                :label="item.dictValue"
                :value="item.dictKey"
              />
                        <el-select v-model="filters.ai_types" placeholder="关联算法" class="filter-item" clearable>
                            <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue"
                                :value="item.dictKey" />
            </el-select>
            <el-select
              v-model="filters.type"
              placeholder="请选择工单类型"
              class="filter-item"
              clearable
            >
              <el-option
                v-for="item in types"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              />
                        <el-select v-model="filters.type" placeholder="请选择工单类型" class="filter-item" clearable>
                            <el-option v-for="item in types" :key="item.value" :label="item.label"
                                :value="item.value" />
            </el-select>
          
            <el-select
              v-model="filters.status"
              placeholder="请选择工单状态"
              class="filter-item"
              clearable
            >
              <el-option
                v-for="item in statuses"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              />
                        <el-select v-model="filters.status" placeholder="请选择工单状态" class="filter-item" clearable>
                            <el-option v-for="item in statuses" :key="item.value" :label="item.label"
                                :value="item.value" />
            </el-select>
            <el-button type="primary" icon="el-icon-search" @click="handleSearch">查询</el-button>
            <el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
          </div>
          <!-- 表格部分 -->
          <avue-crud
            :data="tableData"
            :option="option"
            :page.sync="pagination"
            :table-loading="loading"
            @current-change="handlePaginationChange"
            @size-change="handlePaginationChange"
            @refresh-change="refreshChange"
            @on-load="onLoad"
          >
                    <avue-crud :data="tableData" :option="option" :page.sync="pagination" :table-loading="loading"
                        @current-change="handlePaginationChange" @size-change="handlePaginationChange"
                        @refresh-change="refreshChange" @on-load="onLoad">
            <template #menu-left>
              <el-button
                type="primary"
                icon="el-icon-plus"
                @click="handleAdd"
              >新建工单</el-button>
              <el-button
                type="success"
                plain
                icon="el-icon-download"
                @click="exportData"
              >导出</el-button>
                            <el-button 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 }">
              <el-button
                type="text"
                icon="el-icon-view"
                @click="handleViewDetail(row)"
              >详情</el-button>
                            <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情</el-button>
            </template>
            <template #status="{ row }">
              <el-tag :type="getStatusTagType(row.status)">{{ mapStatus(row.status) }}</el-tag>
@@ -137,7 +70,8 @@
          <el-col :span="12">
            <el-form-item label="工单类型" prop="type">
              <el-select v-model="form.type" placeholder="请选择工单类型">
                <el-option v-for="item in types" :key="item.value" :label="item.label" :value="item.value" />
                                <el-option v-for="item in types" :key="item.value" :label="item.label"
                                    :value="item.value" />
              </el-select>
            </el-form-item>
          </el-col>
@@ -146,14 +80,16 @@
          <el-col :span="12">
            <el-form-item label="处理人员" prop="handler">
              <el-select v-model="form.handler" placeholder="请选择处理人员">
                <el-option v-for="item in handlers" :key="item.value" :label="item.label" :value="item.value" />
                                <el-option v-for="item in handlers" :key="item.value" :label="item.label"
                                    :value="item.value" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="关联算法" prop="algorithm">
              <el-select v-model="form.algorithm" placeholder="请选择关联算法">
                <el-option v-for="item in algorithms" :key="item.value" :label="item.label" :value="item.value" />
                                <el-option v-for="item in algorithms" :key="item.value" :label="item.label"
                                    :value="item.value" />
              </el-select>
            </el-form-item>
          </el-col>
@@ -178,19 +114,10 @@
        <el-row :gutter="20">
          <el-col :span="24">
            <el-form-item label="上传图片">
              <el-upload
                action="/api/upload"
                list-type="picture-card"
                :on-preview="handleUploadPreview"
                :on-remove="handleUploadRemove"
                :on-success="handleUploadSuccess"
                :on-error="handleUploadError"
                :file-list="form.photos"
                :limit="5"
                :multiple="true"
                accept="image/*"
                :before-upload="beforeUpload"
              >
                            <el-upload action="/api/upload" list-type="picture-card" :on-preview="handleUploadPreview"
                                :on-remove="handleUploadRemove" :on-success="handleUploadSuccess"
                                :on-error="handleUploadError" :file-list="form.photos" :limit="5" :multiple="true"
                                accept="image/*" :before-upload="beforeUpload">
                <i class="el-icon-plus"></i>
                <div slot="tip" class="el-upload__tip">
                  上传工单相关图片(支持jpg/png格式),最多5张,单张不超过5MB
@@ -212,13 +139,8 @@
        <el-col :span="12">
          <el-form label-width="100px">
            <el-form-item label="上传照片">
              <el-upload
                action="/api/upload"
                list-type="picture-card"
                :on-preview="handlePreview"
                :on-remove="handleRemove"
                :file-list="currentDetail.photos"
              >
                            <el-upload action="/api/upload" list-type="picture-card" :on-preview="handlePreview"
                                :on-remove="handleRemove" :file-list="currentDetail.photos">
                <i class="el-icon-plus"></i>
              </el-upload>
              <div class="el-upload__tip">
@@ -263,9 +185,13 @@
</template>
<script>
import { getList, createTicket, getTicketInfo } from '@/api/tickets/orderLog';
import { getDictionary } from '@/api/system/dictbiz';
import { export_json_to_excel } from '@/utils/exportExcel';
import geoJson from '@/assets/geoJson.json'
import { mapGetters } from 'vuex'
import { getAdcodeObj } from '@/utils/disposeData'
import { getList, createTicket, getTicketInfo } from '@/api/tickets/orderLog'
import { getDictionary } from '@/api/system/dictbiz'
import { export_json_to_excel } from '@/utils/exportExcel'
export default {
  name: "TicketPage",
@@ -361,17 +287,22 @@
      loading: false,
      globalCounts: {},
      mapLoaded: false,
    };
        }
  },
    computed: {
        ...mapGetters(['userInfo']),
    },
  async created() {
    this.loadAMapScripts();
    this.fetchDropdownData();
    var response=await getDictionary({ code: 'SF' });
    this.ai_types= response.data.data;
        this.loadAMapScripts()
        this.fetchDropdownData()
        var response = await getDictionary({ code: 'SF' })
        this.ai_types = response.data.data
  
  },
  mounted() {
    this.fetchTableData();
        this.fetchTableData()
  },
@@ -380,43 +311,43 @@
      try {
        // await loadAMap();
        // await loadAMapUI();
        this.mapLoaded = true;
                this.mapLoaded = true
      } catch (error) {
        console.error('Failed to load AMap scripts:', error);
        this.$message.error('地图加载失败,请检查网络或API Key配置');
                console.error('Failed to load AMap scripts:', error)
                this.$message.error('地图加载失败,请检查网络或API Key配置')
      }
    },
  formatCycleTime(row){
    return row.begin_time+"-"+row.end_time+" "+row.rep_rule_val;
            return row.begin_time + "-" + row.end_time + " " + row.rep_rule_val
  },
    async fetchDropdownData() {
      try {
        const response = await getTicketInfo();
        console.log('接口返回数据:', response.data.data);
        const { dept_data, event_type } = response.data.data;
                const response = await getTicketInfo()
                console.log('接口返回数据:', response.data.data)
                const { dept_data, event_type } = response.data.data
        this.departments = dept_data.map(item => ({
          label: item.dept_name,
          value: item.id,
        }));
                }))
        this.types = Object.entries(event_type).map(([key, value]) => ({
          label: value,
          value: key,
        }));
                }))
        console.log('departments:', this.departments);
        console.log('types:', this.types);
                console.log('departments:', this.departments)
                console.log('types:', this.types)
      } catch (error) {
        console.error('获取下拉框数据失败:', error);
        this.$message.error('加载下拉框数据失败');
                console.error('获取下拉框数据失败:', error)
                this.$message.error('加载下拉框数据失败')
      }
    },
    async fetchTableData() {
      this.loading = true;
            this.loading = true
      try {
        const currentTab = this.tabs.find(tab => tab.name === this.activeTab);
                const currentTab = this.tabs.find(tab => tab.name === this.activeTab)
       
        const params = {
          key_word: this.filters.key_word || undefined,
@@ -429,97 +360,97 @@
          end_date: this.filters.dateRange?.[1] ? this.formatDate(this.filters.dateRange[1]).replace("00:00:00", "23:59:59") : undefined,
          current: this.pagination.currentPage,
          size: this.pagination.pageSize,
        };
        console.log("发送的参数:", params);
        const response = await getList(params);
                }
                console.log("发送的参数:", params)
                const response = await getList(params)
        if (!response?.data?.data?.records) {
          throw new Error('接口返回数据格式不正确');
                    throw new Error('接口返回数据格式不正确')
        }
        const { total, records } = response.data.data;
                const { total, records } = response.data.data
        this.tableData = records.map(item => {
     
          return item;
        });
                    return item
                })
        if (this.activeTab === 'all') {
          this.updateGlobalCounts(records, total);
                    this.updateGlobalCounts(records, total)
        }
        this.pagination.total = total || 0;
        this.updateTabCounts();
                this.pagination.total = total || 0
                this.updateTabCounts()
      } catch (error) {
        console.error("获取数据失败:", error);
        this.$message.error(error.message || "获取数据失败");
        this.tableData = [];
        this.pagination.total = 0;
                console.error("获取数据失败:", error)
                this.$message.error(error.message || "获取数据失败")
                this.tableData = []
                this.pagination.total = 0
      } finally {
        this.loading = false;
                this.loading = false
      }
    },
    beforeUpload(file) {
      const isImage = file.type.includes('image');
      const isLt5M = file.size / 1024 / 1024 < 5;
            const isImage = file.type.includes('image')
            const isLt5M = file.size / 1024 / 1024 < 5
      if (!isImage) {
        this.$message.error('只能上传图片文件!');
        return false;
                this.$message.error('只能上传图片文件!')
                return false
      }
      if (!isLt5M) {
        this.$message.error('图片大小不能超过5MB!');
        return false;
                this.$message.error('图片大小不能超过5MB!')
                return false
      }
      return true;
            return true
    },
    handleUploadPreview(file) {
      this.$message.info(`预览图片:${file.name}`);
            this.$message.info(`预览图片:${file.name}`)
    },
    handleUploadRemove(file, fileList) {
      this.form.photos = fileList;
      this.$message.success(`已移除图片:${file.name}`);
            this.form.photos = fileList
            this.$message.success(`已移除图片:${file.name}`)
    },
    handleUploadSuccess(response, file, fileList) {
      this.form.photos = fileList;
      this.$message.success(`图片上传成功:${file.name}`);
            this.form.photos = fileList
            this.$message.success(`图片上传成功:${file.name}`)
    },
    handleUploadError(err, file) {
      this.$message.error(`图片上传失败:${file.name}`);
      console.error('上传失败:', err);
            this.$message.error(`图片上传失败:${file.name}`)
            console.error('上传失败:', err)
    },
    async uploadFiles(files) {
      const uploadPromises = files.map(file => {
        return new Promise((resolve) => {
          const formData = new FormData();
          formData.append('file', file.raw);
                    const formData = new FormData()
                    formData.append('file', file.raw)
          setTimeout(() => {
            resolve({
              url: URL.createObjectURL(file.raw),
              name: file.name
            });
          }, 1000);
        });
      });
      return Promise.all(uploadPromises);
                        })
                    }, 1000)
                })
            })
            return Promise.all(uploadPromises)
    },
    async submitForm() {
      this.$refs.form.validate(async (valid) => {
        if (valid) {
          if (!this.form.location || this.form.location.length !== 2) {
            this.$message.warning('请在地图上选择位置');
            return;
                        this.$message.warning('请在地图上选择位置')
                        return
          }
          try {
            const unUploadedFiles = this.form.photos.filter(file => file.raw);
                        const unUploadedFiles = this.form.photos.filter(file => file.raw)
            if (unUploadedFiles.length > 0) {
              await this.uploadFiles(unUploadedFiles);
                            await this.uploadFiles(unUploadedFiles)
            }
            const submitData = {
@@ -527,24 +458,24 @@
              photos: this.form.photos.map(file => file.url || file.response?.url),
              location: this.form.location.join(','),
              status: 1
            };
                        }
            await createTicket(submitData);
            this.dialogVisible = false;
            this.$message.success('工单创建成功');
            this.fetchTableData();
                        await createTicket(submitData)
                        this.dialogVisible = false
                        this.$message.success('工单创建成功')
                        this.fetchTableData()
          } catch (error) {
            console.error('提交失败:', error);
            this.$message.error('工单创建失败: ' + (error.message || '服务器错误'));
                        console.error('提交失败:', error)
                        this.$message.error('工单创建失败: ' + (error.message || '服务器错误'))
          }
        }
      });
            })
    },
    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`;
            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) {
@@ -554,8 +485,8 @@
        3: "处理中",
        4: "已完成",
        5: "已完结"
      };
      return statusTextMap[status] || "未知状态";
            }
            return statusTextMap[status] || "未知状态"
    },
    getStatusTagType(status) {
@@ -565,20 +496,20 @@
        3: "primary",
        4: "success",
        5: "danger",
      };
      return statusMap[status] || "info";
            }
            return statusMap[status] || "info"
    },
    handleTabChange(tab) {
      this.activeTab = tab.props?.name || tab.name;
      this.filters.status = "";
      this.pagination.currentPage = 1;
      this.fetchTableData();
            this.activeTab = tab.props?.name || tab.name
            this.filters.status = ""
            this.pagination.currentPage = 1
            this.fetchTableData()
    },
    handleSearch() {
      this.pagination.currentPage = 1;
      this.fetchTableData();
            this.pagination.currentPage = 1
            this.fetchTableData()
    },
    handleReset() {
@@ -588,15 +519,15 @@
        type: "",
        dateRange: [],
        status: "",
      };
      this.pagination.currentPage = 1;
      this.fetchTableData();
            }
            this.pagination.currentPage = 1
            this.fetchTableData()
    },
    handlePaginationChange(val) {
      this.pagination.currentPage = val.currentPage;
      this.pagination.pageSize = val.pageSize;
      this.fetchTableData();
            this.pagination.currentPage = val.currentPage
            this.pagination.pageSize = val.pageSize
            this.fetchTableData()
    },
    updateGlobalCounts(records, total) {
@@ -608,36 +539,36 @@
        completed: 0,
        closed: 0,
        myTickets: 0
      };
            }
      records.forEach(item => {
        const tab = this.tabs.find(t => t.value === Number(item.status));
                const tab = this.tabs.find(t => t.value === Number(item.status))
        if (tab) {
          counts[tab.name] = (counts[tab.name] || 0) + 1;
                    counts[tab.name] = (counts[tab.name] || 0) + 1
        }
      });
            })
      this.globalCounts = counts;
            this.globalCounts = counts
    },
    updateTabCounts() {
      if (this.activeTab === 'all') {
        this.tabs.forEach(tab => {
          tab.count = this.globalCounts[tab.name] || 0;
        });
                    tab.count = this.globalCounts[tab.name] || 0
                })
      } else {
        this.tabs.forEach(tab => {
          if (tab.name === this.activeTab) {
            tab.count = this.tableData.length;
                        tab.count = this.tableData.length
          } else {
            tab.count = this.globalCounts[tab.name] || 0;
                        tab.count = this.globalCounts[tab.name] || 0
          }
        });
                })
      }
    },
    handleAdd() {
      this.dialogVisible = true;
            this.dialogVisible = true
    },
    resetForm() {
@@ -650,50 +581,55 @@
        address: '',
        content: '',
        photos: [],
      };
            }
      if (this.$refs.form) {
        this.$refs.form.resetFields();
                this.$refs.form.resetFields()
      }
    },
    formatLocation(location) {
      if (!Array.isArray(location)) {
        return '未知位置';
                return '未知位置'
      }
      return `${location[0].toFixed(6)}, ${location[1].toFixed(6)}`;
            return `${location[0].toFixed(6)}, ${location[1].toFixed(6)}`
    },
    handleViewDetail(row) {
      this.currentDetail = {
        ...row,
        photos: row.photos || [],
      };
      this.detailVisible = true;
            }
            this.detailVisible = true
    },
    openMap() {
      this.$message.info("地图选址功能暂未实现");
            let cur = getAdcodeObj(geoJson, 'adcode', this.userInfo.detail.areaCode.substring(0, 6))
            console.log(cur, 111)
            this.$message.info("地图选址功能暂未实现")
    },
    handlePreview(file) {
      this.$message.info(`预览图片:${file.name}`);
            this.$message.info(`预览图片:${file.name}`)
    },
    handleRemove(file) {
      this.$message.info(`移除图片:${file.name}`);
            this.$message.info(`移除图片:${file.name}`)
    },
    refreshChange() {
      this.fetchTableData();
            this.fetchTableData()
    },
    onLoad() {
      this.fetchTableData();
            this.fetchTableData()
    },
    async exportData() {
      try {
        this.loading = true;
                this.loading = true
        const params = {
          keyword: this.filters.keyword || undefined,
          word_order_type: this.filters.type || undefined,
@@ -701,14 +637,14 @@
          dept_id: this.filters.department || undefined,
          start_date: this.filters.dateRange?.[0] ? this.formatDate(this.filters.dateRange[0]) : undefined,
          end_date: this.filters.dateRange?.[1] ? this.formatDate(this.filters.dateRange[1]) : undefined,
        };
        const response = await getList(params);
        if (!response?.data?.data?.records) {
          throw new Error('接口返回数据格式不正确');
        }
        const records = response.data.data.records;
                const response = await getList(params)
                if (!response?.data?.data?.records) {
                    throw new Error('接口返回数据格式不正确')
                }
                const records = response.data.data.records
        const exportData = records.map(item => ({
          工单编号: item.wayline_job_id || '',
          工单名称: item.event_name || '',
@@ -721,31 +657,31 @@
          创建人: item.create_user || '未知创建人',
          处理人: item.update_user || '未分配',
          工单状态: this.mapStatus(Number(item.status || 0)),
        }));
                }))
        export_json_to_excel(
          ['工单编号', '工单名称', '所属单位', '发起时间', '工单内容', '工单类型', '经纬度', '详细地址', '创建人', '处理人', '工单状态'],
          exportData,
          '工单数据'
        );
        this.$message.success('数据导出成功');
                )
                this.$message.success('数据导出成功')
      } catch (error) {
        console.error('导出失败:', error);
        this.$message.error('数据导出失败');
                console.error('导出失败:', error)
                this.$message.error('数据导出失败')
      } finally {
        this.loading = false;
                this.loading = false
      }
    },
  },
  watch: {
    tableData: {
      handler() {
        this.updateTabCounts();
                this.updateTabCounts()
      },
      deep: true
    },
  }
};
}
</script>
<style lang="scss" scoped>