yangyuxuan 4 kuukautta sitten
vanhempi
commit
a31ebc9978

+ 11 - 0
src/api/dataFilling/fillingManage.ts

@@ -44,4 +44,15 @@ export const fillingRelease = (reportId) => {
   });
 };
 
+// 导出
+export const fillingTable = (reportId) => {
+  return request({
+    url: `/api/dataFilling/export_to_excel`, // 相对于基础 URL 的路径
+    method: 'get',
+    params: {
+      report_id: reportId
+    }
+  });
+};
+
 

+ 3 - 0
src/types/components.d.ts

@@ -41,6 +41,7 @@ declare module 'vue' {
     ElForm: typeof import('element-plus/es')['ElForm']
     ElFormItem: typeof import('element-plus/es')['ElFormItem']
     ElIcon: typeof import('element-plus/es')['ElIcon']
+    ElImage: typeof import('element-plus/es')['ElImage']
     ElInput: typeof import('element-plus/es')['ElInput']
     ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
     ElMenu: typeof import('element-plus/es')['ElMenu']
@@ -59,6 +60,8 @@ declare module 'vue' {
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
     ElTag: typeof import('element-plus/es')['ElTag']
     ElText: typeof import('element-plus/es')['ElText']
+    ElTimeline: typeof import('element-plus/es')['ElTimeline']
+    ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
     ElTooltip: typeof import('element-plus/es')['ElTooltip']
     ElTree: typeof import('element-plus/es')['ElTree']
     ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']

+ 29 - 22
src/views/dataFilling/fillingManage.vue

@@ -46,7 +46,7 @@
                   <el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button>
                   <el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
                   <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-                  <el-button type="warning" plain icon="Download" @click="exportTableData()">导出</el-button>
+                  <el-button type="warning" plain icon="Download" :disabled="multiple" @click="exportTableData">导出</el-button>
                 </el-col>
               </el-row>
             </el-form>
@@ -54,6 +54,7 @@
         </transition>
         <!-- 表格组件 -->
         <el-table ref="multipleTable" v-loading="loading" :data="tableData" @selection-change="handleSelectionChange" style="margin-top: 10px">
+          <el-table-column type="selection" width="55" align="center" />
           <el-table-column label="序号" align="center" type="index" width="50px" />
           <el-table-column label="表格名称" align="center" prop="table_name" />
           <el-table-column label="发布日期" align="center" prop="start_time" />
@@ -97,14 +98,16 @@ import FillingAdd from './fillingAdd.vue';
 import fillingIssued from './fillingIssued.vue';
 import TableDetails from './tableDetails.vue';
 import { ElButton, ElCol } from 'element-plus';
-import { fillingSelect, fillingRelease } from '@/api/dataFilling/fillingManage';
+import { fillingSelect, fillingRelease, fillingTable, fillingChange } from '@/api/dataFilling/fillingManage';
 import * as XLSX from 'xlsx';
 import { deepClone } from '@/utils';
 import { addDateRange2, parseTime } from '@/utils/ruoyi';
 import { fillList } from '@/api/dataFilling/datafilling';
+import { download2 } from '@/utils/request';
 
 const loading = ref(true);
 const showSearch = ref(true);
+const multiple = ref(true);
 const selectedTime = ref([]);
 const ids = ref<Array<number | string>>([]);
 const total = ref(0);
@@ -223,26 +226,30 @@ const resetQuery = () => {
   handleQuery();
 };
 
+const filename = ref();
 const handleSelectionChange = (selection) => {
-  ids.value = selection.map((item) => item.id);
+  selection.forEach((item) => {
+    ids.value.push(item.report_id);
+    filename.value = item.table_name;
+  })
+  if (selection.length == 1) {
+    multiple .value = false;
+  }if (selection.length !== 1) {
+    multiple .value = true;
+  }
+
 };
 
 const handleTimeChange = () => {
   // selectedTimeLabel.value = value ? `${value[0]} 至 ${value[1]}` : '请选择时间';
 };
 
+const baseUrl = import.meta.env.VITE_APP_BASE_API;
 const exportTableData = () => {
-  const worksheet = XLSX.utils.json_to_sheet(tableData.value);
-  const workbook = { Sheets: { data: worksheet }, SheetNames: ['data'] };
-  const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
+  fillingTable(ids.value[0]);
+  download2(baseUrl + '/api/dataFilling/export_to_excel?report_id='+ids.value[0], filename.value + '.xlsx');
+
 
-  const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
-  const link = document.createElement('a');
-  const url = window.URL.createObjectURL(blob);
-  link.href = url;
-  link.download = 'SheetJS.xlsx';
-  link.click();
-  window.URL.revokeObjectURL(url); // 清理
 };
 
 const handlePagination = ({ page, limit }) => {
@@ -252,8 +259,10 @@ const handlePagination = ({ page, limit }) => {
 };
 
 const handleIssue = (row) => {
-  issuedState.show = true;
-  issuedState.id = row.report_id;
+  // issuedState.show = true;
+  // issuedState.id = row.report_id;
+
+
   // 检查是否有report_id
   // if (!row.report_id) {
   //   console.error('报告ID不存在,无法下发');
@@ -262,13 +271,11 @@ const handleIssue = (row) => {
   // // 构造下发请求的URL
   // const releaseUrl = `${row.report_id}`;
   // 发起下发请求
-  // fillingRelease(releaseUrl)
-  //   .then(() => {
-  //     fetchFillList();
-  //   })
-  //   .catch((error) => {
-  //     console.error('下发操作失败:', error);
-  //   });
+  fillingRelease(row.report_id)
+    .then(() => {
+      proxy.$modal.msgSuccess('发布成功');
+      fetchFillList();
+    })
 };
 const handleEditClose = () => {
   issuedState.show = false;

+ 102 - 22
src/views/dataFilling/formDetail.vue

@@ -16,16 +16,17 @@
         </el-row>
       </el-col>
       <el-col :lg="30" :xs="24">
-        <el-table :data="tableData" border>
-          <el-table-column v-for="header in editableHeaders" :key="header" :label="header" :prop="header">
-            <template #header="{ column }">
-              <span class="editable-header" v-text="column.label"></span>
-            </template>
-            <template #default="{ row, $index }">
-              <span class="editable-span" v-text="row[header]"></span>
-            </template>
-          </el-table-column>
-        </el-table>
+<!--        <el-table :data="tableData" border>-->
+<!--          <el-table-column v-for="header in editableHeaders" :key="header" :label="header" :prop="header">-->
+<!--            <template #header="{ column }">-->
+<!--              <span class="editable-header" v-text="column.label"></span>-->
+<!--            </template>-->
+<!--            <template #default="{ row, $index }">-->
+<!--              <span class="editable-span" v-text="row[header]"></span>-->
+<!--            </template>-->
+<!--          </el-table-column>-->
+<!--        </el-table>-->
+        <hot-table v-if="tableData.length > 0" ref="wrapper" :data="tableData" :settings="hotSettings" />
       </el-col>
     </el-row>
   </div>
@@ -35,6 +36,7 @@ import { ref, onMounted } from 'vue';
 import { ElTable, ElButton, ElCol, ElRow, ElTableColumn } from 'element-plus';
 import * as XLSX from 'xlsx';
 import { fillDetail } from '@/api/dataFilling/datafilling';
+import { HotTable } from '@handsontable/vue3';
 
 const emits = defineEmits(['close']);
 const props = defineProps<{
@@ -44,6 +46,7 @@ const props = defineProps<{
 // 更新表头以匹配新的数据结构
 const editableHeaders = ref(['员工姓名', '员工性别', '加班小时', '新的备注', '新的地址']);
 const tableData = ref([]);
+const hotData = ref([]);
 const detailData = ref({
   title: '表单数据',
   start: '',
@@ -69,25 +72,102 @@ const exportToExcel = () => {
 };
 
 const fetchFillDetail = async () => {
-  try {
-    const res = await fillDetail({ report_id: props.eventId });
-    tableData.value = res.data.map((item) => ({
-      '员工姓名': item.ygxm,
-      '员工性别': item.ygxb,
-      '加班小时': item.jbxs,
-      '新的备注': item.bz,
-      '新的地址': item.dz
-    }));
+  // try {
+  //   const res = await fillDetail({ report_id: props.eventId });
+  //   tableData.value = res.data.map((item) => ({
+  //     '员工姓名': item.ygxm,
+  //     '员工性别': item.ygxb,
+  //     '加班小时': item.jbxs,
+  //     '新的备注': item.bz,
+  //     '新的地址': item.dz
+  //   }));
+  //   detailData.value.start = res.start_time;
+  //   detailData.value.end = res.end_time;
+  // } catch (error) {
+  //   console.error('Error fetching data:', error);
+  // }
+  fillDetail({ report_id: props.eventId }).then((res) => {
     detailData.value.start = res.start_time;
     detailData.value.end = res.end_time;
-  } catch (error) {
-    console.error('Error fetching data:', error);
-  }
+    // tableData.value = res.data;
+
+    tableData.value = res.data.map(item => [item.ygxm, item.ygxb, item.jbxs, item.bz, item.dz]);
+  })
 };
 
 const handleReturn = () => {
   emits('close');
 };
+
+const hotSettings = reactive({
+  language: 'zh-CN',
+  colHeaders: true,
+  rowHeaders: true,
+  autoColumnSize: true,
+  width: '100%', // auto  or  100%
+  height: '100%', // auto  or  100%
+  licenseKey: 'non-commercial-and-evaluation', // 隐藏版权文字
+  colWidths: 129, // 默认单元格宽度
+  rowHeights: 28, // 默认单元格高度
+  wordWrap: true, // 单元格文字是否换行展示
+  contextMenu: {
+    // 自定义右键菜单
+    items: {
+      'row_above': {
+        name: '向上插一行'
+      },
+      'row_below': {
+        name: '向下插一行'
+      },
+      'col_left': {
+        name: '向左插一列'
+      },
+      'col_right': {
+        name: '向右插一列'
+      },
+      'hsep1': '---------', // 分隔线
+      'remove_row': {
+        name: '删除当前行'
+      },
+      'remove_col': {
+        name: '删除当前列'
+      },
+      'clear_column': {
+        name: '清空当前列'
+      },
+      'hsep2': '---------', // 必须和上次的变量名不一样
+      'undo': {
+        name: '撤销'
+      },
+      'cut': {
+        name: '剪切'
+      },
+      'copy': {
+        name: '复制'
+      },
+      'alignment': {
+        name: '对齐'
+      },
+      'hsep3': '---------',
+      'commentsAddEdit': {
+        // 必须开启 comments: true
+        name: '添加备注'
+      },
+      'commentsRemove': {
+        // 必须开启 comments: true
+        name: '删除备注'
+      },
+      'freeze_column': {
+        // 必须开启 manualColumnFreeze: true
+        name: '固定列'
+      },
+      'unfreeze_column': {
+        // 必须开启 manualColumnFreeze: true
+        name: '取消固定列'
+      }
+    }
+  }
+});
 </script>
 
 <style scoped>

+ 116 - 67
src/views/dataFilling/tableDetails.vue

@@ -15,65 +15,73 @@
 <!--          <el-button v-if="is_filling_ended === 0" type="primary" @click="handleReport()">智能识别</el-button>-->
 <!--        </el-col>-->
         <el-col :span="1.5">
-          <el-button v-if="is_filling_ended === 0" type="primary" @click="handleSaveTemporarily()">暂存</el-button>
+          <el-button v-if="is_filling_ended === 0" type="primary" @click="handleSaveTemporarily(1)">暂存</el-button>
         </el-col>
         <el-col :span="1.5">
-          <el-button v-if="is_filling_ended === 0" type="primary" @click="handleData()">数据</el-button>
+          <el-button v-if="reportInfo.issued_status === 2" type="primary" @click="handleData()">数据</el-button>
         </el-col>
         <el-col :span="1.5">
-          <el-button v-if="is_filling_ended === 0" type="primary" @click="handleSave()">发布</el-button>
+          <el-button v-if="is_filling_ended === 0" type="primary" @click="handleSave(2)">发布</el-button>
         </el-col>
         <el-col :span="1.5">
           <el-button type="danger" @click="handleReturn()">返回</el-button>
         </el-col>
       </el-row>
-      <el-col :lg="30" :xs="24" style="">
-        <el-row :span="24" :gutter="10">
-          <el-col :span="8">
-            <el-form-item label="联系人姓名:" prop="creator_name" label-width="auto">
-              <div>{{ reportInfo.creator_name }}</div>
-            </el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <el-form-item label="联系电话:" prop="creator_phone" label-width="auto">
-              <div>{{ reportInfo.creator_phone }}</div>
-            </el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <el-form-item label="截止时间:" prop="release_time">
-              <div>{{ reportInfo.end_time }}</div>
-              <span class="label">前报送该表</span>
-            </el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <el-form-item label="表名:" prop="table_name" label-width="auto">
-              <div>{{ reportInfo.table_name }}</div>
-            </el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <el-form-item label="" prop="people_name" label-width="auto">
-              <el-form-item label="选择填报人:" prop="user_ids" label-width="auto" style="font-weight: bold">
-                <div>
-                  <el-tag
-                    v-for="tag in selectedReporter"
-                    :key="tag"
-                    closable
-                    :disable-transitions="false"
-                    @close="handleClose(tag)"
-                    style="margin-right: 10px"
-                  >
-                    {{ tag.label }}
-                  </el-tag>
-                </div>
-                <el-button @click="showSelect">点击选择</el-button>
-              </el-form-item>
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-col>
     </el-row>
+    <el-form :model="reportInfo" :rules="rules" ref="formRef" style="margin-top: 20px">
+      <el-row :gutter="20">
+        <el-col :lg="30" :xs="24" style="margin-top: -10px">
+          <el-row :span="24" :gutter="10">
+            <!-- 联系人姓名 -->
+            <el-col :span="8">
+              <el-form-item label="联系人姓名:" prop="creator_name" label-width="auto">
+                <el-input v-model="reportInfo.creator_name" placeholder="请输入联系人姓名" style="width: 300px"></el-input>
+              </el-form-item>
+            </el-col>
+            <!-- 联系电话 -->
+            <el-col :span="8">
+              <el-form-item label="联&nbsp系&nbsp电&nbsp话:" prop="creator_phone" label-width="auto">
+                <el-input v-model="reportInfo.creator_phone" placeholder="请输入联系电话" style="width: 300px"></el-input>
+              </el-form-item>
+            </el-col>
+            <!-- 截止时间 -->
+            <el-col :span="8">
+              <el-form-item label="截&nbsp止&nbsp时&nbsp间&nbsp:" prop="end_time">
+                <el-date-picker v-model="reportInfo.end_time" value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm" type="datetime" placeholder="选择截止时间" style="width: 300px" @change="handleTimeChange" />
+              </el-form-item>
+            </el-col>
+            <!-- 操作按钮 -->
+            <el-col :span="8">
+              <el-form-item label="表&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp名:" prop="table_name" label-width="auto">
+                <el-input v-model="reportInfo.table_name" placeholder="请输入表名" style="width: 300px"></el-input>
+              </el-form-item>
+            </el-col>
+            <!-- 选择填报人 -->
+            <el-col :span="8">
+              <el-form-item label="" prop="people_name" label-width="auto">
+                <el-form-item label="选择填报人:" prop="user_ids" label-width="auto" style="font-weight: bold">
+                  <div>
+                    <el-tag
+                      v-for="tag in selectedReporter"
+                      :key="tag"
+                      closable
+                      :disable-transitions="false"
+                      @close="handleClose(tag)"
+                      style="margin-right: 10px"
+                    >
+                      {{ tag.label }}
+                    </el-tag>
+                  </div>
+                  <el-button @click="showSelect">点击选择</el-button>
+                </el-form-item>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-col>
+      </el-row>
+    </el-form>
   </div>
-  <div style="height: 350px">
+  <div style="height: 350px; margin-left: 10px">
     <hot-table v-if="tableData && tableData.length > 0" ref="wrapper" :data="tableData" :settings="hotSettings" />
     <hot-table v-if="isShowTable" ref="wrapper" :data="hotData" :settings="hotSettings" />
   </div>
@@ -82,13 +90,16 @@
 
 <script setup lang="ts">
 import * as XLSX from 'xlsx';
-import { fillingList } from '@/api/dataFilling/fillingManage';
+import { fillingAdd, fillingChange, fillingList, fillingRelease } from '@/api/dataFilling/fillingManage';
 import { useRouter } from 'vue-router';
 import { HotTable } from '@handsontable/vue3';
 import { getPhoneList } from '@/api/informationissue/informationissue';
 import informantSelect from './informantSelect.vue';
 import { deepClone } from '@/utils';
+import { ElButton, ElCol, ElDatePicker, ElFormItem, ElInput, ElRow } from 'element-plus';
+import { validatePhone } from '@/utils/validate';
 
+const { proxy } = getCurrentInstance();
 const isShowSelect = ref(false);
 let treeData = ref([]);
 const emits = defineEmits(['close']);
@@ -110,8 +121,19 @@ const reportInfo = ref({
   updated_at: '',
   num_reported: 0,
   num_unreported: 0,
+  field_names: [], //表格内容
   user_ids: []
 });
+const rules = {
+  table_name: [{ required: true, message: '表名不能为空', trigger: 'blur' }],
+  end_time: [{ required: true, message: '截止时间不能为空', trigger: 'blur' }],
+  creator_name: [{ required: true, message: '联系人姓名不能为空', trigger: 'blur' }],
+  creator_phone: [
+    { required: true, message: '联系电话不能为空', trigger: 'blur' },
+    { validator: validatePhone, message: '请输入正确格式的联系电话', trigger: 'blur' }
+  ],
+  user_ids: [{ required: true, message: '请选择填报人', trigger: 'blur' }],
+}
 const is_filling_ended = ref(0);
 const tableData = ref([]);
 const selectedReporter = ref(null);
@@ -123,6 +145,12 @@ const props = defineProps({
 const reportId = ref(props.eventId);
 
 watch(reportId, async (newVal) => {
+  // tableData.value = [];
+  //
+  //
+  // nextTick(() => {
+  //   tableData.value = [{id: 1}];
+  // })
   if (newVal) {
     await fetchReportDetails(newVal);
   }
@@ -299,31 +327,52 @@ const handleReload = () => {
   alert('表格已清空');
 };
 
-const handleSaveTemporarily = () => {
-  alert('数据已暂存');
+const handleSaveTemporarily = async (statuCode) => {
+  if (hotData.value && hotData.value[0] && hotData.value[0].length > 0) {
+    const data2 = [];
+    hotData.value[0].forEach((item) => {
+      if (!!item) {
+        data2.push(item);
+      }
+    })
+    reportInfo.value.field_names = tableData.value;
+  }
+
+  reportInfo.value.issued_status = statuCode;
+  const tempHead = reportInfo.value.field_names.flatMap(obj =>
+    Object.values(obj).filter(value => typeof value === "string")
+  );
+  let data = {
+    table_name: reportInfo.value.table_name,
+    status: reportInfo.value.issued_status,
+    period_type: reportInfo.value.period_type,
+    end_time: reportInfo.value.end_time,
+    new_fields: tempHead
+  }
+  fillingChange(reportId.value, data).then(() => {
+    proxy.$modal.msgSuccess('暂存成功');
+    emits('close');
+  });
 };
 
 const handleReport = () => console.log('上报');
 
-const handleSave = async () => {
-  const data = {
+const handleSave = async (statuCode) => {
+  reportInfo.value.issued_status = statuCode;
+  const tempHead = reportInfo.value.field_names.flatMap(obj =>
+    Object.values(obj).filter(value => typeof value === "string")
+  );
+  let data = {
     table_name: reportInfo.value.table_name,
-    data_table_name: reportInfo.value.data_table_name,
-    start_time: reportInfo.value.start_time,
-    end_time: reportInfo.value.end_time,
-    status: reportInfo.value.status,
-    issued_status: reportInfo.value.issued_status,
+    status: reportInfo.value.issued_status,
     period_type: reportInfo.value.period_type,
-    creator_name: reportInfo.value.creator_name,
-    creator_id: reportInfo.value.creator_id,
-    creator_phone: reportInfo.value.creator_phone, // 使用 reportInfo 中的 creator_phone
-    field_names: tableData.value,
-    user_ids: []
-  };
-  const response = await fillingList(data); // 确保 fillingAdd 函数被定义
-  if (response && response.success) {
-    alert('数据已成功保存');
+    end_time: reportInfo.value.end_time,
+    new_fields: tempHead
   }
+  fillingChange(reportId.value, data).then(() => {
+    proxy.$modal.msgSuccess('发布成功');
+    emits('close');
+  });
 };
 
 const handleReturn = () => {