liuxiaole 6 dni temu
rodzic
commit
effe1a4308

+ 107 - 72
src/api/modules/newLoginApi.ts

@@ -211,86 +211,121 @@ export const addAppealNew = (params: FormData | Record<string, unknown>) => {
 };
 
 // 动态-------------------------------------------------------------------------------------
-/** 商家端 commonComment/addComment:发表评论/回复(评价回复 sourceType=1,动态评论 sourceType=2) */
-// 发表评论 - 表单形式提交(字符串键值对,非 JSON 对象)
-export const addComment = (data: {
-  commentContent: string;
-  businessType: number;
-  businessId: string | number;
-  storeId: string;
-  phoneId: string;
-  replyId: string;
-  commentStar: string;
-  multipartRequest: string;
-}) => {
-  const formData = new FormData();
-  formData.append("commentContent", data.commentContent);
-  formData.append("businessType", String(data.businessType));
-  formData.append("businessId", String(data.businessId));
-  formData.append("storeId", data.storeId);
-  formData.append("phoneId", data.phoneId);
-  formData.append("replyId", data.replyId);
-  formData.append("commentStar", data.commentStar);
-  formData.append("multipartRequest", data.multipartRequest);
-  return httpLogin.post(`/alienStore/storeComment/saveComment`, formData);
+/** commonComment/addComment 请求体(与接口模型一致;新增评论一般只传部分字段) */
+export interface AddCommonCommentBody {
+  auditReason?: string;
+  /** 0-待审核 1-通过 2-驳回 */
+  auditStatus?: number;
+  /** 1-用户评论 2-商户评论(仅回复) */
+  commentType?: number;
+  content?: string;
+  createdTime?: string;
+  /** 0-未删除 1-已删除 */
+  deleteFlag?: number;
+  extInfo?: string;
+  id?: number;
+  imageUrls?: string;
+  /** 0-否 1-是(仅用户评论生效) */
+  isAnonymous?: number;
+  /** 0-隐藏 1-展示 */
+  isShow?: number;
+  likeCount?: number;
+  /** commentType=2 时必填 */
+  merchantId?: number;
+  /** 0=根评论,>0=回复某条评论 */
+  parentId?: number;
+  replyCount?: number;
+  /** sourceType=1 rating.id;=2 动态ID;=3 打卡;=4 二手商品 */
+  sourceId?: number;
+  /** 1-评价的评论 2-动态 3-打卡 4-二手商品 */
+  sourceType?: number;
+  updatedTime?: string;
+  /** 用户=用户ID,商户=商户运营账号ID */
+  userId?: number;
+}
+
+function omitUndefinedRecord(obj: Record<string, unknown>): Record<string, unknown> {
+  return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined && v !== null));
+}
+
+/** 将可转为整型的 id 字段转为 number,无法转换则返回 undefined */
+function toInt64(v: unknown): number | undefined {
+  if (v === undefined || v === null || v === "") return undefined;
+  const n = Number(v);
+  return Number.isFinite(n) ? Math.trunc(n) : undefined;
+}
+
+function buildSaveCommentBody(params: any): AddCommonCommentBody {
+  const businessType = Number(params.businessType ?? 2);
+  const isRating = businessType === 1;
+  const sourceType = isRating ? 1 : 2;
+  const sourceIdRaw = isRating ? (params.replyId ?? params.businessId) : (params.businessId ?? params.sourceId);
+  const parentId = isRating ? 0 : Number(params.replyId || 0);
+  const merchantRaw = params.merchantId ?? params.storeId ?? (isRating ? params.businessId : undefined);
+
+  const body: AddCommonCommentBody = {
+    userId: toInt64(params.userId ?? params.phoneId),
+    sourceType,
+    sourceId: toInt64(sourceIdRaw),
+    parentId,
+    content: String(params.commentContent ?? params.content ?? ""),
+    commentType: Number(params.commentType ?? 2),
+    merchantId: toInt64(merchantRaw),
+    isAnonymous: params.isAnonymous !== undefined ? Number(params.isAnonymous) : 0
+  };
+
+  if (params.auditReason != null && params.auditReason !== "") body.auditReason = String(params.auditReason);
+  if (params.auditStatus !== undefined) body.auditStatus = Number(params.auditStatus);
+  if (params.createdTime) body.createdTime = String(params.createdTime);
+  if (params.deleteFlag !== undefined) body.deleteFlag = Number(params.deleteFlag);
+  if (params.extInfo != null && params.extInfo !== "") body.extInfo = String(params.extInfo);
+  if (params.id !== undefined && params.id !== null && params.id !== "") {
+    const idNum = toInt64(params.id);
+    if (idNum !== undefined) body.id = idNum;
+  }
+  if (params.imageUrls != null && params.imageUrls !== "") body.imageUrls = String(params.imageUrls);
+  if (params.isShow !== undefined) body.isShow = Number(params.isShow);
+  if (params.likeCount !== undefined) body.likeCount = Number(params.likeCount);
+  if (params.replyCount !== undefined) body.replyCount = Number(params.replyCount);
+  if (params.updatedTime) body.updatedTime = String(params.updatedTime);
+
+  return body;
+}
+
+/** 商家端 commonComment/addComment,请求体字段与接口一致 */
+export const addComment = (data: AddCommonCommentBody) => {
+  const raw: Record<string, unknown> = { ...data };
+  return httpLogin.post(`/alienStore/commonComment/addComment`, omitUndefinedRecord(raw));
 };
 
 /**
- * 发表评论/回复(兼容旧参数,内部转为 addComment)
- * - 评价回复:businessType=1,replyId=评价ID → sourceType=1, sourceId=replyId, parentId=0
- * - 动态评论:businessType=2,businessId=动态ID,replyId 有值为回复评论ID → sourceType=2, sourceId=businessId, parentId=replyId||0
+ * 发表评论/回复(兼容旧入参:businessId、replyId、commentContent、phoneId/userId、businessType、storeId
+ * - businessType=1:评价相关,sourceType=1,sourceId 取 replyId/businessId,parentId=0
+ * - businessType=2:动态,sourceType=2,sourceId=动态 id,parentId=回复的评论 id 或 0
  */
 export const saveComment = (params: any) => {
-  const businessType = Number(params.businessType ?? 0);
-  const isRating = businessType === 1;
-  const payload = {
-    commentContent: String(params.commentContent ?? params.content ?? ""),
-    businessType: 2,
-    businessId: isRating ? params.replyId : params.businessId,
-    storeId: String(params.storeId ?? ""),
-    phoneId: String(params.userId ?? params.phoneId ?? ""),
-    replyId: String(params.replyId ?? ""),
-    commentStar: "",
-    multipartRequest: ""
-  };
-  return addComment(payload);
+  return addComment(buildSaveCommentBody(params));
 };
 
 // 评价-------------------------------------------------------------------------------------
-export const addComment2 = (data: {
-  sourceType: number; // 1-评价的评论 2-动态等
-  sourceId: string | number; // 评价ID或动态ID
-  userId: string;
-  parentId: number; // 0-根评论
-  content: string;
-  commentType: number; // 2-商户评论
-  merchantId: string;
-  isAnonymous?: number;
-}) => {
-  return httpLogin.post(`/alienStore/commonComment/addComment`, {
-    ...data,
-    isAnonymous: data.isAnonymous ?? 0
-  });
-};
-export const saveComment2 = (params: any) => {
-  const businessType = Number(params.businessType ?? 0);
-  const isRating = businessType === 1;
-  const payload = {
-    sourceType: isRating ? 1 : 2,
-    sourceId: isRating ? params.replyId : params.businessId,
-    userId: String(params.userId ?? params.phoneId ?? ""),
-    parentId: isRating ? 0 : Number(params.replyId || 0),
-    content: String(params.commentContent ?? params.content ?? ""),
-    commentType: 2,
-    merchantId: String(params.merchantId ?? params.storeId ?? params.businessId ?? ""),
-    isAnonymous: 0
-  };
-  return addComment2(payload);
-};
-
-//评论列表
-export const commentList = (params: any) => {
-  return httpLogin.get(`/alienStore/storeComment/getList`, params);
+export const addComment2 = (data: AddCommonCommentBody) => addComment(data);
+
+export const saveComment2 = (params: any) => saveComment(params);
+
+/** 评论列表查询(getListBySourceType) */
+export interface CommentListParams {
+  pageNum: number;
+  pageSize: number;
+  /** 来源 id,如动态 id */
+  sourceId: number | string;
+  /** 1-评价 2-动态 3-打卡 4-二手商品 */
+  sourceType: number;
+  /** 可选,评论发布者/当前用户 id */
+  userId?: number;
+}
+
+export const commentList = (params: CommentListParams) => {
+  return httpLogin.get(`/alienStore/commonComment/getListBySourceType`, params);
 };
 
 //我的动态

+ 29 - 0
src/utils/commonCommentList.ts

@@ -0,0 +1,29 @@
+/** 将 commonComment/getListBySourceType 等接口的单条评论转为列表展示用结构(兼容旧 storeComment 模板字段) */
+export function normalizeCommonCommentListItem(row: any): any {
+  if (!row || typeof row !== "object") return row;
+  const children = row.childCommonComments ?? row.storeComment ?? [];
+  const normalizedChildren = Array.isArray(children) ? children.map(normalizeCommonCommentListItem) : [];
+  return {
+    ...row,
+    userAvatar: row.userAvatar ?? row.headImg,
+    userName: row.userName ?? row.headName ?? row.headPhone ?? "用户",
+    commentContent: row.commentContent ?? row.content ?? "",
+    isLiked: row.isLiked === true || row.isLiked === 1 || row.isLike === "1" || row.isLike === 1,
+    userImage: row.userImage ?? row.headImg,
+    storeComment: normalizedChildren
+  };
+}
+
+/**
+ * 解析列表接口 data:支持 data 为数组,或分页 records
+ */
+export function normalizeCommonCommentListResponse(resData: unknown): any[] {
+  if (Array.isArray(resData)) return resData.map(normalizeCommonCommentListItem);
+  const rec = (resData as { records?: unknown })?.records;
+  if (Array.isArray(rec)) return rec.map(normalizeCommonCommentListItem);
+  return [];
+}
+
+export function countTopAndNestedComments(list: { storeComment?: unknown[] }[]): number {
+  return list.reduce((n, c) => n + 1 + (Array.isArray(c.storeComment) ? c.storeComment.length : 0), 0);
+}

+ 20 - 18
src/views/dynamicManagement/index.vue

@@ -522,6 +522,7 @@ import {
   uploadImg,
   saveComment,
   commentList,
+  type CommentListParams,
   getMutualAttention,
   addTransferCount,
   deleteDynamicsById,
@@ -533,6 +534,7 @@ import {
 } from "@/api/modules/newLoginApi";
 
 // import { uploadImg } from "@/api/modules/upload";
+import { normalizeCommonCommentListResponse, countTopAndNestedComments } from "@/utils/commonCommentList";
 import { useUserStore } from "@/stores/modules/user";
 import { useWebSocketStore } from "@/stores/modules/websocket";
 
@@ -1021,31 +1023,31 @@ const loadCommentList = async () => {
   if (!currentDetail.value) return;
 
   try {
-    let params = {
-      businessId: String(currentDetail.value.id),
-      businessType: "2",
-      replyStatus: 0,
+    const params: CommentListParams = {
       pageNum: 1,
-      pageSize: 10,
-      commentType: 0,
-      days: "",
-      phoneId: `store_${userStore.userInfo?.phone}`
+      pageSize: 100,
+      sourceId: currentDetail.value.id,
+      sourceType: 2
     };
+    const uid = userStore.userInfo?.userId ?? userStore.userInfo?.id;
+    if (uid !== undefined && uid !== null && uid !== "") {
+      const n = Number(uid);
+      if (Number.isFinite(n)) params.userId = Math.trunc(n);
+    }
     const res: any = await commentList(params);
     if (res.code === 200) {
-      commentListData.value = res.data.records || [];
-      // 更新评论总数(包括回复数)
+      const list = normalizeCommonCommentListResponse(res.data);
+      commentListData.value = list;
       if (currentDetail.value) {
-        const baseCommentCount = res.data.total || 0;
-        // 计算所有回复的总数
-        const replyCount = commentListData.value.reduce((total, comment) => {
-          return total + (comment.storeComment?.length || 0);
-        }, 0);
-        // 评论总数 = 评论数 + 回复数
-        currentDetail.value.commentCount = baseCommentCount + replyCount;
+        const raw = res.data;
+        const pageTotal =
+          raw && typeof raw === "object" && !Array.isArray(raw) && typeof (raw as { total?: number }).total === "number"
+            ? (raw as { total: number }).total
+            : undefined;
+        currentDetail.value.commentCount =
+          pageTotal !== undefined && pageTotal >= 0 ? pageTotal : countTopAndNestedComments(list);
       }
       console.log("评论列表:", commentListData.value);
-      console.log("评论总数:", res.data.total);
     }
   } catch (error) {
     console.error("加载评论列表失败:", error);

+ 23 - 24
src/views/dynamicManagement/myDynamic.vue

@@ -740,6 +740,7 @@ import {
   getDianZanList,
   saveComment,
   commentList,
+  type CommentListParams,
   getMutualAttention,
   getMyFollowed,
   addTransferCount,
@@ -756,6 +757,7 @@ import {} from "@/api/modules/dynamicManagement";
 import { useUserStore } from "@/stores/modules/user";
 import FriendCoupon from "./friendCoupon.vue";
 import { localGet } from "@/utils";
+import { normalizeCommonCommentListResponse, countTopAndNestedComments } from "@/utils/commonCommentList";
 const router = useRouter();
 const userStore = useUserStore();
 
@@ -1273,34 +1275,31 @@ const loadCommentList = async () => {
   if (!currentDetail.value) return;
 
   try {
-    const phone = userStore.userInfo?.phone || "";
-    const phoneId = phone.startsWith("store_") ? phone : `store_${phone}`;
-
-    let params = {
-      businessId: String(currentDetail.value.id),
-      businessType: "2",
-      replyStatus: 0,
+    const params: CommentListParams = {
       pageNum: 1,
       pageSize: 100,
-      commentType: 0,
-      days: "",
-      phoneId: phoneId
+      sourceId: currentDetail.value.id,
+      sourceType: 2
     };
+    const uid = userStore.userInfo?.userId ?? userStore.userInfo?.id;
+    if (uid !== undefined && uid !== null && uid !== "") {
+      const n = Number(uid);
+      if (Number.isFinite(n)) params.userId = Math.trunc(n);
+    }
     const res: any = await commentList(params);
     if (res.code === 200) {
-      commentListData.value = res.data.records || [];
-      // 更新评论总数(包括回复数)
+      const list = normalizeCommonCommentListResponse(res.data);
+      commentListData.value = list;
       if (currentDetail.value) {
-        const baseCommentCount = res.data.total || 0;
-        // 计算所有回复的总数
-        const replyCount = commentListData.value.reduce((total, comment) => {
-          return total + (comment.storeComment?.length || 0);
-        }, 0);
-        // 评论总数 = 评论数 + 回复数
-        currentDetail.value.commentCount = baseCommentCount + replyCount;
+        const raw = res.data;
+        const pageTotal =
+          raw && typeof raw === "object" && !Array.isArray(raw) && typeof (raw as { total?: number }).total === "number"
+            ? (raw as { total: number }).total
+            : undefined;
+        currentDetail.value.commentCount =
+          pageTotal !== undefined && pageTotal >= 0 ? pageTotal : countTopAndNestedComments(list);
       }
       console.log("评论列表:", commentListData.value);
-      console.log("评论总数:", res.data.total);
     }
   } catch (error) {
     console.error("加载评论列表失败:", error);
@@ -1382,12 +1381,12 @@ const handleSubmitComment = async () => {
     const isReply = !!replyingComment.value;
 
     const params: any = {
-      replyId: isReply ? replyingComment.value.id : "", // 回复评论时传评论ID,否则为空
+      replyId: isReply ? replyingComment.value.id : "", // 回复评论时传 parentId,否则为 0
       commentContent: commentInput.value,
       businessType: "2",
-      businessId: String(currentDetail.value.id),
-      storeId: userStore.userInfo?.storeId || userStore.userInfo?.createdId,
-      commentStar: "",
+      businessId: String(currentDetail.value.id), // 对应请求体 sourceId(动态 id)
+      storeId: userStore.userInfo?.storeId || userStore.userInfo?.createdId, // 对应 merchantId
+      userId: userStore.userInfo?.userId ?? userStore.userInfo?.id ?? "",
       phoneId: phoneId
     };
 

+ 19 - 20
src/views/dynamicManagement/userDynamic.vue

@@ -598,6 +598,7 @@ import {
   setFriendCoupon,
   saveComment,
   commentList,
+  type CommentListParams,
   getUserByPhone,
   reportUserViolation,
   uploadImg,
@@ -607,6 +608,7 @@ import {
 } from "@/api/modules/newLoginApi";
 import { useUserStore } from "@/stores/modules/user";
 import { localGet } from "@/utils";
+import { normalizeCommonCommentListResponse, countTopAndNestedComments } from "@/utils/commonCommentList";
 
 const route = useRoute();
 const router = useRouter();
@@ -872,34 +874,31 @@ const loadCommentList = async () => {
   if (!currentDetail.value) return;
 
   try {
-    const phone = userStore.userInfo?.phone || "";
-    const phoneId = phone.startsWith("store_") ? phone : `store_${phone}`;
-
-    let params = {
-      businessId: String(currentDetail.value.id),
-      businessType: "2",
-      replyStatus: 0,
+    const params: CommentListParams = {
       pageNum: 1,
       pageSize: 100,
-      commentType: 0,
-      days: "",
-      phoneId: phoneId
+      sourceId: currentDetail.value.id,
+      sourceType: 2
     };
+    const uid = userStore.userInfo?.userId ?? userStore.userInfo?.id;
+    if (uid !== undefined && uid !== null && uid !== "") {
+      const n = Number(uid);
+      if (Number.isFinite(n)) params.userId = Math.trunc(n);
+    }
     const res: any = await commentList(params);
     if (res.code === 200) {
-      commentListData.value = res.data.records || [];
-      // 更新评论总数(包括回复数)
+      const list = normalizeCommonCommentListResponse(res.data);
+      commentListData.value = list;
       if (currentDetail.value) {
-        const baseCommentCount = res.data.total || 0;
-        // 计算所有回复的总数
-        const replyCount = commentListData.value.reduce((total, comment) => {
-          return total + (comment.storeComment?.length || 0);
-        }, 0);
-        // 评论总数 = 评论数 + 回复数
-        currentDetail.value.commentCount = baseCommentCount + replyCount;
+        const raw = res.data;
+        const pageTotal =
+          raw && typeof raw === "object" && !Array.isArray(raw) && typeof (raw as { total?: number }).total === "number"
+            ? (raw as { total: number }).total
+            : undefined;
+        currentDetail.value.commentCount =
+          pageTotal !== undefined && pageTotal >= 0 ? pageTotal : countTopAndNestedComments(list);
       }
       console.log("评论列表:", commentListData.value);
-      console.log("评论总数:", res.data.total);
     }
   } catch (error) {
     console.error("加载评论列表失败:", error);

+ 47 - 23
src/views/storeDecoration/storeHeadMap/index.vue

@@ -5,12 +5,21 @@
       <div class="mode-preview-section">
         <div class="preview-box">
           <div class="preview-card">
-            <div class="preview-images-multiple">
-              <div v-for="(img, index) in displayImages" :key="index" class="preview-image-small">
-                <img v-if="img" :src="img" alt="头图" />
-                <div v-else class="preview-placeholder">示例图</div>
-              </div>
-              <div v-if="displayImages.length < 3" class="preview-image-small">
+            <div class="preview-images-carousel">
+              <el-carousel
+                v-if="carouselPreviewImages.length > 0"
+                height="250px"
+                :autoplay="carouselPreviewImages.length > 1"
+                :interval="4000"
+                indicator-position="none"
+                :arrow="carouselPreviewImages.length > 1 ? 'hover' : 'never'"
+                class="head-preview-carousel"
+              >
+                <el-carousel-item v-for="(url, index) in carouselPreviewImages" :key="index">
+                  <img :src="url" alt="头图" class="carousel-preview-img" />
+                </el-carousel-item>
+              </el-carousel>
+              <div v-else class="carousel-preview-empty">
                 <div class="preview-placeholder">示例图</div>
               </div>
               <div class="overlay-button">
@@ -156,8 +165,9 @@ const previewData = reactive({
   reviews: 1853
 });
 
-const displayImages = computed(() => {
-  return formData.multipleImages.slice(0, 3).map(item => item.url || "");
+/** 预览轮播:展示已上传头图,一次一张 */
+const carouselPreviewImages = computed(() => {
+  return formData.multipleImages.map(item => item.url || "").filter((url): url is string => Boolean(url));
 });
 
 /**
@@ -353,30 +363,42 @@ const handleSave = async () => {
         border-radius: 8px;
         box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
         transition: all 0.3s;
-        .preview-images-multiple {
+        .preview-images-carousel {
           position: relative;
-          display: flex;
-          gap: 4px;
           width: 100%;
-          height: 200px;
           margin-bottom: 16px;
-          overflow: hidden;
+          overflow: visible;
           background-color: #f0f0f0;
           border-radius: 8px;
-          .preview-image-small {
+          .head-preview-carousel {
+            width: 100%;
+            :deep(.el-carousel__container) {
+              height: 200px;
+              border-radius: 8px;
+            }
+            :deep(.el-carousel__item) {
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              overflow: hidden;
+              background-color: #e4e7ed;
+            }
+            :deep(.el-carousel__arrow) {
+              background-color: rgb(0 0 0 / 35%);
+            }
+          }
+          .carousel-preview-img {
+            width: 100%;
+            height: 100%;
+            object-fit: cover;
+          }
+          .carousel-preview-empty {
             display: flex;
-            flex: 1;
             align-items: center;
             justify-content: center;
-            height: 100%;
-            overflow: hidden;
+            height: 200px;
             background-color: #e4e7ed;
-            border-radius: 4px;
-            img {
-              width: 100%;
-              height: 100%;
-              object-fit: cover;
-            }
+            border-radius: 8px;
             .preview-placeholder {
               font-size: 12px;
               color: #909399;
@@ -386,12 +408,14 @@ const handleSave = async () => {
             position: absolute;
             right: 12px;
             bottom: 12px;
+            z-index: 2;
             display: flex;
             gap: 4px;
             align-items: center;
             padding: 6px 12px;
             font-size: 12px;
             color: white;
+            pointer-events: none;
             background-color: rgb(0 0 0 / 60%);
             border-radius: 4px;
           }