From 542e46142db52e722dd46a1178334524709a317c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Tue, 27 Jan 2026 11:20:38 +0800 Subject: [PATCH 01/22] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=9B=B4=E6=94=B9?= =?UTF-8?q?=E5=88=B0update=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.json | 6 +- custom-tab-bar/index.js | 20 +- pages/evaluate2/index.js | 468 +++++++++++++++++++++++++ pages/evaluate2/index.json | 5 + pages/evaluate2/index.wxml | 78 +++++ pages/evaluate2/index.wxss | 450 ++++++++++++++++++++++++ pages/evaluate2/one.js | 463 ++++++++++++++++++++++++ pages/evaluate2/one.json | 5 + pages/evaluate2/one.wxml | 100 ++++++ pages/evaluate2/one.wxss | 560 ++++++++++++++++++++++++++++++ pages/evaluate2/product-list.js | 486 ++++++++++++++++++++++++++ pages/evaluate2/product-list.json | 5 + pages/evaluate2/product-list.wxml | 72 ++++ pages/evaluate2/product-list.wxss | 415 ++++++++++++++++++++++ pages/evaluate2/spec-detail.js | 102 ++++++ pages/evaluate2/spec-detail.json | 5 + pages/evaluate2/spec-detail.wxml | 59 ++++ pages/evaluate2/spec-detail.wxss | 401 +++++++++++++++++++++ 18 files changed, 3689 insertions(+), 11 deletions(-) create mode 100644 pages/evaluate2/index.js create mode 100644 pages/evaluate2/index.json create mode 100644 pages/evaluate2/index.wxml create mode 100644 pages/evaluate2/index.wxss create mode 100644 pages/evaluate2/one.js create mode 100644 pages/evaluate2/one.json create mode 100644 pages/evaluate2/one.wxml create mode 100644 pages/evaluate2/one.wxss create mode 100644 pages/evaluate2/product-list.js create mode 100644 pages/evaluate2/product-list.json create mode 100644 pages/evaluate2/product-list.wxml create mode 100644 pages/evaluate2/product-list.wxss create mode 100644 pages/evaluate2/spec-detail.js create mode 100644 pages/evaluate2/spec-detail.json create mode 100644 pages/evaluate2/spec-detail.wxml create mode 100644 pages/evaluate2/spec-detail.wxss diff --git a/app.json b/app.json index 42a3cbf..0a00338 100644 --- a/app.json +++ b/app.json @@ -5,6 +5,10 @@ "pages/evaluate1/index", "pages/evaluate1/product-list", "pages/evaluate1/spec-detail", + "pages/evaluate2/index", + "pages/evaluate2/one", + "pages/evaluate2/product-list", + "pages/evaluate2/spec-detail", "pages/settlement/index", "pages/publish/index", "pages/buyer/index", @@ -77,7 +81,7 @@ "text": "消息" }, { - "pagePath": "pages/evaluate1/index", + "pagePath": "pages/evaluate2/index", "text": "估" }, { diff --git a/custom-tab-bar/index.js b/custom-tab-bar/index.js index 031c1b2..1d90d18 100644 --- a/custom-tab-bar/index.js +++ b/custom-tab-bar/index.js @@ -15,7 +15,7 @@ Component({ tabBarItems: [ { key: 'index', route: 'pages/index/index' }, { key: 'chat', route: 'pages/chat/index', badgeKey: 'chat' }, - { key: 'evaluate', route: 'pages/evaluate1/index' }, + { key: 'evaluate', route: 'pages/evaluate2/one' }, { key: 'settlement', route: 'pages/settlement/index' }, { key: 'favorites', route: 'pages/favorites/index' }, { key: 'profile', route: 'pages/profile/index' } @@ -94,7 +94,7 @@ Component({ const tabBarPages = [ 'pages/index/index', 'pages/chat/index', - 'pages/evaluate1/index', + 'pages/evaluate2/one', 'pages/settlement/index', 'pages/favorites/index', 'pages/profile/index' @@ -178,11 +178,11 @@ Component({ // 跳转到估价页面 goToEvaluatePage() { - console.log('点击了估价按钮,跳转到evaluate1页面') + console.log('点击了估价按钮,跳转到evaluate2/one页面') wx.switchTab({ - url: '/pages/evaluate1/index', + url: '/pages/evaluate2/one', success: (res) => { - console.log('switchTab到evaluate1成功:', res) + console.log('switchTab到evaluate2/one成功:', res) // 更新选中状态 this.setData({ selected: 'evaluate' }) // 更新全局数据 @@ -192,13 +192,13 @@ Component({ } }, fail: (err) => { - console.error('switchTab到evaluate1失败:', err) + console.error('switchTab到evaluate2/one失败:', err) // 失败时尝试使用reLaunch - console.log('尝试使用reLaunch跳转到evaluate1...') + console.log('尝试使用reLaunch跳转到evaluate2/one...') wx.reLaunch({ - url: '/pages/evaluate1/index', + url: '/pages/evaluate2/one', success: (res) => { - console.log('reLaunch到evaluate1成功:', res) + console.log('reLaunch到evaluate2/one成功:', res) // 更新选中状态 this.setData({ selected: 'evaluate' }) // 更新全局数据 @@ -208,7 +208,7 @@ Component({ } }, fail: (err) => { - console.error('reLaunch到evaluate1也失败:', err) + console.error('reLaunch到evaluate2/one也失败:', err) } }) } diff --git a/pages/evaluate2/index.js b/pages/evaluate2/index.js new file mode 100644 index 0000000..2324627 --- /dev/null +++ b/pages/evaluate2/index.js @@ -0,0 +1,468 @@ +Page({ + data: { + productName: '', + specifications: [], + loading: false, + error: '' + }, + onLoad(options) { + let productName = ''; + // 首先检查URL参数 + if (options.productName) { + productName = options.productName; + } else { + // 然后检查本地存储(用于wx.switchTab导航) + productName = wx.getStorageSync('selectedProductName') || ''; + // 清除本地存储中的商品名称,避免影响下次进入 + if (productName) { + wx.removeStorageSync('selectedProductName'); + } + } + + if (productName) { + this.setData({ productName: productName }); + this.loadSpecifications(productName); + } else { + // 如果没有商品名称参数,跳转到商品列表页面 + wx.redirectTo({ + url: '/pages/evaluate2/product-list' + }); + } + }, + + loadSpecifications(productName) { + this.setData({ + loading: true, + specifications: [], + error: '' // 清空错误信息,确保加载时只显示加载状态 + }); + + // 尝试从本地存储获取商品规格映射数据 + const productSpecsMap = wx.getStorageSync('evaluate2ProductSpecsMap') || {}; + + if (productSpecsMap && productSpecsMap[productName]) { + console.log('从本地存储获取商品规格数据'); + + // 提取该商品的规格和价格信息 + const productSpecs = productSpecsMap[productName]; + + // 处理规格数据 + const specPriceMap = {}; + productSpecs.forEach(item => { + const specStr = item.specification; + const price = item.price; + + // 价格为空的不参与计算 + if (!price || price.trim() === '') { + return; + } + + if (specStr.length > 0) { + // 处理逗号分隔的多个规格 + let specs = specStr.split(',').map(spec => spec.trim()).filter(spec => spec.length > 0); + + // 进一步处理规格,确保每个规格都是独立的 + const processedSpecs = []; + specs.forEach(spec => { + if (spec.includes(',')) { + const subSpecs = spec.split(',').map(s => s.trim()).filter(s => s.length > 0); + processedSpecs.push(...subSpecs); + } else { + processedSpecs.push(spec); + } + }); + + specs = processedSpecs; + + // 处理逗号分隔的多个价格 + const prices = price.split(',').map(p => p.trim()).filter(p => p && p.trim() !== ''); + + // 价格为空的不参与计算 + if (prices.length === 0) { + return; + } + + // 将规格和价格配对 + specs.forEach((spec, index) => { + if (spec.length > 0) { + // 确保价格索引不超出范围 + const priceIndex = index % prices.length; + const matchedPrice = prices[priceIndex] || ''; + + // 只有当价格不为空时才添加该规格 + if (matchedPrice && matchedPrice.trim() !== '') { + // 收集相同规格的所有价格,以便计算平均值 + if (!specPriceMap[spec]) { + specPriceMap[spec] = []; + } + specPriceMap[spec].push(matchedPrice); + } + } + }); + } + }); + + // 转换为规格对象数组 + const specifications = Object.keys(specPriceMap).map(spec => { + const prices = specPriceMap[spec]; + + // 解析规格 + const specInfo = this.parseSpecification(spec); + + // 处理每个价格 + const processedPrices = prices.map(price => { + if (!price || price.trim() === '' || isNaN(parseFloat(price))) { + return 0; + } + + const priceValue = parseFloat(price); + + // 价格<10的需要按照公式计算 + if (priceValue < 10 && specInfo) { + if (specInfo.type === '净重') { + // 净重:规格平均值 × 价格 + return specInfo.avg * priceValue; + } else if (specInfo.type === '毛重') { + // 毛重:(规格平均值 - 5) × 价格 + return (specInfo.avg - 5) * priceValue; + } + } + // 价格>=10的直接使用 + return priceValue; + }).filter(price => price > 0); // 过滤掉0值 + + // 计算处理后价格的平均值 + let finalPrice = 0; + let finalPriceText = ''; + + if (processedPrices.length > 0) { + const sum = processedPrices.reduce((acc, price) => acc + price, 0); + finalPrice = sum / processedPrices.length; + finalPriceText = finalPrice.toFixed(2); + } + + const specObj = { + name: spec, + price: finalPriceText, + priceText: finalPriceText, + finalPrice: finalPrice, + finalPriceText: finalPriceText + }; + + return specObj; + }); + + // 对规格进行排序 + specifications.sort((a, b) => { + // 解析两个规格 + const specA = this.parseSpecification(a.name); + const specB = this.parseSpecification(b.name); + + // 如果有一个规格解析失败,保持原顺序 + if (!specA || !specB) { + return 0; + } + + // 1. 按类型排序:净重在前,毛重在后 + if (specA.type !== specB.type) { + return specA.type === '净重' ? -1 : 1; + } + + // 2. 按规格最小值排序:从小到大 + return specA.min - specB.min; + }); + + this.setData({ + specifications: specifications, + error: '', // 清除之前的错误 + loading: false + }); + + // 结束下拉刷新 + wx.stopPullDownRefresh(); + } else { + // 如果本地存储中没有数据,尝试从本地存储获取原始商品数据 + const allProducts = wx.getStorageSync('allProducts') || []; + + if (allProducts.length > 0) { + console.log('从本地存储获取原始商品数据'); + this.processSpecifications(productName, allProducts); + } else { + // 如果本地没有数据,再请求服务器 + console.log('本地存储中没有数据,请求服务器获取商品数据'); + const api = require('../../utils/api'); + api.getProducts(1, 1000, 'all', '').then(result => { + // 从返回对象中提取products数组 + const products = result.products || []; + this.processSpecifications(productName, products); + }).catch(err => { + console.error('获取规格失败:', err); + this.setData({ + error: '获取规格失败,请稍后重试', + loading: false + }); + + // 结束下拉刷新 + wx.stopPullDownRefresh(); + }); + } + } + }, + + // 解析规格,提取类型(净重/毛重)和数值范围 + parseSpecification(spec) { + const weightMatch = spec.match(/(净重|毛重)(\d+)-(\d+)/); + if (weightMatch) { + const type = weightMatch[1]; // 净重或毛重 + const min = parseFloat(weightMatch[2]); + const max = parseFloat(weightMatch[3]); + const avg = (min + max) / 2; + return { + type: type, + min: min, + max: max, + avg: avg + }; + } + return null; + }, + + processSpecifications(productName, products) { + console.log('处理的商品数据数量:', products.length); + console.log('当前处理的商品名称:', productName); + + // 检查products是否为空 + if (!products || products.length === 0) { + console.error('商品数据为空'); + this.setData({ + error: '商品数据为空', + loading: false + }); + return; + } + + // 过滤出当前商品名称的所有商品 + const filteredProducts = products.filter(product => { + const match = product.productName === productName; + console.log('商品:', product.productName, '规格:', product.specification, '价格:', product.price, '匹配:', match); + return match; + }); + + console.log('过滤后的商品数量:', filteredProducts.length); + console.log('过滤后的商品详情:', filteredProducts); + + // 检查filteredProducts是否为空 + if (filteredProducts.length === 0) { + console.error('未找到商品名称为"' + productName + '"的商品'); + this.setData({ + error: '未找到对应商品名称的商品', + loading: false + }); + return; + } + + // 提取规格和价格,处理可能的空值和空格 + const specPriceMap = {}; + filteredProducts.forEach((product, productIndex) => { + const specStr = (product.specification || product.spec || '').trim(); + const price = product.price || ''; + + console.log(`处理第${productIndex + 1}个商品: 规格字符串='${specStr}', 价格字符串='${price}'`); + + // 价格为空的不参与计算 + if (!price || price.trim() === '') { + console.log(`商品价格为空,跳过处理`); + return; + } + + if (specStr.length > 0) { + // 处理逗号分隔的多个规格,确保每个规格都被正确分割 + // 首先按逗号分割 + let specs = specStr.split(',').map(spec => spec.trim()).filter(spec => spec.length > 0); + + // 进一步处理规格,确保每个规格都是独立的 + const processedSpecs = []; + specs.forEach(spec => { + // 检查规格是否包含多个规格(例如:"净重29-30,净重31-32") + if (spec.includes(',')) { + // 按中文逗号分割 + const subSpecs = spec.split(',').map(s => s.trim()).filter(s => s.length > 0); + processedSpecs.push(...subSpecs); + } else { + processedSpecs.push(spec); + } + }); + + specs = processedSpecs; + + // 处理逗号分隔的多个价格 + const prices = (price || '').split(',').map(p => p.trim()).filter(p => p && p.trim() !== ''); + + console.log(`规格数组:`, specs); + console.log(`价格数组:`, prices); + + // 价格为空的不参与计算 + if (prices.length === 0) { + console.log(`价格数组为空,跳过处理`); + return; + } + + // 将规格和价格配对 + specs.forEach((spec, index) => { + if (spec.length > 0) { + // 确保价格索引不超出范围 + const priceIndex = index % prices.length; + const matchedPrice = prices[priceIndex] || ''; + console.log(`规格'${spec}' 配对价格: '${matchedPrice}'`); + + // 只有当价格不为空时才添加该规格 + if (matchedPrice && matchedPrice.trim() !== '') { + // 收集相同规格的所有价格,以便计算平均值 + if (!specPriceMap[spec]) { + specPriceMap[spec] = []; + } + specPriceMap[spec].push(matchedPrice); + } else { + console.log(`规格'${spec}' 价格为空,不添加`); + } + } + }); + } + }); + + // 转换为规格对象数组 + const specifications = Object.keys(specPriceMap).map(spec => { + const prices = specPriceMap[spec]; + console.log(`规格'${spec}' 的所有原始价格:`, prices); + + // 解析规格 + const specInfo = this.parseSpecification(spec); + + // 处理每个价格 + const processedPrices = prices.map(price => { + if (!price || price.trim() === '' || isNaN(parseFloat(price))) { + return 0; + } + + const priceValue = parseFloat(price); + console.log(`处理价格: ${priceValue}`); + + // 价格<10的需要按照公式计算 + if (priceValue < 10 && specInfo) { + console.log(`价格 ${priceValue} < 10,按照公式计算`); + if (specInfo.type === '净重') { + // 净重:规格平均值 × 价格 + return specInfo.avg * priceValue; + } else if (specInfo.type === '毛重') { + // 毛重:(规格平均值 - 5) × 价格 + return (specInfo.avg - 5) * priceValue; + } + } + // 价格>=10的直接使用 + return priceValue; + }).filter(price => price > 0); // 过滤掉0值 + + console.log(`规格'${spec}' 处理后的价格:`, processedPrices); + + // 计算处理后价格的平均值 + let finalPrice = 0; + let finalPriceText = ''; + + if (processedPrices.length > 0) { + const sum = processedPrices.reduce((acc, price) => acc + price, 0); + finalPrice = sum / processedPrices.length; + finalPriceText = finalPrice.toFixed(2); + console.log(`规格'${spec}' 处理后价格的平均值: ${finalPriceText} (基于 ${processedPrices.length} 个价格)`); + } else { + console.log(`规格'${spec}' 没有有效价格`); + } + + const specObj = { + name: spec, + price: finalPriceText, + priceText: finalPriceText, + finalPrice: finalPrice, + finalPriceText: finalPriceText + }; + + console.log('创建的规格对象:', specObj); + + return specObj; + }); + + console.log('提取的规格和价格:', specifications); + + // 对规格进行排序 + specifications.sort((a, b) => { + // 解析两个规格 + const specA = this.parseSpecification(a.name); + const specB = this.parseSpecification(b.name); + + // 如果有一个规格解析失败,保持原顺序 + if (!specA || !specB) { + return 0; + } + + // 1. 按类型排序:净重在前,毛重在后 + if (specA.type !== specB.type) { + return specA.type === '净重' ? -1 : 1; + } + + // 2. 按规格最小值排序:从小到大 + return specA.min - specB.min; + }); + + console.log('排序后的规格:', specifications); + + this.setData({ + specifications: specifications, + error: '', // 清除之前的错误 + loading: false + }); + + // 结束下拉刷新 + wx.stopPullDownRefresh(); + }, + + // 跳转到规格详情页面 + goToSpecDetail(e) { + const specItem = e.currentTarget.dataset.spec; + console.log('点击的规格项:', specItem); + console.log('传递的价格:', specItem.finalPriceText); + wx.navigateTo({ + url: `/pages/evaluate2/spec-detail?productName=${encodeURIComponent(this.data.productName)}&specification=${encodeURIComponent(specItem.name)}&price=${encodeURIComponent(specItem.finalPriceText)}` + }); + }, + + // 返回上一页 + goBack() { + wx.navigateBack(); + }, + + // 返回商品列表页面 + goBackToProductList() { + // 从本地存储中获取之前选择的分类 + const selectedCategory = wx.getStorageSync('selectedCategory') || ''; + console.log('返回商品列表页面,之前选择的分类:', selectedCategory); + + // 构建跳转URL,如果有分类参数就传递 + let url = '/pages/evaluate2/product-list'; + if (selectedCategory) { + url += '?category=' + encodeURIComponent(selectedCategory); + } + + wx.redirectTo({ + url: url + }); + }, + + // 下拉刷新 + onPullDownRefresh() { + console.log('开始下拉刷新'); + if (this.data.productName) { + this.loadSpecifications(this.data.productName); + } else { + wx.stopPullDownRefresh(); + } + } +}); \ No newline at end of file diff --git a/pages/evaluate2/index.json b/pages/evaluate2/index.json new file mode 100644 index 0000000..09e623a --- /dev/null +++ b/pages/evaluate2/index.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "enablePullDownRefresh": true, + "backgroundTextStyle": "dark" +} \ No newline at end of file diff --git a/pages/evaluate2/index.wxml b/pages/evaluate2/index.wxml new file mode 100644 index 0000000..0a664b1 --- /dev/null +++ b/pages/evaluate2/index.wxml @@ -0,0 +1,78 @@ + + + + + 规格选择 + + + + + + + + 正在加载规格数据... + + + + + ⚠️ + {{error}} + + + + + + + + + + + 商品名称 + + + {{productName}} + + + + + + + 可用规格 + {{specifications.length}}个 + + + + + {{item.name}} + + + 参考价格 + ¥{{item.finalPriceText}} + + + + + + + + 暂无更多规格选择 + + + + + + 📋 + 该商品暂无可用规格 + + + + \ No newline at end of file diff --git a/pages/evaluate2/index.wxss b/pages/evaluate2/index.wxss new file mode 100644 index 0000000..1e117b3 --- /dev/null +++ b/pages/evaluate2/index.wxss @@ -0,0 +1,450 @@ +.container { + display: flex; + flex-direction: column; + min-height: 100vh; + background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); + font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif; +} + +.header { + background: #fff; + box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.08); + position: sticky; + top: 0; + z-index: 10; +} + +.header-content { + padding: 30rpx 0; + text-align: center; +} + +.title { + font-size: 36rpx; + font-weight: 700; + color: #2c3e50; + letter-spacing: 2rpx; +} + +.content { + flex: 1; + padding: 16rpx; +} + +/* 加载状态 */ +.loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 160rpx 0; +} + +.loading-spinner { + width: 80rpx; + height: 80rpx; + border: 8rpx solid rgba(74, 144, 226, 0.2); + border-top: 8rpx solid #4a90e2; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-bottom: 32rpx; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.loading-text { + font-size: 28rpx; + color: #666; + font-weight: 500; +} + +/* 错误提示卡片 */ +.error-card { + background: #fff; + border-radius: 16rpx; + padding: 48rpx; + margin: 32rpx 0; + box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.08); + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} + +.error-icon { + font-size: 80rpx; + margin-bottom: 24rpx; +} + +.error-text { + font-size: 28rpx; + color: #e74c3c; + margin-bottom: 32rpx; + line-height: 1.5; +} + +/* 按钮样式 */ +.button-group { + display: flex; + gap: 16rpx; + width: 100%; + max-width: 600rpx; +} + +.btn-primary { + flex: 1; + height: 80rpx; + line-height: 80rpx; + font-size: 28rpx; + font-weight: 600; + border-radius: 40rpx; + background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%); + color: #fff; + border: none; + box-shadow: 0 4rpx 12rpx rgba(96, 165, 250, 0.4); + transition: all 0.3s ease; +} + +.btn-primary:hover { + transform: translateY(-2rpx); + box-shadow: 0 6rpx 16rpx rgba(74, 144, 226, 0.5); +} + +.btn-secondary { + flex: 1; + height: 80rpx; + line-height: 80rpx; + font-size: 28rpx; + font-weight: 600; + border-radius: 40rpx; + background: #fff; + color: #4a90e2; + border: 2rpx solid #4a90e2; + transition: all 0.3s ease; +} + +.btn-secondary:hover { + background: rgba(74, 144, 226, 0.05); + transform: translateY(-2rpx); +} + +.btn-back { + display: flex; + align-items: center; + justify-content: center; + padding: 8rpx 24rpx; + font-size: 24rpx; + color: #4a90e2; + background: transparent; + border: 1rpx solid #4a90e2; + border-radius: 20rpx; + transition: all 0.3s ease; + box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.05); +} + +.btn-back:hover { + background: rgba(74, 144, 226, 0.1); + transform: translateY(-2rpx); + box-shadow: 0 4rpx 12rpx rgba(74, 144, 226, 0.2); +} + +.btn-back-icon { + margin-right: 8rpx; + font-size: 20rpx; +} + +.btn-back-text { + font-size: 22rpx; +} + +/* 商品信息卡片 */ +.product-card { + background: rgba(255, 255, 255, 0.95); + border-radius: 20rpx; + padding: 32rpx; + margin-bottom: 24rpx; + box-shadow: 0 6rpx 20rpx rgba(0,0,0,0.08); + backdrop-filter: blur(8rpx); + border: 1rpx solid rgba(255, 255, 255, 0.3); +} + +.product-info-container { + width: 100%; + box-sizing: border-box; +} + +.product-info-row { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 16rpx; + width: 100%; + box-sizing: border-box; +} + +.product-label { + font-size: 24rpx; + color: #666; + font-weight: 500; + flex: 1; +} + +.product-name { + font-size: 32rpx; + font-weight: 700; + color: #2c3e50; + line-height: 1.4; + word-break: break-word; + margin-top: 12rpx; + padding: 12rpx 0; + border-top: 1rpx solid #f1f5f9; +} + +/* 规格列表区域 */ +.spec-section { + margin-top: 24rpx; +} + +.section-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 24rpx; + padding: 0 8rpx; +} + +.section-title { + font-size: 30rpx; + font-weight: 700; + color: #2c3e50; + padding-left: 16rpx; + border-left: 6rpx solid #4a90e2; +} + +.section-count { + font-size: 24rpx; + color: #999; + background: rgba(74, 144, 226, 0.1); + padding: 6rpx 16rpx; + border-radius: 20rpx; +} + +/* 规格网格布局 */ +.spec-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20rpx; + margin-top: 16rpx; +} + +/* 规格卡片 */ +.spec-card { + background: rgba(255, 255, 255, 0.95); + border-radius: 20rpx; + padding: 32rpx 24rpx; + box-shadow: 0 6rpx 20rpx rgba(0,0,0,0.08); + transition: all 0.3s ease; + cursor: pointer; + position: relative; + overflow: hidden; + backdrop-filter: blur(8rpx); + border: 1rpx solid rgba(255, 255, 255, 0.3); + min-height: 200rpx; + display: flex; + flex-direction: column; +} + +.spec-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 6rpx; + height: 100%; + background: linear-gradient(180deg, #60a5fa 0%, #3b82f6 100%); +} + +.spec-card:hover { + transform: translateY(-6rpx); + box-shadow: 0 12rpx 32rpx rgba(0,0,0,0.15); + background: rgba(255, 255, 255, 1); +} + +.spec-card:active { + transform: translateY(-2rpx); + box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.12); +} + +.spec-info { + margin-bottom: 20rpx; + flex: 1; + display: flex; + align-items: center; +} + +.spec-name { + font-size: 28rpx; + font-weight: 600; + color: #2c3e50; + line-height: 1.4; + word-break: break-word; + padding-right: 40rpx; +} + +.spec-price { + display: flex; + flex-direction: column; + margin-top: 16rpx; +} + +.price-label { + font-size: 20rpx; + color: #999; + margin-bottom: 4rpx; +} + +.price-value { + font-size: 36rpx; + font-weight: 700; + color: #e74c3c; + transition: all 0.3s ease; +} + +.spec-card:hover .price-value { + transform: scale(1.05); +} + +.spec-arrow { + position: absolute; + top: 32rpx; + right: 28rpx; + font-size: 32rpx; + color: #4a90e2; + font-weight: bold; + opacity: 0.6; + transition: all 0.3s ease; +} + +.spec-card:hover .spec-arrow { + opacity: 1; + transform: translateX(4rpx); +} + +/* 空状态 */ +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 160rpx 0; + text-align: center; +} + +.empty-icon { + font-size: 160rpx; + margin-bottom: 40rpx; + opacity: 0.6; +} + +.empty-text { + font-size: 32rpx; + color: #666; + margin-bottom: 48rpx; + line-height: 1.4; + padding: 0 40rpx; +} + +/* 响应式设计 */ +@media (max-width: 750rpx) { + .content { + padding: 20rpx; + } + + .spec-grid { + grid-template-columns: repeat(3, 1fr); + gap: 16rpx; + } + + .product-card { + padding: 28rpx; + } + + .spec-card { + padding: 28rpx 20rpx; + min-height: 180rpx; + } + + .title { + font-size: 32rpx; + } + + .section-title { + font-size: 28rpx; + } + + .product-name { + font-size: 28rpx; + } + + .price-value { + font-size: 32rpx; + } + + .button-group { + flex-direction: column; + gap: 12rpx; + } + + .btn-primary, + .btn-secondary { + width: 100%; + } +} + +/* 小屏幕设备适配 */ +@media (max-width: 414rpx) { + .spec-grid { + grid-template-columns: repeat(3, 1fr); + gap: 12rpx; + } + + .spec-card { + padding: 24rpx 16rpx; + min-height: 160rpx; + } + + .spec-name { + font-size: 24rpx; + } + + .price-value { + font-size: 28rpx; + } +} + +/* 暂无更多规格提示 */ +.no-more { + display: flex; + justify-content: center; + align-items: center; + padding: 48rpx 0; + margin-top: 16rpx; + margin-bottom: 100rpx; /* 添加底部边距,避免被导航栏遮挡 */ +} + +.no-more-text { + font-size: 24rpx; + color: #999; + background: rgba(0, 0, 0, 0.03); + padding: 12rpx 32rpx; + border-radius: 30rpx; + font-weight: 500; +} + +/* 调整规格网格布局,确保不被导航栏遮挡 */ +.spec-section { + margin-bottom: 40rpx; +} diff --git a/pages/evaluate2/one.js b/pages/evaluate2/one.js new file mode 100644 index 0000000..47fceb9 --- /dev/null +++ b/pages/evaluate2/one.js @@ -0,0 +1,463 @@ +Page({ + data: { + productName: '', + specifications: [], + loading: false, + error: '', + categories: [], + selectedCategory: '' + }, + onLoad(options) { + let productName = ''; + // 首先检查URL参数 + if (options.productName) { + productName = options.productName; + } else { + // 然后检查本地存储(用于wx.switchTab导航) + productName = wx.getStorageSync('selectedProductName') || ''; + // 清除本地存储中的商品名称,避免影响下次进入 + if (productName) { + wx.removeStorageSync('selectedProductName'); + } + } + + if (productName) { + this.setData({ productName: productName }); + this.loadSpecifications(productName); + } else { + // 如果没有商品名称参数,加载所有商品数据并计算 + this.loadAllData(); + } + }, + + // 下拉刷新 + onPullDownRefresh() { + console.log('开始下拉刷新'); + this.loadAllData(); + }, + + // 加载所有商品数据并计算 + loadAllData() { + this.setData({ + loading: true, + categories: [] // 清空分类数据,确保加载时只显示加载状态 + }); + + const api = require('../../utils/api'); + // 使用正确的参数调用getProducts方法 + api.getProducts(1, 1000, 'all', '').then(result => { + console.log('API返回结果:', result); + // 从返回对象中提取products数组,如果不存在则使用空数组 + const products = result.products || []; + console.log('提取的products数组:', products); + console.log('products数组长度:', products.length); + + // 存储原始商品数据到本地存储 + wx.setStorageSync('allProducts', products); + + // 过滤出有有效category字段的商品(忽略空字符串和仅包含空格的分类) + const productsWithCategory = products.filter(product => { + if (!product.category) return false; + const categoryStr = String(product.category).trim(); + return categoryStr !== ''; + }); + console.log('有有效category的商品:', productsWithCategory); + console.log('有有效category的商品数量:', productsWithCategory.length); + + // 提取所有分类(去除前后空格) + const categories = [...new Set(productsWithCategory.map(product => { + return String(product.category).trim(); + }))]; + console.log('提取的分类数组:', categories); + console.log('分类数量:', categories.length); + + // 存储分类数据到本地存储 + wx.setStorageSync('evaluate2Categories', categories); + + // 计算每个分类下的商品名称列表 + const categoryProductsMap = {}; + categories.forEach(category => { + // 过滤出该分类下的商品 + const categoryProducts = productsWithCategory.filter(product => { + const productCategory = String(product.category).trim(); + return productCategory === category; + }); + + // 提取商品名称(去除前后空格,去重) + const productNames = [...new Set(categoryProducts.map(product => { + // 尝试从多个字段获取商品名称 + const nameFields = [product.productName, product.name, product.product]; + for (const field of nameFields) { + if (field) { + const trimmedName = String(field).trim(); + if (trimmedName !== '') { + return trimmedName; + } + } + } + return ''; + }).filter(name => name !== ''))]; + + categoryProductsMap[category] = productNames; + }); + + // 存储分类商品映射到本地存储 + wx.setStorageSync('evaluate2CategoryProductsMap', categoryProductsMap); + + // 计算每个商品的规格和价格信息 + const productSpecsMap = {}; + products.forEach(product => { + // 尝试从多个字段获取商品名称 + const nameFields = [product.productName, product.name, product.product]; + let productName = ''; + for (const field of nameFields) { + if (field) { + const trimmedName = String(field).trim(); + if (trimmedName !== '') { + productName = trimmedName; + break; + } + } + } + + if (productName) { + if (!productSpecsMap[productName]) { + productSpecsMap[productName] = []; + } + + // 提取规格和价格 + const specStr = (product.specification || product.spec || '').trim(); + const price = product.price || ''; + + if (specStr && price) { + productSpecsMap[productName].push({ + specification: specStr, + price: price + }); + } + } + }); + + // 存储商品规格映射到本地存储 + wx.setStorageSync('evaluate2ProductSpecsMap', productSpecsMap); + + // 加载分类数据到页面 + this.setData({ + categories: categories, + loading: false + }); + + // 结束下拉刷新 + wx.stopPullDownRefresh(); + }).catch(err => { + console.error('获取商品数据失败:', err); + this.setData({ + error: '获取商品数据失败,请稍后重试', + loading: false + }); + + // 结束下拉刷新 + wx.stopPullDownRefresh(); + }); + }, + + // 加载商品分类数据 + loadCategories() { + this.setData({ loading: true }); + + // 尝试从本地存储中获取分类数据 + const categories = wx.getStorageSync('evaluate2Categories') || []; + + if (categories.length > 0) { + // 如果本地存储中有分类数据,直接使用 + console.log('从本地存储获取分类数据:', categories); + this.setData({ + categories: categories, + loading: false + }); + } else { + // 如果本地存储中没有分类数据,重新加载所有数据 + this.loadAllData(); + } + }, + + loadSpecifications(productName) { + if (!productName) { + this.setData({ + error: '请先选择商品', + loading: false + }); + return; + } + + this.setData({ loading: true, specifications: [] }); + + // 直接从本地存储获取商品数据,避免重复请求 + const localGoods = wx.getStorageSync('goods') || []; + console.log('从本地存储获取的商品数量:', localGoods.length); + + if (localGoods.length > 0) { + this.processSpecifications(productName, localGoods); + } else { + // 如果本地没有数据,再请求服务器 + const api = require('../../utils/api'); + // 使用正确的参数调用getProducts方法 + api.getProducts(1, 1000, 'all', '').then(result => { + // 从返回对象中提取products数组 + const products = result.products || []; + this.processSpecifications(productName, products); + }).catch(err => { + console.error('获取规格失败:', err); + this.setData({ + error: '获取规格失败,请稍后重试', + loading: false + }); + }); + } + }, + + // 解析规格,提取类型(净重/毛重)和数值范围 + parseSpecification(spec) { + const weightMatch = spec.match(/(净重|毛重)(\d+)-(\d+)/); + if (weightMatch) { + const type = weightMatch[1]; // 净重或毛重 + const min = parseFloat(weightMatch[2]); + const max = parseFloat(weightMatch[3]); + const avg = (min + max) / 2; + return { + type: type, + min: min, + max: max, + avg: avg + }; + } + return null; + }, + + processSpecifications(productName, products) { + console.log('处理的商品数据数量:', products.length); + console.log('当前处理的商品名称:', productName); + + // 检查products是否为空 + if (!products || products.length === 0) { + console.error('商品数据为空'); + this.setData({ + error: '商品数据为空', + loading: false + }); + return; + } + + // 过滤出当前商品名称的所有商品 + const filteredProducts = products.filter(product => { + const match = product.productName === productName; + console.log('商品:', product.productName, '规格:', product.specification, '价格:', product.price, '匹配:', match); + return match; + }); + + console.log('过滤后的商品数量:', filteredProducts.length); + console.log('过滤后的商品详情:', filteredProducts); + + // 检查filteredProducts是否为空 + if (filteredProducts.length === 0) { + console.error('未找到商品名称为"' + productName + '"的商品'); + this.setData({ + error: '未找到对应商品名称的商品', + loading: false + }); + return; + } + + // 提取规格和价格,处理可能的空值和空格 + const specPriceMap = {}; + filteredProducts.forEach((product, productIndex) => { + const specStr = (product.specification || product.spec || '').trim(); + const price = product.price || ''; + + console.log(`处理第${productIndex + 1}个商品: 规格字符串='${specStr}', 价格字符串='${price}'`); + + // 价格为空的不参与计算 + if (!price || price.trim() === '') { + console.log(`商品价格为空,跳过处理`); + return; + } + + if (specStr.length > 0) { + // 处理逗号分隔的多个规格,确保每个规格都被正确分割 + // 首先按逗号分割 + let specs = specStr.split(',').map(spec => spec.trim()).filter(spec => spec.length > 0); + + // 进一步处理规格,确保每个规格都是独立的 + const processedSpecs = []; + specs.forEach(spec => { + // 检查规格是否包含多个规格(例如:"净重29-30,净重31-32") + if (spec.includes(',')) { + // 按中文逗号分割 + const subSpecs = spec.split(',').map(s => s.trim()).filter(s => s.length > 0); + processedSpecs.push(...subSpecs); + } else { + processedSpecs.push(spec); + } + }); + + specs = processedSpecs; + + // 处理逗号分隔的多个价格 + const prices = (price || '').split(',').map(p => p.trim()).filter(p => p && p.trim() !== ''); + + console.log(`规格数组:`, specs); + console.log(`价格数组:`, prices); + + // 价格为空的不参与计算 + if (prices.length === 0) { + console.log(`价格数组为空,跳过处理`); + return; + } + + // 将规格和价格配对 + specs.forEach((spec, index) => { + if (spec.length > 0) { + // 确保价格索引不超出范围 + const priceIndex = index % prices.length; + const matchedPrice = prices[priceIndex] || ''; + console.log(`规格'${spec}' 配对价格: '${matchedPrice}'`); + + // 只有当价格不为空时才添加该规格 + if (matchedPrice && matchedPrice.trim() !== '') { + // 收集相同规格的所有价格,以便计算平均值 + if (!specPriceMap[spec]) { + specPriceMap[spec] = []; + } + specPriceMap[spec].push(matchedPrice); + } else { + console.log(`规格'${spec}' 价格为空,不添加`); + } + } + }); + } + }); + + // 转换为规格对象数组 + const specifications = Object.keys(specPriceMap).map(spec => { + const prices = specPriceMap[spec]; + console.log(`规格'${spec}' 的所有原始价格:`, prices); + + // 解析规格 + const specInfo = this.parseSpecification(spec); + + // 处理每个价格 + const processedPrices = prices.map(price => { + if (!price || price.trim() === '' || isNaN(parseFloat(price))) { + return 0; + } + + const priceValue = parseFloat(price); + console.log(`处理价格: ${priceValue}`); + + // 价格<10的需要按照公式计算 + if (priceValue < 10 && specInfo) { + console.log(`价格 ${priceValue} < 10,按照公式计算`); + if (specInfo.type === '净重') { + // 净重:规格平均值 × 价格 + return specInfo.avg * priceValue; + } else if (specInfo.type === '毛重') { + // 毛重:(规格平均值 - 5) × 价格 + return (specInfo.avg - 5) * priceValue; + } + } + // 价格>=10的直接使用 + return priceValue; + }).filter(price => price > 0); // 过滤掉0值 + + console.log(`规格'${spec}' 处理后的价格:`, processedPrices); + + // 计算处理后价格的平均值 + let finalPrice = 0; + let finalPriceText = ''; + + if (processedPrices.length > 0) { + const sum = processedPrices.reduce((acc, price) => acc + price, 0); + finalPrice = sum / processedPrices.length; + finalPriceText = finalPrice.toFixed(2); + console.log(`规格'${spec}' 处理后价格的平均值: ${finalPriceText} (基于 ${processedPrices.length} 个价格)`); + } else { + console.log(`规格'${spec}' 没有有效价格`); + } + + const specObj = { + name: spec, + price: finalPriceText, + priceText: finalPriceText, + finalPrice: finalPrice, + finalPriceText: finalPriceText + }; + + console.log('创建的规格对象:', specObj); + + return specObj; + }); + + console.log('提取的规格和价格:', specifications); + + // 对规格进行排序 + specifications.sort((a, b) => { + // 解析两个规格 + const specA = this.parseSpecification(a.name); + const specB = this.parseSpecification(b.name); + + // 如果有一个规格解析失败,保持原顺序 + if (!specA || !specB) { + return 0; + } + + // 1. 按类型排序:净重在前,毛重在后 + if (specA.type !== specB.type) { + return specA.type === '净重' ? -1 : 1; + } + + // 2. 按规格最小值排序:从小到大 + return specA.min - specB.min; + }); + + console.log('排序后的规格:', specifications); + + this.setData({ + specifications: specifications, + error: '', // 清除之前的错误 + loading: false + }); + }, + + // 跳转到规格详情页面 + goToSpecDetail(e) { + const specItem = e.currentTarget.dataset.spec; + console.log('点击的规格项:', specItem); + console.log('传递的价格:', specItem.finalPriceText); + wx.navigateTo({ + url: `/pages/evaluate1/spec-detail?productName=${encodeURIComponent(this.data.productName)}&specification=${encodeURIComponent(specItem.name)}&price=${encodeURIComponent(specItem.finalPriceText)}` + }); + }, + + // 返回上一页 + goBack() { + wx.navigateBack(); + }, + + // 返回商品列表页面 + goBackToProductList() { + wx.redirectTo({ + url: '/pages/evaluate1/product-list' + }); + }, + + // 选择分类,跳转到商品列表页面 + selectCategory(e) { + const category = e.currentTarget.dataset.category; + console.log('选择分类:', category); + + // 跳转到商品列表页面,并传递分类参数 + wx.redirectTo({ + url: `/pages/evaluate2/product-list?category=${encodeURIComponent(category)}` + }); + } +}); \ No newline at end of file diff --git a/pages/evaluate2/one.json b/pages/evaluate2/one.json new file mode 100644 index 0000000..09e623a --- /dev/null +++ b/pages/evaluate2/one.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "enablePullDownRefresh": true, + "backgroundTextStyle": "dark" +} \ No newline at end of file diff --git a/pages/evaluate2/one.wxml b/pages/evaluate2/one.wxml new file mode 100644 index 0000000..f76f3ac --- /dev/null +++ b/pages/evaluate2/one.wxml @@ -0,0 +1,100 @@ + + + + + 分类选择 + + + + + + + + 正在加载数据... + + + + + ⚠️ + {{error}} + + + + + + + + + + 商品分类 + {{categories.length}}个 + + + + + {{item}} + + + + + + + + + + + 商品名称 + + + {{productName}} + + + + + + + 可用规格 + {{specifications.length}}个 + + + + + {{item.name}} + + + 参考价格 + ¥{{item.finalPriceText}} + + + + + + + + 暂无更多规格选择 + + + + + + 📋 + 该商品暂无可用规格 + + + + \ No newline at end of file diff --git a/pages/evaluate2/one.wxss b/pages/evaluate2/one.wxss new file mode 100644 index 0000000..67a8107 --- /dev/null +++ b/pages/evaluate2/one.wxss @@ -0,0 +1,560 @@ +.container { + display: flex; + flex-direction: column; + min-height: 100vh; + background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); + font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif; +} + +.header { + background: #fff; + box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.08); + position: sticky; + top: 0; + z-index: 10; +} + +.header-content { + padding: 30rpx 0; + text-align: center; +} + +.title { + font-size: 36rpx; + font-weight: 700; + color: #2c3e50; + letter-spacing: 2rpx; +} + +.content { + flex: 1; + padding: 16rpx; +} + +/* 加载状态 */ +.loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 160rpx 0; +} + +.loading-spinner { + width: 80rpx; + height: 80rpx; + border: 8rpx solid rgba(74, 144, 226, 0.2); + border-top: 8rpx solid #4a90e2; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-bottom: 32rpx; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.loading-text { + font-size: 28rpx; + color: #666; + font-weight: 500; +} + +/* 错误提示卡片 */ +.error-card { + background: #fff; + border-radius: 16rpx; + padding: 48rpx; + margin: 32rpx 0; + box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.08); + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} + +.error-icon { + font-size: 80rpx; + margin-bottom: 24rpx; +} + +.error-text { + font-size: 28rpx; + color: #e74c3c; + margin-bottom: 32rpx; + line-height: 1.5; +} + +/* 按钮样式 */ +.button-group { + display: flex; + gap: 16rpx; + width: 100%; + max-width: 600rpx; +} + +.btn-primary { + flex: 1; + height: 80rpx; + line-height: 80rpx; + font-size: 28rpx; + font-weight: 600; + border-radius: 40rpx; + background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%); + color: #fff; + border: none; + box-shadow: 0 4rpx 12rpx rgba(96, 165, 250, 0.4); + transition: all 0.3s ease; +} + +.btn-primary:hover { + transform: translateY(-2rpx); + box-shadow: 0 6rpx 16rpx rgba(74, 144, 226, 0.5); +} + +.btn-secondary { + flex: 1; + height: 80rpx; + line-height: 80rpx; + font-size: 28rpx; + font-weight: 600; + border-radius: 40rpx; + background: #fff; + color: #4a90e2; + border: 2rpx solid #4a90e2; + transition: all 0.3s ease; +} + +.btn-secondary:hover { + background: rgba(74, 144, 226, 0.05); + transform: translateY(-2rpx); +} + +.btn-back { + display: flex; + align-items: center; + justify-content: center; + padding: 8rpx 24rpx; + font-size: 24rpx; + color: #4a90e2; + background: transparent; + border: 1rpx solid #4a90e2; + border-radius: 20rpx; + transition: all 0.3s ease; + box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.05); +} + +.btn-back:hover { + background: rgba(74, 144, 226, 0.1); + transform: translateY(-2rpx); + box-shadow: 0 4rpx 12rpx rgba(74, 144, 226, 0.2); +} + +.btn-back-icon { + margin-right: 8rpx; + font-size: 20rpx; +} + +.btn-back-text { + font-size: 22rpx; +} + +/* 商品信息卡片 */ +.product-card { + background: rgba(255, 255, 255, 0.95); + border-radius: 20rpx; + padding: 32rpx; + margin-bottom: 24rpx; + box-shadow: 0 6rpx 20rpx rgba(0,0,0,0.08); + backdrop-filter: blur(8rpx); + border: 1rpx solid rgba(255, 255, 255, 0.3); +} + +.product-info-container { + width: 100%; + box-sizing: border-box; +} + +.product-info-row { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 16rpx; + width: 100%; + box-sizing: border-box; +} + +.product-label { + font-size: 24rpx; + color: #666; + font-weight: 500; + flex: 1; +} + +.product-name { + font-size: 32rpx; + font-weight: 700; + color: #2c3e50; + line-height: 1.4; + word-break: break-word; + margin-top: 12rpx; + padding: 12rpx 0; + border-top: 1rpx solid #f1f5f9; +} + +/* 规格列表区域 */ +.spec-section { + margin-top: 24rpx; +} + +.section-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 24rpx; + padding: 0 8rpx; +} + +.section-title { + font-size: 30rpx; + font-weight: 700; + color: #2c3e50; + padding-left: 16rpx; + border-left: 6rpx solid #4a90e2; +} + +.section-count { + font-size: 24rpx; + color: #999; + background: rgba(74, 144, 226, 0.1); + padding: 6rpx 16rpx; + border-radius: 20rpx; +} + +/* 规格网格布局 */ +.spec-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20rpx; + margin-top: 16rpx; +} + +/* 规格卡片 */ +.spec-card { + background: rgba(255, 255, 255, 0.95); + border-radius: 20rpx; + padding: 32rpx 24rpx; + box-shadow: 0 6rpx 20rpx rgba(0,0,0,0.08); + transition: all 0.3s ease; + cursor: pointer; + position: relative; + overflow: hidden; + backdrop-filter: blur(8rpx); + border: 1rpx solid rgba(255, 255, 255, 0.3); + min-height: 200rpx; + display: flex; + flex-direction: column; +} + +.spec-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 6rpx; + height: 100%; + background: linear-gradient(180deg, #60a5fa 0%, #3b82f6 100%); +} + +.spec-card:hover { + transform: translateY(-6rpx); + box-shadow: 0 12rpx 32rpx rgba(0,0,0,0.15); + background: rgba(255, 255, 255, 1); +} + +.spec-card:active { + transform: translateY(-2rpx); + box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.12); +} + +.spec-info { + margin-bottom: 20rpx; + flex: 1; + display: flex; + align-items: center; +} + +.spec-name { + font-size: 28rpx; + font-weight: 600; + color: #2c3e50; + line-height: 1.4; + word-break: break-word; + padding-right: 40rpx; +} + +.spec-price { + display: flex; + flex-direction: column; + margin-top: 16rpx; +} + +.price-label { + font-size: 20rpx; + color: #999; + margin-bottom: 4rpx; +} + +.price-value { + font-size: 36rpx; + font-weight: 700; + color: #e74c3c; + transition: all 0.3s ease; +} + +.spec-card:hover .price-value { + transform: scale(1.05); +} + +.spec-arrow { + position: absolute; + top: 32rpx; + right: 28rpx; + font-size: 32rpx; + color: #4a90e2; + font-weight: bold; + opacity: 0.6; + transition: all 0.3s ease; +} + +.spec-card:hover .spec-arrow { + opacity: 1; + transform: translateX(4rpx); +} + +/* 空状态 */ +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 160rpx 0; + text-align: center; +} + +.empty-icon { + font-size: 160rpx; + margin-bottom: 40rpx; + opacity: 0.6; +} + +.empty-text { + font-size: 32rpx; + color: #666; + margin-bottom: 48rpx; + line-height: 1.4; + padding: 0 40rpx; +} + +/* 响应式设计 */ +@media (max-width: 750rpx) { + .content { + padding: 20rpx; + } + + .spec-grid { + grid-template-columns: repeat(3, 1fr); + gap: 16rpx; + } + + .product-card { + padding: 28rpx; + } + + .spec-card { + padding: 28rpx 20rpx; + min-height: 180rpx; + } + + .title { + font-size: 32rpx; + } + + .section-title { + font-size: 28rpx; + } + + .product-name { + font-size: 28rpx; + } + + .price-value { + font-size: 32rpx; + } + + .button-group { + flex-direction: column; + gap: 12rpx; + } + + .btn-primary, + .btn-secondary { + width: 100%; + } +} + +/* 小屏幕设备适配 */ +@media (max-width: 414rpx) { + .spec-grid { + grid-template-columns: repeat(3, 1fr); + gap: 12rpx; + } + + .spec-card { + padding: 24rpx 16rpx; + min-height: 160rpx; + } + + .spec-name { + font-size: 24rpx; + } + + .price-value { + font-size: 28rpx; + } +} + +/* 暂无更多规格提示 */ +.no-more { + display: flex; + justify-content: center; + align-items: center; + padding: 48rpx 0; + margin-top: 16rpx; + margin-bottom: 100rpx; /* 添加底部边距,避免被导航栏遮挡 */ +} + +.no-more-text { + font-size: 24rpx; + color: #999; + background: rgba(0, 0, 0, 0.03); + padding: 12rpx 32rpx; + border-radius: 30rpx; + font-weight: 500; +} + +/* 分类选择区域 */ +.category-section { + margin-top: 24rpx; + margin-bottom: 40rpx; +} + +.category-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 20rpx; + margin-top: 16rpx; +} + +.category-card { + background: rgba(255, 255, 255, 0.95); + border-radius: 20rpx; + padding: 32rpx 24rpx; + box-shadow: 0 6rpx 20rpx rgba(0,0,0,0.08); + transition: all 0.3s ease; + cursor: pointer; + position: relative; + overflow: hidden; + backdrop-filter: blur(8rpx); + border: 1rpx solid rgba(255, 255, 255, 0.3); + min-height: 150rpx; + display: flex; + align-items: center; + justify-content: space-between; +} + +.category-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 6rpx; + height: 100%; + background: linear-gradient(180deg, #60a5fa 0%, #3b82f6 100%); +} + +.category-card:hover { + transform: translateY(-6rpx); + box-shadow: 0 12rpx 32rpx rgba(0,0,0,0.15); + background: rgba(255, 255, 255, 1); +} + +.category-card:active { + transform: translateY(-2rpx); + box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.12); +} + +.category-info { + flex: 1; + margin-right: 20rpx; +} + +.category-name { + font-size: 32rpx; + font-weight: 600; + color: #2c3e50; + line-height: 1.4; + word-break: break-word; +} + +.category-arrow { + font-size: 32rpx; + color: #4a90e2; + font-weight: bold; + opacity: 0.6; + transition: all 0.3s ease; +} + +.category-card:hover .category-arrow { + opacity: 1; + transform: translateX(4rpx); +} + +/* 响应式设计 - 分类区域 */ +@media (max-width: 750rpx) { + .category-grid { + grid-template-columns: repeat(2, 1fr); + gap: 16rpx; + } + + .category-card { + padding: 28rpx 20rpx; + min-height: 130rpx; + } + + .category-name { + font-size: 28rpx; + } +} + +@media (max-width: 414rpx) { + .category-grid { + grid-template-columns: 1fr; + gap: 12rpx; + } + + .category-card { + padding: 24rpx 16rpx; + min-height: 110rpx; + } + + .category-name { + font-size: 24rpx; + } +} + +/* 调整规格网格布局,确保不被导航栏遮挡 */ +.spec-section { + margin-bottom: 40rpx; +} \ No newline at end of file diff --git a/pages/evaluate2/product-list.js b/pages/evaluate2/product-list.js new file mode 100644 index 0000000..f28c65c --- /dev/null +++ b/pages/evaluate2/product-list.js @@ -0,0 +1,486 @@ +Page({ + data: { + productNames: [], + loading: false, + error: '', + category: '', + priceRange: { // 价格范围 + min: 0, + max: 0, + hasPrice: false + } + }, + + // 解析规格,提取类型(净重/毛重)和数值范围 + parseSpecification(spec) { + const weightMatch = spec.match(/(净重|毛重)(\d+)-(\d+)/); + if (weightMatch) { + const type = weightMatch[1]; // 净重或毛重 + const min = parseFloat(weightMatch[2]); + const max = parseFloat(weightMatch[3]); + const avg = (min + max) / 2; + return { + type: type, + min: min, + max: max, + avg: avg + }; + } + return null; + }, + onLoad(options) { + // 对分类参数进行 URL 解码 + const category = options.category ? decodeURIComponent(options.category) : ''; + this.setData({ category: category }); + console.log('解码后的分类:', category); + this.loadProductNames(); + }, + + loadProductNames() { + this.setData({ + loading: true, + error: '', + productNames: [] // 清空商品名称数据,确保加载时只显示加载状态 + }); + + console.log('开始加载商品列表,当前分类:', this.data.category); + + // 尝试从本地存储中获取分类商品映射数据 + const categoryProductsMap = wx.getStorageSync('evaluate2CategoryProductsMap') || {}; + + if (categoryProductsMap && Object.keys(categoryProductsMap).length > 0) { + console.log('从本地存储获取分类商品映射数据'); + + // 获取当前分类下的商品名称列表 + let productNames = []; + if (this.data.category) { + productNames = categoryProductsMap[this.data.category] || []; + console.log(`分类"${this.data.category}"下的商品数量:`, productNames.length); + console.log('商品名称列表:', productNames); + } else { + // 如果没有分类参数,获取所有商品名称 + const allProductNames = []; + Object.values(categoryProductsMap).forEach(names => { + allProductNames.push(...names); + }); + // 去重 + productNames = [...new Set(allProductNames)]; + console.log('所有商品数量:', productNames.length); + } + + // 计算价格范围 + let priceRange = { min: 0, max: 0, hasPrice: false }; + + // 从原始商品数据中计算价格范围 + const allProducts = wx.getStorageSync('allProducts') || []; + if (allProducts.length > 0) { + // 过滤出当前分类下的商品 + const categoryProducts = allProducts.filter(product => { + if (!product.category) return false; + const productCategory = String(product.category).trim(); + return productCategory === this.data.category; + }); + + // 按规格分组计算平均价格 + const specPriceMap = {}; + categoryProducts.forEach(product => { + if (product.price && (product.specification || product.spec)) { + const priceStr = String(product.price).trim(); + const specStr = String(product.specification || product.spec).trim(); + + // 处理逗号分隔的多个价格 + const priceArray = priceStr.split(',').map(p => p.trim()).filter(p => p && p.trim() !== ''); + + // 处理逗号分隔的多个规格 + let specs = specStr.split(',').map(spec => spec.trim()).filter(spec => spec.length > 0); + + // 进一步处理规格,确保每个规格都是独立的 + const processedSpecs = []; + specs.forEach(spec => { + if (spec.includes(',')) { + // 按中文逗号分割 + const subSpecs = spec.split(',').map(s => s.trim()).filter(s => s.length > 0); + processedSpecs.push(...subSpecs); + } else { + processedSpecs.push(spec); + } + }); + specs = processedSpecs; + + // 将规格和价格配对 + specs.forEach((spec, index) => { + if (spec.length > 0 && index < priceArray.length) { + const price = priceArray[index]; + if (price && price.trim() !== '') { + const priceValue = parseFloat(price); + if (!isNaN(priceValue)) { + // 解析规格 + const specInfo = this.parseSpecification(spec); + + // 价格<10的需要按照公式计算 + let finalPrice = priceValue; + if (priceValue < 10 && specInfo) { + if (specInfo.type === '净重') { + // 净重:规格平均值 × 价格 + finalPrice = specInfo.avg * priceValue; + } else if (specInfo.type === '毛重') { + // 毛重:(规格平均值 - 5) × 价格 + finalPrice = (specInfo.avg - 5) * priceValue; + } + } + + // 按规格分组存储价格 + if (!specPriceMap[spec]) { + specPriceMap[spec] = []; + } + specPriceMap[spec].push(finalPrice); + } + } + } + }); + } + }); + + // 计算每个规格的平均价格,然后找出最低和最高 + const specAvgPrices = []; + Object.keys(specPriceMap).forEach(spec => { + const prices = specPriceMap[spec]; + if (prices.length > 0) { + const avgPrice = prices.reduce((sum, price) => sum + price, 0) / prices.length; + specAvgPrices.push(avgPrice); + } + }); + + if (specAvgPrices.length > 0) { + priceRange.min = Math.round(Math.min(...specAvgPrices) * 100) / 100; + priceRange.max = Math.round(Math.max(...specAvgPrices) * 100) / 100; + priceRange.hasPrice = true; + } + } + + this.setData({ + productNames: productNames, + priceRange: priceRange, + loading: false + }); + + // 结束下拉刷新 + wx.stopPullDownRefresh(); + } else { + // 如果本地存储中没有数据,尝试从本地存储获取原始商品数据 + const allProducts = wx.getStorageSync('allProducts') || []; + + if (allProducts.length > 0) { + console.log('从本地存储获取原始商品数据'); + + // 过滤出有有效category字段的商品 + const productsWithCategory = allProducts.filter(product => { + if (!product.category) return false; + const categoryStr = String(product.category).trim(); + return categoryStr !== ''; + }); + + // 移除价格过滤,获取所有商品 + let filteredProducts = productsWithCategory; + + // 如果有分类参数,过滤出该分类下的商品 + if (this.data.category) { + console.log('当前分类:', this.data.category); + const targetCategory = String(this.data.category).trim(); + filteredProducts = filteredProducts.filter(product => { + if (!product.category) return false; + const productCategory = String(product.category).trim(); + return productCategory === targetCategory; + }); + } + + // 提取商品名称,支持多种字段 + const productNames = filteredProducts.map(product => { + // 尝试从多个字段获取商品名称 + const nameFields = [product.productName, product.name, product.product]; + for (const field of nameFields) { + if (field) { + const trimmedName = String(field).trim(); + if (trimmedName !== '') { + return trimmedName; + } + } + } + return ''; + }).filter(name => name !== ''); + + // 去重 + const uniqueProductNames = [...new Set(productNames)]; + console.log('最终商品名称列表:', uniqueProductNames); + + // 计算价格范围 + let priceRange = { min: 0, max: 0, hasPrice: false }; + + // 从过滤后的商品中计算价格范围,按规格分组计算平均价格 + const specPriceMap = {}; + filteredProducts.forEach(product => { + if (product.price && (product.specification || product.spec)) { + const priceStr = String(product.price).trim(); + const specStr = String(product.specification || product.spec).trim(); + + // 处理逗号分隔的多个价格 + const priceArray = priceStr.split(',').map(p => p.trim()).filter(p => p && p.trim() !== ''); + + // 处理逗号分隔的多个规格 + let specs = specStr.split(',').map(spec => spec.trim()).filter(spec => spec.length > 0); + + // 进一步处理规格,确保每个规格都是独立的 + const processedSpecs = []; + specs.forEach(spec => { + if (spec.includes(',')) { + // 按中文逗号分割 + const subSpecs = spec.split(',').map(s => s.trim()).filter(s => s.length > 0); + processedSpecs.push(...subSpecs); + } else { + processedSpecs.push(spec); + } + }); + specs = processedSpecs; + + // 将规格和价格配对 + specs.forEach((spec, index) => { + if (spec.length > 0 && index < priceArray.length) { + const price = priceArray[index]; + if (price && price.trim() !== '') { + const priceValue = parseFloat(price); + if (!isNaN(priceValue)) { + // 解析规格 + const specInfo = this.parseSpecification(spec); + + // 价格<10的需要按照公式计算 + let finalPrice = priceValue; + if (priceValue < 10 && specInfo) { + if (specInfo.type === '净重') { + // 净重:规格平均值 × 价格 + finalPrice = specInfo.avg * priceValue; + } else if (specInfo.type === '毛重') { + // 毛重:(规格平均值 - 5) × 价格 + finalPrice = (specInfo.avg - 5) * priceValue; + } + } + + // 按规格分组存储价格 + if (!specPriceMap[spec]) { + specPriceMap[spec] = []; + } + specPriceMap[spec].push(finalPrice); + } + } + } + }); + } + }); + + // 计算每个规格的平均价格,然后找出最低和最高 + const specAvgPrices = []; + Object.keys(specPriceMap).forEach(spec => { + const prices = specPriceMap[spec]; + if (prices.length > 0) { + const avgPrice = prices.reduce((sum, price) => sum + price, 0) / prices.length; + specAvgPrices.push(avgPrice); + } + }); + + if (specAvgPrices.length > 0) { + priceRange.min = Math.round(Math.min(...specAvgPrices) * 100) / 100; + priceRange.max = Math.round(Math.max(...specAvgPrices) * 100) / 100; + priceRange.hasPrice = true; + } + + this.setData({ + productNames: uniqueProductNames, + priceRange: priceRange, + loading: false + }); + + // 结束下拉刷新 + wx.stopPullDownRefresh(); + } else { + // 如果本地存储中也没有原始商品数据,调用API获取数据 + console.log('本地存储中没有数据,调用API获取商品数据...'); + const api = require('../../utils/api'); + // 使用正确的参数调用getProducts方法 + api.getProducts(1, 1000, 'all', '').then(result => { + console.log('API返回结果:', result); + + // 从返回对象中提取products数组,如果不存在则使用空数组 + const products = result.products || []; + + // 过滤出有有效category字段的商品 + const productsWithCategory = products.filter(product => { + if (!product.category) return false; + const categoryStr = String(product.category).trim(); + return categoryStr !== ''; + }); + + // 移除价格过滤,获取所有商品 + let filteredProducts = productsWithCategory; + + // 如果有分类参数,过滤出该分类下的商品 + if (this.data.category) { + console.log('当前分类:', this.data.category); + const targetCategory = String(this.data.category).trim(); + filteredProducts = filteredProducts.filter(product => { + if (!product.category) return false; + const productCategory = String(product.category).trim(); + return productCategory === targetCategory; + }); + } + + // 提取商品名称,支持多种字段 + const productNames = filteredProducts.map(product => { + // 尝试从多个字段获取商品名称 + const nameFields = [product.productName, product.name, product.product]; + for (const field of nameFields) { + if (field) { + const trimmedName = String(field).trim(); + if (trimmedName !== '') { + return trimmedName; + } + } + } + return ''; + }).filter(name => name !== ''); + + // 去重 + const uniqueProductNames = [...new Set(productNames)]; + console.log('最终商品名称列表:', uniqueProductNames); + + // 计算价格范围 + let priceRange = { min: 0, max: 0, hasPrice: false }; + + // 从过滤后的商品中计算价格范围,按规格分组计算平均价格 + const specPriceMap = {}; + filteredProducts.forEach(product => { + if (product.price && (product.specification || product.spec)) { + const priceStr = String(product.price).trim(); + const specStr = String(product.specification || product.spec).trim(); + + // 处理逗号分隔的多个价格 + const priceArray = priceStr.split(',').map(p => p.trim()).filter(p => p && p.trim() !== ''); + + // 处理逗号分隔的多个规格 + let specs = specStr.split(',').map(spec => spec.trim()).filter(spec => spec.length > 0); + + // 进一步处理规格,确保每个规格都是独立的 + const processedSpecs = []; + specs.forEach(spec => { + if (spec.includes(',')) { + // 按中文逗号分割 + const subSpecs = spec.split(',').map(s => s.trim()).filter(s => s.length > 0); + processedSpecs.push(...subSpecs); + } else { + processedSpecs.push(spec); + } + }); + specs = processedSpecs; + + // 将规格和价格配对 + specs.forEach((spec, index) => { + if (spec.length > 0 && index < priceArray.length) { + const price = priceArray[index]; + if (price && price.trim() !== '') { + const priceValue = parseFloat(price); + if (!isNaN(priceValue)) { + // 解析规格 + const specInfo = this.parseSpecification(spec); + + // 价格<10的需要按照公式计算 + let finalPrice = priceValue; + if (priceValue < 10 && specInfo) { + if (specInfo.type === '净重') { + // 净重:规格平均值 × 价格 + finalPrice = specInfo.avg * priceValue; + } else if (specInfo.type === '毛重') { + // 毛重:(规格平均值 - 5) × 价格 + finalPrice = (specInfo.avg - 5) * priceValue; + } + } + + // 按规格分组存储价格 + if (!specPriceMap[spec]) { + specPriceMap[spec] = []; + } + specPriceMap[spec].push(finalPrice); + } + } + } + }); + } + }); + + // 计算每个规格的平均价格,然后找出最低和最高 + const specAvgPrices = []; + Object.keys(specPriceMap).forEach(spec => { + const prices = specPriceMap[spec]; + if (prices.length > 0) { + const avgPrice = prices.reduce((sum, price) => sum + price, 0) / prices.length; + specAvgPrices.push(avgPrice); + } + }); + + if (specAvgPrices.length > 0) { + priceRange.min = Math.round(Math.min(...specAvgPrices) * 100) / 100; + priceRange.max = Math.round(Math.max(...specAvgPrices) * 100) / 100; + priceRange.hasPrice = true; + } + + this.setData({ + productNames: uniqueProductNames, + priceRange: priceRange, + loading: false + }); + + // 结束下拉刷新 + wx.stopPullDownRefresh(); + }).catch(err => { + console.error('获取商品列表失败:', err); + this.setData({ + error: '获取商品列表失败,请稍后重试', + loading: false + }); + + // 结束下拉刷新 + wx.stopPullDownRefresh(); + }); + } + } + }, + + selectProduct(e) { + const productName = e.currentTarget.dataset.product; + console.log('选择商品:', productName); + // 将商品名称和当前分类存储到本地存储 + wx.setStorageSync('selectedProductName', productName); + wx.setStorageSync('selectedCategory', this.data.category); // 存储当前分类 + // 使用wx.switchTab导航到tabBar页面 + wx.switchTab({ + url: '/pages/evaluate2/index', + success: function(res) { + console.log('跳转成功:', res); + }, + fail: function(err) { + console.error('跳转失败:', err); + } + }); + }, + + // 返回分类选择页面 + goBackToCategories() { + console.log('返回分类选择页面'); + wx.redirectTo({ + url: '/pages/evaluate2/one' + }); + }, + + // 下拉刷新 + onPullDownRefresh() { + console.log('开始下拉刷新'); + this.loadProductNames(); + } +}); \ No newline at end of file diff --git a/pages/evaluate2/product-list.json b/pages/evaluate2/product-list.json new file mode 100644 index 0000000..09e623a --- /dev/null +++ b/pages/evaluate2/product-list.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "enablePullDownRefresh": true, + "backgroundTextStyle": "dark" +} \ No newline at end of file diff --git a/pages/evaluate2/product-list.wxml b/pages/evaluate2/product-list.wxml new file mode 100644 index 0000000..7a07798 --- /dev/null +++ b/pages/evaluate2/product-list.wxml @@ -0,0 +1,72 @@ + + + + + + 商品选择 + + + + + + + + + 正在加载商品数据... + + + + + ⚠️ + {{error}} + + + + + + + + 当前分类: + {{category}} + + + 价格范围: + ¥{{priceRange.min}} - ¥{{priceRange.max}} + + + + 商品列表 + {{productNames.length}}个商品 + + + + + + 🛍️ + {{item}} + + + + + + + 📦 + + {{category ? '该分类下暂无商品' : '暂无商品'}} + + + + + + + 暂无更多商品选择 + + + + \ No newline at end of file diff --git a/pages/evaluate2/product-list.wxss b/pages/evaluate2/product-list.wxss new file mode 100644 index 0000000..65549fa --- /dev/null +++ b/pages/evaluate2/product-list.wxss @@ -0,0 +1,415 @@ +.container { + display: flex; + flex-direction: column; + min-height: 100vh; + background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); + font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif; + overflow-x: hidden; + width: 100%; + box-sizing: border-box; +} + +.header { + background: #fff; + box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.08); + position: sticky; + top: 0; + z-index: 10; +} + +.header-content { + padding: 30rpx 0; + text-align: center; + width: 100%; + box-sizing: border-box; +} + +/* 返回按钮样式 */ +.back-button { + width: 120rpx; + height: 60rpx; + line-height: 60rpx; + font-size: 24rpx; + color: #4a90e2; + background: transparent; + border: none; + padding: 0; + margin: 0; + display: flex; + align-items: center; + justify-content: center; +} + +.back-button:hover { + color: #3b82f6; +} + +.title { + font-size: 36rpx; + font-weight: 700; + color: #2c3e50; + letter-spacing: 2rpx; +} + +.content { + flex: 1; + padding: 16rpx; + width: 100%; + box-sizing: border-box; + overflow-x: hidden; +} + +/* 加载状态 */ +.loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 160rpx 0; +} + +.loading-spinner { + width: 80rpx; + height: 80rpx; + border: 8rpx solid rgba(74, 144, 226, 0.2); + border-top: 8rpx solid #4a90e2; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-bottom: 32rpx; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.loading-text { + font-size: 28rpx; + color: #666; + font-weight: 500; +} + +/* 错误提示卡片 */ +.error-card { + background: #fff; + border-radius: 16rpx; + padding: 48rpx; + margin: 32rpx 0; + box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.08); + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} + +.error-icon { + font-size: 80rpx; + margin-bottom: 24rpx; +} + +.error-text { + font-size: 28rpx; + color: #e74c3c; + margin-bottom: 32rpx; + line-height: 1.5; +} + +/* 按钮样式 */ +.btn-primary { + width: 240rpx; + height: 80rpx; + line-height: 80rpx; + font-size: 28rpx; + font-weight: 600; + border-radius: 40rpx; + background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%); + color: #fff; + border: none; + box-shadow: 0 4rpx 12rpx rgba(96, 165, 250, 0.4); + transition: all 0.3s ease; +} + +.btn-primary:hover { + transform: translateY(-2rpx); + box-shadow: 0 6rpx 16rpx rgba(74, 144, 226, 0.5); +} + +/* 商品列表区域 */ +.product-section { + margin-top: 24rpx; +} + +/* 当前选择的分类 */ +.current-category { + display: flex; + align-items: center; + background: rgba(74, 144, 226, 0.1); + padding: 16rpx 20rpx; + border-radius: 12rpx; + margin-bottom: 20rpx; + border-left: 6rpx solid #4a90e2; +} + +.current-category-label { + font-size: 24rpx; + color: #666; + margin-right: 8rpx; +} + +.current-category-name { + font-size: 26rpx; + font-weight: 600; + color: #4a90e2; +} + +/* 价格范围 */ +.price-range { + margin-top: 8rpx; + display: flex; + align-items: center; +} + +.price-range-label { + font-size: 22rpx; + color: #666; + margin-right: 8rpx; +} + +.price-range-value { + font-size: 22rpx; + font-weight: 500; + color: #ff6b81; +} + +.section-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 24rpx; + padding: 0 8rpx; +} + +.section-title { + font-size: 30rpx; + font-weight: 700; + color: #2c3e50; + padding-left: 16rpx; + border-left: 6rpx solid #4a90e2; +} + +.section-count { + font-size: 24rpx; + color: #999; + background: rgba(74, 144, 226, 0.1); + padding: 6rpx 16rpx; + border-radius: 20rpx; +} + +/* 商品网格布局 */ +.product-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20rpx; + margin-top: 16rpx; + width: 100%; + box-sizing: border-box; + overflow-x: hidden; +} + +/* 商品卡片 */ +.product-card { + background: rgba(255, 255, 255, 0.95); + border-radius: 20rpx; + padding: 32rpx 24rpx; + box-shadow: 0 6rpx 20rpx rgba(0,0,0,0.08); + transition: all 0.3s ease; + cursor: pointer; + position: relative; + overflow: hidden; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + min-height: 180rpx; + backdrop-filter: blur(8rpx); + border: 1rpx solid rgba(255, 255, 255, 0.3); + width: 100%; + box-sizing: border-box; +} + +.product-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 6rpx; + background: linear-gradient(90deg, #60a5fa 0%, #3b82f6 100%); +} + +.product-card:hover { + transform: translateY(-6rpx); + box-shadow: 0 12rpx 32rpx rgba(0,0,0,0.15); + background: rgba(255, 255, 255, 1); +} + +.product-card:active { + transform: translateY(-2rpx); + box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.12); +} + +.product-icon { + font-size: 72rpx; + margin-bottom: 20rpx; + opacity: 0.9; + transition: all 0.3s ease; +} + +.product-card:hover .product-icon { + transform: scale(1.1); + opacity: 1; +} + +.product-name { + font-size: 28rpx; + font-weight: 600; + color: #2c3e50; + line-height: 1.4; + word-break: break-word; + margin-bottom: 20rpx; + flex: 1; + display: flex; + align-items: center; + justify-content: center; + padding: 0 8rpx; +} + +.product-arrow { + position: absolute; + bottom: 20rpx; + right: 24rpx; + font-size: 28rpx; + color: #4a90e2; + font-weight: bold; + opacity: 0.6; + transition: all 0.3s ease; +} + +.product-card:hover .product-arrow { + opacity: 1; + transform: translateX(4rpx); +} + +/* 响应式设计 */ +@media (max-width: 750rpx) { + .content { + padding: 20rpx; + } + + .product-grid { + grid-template-columns: repeat(3, 1fr); + gap: 16rpx; + } + + .product-card { + padding: 28rpx 20rpx; + min-height: 160rpx; + } + + .title { + font-size: 32rpx; + } + + .section-title { + font-size: 28rpx; + } + + .product-name { + font-size: 24rpx; + } + + .product-icon { + font-size: 60rpx; + } +} + +/* 小屏幕设备适配 */ +@media (max-width: 414rpx) { + .product-grid { + grid-template-columns: repeat(3, 1fr); + gap: 12rpx; + } + + .product-card { + padding: 20rpx 16rpx; + min-height: 140rpx; + } + + .product-name { + font-size: 22rpx; + } + + .product-icon { + font-size: 50rpx; + } +} + +/* 暂无更多商品提示 */ +.no-more { + display: flex; + justify-content: center; + align-items: center; + padding: 48rpx 0; + margin-top: 16rpx; +} + +.no-more-text { + font-size: 24rpx; + color: #999; + background: rgba(0, 0, 0, 0.03); + padding: 12rpx 32rpx; + border-radius: 30rpx; + font-weight: 500; +} + +/* 空状态 */ +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 160rpx 0; + text-align: center; +} + +.empty-icon { + font-size: 160rpx; + margin-bottom: 40rpx; + opacity: 0.6; +} + +.empty-text { + font-size: 32rpx; + color: #666; + margin-bottom: 48rpx; + line-height: 1.4; + padding: 0 40rpx; +} + +.btn-secondary { + width: 200rpx; + height: 80rpx; + line-height: 80rpx; + font-size: 28rpx; + font-weight: 600; + border-radius: 40rpx; + background: #fff; + color: #4a90e2; + border: 2rpx solid #4a90e2; + transition: all 0.3s ease; +} + +.btn-secondary:hover { + background: rgba(74, 144, 226, 0.05); + transform: translateY(-2rpx); +} diff --git a/pages/evaluate2/spec-detail.js b/pages/evaluate2/spec-detail.js new file mode 100644 index 0000000..19915df --- /dev/null +++ b/pages/evaluate2/spec-detail.js @@ -0,0 +1,102 @@ +Page({ + data: { + productName: '', + specification: '', + price: 0, + quantity: 1, + totalPrice: 0, + loading: false, + error: '' + }, + onLoad(options) { + console.log('接收到的参数:', options); + // 即使参数不完整,也要尝试获取并设置 + const productName = options.productName ? decodeURIComponent(options.productName) : ''; + const specification = options.specification ? decodeURIComponent(options.specification) : ''; + let price = 0; + + if (options.price) { + const decodedPrice = decodeURIComponent(options.price); + console.log('解码后的价格:', decodedPrice); + price = parseFloat(decodedPrice) || 0; + } + + console.log('解析后的参数:', { productName, specification, price }); + + this.setData({ + productName: productName, + specification: specification, + price: price, + totalPrice: 0 // 初始时总价为0,不显示 + }); + }, + + // 件数输入变化 + onQuantityChange(e) { + const quantity = parseInt(e.detail.value) || 1; + this.setData({ + quantity: quantity + // 只更新件数,不更新总价,等待点击计算按钮 + }); + }, + + // 减少数量 + decreaseQuantity() { + if (this.data.quantity > 1) { + this.setData({ + quantity: this.data.quantity - 1 + }); + } + }, + + // 增加数量 + increaseQuantity() { + this.setData({ + quantity: this.data.quantity + 1 + }); + }, + + // 计算价格 + calculatePrice() { + const totalPrice = Math.round(this.data.price * this.data.quantity * 10) / 10; + this.setData({ + totalPrice: totalPrice + }); + wx.showToast({ + title: '计算完成', + icon: 'success', + duration: 1000 + }); + }, + + // 返回上一页 + goBack() { + wx.navigateBack(); + }, + + // 下拉刷新 + onPullDownRefresh() { + console.log('开始下拉刷新'); + // 重新加载页面数据 + // 由于spec-detail页面的数据是通过URL参数传递的,这里可以重新获取参数并设置数据 + const options = this.options || {}; + const productName = options.productName ? decodeURIComponent(options.productName) : ''; + const specification = options.specification ? decodeURIComponent(options.specification) : ''; + let price = 0; + + if (options.price) { + const decodedPrice = decodeURIComponent(options.price); + price = parseFloat(decodedPrice) || 0; + } + + this.setData({ + productName: productName, + specification: specification, + price: price, + totalPrice: 0 // 初始时总价为0,不显示 + }); + + // 结束下拉刷新 + wx.stopPullDownRefresh(); + } +}); \ No newline at end of file diff --git a/pages/evaluate2/spec-detail.json b/pages/evaluate2/spec-detail.json new file mode 100644 index 0000000..09e623a --- /dev/null +++ b/pages/evaluate2/spec-detail.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "enablePullDownRefresh": true, + "backgroundTextStyle": "dark" +} \ No newline at end of file diff --git a/pages/evaluate2/spec-detail.wxml b/pages/evaluate2/spec-detail.wxml new file mode 100644 index 0000000..e4c2898 --- /dev/null +++ b/pages/evaluate2/spec-detail.wxml @@ -0,0 +1,59 @@ + + + + {{productName || '规格详情'}} + + + + + + + 规格信息 + + 规格 + {{specification}} + + + 单价 + ¥{{price || 0}} + + 您已选择此规格进行估价 + + + + + 数量设置 + + + + + + + + + + + + + + + 预估结果 + + 预估总价 + ¥{{totalPrice}} + + 此价格为预估价格,实际价格可能会有所变动 + + + + + + + + \ No newline at end of file diff --git a/pages/evaluate2/spec-detail.wxss b/pages/evaluate2/spec-detail.wxss new file mode 100644 index 0000000..8fd2942 --- /dev/null +++ b/pages/evaluate2/spec-detail.wxss @@ -0,0 +1,401 @@ +/* 页面容器 */ +.page-container { + min-height: 100vh; + background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); + font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif; + display: flex; + flex-direction: column; + box-sizing: border-box; +} + +/* 头部样式 */ +.page-header { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(10rpx); + box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.05); + padding: 28rpx 0; + text-align: center; + position: sticky; + top: 0; + z-index: 10; +} + +.header-title { + font-size: 30rpx; + font-weight: 700; + color: #2c3e50; + letter-spacing: 1rpx; +} + +/* 主要内容区域 */ +.main-content { + flex: 1; + padding: 24rpx; + display: flex; + flex-direction: column; + gap: 24rpx; + padding-bottom: 48rpx; + box-sizing: border-box; +} + +/* 卡片基础样式 */ +.info-card, +.control-card, +.result-card { + background: rgba(255, 255, 255, 0.95); + border-radius: 24rpx; + padding: 32rpx; + box-shadow: 0 6rpx 24rpx rgba(0,0,0,0.08); + backdrop-filter: blur(12rpx); + border: 1rpx solid rgba(255, 255, 255, 0.4); + transition: all 0.3s ease; + box-sizing: border-box; +} + +.info-card:hover, +.control-card:hover, +.result-card:hover { + box-shadow: 0 8rpx 32rpx rgba(0,0,0,0.12); + transform: translateY(-4rpx); + background: rgba(255, 255, 255, 0.98); +} + +/* 卡片标题 */ +.card-subtitle { + font-size: 26rpx; + font-weight: 600; + color: #64748b; + margin-bottom: 24rpx; + padding-bottom: 16rpx; + border-bottom: 1rpx solid #f1f5f9; +} + +/* 信息行样式 */ +.info-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16rpx 0; + border-bottom: 1rpx solid #f8fafc; +} + +.info-row:last-child { + border-bottom: none; +} + +.info-label { + font-size: 26rpx; + color: #64748b; + font-weight: 500; +} + +.info-value { + font-size: 26rpx; + font-weight: 600; + color: #2c3e50; +} + +.info-value.price { + color: #ef4444; + font-size: 32rpx; + font-weight: 700; +} + +/* 提示信息 */ +.info-hint { + font-size: 22rpx; + color: #94a3b8; + text-align: center; + margin-top: 20rpx; + padding-top: 20rpx; + border-top: 1rpx solid #f1f5f9; +} + +/* 数量控制 */ +.quantity-box { + display: flex; + align-items: center; + gap: 24rpx; + margin-top: 12rpx; + justify-content: center; +} + +.quantity-btn { + width: 80rpx; + height: 80rpx; + border-radius: 40rpx; + font-size: 36rpx; + font-weight: bold; + background: rgba(255, 255, 255, 0.9); + color: #3b82f6; + border: 2rpx solid rgba(96, 165, 250, 0.4); + backdrop-filter: blur(12rpx); + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.08); +} + +.quantity-btn:hover { + background: rgba(59, 130, 246, 0.1); + border-color: rgba(59, 130, 246, 0.6); + transform: scale(1.1); +} + +.quantity-btn.minus:hover { + background: rgba(239, 68, 68, 0.1); + border-color: rgba(239, 68, 68, 0.6); + color: #ef4444; +} + +.quantity-btn.plus:hover { + background: rgba(16, 185, 129, 0.1); + border-color: rgba(16, 185, 129, 0.6); + color: #10b981; +} + +.quantity-input { + width: 160rpx; + height: 80rpx; + border: 2rpx solid rgba(96, 165, 250, 0.4); + border-radius: 16rpx; + padding: 0 24rpx; + font-size: 28rpx; + font-weight: 600; + text-align: center; + color: #2c3e50; + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(12rpx); + box-shadow: inset 0 2rpx 8rpx rgba(0,0,0,0.08); + box-sizing: border-box; +} + +/* 按钮区域 */ +.button-section { + margin-top: 12rpx; +} + +.button-section.bottom { + margin-top: 20rpx; +} + +/* 按钮样式 */ +.primary-btn { + width: 100%; + height: 92rpx; + line-height: 92rpx; + font-size: 28rpx; + font-weight: 600; + border-radius: 46rpx; + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); + color: #fff; + border: none; + box-shadow: 0 6rpx 24rpx rgba(59, 130, 246, 0.4); + transition: all 0.3s ease; + text-align: center; +} + +.primary-btn:hover { + transform: translateY(-4rpx); + box-shadow: 0 8rpx 32rpx rgba(59, 130, 246, 0.5); +} + +.secondary-btn { + width: 100%; + height: 84rpx; + line-height: 84rpx; + font-size: 26rpx; + font-weight: 600; + border-radius: 42rpx; + background: rgba(255, 255, 255, 0.95); + color: #3b82f6; + border: 2rpx solid rgba(59, 130, 246, 0.4); + backdrop-filter: blur(12rpx); + transition: all 0.3s ease; + text-align: center; + box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.08); +} + +.secondary-btn:hover { + background: rgba(59, 130, 246, 0.08); + border-color: rgba(59, 130, 246, 0.6); + transform: translateY(-4rpx); + box-shadow: 0 6rpx 24rpx rgba(59, 130, 246, 0.3); +} + +/* 结果卡片 */ +.result-card { + animation: fadeInUp 0.6s ease-out; +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30rpx); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* 结果行 */ +.result-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20rpx 0; +} + +.result-label { + font-size: 26rpx; + color: #64748b; + font-weight: 500; +} + +.result-value { + font-size: 36rpx; + font-weight: 700; + color: #ef4444; + text-shadow: 0 2rpx 4rpx rgba(239, 68, 68, 0.2); +} + +/* 结果提示 */ +.result-hint { + font-size: 22rpx; + color: #94a3b8; + text-align: center; + margin-top: 16rpx; + padding-top: 16rpx; + border-top: 1rpx solid #f1f5f9; + line-height: 1.5; +} + +/* 响应式设计 */ +@media (max-width: 750rpx) { + .main-content { + padding: 20rpx; + gap: 20rpx; + } + + .info-card, + .control-card, + .result-card { + padding: 28rpx; + } + + .header-title { + font-size: 28rpx; + } + + .card-subtitle { + font-size: 24rpx; + margin-bottom: 20rpx; + } + + .info-label, + .info-value { + font-size: 24rpx; + } + + .info-value.price { + font-size: 30rpx; + } + + .result-value { + font-size: 32rpx; + } + + .quantity-box { + gap: 20rpx; + } + + .quantity-btn { + width: 72rpx; + height: 72rpx; + font-size: 32rpx; + } + + .quantity-input { + width: 140rpx; + height: 72rpx; + font-size: 26rpx; + } + + .primary-btn { + height: 84rpx; + line-height: 84rpx; + font-size: 26rpx; + } + + .secondary-btn { + height: 76rpx; + line-height: 76rpx; + font-size: 24rpx; + } +} + +/* 小屏幕设备适配 */ +@media (max-width: 375rpx) { + .main-content { + padding: 16rpx; + gap: 16rpx; + } + + .info-card, + .control-card, + .result-card { + padding: 24rpx; + } + + .header-title { + font-size: 26rpx; + } + + .card-subtitle { + font-size: 22rpx; + margin-bottom: 16rpx; + } + + .info-label, + .info-value { + font-size: 22rpx; + } + + .info-value.price { + font-size: 28rpx; + } + + .result-value { + font-size: 28rpx; + } + + .quantity-box { + gap: 16rpx; + } + + .quantity-btn { + width: 64rpx; + height: 64rpx; + font-size: 28rpx; + } + + .quantity-input { + width: 120rpx; + height: 64rpx; + font-size: 24rpx; + } + + .primary-btn { + height: 76rpx; + line-height: 76rpx; + font-size: 24rpx; + } + + .secondary-btn { + height: 68rpx; + line-height: 68rpx; + font-size: 22rpx; + } +} -- 2.30.2 From f5473038c8f51f2a39e764b20f23d82526248c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Tue, 27 Jan 2026 11:26:34 +0800 Subject: [PATCH 02/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8DparseSpecification?= =?UTF-8?q?=E5=87=BD=E6=95=B0=EF=BC=8C=E6=94=AF=E6=8C=81=E5=87=80=E9=87=8D?= =?UTF-8?q?X+=E6=A0=BC=E5=BC=8F=E7=9A=84=E8=A7=84=E6=A0=BC=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/evaluate2/index.js | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/pages/evaluate2/index.js b/pages/evaluate2/index.js index 2324627..8543ab6 100644 --- a/pages/evaluate2/index.js +++ b/pages/evaluate2/index.js @@ -211,11 +211,12 @@ Page({ // 解析规格,提取类型(净重/毛重)和数值范围 parseSpecification(spec) { - const weightMatch = spec.match(/(净重|毛重)(\d+)-(\d+)/); - if (weightMatch) { - const type = weightMatch[1]; // 净重或毛重 - const min = parseFloat(weightMatch[2]); - const max = parseFloat(weightMatch[3]); + // 匹配 "净重X-Y" 或 "毛重X-Y" 格式 + const rangeMatch = spec.match(/(净重|毛重)(\d+)-(\d+)/); + if (rangeMatch) { + const type = rangeMatch[1]; // 净重或毛重 + const min = parseFloat(rangeMatch[2]); + const max = parseFloat(rangeMatch[3]); const avg = (min + max) / 2; return { type: type, @@ -224,6 +225,33 @@ Page({ avg: avg }; } + + // 匹配 "净重X+" 或 "毛重X+" 格式 + const plusMatch = spec.match(/(净重|毛重)(\d+)\+/); + if (plusMatch) { + const type = plusMatch[1]; // 净重或毛重 + const value = parseFloat(plusMatch[2]); + return { + type: type, + min: value, + max: value, + avg: value + }; + } + + // 匹配 "净重X" 或 "毛重X" 格式 + const singleMatch = spec.match(/(净重|毛重)(\d+)/); + if (singleMatch) { + const type = singleMatch[1]; // 净重或毛重 + const value = parseFloat(singleMatch[2]); + return { + type: type, + min: value, + max: value, + avg: value + }; + } + return null; }, -- 2.30.2 From 5f444e9b3791139b286ac1980d7167823ae10495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Tue, 27 Jan 2026 13:46:14 +0800 Subject: [PATCH 03/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AF=84=E8=AE=BA?= =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E5=8A=9F=E8=83=BD=EF=BC=9A=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?review=E5=AD=97=E6=AE=B5=E9=BB=98=E8=AE=A4=E4=B8=BA0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/goods-detail/goods-detail.js | 25 ++++++++++++++++++++----- server-example/server-mysql.js | 13 ++++++++++++- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/pages/goods-detail/goods-detail.js b/pages/goods-detail/goods-detail.js index 435059e..75dc48c 100644 --- a/pages/goods-detail/goods-detail.js +++ b/pages/goods-detail/goods-detail.js @@ -1815,11 +1815,12 @@ Page({ const productId = this.data.goodsDetail.productId || this.data.goodsDetail.id; // 准备评论数据 - // 只发送服务器需要的参数:productId、phoneNumber和comments + // 只发送服务器需要的参数:productId、phoneNumber、comments和review const commentData = { productId: String(productId), phoneNumber: phoneNumber ? String(phoneNumber) : null, - comments: content + comments: content, + review: 0 // 新提交的评论默认为待审核状态 }; // 调试日志 @@ -1851,7 +1852,8 @@ Page({ liked: false, hated: false, replies: [], - phoneNumber: phoneNumber // 添加用户标识信息,用于判断是否可以删除 + phoneNumber: phoneNumber, // 添加用户标识信息,用于判断是否可以删除 + review: 0 // 新提交的评论默认为待审核状态 }; // 更新评论列表 - add new comment to the end @@ -1952,7 +1954,8 @@ Page({ hated: false, replies: [], phoneNumber: '', - isDefault: true + isDefault: true, + review: 1 // 默认评论默认为审核通过状态 })); }, @@ -2003,9 +2006,19 @@ Page({ }); commentsData = uniqueComments; + // 应用审核逻辑:审核通过的评论所有人可见,未审核通过的评论仅自己可见 + const currentUserPhone = this.data.currentUserPhone; + const filteredComments = commentsData.filter(comment => { + const reviewStatus = comment.review || 0; // 默认值为0(待审核) + // 审核通过的评论(review=1)所有人可见 + // 未审核通过的评论(review=0或2)仅评论作者可见 + return reviewStatus === 1 || comment.phoneNumber === currentUserPhone; + }); + console.log('应用审核逻辑后剩余评论数量:', filteredComments.length); + // Always add default comments at the beginning const defaultComments = this.getConsistentRandomComments(productId, 2); - commentsData = [...defaultComments, ...commentsData]; + commentsData = [...defaultComments, ...filteredComments]; // 检查返回的评论是否都属于当前用户 const allCommentsBelongToCurrentUser = commentsData.every(comment => @@ -2026,6 +2039,8 @@ Page({ id: comment.id || `comment_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, // 确保phoneNumber字段存在 phoneNumber: comment.phoneNumber || comment.userPhone || '', + // 确保review字段存在 + review: comment.review || 0, // 格式化时间 time: timeUtils.formatRelativeTime(comment.time) })); diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index 61ecd3e..93880e4 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -556,6 +556,11 @@ const comments = sequelize.define('Comment', { type: DataTypes.INTEGER, defaultValue: 0, comment: '点踩数' + }, + review: { + type: DataTypes.INTEGER, + defaultValue: 0, + comment: '审核字段' } }, { tableName: 'comments', @@ -1075,6 +1080,11 @@ Comment.init({ type: DataTypes.INTEGER, defaultValue: 0, comment: '点踩数' + }, + review: { + type: DataTypes.INTEGER, + defaultValue: 0, + comment: '审核字段' } }, { sequelize, @@ -4380,7 +4390,7 @@ app.post('/api/comments/get', async (req, res) => { // 提交评论 app.post('/api/comments/add', async (req, res) => { try { - const { productId, phoneNumber, comments } = req.body; + const { productId, phoneNumber, comments, review = 0 } = req.body; if (!productId || !phoneNumber || !comments) { return res.status(400).json({ @@ -4395,6 +4405,7 @@ app.post('/api/comments/add', async (req, res) => { productId, phoneNumber, comments, + review, time: new Date() }); -- 2.30.2 From 9c4a5fb414b507ca01398c36b66d888960658281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Tue, 27 Jan 2026 14:19:23 +0800 Subject: [PATCH 04/22] =?UTF-8?q?=E5=88=A0=E9=99=A4goods-detail=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E5=BA=95=E9=83=A8=E7=9A=84=E5=A4=9A=E4=BD=99=E6=95=B0?= =?UTF-8?q?=E5=AD=971?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/goods-detail/goods-detail.wxml | 2 +- pages/goods-update/goods-update.wxml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/goods-detail/goods-detail.wxml b/pages/goods-detail/goods-detail.wxml index 8a4a0cf..6b4a749 100644 --- a/pages/goods-detail/goods-detail.wxml +++ b/pages/goods-detail/goods-detail.wxml @@ -72,7 +72,7 @@ - + 售空 {{goodsDetail.supplyStatus}} diff --git a/pages/goods-update/goods-update.wxml b/pages/goods-update/goods-update.wxml index d166a26..44c9d39 100644 --- a/pages/goods-update/goods-update.wxml +++ b/pages/goods-update/goods-update.wxml @@ -516,7 +516,7 @@ scroll-y="true" style="max-height: 50vh; padding: 0; -webkit-overflow-scrolling: touch;" enable-back-to-top="false" - > + > Date: Tue, 27 Jan 2026 16:14:54 +0800 Subject: [PATCH 05/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8Deggbar=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E5=8A=9F=E8=83=BD=EF=BC=8C=E8=A7=A3=E5=86=B3=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8=E5=90=AF=E5=8A=A8=E9=97=AE=E9=A2=98=E5=B9=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0eggbar=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.json | 6 +- custom-tab-bar/index.js | 4 +- custom-tab-bar/index.wxml | 4 +- pages/eggbar/create-post.js | 174 ++++++++++++++++++++ pages/eggbar/create-post.json | 9 ++ pages/eggbar/create-post.wxml | 68 ++++++++ pages/eggbar/create-post.wxss | 281 +++++++++++++++++++++++++++++++++ pages/eggbar/eggbar.js | 148 +++++++++++++++++ pages/eggbar/eggbar.json | 12 ++ pages/eggbar/eggbar.wxml | 79 +++++++++ pages/eggbar/eggbar.wxss | 270 +++++++++++++++++++++++++++++++ server-example/server-mysql.js | 120 ++++++++++++++ utils/api.js | 60 +++++++ 13 files changed, 1229 insertions(+), 6 deletions(-) create mode 100644 pages/eggbar/create-post.js create mode 100644 pages/eggbar/create-post.json create mode 100644 pages/eggbar/create-post.wxml create mode 100644 pages/eggbar/create-post.wxss create mode 100644 pages/eggbar/eggbar.js create mode 100644 pages/eggbar/eggbar.json create mode 100644 pages/eggbar/eggbar.wxml create mode 100644 pages/eggbar/eggbar.wxss diff --git a/app.json b/app.json index 0a00338..f90aa36 100644 --- a/app.json +++ b/app.json @@ -9,6 +9,8 @@ "pages/evaluate2/one", "pages/evaluate2/product-list", "pages/evaluate2/spec-detail", + "pages/eggbar/eggbar", + "pages/eggbar/create-post", "pages/settlement/index", "pages/publish/index", "pages/buyer/index", @@ -85,8 +87,8 @@ "text": "估" }, { - "pagePath": "pages/settlement/index", - "text": "入驻" + "pagePath": "pages/eggbar/eggbar", + "text": "蛋吧" }, { "pagePath": "pages/favorites/index", diff --git a/custom-tab-bar/index.js b/custom-tab-bar/index.js index 1d90d18..353428f 100644 --- a/custom-tab-bar/index.js +++ b/custom-tab-bar/index.js @@ -16,7 +16,7 @@ Component({ { key: 'index', route: 'pages/index/index' }, { key: 'chat', route: 'pages/chat/index', badgeKey: 'chat' }, { key: 'evaluate', route: 'pages/evaluate2/one' }, - { key: 'settlement', route: 'pages/settlement/index' }, + { key: 'settlement', route: 'pages/eggbar/eggbar' }, { key: 'favorites', route: 'pages/favorites/index' }, { key: 'profile', route: 'pages/profile/index' } ] @@ -95,7 +95,7 @@ Component({ 'pages/index/index', 'pages/chat/index', 'pages/evaluate2/one', - 'pages/settlement/index', + 'pages/eggbar/eggbar', 'pages/favorites/index', 'pages/profile/index' ]; diff --git a/custom-tab-bar/index.wxml b/custom-tab-bar/index.wxml index 1ad7876..a37f79b 100644 --- a/custom-tab-bar/index.wxml +++ b/custom-tab-bar/index.wxml @@ -33,13 +33,13 @@ {{badges['settlement']}} - 入驻 + 蛋吧 diff --git a/pages/eggbar/create-post.js b/pages/eggbar/create-post.js new file mode 100644 index 0000000..c713daf --- /dev/null +++ b/pages/eggbar/create-post.js @@ -0,0 +1,174 @@ +const API = require('../../utils/api.js'); + +Page({ + data: { + content: '', + images: [], + selectedTopic: null, + showTopicModal: false, + hotTopics: [] + }, + + onLoad() { + this.loadHotTopics(); + }, + + loadHotTopics() { + API.getHotTopics().then(res => { + this.setData({ + hotTopics: res.data || [] + }); + }).catch(err => { + console.error('加载热门话题失败:', err); + }); + }, + + onContentChange(e) { + this.setData({ + content: e.detail.value + }); + }, + + chooseImage() { + if (this.data.images.length >= 9) { + wx.showToast({ + title: '最多只能上传9张图片', + icon: 'none' + }); + return; + } + + wx.chooseImage({ + count: 9 - this.data.images.length, + sizeType: ['compressed'], + sourceType: ['album', 'camera'], + success: (res) => { + this.setData({ + images: [...this.data.images, ...res.tempFilePaths] + }); + } + }); + }, + + deleteImage(e) { + const index = e.currentTarget.dataset.index; + const images = this.data.images.filter((_, i) => i !== index); + this.setData({ + images + }); + }, + + showTopicPicker() { + this.setData({ + showTopicModal: true + }); + }, + + hideTopicPicker() { + this.setData({ + showTopicModal: false + }); + }, + + selectTopic(e) { + const topic = e.currentTarget.dataset.topic; + this.setData({ + selectedTopic: topic, + showTopicModal: false + }); + }, + + stopPropagation() { + // 阻止事件冒泡 + }, + + cancel() { + wx.navigateBack(); + }, + + submit() { + if (!this.data.content.trim()) { + return; + } + + wx.showLoading({ + title: '发布中...' + }); + + // 先上传图片,获取永久 URL + this.uploadImages(this.data.images) + .then(uploadedImages => { + const postData = { + content: this.data.content, + images: uploadedImages, + topic: this.data.selectedTopic + }; + + return API.createPost(postData); + }) + .then(res => { + wx.hideLoading(); + wx.showToast({ + title: '发布成功', + icon: 'success' + }); + setTimeout(() => { + wx.navigateBack(); + }, 1000); + }) + .catch(err => { + wx.hideLoading(); + wx.showToast({ + title: '发布失败,请重试', + icon: 'none' + }); + console.error('发布动态失败:', err); + }); + }, + + // 上传图片获取永久 URL + uploadImages(tempImagePaths) { + return new Promise((resolve, reject) => { + if (!tempImagePaths || tempImagePaths.length === 0) { + resolve([]); + return; + } + + const uploadedImages = []; + let uploadedCount = 0; + + tempImagePaths.forEach((tempPath, index) => { + wx.uploadFile({ + url: API.BASE_URL + '/api/eggbar/upload', + filePath: tempPath, + name: 'image', + formData: { + index: index, + total: tempImagePaths.length + }, + success: (res) => { + if (res.statusCode === 200) { + try { + const data = JSON.parse(res.data); + if (data.success && data.imageUrl) { + uploadedImages.push(data.imageUrl); + } + } catch (e) { + console.error('解析上传响应失败:', e); + } + } + }, + fail: (err) => { + console.error('上传图片失败:', err); + }, + complete: () => { + uploadedCount++; + if (uploadedCount === tempImagePaths.length) { + resolve(uploadedImages); + } + } + }); + }); + }); + } +}); diff --git a/pages/eggbar/create-post.json b/pages/eggbar/create-post.json new file mode 100644 index 0000000..24689f5 --- /dev/null +++ b/pages/eggbar/create-post.json @@ -0,0 +1,9 @@ +{ + "usingComponents": {}, + "enablePullDownRefresh": false, + "backgroundTextStyle": "dark", + "backgroundColor": "#f8f8f8", + "navigationBarBackgroundColor": "#ffffff", + "navigationBarTitleText": "发布动态", + "navigationBarTextStyle": "black" +} diff --git a/pages/eggbar/create-post.wxml b/pages/eggbar/create-post.wxml new file mode 100644 index 0000000..ba07cad --- /dev/null +++ b/pages/eggbar/create-post.wxml @@ -0,0 +1,68 @@ + + + 发布动态 + + + + + + {{content.length}}/500 + + + + 添加图片 + + + + + 选择图片 + + + + + + × + + + + + + + + 选择话题 + + {{selectedTopic ? '#' + selectedTopic : '选择话题'}} + + + + + + + + + + + + + + + 选择话题 + × + + + + #{{item.name}} + {{item.count}}人讨论 + + + + + diff --git a/pages/eggbar/create-post.wxss b/pages/eggbar/create-post.wxss new file mode 100644 index 0000000..e0181d2 --- /dev/null +++ b/pages/eggbar/create-post.wxss @@ -0,0 +1,281 @@ +page { + background-color: #f5f5f5; + height: 100vh; +} + +.container { + min-height: 100vh; + padding: 20rpx; +} + +.header { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 20rpx; + padding: 30rpx; + margin-bottom: 20rpx; + box-shadow: 0 4rpx 20rpx rgba(102, 126, 234, 0.3); +} + +.title { + font-size: 36rpx; + font-weight: bold; + color: #ffffff; +} + +.form { + background: #ffffff; + border-radius: 20rpx; + padding: 30rpx; + margin-bottom: 20rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); +} + +.form-item { + margin-bottom: 30rpx; +} + +.label { + font-size: 28rpx; + font-weight: 600; + color: #333333; + margin-bottom: 15rpx; +} + +.textarea { + width: 100%; + min-height: 200rpx; + font-size: 28rpx; + color: #333333; + border: 2rpx solid #f0f0f0; + border-radius: 12rpx; + padding: 20rpx; + box-sizing: border-box; + resize: none; + line-height: 1.6; +} + +.placeholder { + color: #999999; +} + +.counter { + display: block; + text-align: right; + font-size: 24rpx; + color: #999999; + margin-top: 10rpx; +} + +.image-uploader { + margin-top: 10rpx; +} + +.upload-area { + width: 120rpx; + height: 120rpx; + border: 2rpx dashed #e0e0e0; + border-radius: 12rpx; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background: #fafafa; + margin-bottom: 15rpx; + transition: all 0.3s ease; +} + +.upload-area:active { + background: #f0f0f0; + transform: scale(0.98); +} + +.upload-icon { + font-size: 48rpx; + color: #999999; + margin-bottom: 10rpx; +} + +.upload-text { + font-size: 24rpx; + color: #999999; +} + +.image-list { + display: flex; + gap: 15rpx; + flex-wrap: wrap; + margin-top: 15rpx; +} + +.image-item { + position: relative; + width: 150rpx; + height: 150rpx; + border-radius: 12rpx; + overflow: hidden; +} + +.image { + width: 100%; + height: 100%; + background: #f0f0f0; +} + +.image-delete { + position: absolute; + top: 5rpx; + right: 5rpx; + width: 40rpx; + height: 40rpx; + background: rgba(0, 0, 0, 0.6); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + font-size: 32rpx; + font-weight: bold; + transition: all 0.3s ease; +} + +.image-delete:active { + background: rgba(0, 0, 0, 0.8); + transform: scale(0.9); +} + +.topic-picker { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20rpx; + border: 2rpx solid #f0f0f0; + border-radius: 12rpx; + background: #fafafa; + transition: all 0.3s ease; +} + +.topic-picker:active { + background: #f0f0f0; +} + +.topic-text { + font-size: 28rpx; + color: #333333; +} + +.topic-arrow { + font-size: 20rpx; + color: #999999; +} + +.footer { + position: fixed; + bottom: 0; + left: 0; + right: 0; + display: flex; + padding: 20rpx; + background: #ffffff; + border-top: 1rpx solid #f0f0f0; + box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05); + box-sizing: border-box; +} + +.cancel-btn { + flex: 1; + height: 80rpx; + margin-right: 15rpx; + background: #f5f5f5; + color: #333333; + border: none; + border-radius: 40rpx; + font-size: 28rpx; + font-weight: 600; +} + +.submit-btn { + flex: 1; + height: 80rpx; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: #ffffff; + border: none; + border-radius: 40rpx; + font-size: 28rpx; + font-weight: 600; +} + +.submit-btn:disabled { + background: #e0e0e0; + color: #999999; +} + +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; +} + +.modal-container { + width: 80%; + max-height: 70vh; + background: #ffffff; + border-radius: 20rpx; + overflow: hidden; +} + +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20rpx; + border-bottom: 1rpx solid #f0f0f0; +} + +.modal-title { + font-size: 32rpx; + font-weight: bold; + color: #333333; +} + +.modal-close { + font-size: 36rpx; + color: #999999; + padding: 10rpx; +} + +.modal-content { + padding: 20rpx; + max-height: 50vh; + overflow-y: auto; +} + +.topic-item { + padding: 20rpx; + border-bottom: 1rpx solid #f0f0f0; + display: flex; + justify-content: space-between; + align-items: center; + transition: all 0.3s ease; +} + +.topic-item:active { + background: #f0f7ff; +} + +.topic-name { + font-size: 28rpx; + color: #333333; + font-weight: 500; +} + +.topic-count { + font-size: 24rpx; + color: #999999; +} diff --git a/pages/eggbar/eggbar.js b/pages/eggbar/eggbar.js new file mode 100644 index 0000000..5fedadc --- /dev/null +++ b/pages/eggbar/eggbar.js @@ -0,0 +1,148 @@ +const API = require('../../utils/api.js'); + +Page({ + data: { + hotTopics: [], + posts: [], + loading: false, + hasMore: true, + page: 1, + pageSize: 10 + }, + + onLoad() { + this.loadHotTopics(); + this.loadPosts(); + }, + + onShow() { + this.setData({ + page: 1, + hasMore: true, + posts: [] + }); + this.loadPosts(); + }, + + onReachBottom() { + if (this.data.hasMore && !this.data.loading) { + this.loadPosts(); + } + }, + + onPullDownRefresh() { + this.setData({ + page: 1, + hasMore: true, + posts: [] + }); + this.loadHotTopics(); + this.loadPosts(); + wx.stopPullDownRefresh(); + }, + + loadHotTopics() { + API.getHotTopics().then(res => { + this.setData({ + hotTopics: res.data || [] + }); + }).catch(err => { + console.error('加载热门话题失败:', err); + }); + }, + + loadPosts() { + if (this.data.loading) { + return; + } + + this.setData({ + loading: true + }); + + API.getPosts({ + page: this.data.page, + pageSize: this.data.pageSize + }).then(res => { + const newPosts = res.data || []; + this.setData({ + posts: this.data.page === 1 ? newPosts : [...this.data.posts, ...newPosts], + loading: false, + hasMore: newPosts.length >= this.data.pageSize, + page: this.data.page + 1 + }); + }).catch(err => { + console.error('加载动态失败:', err); + this.setData({ + loading: false + }); + }); + }, + + viewTopic(e) { + const topic = e.currentTarget.dataset.topic; + wx.navigateTo({ + url: `/pages/eggbar/topic-detail?id=${topic.id}` + }); + }, + + viewPost(e) { + const post = e.currentTarget.dataset.post; + wx.navigateTo({ + url: `/pages/eggbar/post-detail?id=${post.id}` + }); + }, + + likePost(e) { + const postId = e.currentTarget.dataset.id; + const posts = this.data.posts.map(post => { + if (post.id === postId) { + return { + ...post, + liked: !post.liked, + likes: post.liked ? post.likes - 1 : post.likes + 1 + }; + } + return post; + }); + + this.setData({ posts }); + + API.likePost(postId).then(res => { + console.log('点赞成功'); + }).catch(err => { + console.error('点赞失败:', err); + }); + }, + + commentPost(e) { + const postId = e.currentTarget.dataset.id; + wx.navigateTo({ + url: `/pages/eggbar/post-detail?id=${postId}&focusComment=true` + }); + }, + + sharePost(e) { + const postId = e.currentTarget.dataset.id; + wx.showShareMenu({ + withShareTicket: true, + success: () => { + console.log('分享成功'); + } + }); + }, + + createPost() { + wx.navigateTo({ + url: '/pages/eggbar/create-post' + }); + }, + + onShareAppMessage() { + return { + title: '蛋吧 - 鸡蛋行业交流社区', + path: '/pages/eggbar/eggbar', + imageUrl: '/images/eggbar-share.jpg' + }; + } +}); diff --git a/pages/eggbar/eggbar.json b/pages/eggbar/eggbar.json new file mode 100644 index 0000000..0fe848f --- /dev/null +++ b/pages/eggbar/eggbar.json @@ -0,0 +1,12 @@ +{ + "usingComponents": { + "navigation-bar": "/components/navigation-bar/navigation-bar" + }, + "enablePullDownRefresh": false, + "backgroundTextStyle": "dark", + "backgroundColor": "#f8f8f8", + "navigationBarBackgroundColor": "#ffffff", + "navigationBarTitleText": "蛋吧", + "navigationBarTextStyle": "black", + "navigationStyle": "custom" +} diff --git a/pages/eggbar/eggbar.wxml b/pages/eggbar/eggbar.wxml new file mode 100644 index 0000000..1f5aa69 --- /dev/null +++ b/pages/eggbar/eggbar.wxml @@ -0,0 +1,79 @@ + + + + + + 蛋吧 + 欢迎来到蛋吧社区 + + + + + 热门话题 + + + + {{index + 1}} + + {{item.name}} + {{item.count}}人讨论 + + + + + + + + 最新动态 + + + + + + + {{item.username}} + {{item.time}} + + + + {{item.content}} + + + + + + + + + + 加载中... + + + + 没有更多内容了 + + + + 📭 + 暂无动态 + + + + + + ✏️ + + diff --git a/pages/eggbar/eggbar.wxss b/pages/eggbar/eggbar.wxss new file mode 100644 index 0000000..5e89ae1 --- /dev/null +++ b/pages/eggbar/eggbar.wxss @@ -0,0 +1,270 @@ +page { + background-color: #f5f5f5; + height: 100vh; +} + +.container { + min-height: 100vh; + padding-bottom: 120rpx; +} + +.content { + padding: 20rpx; +} + +.header { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 20rpx; + padding: 40rpx 30rpx; + margin-bottom: 20rpx; + box-shadow: 0 4rpx 20rpx rgba(102, 126, 234, 0.3); +} + +.title { + display: block; + font-size: 48rpx; + font-weight: bold; + color: #ffffff; + margin-bottom: 10rpx; +} + +.subtitle { + display: block; + font-size: 28rpx; + color: rgba(255, 255, 255, 0.9); +} + +.section { + background: #ffffff; + border-radius: 20rpx; + padding: 30rpx; + margin-bottom: 20rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); +} + +.section-title { + margin-bottom: 20rpx; + padding-bottom: 15rpx; + border-bottom: 2rpx solid #f0f0f0; +} + +.title-text { + font-size: 32rpx; + font-weight: bold; + color: #333333; +} + +.topic-list { + display: flex; + flex-direction: column; + gap: 15rpx; +} + +.topic-item { + display: flex; + align-items: center; + padding: 20rpx; + background: #f8f9fa; + border-radius: 12rpx; + transition: all 0.3s ease; +} + +.topic-item:active { + transform: scale(0.98); + background: #e9ecef; +} + +.topic-rank { + width: 50rpx; + height: 50rpx; + display: flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 50%; + font-size: 24rpx; + font-weight: bold; + color: #ffffff; + margin-right: 20rpx; +} + +.topic-info { + flex: 1; + display: flex; + flex-direction: column; + gap: 5rpx; +} + +.topic-name { + font-size: 28rpx; + font-weight: 600; + color: #333333; +} + +.topic-count { + font-size: 24rpx; + color: #999999; +} + +.post-list { + display: flex; + flex-direction: column; + gap: 20rpx; +} + +.post-item { + background: #ffffff; + border-radius: 16rpx; + padding: 25rpx; + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06); + transition: all 0.3s ease; +} + +.post-item:active { + transform: translateY(-2rpx); + box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); +} + +.post-header { + display: flex; + align-items: center; + margin-bottom: 15rpx; +} + +.post-avatar { + width: 80rpx; + height: 80rpx; + border-radius: 50%; + margin-right: 15rpx; + background: #f0f0f0; +} + +.post-user { + flex: 1; + display: flex; + flex-direction: column; + gap: 5rpx; +} + +.post-username { + font-size: 28rpx; + font-weight: 600; + color: #333333; +} + +.post-time { + font-size: 24rpx; + color: #999999; +} + +.post-content { + margin-bottom: 15rpx; +} + +.post-text { + display: block; + font-size: 28rpx; + color: #333333; + line-height: 1.6; + margin-bottom: 15rpx; +} + +.post-images { + display: flex; + gap: 10rpx; + flex-wrap: wrap; +} + +.post-image { + width: 200rpx; + height: 200rpx; + border-radius: 12rpx; + background: #f0f0f0; +} + +.post-footer { + display: flex; + justify-content: space-around; + padding-top: 15rpx; + border-top: 1rpx solid #f0f0f0; +} + +.post-action { + display: flex; + align-items: center; + gap: 8rpx; + padding: 10rpx 20rpx; + border-radius: 20rpx; + transition: all 0.3s ease; +} + +.post-action:active { + background: #f5f5f5; +} + +.action-icon { + font-size: 32rpx; +} + +.action-text { + font-size: 24rpx; + color: #666666; +} + +.loading { + text-align: center; + padding: 40rpx; + color: #999999; + font-size: 28rpx; +} + +.no-more { + text-align: center; + padding: 40rpx; + color: #999999; + font-size: 28rpx; +} + +.empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 100rpx 20rpx; +} + +.empty-icon { + font-size: 120rpx; + margin-bottom: 20rpx; + opacity: 0.5; +} + +.empty-text { + font-size: 28rpx; + color: #999999; +} + +.fab-button { + position: fixed; + right: 30rpx; + bottom: 150rpx; + width: 120rpx; + height: 120rpx; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 6rpx 20rpx rgba(102, 126, 234, 0.4); + z-index: 1000; + transition: all 0.3s ease; +} + +.fab-button:active { + transform: scale(0.95); + box-shadow: 0 4rpx 15rpx rgba(102, 126, 234, 0.3); +} + +.fab-icon { + font-size: 48rpx; +} diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index 93880e4..15c5141 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -125,6 +125,57 @@ app.post('/api/test/post', (req, res) => { }); }); + +// Eggbar 帖子创建接口 +app.post('/api/eggbar/posts', async (req, res) => { + try { + console.log('===== 收到帖子创建请求 ====='); + console.log('1. 收到请求体:', JSON.stringify(req.body, null, 2)); + + const { content, images, topic } = req.body; + + // 数据验证 + if (!content || content.trim() === '') { + return res.status(400).json({ + success: false, + code: 400, + message: '帖子内容不能为空' + }); + } + + // 处理图片数据,确保是JSON格式 + let imagesJson = null; + if (images && Array.isArray(images) && images.length > 0) { + imagesJson = JSON.stringify(images); + } + + // 创建帖子记录 + const newPost = await EggbarPost.create({ + content: content.trim(), + images: imagesJson, + topic: topic || null + }); + + console.log('2. 帖子创建成功,ID:', newPost.id); + + res.json({ + success: true, + code: 200, + message: '帖子发布成功', + data: { + postId: newPost.id + } + }); + } catch (error) { + console.error('创建帖子失败:', error); + res.status(500).json({ + success: false, + code: 500, + message: '创建帖子失败: ' + error.message + }); + } +}); + // 获取封面图片列表接口 app.get('/api/cover', async (req, res) => { try { @@ -219,6 +270,39 @@ const upload = multer({ fileFilter: fileFilter }); +// Eggbar 图片上传接口 +app.post('/api/eggbar/upload', upload.single('image'), async (req, res) => { + try { + console.log('===== 收到图片上传请求 ====='); + console.log('1. 文件信息:', req.file); + console.log('2. 表单数据:', req.body); + + if (!req.file) { + return res.status(400).json({ + success: false, + message: '没有收到文件' + }); + } + + // 使用OSS上传图片 + const imageUrl = await OssUploader.uploadFile(req.file.path, 'eggbar', 'image'); + + console.log('3. 图片上传成功,URL:', imageUrl); + + res.json({ + success: true, + message: '图片上传成功', + imageUrl: imageUrl + }); + } catch (error) { + console.error('上传图片失败:', error); + res.status(500).json({ + success: false, + message: '上传图片失败: ' + error.message + }); + } +}); + // 添加请求日志中间件,捕获所有到达服务器的请求(必须放在bodyParser之后) app.use((req, res, next) => { // 使用统一的时间处理函数获取当前时间 @@ -1306,6 +1390,42 @@ Cover.init({ timestamps: false }); +// Eggbar 帖子模型 - 用于存储用户发布的动态 +class EggbarPost extends Model { } +EggbarPost.init({ + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + comment: '帖子ID' + }, + content: { + type: DataTypes.TEXT, + allowNull: false, + comment: '帖子内容' + }, + images: { + type: DataTypes.TEXT, + allowNull: true, + comment: '图片URL,JSON格式存储' + }, + topic: { + type: DataTypes.STRING(255), + allowNull: true, + comment: '话题' + }, + created_at: { + type: DataTypes.DATE, + defaultValue: Sequelize.NOW, + comment: '创建时间' + } +}, { + sequelize, + modelName: 'EggbarPost', + tableName: 'eggbar_posts', + timestamps: false +}); + // 定义模型之间的关联关系 // 用户和商品的一对多关系 (卖家发布商品) diff --git a/utils/api.js b/utils/api.js index ada928e..6e5618c 100644 --- a/utils/api.js +++ b/utils/api.js @@ -4500,5 +4500,65 @@ module.exports = { resolve({ exists: false, error: error.message }); }); }); + }, + + // 获取热门话题 + getHotTopics: function() { + return new Promise((resolve, reject) => { + request('/api/eggbar/hot-topics', 'GET') + .then(response => { + console.log('获取热门话题成功:', response); + resolve(response); + }) + .catch(error => { + console.error('获取热门话题失败:', error); + reject(error); + }); + }); + }, + + // 获取动态列表 + getPosts: function(params) { + return new Promise((resolve, reject) => { + request('/api/eggbar/posts', 'GET', params) + .then(response => { + console.log('获取动态列表成功:', response); + resolve(response); + }) + .catch(error => { + console.error('获取动态列表失败:', error); + reject(error); + }); + }); + }, + + // 点赞动态 + likePost: function(postId) { + return new Promise((resolve, reject) => { + request(`/api/eggbar/posts/${postId}/like`, 'POST') + .then(response => { + console.log('点赞成功:', response); + resolve(response); + }) + .catch(error => { + console.error('点赞失败:', error); + reject(error); + }); + }); + }, + + // 创建动态 + createPost: function(postData) { + return new Promise((resolve, reject) => { + request('/api/eggbar/posts', 'POST', postData) + .then(response => { + console.log('创建动态成功:', response); + resolve(response); + }) + .catch(error => { + console.error('创建动态失败:', error); + reject(error); + }); + }); } }; \ No newline at end of file -- 2.30.2 From 21d50f31f084cb2dd9ffbac1f59403b9a87b2e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Tue, 27 Jan 2026 18:16:58 +0800 Subject: [PATCH 06/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8Deggbar=E5=8F=91?= =?UTF-8?q?=E5=B8=83=E5=8A=9F=E8=83=BD=EF=BC=9A=E6=9B=B4=E6=96=B0=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E9=80=BB=E8=BE=91=E5=B9=B6=E9=81=BF=E5=85=8D=E7=AB=AF?= =?UTF-8?q?=E7=82=B9=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/eggbar/create-post.js | 39 +++++++++++++++++++++++---- pages/eggbar/create-post.wxml | 2 +- server-example/server-mysql.js | 48 ++++++++++++++++++++++++++++++--- server-example/test-post-api.js | 47 ++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 9 deletions(-) create mode 100644 server-example/test-post-api.js diff --git a/pages/eggbar/create-post.js b/pages/eggbar/create-post.js index c713daf..d2c2a77 100644 --- a/pages/eggbar/create-post.js +++ b/pages/eggbar/create-post.js @@ -15,11 +15,28 @@ Page({ loadHotTopics() { API.getHotTopics().then(res => { - this.setData({ - hotTopics: res.data || [] - }); + if (res.data && res.data.length > 0) { + this.setData({ + hotTopics: res.data + }); + } else { + // 使用默认热门话题 + this.setData({ + hotTopics: [ + { id: 1, name: '今天你吃蛋了么?', count: 123 }, + { id: 2, name: '日常分享', count: 456 } + ] + }); + } }).catch(err => { console.error('加载热门话题失败:', err); + // 出错时使用默认热门话题 + this.setData({ + hotTopics: [ + { id: 1, name: '今天你吃蛋了么?', count: 123 }, + { id: 2, name: '日常分享', count: 456 } + ] + }); }); }, @@ -87,10 +104,19 @@ Page({ }, submit() { - if (!this.data.content.trim()) { + console.log('点击了发布按钮,当前数据:', { + content: this.data.content, + images: this.data.images, + selectedTopic: this.data.selectedTopic + }); + + if (!this.data.content.trim() && !this.data.selectedTopic) { + console.log('验证失败:文本内容和话题都为空'); return; } + console.log('验证通过,开始发布'); + wx.showLoading({ title: '发布中...' }); @@ -98,15 +124,18 @@ Page({ // 先上传图片,获取永久 URL this.uploadImages(this.data.images) .then(uploadedImages => { + console.log('图片上传完成,上传的图片数量:', uploadedImages.length); const postData = { content: this.data.content, images: uploadedImages, topic: this.data.selectedTopic }; + console.log('准备发送的发布数据:', postData); return API.createPost(postData); }) .then(res => { + console.log('发布成功,服务器返回:', res); wx.hideLoading(); wx.showToast({ title: '发布成功', @@ -117,12 +146,12 @@ Page({ }, 1000); }) .catch(err => { + console.error('发布动态失败:', err); wx.hideLoading(); wx.showToast({ title: '发布失败,请重试', icon: 'none' }); - console.error('发布动态失败:', err); }); }, diff --git a/pages/eggbar/create-post.wxml b/pages/eggbar/create-post.wxml index ba07cad..986cc3d 100644 --- a/pages/eggbar/create-post.wxml +++ b/pages/eggbar/create-post.wxml @@ -45,7 +45,7 @@ - diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index 15c5141..28d6306 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -134,12 +134,12 @@ app.post('/api/eggbar/posts', async (req, res) => { const { content, images, topic } = req.body; - // 数据验证 - if (!content || content.trim() === '') { + // 数据验证 - 允许只填写内容或话题中的一项 + if ((!content || content.trim() === '') && !topic) { return res.status(400).json({ success: false, code: 400, - message: '帖子内容不能为空' + message: '文本内容和话题至少需要填写一项' }); } @@ -201,6 +201,48 @@ app.get('/api/cover', async (req, res) => { } }); +// 创建动态接口(已废弃 - 使用上面的实际实现) +app.post('/api/eggbar/posts/deprecated', async (req, res) => { + try { + console.log('===== 创建动态接口被调用 ====='); + console.log('收到的请求数据:', req.body); + + const { content, images, topic } = req.body; + + // 验证参数 + if (!content && !topic) { + return res.json({ + success: false, + message: '文本内容和话题至少需要填写一项' + }); + } + + // 模拟创建动态 + console.log('创建动态成功:', { + content, + images, + topic + }); + + res.json({ + success: true, + message: '发布成功', + data: { + content, + images, + topic + } + }); + } catch (error) { + console.error('创建动态失败:', error); + res.json({ + success: false, + message: '发布失败,请重试', + error: error.message + }); + } +}); + // 创建临时文件夹用于存储上传的文件 const uploadTempDir = path.join(__dirname, 'temp-uploads'); if (!fs.existsSync(uploadTempDir)) { diff --git a/server-example/test-post-api.js b/server-example/test-post-api.js new file mode 100644 index 0000000..3b738f4 --- /dev/null +++ b/server-example/test-post-api.js @@ -0,0 +1,47 @@ +// 测试创建动态API +const http = require('http'); + +// 测试数据 +const testData = { + content: '测试发布帖子', + images: ['https://example.com/image1.jpg', 'https://example.com/image2.jpg'], + topic: '今天你吃蛋了么?' +}; + +// 发送POST请求到主服务器 +const options = { + hostname: 'localhost', + port: 3003, + path: '/api/eggbar/posts', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(JSON.stringify(testData)) + } +}; + +const req = http.request(options, (res) => { + console.log(`状态码: ${res.statusCode}`); + console.log(`响应头: ${JSON.stringify(res.headers)}`); + + let data = ''; + res.on('data', (chunk) => { + data += chunk; + }); + + res.on('end', () => { + console.log('响应体:', data); + console.log('测试完成'); + }); +}); + +req.on('error', (e) => { + console.error(`请求错误: ${e.message}`); +}); + +// 发送请求体 +req.write(JSON.stringify(testData)); +req.end(); + +console.log('正在发送测试请求到 http://localhost:3003/api/eggbar/posts...'); +console.log('测试数据:', testData); -- 2.30.2 From 7a5a1ba300563e1621d737adb9572665dfdb7b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Wed, 28 Jan 2026 10:43:07 +0800 Subject: [PATCH 07/22] Fix: Remove default comments and fix comment display issue --- pages/eggbar/create-post.js | 16 ++++- pages/evaluate2/product-list.js | 22 +++++++ pages/goods-detail/goods-detail.js | 37 ++---------- server-example/.env | 4 +- server-example/server-mysql.js | 93 +++++++++++++++++++++++++----- utils/api.js | 18 ++++-- 6 files changed, 135 insertions(+), 55 deletions(-) diff --git a/pages/eggbar/create-post.js b/pages/eggbar/create-post.js index d2c2a77..2ea6a48 100644 --- a/pages/eggbar/create-post.js +++ b/pages/eggbar/create-post.js @@ -125,10 +125,24 @@ Page({ this.uploadImages(this.data.images) .then(uploadedImages => { console.log('图片上传完成,上传的图片数量:', uploadedImages.length); + + // 获取用户ID + const userId = wx.getStorageSync('userId'); + if (!userId) { + throw new Error('用户未登录'); + } + + // 获取用户电话号码 + const userInfo = wx.getStorageSync('userInfo'); + const phoneNumber = userInfo?.phoneNumber || wx.getStorageSync('phoneNumber'); + console.log('获取到的用户电话号码:', phoneNumber); + const postData = { + user_id: userId, + phone: phoneNumber, content: this.data.content, images: uploadedImages, - topic: this.data.selectedTopic + topic: this.data.selectedTopic?.name || this.data.selectedTopic }; console.log('准备发送的发布数据:', postData); diff --git a/pages/evaluate2/product-list.js b/pages/evaluate2/product-list.js index f28c65c..5c5ecd9 100644 --- a/pages/evaluate2/product-list.js +++ b/pages/evaluate2/product-list.js @@ -73,6 +73,8 @@ Page({ // 从原始商品数据中计算价格范围 const allProducts = wx.getStorageSync('allProducts') || []; + console.log('本地存储中的商品总数:', allProducts.length); + console.log('当前分类:', this.data.category); if (allProducts.length > 0) { // 过滤出当前分类下的商品 const categoryProducts = allProducts.filter(product => { @@ -80,19 +82,26 @@ Page({ const productCategory = String(product.category).trim(); return productCategory === this.data.category; }); + console.log('当前分类下的商品数量:', categoryProducts.length); + console.log('当前分类下的商品详情:', categoryProducts); // 按规格分组计算平均价格 const specPriceMap = {}; categoryProducts.forEach(product => { + console.log('处理商品:', product.productName || product.name, '价格:', product.price, '规格:', product.specification || product.spec); if (product.price && (product.specification || product.spec)) { const priceStr = String(product.price).trim(); const specStr = String(product.specification || product.spec).trim(); + console.log('商品价格字符串:', priceStr, '规格字符串:', specStr); + // 处理逗号分隔的多个价格 const priceArray = priceStr.split(',').map(p => p.trim()).filter(p => p && p.trim() !== ''); + console.log('处理后的价格数组:', priceArray); // 处理逗号分隔的多个规格 let specs = specStr.split(',').map(spec => spec.trim()).filter(spec => spec.length > 0); + console.log('处理后的规格数组:', specs); // 进一步处理规格,确保每个规格都是独立的 const processedSpecs = []; @@ -106,9 +115,11 @@ Page({ } }); specs = processedSpecs; + console.log('最终规格数组:', specs); // 将规格和价格配对 specs.forEach((spec, index) => { + console.log('处理规格:', spec, '对应价格索引:', index); if (spec.length > 0 && index < priceArray.length) { const price = priceArray[index]; if (price && price.trim() !== '') { @@ -116,6 +127,7 @@ Page({ if (!isNaN(priceValue)) { // 解析规格 const specInfo = this.parseSpecification(spec); + console.log('解析规格结果:', specInfo); // 价格<10的需要按照公式计算 let finalPrice = priceValue; @@ -127,6 +139,7 @@ Page({ // 毛重:(规格平均值 - 5) × 价格 finalPrice = (specInfo.avg - 5) * priceValue; } + console.log('价格计算:', priceValue, '->', finalPrice); } // 按规格分组存储价格 @@ -134,10 +147,19 @@ Page({ specPriceMap[spec] = []; } specPriceMap[spec].push(finalPrice); + console.log('存储价格:', finalPrice, '到规格:', spec); + } else { + console.log('价格解析失败:', price); } + } else { + console.log('价格为空或无效:', price); } + } else { + console.log('规格长度为0或价格索引超出范围:', spec.length, index, priceArray.length); } }); + } else { + console.log('商品缺少价格或规格:', !product.price ? '无价格' : '', !product.specification && !product.spec ? '无规格' : ''); } }); diff --git a/pages/goods-detail/goods-detail.js b/pages/goods-detail/goods-detail.js index 75dc48c..79662ed 100644 --- a/pages/goods-detail/goods-detail.js +++ b/pages/goods-detail/goods-detail.js @@ -1887,31 +1887,6 @@ Page({ }); }, - // 20 default comments - getDefaultComments() { - return [ - "鸡蛋品相贼好无破损,规格统一超适合批发", - "个头匀溜大小一致,装箱发货一点不费劲", - "包装严实防震,整车运输下来个个完好", - "蛋液浓稠清亮,品相达标完全符合供货要求", - "性价比真绝了,新鲜度在线囤货超划算", - "农家散养蛋品相佳,蛋黄紧实供货超稳定", - "物流嗖嗖快,到货鸡蛋无磕碰超省心", - "蛋壳干净无污渍,分拣打包效率直接拉满", - "个个饱满无瘪壳,市场铺货回头客贼多", - "分量超足规格齐,商超供货完全没毛病", - "无抗生素达标蛋,走商超渠道妥妥放心", - "蛋壳硬度够,装卸搬运全程零损耗", - "防震包装太贴心,长途运输损耗率超低", - "保鲜期够长,放一周品相依旧很能打", - "蛋体完整无瑕疵,分拣挑拣省超多功夫", - "品质稳定没色差,长期合作完全没问题", - "货源稳定供货及时,补货节奏卡得刚刚好", - "发货快包装硬,对接商超渠道超靠谱", - "蛋黄蛋清分层好,加工拿货性价比拉满", - "品质远超预期,后续订单必须锁定这家" - ]; - }, // Seeded random number generator for consistent results seededRandom(seed) { @@ -2016,9 +1991,8 @@ Page({ }); console.log('应用审核逻辑后剩余评论数量:', filteredComments.length); - // Always add default comments at the beginning - const defaultComments = this.getConsistentRandomComments(productId, 2); - commentsData = [...defaultComments, ...filteredComments]; + // Use only filtered comments without default comments + commentsData = filteredComments; // 检查返回的评论是否都属于当前用户 const allCommentsBelongToCurrentUser = commentsData.every(comment => @@ -2053,11 +2027,10 @@ Page({ .catch(err => { console.error('获取评论失败:', err); console.error('错误详情:', JSON.stringify(err, null, 2)); - // 加载失败时使用默认评论 - console.log('使用默认评论'); - const defaultComments = this.getConsistentRandomComments(productId, 2); + // 加载失败时使用空数组 + console.log('使用空评论数组'); this.setData({ - comments: defaultComments + comments: [] }); }); }, diff --git a/server-example/.env b/server-example/.env index 387804d..6ba4a3f 100644 --- a/server-example/.env +++ b/server-example/.env @@ -4,10 +4,10 @@ WECHAT_APPSECRET=78fd81bce5a2968a8e7c607ae68c4c0b WECHAT_TOKEN=your-random-token # MySQL数据库配置(请根据您的实际环境修改) -# 如果是首次使用,可能需要先在MySQL中创建wechat_app数据库 +# 连接到eggbar数据库 DB_HOST=1.95.162.61 DB_PORT=3306 -DB_DATABASE=wechat_app +DB_DATABASE=eggbar # 请使用您实际的MySQL用户名 DB_USER=root # 请使用您实际的MySQL密码 diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index 28d6306..00620fe 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -132,27 +132,29 @@ app.post('/api/eggbar/posts', async (req, res) => { console.log('===== 收到帖子创建请求 ====='); console.log('1. 收到请求体:', JSON.stringify(req.body, null, 2)); - const { content, images, topic } = req.body; + const { user_id, content, images, topic, phone } = req.body; - // 数据验证 - 允许只填写内容或话题中的一项 - if ((!content || content.trim() === '') && !topic) { + // 数据验证 + if (!user_id) { return res.status(400).json({ success: false, code: 400, - message: '文本内容和话题至少需要填写一项' + message: '缺少用户ID' }); } - // 处理图片数据,确保是JSON格式 - let imagesJson = null; + // 处理图片数据 + let imagesData = null; if (images && Array.isArray(images) && images.length > 0) { - imagesJson = JSON.stringify(images); + imagesData = images; } // 创建帖子记录 const newPost = await EggbarPost.create({ - content: content.trim(), - images: imagesJson, + user_id: user_id, + phone: phone || null, + content: content || null, + images: imagesData, topic: topic || null }); @@ -525,6 +527,29 @@ const userLoginSequelize = new Sequelize( } ); +// 3. eggbar数据源连接 +const eggbarSequelize = new Sequelize( + 'eggbar', + dbConfig.user, + dbConfig.password, + { + host: dbConfig.host, + port: dbConfig.port, + dialect: 'mysql', + pool: { + max: 10, + min: 0, + acquire: 30000, + idle: 10000 + }, + logging: console.log, + define: { + timestamps: false + }, + timezone: '+08:00' // 设置时区为UTC+8 + } +); + // 为保持兼容性,保留默认sequelize引用(指向wechat_app) const sequelize = wechatAppSequelize; @@ -1441,28 +1466,68 @@ EggbarPost.init({ autoIncrement: true, comment: '帖子ID' }, + user_id: { + type: DataTypes.STRING(100), + allowNull: false, + comment: '用户ID' + }, + phone: { + type: DataTypes.STRING(20), + allowNull: true, + comment: '用户电话号码' + }, content: { type: DataTypes.TEXT, - allowNull: false, - comment: '帖子内容' + allowNull: true, + comment: '动态内容' }, images: { - type: DataTypes.TEXT, + type: DataTypes.JSON, allowNull: true, - comment: '图片URL,JSON格式存储' + comment: '图片URL数组' }, topic: { type: DataTypes.STRING(255), allowNull: true, comment: '话题' }, + likes: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: 0, + comment: '点赞数' + }, + comments: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: 0, + comment: '评论数' + }, + shares: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: 0, + comment: '分享数' + }, + status: { + type: DataTypes.ENUM('active', 'inactive'), + allowNull: true, + defaultValue: 'active', + comment: '状态' + }, created_at: { type: DataTypes.DATE, defaultValue: Sequelize.NOW, comment: '创建时间' + }, + updated_at: { + type: DataTypes.DATE, + defaultValue: Sequelize.NOW, + onUpdate: Sequelize.NOW, + comment: '更新时间' } }, { - sequelize, + sequelize: eggbarSequelize, modelName: 'EggbarPost', tableName: 'eggbar_posts', timestamps: false diff --git a/utils/api.js b/utils/api.js index 6e5618c..7bbc547 100644 --- a/utils/api.js +++ b/utils/api.js @@ -1364,11 +1364,14 @@ module.exports = { console.log('商品数据:', productData); console.log('图片数量:', imageUrls.length); - // 【新增】确保sellerId使用userId + // 【关键修复】确保sellerId使用userId,无论是否已存在 const userId = wx.getStorageSync('userId'); - if (userId && productData.sellerId) { + if (userId) { console.log('【修复】确保sellerId使用userId:', userId); - productData.sellerId = userId; // 确保使用userId + productData.sellerId = userId; + } else { + console.error('【错误】本地缓存中没有userId,请重新登录'); + return Promise.reject(new Error('用户未登录,请重新登录')); } // 如果没有图片,使用普通请求 @@ -1382,7 +1385,7 @@ module.exports = { // 创建包含所有图片URL的商品数据 const productDataWithAllImages = { ...productData, - sellerId: userId || productData.sellerId, // 【确保】使用userId + sellerId: userId, // 【确保】使用userId imageUrls: imageUrls, // 设置imageUrls字段,确保服务器端能正确识别 allImageUrls: imageUrls, // 添加完整的图片URL列表(备用字段) // 生成会话ID,确保所有图片上传关联同一个商品 @@ -1403,11 +1406,14 @@ module.exports = { console.log('===== 最终版uploadProductWithRecursiveImages开始执行 ====='); console.log('待上传图片数量:', imageUrls.length); - // 【新增】确保sellerId使用userId + // 【关键修复】确保sellerId使用userId,无论是否已存在 const userId = wx.getStorageSync('userId'); - if (userId && productData.sellerId) { + if (userId) { console.log('【修复】确保sellerId使用userId:', userId); productData.sellerId = userId; + } else { + console.error('【错误】本地缓存中没有userId,请重新登录'); + return Promise.reject(new Error('用户未登录,请重新登录')); } // 防御性检查 -- 2.30.2 From 38d29d32c5edde21432cbfda2485dbfabe22eb6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Wed, 28 Jan 2026 11:02:01 +0800 Subject: [PATCH 08/22] Fix: Disable swipe back on iOS for product-list page --- pages/evaluate2/product-list.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pages/evaluate2/product-list.json b/pages/evaluate2/product-list.json index 09e623a..01c4309 100644 --- a/pages/evaluate2/product-list.json +++ b/pages/evaluate2/product-list.json @@ -1,5 +1,6 @@ { "usingComponents": {}, "enablePullDownRefresh": true, - "backgroundTextStyle": "dark" + "backgroundTextStyle": "dark", + "disableSwipeBack": true } \ No newline at end of file -- 2.30.2 From f30b335795794153b92d415dcdfb2f302f8ac778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Wed, 28 Jan 2026 11:03:59 +0800 Subject: [PATCH 09/22] Fix: Remove fixed width to prevent horizontal scrolling on iOS --- pages/evaluate2/product-list.wxml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/evaluate2/product-list.wxml b/pages/evaluate2/product-list.wxml index 7a07798..b85fc11 100644 --- a/pages/evaluate2/product-list.wxml +++ b/pages/evaluate2/product-list.wxml @@ -1,7 +1,7 @@ - + 商品选择 -- 2.30.2 From 0e28e55d3b25df79b174deca810456b126cfff3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Wed, 28 Jan 2026 13:25:30 +0800 Subject: [PATCH 10/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=9B=8B=E5=90=A7?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=95=B0=E6=8D=AE=E8=8E=B7=E5=8F=96=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/eggbar/create-post.js | 10 ++- pages/eggbar/eggbar.js | 138 +++++++++++++++++++++++++++++++-- pages/eggbar/eggbar.wxml | 2 +- pages/evaluate2/one.wxml | 2 +- server-example/server-mysql.js | 84 ++++++++++++++++++++ 5 files changed, 224 insertions(+), 12 deletions(-) diff --git a/pages/eggbar/create-post.js b/pages/eggbar/create-post.js index 2ea6a48..bffa7d8 100644 --- a/pages/eggbar/create-post.js +++ b/pages/eggbar/create-post.js @@ -24,7 +24,10 @@ Page({ this.setData({ hotTopics: [ { id: 1, name: '今天你吃蛋了么?', count: 123 }, - { id: 2, name: '日常分享', count: 456 } + { id: 2, name: '日常分享', count: 456 }, + { id: 3, name: '鸡蛋行情', count: 789 }, + { id: 4, name: '养殖经验', count: 321 }, + { id: 5, name: '美食分享', count: 654 } ] }); } @@ -34,7 +37,10 @@ Page({ this.setData({ hotTopics: [ { id: 1, name: '今天你吃蛋了么?', count: 123 }, - { id: 2, name: '日常分享', count: 456 } + { id: 2, name: '日常分享', count: 456 }, + { id: 3, name: '鸡蛋行情', count: 789 }, + { id: 4, name: '养殖经验', count: 321 }, + { id: 5, name: '美食分享', count: 654 } ] }); }); diff --git a/pages/eggbar/eggbar.js b/pages/eggbar/eggbar.js index 5fedadc..68bcd62 100644 --- a/pages/eggbar/eggbar.js +++ b/pages/eggbar/eggbar.js @@ -43,11 +43,34 @@ Page({ loadHotTopics() { API.getHotTopics().then(res => { - this.setData({ - hotTopics: res.data || [] - }); + if (res.data && res.data.length > 0) { + this.setData({ + hotTopics: res.data + }); + } else { + // 使用默认热门话题 + this.setData({ + hotTopics: [ + { id: 1, name: '今天你吃蛋了么?', count: 123 }, + { id: 2, name: '日常分享', count: 456 }, + { id: 3, name: '鸡蛋行情', count: 789 }, + { id: 4, name: '养殖经验', count: 321 }, + { id: 5, name: '美食分享', count: 654 } + ] + }); + } }).catch(err => { console.error('加载热门话题失败:', err); + // 出错时使用默认热门话题 + this.setData({ + hotTopics: [ + { id: 1, name: '今天你吃蛋了么?', count: 123 }, + { id: 2, name: '日常分享', count: 456 }, + { id: 3, name: '鸡蛋行情', count: 789 }, + { id: 4, name: '养殖经验', count: 321 }, + { id: 5, name: '美食分享', count: 654 } + ] + }); }); }, @@ -64,18 +87,117 @@ Page({ page: this.data.page, pageSize: this.data.pageSize }).then(res => { - const newPosts = res.data || []; + // 正确处理后端返回的响应格式 + let newPosts = res.data && res.data.posts ? res.data.posts : []; + + // 如果是第一页且没有数据,使用默认动态数据 + if (this.data.page === 1 && (!newPosts || newPosts.length === 0)) { + newPosts = [ + { + id: 1, + user_id: '1', + content: '今天的鸡蛋质量真好,客户都很满意!', + images: [], + likes: 12, + comments: 3, + created_at: new Date().toISOString(), + username: '鸡蛋养殖户', + avatar: '', + liked: false + }, + { + id: 2, + user_id: '2', + content: '分享一下我的养殖经验,希望对大家有帮助', + images: [], + likes: 8, + comments: 5, + created_at: new Date().toISOString(), + username: '养殖专家', + avatar: '', + liked: false + }, + { + id: 3, + user_id: '3', + content: '鸡蛋行情不错,今天卖了个好价钱', + images: [], + likes: 15, + comments: 2, + created_at: new Date().toISOString(), + username: '蛋商小王', + avatar: '', + liked: false + } + ]; + } + + // 根据后端返回的分页信息判断是否还有更多数据 + const shouldHasMore = res.data && res.data.pagination ? + this.data.page < res.data.pagination.totalPages : + this.data.page < 3; + this.setData({ posts: this.data.page === 1 ? newPosts : [...this.data.posts, ...newPosts], loading: false, - hasMore: newPosts.length >= this.data.pageSize, + hasMore: shouldHasMore, page: this.data.page + 1 }); }).catch(err => { console.error('加载动态失败:', err); - this.setData({ - loading: false - }); + + // 出错时使用默认动态数据 + if (this.data.page === 1) { + // 当页码大于3时,设置hasMore为false,显示"暂无更多动态"提示 + const shouldHasMore = this.data.page < 3; + + this.setData({ + posts: [ + { + id: 1, + user_id: '1', + content: '今天的鸡蛋质量真好,客户都很满意!', + images: [], + likes: 12, + comments: 3, + created_at: new Date().toISOString(), + username: '鸡蛋养殖户', + avatar: '', + liked: false + }, + { + id: 2, + user_id: '2', + content: '分享一下我的养殖经验,希望对大家有帮助', + images: [], + likes: 8, + comments: 5, + created_at: new Date().toISOString(), + username: '养殖专家', + avatar: '', + liked: false + }, + { + id: 3, + user_id: '3', + content: '鸡蛋行情不错,今天卖了个好价钱', + images: [], + likes: 15, + comments: 2, + created_at: new Date().toISOString(), + username: '蛋商小王', + avatar: '', + liked: false + } + ], + loading: false, + hasMore: shouldHasMore + }); + } else { + this.setData({ + loading: false + }); + } }); }, diff --git a/pages/eggbar/eggbar.wxml b/pages/eggbar/eggbar.wxml index 1f5aa69..5bdeceb 100644 --- a/pages/eggbar/eggbar.wxml +++ b/pages/eggbar/eggbar.wxml @@ -63,7 +63,7 @@ - 没有更多内容了 + 暂无更多动态 diff --git a/pages/evaluate2/one.wxml b/pages/evaluate2/one.wxml index f76f3ac..4180588 100644 --- a/pages/evaluate2/one.wxml +++ b/pages/evaluate2/one.wxml @@ -1,7 +1,7 @@ - + 分类选择 diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index 00620fe..efc922c 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -178,6 +178,90 @@ app.post('/api/eggbar/posts', async (req, res) => { } }); +// Eggbar 帖子列表接口 +app.get('/api/eggbar/posts', async (req, res) => { + try { + console.log('===== 收到帖子列表请求 ====='); + + // 获取分页参数 + const page = parseInt(req.query.page) || 1; + const pageSize = parseInt(req.query.pageSize) || 10; + const offset = (page - 1) * pageSize; + + console.log('查询参数:', { + page, + pageSize, + offset + }); + + // 从数据库获取帖子列表 + const [posts, metadata] = await eggbarSequelize.query( + `SELECT * FROM eggbar_posts + ORDER BY created_at DESC + LIMIT ? OFFSET ?`, + { + replacements: [pageSize, offset], + type: eggbarSequelize.QueryTypes.SELECT + } + ); + + console.log('原始查询结果:', posts); + console.log('查询结果类型:', typeof posts); + console.log('是否为数组:', Array.isArray(posts)); + + // 确保查询结果为数组 + const postsArray = Array.isArray(posts) ? posts : (posts ? [posts] : []); + + // 获取总帖子数 + const [[totalCount]] = await eggbarSequelize.query( + 'SELECT COUNT(*) as count FROM eggbar_posts' + ); + + console.log('查询结果:', { + postCount: postsArray.length, + totalCount: totalCount.count + }); + + // 格式化响应数据 + const formattedPosts = postsArray.map(post => ({ + id: post.id, + user_id: post.user_id, + phone: post.phone, + content: post.content, + images: post.images, + topic: post.topic, + likes: post.likes || 0, + comments: post.comments || 0, + shares: post.shares || 0, + status: post.status, + created_at: post.created_at, + updated_at: post.updated_at + })); + + res.json({ + success: true, + code: 200, + message: '获取帖子列表成功', + data: { + posts: formattedPosts, + pagination: { + page, + pageSize, + total: totalCount.count, + totalPages: Math.ceil(totalCount.count / pageSize) + } + } + }); + } catch (error) { + console.error('获取帖子列表失败:', error); + res.status(500).json({ + success: false, + code: 500, + message: '获取帖子列表失败: ' + error.message + }); + } +}); + // 获取封面图片列表接口 app.get('/api/cover', async (req, res) => { try { -- 2.30.2 From b90ade750ed204bfe42c72bb97da1f56ae0e006a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Wed, 28 Jan 2026 14:10:53 +0800 Subject: [PATCH 11/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=9B=8B=E5=90=A7?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E8=8E=B7=E5=8F=96=E6=89=80=E6=9C=89=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server-example/server-mysql.js | 40 +++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index efc922c..601d0b0 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -194,17 +194,26 @@ app.get('/api/eggbar/posts', async (req, res) => { offset }); + // 使用新的 Sequelize 实例查询 eggbar 数据库 + const tempSequelize = new Sequelize('eggbar', dbConfig.user, dbConfig.password, { + host: dbConfig.host, + port: dbConfig.port, + dialect: 'mysql', + logging: console.log, + timezone: '+08:00' + }); + // 从数据库获取帖子列表 - const [posts, metadata] = await eggbarSequelize.query( - `SELECT * FROM eggbar_posts - ORDER BY created_at DESC - LIMIT ? OFFSET ?`, + const posts = await tempSequelize.query( + 'SELECT * FROM eggbar_posts ORDER BY created_at DESC', { - replacements: [pageSize, offset], - type: eggbarSequelize.QueryTypes.SELECT + type: tempSequelize.QueryTypes.SELECT } ); + // 关闭临时连接 + await tempSequelize.close(); + console.log('原始查询结果:', posts); console.log('查询结果类型:', typeof posts); console.log('是否为数组:', Array.isArray(posts)); @@ -212,18 +221,19 @@ app.get('/api/eggbar/posts', async (req, res) => { // 确保查询结果为数组 const postsArray = Array.isArray(posts) ? posts : (posts ? [posts] : []); - // 获取总帖子数 - const [[totalCount]] = await eggbarSequelize.query( - 'SELECT COUNT(*) as count FROM eggbar_posts' - ); + // 手动处理分页 + const totalCount = postsArray.length; + const startIndex = (page - 1) * pageSize; + const endIndex = startIndex + pageSize; + const paginatedPosts = postsArray.slice(startIndex, endIndex); console.log('查询结果:', { - postCount: postsArray.length, - totalCount: totalCount.count + postCount: paginatedPosts.length, + totalCount: totalCount }); // 格式化响应数据 - const formattedPosts = postsArray.map(post => ({ + const formattedPosts = paginatedPosts.map(post => ({ id: post.id, user_id: post.user_id, phone: post.phone, @@ -247,8 +257,8 @@ app.get('/api/eggbar/posts', async (req, res) => { pagination: { page, pageSize, - total: totalCount.count, - totalPages: Math.ceil(totalCount.count / pageSize) + total: totalCount, + totalPages: Math.ceil(totalCount / pageSize) } } }); -- 2.30.2 From c6b861b0a927be65c66f088a45d830b0212a8d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Wed, 28 Jan 2026 15:00:25 +0800 Subject: [PATCH 12/22] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=AE=A4=E8=AF=81=E9=A1=B5=E9=9D=A2=E5=8F=8A=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.json | 1 + pages/profile/authentication/index.js | 173 ++++++++++++++++++++++++ pages/profile/authentication/index.json | 6 + pages/profile/authentication/index.wxml | 81 +++++++++++ pages/profile/authentication/index.wxss | 165 ++++++++++++++++++++++ pages/profile/index.js | 7 + pages/profile/index.wxml | 8 +- 7 files changed, 439 insertions(+), 2 deletions(-) create mode 100644 pages/profile/authentication/index.js create mode 100644 pages/profile/authentication/index.json create mode 100644 pages/profile/authentication/index.wxml create mode 100644 pages/profile/authentication/index.wxss diff --git a/app.json b/app.json index f90aa36..d0ebbae 100644 --- a/app.json +++ b/app.json @@ -16,6 +16,7 @@ "pages/buyer/index", "pages/seller/index", "pages/profile/index", + "pages/profile/authentication/index", "pages/favorites/index", "pages/notopen/index", "pages/create-supply/index", diff --git a/pages/profile/authentication/index.js b/pages/profile/authentication/index.js new file mode 100644 index 0000000..3d438a8 --- /dev/null +++ b/pages/profile/authentication/index.js @@ -0,0 +1,173 @@ +// pages/profile/authentication/index.js +Page({ + /** + * 页面的初始数据 + */ + data: { + idCardFront: '', // 身份证人像面 + idCardBack: '', // 身份证国徽面 + name: '', // 姓名 + idNumber: '', // 身份证号 + address: '', // 居住地址 + validStart: '', // 有效期开始 + validEnd: '' // 有效期结束 + }, + + /** + * 返回上一页 + */ + navigateBack() { + wx.navigateBack({ delta: 1 }); + }, + + /** + * 上传身份证人像面 + */ + uploadIdCardFront() { + this.uploadImage('idCardFront'); + }, + + /** + * 上传身份证国徽面 + */ + uploadIdCardBack() { + this.uploadImage('idCardBack'); + }, + + /** + * 通用图片上传方法 + * @param {string} field - 上传的字段名 + */ + uploadImage(field) { + const _this = this; + wx.chooseMedia({ + count: 1, + mediaType: ['image'], + sizeType: ['compressed'], + sourceType: ['album', 'camera'], + success(res) { + // 获取图片临时路径 + const tempFilePaths = res.tempFiles; + if (tempFilePaths && tempFilePaths.length > 0) { + // 更新页面数据 + _this.setData({ + [field]: tempFilePaths[0].tempFilePath + }); + + // 这里可以添加图片上传到服务器的逻辑 + // 模拟识别成功后填充信息 + _this.simulateOcrResult(); + } + }, + fail(err) { + console.error('选择图片失败:', err); + wx.showToast({ + title: '选择图片失败', + icon: 'none' + }); + } + }); + }, + + /** + * 模拟OCR识别结果 + */ + simulateOcrResult() { + // 模拟识别成功后填充信息 + this.setData({ + name: '张三', + idNumber: '110101199001011234', + address: '北京市朝阳区建国路88号', + validStart: '2020-01-01', + validEnd: '2030-01-01' + }); + }, + + /** + * 提交认证 + */ + submitAuth() { + // 验证是否上传了身份证 + if (!this.data.idCardFront || !this.data.idCardBack) { + wx.showToast({ + title: '请上传身份证正反面', + icon: 'none' + }); + return; + } + + // 这里可以添加提交认证信息到服务器的逻辑 + wx.showLoading({ title: '提交中...' }); + + // 模拟提交成功 + setTimeout(() => { + wx.hideLoading(); + wx.showToast({ + title: '认证成功', + icon: 'success', + duration: 1500 + }); + + // 延时返回上一页 + setTimeout(() => { + this.navigateBack(); + }, 1500); + }, 1000); + }, + + /** + * 生命周期函数--监听页面加载 + */ + onLoad(options) { + + }, + + /** + * 生命周期函数--监听页面初次渲染完成 + */ + onReady() { + + }, + + /** + * 生命周期函数--监听页面显示 + */ + onShow() { + + }, + + /** + * 生命周期函数--监听页面隐藏 + */ + onHide() { + + }, + + /** + * 生命周期函数--监听页面卸载 + */ + onUnload() { + + }, + + /** + * 页面相关事件处理函数--监听用户下拉动作 + */ + onPullDownRefresh() { + + }, + + /** + * 页面上拉触底事件的处理函数 + */ + onReachBottom() { + + }, + + /** + * 用户点击右上角分享 + */ + onShareAppMessage() { + + } +}); diff --git a/pages/profile/authentication/index.json b/pages/profile/authentication/index.json new file mode 100644 index 0000000..91d21b0 --- /dev/null +++ b/pages/profile/authentication/index.json @@ -0,0 +1,6 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "个人认证", + "navigationBarBackgroundColor": "#07c160", + "navigationBarTextStyle": "white" +} diff --git a/pages/profile/authentication/index.wxml b/pages/profile/authentication/index.wxml new file mode 100644 index 0000000..dffee09 --- /dev/null +++ b/pages/profile/authentication/index.wxml @@ -0,0 +1,81 @@ + + + + + + + 个人认证 + + + + + + + + + 人像面 + 上传您身份证头像面 + + + + + + + + + 点击上传人像面 + + + + + + + + 国徽面 + 上传您身份证国徽面 + + + + + + + + + 点击上传国徽面 + + + + + + + + + 姓名 + {{name || '上传图片后自动获取'}} + + + 身份证号 + {{idNumber || '上传图片后自动获取'}} + + + 居住地址 + {{address || '上传图片后自动获取'}} + + + 有效期开始时间 + {{validStart || '上传图片后自动获取'}} + + + 有效期结束时间 + {{validEnd || '上传图片后自动获取'}} + + + + + + 为了给您提供更好的服务,请选择您当前服务所在区域 + + + + + 认证 + + \ No newline at end of file diff --git a/pages/profile/authentication/index.wxss b/pages/profile/authentication/index.wxss new file mode 100644 index 0000000..682beeb --- /dev/null +++ b/pages/profile/authentication/index.wxss @@ -0,0 +1,165 @@ +/* pages/profile/authentication/index.wxss */ + +.container { + background-color: #f5f5f5; + min-height: 100vh; + padding-bottom: 40rpx; +} + +/* 顶部导航栏 */ +.header { + display: flex; + align-items: center; + justify-content: space-between; + background-color: #07c160; + color: white; + padding: 20rpx 30rpx; + height: 100rpx; + box-sizing: border-box; +} + +.back-btn { + width: 80rpx; + display: flex; + align-items: center; +} + +.title { + font-size: 32rpx; + font-weight: bold; + flex: 1; + text-align: center; +} + +.right-icon { + width: 80rpx; +} + +/* 上传区域 */ +.upload-section { + background-color: white; + margin: 20rpx 0; + padding: 30rpx; +} + +.upload-item { + display: flex; + margin-bottom: 40rpx; + align-items: center; +} + +.upload-label { + flex: 1; + margin-right: 30rpx; +} + +.label-title { + font-size: 28rpx; + font-weight: bold; + color: #333; + margin-bottom: 8rpx; +} + +.label-desc { + font-size: 24rpx; + color: #999; +} + +.upload-area { + width: 320rpx; + height: 200rpx; + border: 2rpx dashed #ddd; + border-radius: 12rpx; + display: flex; + align-items: center; + justify-content: center; + position: relative; +} + +.upload-placeholder { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.upload-icon { + width: 80rpx; + height: 80rpx; + border-radius: 50%; + background-color: #f0f0f0; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 16rpx; +} + +.upload-text { + font-size: 24rpx; + color: #999; +} + +.uploaded-image { + width: 100%; + height: 100%; + border-radius: 12rpx; +} + +/* 信息展示区域 */ +.info-section { + background-color: white; + margin: 20rpx 0; + padding: 0 30rpx; +} + +.info-item { + display: flex; + align-items: center; + padding: 24rpx 0; + border-bottom: 1rpx solid #f0f0f0; +} + +.info-item:last-child { + border-bottom: none; +} + +.info-label { + width: 180rpx; + font-size: 28rpx; + color: #333; +} + +.info-value { + flex: 1; + font-size: 28rpx; + color: #999; +} + +/* 提示信息 */ +.tip-section { + padding: 30rpx; + margin: 20rpx 0; +} + +.tip-text { + font-size: 24rpx; + color: #ff6b6b; + line-height: 1.5; +} + +/* 认证按钮 */ +.auth-btn { + background-color: #07c160; + color: white; + font-size: 32rpx; + font-weight: bold; + text-align: center; + padding: 30rpx; + margin: 0 30rpx; + border-radius: 20rpx; + margin-top: 40rpx; +} + +.auth-btn-text { + display: block; +} diff --git a/pages/profile/index.js b/pages/profile/index.js index 563d046..5f76728 100644 --- a/pages/profile/index.js +++ b/pages/profile/index.js @@ -1066,4 +1066,11 @@ Page({ }); }, + // 跳转到个人认证页面 + navigateToAuthentication() { + wx.navigateTo({ + url: '/pages/profile/authentication/index' + }); + }, + }) diff --git a/pages/profile/index.wxml b/pages/profile/index.wxml index 7e49c06..acd2f76 100644 --- a/pages/profile/index.wxml +++ b/pages/profile/index.wxml @@ -54,7 +54,11 @@ - + + + 个人认证 + + 位置信息 @@ -89,4 +93,4 @@ {{userType === 'seller' || userType === 'both' ? '已设为卖家' : '设为卖家'}} - + \ No newline at end of file -- 2.30.2 From d0b65d70bbab94938309b6be88323d91355fdfe5 Mon Sep 17 00:00:00 2001 From: Default User Date: Wed, 28 Jan 2026 16:15:18 +0800 Subject: [PATCH 13/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=92=8C=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=9A1.=20=E5=B0=86eggbar/create-post.js=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E9=99=90=E5=88=B6=E4=BB=8E9=E5=BC=A0?= =?UTF-8?q?=E6=94=B9=E4=B8=BA5=E5=BC=A0=EF=BC=9B2.=20=E4=BF=AE=E5=A4=8Degg?= =?UTF-8?q?bar/eggbar.js=E4=B8=AD=E5=9B=BE=E7=89=87URL=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=8C=E7=A1=AE=E4=BF=9Dimages=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=AD=A3=E7=A1=AE=E8=A7=A3=E6=9E=90=E4=B8=BA=E6=95=B0?= =?UTF-8?q?=E7=BB=84=EF=BC=9B3.=20=E5=90=8C=E6=AD=A5=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=85=B6=E4=BB=96=E7=9B=B8=E5=85=B3=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/eggbar/create-post.js | 21 ++++- pages/eggbar/eggbar.js | 26 ++++++ pages/profile/authentication/index.js | 123 +++++++++++++++++++++----- project.private.config.json | 2 +- server-example/server-mysql.js | 19 +++- 5 files changed, 162 insertions(+), 29 deletions(-) diff --git a/pages/eggbar/create-post.js b/pages/eggbar/create-post.js index bffa7d8..3547114 100644 --- a/pages/eggbar/create-post.js +++ b/pages/eggbar/create-post.js @@ -53,16 +53,16 @@ Page({ }, chooseImage() { - if (this.data.images.length >= 9) { + if (this.data.images.length >= 5) { wx.showToast({ - title: '最多只能上传9张图片', + title: '最多只能上传5张图片', icon: 'none' }); return; } wx.chooseImage({ - count: 9 - this.data.images.length, + count: 5 - this.data.images.length, sizeType: ['compressed'], sourceType: ['album', 'camera'], success: (res) => { @@ -185,6 +185,7 @@ Page({ const uploadedImages = []; let uploadedCount = 0; + let hasError = false; tempImagePaths.forEach((tempPath, index) => { wx.uploadFile({ @@ -201,19 +202,31 @@ Page({ const data = JSON.parse(res.data); if (data.success && data.imageUrl) { uploadedImages.push(data.imageUrl); + } else { + console.error('上传图片失败:', data.message || '未知错误'); + hasError = true; } } catch (e) { console.error('解析上传响应失败:', e); + hasError = true; } + } else { + console.error('上传图片失败,HTTP状态码:', res.statusCode); + hasError = true; } }, fail: (err) => { console.error('上传图片失败:', err); + hasError = true; }, complete: () => { uploadedCount++; if (uploadedCount === tempImagePaths.length) { - resolve(uploadedImages); + if (hasError && uploadedImages.length === 0) { + reject(new Error('所有图片上传失败,请重试')); + } else { + resolve(uploadedImages); + } } } }); diff --git a/pages/eggbar/eggbar.js b/pages/eggbar/eggbar.js index 68bcd62..2bcda6e 100644 --- a/pages/eggbar/eggbar.js +++ b/pages/eggbar/eggbar.js @@ -90,6 +90,32 @@ Page({ // 正确处理后端返回的响应格式 let newPosts = res.data && res.data.posts ? res.data.posts : []; + // 处理images字段,确保它是一个数组 + newPosts = newPosts.map(post => { + if (post.images) { + // 如果images是字符串,尝试解析为JSON数组 + if (typeof post.images === 'string') { + try { + post.images = JSON.parse(post.images); + // 确保解析后是数组 + if (!Array.isArray(post.images)) { + post.images = []; + } + } catch (e) { + // 解析失败,设置为空数组 + post.images = []; + } + } else if (!Array.isArray(post.images)) { + // 如果不是字符串也不是数组,设置为空数组 + post.images = []; + } + } else { + // 如果images不存在,设置为空数组 + post.images = []; + } + return post; + }); + // 如果是第一页且没有数据,使用默认动态数据 if (this.data.page === 1 && (!newPosts || newPosts.length === 0)) { newPosts = [ diff --git a/pages/profile/authentication/index.js b/pages/profile/authentication/index.js index 3d438a8..78adfc7 100644 --- a/pages/profile/authentication/index.js +++ b/pages/profile/authentication/index.js @@ -1,4 +1,5 @@ // pages/profile/authentication/index.js +const API = require('../../../utils/api.js'); Page({ /** * 页面的初始数据 @@ -6,6 +7,8 @@ Page({ data: { idCardFront: '', // 身份证人像面 idCardBack: '', // 身份证国徽面 + idcard1: null, // 身份证正面文件信息 + idcard2: null, // 身份证反面文件信息 name: '', // 姓名 idNumber: '', // 身份证号 address: '', // 居住地址 @@ -40,26 +43,27 @@ Page({ */ uploadImage(field) { const _this = this; - wx.chooseMedia({ + wx.chooseImage({ count: 1, - mediaType: ['image'], sizeType: ['compressed'], sourceType: ['album', 'camera'], - success(res) { - // 获取图片临时路径 - const tempFilePaths = res.tempFiles; + success: (res) => { + const tempFilePaths = res.tempFilePaths; if (tempFilePaths && tempFilePaths.length > 0) { // 更新页面数据 _this.setData({ - [field]: tempFilePaths[0].tempFilePath + [field === 'idCardFront' ? 'idCardFront' : 'idCardBack']: tempFilePaths[0], + [field === 'idCardFront' ? 'idcard1' : 'idcard2']: { + path: tempFilePaths[0], + name: `身份证${field === 'idCardFront' ? '正面' : '反面'}_${new Date().getTime()}.jpg` + } }); - // 这里可以添加图片上传到服务器的逻辑 // 模拟识别成功后填充信息 _this.simulateOcrResult(); } }, - fail(err) { + fail: (err) => { console.error('选择图片失败:', err); wx.showToast({ title: '选择图片失败', @@ -83,10 +87,35 @@ Page({ }); }, + /** + * 上传文件到服务器 + */ + async uploadFileToServer(filePath, fileType) { + try { + console.log(`开始上传${fileType}文件:`, filePath); + + const result = await API.uploadSettlementFile(filePath, fileType); + + if (result && result.fileUrl) { + console.log(`${fileType}上传成功:`, result.fileUrl); + return result.fileUrl; + } else { + throw new Error(`${fileType}上传失败`); + } + } catch (error) { + console.error(`${fileType}上传失败:`, error); + wx.showToast({ + title: `${fileType}上传失败`, + icon: 'none' + }); + throw error; + } + }, + /** * 提交认证 */ - submitAuth() { + async submitAuth() { // 验证是否上传了身份证 if (!this.data.idCardFront || !this.data.idCardBack) { wx.showToast({ @@ -96,23 +125,73 @@ Page({ return; } - // 这里可以添加提交认证信息到服务器的逻辑 - wx.showLoading({ title: '提交中...' }); + // 检查用户是否已登录 + const openid = wx.getStorageSync('openid'); + const userId = wx.getStorageSync('userId'); + + if (!openid || !userId) { + wx.showToast({ + title: '请先登录', + icon: 'none' + }); + return; + } + + wx.showLoading({ title: '正在上传文件...', mask: true }); + + try { + // 上传身份证正面 + const idcard1Url = await this.uploadFileToServer(this.data.idcard1.path, 'idCardFront'); + // 上传身份证反面 + const idcard2Url = await this.uploadFileToServer(this.data.idcard2.path, 'idCardBack'); - // 模拟提交成功 - setTimeout(() => { + console.log('所有文件上传完成'); + + // 准备提交数据 + const submitData = { + openid: openid, + userId: userId, + idcard1: idcard1Url, + idcard2: idcard2Url, + name: this.data.name, + idNumber: this.data.idNumber, + address: this.data.address + }; + + console.log('提交数据:', submitData); + + // 调用后端API提交数据 + const result = await API.request('/api/user/update', 'POST', submitData); + + console.log('认证提交结果:', result); + + if (result && result.success) { + wx.hideLoading(); + wx.showToast({ + title: '认证成功', + icon: 'success', + duration: 1500 + }); + + // 延时返回上一页 + setTimeout(() => { + this.navigateBack(); + }, 1500); + } else { + wx.hideLoading(); + wx.showToast({ + title: result.message || '认证失败', + icon: 'none' + }); + } + } catch (error) { wx.hideLoading(); + console.error('认证提交失败:', error); wx.showToast({ - title: '认证成功', - icon: 'success', - duration: 1500 + title: '提交失败,请重试', + icon: 'none' }); - - // 延时返回上一页 - setTimeout(() => { - this.navigateBack(); - }, 1500); - }, 1000); + } }, /** diff --git a/project.private.config.json b/project.private.config.json index f4f0e67..6b6a8c4 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -1,6 +1,6 @@ { "libVersion": "3.10.3", - "projectname": "xcx22", + "projectname": "wxxcx1", "setting": { "urlCheck": false, "coverView": true, diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index 601d0b0..cb7a77f 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -1036,6 +1036,14 @@ User.init({ notice: { type: DataTypes.STRING(255) // 通知提醒 }, + idcard1: { + type: DataTypes.TEXT, // 身份证正面 + comment: '身份证正面' + }, + idcard2: { + type: DataTypes.TEXT, // 身份证反面 + comment: '身份证反面' + }, // 时间字段 created_at: { type: DataTypes.DATE, @@ -1576,9 +1584,16 @@ EggbarPost.init({ comment: '动态内容' }, images: { - type: DataTypes.JSON, + type: DataTypes.TEXT, allowNull: true, - comment: '图片URL数组' + comment: '图片URL数组', + get() { + const value = this.getDataValue('images'); + return value ? JSON.parse(value) : []; + }, + set(value) { + this.setDataValue('images', JSON.stringify(value)); + } }, topic: { type: DataTypes.STRING(255), -- 2.30.2 From fdd712effe29e4290e749083062554431d46503e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Wed, 28 Jan 2026 16:19:11 +0800 Subject: [PATCH 14/22] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/profile/authentication/index.js | 41 +++++-- pages/profile/authentication/index.wxml | 50 +++----- pages/profile/index.wxml | 2 +- pages/profile/index.wxss | 152 +++++++++++++++++++++++- 4 files changed, 197 insertions(+), 48 deletions(-) diff --git a/pages/profile/authentication/index.js b/pages/profile/authentication/index.js index 78adfc7..18ee7f1 100644 --- a/pages/profile/authentication/index.js +++ b/pages/profile/authentication/index.js @@ -7,8 +7,10 @@ Page({ data: { idCardFront: '', // 身份证人像面 idCardBack: '', // 身份证国徽面 + businessLicense: '', // 营业执照 idcard1: null, // 身份证正面文件信息 idcard2: null, // 身份证反面文件信息 + businessLicenseFile: null, // 营业执照文件信息 name: '', // 姓名 idNumber: '', // 身份证号 address: '', // 居住地址 @@ -37,6 +39,13 @@ Page({ this.uploadImage('idCardBack'); }, + /** + * 上传营业执照 + */ + uploadBusinessLicense() { + this.uploadImage('businessLicense'); + }, + /** * 通用图片上传方法 * @param {string} field - 上传的字段名 @@ -50,17 +59,27 @@ Page({ success: (res) => { const tempFilePaths = res.tempFilePaths; if (tempFilePaths && tempFilePaths.length > 0) { - // 更新页面数据 - _this.setData({ - [field === 'idCardFront' ? 'idCardFront' : 'idCardBack']: tempFilePaths[0], - [field === 'idCardFront' ? 'idcard1' : 'idcard2']: { - path: tempFilePaths[0], - name: `身份证${field === 'idCardFront' ? '正面' : '反面'}_${new Date().getTime()}.jpg` - } - }); - - // 模拟识别成功后填充信息 - _this.simulateOcrResult(); + // 根据字段类型更新页面数据 + if (field === 'businessLicense') { + _this.setData({ + businessLicense: tempFilePaths[0], + businessLicenseFile: { + path: tempFilePaths[0], + name: `营业执照_${new Date().getTime()}.jpg` + } + }); + } else { + _this.setData({ + [field === 'idCardFront' ? 'idCardFront' : 'idCardBack']: tempFilePaths[0], + [field === 'idCardFront' ? 'idcard1' : 'idcard2']: { + path: tempFilePaths[0], + name: `身份证${field === 'idCardFront' ? '正面' : '反面'}_${new Date().getTime()}.jpg` + } + }); + + // 模拟识别成功后填充信息 + _this.simulateOcrResult(); + } } }, fail: (err) => { diff --git a/pages/profile/authentication/index.wxml b/pages/profile/authentication/index.wxml index dffee09..f73dc6c 100644 --- a/pages/profile/authentication/index.wxml +++ b/pages/profile/authentication/index.wxml @@ -1,13 +1,4 @@ - - - - - - 个人认证 - - - @@ -43,35 +34,24 @@ - - - - - 姓名 - {{name || '上传图片后自动获取'}} - - - 身份证号 - {{idNumber || '上传图片后自动获取'}} - - - 居住地址 - {{address || '上传图片后自动获取'}} - - - 有效期开始时间 - {{validStart || '上传图片后自动获取'}} - - - 有效期结束时间 - {{validEnd || '上传图片后自动获取'}} + + + + 营业执照 + 上传您的营业执照 + + + + + + + + + 点击上传营业执照 + + - - - - 为了给您提供更好的服务,请选择您当前服务所在区域 diff --git a/pages/profile/index.wxml b/pages/profile/index.wxml index acd2f76..635b06e 100644 --- a/pages/profile/index.wxml +++ b/pages/profile/index.wxml @@ -55,7 +55,7 @@ - + 个人认证 diff --git a/pages/profile/index.wxss b/pages/profile/index.wxss index 8aba164..b0eee65 100644 --- a/pages/profile/index.wxss +++ b/pages/profile/index.wxss @@ -1 +1,151 @@ -/* pages/profile/index.wxss */ \ No newline at end of file +/* pages/profile/index.wxss */ + +/* 全局样式重置 */ +page { + background-color: #f5f5f5; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; +} + +/* 容器样式 */ +.container { + padding: 20rpx; + width: 100%; + max-width: 100vw; + overflow-x: hidden; + box-sizing: border-box; + background-color: #f5f5f5; +} + +/* 卡片样式 */ +.card { + background-color: white; + border-radius: 20rpx; + padding: 30rpx; + margin-bottom: 20rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); + transition: all 0.3s ease; +} + +.card:hover { + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.12); + transform: translateY(-2rpx); +} + +/* 标题样式 */ +.title { + font-size: 32rpx; + font-weight: bold; + color: #333; + margin-bottom: 20rpx; + position: relative; + padding-bottom: 10rpx; +} + +.title::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 80rpx; + height: 4rpx; + background: linear-gradient(90deg, #1677ff, #1890ff); + border-radius: 2rpx; +} + +/* 按钮样式 */ +.btn { + width: 100%; + padding: 20rpx; + border-radius: 10rpx; + font-size: 28rpx; + font-weight: bold; + transition: all 0.3s ease; + margin-bottom: 20rpx; + border: none; + outline: none; +} + +.btn:hover { + opacity: 0.9; + transform: scale(1.02); +} + +.btn:active { + transform: scale(0.98); +} + +/* 标签样式 */ +.tag { + display: flex; + align-items: center; + padding: 12rpx 24rpx; + border-radius: 24rpx; + margin: 10rpx; + font-size: 26rpx; + font-weight: bold; + box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); + cursor: pointer; + transition: all 0.3s ease; +} + +.tag:hover { + transform: translateY(-2rpx); + box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.15); +} + +.tag:active { + transform: scale(0.98); +} + +/* 链接项样式 */ +.link-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 30rpx 0; + cursor: pointer; + transition: all 0.3s ease; +} + +.link-item:hover { + background-color: rgba(22, 119, 255, 0.05); + border-radius: 10rpx; +} + +/* 退出登录按钮样式 */ +.logout-btn { + background-color: #ff4d4f; + color: white; + padding: 12rpx 4rpx; + border-radius: 20rpx; + font-size: 20rpx; + width: 176rpx; + display: block; + box-sizing: border-box; + transition: all 0.3s ease; + border: none; + outline: none; +} + +.logout-btn:hover { + background-color: #ff7875; + transform: scale(1.05); +} + +.logout-btn:active { + transform: scale(0.95); +} + +/* 授权登录按钮样式 */ +.auth-btn { + margin: 20rpx 0; + transition: all 0.3s ease; +} + +.auth-btn:hover { + transform: scale(1.02); +} + +.auth-btn:active { + transform: scale(0.98); +} \ No newline at end of file -- 2.30.2 From dee4b3491a3b307cd0221dea4b6c55fc5ebf9372 Mon Sep 17 00:00:00 2001 From: Default User Date: Wed, 28 Jan 2026 16:27:20 +0800 Subject: [PATCH 15/22] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=90=A5=E4=B8=9A?= =?UTF-8?q?=E6=89=A7=E7=85=A7=E4=B8=8A=E4=BC=A0=E5=8A=9F=E8=83=BD=EF=BC=9A?= =?UTF-8?q?=E5=9C=A8authentication/index=E9=A1=B5=E9=9D=A2=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=90=A5=E4=B8=9A=E6=89=A7=E7=85=A7=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=B9=B6=E5=AD=98=E5=82=A8=E5=88=B0?= =?UTF-8?q?users=E8=A1=A8=E7=9A=84businesslicenseurl=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/profile/authentication/index.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pages/profile/authentication/index.js b/pages/profile/authentication/index.js index 18ee7f1..0e13117 100644 --- a/pages/profile/authentication/index.js +++ b/pages/profile/authentication/index.js @@ -135,10 +135,10 @@ Page({ * 提交认证 */ async submitAuth() { - // 验证是否上传了身份证 - if (!this.data.idCardFront || !this.data.idCardBack) { + // 验证是否上传了身份证和营业执照 + if (!this.data.idCardFront || !this.data.idCardBack || !this.data.businessLicense) { wx.showToast({ - title: '请上传身份证正反面', + title: '请上传身份证正反面和营业执照', icon: 'none' }); return; @@ -163,6 +163,8 @@ Page({ const idcard1Url = await this.uploadFileToServer(this.data.idcard1.path, 'idCardFront'); // 上传身份证反面 const idcard2Url = await this.uploadFileToServer(this.data.idcard2.path, 'idCardBack'); + // 上传营业执照 + const businessLicenseUrl = await this.uploadFileToServer(this.data.businessLicenseFile.path, 'businessLicense'); console.log('所有文件上传完成'); @@ -172,6 +174,7 @@ Page({ userId: userId, idcard1: idcard1Url, idcard2: idcard2Url, + businesslicenseurl: businessLicenseUrl, name: this.data.name, idNumber: this.data.idNumber, address: this.data.address -- 2.30.2 From 8a6745d9f30f435c6c32235a1a563225e44a000d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Wed, 28 Jan 2026 16:38:05 +0800 Subject: [PATCH 16/22] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AF=B9?= =?UTF-8?q?=E6=AF=94=E4=BB=B7=E6=A0=BC=E6=8C=89=E9=92=AE=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=92=8C=E8=BA=AB=E4=BB=BD=E8=AF=81=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 对比价格按钮添加登录状态检查,未登录显示登录弹窗 - 添加身份证信息(idcard1/idcard2)完整性验证 - 身份证信息不完整时提示并跳转到认证页面 - 认证页面支持从服务器加载已存在的认证信息 - 认证图片支持点击更换,保留原图片URL - 提交时智能判断是否需要重新上传图片 --- pages/goods-detail/goods-detail.js | 36 +++++++++ pages/profile/authentication/index.js | 108 ++++++++++++++++++++++++-- 2 files changed, 136 insertions(+), 8 deletions(-) diff --git a/pages/goods-detail/goods-detail.js b/pages/goods-detail/goods-detail.js index 79662ed..1e8aedd 100644 --- a/pages/goods-detail/goods-detail.js +++ b/pages/goods-detail/goods-detail.js @@ -2939,6 +2939,42 @@ Page({ onCompareClick: function () { console.log('用户点击了对比价格按钮,准备显示弹窗'); + // 检查用户登录状态 + const openid = wx.getStorageSync('openid'); + const userId = wx.getStorageSync('userId'); + + if (!openid || !userId) { + console.log('用户未登录,显示登录弹窗'); + this.setData({ + showOneKeyLoginModal: true + }); + return; + } + + // 检查身份证信息 + const userInfo = wx.getStorageSync('userInfo') || {}; + const idcard1 = userInfo.idcard1; + const idcard2 = userInfo.idcard2; + + console.log('检查身份证信息:', { idcard1, idcard2 }); + + if (!idcard1 || !idcard2) { + console.log('身份证信息不完整,跳转到认证页面'); + wx.showToast({ + title: '信息不完整,请先完成身份认证', + icon: 'none', + duration: 2000 + }); + + // 跳转到认证页面 + setTimeout(() => { + wx.navigateTo({ + url: '/pages/profile/authentication/index' + }); + }, 1000); + return; + } + // 直接获取当前页面滚动位置 wx.createSelectorQuery().selectViewport().scrollOffset(function(res) { console.log('记录当前滚动位置:', res.scrollTop); diff --git a/pages/profile/authentication/index.js b/pages/profile/authentication/index.js index 0e13117..878cadd 100644 --- a/pages/profile/authentication/index.js +++ b/pages/profile/authentication/index.js @@ -156,17 +156,32 @@ Page({ return; } - wx.showLoading({ title: '正在上传文件...', mask: true }); + wx.showLoading({ title: '正在提交认证信息...', mask: true }); try { - // 上传身份证正面 - const idcard1Url = await this.uploadFileToServer(this.data.idcard1.path, 'idCardFront'); - // 上传身份证反面 - const idcard2Url = await this.uploadFileToServer(this.data.idcard2.path, 'idCardBack'); - // 上传营业执照 - const businessLicenseUrl = await this.uploadFileToServer(this.data.businessLicenseFile.path, 'businessLicense'); + let idcard1Url = this.data.idcard1?.path || this.data.idCardFront; + let idcard2Url = this.data.idcard2?.path || this.data.idCardBack; + let businessLicenseUrl = this.data.businessLicenseFile?.path || this.data.businessLicense; - console.log('所有文件上传完成'); + // 检查是否是本地路径(需要上传)还是远程URL(直接使用) + const isLocalPath = (path) => path && (path.startsWith('http://') || path.startsWith('https://') || path.startsWith('wxfile://') || path.startsWith('cloud://')); + + // 上传身份证正面(仅当是本地路径时) + if (this.data.idcard1?.path && !isLocalPath(this.data.idcard1.path)) { + idcard1Url = await this.uploadFileToServer(this.data.idcard1.path, 'idCardFront'); + } + + // 上传身份证反面(仅当是本地路径时) + if (this.data.idcard2?.path && !isLocalPath(this.data.idcard2.path)) { + idcard2Url = await this.uploadFileToServer(this.data.idcard2.path, 'idCardBack'); + } + + // 上传营业执照(仅当是本地路径时) + if (this.data.businessLicenseFile?.path && !isLocalPath(this.data.businessLicenseFile.path)) { + businessLicenseUrl = await this.uploadFileToServer(this.data.businessLicenseFile.path, 'businessLicense'); + } + + console.log('文件处理完成,正面:', idcard1Url, '反面:', idcard2Url, '营业执照:', businessLicenseUrl); // 准备提交数据 const submitData = { @@ -188,6 +203,19 @@ Page({ console.log('认证提交结果:', result); if (result && result.success) { + // 更新本地存储的用户信息 + const userInfo = wx.getStorageSync('userInfo') || {}; + const updatedUserInfo = { + ...userInfo, + idcard1: idcard1Url, + idcard2: idcard2Url, + businesslicenseurl: businessLicenseUrl, + name: this.data.name, + idNumber: this.data.idNumber, + address: this.data.address + }; + wx.setStorageSync('userInfo', updatedUserInfo); + wx.hideLoading(); wx.showToast({ title: '认证成功', @@ -234,7 +262,71 @@ Page({ * 生命周期函数--监听页面显示 */ onShow() { + // 页面显示时加载已存在的认证信息 + this.loadExistingAuthData(); + }, + /** + * 从服务器加载已存在的认证信息 + */ + loadExistingAuthData() { + const openid = wx.getStorageSync('openid'); + const userId = wx.getStorageSync('userId'); + + if (!openid || !userId) { + console.log('用户未登录,无法加载认证信息'); + return; + } + + console.log('开始加载用户认证信息,openid:', openid, 'userId:', userId); + + // 调用API获取用户信息,包括认证数据 + API.getUserInfo(openid).then(res => { + console.log('获取用户认证信息响应:', res); + + if (res && res.success && res.data) { + const userData = res.data; + console.log('用户认证数据:', userData); + + // 构建更新数据对象 + const updateData = { + name: userData.name || '', + idNumber: userData.idNumber || userData.id_number || '', + address: userData.address || '', + validStart: userData.validStart || userData.valid_start || '', + validEnd: userData.validEnd || userData.valid_end || '' + }; + + // 处理身份证正面图片 + if (userData.idcard1) { + updateData.idcard1 = { path: userData.idcard1 }; + updateData.idCardFront = userData.idcard1; + console.log('已加载身份证正面:', userData.idcard1); + } + + // 处理身份证反面图片 + if (userData.idcard2) { + updateData.idcard2 = { path: userData.idcard2 }; + updateData.idCardBack = userData.idcard2; + console.log('已加载身份证反面:', userData.idcard2); + } + + // 处理营业执照图片 + if (userData.businesslicenseurl) { + updateData.businessLicenseFile = { path: userData.businesslicenseurl }; + updateData.businessLicense = userData.businesslicenseurl; + console.log('已加载营业执照:', userData.businesslicenseurl); + } + + // 更新页面数据 + this.setData(updateData); + console.log('认证信息加载完成,当前数据:', this.data); + } else { + console.log('未获取到用户认证信息或获取失败'); + } + }).catch(err => { + console.error('加载用户认证信息失败:', err); + }); }, /** -- 2.30.2 From ebe0467c482755b4c2b6749462e5002fe27a44ae Mon Sep 17 00:00:00 2001 From: Default User Date: Wed, 28 Jan 2026 16:38:42 +0800 Subject: [PATCH 17/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=B4=E5=83=8FURL?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E9=97=AE=E9=A2=98=EF=BC=9A=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?processAvatarUrl=E6=96=B9=E6=B3=95=EF=BC=8C=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E8=A7=A3=E6=9E=90=E5=AD=98=E5=82=A8=E4=B8=BA?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E5=BD=A2=E5=BC=8F=E7=9A=84OSS=20URL=E5=A4=B4?= =?UTF-8?q?=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/profile/index.js | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/pages/profile/index.js b/pages/profile/index.js index 5f76728..43fe239 100644 --- a/pages/profile/index.js +++ b/pages/profile/index.js @@ -55,6 +55,37 @@ Page({ return phoneStr.substring(0, 3) + '****' + phoneStr.substring(7) }, + // 处理头像URL,确保正确解析数组形式的OSS URL + processAvatarUrl(avatarUrl) { + if (!avatarUrl) { + return 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'; + } + + // 如果是字符串,尝试解析为JSON数组 + if (typeof avatarUrl === 'string') { + try { + const parsedUrl = JSON.parse(avatarUrl); + // 如果解析成功且是数组且不为空,使用第一个元素 + if (Array.isArray(parsedUrl) && parsedUrl.length > 0) { + return parsedUrl[0]; + } + // 如果解析成功但不是数组,直接返回 + return avatarUrl; + } catch (e) { + // 解析失败,直接返回 + return avatarUrl; + } + } + + // 如果是数组且不为空,使用第一个元素 + if (Array.isArray(avatarUrl) && avatarUrl.length > 0) { + return avatarUrl[0]; + } + + // 其他情况返回默认头像 + return 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'; + }, + // 加载用户信息 loadUserInfo() { console.log('开始加载用户信息') @@ -64,10 +95,14 @@ Page({ const localUserInfo = wx.getStorageSync('userInfo') || {} if (app.globalData.userInfo) { const userInfo = { ...app.globalData.userInfo } + // 处理头像URL + userInfo.avatarUrl = this.processAvatarUrl(userInfo.avatarUrl); userInfo.hiddenPhoneNumber = this.hidePhoneNumber(userInfo.phoneNumber) this.setData({ userInfo }) } else { const userInfo = { ...localUserInfo } + // 处理头像URL + userInfo.avatarUrl = this.processAvatarUrl(userInfo.avatarUrl); userInfo.hiddenPhoneNumber = this.hidePhoneNumber(userInfo.phoneNumber) app.globalData.userInfo = userInfo this.setData({ @@ -199,6 +234,9 @@ Page({ ...serverUserInfo } + // 处理头像URL + updatedUserInfo.avatarUrl = this.processAvatarUrl(updatedUserInfo.avatarUrl); + // 添加隐藏的电话号码 updatedUserInfo.hiddenPhoneNumber = this.hidePhoneNumber(updatedUserInfo.phoneNumber) @@ -232,6 +270,9 @@ Page({ ...serverUserInfo } + // 处理头像URL + updatedUserInfo.avatarUrl = this.processAvatarUrl(updatedUserInfo.avatarUrl); + // 添加隐藏的电话号码 updatedUserInfo.hiddenPhoneNumber = this.hidePhoneNumber(updatedUserInfo.phoneNumber) -- 2.30.2 From 8bcbe163e8a1abb4996d27cdd62f9cba40a6290d Mon Sep 17 00:00:00 2001 From: Default User Date: Wed, 28 Jan 2026 16:45:51 +0800 Subject: [PATCH 18/22] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=A4=B4=E5=83=8F?= =?UTF-8?q?=E6=9B=B4=E6=8D=A2=E5=8A=9F=E8=83=BD=EF=BC=9A=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?onAvatarClick=E6=96=B9=E6=B3=95=EF=BC=8C=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E5=A4=B4=E5=83=8F=E6=97=B6=E5=BC=B9=E5=87=BA=E6=9B=B4=E6=8D=A2?= =?UTF-8?q?=E9=80=89=E6=8B=A9=EF=BC=8C=E4=B8=8A=E4=BC=A0=E5=90=8E=E6=9B=B4?= =?UTF-8?q?=E6=96=B0avatarUrl=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/profile/index.js | 70 ++++++++++++++++++++++++++++++++++++++++ pages/profile/index.wxml | 3 +- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/pages/profile/index.js b/pages/profile/index.js index 43fe239..3de6a01 100644 --- a/pages/profile/index.js +++ b/pages/profile/index.js @@ -1114,4 +1114,74 @@ Page({ }); }, + // 点击头像更换图片 + onAvatarClick() { + wx.chooseImage({ + count: 1, + sizeType: ['compressed'], + sourceType: ['album', 'camera'], + success: (res) => { + const tempFilePaths = res.tempFilePaths; + if (tempFilePaths && tempFilePaths.length > 0) { + this.uploadAvatar(tempFilePaths[0]); + } + }, + fail: (err) => { + console.error('选择图片失败:', err); + } + }); + }, + + // 上传头像并更新 + async uploadAvatar(filePath) { + wx.showLoading({ title: '上传中...', mask: true }); + + try { + // 上传图片到服务器 + const API = require('../../utils/api.js'); + const result = await API.uploadSettlementFile(filePath, 'avatar'); + + if (result && result.fileUrl) { + const avatarUrl = result.fileUrl; + + // 更新本地和全局用户信息 + const app = getApp(); + const updatedUserInfo = { + ...this.data.userInfo, + avatarUrl: avatarUrl + }; + + // 保存到本地存储和全局状态 + app.globalData.userInfo = updatedUserInfo; + wx.setStorageSync('userInfo', updatedUserInfo); + + // 更新页面显示 + this.setData({ userInfo: updatedUserInfo }); + + // 上传到服务器更新数据库 + const userId = wx.getStorageSync('userId'); + if (userId) { + await this.uploadUserInfoToServer(updatedUserInfo, userId, this.data.userType); + } + + wx.showToast({ + title: '头像更新成功', + icon: 'success', + duration: 2000 + }); + } else { + throw new Error('上传失败'); + } + } catch (error) { + console.error('上传头像失败:', error); + wx.showToast({ + title: '上传失败,请重试', + icon: 'none', + duration: 2000 + }); + } finally { + wx.hideLoading(); + } + }, + }) diff --git a/pages/profile/index.wxml b/pages/profile/index.wxml index 635b06e..b3762cc 100644 --- a/pages/profile/index.wxml +++ b/pages/profile/index.wxml @@ -3,7 +3,8 @@ {{userInfo.hiddenPhoneNumber || userInfo.phoneNumber || '未登录'}} -- 2.30.2 From 87bbe8b13c75f605da8ba64e9f4a2b0921385f12 Mon Sep 17 00:00:00 2001 From: Default User Date: Wed, 28 Jan 2026 17:12:14 +0800 Subject: [PATCH 19/22] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=A4=B4=E5=83=8F?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=A4=9A=E5=BC=A0=E5=A4=B4=E5=83=8F=E8=A7=A3=E6=9E=90=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/profile/index.js | 164 ++++++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 69 deletions(-) diff --git a/pages/profile/index.js b/pages/profile/index.js index 3de6a01..811dfa9 100644 --- a/pages/profile/index.js +++ b/pages/profile/index.js @@ -25,7 +25,9 @@ Page({ needPhoneAuth: false, // 是否需要重新授权手机号 locationInfo: '', // 位置信息 hasLocationAuth: false, // 是否已经授权位置 - isInPersonnel: false // 用户手机号是否在personnel表中 + isInPersonnel: false, // 用户手机号是否在personnel表中 + currentAvatarIndex: 0, // 当前显示的头像索引,默认显示第一张 + rawAvatarUrl: null // 存储原始的头像URL数据(可能是数组) }, onLoad() { @@ -95,19 +97,27 @@ Page({ const localUserInfo = wx.getStorageSync('userInfo') || {} if (app.globalData.userInfo) { const userInfo = { ...app.globalData.userInfo } - // 处理头像URL + // 保存原始的头像URL数据 + const rawAvatarUrl = userInfo.avatarUrl; + // 处理头像URL用于显示 userInfo.avatarUrl = this.processAvatarUrl(userInfo.avatarUrl); userInfo.hiddenPhoneNumber = this.hidePhoneNumber(userInfo.phoneNumber) - this.setData({ userInfo }) + this.setData({ + userInfo, + rawAvatarUrl + }) } else { const userInfo = { ...localUserInfo } - // 处理头像URL + // 保存原始的头像URL数据 + const rawAvatarUrl = userInfo.avatarUrl; + // 处理头像URL用于显示 userInfo.avatarUrl = this.processAvatarUrl(userInfo.avatarUrl); userInfo.hiddenPhoneNumber = this.hidePhoneNumber(userInfo.phoneNumber) app.globalData.userInfo = userInfo this.setData({ userInfo, - needPhoneAuth: !userInfo.phoneNumber + needPhoneAuth: !userInfo.phoneNumber, + rawAvatarUrl }) } @@ -234,7 +244,9 @@ Page({ ...serverUserInfo } - // 处理头像URL + // 保存原始的头像URL数据 + const rawAvatarUrl = updatedUserInfo.avatarUrl; + // 处理头像URL用于显示 updatedUserInfo.avatarUrl = this.processAvatarUrl(updatedUserInfo.avatarUrl); // 添加隐藏的电话号码 @@ -242,7 +254,10 @@ Page({ app.globalData.userInfo = updatedUserInfo wx.setStorageSync('userInfo', updatedUserInfo) - this.setData({ userInfo: updatedUserInfo }) + this.setData({ + userInfo: updatedUserInfo, + rawAvatarUrl + }) // 同步更新用户身份信息(当前身份由数据库决定) if (serverUserInfo.type) { @@ -270,7 +285,9 @@ Page({ ...serverUserInfo } - // 处理头像URL + // 保存原始的头像URL数据 + const rawAvatarUrl = updatedUserInfo.avatarUrl; + // 处理头像URL用于显示 updatedUserInfo.avatarUrl = this.processAvatarUrl(updatedUserInfo.avatarUrl); // 添加隐藏的电话号码 @@ -278,7 +295,10 @@ Page({ app.globalData.userInfo = updatedUserInfo wx.setStorageSync('userInfo', updatedUserInfo) - this.setData({ userInfo: updatedUserInfo }) + this.setData({ + userInfo: updatedUserInfo, + rawAvatarUrl + }) // 同步更新用户身份信息(当前身份由数据库决定) if (serverUserInfo.type) { @@ -1114,74 +1134,80 @@ Page({ }); }, - // 点击头像更换图片 + // 点击头像切换图片 onAvatarClick() { - wx.chooseImage({ - count: 1, - sizeType: ['compressed'], - sourceType: ['album', 'camera'], - success: (res) => { - const tempFilePaths = res.tempFilePaths; - if (tempFilePaths && tempFilePaths.length > 0) { - this.uploadAvatar(tempFilePaths[0]); - } - }, - fail: (err) => { - console.error('选择图片失败:', err); - } - }); - }, - - // 上传头像并更新 - async uploadAvatar(filePath) { - wx.showLoading({ title: '上传中...', mask: true }); - - try { - // 上传图片到服务器 - const API = require('../../utils/api.js'); - const result = await API.uploadSettlementFile(filePath, 'avatar'); - - if (result && result.fileUrl) { - const avatarUrl = result.fileUrl; - - // 更新本地和全局用户信息 - const app = getApp(); - const updatedUserInfo = { - ...this.data.userInfo, - avatarUrl: avatarUrl - }; - - // 保存到本地存储和全局状态 - app.globalData.userInfo = updatedUserInfo; - wx.setStorageSync('userInfo', updatedUserInfo); - - // 更新页面显示 - this.setData({ userInfo: updatedUserInfo }); - - // 上传到服务器更新数据库 - const userId = wx.getStorageSync('userId'); - if (userId) { - await this.uploadUserInfoToServer(updatedUserInfo, userId, this.data.userType); + // 使用rawAvatarUrl获取完整的头像URL数组 + let avatarUrls = []; + const rawAvatarUrl = this.data.rawAvatarUrl; + + if (rawAvatarUrl) { + if (typeof rawAvatarUrl === 'string') { + // 如果是字符串,尝试解析为JSON数组 + try { + const parsed = JSON.parse(rawAvatarUrl); + if (Array.isArray(parsed)) { + avatarUrls = parsed; + } else { + // 如果不是数组,将当前URL作为第一个元素 + avatarUrls = [rawAvatarUrl]; + } + } catch (e) { + // 解析失败,将当前URL作为第一个元素 + avatarUrls = [rawAvatarUrl]; } - - wx.showToast({ - title: '头像更新成功', - icon: 'success', - duration: 2000 - }); - } else { - throw new Error('上传失败'); + } else if (Array.isArray(rawAvatarUrl)) { + // 如果已经是数组,直接使用 + avatarUrls = rawAvatarUrl; } - } catch (error) { - console.error('上传头像失败:', error); + } + + // 检查是否有至少两张图片可以切换 + if (avatarUrls.length < 2) { wx.showToast({ - title: '上传失败,请重试', + title: '没有足够的头像可以切换', icon: 'none', duration: 2000 }); - } finally { - wx.hideLoading(); + return; + } + + // 切换到下一张头像 + let nextIndex = this.data.currentAvatarIndex + 1; + if (nextIndex >= avatarUrls.length) { + nextIndex = 0; // 如果已经是最后一张,回到第一张 } + + // 显示切换头像的提示 + wx.showModal({ + title: '切换头像', + content: `确定要切换到第${nextIndex + 1}张头像吗?`, + success: (res) => { + if (res.confirm) { + // 切换到下一张图片 + const app = getApp(); + const updatedUserInfo = { + ...this.data.userInfo, + avatarUrl: avatarUrls[nextIndex] // 直接使用下一张图片 + }; + + // 保存到本地存储和全局状态 + app.globalData.userInfo = updatedUserInfo; + wx.setStorageSync('userInfo', updatedUserInfo); + + // 更新页面显示 + this.setData({ + userInfo: updatedUserInfo, + currentAvatarIndex: nextIndex + }); + + wx.showToast({ + title: '头像切换成功', + icon: 'success', + duration: 2000 + }); + } + } + }); }, }) -- 2.30.2 From b6733d27d2fee46eb6bec22336c0d00e4dd880ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Wed, 28 Jan 2026 17:24:01 +0800 Subject: [PATCH 20/22] Add login verification and partnerstatus check for evaluate2/one page --- pages/evaluate2/one.js | 347 ++++++++++++++++++++++++++++++++++++++- pages/evaluate2/one.wxml | 23 +++ pages/evaluate2/one.wxss | 92 +++++++++++ 3 files changed, 461 insertions(+), 1 deletion(-) diff --git a/pages/evaluate2/one.js b/pages/evaluate2/one.js index 47fceb9..16cdbb4 100644 --- a/pages/evaluate2/one.js +++ b/pages/evaluate2/one.js @@ -5,7 +5,8 @@ Page({ loading: false, error: '', categories: [], - selectedCategory: '' + selectedCategory: '', + showOneKeyLoginModal: false // 是否显示登录弹窗 }, onLoad(options) { let productName = ''; @@ -455,9 +456,353 @@ Page({ const category = e.currentTarget.dataset.category; console.log('选择分类:', category); + // 检查用户登录状态 + const openid = wx.getStorageSync('openid'); + const userId = wx.getStorageSync('userId'); + + if (!openid || !userId) { + // 用户未登录,显示登录弹窗 + console.log('用户未登录,显示登录弹窗'); + this.setData({ + showOneKeyLoginModal: true + }); + return; + } + + // 检查用户合作状态 + const userInfo = wx.getStorageSync('userInfo') || {}; + const partnerStatus = userInfo.partnerstatus || ''; + + if (partnerStatus !== 'approved') { + // 合作状态未批准,显示提示 + wx.showModal({ + title: '提示', + content: '需要入住成功才能查看', + confirmText: '立即入驻', + success: function(res) { + if (res.confirm) { + wx.navigateTo({ + url: '/pages/profile/authentication/index' + }); + } + } + }); + return; + } + // 跳转到商品列表页面,并传递分类参数 wx.redirectTo({ url: `/pages/evaluate2/product-list?category=${encodeURIComponent(category)}` }); + }, + + // 关闭登录弹窗 + closeOneKeyLoginModal() { + this.setData({ + showOneKeyLoginModal: false + }); + }, + + // 处理登录授权 + async onGetPhoneNumber(e) { + console.log('收到手机号授权事件:', e.detail); + + // 关闭手机号授权弹窗 + this.setData({ showOneKeyLoginModal: false }); + + // 用户点击拒绝授权 + if (e.detail.errMsg === 'getPhoneNumber:fail user deny') { + wx.showToast({ + title: '需要授权手机号才能使用', + icon: 'none', + duration: 2000 + }); + return; + } + + // 处理没有权限的情况 + if (e.detail.errMsg === 'getPhoneNumber:fail no permission') { + wx.showToast({ + title: '当前环境无法获取手机号权限', + icon: 'none', + duration: 3000 + }); + return; + } + + // 检查是否已经登录,避免重复授权 + const existingOpenid = wx.getStorageSync('openid'); + const existingUserId = wx.getStorageSync('userId'); + const existingUserInfo = wx.getStorageSync('userInfo'); + + if (existingOpenid && existingUserId && existingUserInfo && existingUserInfo.phoneNumber) { + console.log('用户已登录且手机号有效,登录流程已完成'); + wx.showToast({ + title: '您已登录', + icon: 'success', + duration: 1500 + }); + return; + } + + wx.showLoading({ title: '登录中...', mask: true }); + + try { + if (e.detail.errMsg === 'getPhoneNumber:ok') { + // 用户同意授权,实际处理授权流程 + console.log('用户同意授权获取手机号'); + + // 1. 先执行微信登录获取code + const loginRes = await new Promise((resolve, reject) => { + wx.login({ + success: resolve, + fail: reject + }); + }); + + if (!loginRes.code) { + throw new Error('获取登录code失败'); + } + + console.log('获取登录code成功:', loginRes.code); + + // 2. 使用code换取openid + const API = require('../../utils/api'); + const openidRes = await API.getOpenid(loginRes.code); + + // 改进错误处理逻辑,更宽容地处理服务器返回格式 + let openid = null; + let userId = null; + console.log('openidRes完整响应:', JSON.stringify(openidRes)); + + if (openidRes && typeof openidRes === 'object') { + // 适配服务器返回格式:{success: true, code: 200, message: '获取openid成功', data: {openid, userId}} + if (openidRes.data && typeof openidRes.data === 'object') { + console.log('识别到标准服务器返回格式,从data字段提取信息'); + openid = openidRes.data.openid || openidRes.data.OpenID || null; + userId = openidRes.data.userId || null; + } else { + // 尝试从响应对象中直接提取openid + console.log('尝试从根对象直接提取openid'); + openid = openidRes.openid || openidRes.OpenID || null; + userId = openidRes.userId || null; + } + } + + if (!openid) { + console.error('无法从服务器响应中提取openid,完整响应:', JSON.stringify(openidRes)); + throw new Error(`获取openid失败: 服务器返回数据格式可能不符合预期`); + } + + console.log('获取openid成功:', openid); + + // 3. 存储openid和session_key + wx.setStorageSync('openid', openid); + + // 从服务器返回中获取session_key + if (openidRes && openidRes.session_key) { + wx.setStorageSync('sessionKey', openidRes.session_key); + } else if (openidRes && openidRes.data && openidRes.data.session_key) { + wx.setStorageSync('sessionKey', openidRes.data.session_key); + } + + // 优先使用从服务器响应data字段中提取的userId + if (userId) { + wx.setStorageSync('userId', userId); + console.log('使用从服务器data字段提取的userId:', userId); + } else if (openidRes && openidRes.userId) { + wx.setStorageSync('userId', openidRes.userId); + console.log('使用服务器根对象中的userId:', openidRes.userId); + } else { + // 生成临时userId + const tempUserId = 'user_' + Date.now(); + wx.setStorageSync('userId', tempUserId); + console.log('生成临时userId:', tempUserId); + } + + // 4. 上传手机号加密数据到服务器解密 + const phoneData = { + ...e.detail, + openid: openid + }; + + console.log('准备上传手机号加密数据到服务器'); + const phoneRes = await API.uploadPhoneNumberData(phoneData); + + // 改进手机号解密结果的处理逻辑 + if (!phoneRes || (!phoneRes.success && !phoneRes.phoneNumber)) { + // 如果服务器返回格式不标准但包含手机号,也接受 + if (phoneRes && phoneRes.phoneNumber) { + console.warn('服务器返回格式可能不符合预期,但成功获取手机号'); + } else { + throw new Error('获取手机号失败: ' + (phoneRes && phoneRes.message ? phoneRes.message : '未知错误')); + } + } + + // 检查是否有手机号冲突 + const hasPhoneConflict = phoneRes.phoneNumberConflict || false; + const isNewPhone = phoneRes.isNewPhone || true; + const phoneNumber = phoneRes.phoneNumber || null; + + // 如果有手机号冲突且没有返回手机号,使用实际返回的手机号 + const finalPhoneNumber = phoneNumber; + + console.log('手机号解密结果:', { + phoneNumber: finalPhoneNumber, + hasPhoneConflict: hasPhoneConflict, + isNewPhone: isNewPhone + }); + + // 5. 获取用户微信名称和头像 + let userProfile = null; + try { + userProfile = await new Promise((resolve, reject) => { + wx.getUserProfile({ + desc: '用于完善会员资料', + success: resolve, + fail: reject + }); + }); + console.log('获取用户信息成功:', userProfile); + } catch (err) { + console.warn('获取用户信息失败:', err); + // 如果获取失败,使用默认值 + } + + // 6. 创建用户信息 + const tempUserInfo = { + name: userProfile ? (userProfile.userInfo.name || userProfile.userInfo.nickName) : '微信用户', + // 获取微信头像失败时使用微信默认头像 + avatarUrl: userProfile ? userProfile.userInfo.avatarUrl : 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0', + gender: userProfile ? userProfile.userInfo.gender : 0, + country: userProfile ? userProfile.userInfo.country : '', + province: userProfile ? userProfile.userInfo.province : '', + city: userProfile ? userProfile.userInfo.city : '', + language: userProfile ? userProfile.userInfo.language : 'zh_CN', + phoneNumber: finalPhoneNumber + }; + + // 7. 保存用户信息 + const storedUserId = wx.getStorageSync('userId'); + const users = wx.getStorageSync('users') || {}; + const currentUserType = users[storedUserId] && users[storedUserId].type ? users[storedUserId].type : 'buyer'; + + console.log('用户身份类型:', currentUserType); + + // 8. 保存用户信息到本地和服务器 + console.log('开始保存用户信息...'); + await this.saveUserInfo(tempUserInfo, currentUserType); + console.log('用户信息保存完成'); + + wx.hideLoading(); + + // 根据服务器返回的结果显示不同的提示 + if (phoneRes && phoneRes.phoneNumberConflict) { + wx.showModal({ + title: '登录成功', + content: '您的手机号已被其他账号绑定', + showCancel: false, + confirmText: '我知道了', + success(res) { + if (res.confirm) { + console.log('用户点击了我知道了'); + } + } + }); + } + + // 1. 登录成功提示 + wx.showToast({ + title: '登录成功', + icon: 'success', + duration: 1500 + }); + + // 2. 从服务器获取最新用户信息 + const userInfoRes = await API.getUserInfo(openid); + + // 3. 获取服务器返回的partnerstatus + const serverUserInfo = userInfoRes.data; + const partnerStatus = serverUserInfo.partnerstatus || 'pending'; + + // 4. 更新本地缓存 + const localUserInfo = wx.getStorageSync('userInfo') || {}; + const updatedUserInfo = { + ...localUserInfo, + partnerstatus: partnerStatus + }; + wx.setStorageSync('userInfo', updatedUserInfo); + + // 5. 检查partnerstatus值 + if (partnerStatus !== 'approved') { + // 显示入驻提示 + setTimeout(() => { + wx.showModal({ + title: '提示', + content: '需要入住成功才能查看', + confirmText: '立即入驻', + success: function(res) { + if (res.confirm) { + wx.navigateTo({ + url: '/pages/profile/authentication/index' + }); + } + } + }); + }, 2000); + } + } + } catch (error) { + wx.hideLoading(); + console.error('登录失败:', error); + wx.showToast({ + title: '登录失败,请重试', + icon: 'none', + duration: 2000 + }); + } + }, + + // 保存用户信息 + async saveUserInfo(userInfo, userType = 'buyer') { + return new Promise(async (resolve, reject) => { + try { + const storedUserId = wx.getStorageSync('userId'); + const users = wx.getStorageSync('users') || {}; + + // 更新用户信息 + users[storedUserId] = { + ...users[storedUserId], + ...userInfo, + type: userType, + lastLogin: new Date().toISOString() + }; + + // 保存到本地存储 + wx.setStorageSync('users', users); + wx.setStorageSync('userInfo', userInfo); + + // 上传用户信息到服务器 + const API = require('../../utils/api'); + const submitData = { + openid: wx.getStorageSync('openid'), + userId: storedUserId, + ...userInfo, + type: userType + }; + + await API.request('/api/user/update', 'POST', submitData).then(res => { + console.log('用户信息上传成功:', res); + resolve({ success: true, message: '用户信息保存成功' }); + }).catch(err => { + console.error('用户信息上传失败:', err); + // 即使服务器上传失败,也继续流程,只在本地保存 + resolve({ success: false, message: '本地保存成功,服务器同步失败' }); + }); + } catch (error) { + console.error('保存用户信息失败:', error); + reject(error); + } + }); } }); \ No newline at end of file diff --git a/pages/evaluate2/one.wxml b/pages/evaluate2/one.wxml index 4180588..6eaf083 100644 --- a/pages/evaluate2/one.wxml +++ b/pages/evaluate2/one.wxml @@ -6,6 +6,29 @@ + + + + 授权登录 + 授权您的手机号后才能使用完整功能 + + + + + + + diff --git a/pages/evaluate2/one.wxss b/pages/evaluate2/one.wxss index 67a8107..d8e7fad 100644 --- a/pages/evaluate2/one.wxss +++ b/pages/evaluate2/one.wxss @@ -557,4 +557,96 @@ /* 调整规格网格布局,确保不被导航栏遮挡 */ .spec-section { margin-bottom: 40rpx; +} + +/* 登录弹窗样式 */ +.auth-modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 9999; +} + +.auth-modal-container { + background: rgba(255, 255, 255, 0.95); + border-radius: 20rpx; + padding: 48rpx; + width: 80%; + max-width: 500rpx; + box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.2); + backdrop-filter: blur(12rpx); + border: 1rpx solid rgba(255, 255, 255, 0.3); +} + +.auth-modal-title { + font-size: 36rpx; + font-weight: 700; + text-align: center; + margin-bottom: 24rpx; + color: #2c3e50; + letter-spacing: 2rpx; +} + +.auth-modal-content { + font-size: 28rpx; + text-align: center; + margin-bottom: 48rpx; + color: #666; + line-height: 1.5; + padding: 0 20rpx; +} + +.auth-modal-buttons { + display: flex; + flex-direction: column; + gap: 24rpx; +} + +.auth-primary-button { + background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%); + color: white; + border: none; + border-radius: 12rpx; + padding: 24rpx; + font-size: 30rpx; + font-weight: 700; + min-height: 88rpx; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 4rpx 16rpx rgba(96, 165, 250, 0.4); + transition: all 0.3s ease; +} + +.auth-primary-button:hover { + transform: translateY(-2rpx); + box-shadow: 0 8rpx 24rpx rgba(96, 165, 250, 0.6); +} + +.auth-cancel-button { + background: rgba(255, 255, 255, 0.9); + color: #2c3e50; + border: 2rpx solid #e2e8f0; + border-radius: 12rpx; + padding: 24rpx; + font-size: 28rpx; + font-weight: 600; + min-height: 88rpx; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); +} + +.auth-cancel-button:hover { + background: rgba(236, 240, 241, 0.8); + transform: translateY(-2rpx); + box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); } \ No newline at end of file -- 2.30.2 From f80397f9881deed5a2eaa15f3d453c784613e8d2 Mon Sep 17 00:00:00 2001 From: Default User Date: Thu, 29 Jan 2026 10:02:27 +0800 Subject: [PATCH 21/22] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=A4=B4=E5=83=8F?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BD=BF=E7=94=A8=E5=9B=BA=E5=AE=9A?= =?UTF-8?q?=E7=9A=84=E5=A4=B4=E5=83=8FURL=E6=95=B0=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/profile/index.js | 124 ++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 57 deletions(-) diff --git a/pages/profile/index.js b/pages/profile/index.js index 811dfa9..d07059a 100644 --- a/pages/profile/index.js +++ b/pages/profile/index.js @@ -27,7 +27,12 @@ Page({ hasLocationAuth: false, // 是否已经授权位置 isInPersonnel: false, // 用户手机号是否在personnel表中 currentAvatarIndex: 0, // 当前显示的头像索引,默认显示第一张 - rawAvatarUrl: null // 存储原始的头像URL数据(可能是数组) + rawAvatarUrl: null, // 存储原始的头像URL数据(可能是数组) + // 固定的头像URL数组 + avatarUrls: [ + "https://my-supplier-photos.oss-cn-chengdu.aliyuncs.com/products/%E6%B5%B7%E8%93%9D%E7%81%B0/image/7a2a8a17a83ba4d3d4270828531e2041.jpeg", + "https://my-supplier-photos.oss-cn-chengdu.aliyuncs.com/products/%E4%BC%8A%E8%8E%8E%E7%B2%89/image/1b2a0ba28eaa17c16c3674985ccee05c.jpeg" + ] }, onLoad() { @@ -65,23 +70,49 @@ Page({ // 如果是字符串,尝试解析为JSON数组 if (typeof avatarUrl === 'string') { + // 去除字符串两端的空格和引号 + let cleanedUrl = avatarUrl.trim(); + // 去除可能存在的前后引号 + if ((cleanedUrl.startsWith('"') && cleanedUrl.endsWith('"')) || + (cleanedUrl.startsWith('`') && cleanedUrl.endsWith('`'))) { + cleanedUrl = cleanedUrl.substring(1, cleanedUrl.length - 1); + } + try { - const parsedUrl = JSON.parse(avatarUrl); + const parsedUrl = JSON.parse(cleanedUrl); // 如果解析成功且是数组且不为空,使用第一个元素 if (Array.isArray(parsedUrl) && parsedUrl.length > 0) { - return parsedUrl[0]; + // 清理第一个元素中的空格和引号 + let firstUrl = parsedUrl[0]; + if (typeof firstUrl === 'string') { + firstUrl = firstUrl.trim(); + if ((firstUrl.startsWith('"') && firstUrl.endsWith('"')) || + (firstUrl.startsWith('`') && firstUrl.endsWith('`'))) { + firstUrl = firstUrl.substring(1, firstUrl.length - 1); + } + } + return firstUrl; } - // 如果解析成功但不是数组,直接返回 - return avatarUrl; + // 如果解析成功但不是数组,直接返回清理后的URL + return cleanedUrl; } catch (e) { - // 解析失败,直接返回 - return avatarUrl; + // 解析失败,返回清理后的URL + return cleanedUrl; } } // 如果是数组且不为空,使用第一个元素 if (Array.isArray(avatarUrl) && avatarUrl.length > 0) { - return avatarUrl[0]; + let firstUrl = avatarUrl[0]; + if (typeof firstUrl === 'string') { + // 清理第一个元素中的空格和引号 + firstUrl = firstUrl.trim(); + if ((firstUrl.startsWith('"') && firstUrl.endsWith('"')) || + (firstUrl.startsWith('`') && firstUrl.endsWith('`'))) { + firstUrl = firstUrl.substring(1, firstUrl.length - 1); + } + } + return firstUrl; } // 其他情况返回默认头像 @@ -97,27 +128,31 @@ Page({ const localUserInfo = wx.getStorageSync('userInfo') || {} if (app.globalData.userInfo) { const userInfo = { ...app.globalData.userInfo } - // 保存原始的头像URL数据 - const rawAvatarUrl = userInfo.avatarUrl; - // 处理头像URL用于显示 - userInfo.avatarUrl = this.processAvatarUrl(userInfo.avatarUrl); + // 使用固定的头像URL数组 + const avatarUrls = this.data.avatarUrls; + // 使用第一张头像作为默认显示 + userInfo.avatarUrl = avatarUrls[0]; userInfo.hiddenPhoneNumber = this.hidePhoneNumber(userInfo.phoneNumber) this.setData({ userInfo, - rawAvatarUrl + rawAvatarUrl: avatarUrls }) + // 更新全局状态中的头像URL,确保下次加载时使用固定的头像 + app.globalData.userInfo = userInfo; + wx.setStorageSync('userInfo', userInfo); } else { const userInfo = { ...localUserInfo } - // 保存原始的头像URL数据 - const rawAvatarUrl = userInfo.avatarUrl; - // 处理头像URL用于显示 - userInfo.avatarUrl = this.processAvatarUrl(userInfo.avatarUrl); + // 使用固定的头像URL数组 + const avatarUrls = this.data.avatarUrls; + // 使用第一张头像作为默认显示 + userInfo.avatarUrl = avatarUrls[0]; userInfo.hiddenPhoneNumber = this.hidePhoneNumber(userInfo.phoneNumber) app.globalData.userInfo = userInfo + wx.setStorageSync('userInfo', userInfo); this.setData({ userInfo, needPhoneAuth: !userInfo.phoneNumber, - rawAvatarUrl + rawAvatarUrl: avatarUrls }) } @@ -244,10 +279,10 @@ Page({ ...serverUserInfo } - // 保存原始的头像URL数据 - const rawAvatarUrl = updatedUserInfo.avatarUrl; - // 处理头像URL用于显示 - updatedUserInfo.avatarUrl = this.processAvatarUrl(updatedUserInfo.avatarUrl); + // 使用固定的头像URL数组 + const avatarUrls = this.data.avatarUrls; + // 使用第一张头像作为默认显示 + updatedUserInfo.avatarUrl = avatarUrls[0]; // 添加隐藏的电话号码 updatedUserInfo.hiddenPhoneNumber = this.hidePhoneNumber(updatedUserInfo.phoneNumber) @@ -256,7 +291,7 @@ Page({ wx.setStorageSync('userInfo', updatedUserInfo) this.setData({ userInfo: updatedUserInfo, - rawAvatarUrl + rawAvatarUrl: avatarUrls }) // 同步更新用户身份信息(当前身份由数据库决定) @@ -285,10 +320,10 @@ Page({ ...serverUserInfo } - // 保存原始的头像URL数据 - const rawAvatarUrl = updatedUserInfo.avatarUrl; - // 处理头像URL用于显示 - updatedUserInfo.avatarUrl = this.processAvatarUrl(updatedUserInfo.avatarUrl); + // 使用固定的头像URL数组 + const avatarUrls = this.data.avatarUrls; + // 使用第一张头像作为默认显示 + updatedUserInfo.avatarUrl = avatarUrls[0]; // 添加隐藏的电话号码 updatedUserInfo.hiddenPhoneNumber = this.hidePhoneNumber(updatedUserInfo.phoneNumber) @@ -297,7 +332,7 @@ Page({ wx.setStorageSync('userInfo', updatedUserInfo) this.setData({ userInfo: updatedUserInfo, - rawAvatarUrl + rawAvatarUrl: avatarUrls }) // 同步更新用户身份信息(当前身份由数据库决定) @@ -1136,30 +1171,8 @@ Page({ // 点击头像切换图片 onAvatarClick() { - // 使用rawAvatarUrl获取完整的头像URL数组 - let avatarUrls = []; - const rawAvatarUrl = this.data.rawAvatarUrl; - - if (rawAvatarUrl) { - if (typeof rawAvatarUrl === 'string') { - // 如果是字符串,尝试解析为JSON数组 - try { - const parsed = JSON.parse(rawAvatarUrl); - if (Array.isArray(parsed)) { - avatarUrls = parsed; - } else { - // 如果不是数组,将当前URL作为第一个元素 - avatarUrls = [rawAvatarUrl]; - } - } catch (e) { - // 解析失败,将当前URL作为第一个元素 - avatarUrls = [rawAvatarUrl]; - } - } else if (Array.isArray(rawAvatarUrl)) { - // 如果已经是数组,直接使用 - avatarUrls = rawAvatarUrl; - } - } + // 使用固定的头像URL数组 + const avatarUrls = this.data.avatarUrls; // 检查是否有至少两张图片可以切换 if (avatarUrls.length < 2) { @@ -1185,15 +1198,12 @@ Page({ if (res.confirm) { // 切换到下一张图片 const app = getApp(); + // 只更新显示用的avatarUrl const updatedUserInfo = { ...this.data.userInfo, - avatarUrl: avatarUrls[nextIndex] // 直接使用下一张图片 + avatarUrl: avatarUrls[nextIndex] // 直接使用下一张图片用于显示 }; - // 保存到本地存储和全局状态 - app.globalData.userInfo = updatedUserInfo; - wx.setStorageSync('userInfo', updatedUserInfo); - // 更新页面显示 this.setData({ userInfo: updatedUserInfo, -- 2.30.2 From 91c872a1a0c0be663776f60c53fcd0e117fe75de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Thu, 29 Jan 2026 10:19:36 +0800 Subject: [PATCH 22/22] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E7=9A=84=E7=82=B9=E8=B5=9E=E5=8A=9F=E8=83=BD=E5=92=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8A=A8=E6=80=81=E6=98=BE=E7=A4=BA=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/eggbar/eggbar.js | 59 ++++++- pages/eggbar/eggbar.wxml | 6 +- server-example/server-mysql.js | 291 +++++++++++++++++++++++++++++---- utils/api.js | 4 +- 4 files changed, 321 insertions(+), 39 deletions(-) diff --git a/pages/eggbar/eggbar.js b/pages/eggbar/eggbar.js index 2bcda6e..ee665ad 100644 --- a/pages/eggbar/eggbar.js +++ b/pages/eggbar/eggbar.js @@ -83,12 +83,25 @@ Page({ loading: true }); - API.getPosts({ + // 获取用户电话号码 + const userInfo = wx.getStorageSync('userInfo'); + const phoneNumber = userInfo?.phoneNumber || wx.getStorageSync('phoneNumber'); + + // 只有当电话号码存在时才传递,避免传递空值 + const params = { page: this.data.page, pageSize: this.data.pageSize - }).then(res => { + }; + if (phoneNumber) { + params.phone = phoneNumber; + } + + API.getPosts(params).then(res => { + console.log('后端返回的完整响应:', res); // 正确处理后端返回的响应格式 let newPosts = res.data && res.data.posts ? res.data.posts : []; + console.log('后端返回的动态数量:', newPosts.length); + console.log('后端返回的动态数据:', newPosts); // 处理images字段,确保它是一个数组 newPosts = newPosts.map(post => { @@ -243,6 +256,20 @@ Page({ likePost(e) { const postId = e.currentTarget.dataset.id; + + // 获取用户电话号码 + const userInfo = wx.getStorageSync('userInfo'); + const phoneNumber = userInfo?.phoneNumber || wx.getStorageSync('phoneNumber'); + + if (!phoneNumber) { + wx.showToast({ + title: '请先登录获取电话号码', + icon: 'none' + }); + return; + } + + // 前端临时更新状态 const posts = this.data.posts.map(post => { if (post.id === postId) { return { @@ -256,10 +283,34 @@ Page({ this.setData({ posts }); - API.likePost(postId).then(res => { - console.log('点赞成功'); + // 调用API + API.likePost(postId, phoneNumber).then(res => { + console.log('点赞成功:', res); + wx.showToast({ + title: res.message || '操作成功', + icon: 'success' + }); }).catch(err => { console.error('点赞失败:', err); + + // 恢复原始状态 + const originalPosts = this.data.posts.map(post => { + if (post.id === postId) { + return { + ...post, + liked: !post.liked, + likes: post.liked ? post.likes + 1 : post.likes - 1 + }; + } + return post; + }); + + this.setData({ posts: originalPosts }); + + wx.showToast({ + title: '操作失败,请重试', + icon: 'none' + }); }); }, diff --git a/pages/eggbar/eggbar.wxml b/pages/eggbar/eggbar.wxml index 5bdeceb..a75559c 100644 --- a/pages/eggbar/eggbar.wxml +++ b/pages/eggbar/eggbar.wxml @@ -42,15 +42,15 @@