From d43d7b9c90ae36c2d369f5c52b207b5549675766 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 03 二月 2026 15:33:07 +0800
Subject: [PATCH] 双奇点改造 1.产品维护添加图片、高度等字段

---
 multiple/config.json                              |   20 +-
 src/views/basicData/product/index.vue             |  326 ++++++++++++++++++++++++++++++++++++++++++++--
 multiple/assets/favicon/SQDico.ico                |    0 
 multiple/assets/screen/SQDView.png                |    0 
 src/views/basicData/product/ImportExcel/index.vue |   59 +++++++-
 multiple/assets/logo/SQDLogo.png                  |    0 
 6 files changed, 370 insertions(+), 35 deletions(-)

diff --git a/multiple/assets/favicon/SQDico.ico b/multiple/assets/favicon/SQDico.ico
new file mode 100644
index 0000000..cd34955
--- /dev/null
+++ b/multiple/assets/favicon/SQDico.ico
Binary files differ
diff --git a/multiple/assets/logo/SQDLogo.png b/multiple/assets/logo/SQDLogo.png
new file mode 100644
index 0000000..271f835
--- /dev/null
+++ b/multiple/assets/logo/SQDLogo.png
Binary files differ
diff --git a/multiple/assets/screen/SQDView.png b/multiple/assets/screen/SQDView.png
new file mode 100644
index 0000000..f53a22f
--- /dev/null
+++ b/multiple/assets/screen/SQDView.png
Binary files differ
diff --git a/multiple/config.json b/multiple/config.json
index 7ad6795..a760667 100644
--- a/multiple/config.json
+++ b/multiple/config.json
@@ -3,19 +3,19 @@
     "env": {
       "VITE_APP_TITLE": "鑺浜戯紙绠$悊淇℃伅绯荤粺锛�"
     },
-    "screen": "screen/JZYJView.png",
-    "logo": "logo/HYSNLogo.png",
-    "favicon": "favicon/HYSNico.ico"
+    "screen": "screen/SQDView.png",
+    "logo": "logo/SQDLogo.png",
+    "favicon": "favicon/SQDico.ico"
   },
-  "TEST": {
+  "SQD": {
     "env": {
-      "VITE_APP_TITLE": "涓皬浼佷笟鏁板瓧鍖栬浆鍨嬩簩绾у椁愬寘",
-      "VITE_BASE_API": "http://1.15.17.182:9003",
-      "VITE_JAVA_API": "http://1.15.17.182:9002"
+      "VITE_APP_TITLE": "澶╂触鍙屽鐐圭鐞嗙郴缁�",
+      "VITE_BASE_API": "http://114.132.189.42:9042",
+      "VITE_JAVA_API": "http://114.132.189.42:9044"
     },
-    "screen": "screen/HYSNView.png",
-    "logo": "logo/ZGLTLogo.png",
-    "favicon": "favicon/favicon.ico"
+    "screen": "screen/SQDView.png",
+    "logo": "logo/SQDLogo.png",
+    "favicon": "favicon/SQDico.ico"
   },
   "screen": "/src/assets/images/login-background.png",
   "logo": "/src/assets/logo/logo.png",
diff --git a/src/views/basicData/product/ImportExcel/index.vue b/src/views/basicData/product/ImportExcel/index.vue
index c25d254..68b6913 100644
--- a/src/views/basicData/product/ImportExcel/index.vue
+++ b/src/views/basicData/product/ImportExcel/index.vue
@@ -3,15 +3,36 @@
     瀵煎叆
   </el-button>
   <el-dialog v-model="upload.open" :title="upload.title">
-    <FileUpload
-      ref="fileUploadRef"
+    <el-upload
+      ref="uploadRef"
+      :limit="1"
       accept=".xlsx, .xls"
       :headers="upload.headers"
       :action="upload.url + '?updateSupport=' + upload.updateSupport"
       :disabled="upload.isUploading"
-      :showTip="false"
-      @success="handleFileSuccess"
-    />
+      :before-upload="upload.beforeUpload"
+      :on-progress="upload.onProgress"
+      :on-success="upload.onSuccess"
+      :on-error="upload.onError"
+      :on-change="upload.onChange"
+      :auto-upload="false"
+      drag
+    >
+      <el-icon class="el-icon--upload"><UploadFilled /></el-icon>
+      <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
+      <template #tip>
+        <div class="el-upload__tip text-center">
+          <span>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</span>
+          <el-link
+            type="primary"
+            :underline="false"
+            style="font-size: 12px; vertical-align: baseline"
+            @click="handleDownloadTemplate"
+            >涓嬭浇妯℃澘</el-link
+          >
+        </div>
+      </template>
+    </el-upload>
     <template #footer>
       <div class="dialog-footer">
         <el-button type="primary" @click="submitFileForm">纭� 瀹�</el-button>
@@ -22,17 +43,18 @@
 </template>
 
 <script setup>
-import { reactive } from "vue";
+import { reactive, ref, getCurrentInstance } from "vue";
 import { getToken } from "@/utils/auth.js";
-import { FileUpload } from "@/components/Upload";
 import { ElMessage } from "element-plus";
+import { UploadFilled } from "@element-plus/icons-vue";
 
 defineOptions({
   name: "浜у搧缁存姢瀵煎叆",
 });
 
 const emits = defineEmits(["uploadSuccess"]);
-const fileUploadRef = ref();
+const uploadRef = ref();
+const { proxy } = getCurrentInstance();
 const upload = reactive({
   // 鏄惁鏄剧ず寮瑰嚭灞傦紙渚涘簲鍟嗗鍏ワ級
   open: false,
@@ -44,6 +66,20 @@
   headers: { Authorization: "Bearer " + getToken() },
   // 涓婁紶鐨勫湴鍧�
   url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import",
+  updateSupport: false,
+  beforeUpload: () => {
+    upload.isUploading = true;
+  },
+  onProgress: () => {},
+  onChange: () => {},
+  onError: () => {
+    upload.isUploading = false;
+    ElMessage({ message: "涓婁紶澶辫触", type: "error" });
+  },
+  onSuccess: (response) => {
+    upload.isUploading = false;
+    handleFileSuccess(response);
+  },
 });
 // 鐐瑰嚮瀵煎叆
 const handleImport = () => {
@@ -51,8 +87,13 @@
   upload.title = "浜у搧瀵煎叆";
 };
 
+// 涓嬭浇瀵煎叆妯℃澘
+const handleDownloadTemplate = () => {
+  proxy.download("/basic/product/downloadTemplate", {}, "浜у搧瀵煎叆妯℃澘.xlsx");
+};
+
 const submitFileForm = () => {
-  fileUploadRef.value.uploadApi();
+  uploadRef.value.submit();
 };
 
 const handleFileSuccess = (response) => {
diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue
index c9058aa..4b36793 100644
--- a/src/views/basicData/product/index.vue
+++ b/src/views/basicData/product/index.vue
@@ -92,7 +92,18 @@
         @selection-change="handleSelectionChange"
         :tableLoading="tableLoading"
         @pagination="pagination"
-      ></PIMTable>
+      >
+        <template #productImage="{ row }">
+          <img
+            v-if="row.url"
+            class="upload-img"
+            :src="javaApiUrl + row.url"
+            @click="previewImage(row.url)"
+            style="cursor: pointer"
+          />
+          <span v-else style="color: #909399">鏆傛棤鍥剧墖</span>
+        </template>
+      </PIMTable>
     </div>
     <el-dialog v-model="productDia" title="浜у搧" width="400px" @keydown.enter.prevent>
       <el-form
@@ -127,7 +138,7 @@
     <el-dialog
       v-model="modelDia"
       title="瑙勬牸鍨嬪彿"
-      width="400px"
+      width="600px"
       @close="closeModelDia"
       @keydown.enter.prevent
     >
@@ -138,8 +149,8 @@
         :rules="modelRules"
         ref="modelFormRef"
       >
-        <el-row>
-          <el-col :span="24">
+        <el-row :gutter="20">
+          <el-col :span="12">
             <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="model">
               <el-input
                 v-model="modelForm.model"
@@ -149,9 +160,7 @@
               />
             </el-form-item>
           </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="24">
+          <el-col :span="12">
             <el-form-item label="鍗曚綅锛�" prop="unit">
               <el-input
                 v-model="modelForm.unit"
@@ -159,6 +168,79 @@
                 clearable
                 @keydown.enter.prevent
               />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="楂樺害锛�" prop="height">
+              <el-input
+                v-model="modelForm.height"
+                placeholder="璇疯緭鍏ラ珮搴�"
+                clearable
+                @keydown.enter.prevent
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="姣忎欢鏁伴噺/鏀細" prop="boxNum">
+              <el-input-number
+                :step="1"
+                :min="0"
+                style="width: 100%"
+                v-model="modelForm.boxNum"
+                @change="calculateTotalPrice"
+                placeholder="璇疯緭鍏ユ瘡浠舵暟閲�"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鍗曚环(鍏�)/浠讹細" prop="taxInclusiveUnitPrice">
+              <el-input-number
+                :step="0.01"
+                :min="0"
+                style="width: 100%"
+                v-model="modelForm.taxInclusiveUnitPrice"
+                @change="calculateTotalPrice"
+                placeholder="璇疯緭鍏ュ崟浠�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍗曚环(缇庡厓)/浠讹細" prop="dollarPrice">
+              <el-input-number
+                :step="0.01"
+                :min="0"
+                style="width: 100%"
+                v-model="modelForm.dollarPrice"
+                placeholder="璇疯緭鍏ョ編鍏冨崟浠�"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="浜у搧鍥剧墖锛�" prop="url">
+              <el-upload
+                :action="uploadUrl"
+                :before-upload="handleBeforeUpload"
+                :on-success="(res, file) => handleUploadSuccess(res, file)"
+                :on-error="handleUploadError"
+                name="file"
+                :show-file-list="false"
+                :headers="headers"
+                accept="image/*"
+                :data="{ type: 13 }"
+              >
+                <img
+                  v-if="modelForm.url"
+                  class="upload-img-dialog"
+                  :src="javaApiUrl + modelForm.url"
+                />
+                <el-icon v-else class="avatar-uploader-icon-dialog"><Plus /></el-icon>
+              </el-upload>
             </el-form-item>
           </el-col>
         </el-row>
@@ -174,8 +256,10 @@
 </template>
 
 <script setup>
-import { ref } from "vue";
+import { ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue";
 import { ElMessageBox } from "element-plus";
+import { Plus } from "@element-plus/icons-vue";
+import { getToken } from "@/utils/auth";
 import {
   addOrEditProduct,
   addOrEditProductModel,
@@ -185,6 +269,7 @@
   productTreeList,
 } from "@/api/basicData/product.js";
 import ImportExcel from "./ImportExcel/index.vue";
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
 
 const { proxy } = getCurrentInstance();
 const tree = ref(null);
@@ -202,12 +287,40 @@
 const expandedKeys = ref([]);
 const tableColumn = ref([
   {
+    label: "浜у搧鍥剧墖",
+    prop: "url",
+    dataType: "slot",
+    slot: "productImage",
+    align: "center",
+    width: 100,
+  },
+  {
     label: "瑙勬牸鍨嬪彿",
     prop: "model",
   },
   {
     label: "鍗曚綅",
     prop: "unit",
+  },
+  {
+    label: "楂樺害",
+    prop: "height",
+    width: 120,
+  },
+  {
+    label: "姣忎欢鏁伴噺/鏀�",
+    prop: "boxNum",
+    width: 120,
+  },
+  {
+    label: "鍗曚环(鍏�)/浠�",
+    prop: "taxInclusiveUnitPrice",
+    width: 120,
+  },
+  {
+    label: "鍗曚环(缇庡厓)/浠�",
+    prop: "dollarPrice",
+    width: 130,
   },
   {
     dataType: "action",
@@ -228,6 +341,11 @@
 const tableLoading = ref(false);
 const isShowButton = ref(false);
 const selectedRows = ref([]);
+
+// 涓婁紶閰嶇疆
+const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃
+const headers = ref({ Authorization: "Bearer " + getToken() });
+const javaApiUrl = proxy.javaApi || import.meta.env.VITE_APP_BASE_API;
 const page = reactive({
   current: 1,
   size: 10,
@@ -246,10 +364,20 @@
   modelForm: {
     model: "",
     unit: "",
+    url: "",
+    height: "",
+    boxNum: null,
+    taxInclusiveUnitPrice: null,
+    dollarPrice: null,
   },
   modelRules: {
-    model: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    unit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    model: [{ required: true, message: "璇疯緭鍏ヨ鏍煎瀷鍙�", trigger: "blur" }],
+    unit: [{ required: true, message: "璇疯緭鍏ュ崟浣�", trigger: "blur" }],
+    url: [{ required: true, message: "璇蜂笂浼犱骇鍝佸浘鐗�", trigger: "change" }],
+    height: [{ required: true, message: "璇疯緭鍏ラ珮搴�", trigger: "blur" }],
+    boxNum: [{ required: true, message: "璇疯緭鍏ユ瘡浠舵暟閲�/鏀�", trigger: "change" }],
+    taxInclusiveUnitPrice: [{ required: true, message: "璇疯緭鍏ュ崟浠�(鍏�)/浠�", trigger: "change" }],
+    dollarPrice: [{ required: true, message: "璇疯緭鍏ュ崟浠�(缇庡厓)/浠�", trigger: "change" }],
   },
 });
 const { form, rules, modelForm, modelRules } = toRefs(data);
@@ -285,11 +413,30 @@
 const openModelDia = (type, data) => {
   modelOperationType.value = type;
   modelDia.value = true;
-  modelForm.value.model = "";
-  modelForm.value.model = "";
-  modelForm.value.id = "";
-  if (type === "edit") {
-    modelForm.value = { ...data };
+  // 閲嶇疆琛ㄥ崟
+  modelForm.value = {
+    model: "",
+    unit: "",
+    url: "",
+    height: "",
+    boxNum: null,
+    taxInclusiveUnitPrice: null,
+    dollarPrice: null,
+    id: "",
+  };
+  if (type === "edit" && data) {
+    // 濡傛灉 url 鏄� Windows 璺緞锛岄渶瑕佽浆鎹�
+    let url = data.url || "";
+    if (url && url.indexOf("\\") > -1) {
+      url = processFileUrl(url);
+    }
+    modelForm.value = {
+      ...data,
+      url: url,
+      boxNum: data.boxNum || null,
+      taxInclusiveUnitPrice: data.taxInclusiveUnitPrice || null,
+      dollarPrice: data.dollarPrice || null,
+    };
   }
 };
 // 鎻愪氦浜у搧鍚嶇О淇敼
@@ -391,10 +538,107 @@
     size: page.size,
   }).then((res) => {
     console.log("res", res);
-    tableData.value = res.records;
+    // 澶勭悊杩斿洖鐨勬暟鎹紝杞崲 Windows 璺緞涓哄彲璁块棶鐨� URL
+    tableData.value = (res.records || []).map((item) => {
+      if (item.url && item.url.indexOf("\\") > -1) {
+        item.url = processFileUrl(item.url);
+      }
+      return item;
+    });
     page.total = res.total;
     tableLoading.value = false;
   });
+};
+
+// 涓婁紶鍓嶆牎楠�
+const handleBeforeUpload = (file) => {
+  const isImage = file.type.startsWith("image/");
+  const isLt5M = file.size / 1024 / 1024 < 5;
+
+  if (!isImage) {
+    proxy.$modal.msgError("涓婁紶鏂囦欢鍙兘鏄浘鐗囨牸寮�!");
+    return false;
+  }
+  if (!isLt5M) {
+    proxy.$modal.msgError("涓婁紶鍥剧墖澶у皬涓嶈兘瓒呰繃 5MB!");
+    return false;
+  }
+  return true;
+};
+
+// 澶勭悊鏂囦欢璺緞锛氬皢 Windows 璺緞杞崲涓哄彲璁块棶鐨� URL
+const processFileUrl = (filePath) => {
+  if (!filePath) return "";
+  
+  // 濡傛灉璺緞鏄� Windows 璺緞鏍煎紡锛堝寘鍚弽鏂滄潬锛夛紝闇�瑕佽浆鎹�
+  if (filePath && filePath.indexOf("\\") > -1) {
+    // 鏌ユ壘 temp 鎴� uploads 鍏抽敭瀛楃殑浣嶇疆
+    const tempIndex = filePath.toLowerCase().indexOf("temp");
+    const uploadsIndex = filePath.toLowerCase().indexOf("uploads");
+    
+    if (tempIndex > -1) {
+      // 浠� temp 寮�濮嬫彁鍙栫浉瀵硅矾寰勶紝骞跺皢鍙嶆枩鏉犳浛鎹负姝f枩鏉�
+      const relativePath = filePath.substring(tempIndex).replace(/\\/g, "/");
+      filePath = "/" + relativePath;
+    } else if (uploadsIndex > -1) {
+      // 浠� uploads 寮�濮嬫彁鍙栫浉瀵硅矾寰�
+      const relativePath = filePath.substring(uploadsIndex).replace(/\\/g, "/");
+      filePath = "/" + relativePath;
+    } else {
+      // 濡傛灉娌℃湁鎵惧埌鍏抽敭瀛楋紝鎻愬彇鏂囦欢鍚�
+      const parts = filePath.split("\\");
+      const fileName = parts[parts.length - 1];
+      filePath = "/temp/uploads/" + fileName;
+    }
+  }
+  
+  // 纭繚璺緞浠� / 寮�澶�
+  if (filePath && !filePath.startsWith("/")) {
+    filePath = "/" + filePath;
+  }
+  
+  return filePath;
+};
+
+// 涓婁紶鎴愬姛
+const handleUploadSuccess = (res, file) => {
+  if (res.code === 200) {
+    // 浠� res.data 涓幏鍙� tempPath锛屽苟杞崲涓哄彲璁块棶鐨� URL
+    const tempPath = res.data?.tempPath || res.tempPath;
+    if (tempPath) {
+      const relativePath = processFileUrl(tempPath);
+      modelForm.value.url = relativePath;
+      proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
+      // 瑙﹀彂琛ㄥ崟楠岃瘉
+      nextTick(() => {
+        proxy.$refs.modelFormRef?.validateField("url");
+      });
+    } else {
+      proxy.$modal.msgError("涓婁紶鎴愬姛浣嗘湭杩斿洖鏂囦欢璺緞");
+    }
+  } else {
+    proxy.$modal.msgError(res.msg || "涓婁紶澶辫触");
+  }
+};
+
+// 涓婁紶澶辫触
+const handleUploadError = () => {
+  proxy.$modal.msgError("涓婁紶澶辫触锛岃閲嶈瘯");
+};
+
+// 璁$畻鎬讳环
+const calculateTotalPrice = () => {
+  // 濡傛灉闇�瑕佽绠楁�讳环锛屽彲浠ュ湪杩欓噷娣诲姞閫昏緫
+  // if (modelForm.value.boxNum && modelForm.value.taxInclusiveUnitPrice) {
+  //   modelForm.value.totalPrice = modelForm.value.boxNum * modelForm.value.taxInclusiveUnitPrice;
+  // }
+};
+
+// 棰勮鍥剧墖
+const previewImage = (url) => {
+  if (url) {
+    window.open(javaApiUrl + url, "_blank");
+  }
 };
 // 鍒犻櫎瑙勬牸鍨嬪彿
 const handleDelete = () => {
@@ -529,4 +773,54 @@
 .product-tree-scroll::-webkit-scrollbar-thumb:hover {
   background: #909399;
 }
+
+.upload-img {
+  width: 50px;
+  height: 50px;
+  object-fit: cover;
+  cursor: pointer;
+  border-radius: 4px;
+}
+
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 50px;
+  height: 50px;
+  line-height: 50px;
+  text-align: center;
+  border: 1px dashed #d9d9d9;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+.avatar-uploader-icon:hover {
+  border-color: #409eff;
+}
+
+.upload-img-dialog {
+  width: 100px;
+  height: 100px;
+  object-fit: cover;
+  cursor: pointer;
+  border-radius: 4px;
+  border: 1px solid #dcdfe6;
+}
+
+.avatar-uploader-icon-dialog {
+  font-size: 28px;
+  color: #8c939d;
+  width: 100px;
+  height: 100px;
+  line-height: 100px;
+  text-align: center;
+  border: 1px dashed #d9d9d9;
+  border-radius: 4px;
+  cursor: pointer;
+  display: block;
+}
+
+.avatar-uploader-icon-dialog:hover {
+  border-color: #409eff;
+}
 </style>

--
Gitblit v1.9.3