Browse Source

完成详情页 及相关页面动态数据渲染

XSXS 6 months ago
parent
commit
0f16b4ddf7

+ 38 - 1
components/CommentSection/CommentSection.vue

@@ -28,11 +28,16 @@
 						<image style="width: 48rpx ;height: 48rpx;" src="@/static/icon/sy_icon_biaoqing.png"></image>
 					</view>
 				</view>
-				<view class="giveTheThumbsUpBox" @click="giveTheThumbsUp()">
+				<view class="giveTheThumbsUpBox" @click="giveTheThumbsUp()" v-if="type != 'crowdfund'">
 					<image v-if="!isLikeFalg" src="@/static/icon/icon-19.png"></image>
 					<image v-else src="@/static/icon/icon-18.png"></image>
 					<span :style="{ color: isLikeFalg ? '#8de10b' : '#999' }">{{ articleInfo.num_like }}</span>
 				</view>
+				<view class="giveTheThumbsUpBox" @click="collect()" v-else>
+					<image v-if="!isLikeFalg" src="@/static/crowdFunding/collect.png"></image>
+					<image v-else src="@/static/crowdFunding/collect-active.png"></image>
+					<span :style="{ color: isLikeFalg ? '#8de10b' : '#999' }">{{ articleInfo.num_like }}</span>
+				</view>
 			</view>
 		</template>
 	</view>
@@ -138,6 +143,38 @@ export default {
 				}
 			});
 		},
+		collect() {  
+			if (this.isLikeFalg == undefined) {
+				this.isLikeFalg = this.articleInfo.is_like  
+			}
+			const action = this.isLikeFalg ? 'remove' : 'add';
+			uni.request({
+				url: this.$apiHost + '/crowdfund/favorite',
+				method: 'POST',
+				header: {
+					"content-type": "application/x-www-form-urlencoded",
+				},
+				data: {
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey,
+					crowdfund_id: this.articleId,
+					action
+				},
+				success: (res) => {
+					console.log(res.data, "收藏");
+
+					if (res.data && res.data.success && res.data.success == 'yes') {
+						this.isLikeFalg = !this.isLikeFalg;
+						uni.showToast({ title: this.isLikeFalg ? '已收藏' : '已取消收藏', icon: 'none' });
+					} else {
+						uni.showToast({ title: res.data.msg || '操作失败', icon: 'none' });
+					}
+				},
+				fail: () => {
+					uni.showToast({ title: '网络错误', icon: 'none' });
+				}
+			});
+		},
 		loadCommentData() {
 			uni.request({
 				url: this.$apiHost + '/Article/getcomments',

+ 107 - 525
pages/crowdFunding/Search.vue

@@ -7,10 +7,10 @@
       </view>
       <view class="search-box">
         <!-- <uni-icons type="search" size="16" color="#999"></uni-icons> -->
-        <input type="text" v-model="searchKeyword" placeholder="请输入关键词" confirm-type="search" @confirm="handleSearch"
+        <input type="text" v-model="searchKeyword" placeholder="请输入关键词" confirm-type="search" @confirm="onSearch"
           @input="handleInput" />
         <uni-icons v-if="searchKeyword" type="clear" size="16" color="#999" @click="clearKeyword"></uni-icons>
-        <view class="searchImgBox" @click="handleSearch">
+        <view class="searchImgBox" @click="onSearch">
           <image class="image" src="@/static/home/sy_icon_sousuo.png"></image>
         </view>
       </view>
@@ -20,7 +20,8 @@
     <view class="search-history" v-if="searchStatus && historyList.length > 0">
       <view class="history-header">
         <text class="title">搜索历史</text>
-        <image @click="clearHistory" style="width: 32rpx;height: 32rpx;" class="deleteAll" src="@/static/home/sy_icon_shanchu.png"></image>
+        <image @click="clearHistory" style="width: 32rpx;height: 32rpx;" class="deleteAll"
+          src="@/static/home/sy_icon_shanchu.png"></image>
       </view>
       <view class="history-list">
         <view class="history-item" v-for="(item, index) in displayedHistoryList" :key="index"
@@ -35,10 +36,10 @@
         </view>
         <view class="expandBtn" @click="toggleHistory">
           <view v-if="!isExpanded">
-          <template v-if="historyList.length > 5">
-            查看全部
-            <image src="@/static/home/sy_icon_chakanquanbu.png"></image>
-          </template>
+            <template v-if="historyList.length > 5">
+              查看全部
+              <image src="@/static/home/sy_icon_chakanquanbu.png"></image>
+            </template>
           </view>
           <view v-else class="fold">
             折叠历史记录
@@ -49,63 +50,16 @@
     </view>
 
     <!-- 搜索结果 -->
-    <view class="search-result" v-if="searchKeyword && !searchStatus">
-      <!-- <view class="search-result"> -->
-      <!-- 这里添加搜索结果的展示逻辑 -->
-      <view>
-        <view class="tab-nav">
-          <view v-for="(tab, index) in ['作品', '作者']" :key="index"
-            :class="['tab-item', currentTab === index ? 'active' : '']" @click="switchTab(index)">
-            {{ tab }}
-            <view class="indicator-triangle">
-            </view>
-          </view>
-        </view>
-
-        <!-- 关注列表 - 类似my.vue -->
-        <view v-show="currentTab === 0" class="follow-list">
-          <block v-if="followList.length > 0">
-            <w-waterfall :data="followList">
-              <template v-slot:content="{ item, width }">
-                <card :item="formatItem(item)" findType="search" :width="width" :custom-style="{ background: '#fff' }" textColor="#999"  titleTextColor="#000">
-                </card>
-              </template>
-            </w-waterfall>
-          </block>
-          <view class="no-data" v-else-if="!isLoadingFollow">
-            <text>暂无作品数据</text>
-          </view>
+    <view class="search-result" v-if="!searchStatus">
+      <block v-if="searchResult.length > 0">
+        <view class="items-grid">
+          <CrowdFundingItem v-for="item in searchResult" :key="item.id" :item="item" @click="goToDetail(item.id)" />
         </view>
-
-        <view v-show="currentTab === 1" class="follow-list" style="padding: 0 30rpx;">
-          <block v-if="recommendList.length > 0">
-            <view class="follow-item" v-for="(item, index) in recommendList" :key="index" @click="goToUserHomepage(item.id)"> 
-              <CircleAvatar  @click="goToUserHomepage(item.user_id)" class="avator" :src="item.avator"></CircleAvatar>
-              <view class="info">
-                <view class="top-box" @click="goToUserHomepage(item.user_id)"> 
-                  <view class="name one-omit">{{ item.nickname }}</view>
-                  <image src="../../static/icon/wd_icon_nan.png" mode="widthFix" v-if="item.sex_id == 1" />
-                  <image src="../../static/icon/wd_icon_nv.png" mode="widthFix" v-else-if="item.sex_id == 2" />
-                  <view class="level">Lv{{ item.level }}</view>
-                </view>
-                <!-- <view class="desc">{{ item.description }}</view> -->
-              </view>
-              <view :class="item.is_attention ? 'unfollow-btn active' : 'unfollow-btn'" @click="toggleFollow(item)">
-                <image src="../../static/me/wd_icon_guanzhu.png"></image>
-                {{ item.is_attention == 0 ? '取消关注' : '关注' }}
-              </view>
-            </view>
-          </block>
-          <view class="no-data" v-else-if="!isLoadingFollow">
-            <text>暂无作者数据</text>
-          </view>
-        </view>
-        <!-- avator: "http://e.yujianmate.com/images/avator/b1.jpg"
-      is_attention: 0
-      level: 0
-      nickname: "刘畅"
-      sex_id: 2 -->
-
+        <view v-if="isLoading" class="loading-more">加载中...</view>
+        <view v-else-if="!hasMore" class="no-more">没有更多了</view>
+      </block>
+      <view class="no-data" v-else-if="!isLoading">
+        <text>暂无数据</text>
       </view>
     </view>
     <DialogBox ref="DialogBox"></DialogBox>
@@ -113,27 +67,22 @@
 </template>
 
 <script>
+import CrowdFundingItem from './components/CrowdFundingItem/CrowdFundingItem.vue';
 const HISTORY_KEY = 'search_history';
 const MAX_HISTORY = 20;
 
 export default {
+  components: { CrowdFundingItem },
   data() {
     return {
       searchKeyword: '', // 搜索关键词
       historyList: [], // 搜索历史
-      searchResult: [], // 搜索结果
-      primaryHistoryList: [],
+      searchResult: [],
+      page: 1,
+      pageSize: 20,
+      hasMore: true,
+      isLoading: false,
       isExpanded: false, // 添加展开/折叠状态变量
-      currentTab: 0, // 当前激活的标签页
-      followList: [], // 关注列表数据
-      followOffset: 0, // 关注列表偏移量
-      hasMoreFollow: true, // 是否有更多关注列表数据
-      recommendList: [], // 推荐列表数据
-      recommendOffset: 0, // 推荐列表偏移量
-      hasMoreRecommend: true, // 是否有更多推荐列表数据
-      isLoadingFollow: false, // 是否正在加载关注列表
-      isLoadingRecommend: false, // 是否正在加载推荐列表 
-
       searchStatus: true,//显示搜索历史  false显示搜索结果
     }
   },
@@ -141,25 +90,12 @@ export default {
     // 加载历史记录
     this.loadHistory();
   },
+  onPullDownRefresh() {
+    this.onSearch(true);
+    uni.stopPullDownRefresh();
+  },
   onReachBottom() {
-    // 触底加载更多数据
-    if (!(hasMoreFollow || hasMoreRecommend)) {
-      switch (this.currentTab) {
-        case 0:
-          this.loadFollowList();
-          break;
-        case 1:
-          this.loadRecommendList();
-          break;
-      }
-    } else {
-      uni.hideToast();
-      uni.showToast({
-        title:'没有更多数据了',
-        icon: 'none'
-      });
-      return;
-    }
+    this.onSearch(false);
   },
   computed: {
     // 添加计算属性以控制显示的历史记录数量
@@ -177,7 +113,6 @@ export default {
         console.error('Failed to load search history:', e);
         this.historyList = [];
       }
-      // this.primaryHistoryList = JSON.parse(JSON.stringify(this.historyList));
     },
 
     // 保存历史记录
@@ -213,11 +148,11 @@ export default {
       }).then((res) => {
         if (res.isConfirm) {
           this.historyList = [];
-            uni.setStorageSync(HISTORY_KEY, '[]');
+          uni.setStorageSync(HISTORY_KEY, '[]');
         }
       })
 
-   
+
     },
     // 清空单个历史记录
     deleteHistoryItem(item) {
@@ -246,19 +181,49 @@ export default {
     // 使用历史记录中的关键词
     useHistoryKeyword(keyword) {
       this.searchKeyword = keyword;
-      this.handleSearch();
+      this.onSearch();
     },
 
     // 处理搜索
-    handleSearch() {
+    async onSearch(isRefresh = true) {
       if (!this.searchKeyword.trim()) return;
-      // 保存到历史记录
+      if (isRefresh) {
+        this.page = 1;
+        this.hasMore = true;
+        this.searchResult = [];
+      }
+      if (!this.hasMore || this.isLoading) return;
+      this.isLoading = true;
+   
+      try {
+        const [err, res] = await uni.request({
+          url: this.$apiHost + '/crowdfund/list',
+          method: 'GET',
+          data: {
+            page: this.page,
+            pageSize: this.pageSize,
+            keyword: this.searchKeyword
+          }
+        });
+        if (!err && res && res.data && res.data.data && res.data.data.list) {
+          const list = res.data.data.list;
+          if (isRefresh) {
+            this.searchResult = list;
+          } else {
+            this.searchResult = [...this.searchResult, ...list];
+          }
+          this.hasMore = this.searchResult.length < (res.data.data.total || 0);
+          this.page++;
+        } else {
+          this.hasMore = false;
+        }
+      } catch (e) {
+        this.hasMore = false;
+      }
+      this.isLoading = false;
+      // 保存历史记录
       this.saveHistory();
       this.searchStatus = false;
-      // this.loadHistory()
-      // TODO: 实现搜索逻辑
-      console.log('Searching for:', this.searchKeyword);
-      this.queryList()
     },
 
     // 清空搜索框
@@ -269,11 +234,6 @@ export default {
     // 处理输入
     handleInput(e) {
       this.searchKeyword = e.detail.value;
-      // this.historyList = this.primaryHistoryList.filter(item => {
-      //   if (item.includes(e.detail.value)) {
-      //     return item;
-      //   }
-      // })
       if (this.searchKeyword.trim() == '') {
         this.searchStatus = true;
       }
@@ -290,263 +250,16 @@ export default {
     toggleHistory() {
       this.isExpanded = !this.isExpanded;
     },
-    switchTab(index) {
-      this.currentTab = index;
-      this.searchRequest(index);
-      this.queryList()
+    goToDetail(id) {
+      uni.navigateTo({ url: '/pages/crowdFunding/crowdfundingDetails?id=' + id });
     },
-    formatItem(item) {
-
-      this.downloadAndProcessImage(item.images)
-        .then((color) => {
-          console.log(`平均颜色: R=${color.r}, G=${color.g}, B=${color.b}`);
-        })
-        .catch((error) => {
-          console.error("获取图像失败:", error);
-        });
-      // 处理接口返回的数据,使其适配card组件
-      return {
-        id: item.id,
-        allowEdit: false,
-        nickname: item.nickname,
-        avator: item.avator,
-        num_like: item.num_like,
-        num_view: item.num_view,
-        image: item.images || item.img_url || item.image, // 优先使用images字段
-        w: item.width,
-        h: item.height,
-        title: item.title || "",
-        desc: item.desc || "",
-        backgroundColor: "#f6f6f6",
-      };
-    },
-    downloadAndProcessImage(imageUrl, width = 10, height = 10) {
-      return new Promise((resolve, reject) => {
-        uni.downloadFile({
-          url: imageUrl,
-          success: (downloadResult) => {
-            if (downloadResult.statusCode === 200) {
-              const tempFilePath = downloadResult.tempFilePath;
-              const ctx = uni.createCanvasContext('myCanvas', this);
-              ctx.drawImage(tempFilePath, 0, 0, width, height);
-              ctx.draw(false, () => {
-                uni.canvasGetImageData({
-                  canvasId: 'myCanvas',
-                  x: 0,
-                  y: 0,
-                  width: width,
-                  height: height,
-                  success: (res) => {
-                    const data = res.data;
-                    let r = 0,
-                      g = 0,
-                      b = 0;
-                    for (let i = 0; i < data.length; i +=
-                      4) {
-                      r += data[i];
-                      g += data[i + 1];
-                      b += data[i + 2];
-                    }
-                    const count = width * height;
-                    r = Math.floor(r / count);
-                    g = Math.floor(g / count);
-                    b = Math.floor(b / count);
-                    resolve({
-                      r,
-                      g,
-                      b
-                    });
-                  },
-                  fail: (err) => {
-                    reject(err);
-                  }
-                });
-              });
-            } else {
-              reject(new Error('下载图像失败'));
-            }
-          },
-          fail: (err) => {
-            reject(err);
-          }
-        });
-      });
-    },
-    queryList() {
-      // 根据当前标签刷新数据
-      switch (this.currentTab) {
-        case 0:
-          // 重置作品列表
-          this.followList = [];
-          this.followOffset = 0;
-          this.hasMoreFollow = true;
-          // this.loadFollowList();
-          this.loadFollowList();
-          break;
-        case 1:
-          // 重置作者列表
-          this.recommendList = [];
-          this.recommendOffset = 0;
-          this.hasMoreRecommend = true;
-          // this.loadRecommendList();
-          this.loadRecommendList();
-          break;
-      }
-    },
-    loadFollowList() {
-      if (this.isLoadingFollow) return;
-      this.isLoadingFollow = true;
-
-      uni.request({
-        url: this.$apiHost + "/Work/getlist",
-        data: {
-          uuid: getApp().globalData.uuid,
-          skey: getApp().globalData.skey,
-          offset: this.followOffset,
-          search: this.searchKeyword,
-        },
-        header: {
-          "content-type": "application/json",
-          sign: getApp().globalData.headerSign,
-        },
-        success: (res) => {
-          console.log("作品列表数据:", res.data);
-          // 确保在任何情况下都完成加载
-          if (
-            res.data.success == "yes" &&
-            res.data.list &&
-            res.data.list.length > 0
-          ) {
-            // 只有当列表有数据时才追加
-            this.followList = [...this.followList, ...res.data.list];
-            this.followOffset += res.data.list.length;
-            console.log(this.followOffset, "作品列表数据");
-
-            if (res.data.list.length < 20) {
-              this.hasMoreFollow = false;
-            }
-          } else {
-            // 如果列表为空,确保标记没有更多数据
-            this.hasMoreFollow = false;
-          }
-
-          // 无论是否有数据,都需要通知z-paging组件完成刷新
-          if (this.$refs.paging) {
-            this.$refs.paging.complete(this.followList);
-          }
-        },
-        complete: () => {
-          this.isLoadingFollow = false;
-        },
-        fail: (e) => {
-          console.log("请求关注列表失败:", e);
-          this.isLoadingFollow = false;
-          // 加载失败时也要通知组件完成
-          if (this.$refs.paging) {
-            this.$refs.paging.complete(false);
-          }
-        },
-      });
-    },
-    loadRecommendList() {
-      console.log(this.recommendOffset, 666);
-
-      if (this.isLoadingRecommend) return;
-      this.isLoadingRecommend = true;
-      uni.request({
-        url: this.$apiHost + "/User/getlist",
-        data: {
-          uuid: getApp().globalData.uuid,
-          skey: getApp().globalData.skey,
-          offset: this.recommendOffset,
-          search: this.searchKeyword,
-        },
-        header: {
-          "content-type": "application/json",
-          sign: getApp().globalData.headerSign,
-        },
-        success: (res) => {
-          console.log("作者列表数据:", res.data);
-          if (
-            res.data.success == "yes" &&
-            res.data.list &&
-            res.data.list.length > 0
-          ) {
-            this.recommendList = [...this.recommendList, ...res.data.list];
-            this.recommendOffset += res.data.list.length;
-            console.log(this.recommendOffset, "作者列表数据");
-
-            if (res.data.list.length < 20) {
-              this.hasMoreRecommend = false;
-            }
-          } else {
-            this.hasMoreRecommend = false;
-          }
-
-          // 无论是否有数据,都需要通知z-paging组件完成刷新
-          if (this.$refs.paging) {
-            this.$refs.paging.complete(this.recommendList);
-          }
-        },
-        complete: () => {
-          this.isLoadingRecommend = false;
-        },
-        fail: (e) => {
-          console.log("请求推荐列表失败:", e);
-          this.isLoadingRecommend = false;
-          // 加载失败时也要通知组件完成
-          if (this.$refs.paging) {
-            this.$refs.paging.complete(false);
-          }
-        },
-      });
-    },
-    toggleFollow(item) {
-      uni.request({
-        url: this.$apiHost + '/Member/attention',
-        data: {
-          uuid: getApp().globalData.uuid,
-          id: item.user_id,
-        },
-        header: {
-          "content-type": "application/json",
-          'sign': getApp().globalData.headerSign
-        },
-        success: (res) => {
-          console.log("关注结果:", res.data);
-          uni.showToast({
-            title: res.data.str,
-            icon: 'none'
-          });
-          if (res.data.success === "yes") {
-            if (res.data.str === "关注成功") {
-              item.is_attention = false
-            }
-            if (res.data.str === "取消关注") {
-              item.is_attention = true
-            }
-          }
-        },
-        fail: (e) => {
-          console.log("关注失败:", e);
-          uni.showToast({
-            title: '网络请求失败',
-            icon: 'none'
-          });
-        }
-      });
-      // 这里可以添加调用后端API的逻辑
-    },
-    // 搜索请求
-    searchRequest() {
-    },
-    	goToUserHomepage(id) {
-			if (!id) {
-				return;
-			} 
-      uni.navigateTo({
-        url: "/pages/my/userHomepage?id=" + id,
-      });
+    handleSearch() {
+      if (!this.searchKeyword.trim()) return;
+      // 保存到历史记录
+      this.saveHistory();
+      this.searchStatus = false;
+      // 加载搜索结果
+      this.queryList();
     },
   }
 }
@@ -554,7 +267,7 @@ export default {
 
 <style lang="scss">
 .search-container {
-  background-color: #ffffff;
+  background-color: #f2f6f2;
   min-height: 100vh;
   width: 100%;
   overflow-x: hidden;
@@ -710,152 +423,11 @@ export default {
   }
 
   .search-result {
-    background-color: #ffffff;
+    // background-color: #ffffff;
     margin-top: 20rpx;
     min-height: 200rpx;
     width: 100%;
     box-sizing: border-box;
-
-    .tab-nav {
-      display: flex;
-      justify-content: flex-start;
-      padding: 20rpx 20rpx;
-      padding-top: 0;
-      box-sizing: border-box;
-      background: #ffffff;
-      width: 100%;
-      overflow-x: hidden;
-
-      .tab-item {
-        padding: 10rpx 38rpx;
-        color: #1F1F1F;
-        font-size: 28rpx;
-        background: #F2F6F2;
-        margin-right: 20rpx;
-        border-radius: 30rpx;
-        position: relative;
-        left: 0;
-        top: 0;
-        line-height: 1;
-        flex-shrink: 0;
-        white-space: nowrap;
-
-        .indicator-triangle {
-          position: absolute;
-          bottom: -10rpx;
-          left: 50%;
-          transform: translateX(-50%);
-          width: 0;
-          height: 0;
-          border-left: 10rpx solid transparent;
-          border-right: 10rpx solid transparent;
-          border-top: 10rpx solid #ACF934;
-          display: none;
-        }
-
-        &.active {
-          background: #ACF934;
-          font-family: "CustomFont" !important;
-
-          .indicator-triangle {
-            display: block;
-          }
-        }
-      }
-    }
-
-    .follow-list {
-      padding: 0;
-      width: 100%;
-      box-sizing: border-box;
-
-      .follow-item {
-        display: flex;
-        align-items: center;
-        padding: 20rpx 0;
-        width: 100%;
-        box-sizing: border-box;
-
-        .avator {
-          width: 120rpx;
-          height: 120rpx;
-          margin-right: 24rpx;
-          flex-shrink: 0;
-        }
-
-        .info {
-          flex: 1;
-          min-width: 0;
-
-          .top-box {
-            display: flex;
-            align-items: center;
-            width: 100%;
-            box-sizing: border-box;
-
-            .name {
-              font-size: 32rpx;
-              font-weight: 500;
-              margin-bottom: 8rpx;
-              max-width: 200rpx;
-              overflow: hidden;
-              text-overflow: ellipsis;
-              white-space: nowrap;
-            }
-
-            >image {
-              width: 36rpx;
-              margin-left: 8rpx;
-              margin-right: 10rpx;
-              flex-shrink: 0;
-            }
-
-            .level {
-              font-weight: 400;
-              font-size: 20rpx;
-              font-family: "PingFang SC-Bold";
-              background: linear-gradient(360deg, #acf934 0%, #ffe439 100%);
-              border-radius: 8rpx;
-              padding: 2rpx 8rpx;
-              display: inline-block;
-              flex-shrink: 0;
-            }
-          }
-        }
-
-        .unfollow-btn {
-          font-size: 24rpx;
-          width: 144rpx;
-          height: 52rpx;
-          display: flex;
-          justify-content: center;
-          align-items: center;
-          color: #1f1f1f;
-          background: #fff;
-          border: 2rpx solid #1f1f1f;
-          border-radius: 112rpx;
-          margin: 0;
-          font-family: 'PingFang SC-Bold';
-          flex-shrink: 0;
-
-          image {
-            display: none;
-            width: 16rpx;
-            height: 16rpx;
-            margin-right: 5rpx;
-          }
-
-          &.active {
-            color: #ACF934;
-            background: #000;
-
-            image {
-              display: inline-block;
-            }
-          }
-        }
-      }
-    }
   }
 
   .no-data {
@@ -864,7 +436,7 @@ export default {
     align-items: center;
     justify-content: center;
     padding: 60rpx 0;
-    background-color: #fff;
+    // background-color: #fff;
     width: 100%;
     box-sizing: border-box;
 
@@ -875,24 +447,34 @@ export default {
   }
 }
 
-    .expandBtn {
-      view {
-        font-family: 'PingFang SC-Bold';
-        color: #999999;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-
-        &.fold {
-          image {
-            transform: rotate(180deg) translateY(-2rpx);
-          }
-        }
+.expandBtn {
+  view {
+    font-family: 'PingFang SC-Bold';
+    color: #999999;
+    display: flex;
+    align-items: center;
+    justify-content: center;
 
-        image {
-          width: 28rpx;
-          height: 28rpx;
-        }
+    &.fold {
+      image {
+        transform: rotate(180deg) translateY(-2rpx);
       }
     }
+
+    image {
+      width: 28rpx;
+      height: 28rpx;
+    }
+  }
+}
+
+.items-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 24rpx 12rpx;
+  padding: 16rpx 12rpx 0 12rpx;
+  background: #f2f6f2;
+}
+.loading-more { text-align: center; color: #999; font-size: 26rpx; padding: 24rpx 0; }
+.no-more { text-align: center; color: #ccc; font-size: 24rpx; padding: 20rpx 0; }
 </style>

+ 39 - 19
pages/crowdFunding/addressEdit.vue

@@ -107,23 +107,27 @@ export default {
       }
     },
     confirm(e) {
-      this.regionText = `${e.value[0].name}/${e.value[1].name}/${e.value[2].name}`;
+      this.regionText = `${e.value[0].name} ${e.value[1].name} ${e.value[2].name}`;
       this.form.region = this.regionText;
+      // 自动填充邮编
+      // let zipcode = '';
+      // if (e.value[2] && (e.value[2].code || e.value[2].zipcode || e.value[2].postalCode)) {
+      //   zipcode = e.value[2].code || e.value[2].zipcode || e.value[2].postalCode;
+      // }
+      // this.form.zipcode = zipcode;
       this.showPicker = false;
-      uni.showToast({
-        icon: "none",
-        title: this.regionText,
-      });
+       
     },
     // 校验方法
     validateForm() {
+      console.log(this.form ,"填写的数据");
       // 姓名
       if (!this.form.name.trim()) {
         uni.showToast({ title: "请填写收货人姓名", icon: "none" });
         return false;
       }
       // 手机号
-      if (!/^1[3-9]\\d{9}$/.test(this.form.mobile)) {
+      if (!/^1[3-9]\d{9}$/.test(this.form.mobile.trim())) {
         uni.showToast({ title: "请填写正确的手机号", icon: "none" });
         return false;
       }
@@ -138,7 +142,7 @@ export default {
         return false;
       }
       // 邮编(可选,填写时校验)
-      if (this.form.zipcode && !/^\\d{6}$/.test(this.form.zipcode)) {
+      if (this.form.zipcode && !/^\d{6}$/.test(this.form.zipcode.trim())) {
         uni.showToast({ title: "请填写正确的邮政编码", icon: "none" });
         return false;
       }
@@ -147,19 +151,35 @@ export default {
 
     save() {
       if (!this.validateForm()) return;
+      // 组装参数
+      const params = {
+        realname: this.form.name,
+        mobile: this.form.mobile,
+        area: this.form.region.trim(),
+        address: this.form.detail.trim(),
+        is_default: this.form.isDefault ? 'yes' : 'no',
+        uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey,
+      };
       // 保存逻辑
-      if (this.isEdit) {
-        // 编辑地址
-        // TODO: 调用编辑接口
-        uni.showToast({ title: "编辑成功", icon: "success" });
-      } else {
-        // 新增地址
-        // TODO: 调用新增接口
-        uni.showToast({ title: "添加成功", icon: "success" });
-      }
-      setTimeout(() => {
-        uni.navigateBack();
-      }, 800);
+      uni.request({
+        url: this.$apiHost + '/Address/submitaddress',
+        method: 'GET',
+        data: params,
+        success: (res) => {
+          if (res.data && res.data.success === 'yes') {
+            uni.showToast({ title: this.isEdit ? '编辑成功' : '添加成功', icon: 'success' });
+            setTimeout(() => {
+              uni.navigateBack();
+            }, 800);
+          } else {
+            uni.showToast({ title: res.data.str || '保存失败', icon: 'none' });
+          }
+        },
+        fail: () => {
+          uni.showToast({ title: '网络错误', icon: 'none' });
+        }
+      });
     },
   },
 };

+ 4 - 4
pages/crowdFunding/components/CrowdFundingItem/CrowdFundingItem.vue

@@ -1,14 +1,14 @@
 <template>
   <view class="grid-item" @click="handleClick">
     <view class="item-image-wrapper">
-      <image :src="item.imageUrl" class="item-image"></image>
+      <image :src="item.main_image" class="item-image"></image>
     </view>
     <view class="line-box"></view>
     <view class="item-info-area">
-      <view class="item-title two-omit">{{ item.title }}</view>
+      <view class="item-title two-omit">{{ item.title || item.short_title }}</view>
       <view class="item-info">
-        <text class="item-price">已筹 ¥{{ item.raisedAmount }}</text>
-        <text class="item-supporters">支持者 {{ item.supporters }}</text>
+        <text class="item-price">已筹 ¥{{ item.current_amount }}</text>
+        <text class="item-supporters">支持者 {{ item.supporter_count }}</text>
       </view>
     </view>
   </view>

+ 41 - 34
pages/crowdFunding/components/productSpecifications/productSpecifications.vue

@@ -1,24 +1,29 @@
 <template>
   <view class="action-sheet-container" v-if="visible" @click="handleMaskClick">
-    <view class="action-sheet-mask" @touchmove.stop.prevent></view>
+    <view class="action-sheet-mask"  @click="hide"></view>
     <view class="action-sheet" :class="{ 'action-sheet-show': animationShow }" @click.stop>
       <!-- 可滚动内容区 -->
       <view class="action-sheet-scroll">
         <!-- 顶部价格与支持人数 -->
-        <view class="sheet-header">
-          <view class="sheet-price">¥{{ price }}</view>
-          <view class="sheet-support">已支持{{ supportCount }}份</view>
+        <view class="sheet-header" v-if="currentReward">
+          <view class="sheet-price">¥{{ currentReward.price }}</view>
+          <view class="sheet-support">已支持{{ currentReward.sold_count }}份</view>
         </view>
 
         <!-- 商品卡片 -->
-        <view class="sheet-product-card" @click="toggleProductSelect">
+        <view class="sheet-product-card" v-if="currentReward">
           <view class="product-info">
             <view style="display: flex">
-              <view class="product-title">{{ product.title }}</view>
-              <view class="product-time">(预计发货时间 {{ product.deliveryTime }})</view>
+              <view class="product-title two-omit">{{title + ' ' + currentReward.title }}</view>
+              <view class="product-time">
+                (预计发货时间 {{ currentReward.delivery_year }}年{{ currentReward.delivery_month }}月)
+              </view>
             </view>
-            <image class="product-img" :src="product.img" mode="aspectFill" />
-            <view class="product-detail" v-for="(d, i) in product.detail" :key="i">{{ d }}</view>
+            <image class="product-img" :src="currentReward.images[0]" mode="aspectFill" />
+            <view class="product-detail" v-for="(d, i) in currentReward.description.split('\\n')" :key="i">{{ d }}</view>
+             <view class="product-detail">发货方式:{{ currentReward.delivery_method }}</view>
+            <view class="product-detail">限购:{{ currentReward.limit_count === 0 ? '不限' : currentReward.limit_count + '份' }}</view>
+            <view class="product-detail" v-if="currentReward.is_early_bird">早鸟档,限量{{ currentReward.early_bird_limit }},截止{{ currentReward.early_bird_end_time }}</view> 
           </view>
         </view>
 
@@ -37,7 +42,7 @@
         </view>
       </view>
       <!-- 底部按钮 -->
-      <view class="action-sheet-confirm-btn" @click="handleConfirm">立即购买支持</view>
+      <view class="action-sheet-confirm-btn blick-btn-animation" @click="handleConfirm">立即购买支持</view>
       <view class="action-sheet-line"></view>
     </view>
   </view>
@@ -47,20 +52,16 @@
 export default {
   name: "productSpecifications",
   props: {
-    price: Number,
-    supportCount: Number,
-    product: Object, // {img, title, deliveryTime, detail: []}
-    specList: Array, // 规格数组
-    // 取消按钮文字
-    cancelText: {
-      type: String,
-      default: "取消",
-    },
-    // 点击遮罩是否关闭
-    maskClosable: {
-      type: Boolean,
-      default: true,
+    rewards: {
+      type: Array,
+      default: () => {
+        return [];
+      }
     },
+    title: {
+      type: String,
+      default: ''
+    }
   },
   data() {
     return {
@@ -69,6 +70,18 @@ export default {
       selectedSpecIndex: 0, // 默认选中第一个规格
     };
   },
+  computed: {
+    // 当前选中的回报档
+    currentReward() {
+      return this.rewards && this.rewards.length > 0
+        ? this.rewards[this.selectedSpecIndex]
+        : null;
+    },
+    // 规格名列表
+    specList() {
+      return this.rewards.map(r => r.title);
+    }
+  },
   methods: {
     // 显示ActionSheet
     show() {
@@ -86,23 +99,18 @@ export default {
       }, 300); // 动画持续时间
     },
 
-    toggleProductSelect() {
-      this.productSelected = !this.productSelected;
-    },
-
     selectSpec(idx) {
       this.selectedSpecIndex = idx;
     },
 
     handleConfirm() {
-      // 回传选中项
       this.$emit("confirm", {
-        productSelected: this.productSelected,
-        selectedSpec: this.specList[this.selectedSpecIndex],
+        selectedReward: this.currentReward,
+        selectedSpecIndex: this.selectedSpecIndex
       });
       this.hide();
     },
-
+    
     // 处理遮罩点击
     handleMaskClick() {
       if (this.maskClosable) {
@@ -208,6 +216,7 @@ export default {
           max-width: 340rpx;
           word-break: break-all;
           display: inline-block;
+          max-width: 300rpx;
         }
 
         .product-time {
@@ -319,9 +328,7 @@ export default {
       align-items: center;
       justify-content: center;
 
-      &:active {
-        background-color: #f2f2f2;
-      }
+   
     }
 
     .action-sheet-line {

+ 83 - 43
pages/crowdFunding/crowdFunding.vue

@@ -48,7 +48,7 @@
         :scroll-into-view="'tab-' + (currentTab - 1)"
         scroll-with-animation
       >
-        <view class="tabs-wrapper">
+        <view class="tabs-wrapper"> 
           <view
             v-for="(tab, index) in tabs"
             :key="index"
@@ -56,7 +56,8 @@
             :class="['tab-item', currentTab === index ? 'active' : '']"
             @click="switchTab(index)"
           >
-            <text>{{ tab.name }}</text>
+            <view><image v-if="tab.icon" :src="tab.icon" class="tab-icon"/>{{ tab.name }}</view>
+    
           </view>
           <!-- 右侧占位空白 -->
           <view class="tab-placeholder"></view>
@@ -109,23 +110,18 @@ export default {
   components: { CrowdFundingItem },
   data() {
     return {
-      tabs: [
-        { name: "全部", icon: "" },
-        { name: "🌟创意", icon: "/static/icon/creative-star.png" },
-        { name: "🧸潮玩", icon: "/static/icon/toy-bear.png" },
-        { name: "📖出版", icon: "" },
-        { name: "🃏桌游", icon: "" },
-        { name: "🃏桌游", icon: "" },
-      ],
+      tabs: [],
       currentTab: 0,
-      tabData: [[], [], [], [], [], []],
-      isRefreshing: [false, false, false, false, false, false],
+      tabData: [],
       scrollTop: {},
-      shouldRestoreScroll: [true, true, true, true, true, true],
       swiperHeight: 600,
-      page: [1, 1, 1, 1, 1, 1],
-      hasMore: [true, true, true, true, true, true],
-      loadingMore: [false, false, false, false, false, false],
+      isRefreshing: [],
+      shouldRestoreScroll: [],
+      page: [],
+      hasMore: [],
+      loadingMore: [],
+      pageSize: 20,
+      keyword: '',
     };
   },
   mounted() {
@@ -149,10 +145,40 @@ export default {
         })
         .exec();
     });
-    // 初始化加载第一个tab数据
-    this.fetchData(0);
+    // 动态获取tabs
+    this.getTabs();
   },
   methods: {
+    getTabs() {
+      uni.request({
+        url: this.$apiHost + '/crowdfund/categories',
+        method: 'GET',
+        success: (res) => {
+          console.log(res.data.data,"获取分类");
+          
+          if (res.data && res.data.success === 'yes' && Array.isArray(res.data.data.list)) {
+            this.tabs = [{ name: '全部', id: '' }, ...res.data.data.list.map(item => ({ name: item.name, id: item.id, icon: item.icon }))];
+          } else {
+            this.tabs = [{ name: '全部', id: '' }];
+          }
+        },
+        fail: () => {
+          this.tabs = [{ name: '全部', id: '' }];
+        },
+        complete: () => {
+          // 初始化tab相关数组长度
+          const len = this.tabs.length;
+          this.tabData = Array(len).fill([]);
+          this.isRefreshing = Array(len).fill(false);
+          this.shouldRestoreScroll = Array(len).fill(true);
+          this.page = Array(len).fill(1);
+          this.hasMore = Array(len).fill(true);
+          this.loadingMore = Array(len).fill(false);
+          // 加载第一个tab数据
+          this.fetchData(0);
+        }
+      });
+    },
     goBack() {
       uni.navigateBack();
     },
@@ -198,38 +224,43 @@ export default {
       } else {
         this.page[tabIndex] = 1;
       }
-      return new Promise((resolve) => {
-        setTimeout(() => {
-          const now = Date.now();
-          const page = this.page[tabIndex];
-          let demo = [];
-          if (page <= 3) {
-            for (let i = 0; i < 4; i++) {
-              demo.push({
-                id: now + page * 100 + i,
-                imageUrl: `/static/crowdFunding/top-img.png`,
-                title: `糖指数100%12分BJD可动人偶盲盒_${page}_${i}`,
-                raisedAmount: (769.8 + Math.floor(Math.random() * 100)).toString(),
-                supporters: 3788 + Math.floor(Math.random() * 100),
-              });
-            }
-          }
+      const params = {
+        page: this.page[tabIndex],
+        pageSize: this.pageSize,
+        category_id: this.tabs[tabIndex]?.id || '',
+        keyword: this.keyword
+      };
+      try {
+        const [err, res] = await uni.request({
+          url: this.$apiHost + '/crowdfund/list',
+          method: 'GET',
+          data: params
+        });
+        if (!err && res && res.data && res.data.data) {
+          let list = res.data.data.list;    
+          console.log(list,"获取列表");
           if (isLoadMore) {
-            if (demo.length) {
-              this.$set(this.tabData, tabIndex, [...this.tabData[tabIndex], ...demo]);
-            }
+            this.$set(this.tabData, tabIndex, [...this.tabData[tabIndex], ...list]);
           } else {
-            this.$set(this.tabData, tabIndex, demo);
+            this.$set(this.tabData, tabIndex, list);
           }
-          this.$set(this.hasMore, tabIndex, page < 3);
-          resolve();
-        }, 1000);
-      });
+          this.$set(this.hasMore, tabIndex, list.length === this.pageSize);
+        } else {
+          this.$set(this.hasMore, tabIndex, false);
+        }
+      } catch (e) {
+        this.$set(this.hasMore, tabIndex, false);
+      }
     },
     goToDetail(id) {
       // 跳转详情页
       uni.navigateTo({ url: '/pages/crowdFunding/crowdfundingDetails?id=' + id });
     },
+    // 搜索输入事件
+    onSearchInput(e) {
+      this.keyword = e.detail.value;
+      this.fetchData(this.currentTab, true);
+    },
   }, 
 };
 </script>
@@ -347,8 +378,17 @@ export default {
   font-weight: 500;
   background: transparent;
   transition: background 0.2s, color 0.2s;
-  text {
+  view {
     white-space: nowrap;
+    display: flex;
+    align-items: center;
+    .tab-icon{
+      width: 40rpx;
+      height: 40rpx;
+      margin: 0;
+      padding: 0;
+      display: inline-block;
+    }
   }
   text-wrap: nowrap;
   .tab-icon {

+ 771 - 630
pages/crowdFunding/crowdfundingDetails.vue

@@ -5,7 +5,7 @@
 				<image src="@/static/crowdFunding/back.png" mode="widthFix"></image>
 			</view>
 			<view class="navbar-center one-omit" style="max-width: 70vw; " :style="{ opacity: navBgOpacity }">
-				【Woh】灯塔 塔罗牌 治愈风泛伟特系伟特系伟特系
+				{{ detail.title }}
 			</view>
 			<view class="navbar-right scale-tap" @click="showShare = true">
 				<image src="@/static/crowdFunding/share.png" mode="widthFix"></image>
@@ -13,66 +13,45 @@
 		</view>
 		<!-- 顶部视频图片混合轮播 -->
 		<view class="swiper-container">
-			<swiper class="top-swiper" 
-				:indicator-dots="false" 
-				circular 
-				:current="currentMediaIndex" 
-				@change="handleSwiperChange"
-				:duration="300"
-			>
+			<swiper class="top-swiper" :indicator-dots="false" circular :current="currentMediaIndex"
+				@change="handleSwiperChange" :duration="300">
 				<swiper-item v-for="(item, idx) in mediaList" :key="idx" class="swiper-item">
 					<view v-if="item.type === 'video'" class="media-wrapper">
-						<video 
-							class="swiper-video" 
-							:src="item.src" 
-							:poster="item.poster" 
-							:id="'video-' + idx"
-							controls
-							object-fit="contain"
-							enable-progress-gesture="false"
-							:loop="false"
-							:show-fullscreen-btn="false"
-							:show-play-btn="true"
-							:enable-play-gesture="false"
-							@ended="onVideoEnded" 
-							@play="onVideoPlay(idx)"
-							@pause="onVideoPause"
-						></video>
+						<video class="swiper-video" :src="item.src" :poster="item.poster" :id="'video-' + idx" controls
+							object-fit="contain" enable-progress-gesture="false" :loop="false"
+							:show-fullscreen-btn="false" :show-play-btn="true" :enable-play-gesture="false"
+							@ended="onVideoEnded" @play="onVideoPlay(idx)" @pause="onVideoPause"></video>
 					</view>
 					<image v-else class="swiper-img" :src="item.src" mode="aspectFill" />
 				</swiper-item>
 			</swiper>
 			<!-- 自定义指示点 -->
 			<view class="custom-dots">
-				<view 
-					v-for="(item, index) in mediaList" 
-					:key="index"
-					:class="['dot', currentMediaIndex === index ? 'active' : '']"
-					@click="switchMedia(index)"
-				></view>
+				<view v-for="(item, index) in mediaList" :key="index"
+					:class="['dot', currentMediaIndex === index ? 'active' : '']" @click="switchMedia(index)"></view>
 			</view>
 		</view>
 
 		<view class="content">
 			<!-- 项目信息 -->
 			<view class="section project-card">
-				<view class="project-title">【Woh】灯塔 塔罗牌 治愈风泛传特系</view>
+				<view class="project-title">{{ detail.title }}</view>
 				<view class="progress-bar-wrap">
-					<uv-line-progress height="8rpx" :showText="false" :percentage="85.45" inactiveColor="#F0F0F0"
-						activeColor="#ACF934"></uv-line-progress>
-					<view class="progress-percent">85.45%</view>
+					<uv-line-progress height="8rpx" :showText="false" :percentage="detail.progress"
+						inactiveColor="#F0F0F0" activeColor="#ACF934"></uv-line-progress>
+					<view class="progress-percent">{{ detail.progress + '%' }}</view>
 				</view>
 				<view class="project-stats">
 					<view class="stat-block">
-						<view class="stat-main amountOfMoney">¥70,808.00</view>
-						<view class="stat-sub">357人支持</view>
+						<view class="stat-main amountOfMoney">¥{{ detail.current_amount }}</view>
+						<view class="stat-sub">{{ detail.supporter_count }}人支持</view>
 					</view>
 					<view class="stat-block">
-						<view class="stat-main">31天</view>
+						<view class="stat-main">{{ detail.daysRemaining }}天</view>
 						<view class="stat-sub">剩余时间</view>
 					</view>
 					<view class="stat-block">
-						<view class="stat-main">¥20,000</view>
+						<view class="stat-main">¥{{ detail.goal_amount }}</view>
 						<view class="stat-sub">众筹目标</view>
 					</view>
 				</view>
@@ -80,31 +59,32 @@
 
 
 			<!-- 项目更新 -->
-			<view class="section project-update">
-				<view class="project-update-left">
+			<view class="section project-update" v-if="projectUpdate && projectUpdate.numb">
+				<view class="project-update-left scale-tap"
+					@click="goPage('/pages/crowdFunding/projectUpdateDetails?id=' + projectUpdate.id)">
 					<view class="project-update-left-title">
-						<view>·2次更新</view>
-						<view style="color: #999;">2025.5.23 16:23</view>
+						<view>·第{{ projectUpdate.numb }}次更新</view>
+						<view style="color: #999;">{{ projectUpdate.create_time }}</view>
 					</view>
 					<view class="project-update-left-content">
-						<view>附赠精品灯塔牌包装,附赠精品灯塔牌包装</view>
+						<view class="two-omit">{{ projectUpdate.title }}</view>
 						<view class="image">
-							<image src="@/static/crowdFunding/crowdfundingDetails-poster.png" />
+							<image :src="projectUpdate.image" />
 						</view>
 					</view>
 				</view>
 				<view class="project-update-right scale-tap"
-					@click="goPage('/pages/crowdFunding/discussionArea?tags=update')">
+					@click="goPage('/pages/crowdFunding/discussionArea?tags=update&id=' +  projectId)">
 					<view>历史更新</view>
 					<image src="@/static/crowdFunding/updateDetails.png"></image>
 
 				</view>
 			</view>
 
-			<view class="section comment scale-tap">
+			<view class="section comment scale-tap"  @click="goPage('/pages/crowdFunding/discussionArea?tags=comment&id=' + projectId)" >
 				<view class="comment-title">
-					<view>项目讨论(10)</view>
-					<view class="comment-more" @click="goPage('/pages/crowdFunding/discussionArea?tags=comment')">查看更多
+					<view>项目讨论({{ totalNumberOfComments }})</view>
+					<view class="comment-more"">查看更多
 						<image src="@/static/crowdFunding/right.png"></image>
 					</view>
 				</view>
@@ -128,19 +108,20 @@
 			<!-- 塔罗牌介绍 -->
 			<view class="section poster">
 				<view class="initiator-bar">
-					<image class="initiator-avatar" :src="initiator.avatar" />
+					<image class="initiator-avatar" :src="detail.creator_avatar" />
 					<view class="initiator-info">
-						<text class="initiator-name">{{ initiator.name }}</text>
+						<text class="initiator-name">{{ detail.creator_nickname }}</text>
 						<text class="initiator-tag">发起人</text>
 					</view>
 					<view class="initiator-service-btn  blick-btn-animation"
-						@click="goPage('/pages/crowdFunding/customerService')">
+						@click="goPage('/pages/crowdFunding/customerService?id=' + detail.creator_id)">
 						<image class="service-icon" src="@/static/crowdFunding/service.png" />
 						<text>客服</text>
 					</view>
 				</view>
-				<image class="intro-img" src="@/static/crowdFunding/crowdfundingDetails-poster.png" mode="widthFix" />
-
+				<block v-for="(item, idx) in detail.content_images" :key="idx">
+					<image class="intro-img" :src="item" mode="widthFix" />
+				</block>
 			</view>
 
 
@@ -166,16 +147,17 @@
 		<view class="bottom-bar-reserveASeat"></view>
 		<view class="bottom-bar">
 			<view class="bottom-bar-left">
-				<view class="bar-btn">
-					<image v-if="true" src="@/static/crowdFunding/collect.png" class=" scale-tap bar-icon" />
-					<image v-else src="@/static/crowdFunding/collect-active.png" class=" scale-tap bar-icon" />
-					<view class="bar-text">收藏</view>
+				<view class="bar-btn" @click="toggleFavorite">
+					<image v-if="isFavorite" src="@/static/crowdFunding/collect-active.png"
+						class="scale-tap bar-icon" />
+					<image v-else src="@/static/crowdFunding/collect.png" class="scale-tap bar-icon" />
+					<view class="bar-text">{{ isFavorite ? '已收藏' : '收藏' }}</view>
 				</view>
-				<view class="bar-btn">
+				<!-- <view class="bar-btn">
 					<image v-if="true" src="@/static/crowdFunding/like.png" class=" scale-tap bar-icon" />
 					<image v-else src="@/static/crowdFunding/like-active.png" class=" scale-tap bar-icon" />
 					<view class="bar-text">看好</view>
-				</view>
+				</view> -->
 			</view>
 			<button class="buy-btn blick-btn-animation" @click="specificationsOpen()">立即购买支持</button>
 		</view>
@@ -183,316 +165,486 @@
 			@click="scrollToTop"></image>
 
 		<!-- 分享弹窗 -->
-		<SharePopup :visible="showShare" :userId="userId" :share-title="shareTitle" :share-desc="shareDesc"
+		<SharePopup :visible="showShare" :userId="0" :share-title="shareTitle" :share-desc="shareDesc"
 			:share-img="shareImg" view="crowdfundingDetails" @close="showShare = false" :isReportContent="true" />
 
-		<productSpecifications ref="specSheet" :price="29.9" :supportCount="357" :product="{
-			img: '/static/crowdFunding/top-img.png',
-			title: '灯塔 塔罗牌 治愈风泛',
-			deliveryTime: '2025年5月内',
-			detail: ['灯塔塔罗牌*1', '联名周边*1', '签名*1', ]
-		}" :specList="['灯塔MINI版', '灯塔铁盒版', '灯塔典藏版']" @confirm="onSpecConfirm" />
+		<productSpecifications ref="specSheet" :rewards="rewards" :title="detail.title" @confirm="onSpecConfirm" />
 
 	</view>
 </template>
 
 <script>
-	import VideoPlayer from "@/components/VideoPlayer/VideoPlayer.vue";
-	import SharePopup from "@/components/SharePopup/SharePopup.vue";
-	import productSpecifications from "./components/productSpecifications/productSpecifications.vue";
-	export default {
-		components: {
-			VideoPlayer,
-			SharePopup,
-			productSpecifications
-		},
-		data() {
+import VideoPlayer from "@/components/VideoPlayer/VideoPlayer.vue";
+import SharePopup from "@/components/SharePopup/SharePopup.vue";
+import productSpecifications from "./components/productSpecifications/productSpecifications.vue";
+
+export default {
+	components: {
+		VideoPlayer,
+		SharePopup,
+		productSpecifications
+	},
+	data() {
+		return {
+			mediaList: [],
+			videoPlaying: false,
+			currentMediaIndex: 0,
+			commentList: [ 
+			],
+			navBgOpacity: 0,
+			swiperHeight: 0,
+			showShare: false,
+			shareTitle: '【Woh】灯塔 塔罗牌 治愈风泛传特系',
+			shareDesc: '快来支持这个有趣的众筹项目吧!',
+			shareImg: require('@/static/crowdFunding/top-img.png'),
+			userId: 0, // 可根据实际登录用户赋值
+			isFavorite: false, // 是否已收藏
+			projectId: null, // 当前项目id
+			detail: {}, // 众筹详情
+			projectUpdate: '',
+			rewards: [], 
+			totalNumberOfComments:0
+		}
+	},
+	computed: {
+		navBgStyle() {
 			return {
-				mediaList: [
-					{
-						type: 'image',
-						src: '../../static/crowdFunding/top-img.png'
-					},{
-						type: 'video',
-						src: 'https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4',
-						poster: 'https://storage.googleapis.com/gtv-videos-bucket/sample/images/ForBiggerBlazes.jpg'
-					},
-					{
-						type: 'image',
-						src: 'https://img.alicdn.com/imgextra/i3/2200704180017/O1CN01Qw6QwF1w6Qw6QwF1w6QwF_!!2200704180017.jpg'
-					}
-				],
-				videoPlaying: false,
-				currentMediaIndex: 0,
-				commentList: [{
-						avatar: '/static/crowdFunding/top-img.png',
-						content: '还是希望签名能签在书上,还是希望签名能签在书上还是希望签名能签在书上还是希望签名能签在书上,还是希望签名能签在书上还是希望签名能签在书上',
-						likeNum: 12,
-						liked: false
-					},
-					{
-						avatar: '/static/crowdFunding/top-img.png',
-						content: '还是希望签名能签在书上',
-						likeNum: 12,
-						liked: true
-					}
-				],
-				navBgOpacity: 0,
-				swiperHeight: 0,
-				initiator: {
-					avatar: '/static/crowdFunding/top-img.png',
-					name: '也许时间是一种解药'
-				},
-				showShare: false,
-				shareTitle: '【Woh】灯塔 塔罗牌 治愈风泛传特系',
-				shareDesc: '快来支持这个有趣的众筹项目吧!',
-				shareImg: require('@/static/crowdFunding/top-img.png'),
-				userId: 0, // 可根据实际登录用户赋值
+				background: `rgba(255,255,255,${this.navBgOpacity})`,
+				transition: 'background 0.3s'
+			}
+		}
+	},
+	methods: {
+		// 返回上一页
+		goBack() {
+			uni.navigateBack({
+				delta: 1,
+			});
+		},
+		scrollToTop() {
+			uni.pageScrollTo({
+				scrollTop: 0,
+				duration: 300
+			});
+		},
+		switchMedia(index) {
+			if (this.currentMediaIndex === index) return;
+
+			// 如果当前在播放视频,先暂停
+			if (this.mediaList[this.currentMediaIndex]?.type === 'video') {
+				const videoContext = uni.createVideoContext('video-' + this.currentMediaIndex, this);
+				if (videoContext) {
+					videoContext.pause();
+				}
 			}
+
+			this.currentMediaIndex = index;
 		},
-		computed: {
-			navBgStyle() {
-				return {
-					background: `rgba(255,255,255,${this.navBgOpacity})`,
-					transition: 'background 0.3s'
+		handleSwiperChange(e) {
+			const lastIndex = this.currentMediaIndex;
+			this.currentMediaIndex = e.detail.current;
+
+			// 如果上一个是视频,暂停它
+			if (this.mediaList[lastIndex]?.type === 'video') {
+				const videoContext = uni.createVideoContext('video-' + lastIndex, this);
+				if (videoContext) {
+					videoContext.pause();
+					this.videoPlaying = false;
 				}
 			}
 		},
-		methods: {
-			// 返回上一页
-			goBack() {
-				uni.navigateBack({
-					delta: 1,
-				});
-			},
-			scrollToTop() {
-				uni.pageScrollTo({
-					scrollTop: 0,
-					duration: 300
-				});
-			},
-			switchMedia(index) {
-				if (this.currentMediaIndex === index) return;
-				
-				// 如果当前在播放视频,先暂停
-				if (this.mediaList[this.currentMediaIndex]?.type === 'video') {
-					const videoContext = uni.createVideoContext('video-' + this.currentMediaIndex, this);
-					if (videoContext) {
-						videoContext.pause();
+		onVideoPlay(idx) {
+			// 更新当前播放的视频索引
+			this.videoPlaying = true;
+			if (this.currentMediaIndex !== idx) {
+				this.currentMediaIndex = idx;
+			}
+		},
+		onVideoPause() {
+			this.videoPlaying = false;
+		},
+		onVideoEnded() {
+			this.videoPlaying = false;
+		},
+		goPage(url) {
+			uni.navigateTo({
+				url: url
+			});
+		},
+		onSpecConfirm(selectedSpec) {
+			console.log('selectedSpec', selectedSpec);
+		},
+		specificationsOpen() {
+			this.$refs.specSheet.show();
+		},
+		toggleFavorite() {
+			if (!this.projectId) {
+				 
+				return;
+			}
+			const action = this.isFavorite ? 'remove' : 'add';
+			uni.request({
+				url: this.$apiHost + '/crowdfund/favorite',
+				method: 'POST',
+				header: {
+					"content-type": "application/x-www-form-urlencoded",
+				},
+				data: {
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey,
+					crowdfund_id: this.projectId,
+					action
+				},
+				success: (res) => {
+					console.log(res.data, "收藏");
+
+					if (res.data && res.data.success && res.data.success == 'yes') {
+						this.isFavorite = !this.isFavorite;
+						uni.showToast({ title: this.isFavorite ? '已收藏' : '已取消收藏', icon: 'none' });
+					} else {
+						uni.showToast({ title: res.data.msg || '操作失败', icon: 'none' });
 					}
+				},
+				fail: () => {
+					uni.showToast({ title: '网络错误', icon: 'none' });
 				}
-				
-				this.currentMediaIndex = index;
-			},
-			handleSwiperChange(e) {
-				const lastIndex = this.currentMediaIndex;
-				this.currentMediaIndex = e.detail.current;
-				
-				// 如果上一个是视频,暂停它
-				if (this.mediaList[lastIndex]?.type === 'video') {
-					const videoContext = uni.createVideoContext('video-' + lastIndex, this);
-					if (videoContext) {
-						videoContext.pause();
-						this.videoPlaying = false;
+			});
+
+		},
+		getDetail() {
+			if (!this.projectId) return;
+			uni.request({
+				url: this.$apiHost + '/crowdfund/detail',
+				method: 'GET',
+				data: {
+					id: this.projectId,
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey
+
+				},
+				success: (res) => {
+					if (res.data && res.data.success === 'yes' && res.data.data) {
+						this.processingDataDetails(res.data.data);
+						// 可根据接口返回字段设置isFavorite等
 					}
 				}
-			},
-			onVideoPlay(idx) {
-				// 更新当前播放的视频索引
-				this.videoPlaying = true;
-				if (this.currentMediaIndex !== idx) {
-					this.currentMediaIndex = idx;
+			});
+			uni.request({
+				url: this.$apiHost + '/crowdfund/favorite/status',
+				method: 'GET',
+				data: {
+					crowdfund_id: this.projectId,
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey
+				},
+				success: (res) => {
+					if (res.data && res.data.success === 'yes' && res.data.data) {
+						console.log(res.data.data, "收藏");
+						this.isFavorite = res.data.data.is_favorited;
+						// 可根据接口返回字段设置isFavorite等
+					}
 				}
-			},
-			onVideoPause() {
-				this.videoPlaying = false;
-			},
-			onVideoEnded() {
-				this.videoPlaying = false;
-			},
-			goPage(url) {
-				uni.navigateTo({
-					url: url
-				});
-			},
-			onSpecConfirm(selectedSpec) {
-				console.log('selectedSpec', selectedSpec);
-			},
-			specificationsOpen() {
-				this.$refs.specSheet.show();
-			},
-		},
-		mounted() {
-			this.$nextTick(() => {
-				// 动态获取轮播图高度
-				uni.createSelectorQuery().in(this).select('.top-swiper').boundingClientRect(rect => {
-					if (rect) {
-						this.swiperHeight = rect.height;
+			});
+			uni.request({
+				url: this.$apiHost + '/crowdfund/articles',
+				method: 'GET',
+				data: {
+					crowdfund_id: this.projectId,
+					page: 1,
+					pageSize: 1,
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey
+				},
+				success: (res) => {
+					if (res.data && res.data.success === 'yes' && res.data.data) {
+						if (Array.isArray(res.data.data.list)) {
+							this.projectUpdate = res.data.data.list[0]
+							this.projectUpdate.create_time = this.projectUpdate.create_time.replace(/-/g, '.').slice(0, 16)
+							console.log(this.projectUpdate, 8888);
+
+						}
 					}
-				}).exec();
+				}
+			}); 
+			uni.request({
+				url: this.$apiHost + '/Article/getcomments',
+				data: {
+					uuid: getApp().globalData.uuid,
+					type: 'crowdfund',
+					id: this.projectId,
+					page: 1,
+					limit: 2,
+				},
+				header: {
+					"content-type": "application/json",
+					'sign': getApp().globalData.headerSign
+				},
+				success: (res) => {
+					console.log("评论列表:", res.data);
+					if (res.data.success == "yes") { 
+						this.totalNumberOfComments = res.data.total
+						// 确保数据存在且是数组,然后只取前两条
+						this.commentList = (res.data.list || []).slice(0, 2).map(item => ({
+							avatar: item.user_avatar || '',
+							content: item.user_content || '',
+							likeNum: item.like_count || 0,
+							liked: item.is_like || false
+						}));
+						
+					} else {
+						// 如果请求失败,使用默认空数组
+						this.commentList = [];
+						uni.showToast({
+							title: '获取评论列表失败',
+							icon: 'none'
+						});
+					}
+				},
+				fail: (e) => {
+					console.log("----e:", e);
+					// 请求失败时使用默认空数组
+					this.commentList = [];
+				}
 			});
+
 		},
-		onPageScroll(e) {
-			const threshold = this.swiperHeight || uni.upx2px(400); // 优先用实际高度
-			let opacity = 0;
-			if (e.scrollTop > 0) {
-				opacity = Math.min(e.scrollTop / threshold, 1);
+		processingDataDetails(data) {
+			this.detail = data;
+			// 确保 image_list 始终是一个数组
+			data.image_list = data.image_list || [];
+
+			const videoItem = data.video_url ? [{
+				type: 'video',
+				poster: data.main_image,
+				src: data.video_url,
+			}] : [];
+
+			const imageItems = data.image_list.map(v => ({
+				type: 'image',
+				src: v
+			}));
+
+			// 计算剩余天数
+			if (data.start_time && data.end_time) {
+				const startDate = new Date(data.start_time.replace(/-/g, '/'));
+				const endDate = new Date(data.end_time.replace(/-/g, '/'));
+				const now = new Date();
+
+				// 如果当前时间在开始时间之前,显示总天数
+				if (now < startDate) {
+					this.detail.daysRemaining = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24));
+				}
+				// 如果当前时间在结束时间之后,显示0天
+				else if (now > endDate) {
+					this.detail.daysRemaining = 0;
+				}
+				// 如果当前时间在开始和结束时间之间,显示剩余天数
+				else {
+					this.detail.daysRemaining = Math.ceil((endDate - now) / (1000 * 60 * 60 * 24));
+				}
+			} else {
+				this.detail.daysRemaining = 0;
 			}
-			this.navBgOpacity = opacity;
+			// 计算进度
+			this.detail.progress = data.current_amount / data.goal_amount
+			if (Number.isNaN) this.detail.progress = 0
+			this.mediaList = [...videoItem, ...imageItems];
+
+			this.rewards = data.rewards
+
+			console.log("回报数据", this.rewards);
+			console.log("顶部轮播数据", this.mediaList, "mediaList");
+			console.log("详情", this.detail, "detail");
 		}
+	},
+	mounted() {
+		this.$nextTick(() => {
+			// 动态获取轮播图高度
+			uni.createSelectorQuery().in(this).select('.top-swiper').boundingClientRect(rect => {
+				if (rect) {
+					this.swiperHeight = rect.height;
+				}
+			}).exec();
+		});
+	},
+	onPageScroll(e) {
+		const threshold = this.swiperHeight || uni.upx2px(400); // 优先用实际高度
+		let opacity = 0;
+		if (e.scrollTop > 0) {
+			opacity = Math.min(e.scrollTop / threshold, 1);
+		}
+		this.navBgOpacity = opacity;
+	},
+	onLoad(options) {
+		// 获取id
+		this.projectId = options.id || null;
+		this.getDetail();
 	}
+}
 </script>
 
 
 <style lang="scss" scoped>
-	.crowdfunding-details {
+.crowdfunding-details {
 
-		/* 自定义导航栏样式 */
-		.custom-navbar {
-			display: flex;
-			flex-direction: row;
-			align-items: center;
-			justify-content: space-between;
+	/* 自定义导航栏样式 */
+	.custom-navbar {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: space-between;
+		width: 100%;
+		height: calc(90rpx + var(--status-bar-height));
+		padding: 0 20rpx;
+		position: fixed;
+		top: 0;
+		z-index: 100;
+		padding: 12rpx 24rpx;
+		padding-top: calc(var(--status-bar-height) + 12rpx);
+		background: transparent;
+		transition: background 0.3s;
+
+		image {
+			width: 64rpx;
+			height: 64rpx;
+		}
+	}
+
+	.swiper-container {
+		position: relative;
+		width: 100vw;
+		height: 100vw;
+		background: #000;
+
+		.top-swiper {
 			width: 100%;
-			height: calc(90rpx + var(--status-bar-height));
-			padding: 0 20rpx;
-			position: fixed;
-			top: 0;
-			z-index: 100;
-			padding: 12rpx 24rpx;
-			padding-top: calc(var(--status-bar-height) + 12rpx);
-			background: transparent;
-			transition: background 0.3s;
+			height: 100%;
 
-			image {
-				width: 64rpx;
-				height: 64rpx;
+			.swiper-item {
+				width: 100%;
+				height: 100%;
+				display: flex;
+				align-items: center;
+				justify-content: center;
 			}
-		}
 
-		.swiper-container {
-			position: relative;
-			width: 100vw;
-			height: 100vw;
-			background: #000;
+			.media-wrapper {
+				width: 100%;
+				height: 100%;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				background: #000;
+			}
 
-			.top-swiper {
+			.swiper-video {
 				width: 100%;
 				height: 100%;
+			}
 
-				.swiper-item {
-					width: 100%;
-					height: 100%;
-					display: flex;
-					align-items: center;
-					justify-content: center;
-				}
+			.swiper-img {
+				width: 100%;
+				height: 100%;
+				object-fit: cover;
+			}
+		}
 
-				.media-wrapper {
-					width: 100%;
-					height: 100%;
-					display: flex;
-					align-items: center;
-					justify-content: center;
-					background: #000;
+		.custom-dots {
+			position: absolute;
+			bottom: 20rpx;
+			left: 50%;
+			transform: translateX(-50%);
+			display: flex;
+			gap: 16rpx;
+
+			.dot {
+				width: 12rpx;
+				height: 12rpx;
+				border-radius: 50%;
+				background: rgba(255, 255, 255, 0.5);
+				transition: all 0.3s;
+
+				&.active {
+					width: 24rpx;
+					border-radius: 6rpx;
+					background: #fff;
 				}
+			}
+		}
+	}
 
-				.swiper-video {
-					width: 100%;
-					height: 100%;
-				}
+	.content {
+		background: #f2f6f2;
+		padding: 20rpx;
 
-				.swiper-img {
-					width: 100%;
-					height: 100%;
-					object-fit: cover;
-				}
-			}
+		.section {
+			background: #fff;
+			border-radius: 12rpx;
+			padding: 16rpx;
+			padding-bottom: 20rpx;
+			margin: 12rpx 0;
 
-			.custom-dots {
-				position: absolute;
-				bottom: 20rpx;
-				left: 50%;
-				transform: translateX(-50%);
-				display: flex;
-				gap: 16rpx;
+			.section-title {
+				font-size: 28rpx;
+				font-family: 'PingFang SC-Medium';
+				margin-bottom: 6rpx;
+			}
 
-				.dot {
-					width: 12rpx;
-					height: 12rpx;
-					border-radius: 50%;
-					background: rgba(255, 255, 255, 0.5);
-					transition: all 0.3s;
+			.section-content {
+				color: #333;
+				font-size: 24rpx;
+				line-height: 1.8;
+			}
 
-					&.active {
-						width: 24rpx;
-						border-radius: 6rpx;
-						background: #fff;
-					}
-				}
+			.intro-img {
+				width: 100%;
+				margin: 0;
+				padding: 0;
+				margin-bottom: -10rpx;
 			}
 		}
 
-		.content {
-			background: #f2f6f2;
-			padding: 20rpx;
-
-			.section {
-				background: #fff;
-				border-radius: 12rpx;
-				padding: 16rpx;
-				padding-bottom: 20rpx;
-				margin: 12rpx 0;
+		.project-card {
+			padding-bottom: 15rpx;
 
-				.section-title {
-					font-size: 28rpx;
-					font-family: 'PingFang SC-Medium';
-					margin-bottom: 6rpx;
-				}
+			.project-title {
+				font-size: 36rpx;
+				color: 1f1f1f;
+				font-family: "PingFang SC-Bold";
+				font-weight: 400;
+			}
 
-				.section-content {
-					color: #333;
-					font-size: 24rpx;
-					line-height: 1.8;
-				}
+			.progress-bar-wrap {
+				display: flex;
+				align-items: center;
+				font-size: 20rpx;
+				color: #1F1F1F;
+				padding-top: 30rpx;
+				padding-bottom: 14rpx;
 
-				.intro-img {
-					width: 100%;
-					margin: 0;
-					padding: 0;
-					margin-bottom: -10rpx;
+				.progress-percent {
+					padding-left: 12rpx;
 				}
 			}
 
-			.project-card {
-				padding-bottom: 15rpx;
-
-				.project-title {
-					font-size: 36rpx;
-					color: 1f1f1f;
-					font-family: "PingFang SC-Bold";
-					font-weight: 400;
-				}
+			.project-stats {
+				display: flex;
+				justify-content: space-between;
+				padding-top: 0;
 
-				.progress-bar-wrap {
+				.stat-block {
 					display: flex;
+					flex-direction: column;
 					align-items: center;
-					font-size: 20rpx;
+					text-align: center;
+					justify-content: center;
 					color: #1F1F1F;
-					padding-top: 30rpx;
-					padding-bottom: 14rpx;
 
-					.progress-percent {
-						padding-left: 12rpx;
+					&:first-child {
+						align-items: flex-start;
 					}
-				}
-
-				.project-stats {
-					display: flex;
-					justify-content: space-between;
-					padding-top: 0;
 
-					.stat-block {
+					&:last-child {
 						display: flex;
 						flex-direction: column;
 						align-items: center;
@@ -505,412 +657,401 @@
 						}
 
 						&:last-child {
-							display: flex;
-							flex-direction: column;
-							align-items: center;
-							text-align: center;
-							justify-content: center;
-							color: #1F1F1F;
-
-							&:first-child {
-								align-items: flex-start;
-							}
-
-							&:last-child {
-								align-items: flex-end;
-							}
+							align-items: flex-end;
+						}
 
-							.stat-main {
-								font-size: 28rpx;
+						.stat-main {
+							font-size: 28rpx;
 
-								&.amountOfMoney {
-									font-size: 32rpx;
-									font-family: "PingFang SC-Bold";
-								}
+							&.amountOfMoney {
+								font-size: 32rpx;
+								font-family: "PingFang SC-Bold";
 							}
+						}
 
-							.stat-sub {
-								font-size: 20rpx;
-							}
+						.stat-sub {
+							font-size: 20rpx;
 						}
 					}
 				}
 			}
+		}
 
-			.project-update {
-				background: transparent;
-				height: 166rpx;
-				display: flex;
-				width: 100%;
-				justify-content: space-between;
-				padding: 0;
+		.project-update {
+			background: transparent;
+			height: 166rpx;
+			display: flex;
+			width: 100%;
+			justify-content: space-between;
+			padding: 0;
 
-				>view {
-					border-radius: 12rpx;
-					background: #fff;
-					flex-shrink: 0;
+			>view {
+				border-radius: 12rpx;
+				background: #fff;
+				flex-shrink: 0;
+			}
+
+			.project-update-left {
+				width: 590rpx;
+				height: 100%;
+				padding: 16rpx;
+
+				.project-update-left-title {
+					display: flex;
+					justify-content: space-between;
+					align-items: center;
+					font-size: 22rpx;
 				}
 
-				.project-update-left {
-					width: 590rpx;
-					height: 100%;
-					padding: 16rpx;
+				.project-update-left-content {
+					display: flex;
+					align-items: center;
+					margin-top: 8rpx;
 
-					.project-update-left-title {
-						display: flex;
-						justify-content: space-between;
-						align-items: center;
-						font-size: 22rpx;
+					>view {
+						font-size: 24rpx;
+						font-weight: 400;
+						font-family: "PingFang SC-Bold";
 					}
 
-					.project-update-left-content {
-						display: flex;
-						align-items: center;
-						margin-top: 8rpx;
-
-						>view {
-							font-size: 24rpx;
-							font-weight: 400;
-							font-family: "PingFang SC-Bold";
-						}
+					.image {
+						width: 180rpx;
+						height: 78rpx;
+						overflow: hidden;
+						margin-left: 26rpx;
+						border-radius: 8rpx;
 
-						.image {
-							width: 180rpx;
-							height: 78rpx;
+						image {
 							overflow: hidden;
-							margin-left: 26rpx;
-							border-radius: 8rpx;
-
-							image {
-								overflow: hidden;
-								width: 100%;
-							}
+							width: 100%;
 						}
 					}
-
-				}
-
-				.project-update-right {
-					width: 108rpx;
-					height: 100%;
-					font-size: 22rpx;
-					display: flex;
-					align-items: center;
-					justify-content: center;
-					flex-direction: column;
-
-					image {
-						margin-top: 12rpx;
-						width: 28rpx;
-						height: 28rpx;
-					}
 				}
-			}
 
-			.poster {
-				padding: 0;
-				padding-top: 16rpx;
 			}
-		}
-
-		.comment {
-			border-radius: 12rpx;
-			background: #fff;
-			margin-top: 24rpx;
-			padding: 0 0 16rpx 0;
 
-			.comment-title {
+			.project-update-right {
+				width: 108rpx;
+				height: 100%;
+				font-size: 22rpx;
 				display: flex;
-				justify-content: space-between;
 				align-items: center;
-				font-size: 26rpx;
-				color: #333;
-				padding: 18rpx 20rpx 0 20rpx;
+				justify-content: center;
+				flex-direction: column;
 
-				.comment-more {
-					color: #999;
-					font-size: 22rpx;
-					display: flex;
-					align-items: center;
-
-					image {
-						width: 20rpx;
-						height: 20rpx;
-						margin-left: 4rpx;
-					}
+				image {
+					margin-top: 12rpx;
+					width: 28rpx;
+					height: 28rpx;
 				}
 			}
+		}
 
-			.comment-content {
-				padding: 0 20rpx;
-
-				.comment-item {
-					display: flex;
-					align-items: flex-start;
-					padding: 18rpx 0 0 0;
-					border-bottom: 1rpx solid #f5f5f5;
-
-					&:last-child {
-						border-bottom: none;
-					}
-
-					.comment-avatar {
-						width: 48rpx;
-						height: 48rpx;
-						border-radius: 50%;
-						margin-right: 16rpx;
-						flex-shrink: 0;
-					}
-
-					.comment-item-main {
-						flex: 1;
-						display: flex;
-						flex-direction: column;
+		.poster {
+			padding: 0;
+			padding-top: 16rpx;
+		}
+	}
 
-						.comment-item-content {
-							color: #1f1f1f;
-							font-size: 24rpx;
-							line-height: 1.7;
-							margin-bottom: 8rpx;
-							display: -webkit-box;
-							-webkit-line-clamp: 2;
-							-webkit-box-orient: vertical;
-							overflow: hidden;
-							text-overflow: ellipsis;
-							word-break: break-all;
-						}
-					}
+	.comment {
+		border-radius: 12rpx;
+		background: #fff;
+		margin-top: 24rpx;
+		padding: 0 0 16rpx 0;
 
-					.comment-item-like {
-						display: flex;
-						align-items: center;
-						margin-left: 36rpx;
+		.comment-title {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			font-size: 26rpx;
+			color: #333;
+			padding: 18rpx 20rpx 0 20rpx;
 
-						.like-icon {
-							width: 28rpx;
-							height: 28rpx;
-							margin-right: 4rpx;
-						}
+			.comment-more {
+				color: #999;
+				font-size: 22rpx;
+				display: flex;
+				align-items: center;
 
-						.like-num {
-							font-size: 22rpx;
-							color: #888;
-						}
-					}
+				image {
+					width: 20rpx;
+					height: 20rpx;
+					margin-left: 4rpx;
 				}
 			}
 		}
 
-		.bottom-bar-reserveASeat {
-			width: 100%;
-			height: calc(12rpx + 88rpx + var(--window-bottom) + 30rpx);
-		}
-
-		.bottom-bar {
-			position: fixed;
-			left: 0;
-			right: 0;
-			bottom: 0;
-			z-index: 999;
-			display: flex;
-			align-items: center;
-			justify-content: space-between;
-			background: #fff;
-			padding: 14rpx 40rpx;
-			padding-bottom: calc(14rpx + var(--window-bottom));
-			box-sizing: border-box;
+		.comment-content {
+			padding: 0 20rpx;
 
-			.bottom-bar-left {
+			.comment-item {
 				display: flex;
+				//align-items: flex-start;
 				align-items: center;
-				gap: 32rpx;
+				padding: 18rpx 0 0 0;
+				border-bottom: 1rpx solid #f5f5f5;
+
+				&:last-child {
+					border-bottom: none;
+				}
+
+				.comment-avatar {
+					width: 48rpx;
+					height: 48rpx;
+					border-radius: 50%;
+					margin-right: 16rpx;
+					flex-shrink: 0;
+				}
 
-				.bar-btn {
+				.comment-item-main {
+					flex: 1;
 					display: flex;
 					flex-direction: column;
-					align-items: center;
-					justify-content: center;
-					width: 80rpx;
-					height: 80rpx;
-					border-radius: 12rpx;
-
-					.bar-icon {
-						width: 48rpx;
-						height: 48rpx;
-						margin-bottom: 4rpx;
-					}
 
-					.bar-text {
-						font-size: 20rpx;
+					.comment-item-content {
 						color: #1f1f1f;
-						font-family: "PingFang SC";
+						font-size: 24rpx;
+						line-height: 1.7;
+						margin-bottom: 8rpx;
+						display: -webkit-box;
+						-webkit-line-clamp: 2;
+						-webkit-box-orient: vertical;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						word-break: break-all;
 					}
 				}
-			}
 
+				.comment-item-like {
+					display: flex;
+					align-items: center;
+					margin-left: 36rpx;
 
-			.buy-btn {
-				width: 500rpx;
-				height: 88rpx;
-				background: #1f1f1f;
-				color: #ACF934;
-				font-size: 32rpx;
-				border-radius: 80rpx;
-				border: none;
-				font-weight: bold;
-				text-align: center;
-				line-height: 80rpx;
-				margin-left: 24rpx;
-			}
+					.like-icon {
+						width: 28rpx;
+						height: 28rpx;
+						margin-right: 4rpx;
+					}
 
+					.like-num {
+						font-size: 22rpx;
+						color: #888;
+					}
+				}
+			}
 		}
 	}
 
-	.back-top {
-		position: fixed;
-		bottom: calc(126rpx + var(--window-bottom));
-		right: 16rpx;
-		width: 82rpx;
-		height: 82rpx;
+	.bottom-bar-reserveASeat {
+		width: 100%;
+		height: calc(12rpx + 88rpx + var(--window-bottom) + 30rpx);
 	}
 
-	.initiator-bar {
+	.bottom-bar {
+		position: fixed;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		z-index: 999;
 		display: flex;
 		align-items: center;
 		justify-content: space-between;
 		background: #fff;
-		border-radius: 10rpx;
-		padding: 18rpx 24rpx 18rpx 18rpx;
-		margin: 0;
-
-		.initiator-avatar {
-			width: 64rpx;
-			height: 64rpx;
-			border-radius: 50%;
-			margin-right: 18rpx;
-			flex-shrink: 0;
-		}
+		padding: 14rpx 40rpx;
+		padding-bottom: calc(14rpx + var(--window-bottom));
+		box-sizing: border-box;
 
-		.initiator-info {
+		.bottom-bar-left {
 			display: flex;
 			align-items: center;
-			flex: 1;
-			min-width: 0;
-		}
+			gap: 32rpx;
 
-		.initiator-name {
-			font-size: 30rpx;
-			color: #222;
-			font-weight: bold;
-			margin-right: 12rpx;
-			max-width: 260rpx;
-			overflow: hidden;
-			text-overflow: ellipsis;
-			white-space: nowrap;
-		}
+			.bar-btn {
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				justify-content: center;
+				width: 80rpx;
+				height: 80rpx;
+				border-radius: 12rpx;
+
+				.bar-icon {
+					width: 48rpx;
+					height: 48rpx;
+					margin-bottom: 4rpx;
+				}
 
-		.initiator-tag {
-			background: #1a1a1a;
-			color: #b6ff4b;
-			font-size: 20rpx;
-			border-radius: 8rpx;
-			padding: 2rpx 12rpx;
-			margin-left: 2rpx;
+				.bar-text {
+					font-size: 20rpx;
+					color: #1f1f1f;
+					font-family: "PingFang SC";
+				}
+			}
 		}
 
-		.initiator-service-btn {
-			display: flex;
-			align-items: center;
-			background: #1a1a1a;
-			color: #b6ff4b;
-			font-size: 28rpx;
-			border-radius: 128rpx;
-			padding: 0 24rpx 0 12rpx;
-			height: 56rpx;
-			margin-left: 18rpx;
+
+		.buy-btn {
+			width: 588rpx;
+			height: 88rpx;
+			background: #1f1f1f;
+			color: #ACF934;
+			font-size: 32rpx;
+			border-radius: 80rpx;
+			border: none;
 			font-weight: bold;
+			text-align: center;
+			line-height: 80rpx;
+			margin-left: 24rpx;
 		}
 
-		.service-icon {
-			width: 32rpx;
-			height: 32rpx;
-			margin-right: 8rpx;
-		}
 	}
-
-	.scale-tap {
-		transition: transform 0.15s;
+}
+
+.back-top {
+	position: fixed;
+	bottom: calc(126rpx + var(--window-bottom));
+	right: 16rpx;
+	width: 82rpx;
+	height: 82rpx;
+}
+
+.initiator-bar {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	background: #fff;
+	border-radius: 10rpx;
+	padding: 18rpx 24rpx 18rpx 18rpx;
+	margin: 0;
+
+	.initiator-avatar {
+		width: 64rpx;
+		height: 64rpx;
+		border-radius: 50%;
+		margin-right: 18rpx;
+		flex-shrink: 0;
 	}
 
-	.scale-tap:active {
-		transform: scale(0.92);
+	.initiator-info {
+		display: flex;
+		align-items: center;
+		flex: 1;
+		min-width: 0;
 	}
 
-	.risk-section {
-		background: #fff;
-		border-radius: 12rpx;
-		margin: 24rpx 0 0 0;
-		padding: 0 0 18rpx 0;
-		position: relative;
+	.initiator-name {
+		font-size: 30rpx;
+		color: #222;
+		font-weight: bold;
+		margin-right: 12rpx;
+		max-width: 260rpx;
 		overflow: hidden;
+		text-overflow: ellipsis;
+		white-space: nowrap;
+	}
 
-		.risk-row {
-			display: flex;
-			align-items: center;
-			justify-content: space-between;
-			padding: 18rpx 24rpx 0 0rpx;
-			font-size: 28rpx;
-			color: #1f1f1f;
-			background: #fff;
+	.initiator-tag {
+		background: #1a1a1a;
+		color: #b6ff4b;
+		font-size: 20rpx;
+		border-radius: 8rpx;
+		padding: 2rpx 12rpx;
+		margin-left: 2rpx;
+	}
 
-			&.risk-row-border {
-				border-top: 1rpx solid #f2f2f2;
-				margin-top: 18rpx;
-				padding-top: 18rpx;
-			}
-		}
+	.initiator-service-btn {
+		display: flex;
+		align-items: center;
+		background: #1a1a1a;
+		color: #b6ff4b;
+		font-size: 28rpx;
+		border-radius: 128rpx;
+		padding: 0 24rpx 0 12rpx;
+		height: 56rpx;
+		margin-left: 18rpx;
+		font-weight: bold;
+	}
 
-		.risk-title {
-			font-size: 28rpx;
-			color: #1f1f1f;
-			font-family: 'PingFang SC-Bold';
-			font-weight: 400;
+	.service-icon {
+		width: 32rpx;
+		height: 32rpx;
+		margin-right: 8rpx;
+	}
+}
 
-		}
+.scale-tap {
+	transition: transform 0.15s;
+}
 
-		.risk-more {
-			color: #1f1f1f;
-			font-size: 24rpx;
-			display: flex;
-			align-items: center;
-			font-weight: 400;
-			font-family: 'PingFang SC-Bold';
-
-			.risk-more-icon {
-				width: 24rpx;
-				height: 24rpx;
-				margin-left: 4rpx;
-				margin-top: 4rpx;
-			}
+.scale-tap:active {
+	transform: scale(0.92);
+}
+
+.risk-section {
+	background: #fff;
+	border-radius: 12rpx;
+	margin: 24rpx 0 0 0;
+	padding: 0 0 18rpx 0;
+	position: relative;
+	overflow: hidden;
+
+	.risk-row {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		padding: 18rpx 24rpx 0 0rpx;
+		font-size: 28rpx;
+		color: #1f1f1f;
+		background: #fff;
+
+		&.risk-row-border {
+			border-top: 1rpx solid #f2f2f2;
+			margin-top: 18rpx;
+			padding-top: 18rpx;
 		}
+	}
 
-		.risk-desc {
-			font-size: 24rpx;
-			color: #999;
-			padding: 8rpx 24rpx 0 0;
-			font-family: 'PingFang SC-Regular';
+	.risk-title {
+		font-size: 28rpx;
+		color: #1f1f1f;
+		font-family: 'PingFang SC-Bold';
+		font-weight: 400;
+
+	}
+
+	.risk-more {
+		color: #1f1f1f;
+		font-size: 24rpx;
+		display: flex;
+		align-items: center;
+		font-weight: 400;
+		font-family: 'PingFang SC-Bold';
+
+		.risk-more-icon {
+			width: 24rpx;
+			height: 24rpx;
+			margin-left: 4rpx;
+			margin-top: 4rpx;
 		}
+	}
 
-		.risk-content {
-			font-size: 24rpx;
-			color: #999;
-			padding: 12rpx 24rpx 0 0;
-			font-family: 'PingFang SC-Regular';
-			line-height: 1.7;
+	.risk-desc {
+		font-size: 24rpx;
+		color: #999;
+		padding: 8rpx 24rpx 0 0;
+		font-family: 'PingFang SC-Regular';
+	}
 
-			>view {
-				margin-bottom: 6rpx;
-			}
+	.risk-content {
+		font-size: 24rpx;
+		color: #999;
+		padding: 12rpx 24rpx 0 0;
+		font-family: 'PingFang SC-Regular';
+		line-height: 1.7;
+
+		>view {
+			margin-bottom: 6rpx;
 		}
 	}
+}
 </style>

+ 367 - 138
pages/crowdFunding/customerService.vue

@@ -15,7 +15,7 @@
 					mode="widthFix"></image>
 
 				<view class="dropdown-menu" v-if="showDropdown">
-					<view class="dropdown-item" @tap="handleOption('report')">举报内容</view> 
+					<view class="dropdown-item" @tap="handleOption('report')">举报内容</view>
 				</view>
 
 			</view>
@@ -30,7 +30,7 @@
 				<view v-if="shouldShowTime(idx)" class="cs-time-bar">
 					<view class="cs-time-inner">{{ formatTime(msg.time) }}</view>
 				</view>
-				<template v-if="msg.type === 'orderCard'">
+				<template v-if="msg.message_type == 5">
 					<view class="cs-msg-order-card-box">
 						<image class="order-card-avatar" :src="msg.avatar" />
 						<view class="cs-msg-order-card">
@@ -60,7 +60,34 @@
 						msg.type === 'user' ? 'cs-msg-self' : 'cs-msg-other',
 					]">
 						<image class="cs-avatar" :src="msg.avatar" />
-						<view class="cs-msg-bubble">{{ msg.content }}</view>
+						<view class="cs-msg-bubble">
+							<!-- 文本消息 -->
+							<template v-if="msg.message_type === 1">
+								{{ msg.content }}
+							</template>
+							<!-- 图片消息 -->
+							<template v-else-if="msg.message_type === 2">
+								<view style="position:relative;display:inline-block;">
+									<image :src="msg.media_url" mode="aspectFit" style="max-width: 180rpx; max-height: 180rpx; border-radius: 8rpx;" @tap="!msg.uploading && previewImage(msg.media_url)" />
+									<view v-if="msg.uploading" style="position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(255,255,255,0.7);display:flex;align-items:center;justify-content:center;">
+										<text style="color:#a6e22e;font-size:24rpx;">{{ msg.progress || 0 }}%</text>
+									</view>
+								</view>
+							</template>
+							<!-- 语音消息 -->
+							<template v-else-if="msg.message_type === 3">
+								<view class="cs-msg-voice">[语音消息] <text style="color:#a6e22e">(暂不支持播放)</text></view>
+							</template>
+							<!-- 视频消息 -->
+							<template v-else-if="msg.message_type === 4">
+								<video :src="msg.media_url" controls style="max-width: 220rpx; max-height: 180rpx; border-radius: 8rpx;" />
+							</template>
+						 
+							<!-- 其它未知类型 -->
+							<template v-else>
+								<text style="color:#bbb">[未知消息类型]</text>
+							</template>
+						</view>
 					</view>
 				</template>
 			</view>
@@ -96,19 +123,33 @@
 				</view>
 			</view>
 
-			<view class="cs-input-area">
+			<!-- 假输入框 -->
+			<view v-if="!showRealInput" class="fake-input-bar" @click="showInputAndFocus">
+				<view class="fake-input-placeholder">在这里输入新消息</view>
+				<view class="fake-input-icons">
+					<image src="/static/icon/icon-picture.png" class="fake-input-icon" />
+					<image src="/static/icon/icon-expression.png" class="fake-input-icon" />
+				</view>
+			</view>
+
+			<!-- 真输入框 -->
+			<view v-else class="cs-input-area">
 				<textarea class="cs-textarea" v-model="inputValue" placeholder="在这里输入新消息" :focus="inputFocused"
 					:adjust-position="false" @focus="onInputFocus" @blur="onInputBlur"
 					@keyboardheightchange="onKeyboardHeightChange" maxlength="300" auto-height
 					:style="{ 'max-height': '120rpx', 'overflow-y': 'auto' }"></textarea>
-				<view class="emoji-trigger" @tap="toggleEmojiPanel">
-					<text class="fa fa-smile-o"></text>
+				<view class="bottom-bar">
+					<view>
+						<image @tap="upload" src="/static/icon/icon-picture.png" class="fake-input-icon" />
+						<image @tap="toggleEmojiPanel" src="/static/icon/icon-expression.png" class="fake-input-icon" />
+					</view>
+					<view :class="['send_btn', inputValue.trim() ? '' : 'prohibit']" @tap="sendMsg">发送</view>
 				</view>
-				<view class="send_btn" @tap="sendMsg">发送</view>
 			</view>
 		</view>
 
 		<view class="emoji-panel" :class="{ show: showEmojiPanel }" v-if="showEmojiPanel">
+			<view class="emoji-mask" @click="showEmojiPanel = false"></view>
 			<view class="emoji-grid">
 				<view class="emoji-item" v-for="(emoji, index) in emojiList" :key="index" @tap="selectEmoji(emoji)">
 					{{ emoji }}
@@ -119,111 +160,33 @@
 </template>
 
 <script>
+import permission from '@/common/permission.js';
+
 export default {
 	data() {
 		return {
-			chatList: [
-				{
-					id: 1,
-					content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
-					type: "customerService",
-					avatar: "/static/home/avator.png",
-					time: "2025-05-21 20:01",
-				},
-				{
-					id: 2,
-					content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
-					type: "customerService",
-					avatar: "/static/home/avator.png",
-					time: "2025-05-21 20:05",
-				},
-				{
-					id: 3,
-					content: "你好请问可以怎么帮助你",
-					type: "user",
-					avatar: "/static/makedetail/characterProfilePicture.png",
-					time: "2025-05-21 20:10",
-				},
-				{
-					id: 4,
-					content:
-						"哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
-					type: "user",
-					avatar: "/static/makedetail/characterProfilePicture.png",
-					time: "2025-05-21 20:10",
-				},
-				{
-					id: 5,
-					content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
-					type: "customerService",
-					avatar: "/static/home/avator.png",
-					time: "2025-05-21 20:01",
-				},
-				{
-					id: 6,
-					content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
-					type: "customerService",
-					avatar: "/static/home/avator.png",
-					time: "2025-05-21 20:05",
-				},
-				{
-					id: 7,
-					content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
-					type: "customerService",
-					avatar: "/static/home/avator.png",
-					time: "2025-05-21 20:01",
-				},
-				{
-					id: 8,
-					content:
-						"哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
-					type: "customerService",
-					avatar: "/static/home/avator.png",
-					time: "2025-05-21 20:05",
-				},
-				{
-					id: 9,
-					content: "你好请问可以怎么帮助你",
-					type: "user",
-					avatar: "/static/makedetail/characterProfilePicture.png",
-					time: "2025-05-21 21:10",
-				},
-				{
-					id: 13,
-					content: "你好请问可以怎么帮助你",
-					type: "user",
-					avatar: "/static/makedetail/characterProfilePicture.png",
-					time: "2025-05-21 20:10",
-				},
-				{
-					id: 10,
-					content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
-					type: "customerService",
-					avatar: "/static/home/avator.png",
-					time: "2025-05-21 20:01",
-				},
-				{
-					id: 11,
-					content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
-					type: "customerService",
-					avatar: "/static/home/avator.png",
-					time: "2025-05-21 23:05",
-				},
-			],
+			chatList: [],
 			inputValue: "",
 			pollTimer: null,
 			scrollToView: "bottom-anchor",
 			adShow: true,
 			keyboardHeight: 0,
 			inputFocused: false,
-			orderCardHeight: 260, // rpx,实际高度可根据广告条内容微调
+			orderCardHeight: 260,
 			showEmojiPanel: false,
-			showDropdown: false, // 控制下拉菜单显示状态 
-			emojiList: ["😀", "😁", "😂", "🤣", "😃", "😄", "😅", "😆", "😉", "😊", "😋", "😎", "😍", "😘", "🥰", "😗", "😙", "😚", "🙂", "🤗", "🤩", "🤔", "🤨", "😐", "😑", "😶", "🙄", "😏", "😣", "😥", "😮", "🤐", "😯", "😪", "😫", "🥱", "😴", "😌", "😛", "😜", "😝", "🤤", "😒", "😓", "😔", "😕", "🙃", "🤑", "😲", "☹️", "🙁", "😖", "😞", "😟", "😤", "😢", "😭", "😦", "😧", "😨", "😩", "🤯", "😬", "😰", "😱", "🥵", "🥶", "😳", "🤪", "😵", "😡", "😠", "🤬", "😷", "🤒", "🤕", "🤢", "🤮", "🥴", "😇", "🥳", "🥺", "🤠", "😈", "👿", "👹", "👺", "💀", "👻", "👽", "🤖", "💩", "😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾", "🙈", "🙉", "🙊", "💋", "💌", "💘", "💝", "💖", "💗", "💓", "💞", "💕", "💟", "❣️", "💔", "❤️", "🧡", "💛", "💚", "💙", "💜", "🤎", "🖤", "🤍", "💯", "💢", "💥", "💫", "💦", "💨", "🕳️", "💣", "💬", "👋", "🤚", "🖐️", "✋", "🖖", "👌", "🤏", "✌️", "🤞", "🤟", "🤘", "🤙", "👈", "👉", "👆", "🖕", "👇", "☝️", "👍", "👎", "✊", "👊", "🤛", "🤜", "👏", "🙌", "👐", "🤲", "🙏", "✍️", "💅", "🤳", "💪", "🦾", "🦵", "🦶", "👂", "👃", "🧠", "🦷", "🦴", "👀", "👁️", "👅", "👄",
-			],
+			showDropdown: false,
+			emojiList: ["😀", "😁", "😂", "🤣", "😃", "😄", "😅", "😆", "😉", "😊", "😋", "😎", "😍", "😘", "🥰", "😗", "😙", "😚", "🙂", "🤗", "🤩", "🤔", "🤨", "😐", "😑", "😶", "🙄", "😏", "😣", "😥", "😮", "🤐", "😯", "😪", "😫", "🥱", "😴", "😌", "😛", "😜", "😝", "🤤", "😒", "😓", "😔", "😕", "🙃", "🤑", "😲", "☹️", "🙁", "😖", "😞", "😟", "😤", "😢", "😭", "😦", "😧", "😨", "😩", "🤯", "😬", "😰", "😱", "🥵", "🥶", "😳", "🤪", "😵", "😡", "😠", "🤬", "😷", "🤒", "🤕", "🤢", "🤮", "🥴", "😇", "🥳", "🥺", "🤠", "😈", "👿", "👹", "👺", "💀", "👻", "👽", "🤖", "💩", "😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾", "🙈", "🙉", "🙊", "💋", "💌", "💘", "💝", "💖", "💗", "💓", "💞", "💕", "💟", "❣️", "💔", "❤️", "🧡", "💛", "💚", "💙", "💜", "🤎", "🖤", "🤍", "💯", "💢", "💥", "💫", "💦", "💨", "🕳️", "💣", "💬", "👋", "🤚", "🖐️", "✋", "🖖", "👌", "🤏", "✌️", "🤞", "🤟", "🤘", "🤙", "👈", "👉", "👆", "🖕", "👇", "☝️", "👍", "👎", "✊", "👊", "🤛", "🤜", "👏", "🙌", "👐", "🤲", "🙏", "✍️", "💅", "🤳", "💪", "🦾", "🦵", "🦶", "👂", "👃", "🧠", "🦷", "🦴", "��", "👁️", "👅", "👄"],
+			conversationId: 0,
+			creatorId: 0,
+			lastMsgId: 0,
+			pageSize: 20,
+			userInfo: {},
+			showRealInput: false, // 控制显示真输入框还是假输入框
 		};
 	},
-	onShow() {
+	onLoad(options) {
+		this.creatorId = options.id || 0;
+		this.fetchMessages();
 		this.startPolling();
 	},
 	onHide() {
@@ -239,8 +202,8 @@ export default {
 		// 轮询获取消息
 		startPolling() {
 			this.clearPolling();
-			this.pollTimer = setInterval(this.fetchMessages, 30000);
-			this.fetchMessages();
+			this.pollTimer = setInterval(() => this.fetchMessages(false), 5000);
+			this.fetchMessages(false);
 		},
 		clearPolling() {
 			if (this.pollTimer) {
@@ -248,29 +211,98 @@ export default {
 				this.pollTimer = null;
 			}
 		},
-		fetchMessages() {
-			// TODO: 替换为实际接口获取消息的接口
-			// uni.request({ ... })
-			// 假设新消息加入chatList
-			// this.chatList.push(...)
-			// 滚动到底部
-			this.$nextTick(() => {
-				this.scrollToView = "bottom-anchor";
+		// 获取消息
+		fetchMessages(isAppend = false) {
+			uni.request({
+				url: this.$apiHost + '/App/kefuGetMessages',
+				method: 'GET',
+				data: {
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey,
+					creator_id: this.creatorId,
+					conversation_id: this.conversationId,
+					last_id: isAppend ? this.lastMsgId : 0,
+					page_size: this.pageSize,
+					zc_id: this.creatorId
+				},
+				success: (res) => {
+					if (res.data && res.data.success === 'yes' && res.data.data) {
+						const { messages, conversation, user_info } = res.data.data;
+						this.userInfo = user_info || {};
+						this.conversationId = conversation?.id || 0;
+						// 格式化消息,保留 message_type、media_url 等字段
+						const msgList = (messages || []).map(msg => ({
+							id: msg.id,
+							content: msg.content,
+							type: msg.from_type === 1 ? 'user' : 'customerService',
+							avatar: msg.from_type === 1 ? (user_info.avatar || '/static/makedetail/characterProfilePicture.png') : '/static/home/avator.png',
+							time: msg.create_time,
+							message_type: msg.message_type, // 消息类型
+							media_url: msg.media_url, // 媒体文件URL
+							progress: msg.progress,
+							uploading: msg.uploading
+						}));
+						// 合并未上传完成的临时消息
+						const tempMsgs = this.chatList.filter(m => m.uploading);
+						let newList;
+						if (isAppend) {
+							newList = [...msgList.reverse(), ...this.chatList.filter(m => !m.uploading), ...tempMsgs];
+						} else {
+							newList = [...msgList.reverse(), ...tempMsgs];
+						}
+						this.chatList = newList;
+						// 记录最后一条消息ID
+						if (messages && messages.length > 0) {
+							this.lastMsgId = messages[0].id;
+						}
+						this.$nextTick(() => {
+							this.scrollToView = "bottom-anchor";
+						});
+					} else {
+						// 只保留临时消息
+						this.chatList = this.chatList.filter(m => m.uploading);
+					}
+				},
+				fail: () => {
+					// 只保留临时消息
+					this.chatList = this.chatList.filter(m => m.uploading);
+				}
 			});
 		},
+		// 发送消息
 		sendMsg() {
 			if (!this.inputValue.trim()) return;
-			this.chatList.push({
-				id: Date.now(),
-				content: this.inputValue,
-				type: "user",
-				avatar: "/static/avatar/cs2.png",
-			});
+			const content = this.inputValue;
 			this.inputValue = "";
-			this.$nextTick(() => {
-				this.scrollToView = "bottom-anchor";
+			uni.request({
+				url: this.$apiHost + '/App/kefuSendMessage',
+				method: 'POST',
+				header: {
+					"content-type": "application/x-www-form-urlencoded",
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey,
+				},
+				data: {
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey,
+					creator_id: this.creatorId,
+					conversation_id: this.conversationId,
+					message_type: 1, // 文本
+					content: content,
+					zc_id: this.creatorId
+				},
+				success: (res) => {
+					if (res.data && res.data.success === 'yes') {
+						// 发送成功后刷新消息
+						this.fetchMessages(false);
+					} else {
+						uni.showToast({ title: res.data.str || '发送失败', icon: 'none' });
+					}
+				},
+				fail: () => {
+					uni.showToast({ title: '网络错误', icon: 'none' });
+				}
 			});
-			// TODO: 发送消息到后端接口
 		},
 		closeOrderCard() {
 			this.adShow = false;
@@ -374,8 +406,152 @@ export default {
 					uni.navigateTo({
 						url: '/pages/my/feedback?isReportContent=true'
 					});
-					break; 
+					break;
 			}
+		}, 
+		showInputAndFocus() {
+			this.showRealInput = true;
+			this.$nextTick(() => {
+				this.inputFocused = true;
+			});
+		},
+		// 上传图片并发送图片消息,增加进度展示
+		async upload() {
+			uni.showActionSheet({
+				itemList: ['拍照', '从相册选择'],
+				success: async (res) => {
+					const sourceType = res.tapIndex === 0 ? 'camera' : 'album';
+					let hasPermission = false;
+
+					try {
+						if (sourceType === 'camera') {
+							hasPermission = await permission.request(permission.PermissionType.CAMERA, {
+								title: '“萌创星球”想访问你的相机',
+								describe: '萌创星球想访问您的摄像头,便于拍摄获取图片来与其他用户进行交流'
+							});
+						} else {
+							hasPermission = await permission.request(permission.PermissionType.PHOTO_LIBRARY, {
+								title: '“萌创星球”想访问你的照片图库',
+								describe: '萌创星球想访问您本地照片图库,便于获取图片来与其他用户进行交流'
+							});
+						}
+						if (!hasPermission) {
+							uni.showToast({
+								title: sourceType === 'camera' ? '未获得相机权限' : '未获得相册权限',
+								icon: 'none'
+							});
+							return;
+						}
+						// 权限通过后,选择图片
+						uni.chooseImage({
+							count: 1,
+							sizeType: ['compressed'],
+							sourceType: [sourceType],
+							success: (res) => {
+								const filePath = res.tempFilePaths[0];
+								// 1. 先插入临时消息
+								const tempMsgId = 'temp_' + Date.now();
+								this.chatList.push({
+									id: tempMsgId,
+									type: 'user',
+									avatar: this.userInfo.avatar || '/static/makedetail/characterProfilePicture.png',
+									time: this.getNowTime(),
+									message_type: 2,
+									media_url: filePath,
+									progress: 0,
+									uploading: true
+								});
+								this.$nextTick(() => {
+									this.scrollToView = "bottom-anchor";
+								});
+								// 2. 上传图片
+								uni.uploadFile({
+									url: this.$apiHost + '/Xweb/upload_img?skey=' + getApp().globalData.skey,
+									filePath: filePath,
+									name: 'file',
+									// 上传进度
+									progress: (e) => {
+										const idx = this.chatList.findIndex(m => m.id === tempMsgId);
+										if (idx !== -1) this.$set(this.chatList, idx, { ...this.chatList[idx], progress: e.progress });
+									},
+									success: (uploadFileRes) => {
+										let resdata = JSON.parse(uploadFileRes.data);
+										const idx = this.chatList.findIndex(m => m.id === tempMsgId);
+										if (resdata.success == 'no') {
+											if (idx !== -1) this.chatList.splice(idx, 1);
+											uni.showToast({ title: resdata.str, icon: 'none' });
+											return;
+										}
+										if (resdata.code == 0) {
+											// 替换为正式消息
+											if (idx !== -1) this.$set(this.chatList, idx, {
+												id: Date.now(),
+												type: 'user',
+												avatar: this.userInfo.avatar || '/static/makedetail/characterProfilePicture.png',
+												time: this.getNowTime(),
+												message_type: 2,
+												media_url: resdata.data.path,
+												progress: 100,
+												uploading: false
+											});
+											// 发送图片消息到服务端
+											this.sendImageMsg(resdata.data.path);
+										}
+									},
+									fail: () => {
+										const idx = this.chatList.findIndex(m => m.id === tempMsgId);
+										if (idx !== -1) this.chatList.splice(idx, 1);
+										uni.showToast({ title: '图片上传失败', icon: 'none' });
+									}
+								});
+							}
+						});
+					} catch (error) {
+						uni.showToast({
+							title: '权限检查失败',
+							icon: 'none'
+						});
+					}
+				}
+			});
+		},
+		sendImageMsg(imgUrl) {
+			uni.request({
+				url: this.$apiHost + '/App/kefuSendMessage',
+				method: 'POST',
+				header: {
+					"content-type": "application/x-www-form-urlencoded",
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey,
+				},
+				data: {
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey,
+					creator_id: this.creatorId,
+					conversation_id: this.conversationId,
+					message_type: 2, // 2为图片
+					content: '', // 图片消息content可为空
+					media_url: imgUrl, // 图片地址
+					zc_id: this.creatorId
+				},
+				success: (res) => {
+					if (res.data && res.data.success === 'yes') {
+						this.fetchMessages(false);
+					} else {
+						uni.showToast({ title: res.data.str || '发送失败', icon: 'none' });
+					}
+				},
+				fail: () => {
+					uni.showToast({ title: '网络错误', icon: 'none' });
+				}
+			});
+		},
+		// 图片预览
+		previewImage(url) {
+			uni.previewImage({
+				current: url,
+				urls: [url]
+			});
 		},
 	},
 };
@@ -629,10 +805,42 @@ export default {
 		right: 0;
 		bottom: 0;
 		z-index: 10;
+		padding-bottom: calc(12rpx + var(--window-bottom));
+
+		.fake-input-bar {
+			display: flex;
+			align-items: center;
+			background: #f6f7f9;
+			border-radius: 24rpx;
+			padding: 12rpx 20rpx;
+			margin: 0 12rpx;
+			flex: 1;
+			min-height: 64rpx;
+			border: 1rpx solid #ededed;
+
+			.fake-input-placeholder {
+				color: #bbb;
+				font-size: 28rpx;
+				flex: 1;
+			}
+
+			.fake-input-icons {
+				display: flex;
+				align-items: center;
+
+			}
+		}
+
+		.fake-input-icon {
+			width: 40rpx;
+			height: 40rpx;
+			margin-left: 16rpx;
+		}
 
 		.cs-input-area {
 			display: flex;
 			align-items: flex-end;
+			flex-direction: column;
 			background: #fff;
 			border-radius: 32rpx;
 			padding: 8rpx 12rpx;
@@ -649,14 +857,15 @@ export default {
 				border-radius: 24rpx;
 				padding: 12rpx 20rpx;
 				resize: none;
+				width: 100%;
 			}
 
-			.emoji-trigger {
-				margin: 0 12rpx;
-				font-size: 36rpx;
-				color: #999;
+			.bottom-bar {
+				width: 100%;
+				padding: 12rpx 0;
 				display: flex;
 				align-items: center;
+				justify-content: space-between;
 			}
 
 			.send_btn {
@@ -664,10 +873,15 @@ export default {
 				color: #fff;
 				border-radius: 32rpx;
 				font-size: 28rpx;
-				padding: 0 32rpx;
-				height: 64rpx;
-				line-height: 64rpx;
-				margin-left: 8rpx;
+				padding: 26rpx 32rpx;
+				line-height: 0;
+				border: 1rpx solid transparent;
+
+				&.prohibit {
+					background: #fff;
+					border: 1rpx solid #999;
+					color: #999;
+				}
 			}
 		}
 	}
@@ -677,27 +891,42 @@ export default {
 		left: 0;
 		right: 0;
 		bottom: 0;
-		max-height: 50vh;
-		width: 100vw;
-		background: #fff;
-		padding: 12rpx 0 0 0;
-		border-top: 1rpx solid #ededed;
 		z-index: 1000;
-		box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.08);
-		overflow-y: auto;
-		transform: translateY(100%);
-		transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
-		border-top: 20rpx solid #fff;
+		width: 100vw;
+		height: 100vh;
 
 		&.show {
 			transform: translateY(0);
 		}
 
+		.emoji-mask {
+			position: fixed;
+			left: 0;
+			right: 0;
+			top: 0;
+			bottom: 0;
+			background: rgba(0, 0, 0, 0.1);
+			z-index: 1001;
+		}
+
 		.emoji-grid {
+			position: relative;
+			z-index: 1002;
 			display: flex;
 			flex-wrap: wrap;
 			justify-content: center;
 			padding-bottom: 24rpx;
+			max-height: 50vh;
+			width: 100vw;
+			border-top: 1rpx solid #ededed;
+
+			background: #fff;
+			padding: 12rpx 0 0 0;
+			box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.08);
+			overflow-y: auto;
+			transform: translateY(100%);
+			transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
+			border-top: 20rpx solid #fff;
 
 			.emoji-item {
 				width: 60rpx;

+ 91 - 105
pages/crowdFunding/discussionArea.vue

@@ -19,34 +19,32 @@
 			</view>
 		</view>
 
-
-
-		<!-- tab内容 -->
+ 
 		<view v-if="tab === 1" class="update-list">
-			<block v-for="(item, idx) in updateList" :key="idx">
-				<view class="update-item" @click="goPages('/pages/crowdFunding/projectUpdateDetails?id='+item.id)">
-					<view class="update-title">第{{ item.index }}次更新</view>
-					<view class="update-content">{{ item.content }}</view>
+			<block v-for="(item, idx) in projectUpdate" :key="idx">
+				<view class="update-item" @click="goPages('/pages/crowdFunding/projectUpdateDetails?id=' + item.id)">
+					<view class="update-title">第{{ item.numb }}次更新</view>
+					<view class="update-content" >{{ item.title }}</view>
 					<view class="update-user">
-						<image class="avatar" :src="item.avatar" />
-						<text class="nickname">{{ item.nickname }}</text>
+						<image class="avatar" :src="articleInfo.creator_avatar" />
+						<text class="nickname">{{ articleInfo.creator_nickname }}</text>
 					</view>
-					<image class="update-img" :src="'../../static/crowdFunding/top-img.png'" mode="widthFix" />
+					<image class="update-img" :src="item.image" mode="widthFix" />
 					<view class="update-footer">
-						<text class="update-time">{{ item.time }}</text>
+						<text class="update-time">{{ item.create_time }}</text>
 						<view class="update-like">
-							<image :src="item.liked ? '/static/icon/icon-18.png' : '/static/icon/icon-19.png'"
+							<!-- <image :src="item.liked ? '/static/icon/icon-18.png' : '/static/icon/icon-19.png'"
 								class="like-icon" />
-							<text class="like-num">{{ item.likeNum }}</text>
+							<text class="like-num">{{ item.likeNum }}</text> -->
 						</view>
 					</view>
 				</view>
 			</block>
 		</view>
 		<!-- 评论区域 -->
-		<CommentSection v-else-if="  articleInfo.title" class="comment" ref="commentSection"
-			:myInfo="myInfo"  :articleId="arcID" @totalNumberOfComments="totalNumberOfComments"
-			:articleInfo="articleInfo" :author="author" find="work">
+		<CommentSection v-else-if=" articleInfo&&articleInfo.is_like != 'undefined'" class="comment" ref="commentSection" :articleId="id"
+			@totalNumberOfComments="totalNumberOfComments" :articleInfo="articleInfo" :myInfo="myInfo" :author="author"
+			find="crowdfund" type="crowdfund">
 		</CommentSection>
 
 	</view>
@@ -57,46 +55,10 @@ export default {
 	data() {
 		return {
 			tab: 1,
-			updateList: [
-				{
-					index: 2,
-					content: '附赠精品灯塔牌包装,附赠精品灯塔牌包装',
-					avatar: '/static/crowdFunding/top-img.png',
-					nickname: '也许时间是一种解药',
-					img: 'https://img.zcool.cn/community/01b6b95d5b2e2fa801216518a7e7e7.jpg',
-					time: '2025.5.23 16:23',
-					likeNum: 12,
-					liked: false
-				},
-				{
-					index: 1,
-					content: '附赠精品灯塔牌包装,附赠精品灯塔牌包装',
-					avatar: '/static/crowdFunding/top-img.png',
-					nickname: '也许时间是一种解药',
-					img: 'https://img.zcool.cn/community/01b6b95d5b2e2fa801216518a7e7e7.jpg',
-					time: '2025.5.23 16:23',
-					likeNum: 12,
-					liked: false
-				}
-			],
-			commentList: [
-				{
-					avatar: '../../static/crowdFunding/top-img.png',
-					content: '还是希望签名能签在书上,还是希望签名能签在书上还是希望签名能签在书上还是希望签名能签在书上,还是希望签名能签在书上还是希望签名能签在书上',
-					nickname: '也许时间是一种解药',
-					time: '2025.5.23 16:23',
-					likeNum: 12,
-					liked: false
-				},
-				{
-					avatar: '../../static/crowdFunding/top-img.png',
-					content: '还是希望签名能签在书上',
-					nickname: '也许时间是一种解药',
-					time: '2025.5.23 16:23',
-					likeNum: 12,
-					liked: true
-				}
+			id: 0,
+			projectUpdate: [ 
 			],
+
 			cate: [
 				{
 					name: "项目更新",
@@ -108,57 +70,15 @@ export default {
 				},
 			],
 			myInfo: {
-				"user_id": 1349,
-				"user_name": "??????????????????????????????",
-				"user_avatar": "http://e.zhichao.art/upload/2025-04/0a7d9b922ac8307a6f988d17b3dd7805_new.jpg"
-			},
-			articleInfo: {
-				"id": 574,
-				"task_type": 1,
-				"queue_id": 0,
-				"article_id": 0,
-				"sso_id": 1458,
-				"images": "http://c.zhichao.art/upload/2025-05/9cc4c00bab5ae9be6486d95c31d2d720_new.jpg",
-				"content": "非常喜欢这个手办图片",
-				"lyrics": "",
-				"result_audio": "",
-				"title": "这个手办感觉不错呀",
-				"style": "",
-				"num_like": 12,
-				"num_comment": 0,
-				"num_view": 84,
-				"city": "",
-				"tdate": "2025-05-26",
-				"reason": "",
-				"can_comment": 1,
-				"can_view_comment": 1,
-				"create_time": "2025-05-26 12:02:22",
-				"status": 1,
-				"video_url": "",
-				"video_width": 1080,
-				"video_height": 1920,
-				"nickname": "",
-				"age": 0,
-				"avator": "",
-				"author": "",
-				"xinzuo": "",
-				"sex": 0,
-				"dtime": "",
-				"is_like": 0,
-				"is_vip": 0,
-				"userID": 0,
-				"like_count": 0,
-				"sms_id": 0
+				user_id: getApp().globalData.user_id, // 用户id
+				user_name: getApp().globalData.nickname, // 用户名
+				user_avatar: getApp().globalData.avator, // 用户头像地址
 			},
-			articleId: 574,
-			arcID: 574,
-			type: 'work',
-			find: 'work',
+			articleInfo: {},
+			type: 'crowdfund',
+			find: 'crowdfund',
 			author: {
-				"id": 1458,
-				"nickname": "时光慢递员∞",
-				"avator": "https://c.zhichao.art/upload/plat/10000000062.jpg",
-				"is_attention": 0
+
 			}
 		}
 	},
@@ -166,13 +86,79 @@ export default {
 		if (options.tags) {
 			this.tab = options.tags === 'update' ? 1 : options.tags === 'comment' ? 2 : 1;
 		}
+		if (options.id) {
+			this.id = options.id;
+		}
+		this.getDetails()
 	},
 	methods: {
 		checkTab(tab) {
 			this.tab = tab;
-		}, totalNumberOfComments(tableTotal) {
+		},
+		totalNumberOfComments(tableTotal) {
 			this.tableTotal = tableTotal;
 		},
+		getDetails() {
+			uni.request({
+				url: this.$apiHost + '/crowdfund/detail',
+				method: 'GET',
+				data: {
+					id: this.id,
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey
+				},
+				success: (res) => {
+					if (res.data && res.data.success === 'yes' && res.data.data) {
+						this.articleInfo = res.data.data
+						this.author = {
+							"id": res.data.data.creator_id,
+							"nickname": res.data.data.creator_nickname,
+							"avator": res.data.data.creator_avatar,
+						}
+					}
+				}
+			});
+			uni.request({
+				url: this.$apiHost + '/crowdfund/articles',
+				method: 'GET',
+				data: {
+					crowdfund_id: this.id, 
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey
+				},
+				success: (res) => {
+					if (res.data && res.data.success === 'yes' && res.data.data) {
+						if (Array.isArray(res.data.data.list)) {
+							this.projectUpdate = res.data.data.list.map(item => ({
+								...item,
+								create_time: item.create_time.replace(/-/g, '.').slice(0, 16)
+							}));
+							 
+
+						}
+					}
+				}
+			}); 
+			uni.request({
+				url: this.$apiHost + '/crowdfund/favorite/status',
+				method: 'GET',
+				data: {
+					crowdfund_id: this.id,
+					uuid: getApp().globalData.uuid,
+					skey: getApp().globalData.skey
+				},
+				success: (res) => {
+					if (res.data && res.data.success === 'yes' && res.data.data) {
+						console.log(res.data.data, "收藏");
+							console.log( res.data.data.is_favorited ,89798789);
+							
+							this.articleInfo.is_like= res.data.data.is_favorited;
+					 
+						// 可根据接口返回字段设置isFavorite等
+					}
+				}
+			});
+		},
 		goPages(url) {
 			uni.navigateTo({
 				url: url

+ 114 - 36
pages/crowdFunding/favorites.vue

@@ -8,18 +8,18 @@
         :key="idx"
       >
         <image
-          :src="item.img"
+          :src="item.main_image"
           class="fav-img"
         ></image>
 
         <view class="fav-content">
           <view class="fav-header">
             <image
-              :src="item.avatar"
+              :src="item.creator_avatar"
               class="avatar"
             ></image>
-            <text class="nickname">{{ item.nickname }}</text>
-            <text class="tag">{{ item.tag }}</text>
+            <text class="nickname">{{ item.creator_username }}</text>
+            <text class="tag">发起人</text>
             <view style="position: relative;left: 0;top: 0;">
               <image
                 src="/static/crowdFunding/more.png"
@@ -39,11 +39,15 @@
           </view>
           <view class="fav-title two-omit">{{ item.title }}</view>
           <view class="fav-bottom">
-            <text class="amount">已筹 ¥{{ item.amount }}万</text>
+            <text class="amount">已筹 ¥{{ item.current_amount }}</text>
+            <!-- <text class="favorite-time">收藏于{{ item.favorite_time }}</text> -->
           </view>
         </view>
       </view>
     </view>
+    <view v-if="!isLoading && list.length === 0" class="no-data">
+      <text>暂无数据</text>
+    </view>
   </view>
 </template>
 
@@ -51,36 +55,67 @@
 export default {
   data() {
     return {
-      list: [
-        {
-          img: "/static/crowdFunding/top-img.png",
-          avatar: "/static/home/avator.png",
-          nickname: "也许时间是一种解药",
-          tag: "发起人",
-          title: "糖指数100%12分BJD可动人偶盲盒糖指数100%12分BJD可动人偶盲盒糖指数100%12分BJD可动人偶盲盒",
-          amount: "769.8",
-        },
-        {
-          img: "/static/crowdFunding/top-img.png",
-          avatar: "/static/home/avator.png",
-          nickname: "也许时间是一种解药",
-          tag: "发起人",
-          title: "糖指数100%12分BJD可动人偶盲盒",
-          amount: "769.8",
-        },
-        {
-          img: "/static/crowdFunding/top-img.png",
-          avatar: "/static/home/avator.png",
-          nickname: "也许时间是一种解药",
-          tag: "发起人",
-          title: "糖指数100%12分BJD可动人偶盲盒",
-          amount: "769.8",
-        },
-      ],
+      list: [],
+      page: 1,
+      pageSize: 20,
+      total: 0,
+      isLoading: false,
+      hasMore: true,
       currentDropdownIndex: null,
     };
   },
+  onLoad() {
+    this.page = 1;
+    this.list = [];
+    this.hasMore = true;
+    this.getList();
+  },
+  onPullDownRefresh() {
+    this.page = 1;
+    this.list = [];
+    this.hasMore = true;
+    this.getList(() => uni.stopPullDownRefresh());
+  },
+  onReachBottom() {
+    if (this.hasMore && !this.isLoading) {
+      this.getList();
+    }
+  },
   methods: {
+    getList(cb) {
+      if (this.isLoading) return;
+      this.isLoading = true;
+      uni.request({
+        url: this.$apiHost + '/crowdfund/favorites',
+        method: 'GET',
+        data: {
+          page: this.page,
+          pageSize: this.pageSize,
+          uuid: getApp().globalData.uuid,
+						skey: getApp().globalData.skey,
+        },
+        success: (res) => {
+          if (res.data && res.data.success === 'yes' && res.data.data) {
+            var { list, total } = res.data.data;
+            if(!Array.isArray(list)) {
+               list = [];
+            }
+            if (this.page === 1) {
+              this.list = list;
+            } else {
+              this.list = [...this.list, ...list];
+            }
+            this.total = total;
+            this.hasMore =this.list&&this.list.length < total;
+            if (this.hasMore) this.page++;
+          }
+        },
+        complete: () => {
+          this.isLoading = false;
+          cb && cb();
+        }
+      });
+    },
     goBack() {
       uni.navigateBack();
     },
@@ -91,12 +126,43 @@ export default {
     handleOption(type, idx) {
       this.currentDropdownIndex = null;
       if (type === "cancelCollection") {
-        uni.showToast({
-          title: '取消收藏成功',
-          icon: 'success',
-          duration: 2000
+        const item = this.list[idx];
+        uni.request({
+          url: this.$apiHost + '/crowdfund/favorite',
+          method: 'POST',
+          header: {
+            'content-type': 'application/x-www-form-urlencoded',
+          },
+          data: {
+            crowdfund_id: item.id,
+            action: 'remove',
+            uuid: getApp().globalData.uuid,
+            skey: getApp().globalData.skey,
+          },
+          success: (res) => {
+            if (res.data && res.data.success && res.data.success === 'yes') {
+              this.list.splice(idx, 1);
+              uni.showToast({
+                title: '取消收藏成功',
+                icon: 'none',
+                duration: 2000
+              });
+            } else {
+              uni.showToast({
+                title: res.data.msg || '取消失败',
+                icon: 'none',
+                duration: 2000
+              });
+            }
+          },
+          fail: () => {
+            uni.showToast({
+              title: '网络错误',
+              icon: 'none',
+              duration: 2000
+            });
+          }
         });
-        // 这里可以加删除逻辑
       }
     },
   },
@@ -180,6 +246,11 @@ export default {
             font-size: 22rpx;
             color: #bdbdbd;
           }
+          .favorite-time {
+            font-size: 22rpx;
+            color: #bdbdbd;
+            margin-left: 10rpx;
+          }
         }
       }
     }
@@ -232,5 +303,12 @@ export default {
       transform: scale(1) translateY(0);
     }
   }
+
+  .no-data {
+    text-align: center;
+    color: #bbb;
+    font-size: 28rpx;
+    padding: 80rpx 0 40rpx 0;
+  }
 }
 </style>

+ 82 - 90
pages/crowdFunding/projectUpdateDetails.vue

@@ -1,123 +1,108 @@
 <template>
   <view class="project-update-details">
-    <view
-      class="custom-navbar"
-      :style="navBgStyle"
-    >
-      <view
-        class="navbar-left scale-tap"
-        @click="goBack"
-      >
-        <image
-          src="@/static/crowdFunding/back.png"
-          mode="widthFix"
-        ></image>
+    <view class="custom-navbar" :style="navBgStyle">
+      <view class="navbar-left scale-tap" @click="goBack">
+        <image src="@/static/crowdFunding/back.png" mode="widthFix"></image>
       </view>
-      <view
-        class="navbar-center one-omit"
-        style="max-width: 70vw"
-        :style="{ opacity: navBgOpacity }"
-      >
-        【Woh】灯塔 塔罗牌 治愈风泛伟特系伟特系伟特系
+      <view class="navbar-center one-omit" style="max-width: 70vw" :style="{ opacity: navBgOpacity }">
+        {{ datails.title }}
       </view>
-      <view
-        class="navbar-right scale-tap"
-        @click="showShare = true"
-      >
-        <image
-          src="@/static/crowdFunding/share.png"
-          mode="widthFix"
-        ></image>
+      <view class="navbar-right scale-tap" @click="showShare = true">
+        <image src="@/static/crowdFunding/share.png" mode="widthFix"></image>
       </view>
     </view>
-    <image
-      class="top-img"
-      src="@/static/crowdFunding/top-img.png"
-      mode="widthFix"
-    ></image>
+    <image class="top-img" src="@/static/crowdFunding/top-img.png" mode="widthFix"></image>
     <view class="update-info">
       <view class="update-title-row">
-        <text class="update-title">· 第2次更新</text>
-        <text class="update-time">2025.5.23 16:23</text>
+        <text class="update-title">· 第{{ datails.numb }}次更新</text>
+        <text class="update-time">{{ datails.create_time }}</text>
       </view>
       <view class="update-user-row">
-        <image
-          class="user-avatar"
-          src="@/static/home/avator.png"
-        ></image>
-        <text class="user-nickname">也许时间是一种解药</text>
+        <image class="user-avatar" :src="author.avator"></image>
+        <text class="user-nickname">{{ author.nickname }}</text>
       </view>
     </view>
-	<view class="content">
-		<uv-parse :content="content" :selectable="true"></uv-parse>
-	</view>
+    <view class="content">
+      <uv-parse :content="datails.content" :selectable="true"></uv-parse>
+    </view>
+
+    <!-- 分享弹窗 -->
+    <SharePopup :visible="showShare" :userId="0" :share-title="shareTitle" :share-desc="shareDesc" :share-img="shareImg"
+      view="crowdfundingDetails" @close="showShare = false" :isReportContent="true" />
   </view>
 </template>
 
-<script> 
-export default { 
+<script>
+export default {
   data() {
     return {
-      navBgOpacity: 0,
+      navBgOpacity: 0, 
+      content: ` `,
+      datails: {},
+      author: {},
       showShare: false,
-      content: `<section data-role="paragraph" class="_135editor" style="">
-	<p style="border-width: 0px; border-radius: 10px;text-align:center;" align="center">
-		<span style="font-size: 20px; border-width: 0px; border-radius: 10px;"><strong style="border-width: 0px; border-radius: 10px;">追加解锁档位和关于地址修改邮费退补的提示</strong></span>&nbsp;
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;text-align:center;" align="center">
-		<br style="border-width: 0px; border-radius: 10px;"/>
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;text-align:center;" align="center">
-		<br style="border-width: 0px; border-radius: 10px;"/>
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;" >
-		感谢大家的热情,我们在半天的时间内达到了68万的 金额。
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;">
-		<br style="border-width: 0px; border-radius: 10px;"/>
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;">
-		&nbsp;为了回应大家的支持,我们决定增加以下
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;">
-		解锁档位:&nbsp;
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;">
-		<br style="border-width: 0px; border-radius: 10px;"/>
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;">
-		350,000:正式开启《三相奇谈官方艺术设定集》制作企划!&lt;已经解锁&gt;&nbsp;
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;">
-		<br style="border-width: 0px; border-radius: 10px;"/>
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;">
-		·500,000:为60元以上档位额外追加表情包贴纸·第 二弹!&lt;已经解锁&gt;&nbsp;
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;">
-		·650,000:为所有档位追加3张角色明信片!&lt;已经解锁&gt;&nbsp;
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;">
-		·800,000:为100元以上档位追加局部彩窗亚克力挂饰一个!&nbsp;
-	</p>
-	<p style="border-width: 0px; border-radius: 10px;">
-		<span style="caret-color: red; border-width: 0px; border-radius: 10px;">·900,000:为所有档位追加角色纪念徽章,根据投票选出角色并全新绘制!</span>
-	</p>
-</section>`,
+      shareTitle: '【Woh】灯塔 塔罗牌 治愈风泛传特系',
+      shareDesc: '快来支持这个有趣的众筹项目吧!',
+      shareImg: require('@/static/crowdFunding/top-img.png'),
     };
   },
   computed: {
     navBgStyle() {
       return {
+        id: 0,
         background: `rgba(255,255,255,${this.navBgOpacity})`,
         transition: "background 0.3s",
       };
     },
   },
+  onLoad(options) {
+    this.id = options.id
+    this.getDetails()
+  },
   methods: {
     goBack() {
       uni.navigateBack();
     },
+    getDetails() {
+      uni.request({
+        url: this.$apiHost + '/crowdfund/article/detail',
+        method: 'GET',
+        data: {
+          id: this.id,
+          uuid: getApp().globalData.uuid,
+          skey: getApp().globalData.skey
+
+        },
+        success: (res) => {
+          console.log('获取到详情数据', res.data.data);
+
+          if (res.data && res.data.success === 'yes' && res.data.data) {
+            this.datails = res.data.data
+
+          }
+        }
+      });
+      uni.request({
+        url: this.$apiHost + '/crowdfund/detail',
+        method: 'GET',
+        data: {
+          id: this.projectId,
+          uuid: getApp().globalData.uuid,
+          skey: getApp().globalData.skey
+
+        },
+        success: (res) => {
+          if (res.data && res.data.success === 'yes' && res.data.data) {
+            this.author = {
+              "id": res.data.data.creator_id,
+              "nickname": res.data.data.creator_nickname,
+              "avator": res.data.data.creator_avatar,
+            }
+            // 可根据接口返回字段设置isFavorite等
+          }
+        }
+      });
+    }
   },
   onPageScroll(e) {
     const threshold = this.swiperHeight || uni.upx2px(400); // 优先用实际高度
@@ -165,29 +150,35 @@ export default {
   .update-info {
     background: #fff;
     padding: 32rpx 32rpx 0 32rpx;
+
     .update-title-row {
       display: flex;
       justify-content: space-between;
       align-items: center;
       margin-bottom: 24rpx;
+
       .update-title {
         font-size: 26rpx;
         color: #222;
       }
+
       .update-time {
         font-size: 24rpx;
         color: #bdbdbd;
       }
     }
+
     .update-user-row {
       display: flex;
       align-items: center;
+
       .user-avatar {
         width: 48rpx;
         height: 48rpx;
         border-radius: 50%;
         margin-right: 16rpx;
       }
+
       .user-nickname {
         font-size: 26rpx;
         color: #222;
@@ -195,8 +186,9 @@ export default {
       }
     }
   }
-  .content{
-	padding: 42rpx 28rpx;
+
+  .content {
+    padding: 42rpx 28rpx;
   }
 }
 </style>

+ 1 - 54
pages/index/index.vue

@@ -612,60 +612,7 @@ export default {
 			this.followOffset = currentList.length;
 			console.log('请求关注列表数据,当前offset =', this.followOffset);
 
-			uni.request({
-				url: this.$apiHost + "/Work/getlist",
-				data: {
-					uuid: getApp().globalData.uuid,
-					skey: getApp().globalData.skey,
-					type: "attention",
-					offset: this.followOffset,
-				},
-				header: {
-					"content-type": "application/json",
-					sign: getApp().globalData.headerSign,
-				},
-				success: (res) => {
-					console.log("关注列表数据:", res.data);
-					if (res.data.success == "yes" && res.data.list && res.data.list.length > 0) {
-						// 追加新数据到列表
-						this.followList = [...currentList, ...res.data.list];
-						console.log('关注列表加载成功,当前列表长度:', this.followList.length);
-						this.hasMoreFollow = res.data.list.length >= 20;
-					} else {
-						this.hasMoreFollow = false;
-						this.showNoMoreDataToast("没有更多关注内容了");
-					}
-
-					// 使用 nextTick 确保数据更新后再通知组件
-					this.$nextTick(() => {
-						if (this.$refs.paging) {
-							// 第一个参数需要是数组,将当前列表传入
-							this.$refs.paging.complete(this.followList);
-						}
-						// 数据加载完成后更新swiper高度
-						if (this.currentTab === 0) {
-							// 使用setTimeout确保数据渲染完成后再更新高度
-							setTimeout(() => {
-								this.updateSwiperHeight();
-							}, 300);
-							setTimeout(() => {
-								this.updateSwiperHeight();
-							}, 650);
-						}
-					});
-				},
-				complete: () => {
-					this.isLoadingFollow = false;
-				},
-				fail: (e) => {
-					console.log("请求关注列表失败:", e);
-					this.isLoadingFollow = false;
-					if (this.$refs.paging) {
-						// 加载失败时提供空数组
-						this.$refs.paging.complete([]);
-					}
-				},
-			});
+			category
 		},
 		// 修改推荐列表加载方法
 		loadRecommendList() {

BIN
static/icon/icon-expression.png


BIN
static/icon/icon-picture.png