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/custom-tab-bar/index.js b/custom-tab-bar/index.js
index 0e7a139..1db8c91 100644
--- a/custom-tab-bar/index.js
+++ b/custom-tab-bar/index.js
@@ -58,7 +58,7 @@ Component({
if (key === 'seller') {
const userId = wx.getStorageSync('userId');
if (userId) {
- // 更新用户类型
+ // 获取当前用户类型
let users = wx.getStorageSync('users');
if (typeof users !== 'object' || users === null) {
users = {};
@@ -66,18 +66,23 @@ Component({
if (!users[userId]) {
users[userId] = {};
}
- users[userId].type = key;
- wx.setStorageSync('users', users);
-
- // 更新标签
- let tags = wx.getStorageSync('tags');
- if (typeof tags !== 'object' || tags === null) {
- tags = {};
+ // 只有当当前类型不是 Colleague 时才修改为 seller
+ const currentType = users[userId].type;
+ if (currentType !== 'Colleague') {
+ // 更新用户类型
+ users[userId].type = key;
+ 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(`身份:${key}`);
+ wx.setStorageSync('tags', tags);
}
- tags[userId] = tags[userId] || [];
- tags[userId] = tags[userId].filter(tag => !tag.startsWith('身份:'));
- tags[userId].push(`身份:${key}`);
- wx.setStorageSync('tags', tags);
}
}
diff --git a/pages/buyer/index.js b/pages/buyer/index.js
index 3b6935b..75f230b 100644
--- a/pages/buyer/index.js
+++ b/pages/buyer/index.js
@@ -477,7 +477,7 @@ Page({
// 确保用户身份被设置为买家
const userId = wx.getStorageSync('userId');
if (userId) {
- // 更新用户类型
+ // 获取当前用户类型
let users = wx.getStorageSync('users');
if (typeof users !== 'object' || users === null) {
users = {};
@@ -485,18 +485,23 @@ 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..2971579
--- /dev/null
+++ b/pages/goods/index.js
@@ -0,0 +1,333 @@
+// 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: 100,
+ 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() {
+ this.setData({
+ isRefreshing: true,
+ currentPage: 1,
+ goodsList: [],
+ hasMore: true
+ })
+ 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() {
+ this.setData({
+ currentPage: 1,
+ goodsList: [],
+ hasMore: true
+ })
+ this.loadGoodsList()
+ },
+
+ /**
+ * 清除搜索
+ */
+ clearSearch() {
+ this.setData({
+ searchKeyword: '',
+ currentPage: 1,
+ goodsList: [],
+ hasMore: true
+ })
+ this.loadGoodsList()
+ },
+
+ /**
+ * 筛选条件改变
+ */
+ onFilterChange(e) {
+ 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-03 10:04:29)
+ if (typeof dateString === 'string' && /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(dateString)) {
+ // 直接返回格式化好的字符串,只保留到分钟
+ return dateString.slice(0, 16)
+ }
+
+ // 检查是否是其他格式的字符串
+ const date = new Date(dateString)
+ if (isNaN(date.getTime())) {
+ // 如果转换失败,直接返回原字符串
+ return dateString
+ }
+
+ 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}`
+ },
+
+ /**
+ * 加载货源列表
+ */
+ 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,不使用name字段
+ const creatorName = item.seller?.nickName || '未知'
+ 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
+ })
+
+ // 如果是第一页,且筛选后的数据不足,尝试加载下一页
+ if (this.data.currentPage === 1 && hasMore && filteredList.length < this.data.pageSize) {
+ console.log('筛选后数据不足,继续加载下一页')
+ this.setData({
+ currentPage: this.data.currentPage + 1
+ })
+ // 递归调用loadGoodsList,继续加载下一页
+ this.loadGoodsList()
+ return
+ }
+ } 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..f12428e
--- /dev/null
+++ b/pages/goods/index.wxml
@@ -0,0 +1,133 @@
+
+
+
+ 内部货源管理
+
+
+
+
+
+
+ ✘
+
+
+
+
+
+
+
+ 全部
+
+
+ 小品种
+
+
+ 大贸易
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 预售
+ 现货
+
+
+
+ {{item.name}}
+ 库存:{{item.quantity || item.minOrder || '充足'}}
+
+ {{item.specification || item.spec || '无'}} | {{item.yolk}}
+
+ ¥{{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 d7cc2c6..360c3b4 100644
--- a/pages/index/index.js
+++ b/pages/index/index.js
@@ -1408,6 +1408,16 @@ Page({
})
},
+ // 跳转到货源管理页面
+ navigateToGoods: function() {
+ this.setData({
+ sidebarBtnHidden: true
+ });
+ wx.navigateTo({
+ url: '/pages/goods/index'
+ })
+ },
+
// 预览图片
previewImage: function(e) {
// 阻止事件冒泡,避免触发商品点击事件
@@ -2537,6 +2547,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/index/index.wxml b/pages/index/index.wxml
index fc84790..42a5830 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 85e7ab1..2d408d2 100644
--- a/server-example/server-mysql.js
+++ b/server-example/server-mysql.js
@@ -763,6 +763,11 @@ Product.init({
type: DataTypes.STRING(10),
allowNull: false
},
+ costprice: {
+ type: DataTypes.STRING(10),
+ allowNull: true,
+ comment: '采购价'
+ },
quantity: {
type: DataTypes.INTEGER,
allowNull: false
@@ -839,6 +844,11 @@ Product.init({
type: DataTypes.STRING(50),
allowNull: true,
comment: '商品种类'
+ },
+ description: {
+ type: DataTypes.TEXT,
+ allowNull: true,
+ comment: '货源描述'
}
}, {
sequelize,
@@ -1969,18 +1979,35 @@ app.post('/api/product/list', async (req, res) => {
{
model: User,
as: 'seller',
- attributes: ['userId', 'name', 'avatarUrl']
+ attributes: [
+ 'userId',
+ ['nickName', 'sellerNickName'], // 使用别名避免字段冲突
+ 'avatarUrl'
+ ]
}
],
- attributes: {
- include: [
- 'region', // 【新增】确保返回地区字段
- 'sourceType', // 【新增】确保返回货源类型字段
- 'supplyStatus', // 【新增】确保返回供应状态字段
- 'category', // 【新增】确保返回商品种类字段
- 'producting' // 【新增】确保返回产品包装字段
- ]
- },
+ attributes: [
+ 'id',
+ 'productId',
+ 'sellerId',
+ 'productName',
+ 'price',
+ 'costprice', // 【新增】确保返回采购价字段
+ 'quantity',
+ 'grossWeight',
+ 'yolk',
+ 'specification',
+ 'created_at',
+ 'updated_at',
+ 'imageUrls',
+ 'status',
+ 'region',
+ 'sourceType',
+ 'supplyStatus',
+ 'category',
+ 'producting',
+ 'description'
+ ],
order: [['created_at', 'DESC']],
limit: pageSize,
offset
@@ -1996,18 +2023,45 @@ 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();
- } else if (typeof productJSON.created_at !== 'string') {
- productJSON.created_at = new Date(new Date(productJSON.created_at).getTime() + 8 * 60 * 60 * 1000).toISOString();
+ // 直接使用Date对象的字符串表示,不转换为ISO格式
+ productJSON.created_at = productJSON.created_at.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
+ } else if (typeof productJSON.created_at === 'string') {
+ // 数据库已经存储的是北京时间字符串,直接使用
+ productJSON.created_at = productJSON.created_at;
+ } else {
+ // 其他类型,转换为Date对象后再转换为北京时间字符串
+ productJSON.created_at = new Date(productJSON.created_at).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
}
}
+
+ // 确保seller对象的nickName字段正确返回
+ if (productJSON.seller) {
+ // 确保seller对象结构正确,处理别名映射 - 只使用nickName,不使用name字段
+ // 保留sellerNickName字段,确保前端能正确访问
+ productJSON.seller = {
+ ...productJSON.seller,
+ // 处理别名,只确保nickName字段存在 - 只使用nickName,不使用name字段
+ nickName: productJSON.seller.sellerNickName || productJSON.seller.nickName || '未知',
+ // 移除name字段,只使用nickName
+ name: undefined,
+ // 保留sellerNickName字段,确保前端能正确访问
+ // sellerNickName: undefined,
+ sellerName: undefined
+ };
+ } else {
+ // 如果没有seller对象,创建默认对象 - 只包含nickName
+ productJSON.seller = {
+ nickName: '未知',
+ name: undefined
+ };
+ }
// 详细分析毛重字段
const grossWeightDetails = {
diff --git a/utils/api.js b/utils/api.js
index 7ae9ff7..94fd615 100644
--- a/utils/api.js
+++ b/utils/api.js
@@ -1649,7 +1649,10 @@ module.exports = {
if (!users[userId]) {
users[userId] = {};
}
- users[userId].type = userType;
+ // 如果当前类型已经是 Colleague,保留不变
+ if (users[userId].type !== 'Colleague') {
+ users[userId].type = userType;
+ }
if (managerId) {
users[userId].managerId = managerId;
} else {
@@ -1826,7 +1829,10 @@ module.exports = {
if (!users[userId]) {
users[userId] = {};
}
- users[userId].type = userType; // 直接存储用户类型
+ // 如果当前类型已经是 Colleague,保留不变
+ if (users[userId].type !== 'Colleague') {
+ users[userId].type = userType; // 直接存储用户类型
+ }
wx.setStorageSync('users', users);
}
@@ -2209,7 +2215,10 @@ module.exports = {
if (!users[userId]) {
users[userId] = {};
}
- users[userId].type = userType;
+ // 如果当前类型已经是 Colleague,保留不变
+ if (users[userId].type !== 'Colleague') {
+ users[userId].type = userType;
+ }
wx.setStorageSync('users', users);
}
@@ -2417,7 +2426,10 @@ module.exports = {
if (!users[userId]) {
users[userId] = {};
}
- users[userId].type = userType.replace('customer', '');
+ // 如果当前类型已经是 Colleague,保留不变
+ if (users[userId].type !== 'Colleague') {
+ users[userId].type = userType.replace('customer', '');
+ }
wx.setStorageSync('users', users);
}
@@ -2959,6 +2971,12 @@ module.exports = {
let users = wx.getStorageSync('users') || {};
let currentType = users[userId] && users[userId].type ? users[userId].type : '';
+ // 如果当前类型是 Colleague,直接返回,不允许修改
+ if (currentType === 'Colleague') {
+ console.log('当前用户是 Colleague 类型,不允许修改用户类型');
+ return;
+ }
+
// 计算新的用户类型(支持buyer、seller、both、manager)
let newType = currentType;
@@ -3156,6 +3174,69 @@ module.exports = {
});
},
+ // 获取货源列表(内部使用)
+ 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') {
+ // 如果seller是对象,只使用nickName,不使用name字段
+ // 正确处理后端返回的别名sellerNickName和sellerName
+ seller = {
+ ...seller,
+ nickName: seller.sellerNickName || seller.nickName || '未知',
+ // 移除name字段,只使用nickName
+ name: undefined
+ };
+ } else {
+ // 如果seller不是对象,创建默认对象,只包含nickName
+ seller = {
+ nickName: '未知',
+ name: undefined
+ };
+ }
+
+ return {
+ ...product,
+ // 确保name字段存在,优先使用productName,其次使用name
+ name: name,
+ // 确保seller对象结构正确
+ seller: seller,
+ // 确保costprice字段存在
+ costprice: product.costprice || ''
+ };
+ });
+ }
+ return data;
+ });
+ },
+
// 添加BASE_URL属性,方便其他地方使用
BASE_URL: BASE_URL,
// 正确导出withdrawSettlementApplication方法