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