Selaa lähdekoodia

[Feat 0000]数据质量页面增加数据导出功能

wangkeyi 3 kuukautta sitten
vanhempi
commit
33a0e38f72

+ 1 - 0
package.json

@@ -79,6 +79,7 @@
     "vxe-table": "4.13.31",
     "vxe-table-plugin-antd": "4.0.8",
     "xe-utils": "3.5.26",
+    "xlsx": "^0.18.5",
     "xss": "^1.0.15"
   },
   "devDependencies": {

+ 1 - 23
src/views/dashboard/basicInfo/dataQuality/dataQuality.data.ts

@@ -2,7 +2,7 @@ import { BasicColumn, FormSchema } from '/@/components/Table';
 import { h } from 'vue';
 
 // 生产状态映射表(扩展所有状态)
-const productionStatusMap: Record<string | number, { label: string; value: number; color: string }> = {
+export const productionStatusMap: Record<string | number, { label: string; value: number; color: string }> = {
   0: { label: '正常生产矿井', value: 0, color: 'green' },
   1: { label: '拟建矿井', value: 1, color: 'blue' },
   2: { label: '正常建设煤矿', value: 2, color: 'green' },
@@ -30,21 +30,6 @@ const colorHexMap: Record<string, string> = {
   gray: '#8c8c8c',
   black: '#000000',
 };
-// 解析queJson并拼接orderNum+queCon的辅助函数
-const formatQueJson = (queJsonStr: string) => {
-  // 空值处理
-  if (!queJsonStr) return '无质量问题';
-  try {
-    const queList = JSON.parse(queJsonStr);
-    // 非数组格式处理
-    if (!Array.isArray(queList)) return '问题格式异常';
-    // 拼接orderNum + queCon,多个问题用分号分隔
-    return queList.map((item) => `${item.orderNum || ''}:${item.queCon || ''}`).join('; ');
-  } catch (error) {
-    console.error('解析质量问题JSON失败:', error);
-    return '问题数据解析失败';
-  }
-};
 
 /** 表格列配置 */
 export const columns: BasicColumn[] = [
@@ -89,13 +74,6 @@ export const columns: BasicColumn[] = [
     dataIndex: 'queJson',
     width: 400,
     ellipsis: true,
-    customRender: ({ record, text }) => {
-      // 核心修改:使用辅助函数格式化显示文本
-      const displayText = formatQueJson(text);
-      return h('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } }, [
-        h('span', { style: { flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, displayText),
-      ]);
-    },
     slots: {
       customRender : 'queJson'
     }

+ 114 - 6
src/views/dashboard/basicInfo/dataQuality/index.vue

@@ -3,12 +3,19 @@
   <Tabs v-model:activeKey="activeKey" class="data-quality-page" type="line">
     <TabPane key="unresolved" tab="未解决">
       <div class="add-button">
+        <a-button 
+          type="default" 
+          preIcon="mdi:download" 
+          @click="handleExportExcel" 
+          style="margin-right: 8px;"
+        > 
+          导出 
+        </a-button>
         <a-button type="primary" preIcon="mdi:page-next-outline" @click="handleOpenModal({}, 'add')"> 新增问题 </a-button>
       </div>
       <BasicTable style="padding: 0" @register="registerUnresolvedTable">
         <template #queJson="{ record }">
           <div style="display: flex; align-items: center; gap: 8px; width: 100%;">
-            <!-- 文字span:添加 flex: 1 占据剩余空间,text-align: center 实现文字居中 -->
             <span style="flex: 1; text-align: center;">
               {{ record?.queJson ? formatQueJson(record.queJson) : '' }}
             </span>
@@ -17,7 +24,6 @@
               <SvgIcon name="view" />
             </button>
           </div>
-
         </template>
         <template #action="{ record }">
           <button @click="handleOpenModal(record, 'edit')" class="action-btn">
@@ -57,7 +63,28 @@
       </BasicTable>
     </TabPane>
     <TabPane key="resolved" tab="已解决">
+      <div class="add-button">
+        <a-button 
+          type="default" 
+          preIcon="mdi:download" 
+          @click="handleExportExcel" 
+          style="margin-right: 8px;"
+        > 
+          导出 
+        </a-button>
+      </div>
       <BasicTable style="padding: 0" @register="registerResolvedTable">
+        <template #queJson="{ record }">
+          <div style="display: flex; align-items: center; gap: 8px; width: 100%;">
+            <span style="flex: 1; text-align: center;">
+              {{ record?.queJson ? formatQueJson(record.queJson) : '' }}
+            </span>
+            <!-- 按钮:无需额外样式,自然靠最右侧 -->
+            <button @click="record && handleOpenModal(record, 'view')" class="action-btn">
+              <SvgIcon name="view" />
+            </button>
+          </div>
+        </template>
         <template #action="{ record }">
           <button @click="handleOpenModal(record, 'view')" class="action-btn">
             <SvgIcon name="details" />
@@ -76,12 +103,13 @@
   import { useRouter } from 'vue-router';
   import { BasicTable, useTable } from '/@/components/Table';
   import { useModal } from '/@/components/Modal';
-  import { Tabs, TabPane, Popconfirm } from 'ant-design-vue';
+  import { Tabs, TabPane, Popconfirm, message } from 'ant-design-vue';
   import DataQualityModal from './components/DataQualityModal.vue';
   import { SvgIcon } from '/@/components/Icon';
-  import { columns, searchFormSchema } from './dataQuality.data';
+  import { columns, searchFormSchema, productionStatusMap } from './dataQuality.data';
   import { getDataQuaQueList, addDataQuaQue, deleteDataQuaQue, editDataQuaQue } from '../basicInfo.api';
   import dayjs from 'dayjs'; 
+  import * as XLSX from 'xlsx';
   // 路由实例
   const router = useRouter();
   // 响应式数据
@@ -122,12 +150,12 @@
       labelWidth: 120,
       schemas: searchFormSchema,
       showAdvancedButton: false,
-      schemaGroupNames: ['常规查询', '高级查询'],
+      schemaGroupNames: ['常规查询'],
     },
     useSearchForm: true,
     pagination: true,
     striped: true,
-    bordered: true,
+    // bordered: true,
     showIndexColumn: false,
     indexColumnProps: {
       title: '序号',
@@ -268,6 +296,86 @@
       console.error('操作失败:', error);
     }
   }
+
+    /**
+   * 获取全部未解决数据(不分页)
+   */
+  async function getAllUnresolvedData() {
+    try {
+      const res = await getDataQuaQueList({ pageNum: 1, pageSize: 9999, isOk: false });
+      return res.records || []; // 请根据实际接口返回结构调整(比如res.list / res.data等)
+    } catch (error) {
+      console.error('获取未解决数据失败:', error);
+      return [];
+    }
+  }
+
+  /**
+   * 获取全部已解决数据(不分页)
+   */
+  async function getAllResolvedData() {
+    try {
+      const res = await getDataQuaQueList({ pageNum: 1, pageSize: 9999, isOk: true });
+      return res.records || []; // 请根据实际接口返回结构调整
+    } catch (error) {
+      console.error('获取已解决数据失败:', error);
+      return [];
+    }
+  }
+
+  /**
+   * 格式化导出数据(统一字段名 + 状态文本)
+   */
+  function formatExportData(dataList: any[]) {
+    return dataList.map(item => ({
+      '煤矿名称': item.mineName || '',
+      '煤矿简称': item.mineNameAbbr || '',
+      '生产状态': productionStatusMap[item.mineProStatus]?.label || '未知状态',
+      '在线状态': item.mineLinkStatus === 1 ? '在线' : (item.mineLinkStatus === 0 ? '离线' : '/'),
+      '质量问题详情': formatQueJson(item.queJson),
+      '当前状态': item.isOk ? '已解决' : '未解决',
+      '处理时间': item.updateTime || ''
+    }));
+  }
+
+  /**
+   * 导出Excel核心方法
+   */
+  async function handleExportExcel() {
+    // 声明关闭函数
+    let hideLoading: () => void = () => {};
+    try {
+      // 初始化loading并获取关闭函数
+      hideLoading = message.loading('正在导出数据,请稍候...');
+      
+      const unresolvedList = await getAllUnresolvedData();
+      const resolvedList = await getAllResolvedData();
+
+      const formattedUnresolved = formatExportData(unresolvedList);
+      const formattedResolved = formatExportData(resolvedList);
+
+      const workbook = XLSX.utils.book_new();
+      const unresolvedSheet = XLSX.utils.json_to_sheet(formattedUnresolved);
+      const resolvedSheet = XLSX.utils.json_to_sheet(formattedResolved);
+
+      XLSX.utils.book_append_sheet(workbook, unresolvedSheet, '未解决');
+      XLSX.utils.book_append_sheet(workbook, resolvedSheet, '已解决');
+
+      const fileName = `数据质量问题_${dayjs().format('YYYYMMDDHHmmss')}.xlsx`;
+      XLSX.writeFile(workbook, fileName);
+
+      // 关闭加载提示
+      hideLoading();
+      message.success('导出成功!');
+    } catch (error) {
+      // 容错:若loading已初始化,再调用关闭
+      if (hideLoading) {
+        hideLoading();
+      }
+      console.error('Excel导出失败:', error);
+      message.error('导出失败,请稍后重试');
+    }
+  }
 </script>
 
 <style scoped lang="less">