riku
2025-08-13 bf42ef43fccdf3d3486eec84ad4073b0c7650aba
新增场景信息文件导入功能
已修改9个文件
已添加2个文件
279 ■■■■ 文件已修改
public/现场监管场景信息导入模板.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fysp/sceneApi.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/button/FYDownloadTableButton.vue 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/map/SceneMap.vue 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/table/FYTable.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/excel.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/data-product/ProdLawEnforceList.vue 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/data-product/base-data-product/PordProblemRecurrence.vue 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/scene/CompSceneImport.vue 103 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/ÏÖ³¡¼à¹Ü³¡¾°ÐÅÏ¢µ¼ÈëÄ£°å.xlsx
Binary files differ
src/api/fysp/sceneApi.js
@@ -93,5 +93,10 @@
   */
  findScene(scene) {
    return $fysp.post('scense/search', scene).then((res) => res.data);
  },
  importScene(file) {
    return $fysp.post('scense/import', file).then((res) => res.data);
  }
};
src/api/index.js
@@ -1,7 +1,7 @@
import axios from 'axios';
import { ElMessage } from 'element-plus';
const debug = true;
const debug = false;
// let ip1 = 'http://47.100.191.150:9005/';
// let ip1_file = 'http://47.100.191.150:9005/';
src/components.d.ts
@@ -86,6 +86,7 @@
    FYBgTaskCard: typeof import('./components/bg-task/FYBgTaskCard.vue')['default']
    FYBgTaskDialog: typeof import('./components/bg-task/FYBgTaskDialog.vue')['default']
    FYBgTaskItem: typeof import('./components/bg-task/FYBgTaskItem.vue')['default']
    FYDownloadTableButton: typeof import('./components/button/FYDownloadTableButton.vue')['default']
    FYForm: typeof import('./components/form/FYForm.vue')['default']
    FYImageSelectDialog: typeof import('./components/FYImageSelectDialog.vue')['default']
    FYInfoSearch: typeof import('./components/search-option/FYInfoSearch.vue')['default']
src/components/button/FYDownloadTableButton.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
<template>
  <el-button
    icon="Download"
    type="primary"
    plain
    @click="download"
    :loading="dlLoading"
    >{{ label }}</el-button
  >
</template>
<script setup>
import { ref } from 'vue';
import { conversionFromTable } from '@/utils/excel';
const props = defineProps({
  // ä¸‹è½½æ–‡ä»¶åç§°
  fileName: String,
  // è¡¨æ ¼å…ƒç´ id
  tableId: String,
  label: {
    type: String,
    default: '下载'
  }
});
const dlLoading = ref(false);
function download() {
  dlLoading.value = true;
  conversionFromTable(props.tableId, props.fileName);
  dlLoading.value = false;
}
</script>
src/components/map/SceneMap.vue
@@ -9,12 +9,20 @@
    ></FYOptionScene>
    <slot name="left-top"></slot>
  </el-row>
  <!-- <el-row class="right-wrap">
    <el-col :span="4">
      <el-button>close</el-button>
    </el-col>
    <el-col :span="20">
    </el-col>
  </el-row> -->
  <el-scrollbar class="right-wrap">
    <div v-for="s in selectedSceneList" :key="s.guid">
      <el-checkbox
        v-model="s._checked"
        :label="s.name"
        @change="handleChange"
        @change="handleChange(s)"
      />
      <!-- <el-text>{{ s.name }}</el-text> -->
    </div>
@@ -53,7 +61,7 @@
    if (nV != oV) {
      clearSceneMarks();
      createSceneMarks();
      filterMarkViews();
      filterMarkViews(true);
    }
  },
  { immediate: true }
@@ -62,14 +70,20 @@
watch(scenetype, (nV, oV) => {
  if (nV != oV) {
    clearSceneMarks();
    filterMarkViews();
    filterMarkViews(true);
  }
});
function handleChange(value) {
  console.log(value);
  filterMarkViews();
function handleChange(scene) {
  const mv = markViewList.find((v) => {
    return scene.guid == v.getExtData().guid;
  });
  if (scene._checked) {
    map.add(mv);
  } else {
    map.remove(mv);
  }
  // filterMarkViews();
}
function createSceneMarks() {
@@ -111,8 +125,11 @@
/**
 * ç­›é€‰æ‰€é€‰ç±»åž‹çš„场景
 */
function filterMarkViews() {
function filterMarkViews(setFitView) {
  onMapMounted(() => {
    if (markViewList.length > 0) {
      map.remove(markViewList);
    }
    if (scenetype.value == undefined) {
      markViewList = allMarkViews;
    } else {
@@ -125,21 +142,21 @@
    }
    markViewList = markViewList.filter((v) => {
      const _index = selectedSceneList.value.findIndex((s) => {
        console.log(s.guid, v.getExtData().guid);
        s.guid == v.getExtData().guid;
        return s.guid == v.getExtData().guid && s._checked;
      });
      return _index != -1;
    });
    map.add(markViewList);
    setTimeout(() => {
      map.setFitView(markViewList);
      // const list = markViewList.map((v) => {
      //   const _extData = v.getExtData();
      //   return [_extData.longitude, _extData.latitude];
      // });
      // mapUtil.setBound(list);
    }, 1000);
    if (setFitView) {
      setTimeout(() => {
        map.setFitView(markViewList);
        // const list = markViewList.map((v) => {
        //   const _extData = v.getExtData();
        //   return [_extData.longitude, _extData.latitude];
        // });
        // mapUtil.setBound(list);
      }, 1000);
    }
  });
}
@@ -166,5 +183,6 @@
  border-radius: 4px;
  padding: 2px 8px;
  max-width: 300px;
  box-shadow: var(--el-box-shadow);
}
</style>
src/components/table/FYTable.vue
@@ -28,7 +28,7 @@
    <slot name="options-expand2"></slot>
  </div>
  <el-table
    id="fyTable"
    v-bind="$attrs"
    ref="tableRef"
    :data="tableData"
    v-loading="loading"
src/utils/excel.js
@@ -20,7 +20,7 @@
  //     }
  //   }
  // }
  console.log(tables);
  // console.log(tables);
  //------放入以上拿到switch状态,以及下拉框代码,如果没克隆元素则会影响到原表格-------------//
src/views/fysp/data-product/ProdLawEnforceList.vue
@@ -1,5 +1,6 @@
<template>
  <FYTable
    id="fyTable"
    @search="onSearch"
    :data="tableData"
    :pagination="false"
@@ -47,15 +48,12 @@
      </el-descriptions>
    </template>
    <template #buttons>
      <el-button
        icon="Download"
        type="primary"
        plain
        @click="download"
        :loading="dlLoading"
      <FYDownloadTableButton
        label="下载清单"
        table-id="fyTable"
        :file-name="fileName"
        :disabled="downloadDisabled"
        >下载清单</el-button
      >
      ></FYDownloadTableButton>
    </template>
    <template #table-column="{ size }">
      <el-table-column fixed="left" label="序号" width="53">
@@ -160,13 +158,8 @@
import evaluateApi from '@/api/fysp/evaluateApi';
import problemApi from '@/api/fysp/problemApi';
import sceneApi from '@/api/fysp/sceneApi';
import { conversionFromTable } from "@/utils/excel";
import { envCreditCode } from '@/constants/index';
import { useTablePaste } from '@/composables/tablePaste';
import { useCloned } from '@vueuse/core';
import { useMessageBoxTip } from '@/composables/messageBox';
import * as XLSX from 'xlsx';
import FileSaver from 'file-saver';
export default {
  setup() {
@@ -239,6 +232,12 @@
        });
        return b;
      }
    },
    fileName() {
      const { locations, scenetype, time } = this.formSearch;
      return `${locations.dName}${dayjs(time).format(
        'YYYYå¹´MM月'
      )}联合执法清单`;
    }
  },
  methods: {
@@ -327,24 +326,6 @@
      const property = column['property'];
      return row[property] === value;
    },
    download() {
      // const workbook = XLSX.utils.book_new();
      // const worksheet = XLSX.utils.json_to_sheet(this.tableData);
      // XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
      // const excelData = XLSX.write(workbook, {
      //   bookType: 'xlsx',
      //   type: 'array'
      // });
      // const blob = new Blob([excelData], {
      //   type: 'application/vnd.openxmlformats-officedocumnet.spreadsheetml.sheet'
      // });
      const { locations, scenetype, time } = this.formSearch;
      const name = `${locations.dName}${dayjs(time).format(
        'YYYYå¹´MM月'
      )}联合执法清单.xlsx`;
      // FileSaver.saveAs(blob, name);
      conversionFromTable('fyTable', name)
    }
  },
  mounted() {
    this.addRefreshEvent(this.$refs.tableRef.doLayout);
src/views/fysp/data-product/base-data-product/PordProblemRecurrence.vue
@@ -1,5 +1,6 @@
<template>
  <FYTable
    id="fyTable"
    @search="onSearch"
    :data="showData"
    :pagination="false"
@@ -34,7 +35,14 @@
        <el-radio :value="2">按问题类型统计</el-radio>
      </el-radio-group>
    </template>
    <template #buttons> </template>
    <template #buttons>
      <FYDownloadTableButton
        label="下载清单"
        table-id="fyTable"
        :file-name="fileName"
        :disabled="downloadDisabled"
      ></FYDownloadTableButton>
    </template>
    <template #table-column="{ size }">
      <!-- <el-table-column fixed="left" label="序号" width="53">
        <template #default="{ row }">
@@ -58,14 +66,9 @@
      </el-table-column>
      <el-table-column prop="townName" label="街镇" width="110">
      </el-table-column>
      <el-table-column prop="problemType" label="问题类型" width="110">
      <el-table-column prop="problemType" label="问题类型" width="170">
      </el-table-column>
      <el-table-column
        v-if="radio == 1"
        prop="problemName"
        label="问题名称"
        width="200"
      >
      <el-table-column v-if="radio == 1" prop="problemName" label="问题名称">
      </el-table-column>
      <el-table-column prop="proNum" label="问题数" width="70">
      </el-table-column>
@@ -134,6 +137,19 @@
  return res;
});
const fileName = computed(() => {
  const { locations, scenetype, timeArr } = formSearch.value;
  return `${locations.dName}${dayjs(timeArr[0]).format(
    'YYYYå¹´MM月DD日'
  )}至${dayjs(timeArr[1]).format('YYYYå¹´MM月DD日')}${
    scenetype.label
  }问题复发清单`;
});
const downloadDisabled = computed(() => {
  return tableData.value.length == 0;
});
function onSearch(page, callback) {
  fetchProbRecurrence().finally(() => callback());
}
src/views/fysp/scene/CompSceneImport.vue
@@ -1,5 +1,7 @@
<template>
  <el-button disabled icon="Upload" type="success" @click="dialogVisible = true">批量导入</el-button>
  <el-button icon="Upload" type="success" @click="dialogVisible = true"
    >批量导入</el-button
  >
  <el-dialog
    v-model="dialogVisible"
    title="场景信息批量导入"
@@ -9,31 +11,102 @@
    <el-upload
      class="upload-demo"
      drag
      action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
      multiple
      :limit="1"
      v-model:file-list="fileList"
      :auto-upload="false"
      accept=".xlsx"
      :on-change="handleChange"
      :on-exceed="handleExceed"
    >
      <el-icon class="el-icon--upload"><upload-filled /></el-icon>
      <div class="el-upload__text">拖动文件或<em>点击上传</em></div>
      <template #tip>
        <!-- <div class="el-upload__tip">jpg/png files with a size less than 500kb</div> -->
        <el-text type="danger" size="small">{{ errMsg }}</el-text>
      </template>
    </el-upload>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="dialogVisible = false">确定</el-button>
      </div>
      <el-row justify="space-between">
        <el-button type="primary" plain @click="downloadTemplate"
          >下载模板</el-button
        >
        <div class="dialog-footer">
          <el-button @click="handleClose">取消</el-button>
          <el-button type="primary" @click="uploadFile" :loading="loading"
            >确定</el-button
          >
        </div>
      </el-row>
    </template>
  </el-dialog>
</template>
<script>
export default {
  data() {
    return {
      dialogVisible: false
    };
<script setup>
import { ref } from 'vue';
import sceneApi from '@/api/fysp/sceneApi';
import { ElMessage } from 'element-plus';
const dialogVisible = ref(false);
const fileList = ref([]);
const errMsg = ref('');
const loading = ref(false);
function handleChange(file) {
  console.log(file);
  const ext = file.name.split('.').pop();
  if (ext !== 'xlsx') {
    ElMessage.error('请上传Excel文件');
    fileList.value.splice(0, 1);
    return;
  }
};
  fileList.value = [file];
}
function handleExceed(files, fileList) {
  ElMessage.error('最多只能上传一个文件');
}
function uploadFile() {
  if (fileList.value.length === 0) {
    ElMessage.error('请上传文件');
    return;
  }
  const formData = new FormData();
  loading.value = true;
  formData.append('file', fileList.value[0].raw);
  errMsg.value = '';
  sceneApi
    .importScene(formData)
    .then((res) => {
      dialogVisible.value = false;
      fileList.value = [];
    })
    .catch((err) => {
      errMsg.value = err;
    })
    .finally(() => {
      loading.value = false;
    });
}
function downloadTemplate() {
  // åˆ›å»ºä¸‹è½½é“¾æŽ¥
  const link = document.createElement('a');
  // è®¾ç½®public目录下的文件路径
  link.href = '/现场监管场景信息导入模板.xlsx';
  // è®¾ç½®ä¸‹è½½æ–‡ä»¶å
  link.download = '现场监管场景信息导入模板.xlsx';
  // å°†é“¾æŽ¥æ·»åŠ åˆ°é¡µé¢
  document.body.appendChild(link);
  // è§¦å‘点击下载
  link.click();
  // ä¸‹è½½å®ŒæˆåŽç§»é™¤é“¾æŽ¥
  document.body.removeChild(link);
}
function handleClose() {
  dialogVisible.value = false;
  fileList.value = [];
  errMsg.value = '';
}
</script>