diff --git a/app.json b/app.json
index e65e84a..0c9b330 100644
--- a/app.json
+++ b/app.json
@@ -15,7 +15,8 @@
"pages/chat-detail/index",
"pages/message-list/index",
"pages/customer-service/index",
- "pages/cooperation/index"
+ "pages/cooperation/index",
+ "pages/goods/index"
],
"subpackages": [
{
diff --git a/pages/buyer/index.js b/pages/buyer/index.js
index 3b6935b..b07a174 100644
--- a/pages/buyer/index.js
+++ b/pages/buyer/index.js
@@ -485,18 +485,22 @@ Page({
if (!users[userId]) {
users[userId] = {};
}
- users[userId].type = 'buyer';
- wx.setStorageSync('users', users);
- // 更新标签
- let tags = wx.getStorageSync('tags');
- if (typeof tags !== 'object' || tags === null) {
- tags = {};
+ // 只有当当前类型不是 Colleague 时才修改为 buyer
+ if (users[userId].type !== 'Colleague') {
+ users[userId].type = 'buyer';
+ wx.setStorageSync('users', users);
+
+ // 更新标签
+ let tags = wx.getStorageSync('tags');
+ if (typeof tags !== 'object' || tags === null) {
+ tags = {};
+ }
+ tags[userId] = tags[userId] || [];
+ tags[userId] = tags[userId].filter(tag => !tag.startsWith('身份:'));
+ tags[userId].push(`身份:buyer`);
+ wx.setStorageSync('tags', tags);
}
- tags[userId] = tags[userId] || [];
- tags[userId] = tags[userId].filter(tag => !tag.startsWith('身份:'));
- tags[userId].push(`身份:buyer`);
- wx.setStorageSync('tags', tags);
}
// ✅ 修改:重置分页状态并清空数据
diff --git a/pages/goods/index.js b/pages/goods/index.js
new file mode 100644
index 0000000..0f92c8a
--- /dev/null
+++ b/pages/goods/index.js
@@ -0,0 +1,342 @@
+// pages/goods/index.js
+const API = require('../../utils/api.js')
+
+Page({
+ // 分享给朋友/群聊
+ onShareAppMessage() {
+ return {
+ title: '内部货源管理 - 鸡蛋贸易平台',
+ path: '/pages/goods/index',
+ imageUrl: '/images/你有好蛋.png'
+ }
+ },
+
+ // 分享到朋友圈
+ onShareTimeline() {
+ return {
+ title: '内部货源管理 - 鸡蛋贸易平台',
+ query: '',
+ imageUrl: '/images/你有好蛋.png'
+ }
+ },
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+ goodsList: [],
+ isLoading: false,
+ isRefreshing: false, // 下拉刷新状态
+ currentPage: 1,
+ pageSize: 20,
+ hasMore: true,
+ searchKeyword: '',
+ activeFilter: 'all', // 当前筛选条件:all, small, large
+ filterConfig: {
+ small: ['何佳芹', '李真音'], // 小品种创建者
+ large: ['吴海燕', '陈骏', '刘琴', '汤敏'] // 大贸易创建者
+ },
+ total: 0 // 总数据条数
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+ this.loadGoodsList()
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+ // 这里的onPullDownRefresh是页面级的,但我们使用的是scroll-view内置的下拉刷新,所以不需要实现这个方法
+ },
+
+ /**
+ * scroll-view下拉刷新事件处理
+ */
+ onRefresherRefresh() {
+ if (this.data.isLoading) return
+
+ this.setData({
+ isRefreshing: true,
+ currentPage: 1,
+ goodsList: [],
+ hasMore: true,
+ isLoading: false
+ })
+ this.loadGoodsList()
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+ if (this.data.hasMore && !this.data.isLoading) {
+ this.setData({
+ currentPage: this.data.currentPage + 1
+ })
+ this.loadGoodsList()
+ }
+ },
+
+ /**
+ * 处理搜索输入
+ */
+ onSearchInput(e) {
+ this.setData({
+ searchKeyword: e.detail.value
+ })
+ },
+
+ /**
+ * 执行搜索
+ */
+ searchGoods() {
+ if (this.data.isLoading) return
+
+ this.setData({
+ currentPage: 1,
+ goodsList: [],
+ hasMore: true
+ })
+ this.loadGoodsList()
+ },
+
+ /**
+ * 清除搜索
+ */
+ clearSearch() {
+ this.setData({
+ searchKeyword: '',
+ currentPage: 1,
+ goodsList: [],
+ hasMore: true
+ })
+ this.loadGoodsList()
+ },
+
+ /**
+ * 筛选条件改变
+ */
+ onFilterChange(e) {
+ if (this.data.isLoading) return
+
+ const filter = e.currentTarget.dataset.filter
+ this.setData({
+ activeFilter: filter,
+ currentPage: 1,
+ goodsList: [],
+ hasMore: true
+ })
+ this.loadGoodsList()
+ },
+
+ /**
+ * 根据筛选条件过滤数据
+ */
+ filterGoodsList(goodsList) {
+ const { activeFilter, filterConfig } = this.data
+
+ if (activeFilter === 'all') {
+ return goodsList
+ }
+
+ const allowedCreators = filterConfig[activeFilter] || []
+ return goodsList.filter(item => {
+ return allowedCreators.includes(item.creatorName)
+ })
+ },
+
+ /**
+ * 格式化时间
+ */
+ formatDateTime(dateString) {
+ if (!dateString) return '未知时间'
+
+ // 检查是否已经是格式化好的北京时间字符串(如:2026-01-05 17:30)
+ if (typeof dateString === 'string' && /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2})?$/.test(dateString)) {
+ // 直接返回格式化好的字符串,只保留到分钟
+ return dateString.slice(0, 16)
+ }
+
+ // 检查是否是ISO格式的字符串(如:2026-01-05T12:00:00.000Z)
+ if (typeof dateString === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/.test(dateString)) {
+ // 转换ISO格式为本地时间
+ const date = new Date(dateString)
+ if (isNaN(date.getTime())) {
+ return '未知时间'
+ }
+
+ const year = date.getFullYear()
+ const month = (date.getMonth() + 1).toString().padStart(2, '0')
+ const day = date.getDate().toString().padStart(2, '0')
+ const hours = date.getHours().toString().padStart(2, '0')
+ const minutes = date.getMinutes().toString().padStart(2, '0')
+ return `${year}-${month}-${day} ${hours}:${minutes}`
+ }
+
+ // 对于其他格式的字符串,直接返回,不进行转换
+ // 这是为了避免对后端返回的北京时间字符串进行错误的时区转换
+ return dateString
+ },
+
+ /**
+ * 加载货源列表
+ */
+ async loadGoodsList() {
+ if (this.data.isLoading) return
+
+ this.setData({
+ isLoading: true
+ })
+
+ console.log('开始加载货源列表,参数:', {
+ page: this.data.currentPage,
+ pageSize: this.data.pageSize,
+ keyword: this.data.searchKeyword,
+ activeFilter: this.data.activeFilter
+ })
+
+ // 调用API获取货源列表
+ try {
+ const res = await API.getGoodsList({
+ page: this.data.currentPage,
+ pageSize: this.data.pageSize,
+ keyword: this.data.searchKeyword
+ })
+
+ console.log('API返回结果:', res)
+
+ // 检查API返回的状态
+ if (res.success) {
+ console.log('API调用成功,products:', res.products)
+ console.log('products长度:', res.products.length)
+ console.log('API返回total:', res.total)
+
+ // 更新总数据条数
+ const total = res.total || 0
+
+ if (res.products && res.products.length > 0) {
+ // 显示第一个产品的详细信息
+ console.log('第一个产品:', res.products[0])
+ console.log('第一个产品的seller:', res.products[0].seller)
+ console.log('第一个产品的seller.nickName:', res.products[0].seller?.nickName)
+ console.log('第一个产品的seller.name:', res.products[0].seller?.name)
+ console.log('第一个产品的seller完整结构:', JSON.stringify(res.products[0].seller))
+
+ let newGoodsList = res.products || []
+
+ // 格式化创建时间并处理创建者信息
+ newGoodsList = newGoodsList.map((item, index) => {
+ // 详细日志,查看每个产品的seller信息
+ console.log(`产品${index}的seller信息:`)
+ console.log(`- seller对象:`, item.seller)
+ console.log(`- seller.nickName:`, item.seller?.nickName)
+ console.log(`- seller.name:`, item.seller?.name)
+ console.log(`- seller完整结构:`, JSON.stringify(item.seller))
+
+ // 确定creatorName - 只使用nickName和sellerNickName字段,不使用name字段
+ // 详细日志,查看seller对象的完整结构和各个字段值
+ console.log('seller对象完整结构:', JSON.stringify(item.seller))
+ console.log('seller.nickName:', item.seller?.nickName)
+ console.log('seller.sellerNickName:', item.seller?.sellerNickName)
+ const creatorName = item.seller?.nickName || item.seller?.sellerNickName || '未知'
+ console.log('creatorName获取结果:', creatorName)
+
+ return {
+ ...item,
+ formattedCreatedAt: this.formatDateTime(item.created_at || item.createTime),
+ creatorName: creatorName
+ }
+ })
+
+ // 应用筛选条件
+ const originalList = [...newGoodsList]
+ const filteredList = this.filterGoodsList(newGoodsList)
+
+ console.log('处理并筛选后的产品列表:', filteredList)
+ console.log('筛选前后数量对比:', originalList.length, '->', filteredList.length)
+
+ // 处理分页逻辑
+ const updatedGoodsList = this.data.currentPage === 1 ? filteredList : [...this.data.goodsList, ...filteredList]
+
+ // 判断是否还有更多数据
+ // 正确逻辑:如果API返回的原始数据数量小于pageSize,说明没有更多数据
+ // 即使筛选后的数据量小于pageSize,只要API返回的原始数据数量等于pageSize,就应该继续尝试加载更多数据
+ const hasMore = res.products.length >= this.data.pageSize
+
+ console.log('分页判断:', {
+ updatedGoodsListLength: updatedGoodsList.length,
+ originalDataLength: res.products.length,
+ pageSize: this.data.pageSize,
+ hasMore: hasMore
+ })
+
+ this.setData({
+ goodsList: updatedGoodsList,
+ hasMore: hasMore,
+ total: total
+ })
+
+ // 移除递归调用逻辑,避免无限递归风险
+ // 用户可以通过正常的上拉加载获取更多数据
+ } else {
+ console.log('没有产品数据返回')
+ this.setData({
+ goodsList: [],
+ hasMore: false,
+ total: 0
+ })
+ }
+ } else {
+ console.error('API调用失败:', res.message)
+ wx.showToast({
+ title: res.message || '获取货源列表失败',
+ icon: 'none'
+ })
+ }
+ } catch (err) {
+ console.error('获取货源列表失败:', err)
+ wx.showToast({
+ title: '获取货源列表失败: ' + err.message,
+ icon: 'none'
+ })
+ } finally {
+ // 结束下拉刷新和加载状态
+ this.setData({
+ isLoading: false,
+ isRefreshing: false
+ })
+ }
+ }
+})
\ No newline at end of file
diff --git a/pages/goods/index.json b/pages/goods/index.json
new file mode 100644
index 0000000..1f1e882
--- /dev/null
+++ b/pages/goods/index.json
@@ -0,0 +1,7 @@
+{
+ "usingComponents": {},
+ "navigationBarTitleText": "内部货源管理",
+ "navigationBarBackgroundColor": "#ffffff",
+ "navigationBarTextStyle": "black",
+ "backgroundColor": "#f5f5f5"
+}
\ No newline at end of file
diff --git a/pages/goods/index.wxml b/pages/goods/index.wxml
new file mode 100644
index 0000000..122c567
--- /dev/null
+++ b/pages/goods/index.wxml
@@ -0,0 +1,133 @@
+
+
+
+ 内部货源管理
+
+
+
+
+
+
+ ✘
+
+
+
+
+
+
+
+ 全部
+
+
+ 小品种
+
+
+ 大贸易
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 预售
+ 现货
+
+
+
+ {{item.productName}}
+ 库存:{{item.quantity || item.minOrder || '充足'}}
+
+ {{item.specification || item.spec || '无'}} | {{item.yolk}}
+
+ {{item.costprice ? '¥' + item.costprice : '无采购价'}}
+ {{item.region || ''}}
+
+ {{item.description || ''}}
+
+ {{item.creatorName || '未知'}}
+ {{item.formattedCreatedAt || item.created_at || '未知'}}
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+ 货源正在快马加鞭的赶来
+
+
+
+
+ 暂无货源数据
+ 下拉刷新试试
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/goods/index.wxss b/pages/goods/index.wxss
new file mode 100644
index 0000000..bc5d223
--- /dev/null
+++ b/pages/goods/index.wxss
@@ -0,0 +1,492 @@
+.container {
+ width: 100%;
+ padding: 20rpx;
+ box-sizing: border-box;
+ background-color: #f5f5f5;
+ min-height: 100vh;
+}
+
+.page-title {
+ font-size: 36rpx;
+ font-weight: bold;
+ color: #333;
+ text-align: center;
+ margin: 20rpx 0 30rpx;
+}
+
+/* 搜索框样式 */
+.search-container {
+ margin-bottom: 20rpx;
+}
+
+.search-box {
+ position: relative;
+ display: flex;
+ align-items: center;
+ background-color: white;
+ border-radius: 40rpx;
+ padding: 0 20rpx;
+ box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
+}
+
+/* 筛选样式 */
+.filter-container {
+ margin: 0 auto 24rpx;
+ padding: 0 30rpx;
+ box-sizing: border-box;
+ width: 100%;
+}
+
+.filter-buttons {
+ display: flex;
+ background-color: white;
+ border-radius: 50rpx;
+ overflow: hidden;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
+ border: 2rpx solid transparent;
+ transition: all 0.3s ease;
+}
+
+.filter-btn {
+ flex: 1;
+ text-align: center;
+ padding: 18rpx 0;
+ font-size: 28rpx;
+ color: #666;
+ background-color: transparent;
+ border: none;
+ cursor: pointer;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ position: relative;
+ font-weight: 500;
+}
+
+.filter-btn.active {
+ color: #1677ff;
+ font-weight: bold;
+ background: linear-gradient(135deg, #e6f0ff 0%, #f0f7ff 100%);
+ box-shadow: inset 0 2rpx 8rpx rgba(22, 119, 255, 0.15);
+}
+
+.filter-btn::after {
+ content: '';
+ position: absolute;
+ right: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 2rpx;
+ height: 48rpx;
+ background: linear-gradient(180deg, transparent 0%, #e8e8e8 50%, transparent 100%);
+}
+
+.filter-btn:last-child::after {
+ display: none;
+}
+
+.filter-btn:active {
+ opacity: 0.8;
+ transform: scale(0.98);
+}
+
+/* 第一个和最后一个按钮特殊样式 */
+.filter-btn:first-child {
+ border-radius: 50rpx 0 0 50rpx;
+}
+
+.filter-btn:last-child {
+ border-radius: 0 50rpx 50rpx 0;
+}
+
+/* 激活状态下的按钮动画效果 */
+.filter-btn.active::before {
+ content: '';
+ position: absolute;
+ top: 10rpx;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 12rpx;
+ height: 6rpx;
+ background: #1677ff;
+ border-radius: 3rpx;
+ animation: pulse 1.5s infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% {
+ opacity: 1;
+ transform: translateX(-50%) scale(1);
+ }
+ 50% {
+ opacity: 0.7;
+ transform: translateX(-50%) scale(1.1);
+ }
+}
+
+.search-input {
+ flex: 1;
+ height: 80rpx;
+ font-size: 28rpx;
+ color: #333;
+ padding: 0 20rpx;
+ box-sizing: border-box;
+}
+
+.search-input::placeholder {
+ color: #999;
+}
+
+.clear-icon {
+ font-size: 30rpx;
+ color: #999;
+ padding: 10rpx;
+ cursor: pointer;
+}
+
+/* 加载中样式 */
+.loading-container {
+ text-align: center;
+ padding: 60rpx 0;
+}
+
+.loading-text {
+ font-size: 28rpx;
+ color: #999;
+}
+
+/* 货源列表样式 - 网格布局 */
+.goods-section {
+ width: 100%;
+ margin-top: 20rpx;
+ height: calc(100vh - 300rpx); /* 设置容器高度,确保scroll-view能正常滚动 */
+}
+
+/* 滚动视图样式 */
+.goods-list {
+ height: 100%; /* 设置scroll-view高度为100%,确保能正常滚动 */
+ overflow: hidden;
+}
+
+.goods-list-container {
+ width: 100%;
+ padding: 0 10rpx;
+ box-sizing: border-box;
+}
+
+/* 网格容器 */
+.grid-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20rpx;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+/* 网格商品项 */
+.grid-item {
+ width: calc((100% - 20rpx) / 2);
+ box-sizing: border-box;
+}
+
+/* 商品卡片样式 */
+.product-card {
+ background-color: white;
+ border: 2rpx solid #e0e0e0;
+ border-radius: 16rpx;
+ overflow: hidden;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+ transition: all 0.3s ease;
+ padding: 16rpx;
+ box-sizing: border-box;
+}
+
+.product-card:active {
+ transform: scale(0.98);
+ box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.1);
+}
+
+/* 商品图片区域 */
+.product-image-wrapper {
+ position: relative;
+ width: 100%;
+ height: 200rpx;
+ background: #f5f5f5;
+ border-radius: 12rpx;
+ overflow: hidden;
+ margin-bottom: 16rpx;
+}
+
+.product-image {
+ width: 100%;
+ height: 100%;
+ display: block;
+ object-fit: cover;
+ object-position: center;
+ background-color: #f5f5f5;
+}
+
+/* 促销标签 */
+.promo-tag {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 6rpx 12rpx;
+ font-size: 20rpx;
+ color: #fff;
+ border-radius: 0 0 12rpx 0;
+ z-index: 1;
+ font-weight: 600;
+}
+
+.promo-tag.presale {
+ background: linear-gradient(135deg, #ff6b00 0%, #ff8c00 100%);
+ box-shadow: 0 2rpx 8rpx rgba(255, 107, 0, 0.3);
+}
+
+.promo-tag.in-stock {
+ background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%);
+ box-shadow: 0 2rpx 8rpx rgba(82, 196, 26, 0.3);
+}
+
+/* 商品信息区域 */
+.product-info {
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 8rpx;
+}
+
+/* 商品标题行 - 包含商品名称和库存 */
+.product-title-row {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ width: 100%;
+ flex-wrap: wrap;
+ gap: 8rpx;
+}
+
+/* 商品标题 */
+.product-title {
+ font-size: 26rpx;
+ color: #000000;
+ line-height: 1.4;
+ height: auto;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 1;
+ -webkit-box-orient: vertical;
+ font-weight: 700;
+ flex: 1;
+ margin-right: 0;
+}
+
+/* 库存计数 */
+.stock-count {
+ font-size: 20rpx;
+ padding: 2rpx 10rpx;
+ border-radius: 12rpx;
+ background: rgba(82, 196, 26, 0.15);
+ color: #389e0d;
+ border: 1rpx solid rgba(82, 196, 26, 0.5);
+ font-weight: 600;
+ align-self: center;
+ margin-top: 0;
+ flex-shrink: 0;
+}
+
+/* 商品规格 */
+.product-spec {
+ font-size: 22rpx;
+ color: #333333;
+ height: auto;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ line-height: 1.3;
+ margin-bottom: 2rpx;
+ margin-top: 2rpx;
+}
+
+/* 商品元信息 */
+.product-meta {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 2rpx 0 4rpx;
+ padding: 0;
+}
+
+.product-price {
+ font-size: 28rpx;
+ color: #ff4d4f;
+ font-weight: bold;
+}
+
+.product-location {
+ font-size: 20rpx;
+ color: #666;
+}
+
+/* 商品描述 */
+.product-description {
+ font-size: 22rpx;
+ color: #666;
+ line-height: 1.4;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ margin: 6rpx 0;
+ background: #fafafa;
+ padding: 6rpx;
+ border-radius: 8rpx;
+ border: 1rpx solid #f0f0f0;
+ width: 100%;
+ box-sizing: border-box;
+ min-height: 50rpx;
+ display: flex;
+ align-items: center;
+}
+
+/* 创建人信息 */
+.creator-info {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 8rpx;
+ padding-top: 12rpx;
+ border-top: 1rpx solid #f0f0f0;
+ font-size: 20rpx;
+}
+
+/* 加载更多样式 */
+.loading-more {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 40rpx 0;
+ width: 100%;
+}
+
+.loading-spinner {
+ width: 32rpx;
+ height: 32rpx;
+ border: 3rpx solid #e5e5e5;
+ border-top-color: #1677ff;
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+ margin-right: 12rpx;
+}
+
+.loading-text {
+ font-size: 26rpx;
+ color: #999;
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+/* 无更多数据 */
+.no-more-data {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 40rpx 0;
+ color: #999;
+ font-size: 26rpx;
+ gap: 20rpx;
+}
+
+.no-more-data::before,
+.no-more-data::after {
+ content: '';
+ flex: 1;
+ height: 1rpx;
+ background: #e5e5e5;
+ max-width: 80rpx;
+}
+
+/* 空状态样式 */
+.empty-container {
+ text-align: center;
+ padding: 100rpx 0;
+ color: #999;
+ font-size: 28rpx;
+}
+
+/* 骨架屏样式 */
+.skeleton-container {
+ padding: 20rpx 0;
+}
+
+.skeleton-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20rpx;
+ width: 100%;
+ padding: 0 10rpx;
+ box-sizing: border-box;
+}
+
+.skeleton-grid-item {
+ width: calc((100% - 20rpx) / 2);
+ background: #fff;
+ border-radius: 16rpx;
+ overflow: hidden;
+ padding: 16rpx;
+ box-sizing: border-box;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+}
+
+.skeleton-image {
+ width: 100%;
+ height: 200rpx;
+ background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 50%, #f0f0f0 75%);
+ background-size: 200% 100%;
+ animation: skeleton-loading 1.5s infinite;
+ border-radius: 12rpx;
+ margin-bottom: 16rpx;
+}
+
+.skeleton-title {
+ height: 32rpx;
+ margin-bottom: 12rpx;
+ background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 50%, #f0f0f0 75%);
+ background-size: 200% 100%;
+ animation: skeleton-loading 1.5s infinite;
+ border-radius: 8rpx;
+}
+
+.skeleton-title.short {
+ width: 60%;
+ height: 24rpx;
+ margin-bottom: 16rpx;
+}
+
+.skeleton-footer {
+ display: flex;
+ justify-content: space-between;
+}
+
+.skeleton-price {
+ width: 80rpx;
+ height: 28rpx;
+ background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 50%, #f0f0f0 75%);
+ background-size: 200% 100%;
+ animation: skeleton-loading 1.5s infinite;
+ border-radius: 8rpx;
+}
+
+@keyframes skeleton-loading {
+ 0% {
+ background-position: 200% 0;
+ }
+ 100% {
+ background-position: -200% 0;
+ }
+}
\ No newline at end of file
diff --git a/pages/index/index.js b/pages/index/index.js
index ad64925..9030faf 100644
--- a/pages/index/index.js
+++ b/pages/index/index.js
@@ -1479,6 +1479,16 @@ Page({
})
},
+ // 跳转到货源管理页面
+ navigateToGoods: function() {
+ this.setData({
+ sidebarBtnHidden: true
+ });
+ wx.navigateTo({
+ url: '/pages/goods/index'
+ })
+ },
+
// 预览图片
previewImage: function(e) {
// 阻止事件冒泡,避免触发商品点击事件
diff --git a/pages/index/index.wxml b/pages/index/index.wxml
index 4fd756c..e3f30f4 100644
--- a/pages/index/index.wxml
+++ b/pages/index/index.wxml
@@ -100,6 +100,10 @@
+
diff --git a/pages/message-list/index.js b/pages/message-list/index.js
index 4214da6..c9fecf8 100644
--- a/pages/message-list/index.js
+++ b/pages/message-list/index.js
@@ -219,6 +219,12 @@ Page({
users[userId] = {}
}
+ // 如果当前类型是 Colleague,直接返回,不允许从服务器同步覆盖
+ if (users[userId].type === 'Colleague') {
+ console.log('当前用户是 Colleague 类型,不允许从服务器同步覆盖用户类型')
+ return
+ }
+
// 移除serverType中的customer(如果存在)
let processedServerType = serverType.replace(/,?customer/g, '').replace(/^,|,$/g, '')
diff --git a/pages/profile/index.js b/pages/profile/index.js
index 73d8fc9..094bdf6 100644
--- a/pages/profile/index.js
+++ b/pages/profile/index.js
@@ -219,6 +219,12 @@ Page({
users[userId] = {}
}
+ // 如果当前类型是 Colleague,直接返回,不允许从服务器同步覆盖
+ if (users[userId].type === 'Colleague') {
+ console.log('当前用户是 Colleague 类型,不允许从服务器同步覆盖用户类型')
+ return
+ }
+
// 移除serverType中的customer(如果存在)
let processedServerType = serverType.replace(/,?customer/g, '').replace(/^,|,$/g, '')
diff --git a/pages/seller/index.js b/pages/seller/index.js
index e7d3884..91e8690 100644
--- a/pages/seller/index.js
+++ b/pages/seller/index.js
@@ -2560,7 +2560,7 @@ Page({
finishSetUserType(type) {
const userId = wx.getStorageSync('userId')
- // 更新用户类型
+ // 获取当前用户类型
let users = wx.getStorageSync('users')
if (typeof users !== 'object' || users === null) {
users = {}
@@ -2568,6 +2568,21 @@ Page({
if (!users[userId]) {
users[userId] = {}
}
+
+ // 如果当前类型是 Colleague,直接跳转到对应页面,不修改用户类型
+ if (users[userId].type === 'Colleague') {
+ console.log('当前用户是 Colleague 类型,不允许修改用户类型,直接跳转')
+ setTimeout(() => {
+ if (type === 'buyer') {
+ wx.switchTab({ url: '/pages/buyer/index' })
+ } else {
+ wx.switchTab({ url: '/pages/seller/index' })
+ }
+ }, 1000)
+ return
+ }
+
+ // 更新用户类型
users[userId].type = type
wx.setStorageSync('users', users)
diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js
index 5f7274b..fcd2091 100644
--- a/server-example/server-mysql.js
+++ b/server-example/server-mysql.js
@@ -839,6 +839,11 @@ Product.init({
type: DataTypes.STRING(50),
allowNull: true,
comment: '商品种类'
+ },
+ description: {
+ type: DataTypes.TEXT,
+ allowNull: true,
+ comment: '货源描述'
}
}, {
sequelize,
@@ -1966,21 +1971,34 @@ app.post('/api/product/list', async (req, res) => {
const { count, rows: products } = await Product.findAndCountAll({
where,
include: [
- {
- model: User,
- as: 'seller',
- attributes: ['userId', 'name', 'avatarUrl']
- }
+ {
+ model: User,
+ as: 'seller',
+ attributes: ['userId', 'name', 'nickName', 'avatarUrl']
+ }
+ ],
+ attributes: [
+ 'id',
+ 'productId',
+ 'sellerId',
+ 'productName',
+ 'price',
+ 'costprice',
+ 'quantity',
+ 'grossWeight',
+ 'yolk',
+ 'specification',
+ 'created_at',
+ 'updated_at',
+ 'imageUrls',
+ 'status',
+ 'region',
+ 'sourceType',
+ 'supplyStatus',
+ 'category',
+ 'producting',
+ 'description'
],
- attributes: {
- include: [
- 'region', // 【新增】确保返回地区字段
- 'sourceType', // 【新增】确保返回货源类型字段
- 'supplyStatus', // 【新增】确保返回供应状态字段
- 'category', // 【新增】确保返回商品种类字段
- 'producting' // 【新增】确保返回产品包装字段
- ]
- },
order: [['created_at', 'DESC']],
limit: pageSize,
offset
@@ -1996,16 +2014,16 @@ app.post('/api/product/list', async (req, res) => {
const processedProducts = await Promise.all(products.map(async product => {
const productJSON = product.toJSON();
- // 确保created_at字段存在并转换为ISO字符串格式
+ // 确保created_at字段存在并转换为正确格式
if (!productJSON.created_at) {
console.log('商品缺少created_at字段,使用默认值');
productJSON.created_at = getBeijingTimeISOString();
} else {
- // 确保created_at是字符串格式
+ // 确保created_at是字符串格式,不进行多余的时区转换
if (productJSON.created_at instanceof Date) {
- productJSON.created_at = new Date(productJSON.created_at.getTime() + 8 * 60 * 60 * 1000).toISOString();
+ productJSON.created_at = productJSON.created_at.toISOString();
} else if (typeof productJSON.created_at !== 'string') {
- productJSON.created_at = new Date(new Date(productJSON.created_at).getTime() + 8 * 60 * 60 * 1000).toISOString();
+ productJSON.created_at = new Date(productJSON.created_at).toISOString();
}
}
@@ -2072,12 +2090,48 @@ app.post('/api/product/list', async (req, res) => {
productJSON.imageUrls = [];
}
+ // 确保seller对象的nickName字段正确返回
+ if (productJSON.seller) {
+ // 确保seller对象结构正确,处理nickName字段
+ console.log('seller对象各字段值:');
+ console.log('- seller.userId:', productJSON.seller.userId);
+ console.log('- seller.nickName:', productJSON.seller.nickName);
+ console.log('- seller.name:', productJSON.seller.name);
+
+ // 按照用户要求,只使用users表里的nickName
+ const nickName = productJSON.seller.nickName || productJSON.seller.name || '未知';
+ console.log('最终确定的nickName:', nickName);
+
+ productJSON.seller = {
+ ...productJSON.seller,
+ // 只使用nickName字段
+ nickName: nickName,
+ sellerNickName: nickName, // 确保sellerNickName字段存在
+ sellerName: nickName
+ };
+ } else {
+ // 如果没有seller对象,创建默认对象
+ productJSON.seller = {
+ nickName: '未知',
+ sellerNickName: '未知',
+ sellerName: '未知'
+ };
+ }
+
+ // 确保created_at字段存在
+ console.log('productJSON.created_at:', productJSON.created_at);
+ if (!productJSON.created_at) {
+ console.warn('商品缺少created_at字段,使用默认值');
+ productJSON.created_at = getBeijingTimeISOString();
+ }
+
// 记录第一个商品的转换信息用于调试
if (products.indexOf(product) === 0) {
console.log('商品列表 - 第一个商品毛重字段处理:');
console.log('- 原始值:', grossWeightDetails.value, '类型:', grossWeightDetails.type);
console.log('- 转换后的值:', productJSON.grossWeight, '类型:', typeof productJSON.grossWeight);
console.log('- reservedCount值:', productJSON.reservedCount, '类型:', typeof productJSON.reservedCount);
+ console.log('- seller信息:', JSON.stringify(productJSON.seller));
}
return productJSON;
diff --git a/utils/api.js b/utils/api.js
index 7ae9ff7..a2243d5 100644
--- a/utils/api.js
+++ b/utils/api.js
@@ -1017,6 +1017,72 @@ module.exports = {
return { success: false, message: '聊天记录修复失败:' + err.message };
});
},
+
+ // 获取商品列表方法,用于goods页面
+ getGoodsList: function (params) {
+ console.log('API.getGoodsList - params:', params);
+ const openid = wx.getStorageSync('openid');
+ if (!openid) {
+ return Promise.reject(new Error('用户未登录'));
+ }
+ const requestData = {
+ openid: openid,
+ page: params.page || 1,
+ pageSize: params.pageSize || 10,
+ status: 'published',
+ viewMode: 'shopping', // 确保能够查看所有内部人员创建的货源
+ _t: new Date().getTime() // 添加时间戳防止缓存
+ };
+
+ // 如果有搜索关键词,添加到请求参数中
+ if (params.keyword) {
+ requestData.keyword = params.keyword;
+ }
+
+ return request('/api/product/list', 'POST', requestData).then(data => {
+ // 添加字段映射,确保产品名称正确显示
+ if (data.success && data.products && Array.isArray(data.products)) {
+ data.products = data.products.map(product => {
+ // 处理产品名称映射
+ const name = product.productName || product.name || '未命名商品';
+
+ // 处理创建者信息
+ let seller = product.seller || {};
+ // 确保seller对象结构正确
+ if (seller && typeof seller === 'object') {
+ // 确保sellerNickName字段存在,同时支持nickName字段作为备选
+ const sellerNickName = seller.sellerNickName || seller.nickName || '未知';
+
+ // 确保seller对象包含所有必要字段,特别是nickName字段
+ seller = {
+ ...seller,
+ nickName: sellerNickName, // 确保nickName字段存在,与sellerNickName保持一致
+ sellerNickName: sellerNickName, // 确保sellerNickName字段存在
+ name: seller.name || sellerNickName // 不再移除name字段,保留原始信息
+ };
+ } else {
+ // 如果seller不是对象,创建默认对象,只包含nickName相关字段
+ seller = {
+ nickName: '未知',
+ sellerNickName: '未知',
+ name: '未知'
+ };
+ }
+
+ return {
+ ...product,
+ // 确保name字段存在,优先使用productName,其次使用name
+ name: name,
+ // 确保seller对象结构正确
+ seller: seller,
+ // 确保costprice字段存在,使用三元运算符处理,保留0值
+ costprice: product.costprice !== undefined && product.costprice !== null ? product.costprice : ''
+ };
+ });
+ }
+ return data;
+ });
+ },
// 上传带图片的商品 - 改进版,确保所有图片都被实际上传到服务器
uploadProductWithImages: function (productData, imageUrls) {