فهرست منبع

1. hdApp 支持花材图文编辑
2. ghsApp 与 hdApp 花材图文编辑时,删除图片,补实现删除oss资源

shizhongqi 10 ماه پیش
والد
کامیت
0ee44db77e

+ 22 - 2
ghsApp/src/admin/item/picTextAdd-Edit.vue

@@ -1,13 +1,15 @@
 <template>
 <template>
   <view class="app-content">
   <view class="app-content">
     <form @submit="formSubmit">
     <form @submit="formSubmit">
-      <view class="module-com input-line-wrap">
+      <view class="module-com">
         <view class="editor-container">
         <view class="editor-container">
           <rich-media-editor
           <rich-media-editor
             ref="richEditor"
             ref="richEditor"
             v-model="form.imageTextVos"
             v-model="form.imageTextVos"
             @change="onContentChange"
             @change="onContentChange"
+            @collect-delete="onCollectDelete"
             :action="getLoginInfo.imgUploadApi"
             :action="getLoginInfo.imgUploadApi"
+            :deferDelete="isEdit"
           />
           />
         </view>
         </view>
 
 
@@ -39,7 +41,9 @@ export default {
       },
       },
       isEdit: false,
       isEdit: false,
       descId: null, // 图文简介ID
       descId: null, // 图文简介ID
-      itemId: null // 花材ID
+      itemId: null, // 花材ID
+      // 编辑模式下,暂存删除的图片路径(短路径)
+      delImgQueue: []
     };
     };
   },
   },
   async onLoad(option) {
   async onLoad(option) {
@@ -194,6 +198,14 @@ export default {
           if (res.code == 1) {
           if (res.code == 1) {
             uni.$emit('refreshListPage');
             uni.$emit('refreshListPage');
             that.$msg(this.isEdit ? '修改成功' : '添加成功');
             that.$msg(this.isEdit ? '修改成功' : '添加成功');
+            // 编辑模式下,如存在待删图片,统一调用批量删除
+            if (this.isEdit && this.delImgQueue.length > 0) {
+              const { delImages } = require('@/api/pic-text');
+              const filePaths = Array.from(new Set(this.delImgQueue))
+              delImages({ filePaths }).then(() => {
+                this.delImgQueue = []
+              }).catch(() => {})
+            }
             uni.navigateBack({
             uni.navigateBack({
               delta: 1
               delta: 1
             });
             });
@@ -228,6 +240,14 @@ export default {
       } else {
       } else {
         this.$msg(checkRes);
         this.$msg(checkRes);
       }
       }
+    },
+    // 收集编辑模式下的删除图片
+    onCollectDelete(payload){
+      if (!this.isEdit) return;
+      if (!payload || !Array.isArray(payload.filePaths)) return;
+      payload.filePaths.forEach(p => {
+        if (p && !this.delImgQueue.includes(p)) this.delImgQueue.push(p)
+      })
     }
     }
   }
   }
 };
 };

+ 51 - 23
ghsApp/src/components/RichMediaEditor/index.vue

@@ -25,7 +25,7 @@
           
           
           <view class="big-image-container">
           <view class="big-image-container">
             <image 
             <image 
-              :src="item.content.startsWith('http') ? item.content : IMGHOST + '/' + item.content"
+              :src="item.content.startsWith('http') ? item.content : constant.imgUrl + '/' + item.content"
               mode="widthFix" 
               mode="widthFix" 
               class="big-image"
               class="big-image"
               @error="onImageError"
               @error="onImageError"
@@ -54,7 +54,7 @@
               class="small-image-wrapper"
               class="small-image-wrapper"
             >
             >
               <image 
               <image 
-                :src="img.startsWith('http') ? img : IMGHOST + '/' + img" 
+                :src="img.startsWith('http') ? img : constant.imgUrl + '/' + img" 
                 mode="aspectFill" 
                 mode="aspectFill" 
                 class="small-image"
                 class="small-image"
                 @error="onImageError"
                 @error="onImageError"
@@ -185,7 +185,6 @@
 </template>
 </template>
 
 
 <script>
 <script>
-import { IMGHOST } from '@/config.js';
 import { delImage, delImages } from "@/api/pic-text";
 import { delImage, delImages } from "@/api/pic-text";
 
 
 export default {
 export default {
@@ -206,6 +205,11 @@ export default {
     iconColor: { //图标颜色
     iconColor: { //图标颜色
       type: String,
       type: String,
       default: '#717173'
       default: '#717173'
+    },
+    // 编辑模式下,延迟删除图片,交由父组件统一处理
+    deferDelete: {
+      type: Boolean,
+      default: false
     }
     }
   },
   },
   data() {
   data() {
@@ -218,7 +222,6 @@ export default {
       currentAddIndex: -1,
       currentAddIndex: -1,
       currentImageType: 1, // 1: 大图, 2: 小图
       currentImageType: 1, // 1: 大图, 2: 小图
       currentSmallImageIndex: -1, // 当前编辑的小图组索引
       currentSmallImageIndex: -1, // 当前编辑的小图组索引
-      IMGHOST, // 图片基础URL
       token: uni.getStorageSync('token')
       token: uni.getStorageSync('token')
     };
     };
   },
   },
@@ -331,19 +334,37 @@ export default {
 
 
             // 后继删除图片处理:首先判断是否是图片,如果是大图,则删除图片,如果是小图片,则批量删除多张图片
             // 后继删除图片处理:首先判断是否是图片,如果是大图,则删除图片,如果是小图片,则批量删除多张图片
             if (tempList.type === 1) {
             if (tempList.type === 1) {
-              // 大图
-              delImage({ filePath: tempList.content }).then(() => {
-                console.log('大图删除成功');
-              });
+              if (this.deferDelete) { // 编辑模式下延迟删除,交由父组件统一处理
+                const p = tempList.content
+                if (p) this.$emit('collect-delete', { filePaths: [p] })
+              } else { // 新增模式下立即删除
+                // 大图立即删除
+                delImage({ filePath: tempList.content }).then(() => {
+                  console.log('大图删除成功');
+                }).catch(err => {
+                  console.error('大图删除失败:', err);
+                });
+              }
             } else if (tempList.type === 2) {
             } else if (tempList.type === 2) {
-              // 批量删除小图
-              let imgs = [];
-              tempList.content.forEach(img => {
-                imgs.push(img);
-              });
-              delImages({ filePaths: imgs }).then(() => {
-                console.log('小图删除成功');
-              });
+              if (this.deferDelete) { // 编辑模式下延迟删除,交由父组件统一处理
+                let imgs = [];
+                tempList.content.forEach(img => {
+                  const p = img
+                  if (p) imgs.push(p)
+                });
+                if (imgs.length > 0) this.$emit('collect-delete', { filePaths: imgs })
+              } else {
+                // 批量删除小图
+                let imgs = [];
+                tempList.content.forEach(img => {
+                  imgs.push(img);
+                });
+                delImages({ filePaths: imgs }).then(() => {
+                  console.log('小图删除成功');
+                }).catch(err => {
+                  console.error('小图删除失败:', err);
+                });
+              }
             }
             }
           }
           }
         }
         }
@@ -438,15 +459,22 @@ export default {
         success: (res) => {
         success: (res) => {
           if (res.confirm) {
           if (res.confirm) {
             const imageUrl = this.contentList[itemIndex].content[imgIndex];
             const imageUrl = this.contentList[itemIndex].content[imgIndex];
-            // 删除服务器上的图片
-            delImage({ filePath: imageUrl }).then(() => {
+            if (this.deferDelete) {
+              const p = imageUrl
               // 从数组中移除图片
               // 从数组中移除图片
               this.contentList[itemIndex].content.splice(imgIndex, 1);
               this.contentList[itemIndex].content.splice(imgIndex, 1);
-            }).catch(err => {
-              console.error('删除图片失败:', err);
-              // 即使删除失败也从数组中移除
-              this.contentList[itemIndex].content.splice(imgIndex, 1);
-            });
+              if (p) this.$emit('collect-delete', { filePaths: [p] })
+            } else {
+              // 删除服务器上的图片
+              delImage({ filePath: imageUrl }).then(() => {
+                // 从数组中移除图片
+                this.contentList[itemIndex].content.splice(imgIndex, 1);
+              }).catch(err => {
+                console.error('删除图片失败:', err);
+                // 即使删除失败也从数组中移除
+                this.contentList[itemIndex].content.splice(imgIndex, 1);
+              });
+            }
           }
           }
         }
         }
       });
       });

+ 8 - 1
hdApp/src/admin/item/list2.vue

@@ -46,7 +46,7 @@
 						<view class="item_list_bx selectAll">
 						<view class="item_list_bx selectAll">
 							<view v-if="!$util.isEmpty(globalItemData)">
 							<view v-if="!$util.isEmpty(globalItemData)">
 								<template v-for="(productItem, productIndex) in globalItemData">
 								<template v-for="(productItem, productIndex) in globalItemData">
-									<view class="item_list_title" v-if="productItem.className && productItem.className!=''">{{ productItem.className }}</view>
+									<view class="item_list_title" :key="`title-${productIndex}`" v-if="productItem.className && productItem.className!=''">{{ productItem.className }}</view>
 									<view style="height:255upx" :key="productIndex">
 									<view style="height:255upx" :key="productIndex">
 										<ItemStock :info="productItem" @moreAction="moreAction" 
 										<ItemStock :info="productItem" @moreAction="moreAction" 
 										@doPrintLabel="doPrintLabel" @cancelDiscountFn="cancelDiscountFn" @cancelFullOff="cancelFullOff"
 										@doPrintLabel="doPrintLabel" @cancelDiscountFn="cancelDiscountFn" @cancelFullOff="cancelFullOff"
@@ -149,6 +149,9 @@
 				<view class="action-button-item">
 				<view class="action-button-item">
 					<button class="action-button" @click="sendStock()">分配库存</button>
 					<button class="action-button" @click="sendStock()">分配库存</button>
 				</view>
 				</view>
+				<view class="action-button-item">
+					<button class="action-button" @click="editDesc()">图文介绍</button>
+				</view>
 				<view class="action-button-item cancel">
 				<view class="action-button-item cancel">
 					<button class="action-button cancel" @click="closeRightShow()">取消</button>
 					<button class="action-button cancel" @click="closeRightShow()">取消</button>
 				</view>
 				</view>
@@ -620,6 +623,10 @@ export default {
 				this.modalCancel();
 				this.modalCancel();
 			} else {
 			} else {
 			}
 			}
+		},
+		editDesc() {
+			this.closeRightShow()
+			this.pageTo({url: '/admin/item/picTextAdd-Edit?itemId='+this.currentInfo.id})
 		}
 		}
 	}
 	}
 };
 };

+ 279 - 0
hdApp/src/admin/item/picTextAdd-Edit.vue

@@ -0,0 +1,279 @@
+<template>
+  <view class="app-content">
+    <form @submit="formSubmit">
+      <view class="module-com">
+        <view class="editor-container">
+          <rich-media-editor
+            ref="richEditor"
+            v-model="form.imageTextVos"
+            @change="onContentChange"
+            @collect-delete="onCollectDelete"
+            :action="getLoginInfo.imgUploadApi"
+            :deferDelete="isEdit"
+          />
+        </view>
+
+        <view class="confirm-btn">
+          <button class="admin-button-com big" @click="previewContent">预览</button>
+          <button class="admin-button-com big blue" formType="submit">确认</button>
+        </view>
+      </view>
+    </form>
+  </view>
+</template>
+
+<script>
+import TuiListCell from '@/components/plugin/list-cell';
+import RichMediaEditor from '@/components/RichMediaEditor/index.vue';
+const form = require('@/utils/formValidation.js');
+import { getItemDesc, createItemDesc, updateItemDesc } from '@/api/item/picText.js';
+export default {
+  name: 'picTextAdd',
+  components: {
+    TuiListCell,
+    RichMediaEditor
+  },
+  data() {
+    return {
+      form: {
+        title: '',
+        imageTextVos: [] // 图文内容数组
+      },
+      isEdit: false,
+      descId: null, // 图文简介ID
+      itemId: null, // 花材ID
+      // 编辑模式下,暂存删除的图片路径(短路径)
+      delImgQueue: []
+    };
+  },
+  async onLoad(option) {
+    try {
+      if (option && option.itemId) {
+        this.itemId = option.itemId;
+        const res = await this.getDetDesc();
+        if (res === 'create') {
+          this.isEdit = false;
+          uni.setNavigationBarTitle({
+            title: '创建简介'
+          });
+        } else {
+          this.isEdit = true;
+          uni.setNavigationBarTitle({
+            title: '修改简介'
+          });
+        }
+      } else {
+        this.$msg('缺少商品ID参数');
+        uni.navigateBack();
+      }
+    } catch (error) {
+      console.error('页面加载错误:', error);
+      this.isEdit = false;
+      uni.setNavigationBarTitle({
+        title: '创建简介'
+      });
+      this.$msg('页面加载失败,请重试');
+    }
+  },
+  methods: {
+    init() {},
+    // 获取描述
+    async getDetDesc() {
+      try {
+        const res = await getItemDesc({ itemId: this.itemId });
+        
+        if (res.code == 0 || this.$util.isEmpty(res.data)) {
+          return 'create';
+        }
+
+        if(res.code == 1 && res.data == 'not_exist'){
+          return 'create';
+        }
+
+        this.descId = res.data.id;
+
+        // 确保将字符串转换成数组
+        let content = [];
+        if (typeof res.data.content === 'string') {
+          try {
+            content = JSON.parse(res.data.content);
+          } catch (e) {
+            console.error('解析图文内容失败:', e);
+            content = [];
+          }
+        } else if (Array.isArray(res.data.content)) {
+          content = res.data.content;
+        }
+
+        // 处理内容数据,确保每个项目都有正确的格式
+        content = content.map((item) => {
+          return {
+            type: item.type || 3, // 默认为文本类型
+            content: item.content || ''
+          };
+        });
+
+        this.form = {
+          title: res.data.title || '',
+          imageTextVos: content
+        };
+
+        // 触发富文本编辑器内容更新
+        this.$nextTick(() => {
+          setTimeout(() => {
+            if (this.$refs.richEditor) {
+              this.$refs.richEditor.updateContent(this.form.imageTextVos);
+            }
+          }, 50);
+        });
+        
+        return 'edit';
+      } catch (error) {
+        console.error('获取描述失败:', error);
+        return 'create';
+      }
+    },
+    // 图文内容变化处理
+    onContentChange(content) {
+      this.form.imageTextVos = content;
+    },
+
+    // 预览内容
+    previewContent() {
+      if (this.form.imageTextVos.length === 0) {
+        this.form.imageTextVos = [
+          {
+            type: 3,
+            content: '这是一个预览示例,因为当前没有添加任何内容。'
+          }
+        ];
+      }
+
+      // 准备预览数据
+      const previewData = {
+        title: this.form.title || '未命名图文',
+        content: this.form.imageTextVos
+      };
+
+      // 通过全局数据传递
+      const app = getApp();
+      app.globalData = app.globalData || {};
+      app.globalData.previewData = previewData;
+
+      // 跳转到预览页面
+      uni.navigateTo({
+        url: '/admin/picText/preview',
+        success: (res) => {
+          console.log('跳转成功:', res);
+        },
+        fail: (err) => {
+          console.error('跳转失败:', err);
+          this.$msg('预览页面跳转失败');
+        }
+      });
+    },
+    // 提交
+    confirmFn() {
+      uni.showLoading({ mask: true });
+      let that = this;
+      let apiCall = this.isEdit ? updateItemDesc : createItemDesc;
+
+      // 准备提交参数
+      let params = {
+        title: this.form.title,
+        content: JSON.stringify(this.form.imageTextVos)
+      };
+
+      // 编辑模式需要添加简介ID,创建模式需要关联商品ID
+      if (this.isEdit) {
+        params.id = this.descId;
+        params.itemId = this.option.itemId;
+      } else {
+        params.itemId = this.option.itemId;
+      }
+
+      apiCall(params)
+        .then((res) => {
+          uni.hideLoading();
+          if (res.code == 1) {
+            uni.$emit('refreshListPage');
+            that.$msg(this.isEdit ? '修改成功' : '添加成功');
+            // 编辑模式下,如存在待删图片,统一调用批量删除
+            if (this.isEdit && this.delImgQueue.length > 0) {
+              const { delImages } = require('@/api/pic-text');
+              const filePaths = Array.from(new Set(this.delImgQueue))
+              delImages({ filePaths }).then(() => {
+                this.delImgQueue = []
+              }).catch(() => {})
+            }
+            uni.navigateBack({
+              delta: 1
+            });
+          } else {
+            that.$msg(res.message || '操作失败');
+          }
+        })
+        .catch((err) => {
+          uni.hideLoading();
+          console.error('提交失败:', err);
+          that.$msg('提交失败,请稍后重试');
+        });
+    },
+    formSubmit(e) {
+      let rules = [
+        //{ name: 'title', rule: ['required', 'notEmpty'], msg: ['请输入标题'] }
+        //{ name: "imageTextVos", rule: ["notEmpty"], msg: ["请添加图文内容"] }
+      ];
+      let formData = e.detail.value;
+      // 将图文内容添加到表单数据中进行验证
+      // formData.imageTextVos = this.form.imageTextVos;
+      let checkRes = form.validation(formData, rules);
+
+      // 检查图文内容
+      if (this.form.imageTextVos.length === 0) {
+        this.$msg('请添加至少一项图文内容');
+        return;
+      }
+
+      if (!checkRes) {
+        this.confirmFn();
+      } else {
+        this.$msg(checkRes);
+      }
+    },
+    // 收集编辑模式下的删除图片
+    onCollectDelete(payload){
+      if (!this.isEdit) return;
+      if (!payload || !Array.isArray(payload.filePaths)) return;
+      payload.filePaths.forEach(p => {
+        if (p && !this.delImgQueue.includes(p)) this.delImgQueue.push(p)
+      })
+    },
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.app-content {
+  min-height: calc(100vh - 20rpx);
+  padding: 12rpx;
+  background-color: #f5f5f5;
+}
+
+.module-com {
+  margin-bottom: 20rpx;
+}
+
+.confirm-btn {
+  display: flex;
+  gap: 40rpx;
+  margin: 40rpx 30rpx 20rpx;
+  .admin-button-com {
+    flex: 1;
+  }
+}
+
+.editor-container {
+  margin-bottom: 20rpx;
+}
+</style>

+ 13 - 0
hdApp/src/api/item/picText.js

@@ -0,0 +1,13 @@
+import https from '@/plugins/luch-request_0.0.7/request'
+
+export const getItemDesc = data => {
+	return https.get("/item/desc", data);
+};
+
+export const createItemDesc = data => {
+	return https.post("/item/create-desc", data);
+};
+
+export const updateItemDesc = data => {
+	return https.post("/item/update-desc", data);
+}

+ 3 - 5
hdApp/src/components/RichMediaEditor/index.vue

@@ -25,7 +25,7 @@
           
           
           <view class="big-image-container">
           <view class="big-image-container">
             <image 
             <image 
-              :src="(item.content.startsWith('http') ? item.content : IMGHOST + '/' + item.content) + '?x-oss-process=image/resize,w_1000'"
+              :src="(item.content.startsWith('http') ? item.content : constant.imgUrl + '/' + item.content) + '?x-oss-process=image/resize,w_1000'"
               mode="widthFix" 
               mode="widthFix" 
               class="big-image"
               class="big-image"
               @error="onImageError"
               @error="onImageError"
@@ -54,7 +54,7 @@
               class="small-image-wrapper"
               class="small-image-wrapper"
             >
             >
               <image 
               <image 
-                :src="(img.startsWith('http') ? img : IMGHOST + '/' + img) + '?x-oss-process=image/resize,w_150'" 
+                :src="(img.startsWith('http') ? img : constant.imgUrl + '/' + img) + '?x-oss-process=image/resize,w_150'" 
                 mode="aspectFill" 
                 mode="aspectFill" 
                 class="small-image"
                 class="small-image"
                 @error="onImageError"
                 @error="onImageError"
@@ -185,7 +185,6 @@
 </template>
 </template>
 
 
 <script>
 <script>
-import { IMGHOST } from '@/config.js';
 import { delImage, delImages } from "@/api/pic-text";
 import { delImage, delImages } from "@/api/pic-text";
 
 
 export default {
 export default {
@@ -207,7 +206,7 @@ export default {
       type: String,
       type: String,
       default: '#717173'
       default: '#717173'
     },
     },
-    // 编辑模式下延迟删除,交由父组件统一处理
+    // 编辑模式下延迟删除图片,交由父组件统一处理
     deferDelete: {
     deferDelete: {
       type: Boolean,
       type: Boolean,
       default: false
       default: false
@@ -223,7 +222,6 @@ export default {
       currentAddIndex: -1,
       currentAddIndex: -1,
       currentImageType: 1, // 1: 大图, 2: 小图
       currentImageType: 1, // 1: 大图, 2: 小图
       currentSmallImageIndex: -1, // 当前编辑的小图组索引
       currentSmallImageIndex: -1, // 当前编辑的小图组索引
-      IMGHOST, // 图片基础URL
       token: uni.getStorageSync('token')
       token: uni.getStorageSync('token')
     };
     };
   },
   },

+ 2 - 1
hdApp/src/pages.json

@@ -90,7 +90,8 @@
 				{"path": "copy","style": {"navigationBarTitleText": "复制新建"}},
 				{"path": "copy","style": {"navigationBarTitleText": "复制新建"}},
 				{"path": "detail","style": {"navigationBarTitleText": "花材详情"}},
 				{"path": "detail","style": {"navigationBarTitleText": "花材详情"}},
 				{"path": "add","style": {"navigationBarTitleText": "添加花材"}},
 				{"path": "add","style": {"navigationBarTitleText": "添加花材"}},
-				{"path": "selectItem","style": {"navigationBarTitleText": "选择花材"}}
+				{"path": "selectItem","style": {"navigationBarTitleText": "选择花材"}},
+				{"path": "picTextAdd-Edit","style": {"navigationBarTitleText": "修改简介"}}
 			]
 			]
 		},
 		},
 		{
 		{