zhangwencui
11 小时以前 bebc6b4464c4a3be2f5f51484260d5fcc67306ce
隐患排查附件功能开发
已添加1个文件
已修改2个文件
588 ■■■■■ 文件已修改
src/pages.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/safeProduction/dangerInvestigation/fileList.vue 566 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/safeProduction/dangerInvestigation/index.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json
@@ -752,6 +752,13 @@
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/safeProduction/dangerInvestigation/fileList",
      "style": {
        "navigationBarTitleText": "隐患排查上报附件",
        "navigationStyle": "custom"
      }
    },
  ],
  "subPackages": [
    {
src/pages/safeProduction/dangerInvestigation/fileList.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,566 @@
<template>
  <view class="file-list-page">
    <!-- é¡µé¢å¤´éƒ¨ -->
    <PageHeader title="附件管理"
                @back="goBack" />
    <!-- é™„件列表 -->
    <view class="file-list-container">
      <view v-if="fileList.length > 0"
            class="file-list">
        <view v-for="(file, index) in fileList"
              :key="file.id || index"
              class="file-item">
          <!-- æ–‡ä»¶å›¾æ ‡ -->
          <!-- <view class="file-icon"
                :class="getFileIconClass(file.fileType)">
            <up-icon :name="getFileIcon(file.fileType)"
                     size="24"
                     color="#ffffff" />
          </view> -->
          <!-- æ–‡ä»¶ä¿¡æ¯ -->
          <view class="file-info">
            <text class="file-name">{{ file.name }}</text>
            <!-- <text class="file-meta">{{ formatFileSize(file.fileSize) }} Â· {{ file.uploadTime || file.createTime }}</text> -->
          </view>
          <!-- æ“ä½œæŒ‰é’® -->
          <view class="file-actions">
            <!-- <u-button size="small"
                      type="primary"
                      plain
                      @click="previewFile(file)">预览</u-button> -->
            <u-button size="small"
                      type="info"
                      plain
                      @click="downloadFile(file)">下载并预览</u-button>
            <u-button size="small"
                      type="error"
                      plain
                      @click="confirmDelete(file, index)">删除</u-button>
          </view>
        </view>
      </view>
      <!-- ç©ºçŠ¶æ€ -->
      <view v-else
            class="empty-state">
        <up-icon name="document"
                 size="64"
                 color="#c0c4cc" />
        <text class="empty-text">暂无附件</text>
      </view>
    </view>
    <!-- <a rel="nofollow"
       id="downloadLink"
       href="#"
       style="display:none;">下载文本文件</a> -->
    <!-- ä¸Šä¼ æŒ‰é’® -->
    <view class="upload-button"
          @click="chooseFile">
      <up-icon name="plus"
               size="24"
               color="#ffffff" />
      <text class="upload-text">上传附件</text>
    </view>
  </view>
</template>
<script setup>
  import { ref, onMounted } from "vue";
  import PageHeader from "@/components/PageHeader.vue";
  import config from "@/config";
  import { getToken } from "@/utils/auth";
  // import { saveAs } from "file-saver";
  import {
    listRuleFiles,
    delRuleFile,
  } from "@/api/managementMeetings/rulesRegulationsManagement";
  import {
    safeHiddenFileAdd,
    fileListPage,
    safeHiddenFileDel,
  } from "@/api/safeProduction/dangerInvestigation";
  import { blobValidate } from "@/utils/ruoyi";
  // é™„件列表
  const fileList = ref([]);
  // è¿”回上一页
  const goBack = () => {
    uni.navigateBack();
  };
  // const request = axios.create({
  //   baseURL: "URL.com",
  //   adapter: axiosAdapterUniapp,
  // });
  // èŽ·å–æ–‡ä»¶å›¾æ ‡
  const getFileIcon = fileType => {
    const iconMap = {
      doc: "document",
      docx: "document",
      xls: "grid",
      xlsx: "grid",
      pdf: "document",
      ppt: "copy",
      pptx: "copy",
      txt: "document",
      jpg: "image",
      jpeg: "image",
      png: "image",
      gif: "image",
      zip: "folder",
      rar: "folder",
    };
    return iconMap[fileType.toLowerCase()] || "document";
  };
  // èŽ·å–æ–‡ä»¶å›¾æ ‡æ ·å¼ç±»
  const getFileIconClass = fileType => {
    const colorMap = {
      doc: "blue",
      docx: "blue",
      xls: "green",
      xlsx: "green",
      pdf: "red",
      ppt: "orange",
      pptx: "orange",
      txt: "gray",
      jpg: "purple",
      jpeg: "purple",
      png: "purple",
      gif: "purple",
      zip: "yellow",
      rar: "yellow",
    };
    return colorMap[fileType.toLowerCase()] || "gray";
  };
  // æ ¼å¼åŒ–文件大小
  const formatFileSize = bytes => {
    if (bytes === 0) return "0 B";
    const k = 1024;
    const sizes = ["B", "KB", "MB", "GB"];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
  };
  // é€‰æ‹©æ–‡ä»¶
  const chooseFile = () => {
    uni.chooseImage({
      count: 9,
      sizeType: ["original", "compressed"],
      sourceType: ["album", "camera"],
      success: res => {
        console.log(res, "选择图片成功");
        uploadFiles(res.tempFiles);
      },
      fail: err => {
        console.error("选择图片失败:", err);
        showToast("选择文件失败");
      },
    });
    // uni.chooseFile({
    //   count: 9,
    //   extension: [
    //     ".doc",
    //     ".docx",
    //     ".xls",
    //     ".xlsx",
    //     ".pdf",
    //     ".ppt",
    //     ".pptx",
    //     ".txt",
    //     ".jpg",
    //     ".jpeg",
    //     ".png",
    //     ".gif",
    //     ".zip",
    //     ".rar",
    //   ],
    //   success: res => {
    //     console.log(res, "选择文件成功");
    //     uploadFiles(res.tempFiles);
    //   },
    //   fail: err => {
    //     showToast("选择文件失败");
    //   },
    // });
  };
  // ä¸Šä¼ æ–‡ä»¶
  const uploadFiles = tempFiles => {
    console.log(tempFiles, "上传文件1");
    tempFiles.forEach((tempFile, index) => {
      // æ˜¾ç¤ºä¸Šä¼ ä¸­æç¤º
      uni.showLoading({
        title: "上传中...",
        mask: true,
      });
      console.log(tempFile, "上传文件2");
      // 1. ç›´æŽ¥ä½¿ç”¨ uni.uploadFile ä¸Šä¼ æ–‡ä»¶
      uni.uploadFile({
        url: config.baseUrl + "/file/upload",
        filePath: tempFile.path,
        name: "file",
        header: {
          Authorization: "Bearer " + getToken(),
        },
        success: uploadRes => {
          uni.hideLoading();
          console.log(uploadRes, "上传文件3");
          try {
            const res = JSON.parse(uploadRes.data);
            console.log(res, "上传文件4");
            if (res.code === 200) {
              // 2. æå–文件信息
              const fileName = tempFile.name
                ? tempFile.name
                : tempFile.path.split("/").pop();
              // const fileType = fileName.split(".").pop();
              // 3. æž„造保存文件信息的参数
              const saveData = {
                name: fileName,
                safeHiddenId: rulesRegulationsManagementId.value,
                url: res.data.tempPath || "",
              };
              console.log(saveData, "保存文件信息参数");
              // 4. è°ƒç”¨ addRuleFile æŽ¥å£ä¿å­˜æ–‡ä»¶ä¿¡æ¯
              safeHiddenFileAdd(saveData)
                .then(addRes => {
                  if (addRes.code === 200) {
                    // 5. æ·»åŠ åˆ°æ–‡ä»¶åˆ—è¡¨
                    const newFile = {
                      ...addRes.data,
                      uploadTime: new Date().toLocaleString(),
                    };
                    // fileList.value.push(newFile);
                    getFileList();
                    showToast("上传成功");
                  } else {
                    showToast("保存文件信息失败");
                  }
                })
                .catch(err => {
                  console.error("保存文件信息失败:", err);
                  showToast("保存文件信息失败");
                });
            } else {
              showToast("文件上传失败");
            }
          } catch (e) {
            console.error("解析上传结果失败:", e);
            showToast("上传失败");
          }
        },
        fail: err => {
          uni.hideLoading();
          console.error("上传失败:", err);
          showToast("上传失败");
        },
      });
    });
  };
  // ä¸‹è½½æ–‡ä»¶
  const downloadFile = file => {
    var url =
      config.baseUrl +
      "/common/download?fileName=" +
      encodeURIComponent(file.url) +
      "&delete=true";
    console.log(url, "url");
    uni
      .downloadFile({
        url: url,
        responseType: "blob",
        header: { Authorization: "Bearer " + getToken() },
      })
      .then(res => {
        let osType = uni.getStorageSync("deviceInfo").osName;
        let filePath = res.tempFilePath;
        if (osType === "ios") {
          uni.openDocument({
            filePath: filePath,
            showMenu: true,
            success: res => {
              resolve(res);
            },
            fail: err => {
              console.log("uni.openDocument--fail");
              reject(err);
            },
          });
        } else {
          uni.saveFile({
            tempFilePath: filePath,
            success: fileRes => {
              uni.showToast({
                icon: "none",
                mask: true,
                title:
                  "文件已保存:Android/data/uni.UNI720216F/apps/__UNI__720216F/" +
                  fileRes.savedFilePath, //保存路径
                duration: 3000,
              });
              setTimeout(() => {
                //打开文档查看
                uni.openDocument({
                  filePath: fileRes.savedFilePath,
                  success: function (res) {
                    resolve(fileRes);
                  },
                });
              }, 3000);
            },
            fail: err => {
              console.log("uni.save--fail");
              reject(err);
            },
          });
        }
        // const isBlob = blobValidate(res.data);
        // if (isBlob) {
        //   const blob = new Blob([res.data], { type: "text/plain" });
        //   const url = URL.createObjectURL(blob);
        //   const downloadLink = document.getElementById("downloadLink");
        //   downloadLink.href = url;
        //   downloadLink.download = file.name;
        //   downloadLink.click();
        //   showToast("下载成功");
        // } else {
        //   showToast("下载失败");
        // }
      })
      .catch(err => {
        console.error("下载失败:", err);
        showToast("下载失败");
      });
  };
  // ç¡®è®¤åˆ é™¤
  const confirmDelete = (file, index) => {
    uni.showModal({
      title: "删除确认",
      content: `确定要删除附件 "${file.name}" å—?`,
      success: res => {
        if (res.confirm) {
          deleteFile(file.id, index);
        }
      },
    });
  };
  // åˆ é™¤æ–‡ä»¶
  const deleteFile = (fileId, index) => {
    uni.showLoading({
      title: "删除中...",
      mask: true,
    });
    safeHiddenFileDel([fileId])
      .then(res => {
        uni.hideLoading();
        if (res.code === 200) {
          // fileList.value.splice(index, 1);
          getFileList();
          showToast("删除成功");
        } else {
          showToast("删除失败");
        }
      })
      .catch(err => {
        uni.hideLoading();
        showToast("删除失败");
      });
  };
  // æ˜¾ç¤ºæç¤º
  const showToast = message => {
    uni.showToast({
      title: message,
      icon: "none",
    });
  };
  const rulesRegulationsManagementId = ref("");
  // é¡µé¢åŠ è½½æ—¶
  onMounted(() => {
    rulesRegulationsManagementId.value = uni.getStorageSync(
      "dangerInvestigationFileId"
    );
    // ä»Ž API èŽ·å–é™„ä»¶åˆ—è¡¨
    getFileList();
    // ä»Žæœ¬åœ°å­˜å‚¨èŽ·å– rulesRegulationsManagementId
  });
  // èŽ·å–é™„ä»¶åˆ—è¡¨
  const getFileList = () => {
    uni.showLoading({
      title: "加载中...",
      mask: true,
    });
    fileListPage({
      safeHiddenId: rulesRegulationsManagementId.value,
      current: -1,
      size: -1,
    })
      .then(res => {
        uni.hideLoading();
        if (res.code === 200) {
          fileList.value = res.data.records || [];
        } else {
          showToast("获取附件列表失败");
        }
      })
      .catch(err => {
        uni.hideLoading();
        showToast("获取附件列表失败");
      });
  };
</script>
<style scoped lang="scss">
  @import "../../../styles/sales-common.scss";
  .file-list-page {
    min-height: 100vh;
    background: #f8f9fa;
    padding-bottom: 100rpx;
  }
  .file-list-container {
    padding: 20rpx;
  }
  .file-list {
    background: #ffffff;
    border-radius: 8rpx;
    overflow: hidden;
    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
  }
  .file-item {
    display: flex;
    align-items: center;
    padding: 20rpx;
    border-bottom: 1rpx solid #f0f0f0;
    &:last-child {
      border-bottom: none;
    }
  }
  .file-icon {
    width: 56rpx;
    height: 56rpx;
    border-radius: 8rpx;
    display: flex;
    justify-content: center;
    align-items: center;
    margin-right: 20rpx;
    &.blue {
      background: #409eff;
    }
    &.green {
      background: #67c23a;
    }
    &.red {
      background: #f56c6c;
    }
    &.orange {
      background: #e6a23c;
    }
    &.gray {
      background: #909399;
    }
    &.purple {
      background: #909399;
    }
    &.yellow {
      background: #e6a23c;
    }
  }
  .file-info {
    flex: 1;
    min-width: 0;
  }
  .file-name {
    display: block;
    font-size: 16px;
    color: #303133;
    margin-bottom: 8rpx;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .file-meta {
    display: block;
    font-size: 12px;
    color: #909399;
  }
  .file-actions {
    display: flex;
    gap: 12rpx;
  }
  .empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 100rpx 0;
    background: #ffffff;
    border-radius: 8rpx;
    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
  }
  .empty-text {
    font-size: 14px;
    color: #909399;
    margin-top: 20rpx;
  }
  .upload-button {
    position: fixed;
    bottom: 40rpx;
    right: 40rpx;
    width: 130rpx;
    height: 130rpx;
    border-radius: 50%;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.4);
    z-index: 1000;
  }
  .upload-text {
    font-size: 10px;
    color: #ffffff;
    margin-top: 4rpx;
  }
  .upload-progress {
    padding: 40rpx 0;
  }
  .upload-progress-text {
    display: block;
    text-align: center;
    margin-top: 20rpx;
    font-size: 14px;
    color: #606266;
  }
</style>
src/pages/safeProduction/dangerInvestigation/index.vue
@@ -137,6 +137,12 @@
                      @click="acceptanceVisit(item)">
              éªŒæ”¶
            </u-button>
            <u-button type="info"
                      size="small"
                      class="action-btn"
                      @click="viewFileList(item)">
              é™„ä»¶
            </u-button>
            <u-button type="error"
                      size="small"
                      class="action-btn"
@@ -202,6 +208,12 @@
  // è¿”回上一页
  const goBack = () => {
    uni.navigateBack();
  };
  const viewFileList = item => {
    uni.setStorageSync("dangerInvestigationFileId", item.id);
    uni.navigateTo({
      url: "/pages/safeProduction/dangerInvestigation/fileList",
    });
  };
  // æŸ¥è¯¢åˆ—表
@@ -349,5 +361,8 @@
    background: #667eea; // ä¿æŒé¡µé¢ç‰¹æœ‰çš„背景色
    box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3); // ä¿æŒé¡µé¢ç‰¹æœ‰çš„阴影效果
  }
  .action-buttons {
    gap: 4px;
  }
</style>