Hua 1 săptămână în urmă
părinte
comite
c1964ac777

+ 15 - 42
src/views/InspectDC/Object/Problem/addProblem.vue

@@ -226,47 +226,21 @@ async function addPro(){
     a.note = tacObjPblmstb.value.note
     a.inspPblmOrgName = tacObjPblmstb.value.inspPblmOrgName
     a.inspPblmDesc = tacObjPblmstb.value.inspPblmDesc
-    uploadFileToServer(fileList.value[0], '36c12e323dfd4623a18bf4ddaefebaaa')
-    // await request.post('/dc/insp/pblm', a).then((res) => {
-    //     if (res.success) {
-    //     showSuccessToast('保存成功!');
-    //     const formData = new FormData();
-    //     const file = fileList.value[0];
-    //     console.log('文件内容类型:', typeof file.content);
-    //     console.log('文件对象:', file);
-
-    //     // 情况1: 如果 file.content 是 Blob/File 对象
-    //     if (file.content instanceof Blob || file.content instanceof File) {
-    //         formData.append('file', file.content, file.name || 'file');
-    //     } 
-    //     // 情况2: 如果 file.content 是 base64 字符串
-    //     else if (typeof file.content === 'string' && file.content.startsWith('data:')) {
-    //     file.content = new File([file.content], file.name || 'file', {
-    //         type: file.type || 'application/octet-stream',
-    //         lastModified: Date.now()
-    //     });
-    //     }
-    //     // 情况3: 如果 file.content 是其他格式
-    //     else {
-    //     // 尝试转换为 Blob
-    //         const blob = new Blob([file.content], { type: file.type || 'application/octet-stream' });
-    //         formData.append('file', blob, file.name || 'file');
-    //     }
-    //     request.post('pdcApi/file/insert?bizId=' + res.data.pblmId, formData, {
-    //     headers: {
-    //         // 不要手动设置Content-Type
-    //         'Accept': 'application/json'
-    //     },
-    //     // 禁用请求体转换(关键:避免request库将FormData转为JSON)
-    //     transformRequest: [data => data],
-    //     // 确保请求体是FormData原生格式
-    //     processData: false,
-    //     contentType: false
-    //     }).then((res) => {
-                    
-    //             });
-    //     }
-    // });
+    if(tacObjPblmstb.value.pblmDesc){
+        await request.post('/dc/insp/pblm', a).then((res) => {
+            if (res.success) {
+                fileList.value.forEach(item => {
+                    uploadFileToServer(item, res.data.pblmId)
+                })
+                showSuccessToast('添加成功!');
+                // tacObjPblmstb.value = {}
+                // fileList.value = []
+            }
+        });
+    }
+    else{
+        showFailToast('请选择一个问题描述!')
+    }
 }
 const dataURLtoBlob = (dataURL) => {
   try {
@@ -370,7 +344,6 @@ const uploadFileToServer = async (file, bizId) => {
       headers: {
         'Content-Type': contentType, // 带boundary的标准格式
         'Accept': 'application/json',
-        'Orgid': appStore.currentOrgId || '034',
         'Persid': userStore.userId,
         'Accesstoken': token,
         'Cache-Control': 'no-cache'

+ 234 - 0
src/views/Problem/detail/indexDc.vue

@@ -75,6 +75,10 @@
         <van-field v-model="tacObjPblmstb.score" readonly label="扣分值" />
         <van-field v-model="tacObjPblmstb.persName" readonly label="上报人" />
         <van-field v-model="tacObjPblmstb.collTime" readonly label="上报时间" />
+        <div style="display: flex;align-items: center;margin-top: -1%;">
+            <div style="width: 20%;text-align: center;font-weight: 700;font-size: 14px;">上传照片</div>
+            <van-uploader v-model="fileList" :after-read="afterRead" style=""/>
+        </div>
       </van-cell-group>
       <div style="margin: 16px;">
         <van-button @click="save" block native-type="submit" round type="primary">
@@ -95,15 +99,18 @@ import {computed, onMounted, ref, watch} from "vue";
 import {useRoute} from "vue-router";
 import tacObjPblmstbList from './TacObjPblmstbList.vue';
 import {getTacQuestionById} from "@/api/inspect";
+import { showConfirmDialog } from 'vant';
 import {addTacQuestion, getIllegalActById, getTacUnitList} from "@/api/questions";
 import {useUserStore} from "@/stores/user";
 import request from "@/utils/request";
 const route = useRoute();
 const userStore = useUserStore();
+const fileList = ref([]);
 const listType = ref(route.query.inspectType || '1');
 const pblm = ref({});
 const tacObjPblmstb =  ref({
 });
+const url = process.env.VUE_APP_BASE_HOST + process.env.VUE_APP_BASE_API
 const columns = ref([]);
 const columns1 = ref([]);
 const columns2 = ref([]);
@@ -123,6 +130,7 @@ const router = useRoute();
 const parSectino = ref([]);
 const subjectList = ref([]);
 const tacObjPblmstbShow = ref(false);
+const accessToken = localStorage.getItem('accessToken') || '';
 function onConfirm3(selectedValues, selectedOptions) {
   tacObjPblmstb.value.ifCasePblm = selectedValues.selectedOptions[0].text
   showPicker3.value = false;
@@ -221,9 +229,54 @@ function getDe(){
                 }
                 columns2.value = [...new Set(columns2.value.map(item => JSON.stringify(item)))].map(str => JSON.parse(str))
             })
+            res.data.gwComFiles.forEach(item => {
+                item.filePath = item.filePath.replace(/\\/g, '/');
+                fileList.value.push({
+                    url: url + item.filePath,
+                    name: item.fileName,
+                    isImage: true,
+                    id: item.id
+                })
+                console.log(fileList.value);
+            })
         }
     })
 }
+// 获取需要认证的图片并转换为 base64
+async function getAuthImageAsBase64(imageUrl) {
+    try {
+        // 1. 使用 fetch 请求图片,携带 token
+        const response = await fetch(imageUrl, {
+            headers: {
+                'Authorization': `Bearer ${localStorage.getItem('token')}`,
+                'X-Token': localStorage.getItem('token') // 根据实际情况调整
+            }
+        });
+        
+        if (!response.ok) {
+            throw new Error(`HTTP错误: ${response.status}`);
+        }
+        
+        // 2. 获取图片的 ArrayBuffer
+        const arrayBuffer = await response.arrayBuffer();
+        
+        // 3. 转换为 base64
+        const base64 = btoa(
+            new Uint8Array(arrayBuffer).reduce(
+                (data, byte) => data + String.fromCharCode(byte),
+                ''
+            )
+        );
+        
+        // 4. 根据图片类型生成 data URL
+        const contentType = response.headers.get('content-type') || 'image/png';
+        return `data:${contentType};base64,${base64}`;
+        
+    } catch (error) {
+        console.error('获取认证图片失败:', error);
+        throw error;
+    }
+}
 async function save(){
     console.log(tacObjPblmstb.value);
     tacObjPblmstb.value.ifCasePblm = tacObjPblmstb.value.ifCasePblm === '是' ? '1' : '0';
@@ -233,6 +286,10 @@ async function save(){
     delete tacObjPblmstb.value.collTime;
     await request.post('/dc/insp/pblm/update', tacObjPblmstb.value).then((res) => {
         if (res.success) {
+            
+            if(newFile.value && newFile.value.id){
+                uploadFileToServer(newFile.value, parData.value.pblmId)
+            }
             showSuccessToast('保存成功!');
         }
     });
@@ -269,6 +326,183 @@ watch(() => tacObjPblmstb.value.checkPoint, (newVal, oldVal) => {
         })
     }
 });
+function getObjectArrayDiff(arr1, arr2, key) {
+  if (!key) throw new Error('必须指定对比的唯一字段(如id)');
+
+  // 提取两个数组的key值集合
+  const keySet1 = new Set(arr1.map(item => item[key]));
+  const keySet2 = new Set(arr2.map(item => item[key]));
+
+  // 仅在arr1中存在的对象
+  const onlyInArr1 = arr1.filter(item => !keySet2.has(item[key]));
+  // 仅在arr2中存在的对象
+  const onlyInArr2 = arr2.filter(item => !keySet1.has(item[key]));
+  // 所有差异对象(合并)
+  const allDiff = [...onlyInArr1, ...onlyInArr2];
+
+  return {
+    onlyInArr1,
+    onlyInArr2,
+    allDiff
+  };
+}
+const dataURLtoBlob = (dataURL) => {
+  try {
+    const arr = dataURL.split(',');
+    const mime = arr[0].match(/:(.*?);/)[1];
+    const bstr = atob(arr[1]);
+    let n = bstr.length;
+    const u8arr = new Uint8Array(n);
+    while (n--) {
+      u8arr[n] = bstr.charCodeAt(n);
+    }
+    return new Blob([u8arr], { type: mime });
+  } catch (e) {
+    console.error('base64转Blob失败:', e);
+    return new Blob([], { type: 'application/octet-stream' });
+  }
+};
+
+// 2. 手动构建multipart/form-data(保留之前验证正确的逻辑)
+const buildMultipartFormData = async (file) => {
+  if (!file) throw new Error('文件为空');
+
+  // 生成标准boundary
+  const boundary = `----WebKitFormBoundary${Math.random().toString(36).substr(2, 16)}`;
+
+  // 处理文件为Blob
+  let fileBlob;
+  if (file.content instanceof Blob || file.content instanceof File) {
+    fileBlob = file.content;
+  } else if (typeof file.content === 'string' && file.content.startsWith('data:')) {
+    fileBlob = dataURLtoBlob(file.content);
+  } else {
+    throw new Error(`不支持的文件格式: ${typeof file.content}`);
+  }
+
+  // 读取文件为ArrayBuffer
+  const fileBuffer = await new Promise((resolve, reject) => {
+    const reader = new FileReader();
+    reader.onload = () => resolve(reader.result);
+    reader.onerror = reject;
+    reader.readAsArrayBuffer(fileBlob);
+  });
+
+  // 手动拼接multipart格式(字符串转Uint8Array,兼容App端)
+  const stringToUint8Array = (str) => {
+    const arr = [];
+    for (let i = 0; i < str.length; i++) {
+      arr.push(str.charCodeAt(i));
+    }
+    return new Uint8Array(arr);
+  };
+
+  const parts = [];
+  // 拼接分隔符+元信息
+  parts.push(stringToUint8Array(`--${boundary}\r\n`));
+  parts.push(stringToUint8Array(`Content-Disposition: form-data; name="file"; filename="${encodeURIComponent(file.name || 'upload.png')}"\r\n`));
+  parts.push(stringToUint8Array(`Content-Type: ${fileBlob.type || 'application/octet-stream'}\r\n\r\n`));
+  // 拼接文件二进制数据
+  parts.push(new Uint8Array(fileBuffer));
+  // 拼接结束分隔符
+  parts.push(stringToUint8Array(`\r\n--${boundary}--\r\n`));
+
+  // 合并所有片段
+  const totalLength = parts.reduce((sum, part) => sum + part.length, 0);
+  const resultBuffer = new Uint8Array(totalLength);
+  let offset = 0;
+  parts.forEach(part => {
+    resultBuffer.set(part, offset);
+    offset += part.length;
+  });
+
+  return {
+    body: resultBuffer,
+    contentType: `multipart/form-data; boundary=${boundary}`
+  };
+};
+
+// 3. 核心:改用Fetch API上传文件(替换Axios)
+const uploadFileToServer = async (file, bizId) => {
+  if (!file || !bizId) {
+    showFailToast('文件或业务ID为空');
+    return null;
+  }
+
+  try {
+    // 构建标准multipart请求体
+    const { body, contentType } = await buildMultipartFormData(file);
+    
+    // 获取token和自定义头(和Axios拦截器一致)
+    const appStore = useAppStore();
+    const userStore = useUserStore();
+    const token = getToken();
+
+    // 拼接完整接口地址(补充baseURL,和你的request封装一致)
+    const baseURL = process.env.VUE_APP_BASE_API;
+    const fullUrl = `${baseURL}/file/insert?bizId=${bizId}`;
+
+    // 使用Fetch API发送请求(原生支持二进制,无兼容性问题)
+    const formData = new FormData();
+    formData.append('file', fileList.value[0].content); // 文件参数
+    const response = await fetch(fullUrl, {
+      method: 'POST',
+      headers: {
+        'Content-Type': contentType, // 带boundary的标准格式
+        'Accept': 'application/json',
+        'Persid': userStore.userId,
+        'Accesstoken': token,
+        'Cache-Control': 'no-cache'
+      },
+      body: new Blob([body], { type: contentType }), // 二进制请求体
+      timeout: 30000,
+      credentials: 'include' // 保持cookie/token会话(和Axios一致)
+    });
+
+    // 解析响应
+    if (!response.ok) {
+      throw new Error(`请求失败: ${response.status}`);
+    }
+    const resData = await response.json();
+    console.log('文件上传成功:', resData);
+    return resData;
+
+  } catch (error) {
+    console.error('文件上传失败:', error);
+    showFailToast('文件上传失败');
+    throw error;
+  }
+};
+// /pdcApi/file
+const newFile = ref({})
+const isAdding = ref(false);
+watch(() => fileList.value, (newVal, oldVal) => {
+    if (newVal.length>oldVal.length) {
+        isAdding.value = true;
+        newFile.value = getObjectArrayDiff(newVal, oldVal, 'id').onlyInArr1[0]
+        console.log(newFile.value.onlyInArr1);
+        
+    }
+    else{
+        isAdding.value = false;
+        newFile.value = getObjectArrayDiff(newVal, oldVal, 'id').onlyInArr2[0];
+        showConfirmDialog({
+        title: '删除',
+        message:
+            '是否确认删除',
+        })
+        .then(() => {
+            request.post(`/file/${newFile.value.id}`).then(res=>{
+                if(res.success){
+                    showSuccessToast('删除成功!');
+                }
+            })
+        })
+        .catch(() => {
+            fileList.value = oldVal;
+        });
+            }
+});
 onMounted(() => {
   var par = JSON.parse(router.query.object);
   pblm.value.objId = par.objId