From 877c9a8df95ff61fbe556b8d1f4cf417252ee256 Mon Sep 17 00:00:00 2001
From: peng <peng.com>
Date: 星期四, 16 十月 2025 12:00:11 +0800
Subject: [PATCH] 用户行为分析

---
 seller/src/views/order/order/editTemplateModal.vue |  479 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 seller/src/api/order.js                            |   13 +
 seller/src/views/order/order/orderDetail.vue       |   40 +++
 3 files changed, 526 insertions(+), 6 deletions(-)

diff --git a/seller/src/api/order.js b/seller/src/api/order.js
index a5fbd57..ca8159a 100644
--- a/seller/src/api/order.js
+++ b/seller/src/api/order.js
@@ -168,3 +168,16 @@
 export const getTracesList = (sn) => {
   return getRequest(`/order/order/getTracesList/${sn}`);
 }
+
+
+//鑾峰彇妯℃澘
+export const getTemplate = (templateId) => {
+  return getRequest(`/order/order/getTemplate/${templateId}`);
+}
+
+//淇敼妯℃澘
+export const editTemplate = (params) => {
+  return postRequest(`/order/order/edit/template`,params,{
+    "Content-type": "application/json"
+  })
+}
diff --git a/seller/src/views/order/order/editTemplateModal.vue b/seller/src/views/order/order/editTemplateModal.vue
new file mode 100644
index 0000000..31b172d
--- /dev/null
+++ b/seller/src/views/order/order/editTemplateModal.vue
@@ -0,0 +1,479 @@
+<template>
+  <Modal
+    v-model="visible"
+    title="淇敼妯℃澘淇℃伅"
+    width="600"
+    @on-ok="handleOk"
+    @on-cancel="handleCancel"
+  >
+    <div v-if="loading" style="text-align: center; padding: 20px;">
+      <Spin size="large" />
+      <p>鍔犺浇涓�...</p>
+    </div>
+
+    <Form ref="form" :model="form" :label-width="100" v-else-if="templateData">
+      <FormItem label="妯℃澘ID">
+        <Input v-model="templateData.id" disabled />
+      </FormItem>
+
+      <FormItem label="妯℃澘鍚嶇О">
+        <Input v-model="form.templateName" disabled />
+      </FormItem>
+
+      <!-- 妯℃澘鍥剧墖閫夋嫨 -->
+      <FormItem
+        v-if="templateData.templateImgs && templateData.templateImgs.length > 0"
+        label="妯℃澘鍥剧墖"
+      >
+        <div class="image-grid">
+          <div
+            v-for="(img, index) in templateData.templateImgs"
+            :key="img.id"
+            class="image-item"
+            :class="{ selected: selectedImageId === img.id }"
+            @click="selectImage(img.id)"
+          >
+            <img :src="getImageUrl(img.imgUrl)" class="image-preview" />
+            <div v-if="selectedImageId === img.id" class="selected-overlay">
+              <Icon type="md-checkmark" size="30" color="#fff" />
+            </div>
+          </div>
+        </div>
+      </FormItem>
+
+      <!-- 鍔ㄦ�佽〃鍗曢」 -->
+      <div v-if="templateData.templateConstomizeTitles">
+        <FormItem
+          v-for="(item, index) in templateData.templateConstomizeTitles"
+          :key="item.id"
+          :label="item.templateTitle"
+        >
+          <!-- 鏂囨湰杈撳叆 -->
+          <Input
+            v-if="item.contentType === 'TEXT'"
+            v-model="formValues[item.id]"
+            :placeholder="'璇疯緭鍏�' + item.templateTitle"
+          />
+
+          <!-- 鍥剧墖涓婁紶 -->
+          <div v-if="item.contentType === 'IMAGE'" class="image-upload-container">
+            <!-- 鍥剧墖棰勮 -->
+            <div v-if="formValues[item.id]" class="image-preview-container">
+              <img :src="getImageUrl(formValues[item.id])" class="uploaded-image" />
+              <Icon
+                type="md-close"
+                class="delete-icon"
+                @click="removeImage(item.id)"
+              />
+            </div>
+
+            <!-- 涓婁紶鎸夐挳 -->
+            <div v-else class="upload-btn" @click="uploadImage(item.id)">
+              <Icon type="md-add" size="30" color="#999" />
+              <span>涓婁紶鍥剧墖</span>
+            </div>
+
+            <!-- 鏂囦欢閫夋嫨杈撳叆妗嗭紙闅愯棌锛� -->
+            <input
+              :ref="'fileInput' + item.id"
+              type="file"
+              accept="image/*"
+              style="display: none"
+              @change="handleFileSelect($event, item.id)"
+            />
+          </div>
+        </FormItem>
+      </div>
+
+      <!-- 璋冭瘯淇℃伅 -->
+<!--      <details style="margin-top: 20px; border: 1px solid #eee; padding: 10px;">-->
+<!--        <summary>璋冭瘯淇℃伅</summary>-->
+<!--        <pre>{{ JSON.stringify(templateData, null, 2) }}</pre>-->
+<!--        <p>閫変腑鐨勫浘鐗嘔D: {{ selectedImageId }}</p>-->
+<!--        <p>琛ㄥ崟鍊�: {{ JSON.stringify(formValues, null, 2) }}</p>-->
+<!--      </details>-->
+    </Form>
+
+    <div v-else>
+      <p>鏈姞杞藉埌妯℃澘鏁版嵁</p>
+    </div>
+
+    <div slot="footer">
+      <Button @click="handleCancel">鍙栨秷</Button>
+      <Button type="primary" @click="handleOk" :loading="loading">纭畾</Button>
+    </div>
+  </Modal>
+</template>
+
+<script>
+import * as API_Order from "@/api/order";
+import { getFilePreviewUrl, uploadFileByLmk } from "@/api/common.js";
+
+export default {
+  name: "EditTemplateModal",
+  props: {
+    value: {
+      type: Boolean,
+      default: false
+    },
+    templateId: {
+      type: [String, Number],
+      default: ""
+    },
+    // 娣诲姞璁㈠崟缂栧彿灞炴��
+    orderSn: {
+      type: String,
+      default: ""
+    }
+  },
+  data() {
+    return {
+      visible: this.value,
+      loading: false,
+      templateData: null,
+      form: {
+        templateName: ""
+      },
+      formValues: {},
+      selectedImageId: null,
+      currentUploadFieldId: null // 褰撳墠姝e湪涓婁紶鐨勫瓧娈礗D
+    };
+  },
+  watch: {
+    value(val) {
+      this.visible = val;
+      if (val) {
+        console.log("EditTemplateModal鎵撳紑锛屾帴鏀跺埌鐨勫弬鏁�:", {
+          templateId: this.templateId,
+          orderSn: this.orderSn
+        });
+        this.loadTemplateData();
+      }
+    },
+    visible(val) {
+      this.$emit("input", val);
+    }
+  },
+  methods: {
+    // 鍔犺浇妯℃澘鏁版嵁
+    async loadTemplateData() {
+      // 纭繚璁㈠崟缂栧彿鏄繀浼犵殑
+      if (!this.orderSn) {
+        this.$Message.error("璁㈠崟缂栧彿涓嶈兘涓虹┖");
+        console.error("璁㈠崟缂栧彿涓虹┖锛屽綋鍓嶅弬鏁�:", {
+          templateId: this.templateId,
+          orderSn: this.orderSn
+        });
+        return;
+      }
+
+      if (!this.templateId) {
+        this.$Message.error("妯℃澘ID涓嶈兘涓虹┖");
+        return;
+      }
+
+      try {
+        this.loading = true;
+        console.log("姝e湪鍔犺浇妯℃澘鏁版嵁锛屾ā鏉縄D:", this.templateId, "璁㈠崟缂栧彿:", this.orderSn);
+        const res = await API_Order.getTemplate(this.templateId);
+        console.log("鑾峰彇鍒扮殑妯℃澘鏁版嵁:", res);
+        if (res.code==200) {
+          this.templateData = res.data;
+          // 浣跨敤 name 瀛楁浣滀负妯℃澘鍚嶇О
+          this.form.templateName = res.data.name || "";
+
+          // 鍒濆鍖栬〃鍗曞��
+          this.formValues = {};
+          // 鍒濆鍖栭�変腑鐨勫浘鐗嘔D
+          this.selectedImageId = null;
+
+          if (res.data.templateConstomizeTitles) {
+            res.data.templateConstomizeTitles.forEach(item => {
+              // 鍥炴樉宸叉湁鐨勫��
+              if (item.value) {
+                this.$set(this.formValues, item.id, item.value);
+              } else {
+                // 鍒濆鍖栬〃鍗曞�硷紙濡傛灉娌℃湁榛樿鍊硷級
+                this.$set(this.formValues, item.id, "");
+              }
+            });
+          }
+
+          // 濡傛灉鏈夋ā鏉垮浘鐗囷紝璁剧疆榛樿閫変腑鐨勫浘鐗�
+          if (res.data.templateImgs && res.data.templateImgs.length > 0) {
+            // 濡傛灉宸叉湁閫変腑鐨勫浘鐗嘔D锛屽垯浣跨敤璇D锛屽惁鍒欓粯璁ら�変腑绗竴寮�
+            if (res.data.chooseImageId) {
+              this.selectedImageId = res.data.chooseImageId;
+            } else {
+              this.selectedImageId = res.data.templateImgs[0].id;
+            }
+          }
+
+          console.log("澶勭悊鍚庣殑鏁版嵁:", {
+            templateData: this.templateData,
+            formValues: this.formValues,
+            selectedImageId: this.selectedImageId
+          });
+        } else {
+          this.$Message.error(res.message || "鑾峰彇妯℃澘鏁版嵁澶辫触");
+        }
+      } catch (error) {
+        this.$Message.error("鍔犺浇妯℃澘鏁版嵁澶辫触: " + error.message);
+        console.error("鍔犺浇妯℃澘鏁版嵁澶辫触:", error);
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 鑾峰彇鍥剧墖URL
+    getImageUrl(fileKey) {
+      // 纭繚fileKey鏄瓧绗︿覆绫诲瀷
+      if (!fileKey || typeof fileKey !== 'string') {
+        console.warn('fileKey is not a valid string:', fileKey);
+        return ''; // 杩斿洖绌哄瓧绗︿覆鎴栭粯璁ゅ浘鐗�
+      }
+
+      // 瀹夊叏妫�鏌tartsWith鏂规硶鏄惁瀛樺湪
+      if (fileKey.startsWith && typeof fileKey.startsWith === 'function' &&
+          (fileKey.startsWith("http://") || fileKey.startsWith("https://"))) {
+        return fileKey;
+      }
+
+      // 鍚﹀垯杩斿洖fileKey锛岃缁勪欢鑷繁澶勭悊
+      return fileKey;
+    },
+
+    // 閫夋嫨鍥剧墖
+    selectImage(imageId) {
+      this.selectedImageId = imageId;
+    },
+
+    // 涓婁紶鍥剧墖
+    uploadImage(fieldId) {
+      this.currentUploadFieldId = fieldId;
+      // 瑙﹀彂鏂囦欢閫夋嫨
+      this.$refs['fileInput' + fieldId][0].click();
+    },
+
+    // 澶勭悊鏂囦欢閫夋嫨
+    async handleFileSelect(event, fieldId) {
+      const file = event.target.files[0];
+      if (!file) return;
+
+      // 楠岃瘉鏂囦欢绫诲瀷
+      if (file.type && !file.type.startsWith('image/')) {
+        this.$Message.error("璇烽�夋嫨鍥剧墖鏂囦欢");
+        return;
+      }
+
+      // 楠岃瘉鏂囦欢澶у皬锛堥檺鍒朵负5MB锛�
+      if (file.size > 5 * 1024 * 1024) {
+        this.$Message.error("鍥剧墖澶у皬涓嶈兘瓒呰繃5MB");
+        return;
+      }
+
+      try {
+        this.loading = true;
+        // 鍒涘缓FormData瀵硅薄
+        const formData = new FormData();
+        formData.append('file', file);
+
+        // 涓婁紶鏂囦欢
+        const res = await uploadFileByLmk(formData);
+        console.log('涓婁紶鏂囦欢杩斿洖缁撴灉:', res); // 娣诲姞璋冭瘯鏃ュ織
+        if (res.code === 200) {
+          // 涓婁紶鎴愬姛锛岃缃〃鍗曞��
+          // 纭繚res.data鏄瓧绗︿覆绫诲瀷
+          let fileKey = '';
+          if (typeof res.data === 'string') {
+            fileKey = res.data;
+          } else if (res.data && typeof res.data === 'object') {
+            // 濡傛灉杩斿洖鐨勬槸瀵硅薄锛屽皾璇曡幏鍙杅ileKey鎴杣rl瀛楁
+            fileKey = res.data.fileKey || res.data.url || '';
+          } else {
+            fileKey = String(res.data);
+          }
+
+          // 纭繚fileKey鏄瓧绗︿覆绫诲瀷
+          if (typeof fileKey !== 'string') {
+            fileKey = String(fileKey);
+          }
+
+          this.$set(this.formValues, fieldId, fileKey);
+          this.$Message.success("鍥剧墖涓婁紶鎴愬姛");
+        } else {
+          this.$Message.error(res.msg || "鍥剧墖涓婁紶澶辫触");
+        }
+      } catch (error) {
+        this.$Message.error("鍥剧墖涓婁紶澶辫触: " + (error.message || error));
+        console.error(error);
+      } finally {
+        this.loading = false;
+        // 娓呯┖鏂囦欢杈撳叆妗�
+        event.target.value = '';
+      }
+    },
+
+    // 绉婚櫎鍥剧墖
+    removeImage(fieldId) {
+      this.$set(this.formValues, fieldId, "");
+    },
+
+    // 鏋勯�犳彁浜ゅ弬鏁�
+    buildSubmitParams() {
+      const params = {
+        templateId: this.templateId,
+        // 娣诲姞璁㈠崟缂栧彿鍒版彁浜ゅ弬鏁�
+        sn: this.orderSn,
+        templateName: this.form.templateName,
+        chooseImageId: this.selectedImageId,
+        templateForm: []
+      };
+
+      // 娣诲姞琛ㄥ崟瀛楁
+      if (this.templateData && this.templateData.templateConstomizeTitles) {
+        this.templateData.templateConstomizeTitles.forEach(item => {
+          params.templateForm.push({
+            id: item.id,
+            templateTitle: item.templateTitle,
+            contentType: item.contentType,
+            value: this.formValues[item.id] || ""
+          });
+        });
+      }
+
+      console.log("鎻愪氦鍙傛暟:", params);
+      return params;
+    },
+
+    // 纭畾鎸夐挳
+    async handleOk() {
+      if (!this.templateData) {
+        this.$Message.error("娌℃湁鍙彁浜ょ殑妯℃澘鏁版嵁");
+        return;
+      }
+
+      this.loading = true;
+      try {
+        const params = this.buildSubmitParams();
+        const res = await API_Order.editTemplate(params);
+        if (res.code==200) {
+          this.$Message.success("妯℃澘淇℃伅淇敼鎴愬姛");
+          this.visible = false;
+          this.$emit("success");
+        } else {
+          this.$Message.error(res.message || "淇敼澶辫触");
+        }
+      } catch (error) {
+        this.$Message.error("淇敼澶辫触: " + error.message);
+        console.error(error);
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 鍙栨秷鎸夐挳
+    handleCancel() {
+      this.visible = false;
+      this.$emit("cancel");
+    }
+  }
+};
+</script>
+
+<style scoped>
+.image-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.image-item {
+  position: relative;
+  width: 100px;
+  height: 100px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  cursor: pointer;
+  overflow: hidden;
+}
+
+.image-item:hover {
+  border-color: #57a3f3;
+}
+
+.image-item.selected {
+  border-color: #57a3f3;
+  box-shadow: 0 0 0 2px rgba(45, 140, 240, 0.2);
+}
+
+.image-preview {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.selected-overlay {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.image-upload-container {
+  display: flex;
+  align-items: center;
+}
+
+.image-preview-container {
+  position: relative;
+  width: 100px;
+  height: 100px;
+  margin-right: 10px;
+}
+
+.uploaded-image {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+  border-radius: 4px;
+}
+
+.delete-icon {
+  position: absolute;
+  top: -8px;
+  right: -8px;
+  width: 20px;
+  height: 20px;
+  background-color: #ed4014;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  color: #fff;
+}
+
+.upload-btn {
+  width: 100px;
+  height: 100px;
+  border: 1px dashed #dcdee2;
+  border-radius: 4px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  color: #999;
+}
+
+.upload-btn:hover {
+  border-color: #57a3f3;
+  color: #57a3f3;
+}
+</style>
diff --git a/seller/src/views/order/order/orderDetail.vue b/seller/src/views/order/order/orderDetail.vue
index 9949108..727d99c 100644
--- a/seller/src/views/order/order/orderDetail.vue
+++ b/seller/src/views/order/order/orderDetail.vue
@@ -157,6 +157,7 @@
                   <div class="div-item-left">鍟嗗搧妯℃澘锛�</div>
                   <div class="div-item-right">
                     {{ item.templateName || '鏃犳ā鏉挎爣棰�' }} <!-- 澶勭悊绌哄�奸粯璁ゆ樉绀� -->
+                    <Button size="small" @click="editTemplateInfo(item.templateId, sn)" style="margin-left: 10px;">缂栬緫</Button>
                   </div>
                 </div>
                 <!-- 4. 閫夋嫨鍥剧墖锛氭覆鏌� chooseImg 瀛楁锛堝鐞� null/绌哄�硷級 -->
@@ -181,8 +182,6 @@
               </div>
             </div>
 
-
-
             <!-- 3. 鏂囨湰鍐呭锛氬垽鏂� content 鏄�屽浘鐗嘦RL銆嶈繕鏄�岀函鏂囨湰銆� -->
             <div class="div-item">
               <div class="div-item-left">{{isUrl(item.content)? '鍥剧墖锛�':'鏂囨湰鍐呭'}}</div>
@@ -198,8 +197,6 @@
                 <span v-else>{{ item.content || '鏃犳枃鏈唴瀹�' }}</span> <!-- 绾枃鏈�/绌哄�煎鐞� -->
               </div>
             </div>
-
-
 
             <!-- 鍙�夛細寰幆椤瑰垎闅旂嚎锛屼紭鍖栬瑙� -->
             <hr v-if="index !== orderInfo.userCheckTemplates.length - 1" style="margin: 15px 0; border: none; border-top: 1px solid #eee;">
@@ -642,6 +639,15 @@
     </Modal>
 
     <multipleMap ref="map" @callback="getAddress"></multipleMap>
+
+    <!-- 娣诲姞妯℃澘缂栬緫寮圭獥 -->
+    <EditTemplateModal
+      v-model="editTemplateModalVisible"
+      :template-id="currentTemplateId"
+      :order-sn="sn"
+      @success="handleTemplateEditSuccess"
+      @cancel="editTemplateModalVisible = false"
+    />
   </div>
 </template>
 
@@ -651,12 +657,13 @@
 import * as RegExp from "@/libs/RegExp.js";
 
 import multipleMap from "@/views/my-components/map/multiple-map";
-
+import EditTemplateModal from "./editTemplateModal.vue";
 
 export default {
   name: "orderDetail",
   components: {
     multipleMap,
+    EditTemplateModal
   },
   data () {
     return {
@@ -1013,7 +1020,10 @@
         },
       ],
       orderPackage: [],
-      packageTraceList: []
+      packageTraceList: [],
+      // 娣诲姞妯℃澘缂栬緫寮圭獥鐩稿叧鏁版嵁
+      editTemplateModalVisible: false,
+      currentTemplateId: ""
     };
   },
   methods: {
@@ -1423,6 +1433,24 @@
       })
     },
 
+    // 缂栬緫妯℃澘淇℃伅
+    editTemplateInfo(templateId, orderSn) {
+      console.log("璋冪敤editTemplateInfo锛屽弬鏁�:", {
+        templateId: templateId,
+        orderSn: orderSn
+      });
+      this.currentTemplateId = templateId;
+      this.editTemplateModalVisible = true;
+    },
+
+    // 妯℃澘缂栬緫鎴愬姛鍥炶皟
+    handleTemplateEditSuccess() {
+      this.editTemplateModalVisible = false;
+      // 鍙互鍦ㄨ繖閲屽埛鏂版暟鎹垨鎻愮ず鐢ㄦ埛
+      this.$Message.success("妯℃澘淇℃伅宸叉洿鏂�");
+      // 鍒锋柊璁㈠崟璇︽儏椤甸潰鏁版嵁
+      this.getDataDetail();
+    }
   },
   mounted () {
     this.sn = this.$route.query.sn;

--
Gitblit v1.8.0