Kaynağa Gözat

代码提交优化

yjwang 2 hafta önce
ebeveyn
işleme
2745e9550b
1 değiştirilmiş dosya ile 306 ekleme ve 22 silme
  1. 306 22
      src/views/store/storeConfig/userInfo.vue

+ 306 - 22
src/views/store/storeConfig/userInfo.vue

@@ -434,15 +434,35 @@
           <el-upload
             class="upload-demo"
             :action="uploadUrl"
-            :on-preview="handlePreview"
             :on-remove="handleRemove"
             :before-remove="beforeRemove"
-            multiple
             :limit="1"
             :on-exceed="handleExceed"
-            :on-success="(response, file) => handleFileSuccess(response, file, 'reportUrl')"
-            :file-list="reportFileList">
-            <el-button size="small" type="primary">点击上传</el-button>
+            :on-success="(response, file) => handleReportUploadSuccess(response, file, 'reportUrl')"
+            :before-upload="beforeReportUpload"
+            :disabled="!!form.reportUrl"
+            accept=".jpg,.jpeg,.png,.gif,.bmp,.pdf"
+          >
+            <div class="report-file-wrapper" v-if="form.reportUrl">
+              <img
+                v-if="isImageFile(form.reportUrl)"
+                :src="form.reportUrl"
+                class="uploaded-file-thumb"
+                width="100px"
+                @click="viewReportFile('reportUrl')"
+              />
+              <div v-else class="document-file-icon" @click="viewReportFile('reportUrl')">
+                <i class="el-icon-document"></i>
+                <span class="file-name">{{ getFileName(form.reportUrl) }}</span>
+              </div>
+            </div>
+            <div v-else class="upload-btn-wrapper">
+              <el-button size="small" type="primary">点击上传</el-button>
+            </div>
+            <div v-if="form.reportUrl" class="report-preview-btn">
+              <el-button size="mini" type="success" @click.stop="viewReportFile('reportUrl')">查看已上传文件</el-button>
+              <el-button size="mini" type="danger" @click.stop="handleReportRemove('reportUrl')">删除</el-button>
+            </div>
           </el-upload>
         </el-form-item>
       </el-col>
@@ -451,15 +471,35 @@
           <el-upload
             class="upload-demo"
             :action="uploadUrl"
-            :on-preview="handlePreview"
             :on-remove="handleRemove"
             :before-remove="beforeRemove"
-            :on-success="(response, file) => handleFileSuccess(response, file, 'filingUrl')"
-             multiple
             :limit="1"
             :on-exceed="handleExceed"
-            :file-list="fileList">
-            <el-button size="small" type="primary">点击上传</el-button>
+            :on-success="(response, file) => handleReportUploadSuccess(response, file, 'filingUrl')"
+            :before-upload="beforeReportUpload"
+            :disabled="!!form.filingUrl"
+            accept=".jpg,.jpeg,.png,.gif,.bmp,.pdf"
+          >
+            <div class="report-file-wrapper" v-if="form.filingUrl">
+              <img
+                v-if="isImageFile(form.filingUrl)"
+                :src="form.filingUrl"
+                class="uploaded-file-thumb"
+                width="100px"
+                @click="viewReportFile('filingUrl')"
+              />
+              <div v-else class="document-file-icon" @click="viewReportFile('filingUrl')">
+                <i class="el-icon-document"></i>
+                <span class="file-name">{{ getFileName(form.filingUrl) }}</span>
+              </div>
+            </div>
+            <div v-else class="upload-btn-wrapper">
+              <el-button size="small" type="primary">点击上传</el-button>
+            </div>
+            <div v-if="form.filingUrl" class="report-preview-btn">
+              <el-button size="mini" type="success" @click.stop="viewReportFile('filingUrl')">查看已上传文件</el-button>
+              <el-button size="mini" type="danger" @click.stop="handleReportRemove('filingUrl')">删除</el-button>
+            </div>
           </el-upload>
         </el-form-item>
       </el-col>
@@ -514,7 +554,7 @@
             </el-radio-group>
           </el-form-item>
         </el-col>
-        <el-col :span="12">
+        <el-col :span="12" v-if="false">
           <el-form-item label="分佣方式" prop="brokerageType">
             <el-radio-group v-model="form.brokerageType" disabled>
               <el-radio label="1" >每盒</el-radio>
@@ -523,7 +563,7 @@
           </el-form-item>
          </el-col>
       </el-row>
-      <el-form-item label="配送方式" prop="shippingType">
+      <el-form-item label="配送方式" prop="shippingType" v-if="false">
         <el-checkbox-group v-model="form.shippingType" size="medium">
           <el-checkbox v-for="(item, index) in shippingTypeOptions" :key="index" :label="item.value"
                        :disabled="item.disabled">{{item.label}}</el-checkbox>
@@ -540,9 +580,39 @@
       <el-button @click="close">关 闭</el-button>
     </div>
 
-    <!-- 修改图片预览对话框,增加更大的预览尺寸 -->
-    <el-dialog :visible.sync="imagePreviewVisible" width="1100px" append-to-body :modal-append-to-body="false" @close="imagePreviewVisible = false">
-      <img :src="previewImageUrl" style="width: 100%; height: auto; max-height: 700px; object-fit: contain;" />
+    <!-- 图片预览对话框,支持鼠标滚轮缩放 -->
+    <el-dialog :visible.sync="imagePreviewVisible" width="1100px" append-to-body :modal-append-to-body="false" @close="onImagePreviewClose">
+      <div slot="title">
+        <span>图片预览</span>
+        <span style="margin-left: 16px; font-size: 13px; color: #909399;">{{ previewScale }}%</span>
+      </div>
+      <div
+        class="img-preview-body"
+        @wheel.prevent="onPreviewWheel"
+        @mousedown="onImgMouseDown"
+        @mousemove="onImgMouseMove"
+        @mouseup="onImgMouseUp"
+        @mouseleave="onImgMouseUp"
+      >
+        <img
+          :src="previewImageUrl"
+          :style="{
+            transform: `translate(${dragOffset.x}px, ${dragOffset.y}px) scale(${previewScale / 100})`,
+            transition: isDragging ? 'none' : 'transform .15s',
+            cursor: isDragging ? 'grabbing' : (previewScale > 100 ? 'grab' : 'default')
+          }"
+          style="max-width: 100%; max-height: 65vh; user-select: none;"
+          @dragstart.prevent
+        />
+      </div>
+      <div slot="footer" class="dialog-footer" style="text-align: left;">
+        <el-button-group>
+          <el-button size="small" icon="el-icon-zoom-out" :disabled="previewScale <= 25" @click="zoomOut">缩小</el-button>
+          <el-button size="small" icon="el-icon-refresh" @click="resetZoom">复位</el-button>
+          <el-button size="small" icon="el-icon-zoom-in" :disabled="previewScale >= 300" @click="zoomIn">放大</el-button>
+        </el-button-group>
+        <el-button size="small" style="float: right;" @click="imagePreviewVisible = false">关 闭</el-button>
+      </div>
     </el-dialog>
 
   </div>
@@ -562,6 +632,30 @@ export default {
       fileList:[],
       previewImageUrl: '', // 添加预览图片URL
       imagePreviewVisible: false,// 添加图片预览对话框可见性控制
+      previewScale: 100, // 预览图片缩放比例
+      dragOffset: { x: 0, y: 0 }, // 拖动偏移
+      isDragging: false, // 是否正在拖动
+      dragStart: { x: 0, y: 0 }, // 拖动起始坐标
+      originalForm: null, // 原始表单快照
+      excludedFields: [
+        'storeId', 'createTime', 'updateTime',
+        'balance', 'totalMoney', 'salesCount', 'productCount',
+        'qualificationUpdateTime', 'nextQualificationUpdateTime', 'daysDiff', 'remainDays',
+        'permStatus', 'storeSeq', 'merchantId', 'selectableProductTypes',
+        'doctorList', 'queryStoreId', 'hasErpInfo',
+        'shippingType', 'brokerageType', 'brokerageRate', 'status',
+        'password', 'licenseImages'
+      ],
+      agreementFields: [
+        'settlementAgreement', 'settlementAgreementFileName', 'settlementAgreementCode',
+        'settlementAgreementStart', 'settlementAgreementEnd', 'settlementAgreementExpiry', 'settlementAgreementFileType',
+        'qualityAssuranceAgreement', 'qualityAssuranceAgreementFileName', 'qualityAssuranceAgreementCode',
+        'qualityAssuranceAgreementStart', 'qualityAssuranceAgreementEnd', 'qualityAssuranceAgreementExpiry', 'qualityAssuranceAgreementFileType',
+        'otherSpecialQualification', 'otherSpecialQualificationFileName', 'otherSpecialQualificationCode',
+        'otherSpecialQualificationStart', 'otherSpecialQualificationEnd', 'otherSpecialQualificationExpiry', 'otherSpecialQualificationFileType',
+        'titleNameOne', 'titleNameTwo', 'titleNameThree',
+        'isEffectivePermanent1', 'isEffectivePermanent2', 'isEffectivePermanent3'
+      ],
       switchMedicalValue: false,
       dialogVisible: false,
       switchValue: false,
@@ -633,15 +727,9 @@ export default {
         licenseImages: [
           { required: true, message: '资质证书不能为空', trigger: 'blur' }
         ],
-        shippingType: [
-          { required: true, message: '配送方式不能为空', trigger: 'blur' }
-        ],
         account: [
           { required: true, message: '登录账号不能为空', trigger: 'blur' }
         ],
-        brokerageType: [
-          { required: true, message: '分佣方式不能为空', trigger: 'blur' }
-        ],
         refundPhone: [
           { required: true, message: '退货电话不能为空', trigger: 'blur' }
         ],
@@ -780,10 +868,11 @@ export default {
     // 添加图片预览方法
     previewImage(url) {
       this.previewImageUrl = url;
+      this.previewScale = 100;
       this.imagePreviewVisible = true;
     },
 
-    //店铺logo
+    // 店铺logo
     handleAvatarSuccess(res, file) {
       if (res.code == 200) {
         this.form.logoUrl = res.url
@@ -799,6 +888,128 @@ export default {
       }
       return isLt1M
     },
+
+    // 图片预览缩放相关
+    onImagePreviewClose() {
+      this.previewScale = 100;
+      this.dragOffset = { x: 0, y: 0 };
+      this.isDragging = false;
+      this.imagePreviewVisible = false;
+    },
+    zoomOut() {
+      if (this.previewScale > 25) {
+        this.previewScale = Math.max(25, this.previewScale - 25);
+        this.dragOffset = { x: 0, y: 0 };
+      }
+    },
+    zoomIn() {
+      if (this.previewScale < 300) {
+        this.previewScale = Math.min(300, this.previewScale + 25);
+      }
+    },
+    resetZoom() {
+      this.previewScale = 100;
+      this.dragOffset = { x: 0, y: 0 };
+    },
+    onPreviewWheel(e) {
+      if (e.deltaY < 0) {
+        this.zoomIn()
+      } else {
+        this.zoomOut()
+      }
+    },
+    onImgMouseDown(e) {
+      this.isDragging = true;
+      this.dragStart = { x: e.clientX - this.dragOffset.x, y: e.clientY - this.dragOffset.y };
+    },
+    onImgMouseMove(e) {
+      if (!this.isDragging) return;
+      this.dragOffset = {
+        x: e.clientX - this.dragStart.x,
+        y: e.clientY - this.dragStart.y
+      };
+    },
+    onImgMouseUp() {
+      this.isDragging = false;
+    },
+
+    // 网销报告/备案文件相关
+    isImageFile(url) {
+      if (!url) return false;
+      return /\.(jpg|jpeg|png|gif|bmp|webp)(\?|$)/i.test(url);
+    },
+    getFileName(url) {
+      if (!url) return '';
+      const parts = url.split('/');
+      return parts[parts.length - 1] || url;
+    },
+    handleReportUploadSuccess(response, file, field) {
+      if (response.code === 200) {
+        this.$set(this.form, field, response.url);
+        this.$message.success(`文件:${file.name}上传成功`);
+        this.$forceUpdate();
+      } else {
+        this.msgError(response.msg);
+      }
+    },
+    handleReportRemove(field) {
+      this.$set(this.form, field, '');
+      this.$message.info('文件已移除');
+    },
+    beforeReportUpload(file) {
+      const acceptTypes = [
+        'image/jpeg', 'image/png', 'image/gif', 'image/bmp',
+        'application/pdf'
+      ];
+      if (!acceptTypes.includes(file.type)) {
+        this.$message.error('仅支持 JPG/PNG/GIF/BMP 图片或 PDF 文件');
+        return false;
+      }
+      const maxSize = 10 * 1024 * 1024;
+      if (file.size > maxSize) {
+        this.$message.error('文件大小不能超过 10MB');
+        return false;
+      }
+      return true;
+    },
+    viewReportFile(field) {
+      const url = this.form[field];
+      if (!url) {
+        this.$message.warning('暂无文件');
+        return;
+      }
+      if (this.isImageFile(url)) {
+        this.previewImageUrl = url;
+        this.previewScale = 100;
+        this.imagePreviewVisible = true;
+      } else {
+        window.open(url, '_blank');
+      }
+    },
+
+    // 表单变更检测
+    fieldsEqual(a, b) {
+      if (a === b) return true;
+      if (a == null && b == null) return true;
+      if (a == null || b == null) return false;
+      if (Array.isArray(a) && Array.isArray(b)) {
+        if (a.length !== b.length) return false;
+        return a.every((v, i) => this.fieldsEqual(v, b[i]));
+      }
+      if ((a === '' && b === null) || (a === null && b === '')) return true;
+      return String(a) === String(b);
+    },
+    getChangedFields(original, current) {
+      const changed = [];
+      for (const key of Object.keys(original)) {
+        if (this.excludedFields.indexOf(key) !== -1) continue;
+        if (!this.fieldsEqual(original[key], current[key])) {
+          changed.push(key);
+        }
+      }
+      return changed;
+    },
+
     //关闭
     close() {
       this.$store.dispatch('tagsView/delView', this.$route)
@@ -914,6 +1125,7 @@ export default {
         foodLicenseBusinessScope: null,
       };
       this.resetForm('form')
+      this.originalForm = null;
     },
     //所有的日期控件校验
     checkDate(){
@@ -979,6 +1191,14 @@ export default {
           if(!this.checkDate()){
             return;
           }
+          const isEdit = this.form.storeId != null;
+          if (isEdit && this.originalForm) {
+            const changedFields = this.getChangedFields(this.originalForm, this.form);
+            if (changedFields.length === 0) {
+              this.$message.warning("未检测到任何修改,无需提交");
+              return;
+            }
+          }
           // 营业执照是必填项,直接进行校验
           businessLicenseCheck({ imageUrl: this.form.businessLicense }).then(checkResponse => {
             if (checkResponse.data.flag === false) {
@@ -1047,6 +1267,7 @@ export default {
           startField: 'settlementAgreementStart',
           endField: 'settlementAgreementEnd',
           agreementField: 'settlementAgreement',
+          permanentFlag: this.form.isEffectivePermanent1 == 1,
           message: '其它资质-入驻协议,有效期开始日期或结束日期不能为空!'
         },
         {
@@ -1054,6 +1275,7 @@ export default {
           startField: 'qualityAssuranceAgreementStart',
           endField: 'qualityAssuranceAgreementEnd',
           agreementField: 'qualityAssuranceAgreement',
+          permanentFlag: this.form.isEffectivePermanent2 == 1,
           message: '质量保证协议,有效期开始日期或结束日期不能为空!'
         },
         {
@@ -1061,10 +1283,12 @@ export default {
           startField: 'otherSpecialQualificationStart',
           endField: 'otherSpecialQualificationEnd',
           agreementField: 'otherSpecialQualification',
+          permanentFlag: this.form.isEffectivePermanent3 == 1,
           message: '其它特殊资质,有效期开始日期或结束日期不能为空!'
         }
       ]
       for (const field of agreementFields) {
+        if (field.permanentFlag) continue;
         if (formData[field.expiryField] && formData[field.expiryField].length === 2) {
           formData[field.startField] = formData[field.expiryField][0]
           formData[field.endField] = formData[field.expiryField][1]
@@ -1186,6 +1410,7 @@ export default {
         }
         this.reportFileList = this.urlToFileList(this.form.reportUrl);
         this.fileList = this.urlToFileList(this.form.filingUrl);
+        this.originalForm = JSON.parse(JSON.stringify(this.form));
       })
     },
     //长期有效营业执照选择
@@ -1455,4 +1680,63 @@ export default {
   cursor: pointer;
   font-size: 14px;
 }
+
+.report-file-wrapper {
+  display: inline-block;
+}
+
+.uploaded-file-thumb {
+  width: 100px;
+  height: 100px;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+  cursor: pointer;
+  vertical-align: middle;
+}
+
+.document-file-icon {
+  width: 150px;
+  height: 100px;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  background-color: #f5f7fa;
+  cursor: pointer;
+  vertical-align: middle;
+}
+
+.document-file-icon .el-icon-document {
+  font-size: 32px;
+  color: #409eff;
+  margin-bottom: 4px;
+}
+
+.document-file-icon .file-name {
+  font-size: 12px;
+  color: #606266;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  max-width: 120px;
+  text-align: center;
+}
+
+.upload-btn-wrapper {
+  display: inline-block;
+}
+
+.report-preview-btn {
+  margin-top: 8px;
+}
+
+.img-preview-body {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  overflow: hidden;
+  min-height: 200px;
+}
 </style>