From 0479b6bbf9dfd1f9ef6db7204af6a28f387b98ef 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, 6 Jan 2026 17:30:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=95=86=E5=93=81?= =?UTF-8?q?=E5=92=A8=E8=AF=A2=E5=88=86=E4=BA=AB=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 goods-card 商品卡片组件,支持在聊天中展示商品信息 - 优化 goods-detail 立即咨询功能,自动发送结构化商品消息 - 完善 chat-detail 页面,支持解析和展示商品卡片消息 - 消息格式支持 JSON 结构化数据,包含商品详情、图片、价格等信息 --- components/goods-card/goods-card.js | 43 +++++++ components/goods-card/goods-card.json | 4 + components/goods-card/goods-card.wxml | 33 ++++++ components/goods-card/goods-card.wxss | 159 +++++++++++++++++++++++++ pages/chat-detail/index.js | 18 ++- pages/chat-detail/index.json | 5 +- pages/chat-detail/index.wxml | 19 ++- pages/chat-detail/index.wxss | 50 ++++++++ pages/goods-detail/goods-detail.js | 161 +++++++++++++++++++++++--- 9 files changed, 476 insertions(+), 16 deletions(-) create mode 100644 components/goods-card/goods-card.js create mode 100644 components/goods-card/goods-card.json create mode 100644 components/goods-card/goods-card.wxml create mode 100644 components/goods-card/goods-card.wxss diff --git a/components/goods-card/goods-card.js b/components/goods-card/goods-card.js new file mode 100644 index 0000000..1ad8696 --- /dev/null +++ b/components/goods-card/goods-card.js @@ -0,0 +1,43 @@ +Component({ + properties: { + id: { type: String, value: '' }, + name: { type: String, value: '' }, + imageUrl: { type: String, value: '' }, + price: { type: [String, Number], value: '' }, + priceUnit: { type: String, value: '/件' }, + region: { type: String, value: '' }, + specification: { type: String, value: '' }, + spec: { type: String, value: '' }, + specs: { type: String, value: '' }, + displaySpecification: { type: String, value: '' }, + displayYolk: { type: String, value: '' }, + sourceType: { type: String, value: '' }, + totalStock: { type: [String, Number], value: '' }, + supplyStatus: { type: String, value: '' }, + status: { type: String, value: '' }, + reservedCount: { type: [String, Number], value: 0 } + }, + + data: { + isSoldOut: false + }, + + observers: { + 'status': function(status) { + this.setData({ + isSoldOut: status === 'sold_out' + }); + } + }, + + methods: { + onTap: function() { + const goodsId = this.properties.id; + if (goodsId) { + wx.navigateTo({ + url: `/pages/goods-detail/goods-detail?id=${goodsId}` + }); + } + } + } +}); diff --git a/components/goods-card/goods-card.json b/components/goods-card/goods-card.json new file mode 100644 index 0000000..a89ef4d --- /dev/null +++ b/components/goods-card/goods-card.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} diff --git a/components/goods-card/goods-card.wxml b/components/goods-card/goods-card.wxml new file mode 100644 index 0000000..26db4ae --- /dev/null +++ b/components/goods-card/goods-card.wxml @@ -0,0 +1,33 @@ + + + + + 暂无图片 + + 预售 + 现货 + 售空 + + + {{name || '商品名称'}} + {{displaySpecification}}{{displayYolk ? ' | ' + displayYolk : ''}} + + {{sourceType || ''}} + 库存:{{totalStock && totalStock !== '充足' ? totalStock + '件' : (totalStock || '充足')}} + + + + ¥ + {{price || '0'}} + {{priceUnit || '/件'}} + + {{region || ''}} + + + diff --git a/components/goods-card/goods-card.wxss b/components/goods-card/goods-card.wxss new file mode 100644 index 0000000..e203bd5 --- /dev/null +++ b/components/goods-card/goods-card.wxss @@ -0,0 +1,159 @@ +.goods-card { + width: 100%; + max-width: 560rpx; + background: #fff; + border-radius: 16rpx; + overflow: hidden; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); + display: flex; + flex-direction: column; +} + +.goods-card.sold-out { + opacity: 0.7; +} + +.goods-image-area { + position: relative; + width: 100%; + height: 280rpx; + background: #f5f5f5; +} + +.goods-image { + width: 100%; + height: 100%; + display: block; + object-fit: cover; +} + +.goods-image-placeholder { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background: #f0f0f0; + color: #999; + font-size: 24rpx; +} + +.promo-tag { + position: absolute; + top: 0; + left: 0; + padding: 6rpx 12rpx; + font-size: 20rpx; + color: #fff; + border-radius: 0 0 12rpx 0; + z-index: 1; + font-weight: 600; +} + +.promo-tag.presale { + background: linear-gradient(135deg, #ff6b00 0%, #ff8c00 100%); +} + +.promo-tag.in-stock { + background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%); +} + +.promo-tag.sold-out { + background: linear-gradient(135deg, #a92a2a 0%, #a6a6a6 100%); +} + +.goods-info { + padding: 16rpx; + display: flex; + flex-direction: column; + gap: 8rpx; +} + +.goods-title { + font-size: 26rpx; + color: #000000; + line-height: 1.4; + height: 72rpx; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + font-weight: 700; +} + +.goods-spec { + font-size: 22rpx; + color: #666; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.goods-tags { + display: flex; + flex-wrap: nowrap; + align-items: center; + gap: 8rpx; + margin: 6rpx 0; +} + +.tag { + font-size: 20rpx; + padding: 4rpx 10rpx; + border-radius: 6rpx; +} + +.tag.source-third { + background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%); + color: #fff; +} + +.tag.source-platform { + background: linear-gradient(135deg, #1677ff 0%, #4096ff 100%); + color: #fff; +} + +.tag.source-unverified { + background: rgba(0, 0, 0, 0.08); + color: #666; +} + +.tag.stock { + background: rgba(255, 77, 79, 0.08); + color: #666; +} + +.goods-bottom { + display: flex; + align-items: baseline; + justify-content: space-between; + margin-top: 6rpx; +} + +.goods-price { + display: flex; + align-items: baseline; +} + +.price-unit { + font-size: 24rpx; + color: #ff4d4f; + font-weight: 700; +} + +.price-value { + font-size: 36rpx; + color: #ff4d4f; + font-weight: 800; + margin: 0 2rpx; +} + +.goods-region { + font-size: 20rpx; + color: #999; + max-width: 100rpx; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/pages/chat-detail/index.js b/pages/chat-detail/index.js index abe1a97..b37b602 100644 --- a/pages/chat-detail/index.js +++ b/pages/chat-detail/index.js @@ -172,9 +172,25 @@ Page({ const processedMessages = res.map(message => { const sender = (message.sender_phone === userPhone) ? 'me' : 'other'; const time = this.formatDateTime(message.created_at); + + // 尝试解析JSON格式的商品消息 + let content = message.content; + let goodsData = null; + + try { + const parsed = JSON.parse(message.content); + if (parsed.type === 'goods' && parsed.goodsData) { + goodsData = parsed.goodsData; + content = parsed.text || ''; + } + } catch (e) { + // 不是JSON格式,使用原始内容 + } + return { id: message.id, - content: message.content, + content: content, + goodsData: goodsData, sender: sender, time: time, originalTime: message.created_at, diff --git a/pages/chat-detail/index.json b/pages/chat-detail/index.json index 796c826..79cf89c 100644 --- a/pages/chat-detail/index.json +++ b/pages/chat-detail/index.json @@ -1,3 +1,6 @@ { - "navigationBarTitleText": "聊天详情" + "navigationBarTitleText": "聊天详情", + "usingComponents": { + "goods-card": "/components/goods-card/goods-card" + } } \ No newline at end of file diff --git a/pages/chat-detail/index.wxml b/pages/chat-detail/index.wxml index e7c0edf..5dd5bc1 100644 --- a/pages/chat-detail/index.wxml +++ b/pages/chat-detail/index.wxml @@ -28,7 +28,24 @@ - {{item.content}} + + + + + + {{item.content}} {{item.time}} diff --git a/pages/chat-detail/index.wxss b/pages/chat-detail/index.wxss index 96571c1..b31d79d 100644 --- a/pages/chat-detail/index.wxss +++ b/pages/chat-detail/index.wxss @@ -233,4 +233,54 @@ .send-button:hover { background-color: #FF526D; +} + +/* 商品消息卡片样式 */ +.goods-message-card { + width: 100%; + min-width: 280rpx; + max-width: 400rpx; +} + +.goods-message-card .goods-card { + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08); +} + +/* 商品卡片在小消息气泡中的适配 */ +.message-item .message-bubble { + padding: 12rpx; +} + +.goods-message-card .goods-image-area { + height: 200rpx; +} + +.goods-message-card .goods-info { + padding: 12rpx; +} + +.goods-message-card .goods-title { + font-size: 24rpx; + height: 66rpx; +} + +.goods-message-card .goods-spec { + font-size: 20rpx; +} + +.goods-message-card .goods-tags { + margin: 4rpx 0; +} + +.goods-message-card .tag { + font-size: 18rpx; + padding: 2rpx 6rpx; +} + +.goods-message-card .price-value { + font-size: 32rpx; +} + +.goods-message-card .price-unit { + font-size: 22rpx; } \ No newline at end of file diff --git a/pages/goods-detail/goods-detail.js b/pages/goods-detail/goods-detail.js index 1ebc8bc..3d92fff 100644 --- a/pages/goods-detail/goods-detail.js +++ b/pages/goods-detail/goods-detail.js @@ -81,6 +81,92 @@ function formatShareTitle(goodsDetail) { return goodsDetail.name ? `优质鸡蛋 - ${goodsDetail.name}` : '优质鸡蛋货源'; } +// 构建商品分享消息内容 +function buildShareGoodsMessage(goodsDetail) { + const parts = []; + + // 商品名称 + if (goodsDetail.name) { + parts.push(`【商品】${goodsDetail.name}`); + } + + // 规格 + const specification = (goodsDetail.specification || goodsDetail.spec || goodsDetail.specs || '').trim(); + if (specification) { + parts.push(`【规格】${specification}`); + } + + // 地区 + const region = (goodsDetail.region || '').trim(); + if (region) { + parts.push(`【地区】${region}`); + } + + // 数量 + const quantity = (goodsDetail.quantity || '').trim(); + if (quantity) { + parts.push(`【数量】${quantity}`); + } + + // 价格 + if (goodsDetail.price) { + parts.push(`【价格】${goodsDetail.price}`); + } + + // 货源类型 + const sourceType = (goodsDetail.sourceType || '').trim(); + if (sourceType) { + parts.push(`【货源】${sourceType}`); + } + + // 联系人 + if (goodsDetail.product_contact) { + parts.push(`【联系人】${goodsDetail.product_contact}`); + } + + // 联系电话 + if (goodsDetail.contact_phone) { + parts.push(`【电话】${goodsDetail.contact_phone}`); + } + + // 蛋黄颜色 + const yolk = (goodsDetail.yolk || '').trim(); + if (yolk) { + parts.push(`【蛋黄】${yolk}`); + } + + // 蛋壳颜色/品种 + const eggshell = (goodsDetail.eggshell || goodsDetail.shell || goodsDetail.breed || '').trim(); + if (eggshell) { + parts.push(`【蛋壳/品种】${eggshell}`); + } + + // 新鲜程度 + const freshness = (goodsDetail.freshness || '').trim(); + if (freshness) { + parts.push(`【新鲜程度】${freshness}`); + } + + // 备注描述 + const description = (goodsDetail.description || '').trim(); + if (description) { + parts.push(`【备注】${description}`); + } + + // 获取第一张图片作为商品图片 + const imageUrls = goodsDetail.imageUrls || []; + const firstImage = imageUrls.find(url => !isVideoUrl(url)); + + let message = parts.join('\n'); + + // 如果有图片,添加图片链接 + if (firstImage) { + message += `\n\n【商品图片】${firstImage}`; + } + + return message; +} + // 获取适合分享的图片 - 优先使用正方形图片填满分享框 function getShareImageUrl(goodsDetail) { const imageUrls = goodsDetail.imageUrls || []; @@ -1379,19 +1465,68 @@ Page({ // 使用联系人手机号作为聊天会话ID const chatSessionId = contactPhone; - // 跳转到聊天页面,确保正确传递联系人手机号和用户名 - wx.navigateTo({ - url: `/pages/chat-detail/index?userId=${chatSessionId}&userName=${encodeURIComponent(contactName || '联系人')}&phone=${contactPhone}&isManager=true`, - success: function () { - console.log('成功跳转到聊天详情页'); - }, - fail: function (error) { - console.error('跳转到聊天详情页失败:', error); - wx.showToast({ - title: '聊天功能开发中', - icon: 'none' - }); - } + // 构建商品分享消息内容(包含显示文本和结构化数据) + const goodsDetail = this.data.goodsDetail; + + // 构建结构化的商品消息 + const goodsData = { + id: goodsDetail.id || '', + name: goodsDetail.name || '', + imageUrl: (goodsDetail.imageUrls && goodsDetail.imageUrls.length > 0) ? + (goodsDetail.imageUrls.find(url => !isVideoUrl(url)) || '') : '', + price: goodsDetail.price || '', + region: goodsDetail.region || '', + displaySpecification: goodsDetail.displaySpecification || goodsDetail.specification || goodsDetail.spec || goodsDetail.specs || '', + displayYolk: goodsDetail.displayYolk || goodsDetail.yolk || '', + sourceType: goodsDetail.sourceType || '', + totalStock: goodsDetail.totalStock || goodsDetail.stock || '', + supplyStatus: goodsDetail.supplyStatus || goodsDetail.status === 'sold_out' ? '' : (goodsDetail.supplyStatus || ''), + status: goodsDetail.status || '' + }; + + // 构建显示文本(兼容旧版本) + const displayText = buildShareGoodsMessage(goodsDetail); + + // 发送结构化商品消息(JSON格式,包含goodsData用于展示卡片) + const structuredMessage = JSON.stringify({ + type: 'goods', + text: displayText, + goodsData: goodsData + }); + + // 发送商品分享消息 + API.sendMessage(userPhone, contactPhone, structuredMessage).then(sendRes => { + console.log('商品分享消息发送成功:', sendRes); + // 跳转到聊天页面 + wx.navigateTo({ + url: `/pages/chat-detail/index?userId=${chatSessionId}&userName=${encodeURIComponent(contactName || '联系人')}&phone=${contactPhone}&isManager=true`, + success: function () { + console.log('成功跳转到聊天详情页'); + }, + fail: function (error) { + console.error('跳转到聊天详情页失败:', error); + wx.showToast({ + title: '聊天功能开发中', + icon: 'none' + }); + } + }); + }).catch(sendErr => { + console.error('发送商品分享消息失败:', sendErr); + // 即使发送消息失败,也跳转到聊天页面 + wx.navigateTo({ + url: `/pages/chat-detail/index?userId=${chatSessionId}&userName=${encodeURIComponent(contactName || '联系人')}&phone=${contactPhone}&isManager=true`, + success: function () { + console.log('成功跳转到聊天详情页'); + }, + fail: function (error) { + console.error('跳转到聊天详情页失败:', error); + wx.showToast({ + title: '聊天功能开发中', + icon: 'none' + }); + } + }); }); }).catch(err => { console.error('建立聊天失败:', err);