diff --git a/app.json b/app.json index 0c9b330..6b6d02b 100644 --- a/app.json +++ b/app.json @@ -11,6 +11,7 @@ "pages/notopen/index", "pages/create-supply/index", "pages/goods-detail/goods-detail", + "pages/goods-update/goods-update", "pages/chat/index", "pages/chat-detail/index", "pages/message-list/index", diff --git a/pages/goods-update/goods-update.js b/pages/goods-update/goods-update.js new file mode 100644 index 0000000..9d6ca0d --- /dev/null +++ b/pages/goods-update/goods-update.js @@ -0,0 +1,1145 @@ +// pages/goods-update/goods-update.js +const API = require('../../utils/api.js') + +// 根据sourceType获取对应的颜色 +function getSourceTypeColor(sourceType) { + const colorMap = { + '三方认证': '#4d9dff', + '三方未认证': '#ff4d4f', + '平台货源': '#2ad21f' + }; + return colorMap[sourceType] || '#4d9dff'; +} + +// 媒体类型判断函数 +function isVideoUrl(url) { + if (!url || typeof url !== 'string') { + return false; + } + // 转换为小写,确保大小写不敏感 + const lowerUrl = url.toLowerCase(); + // 支持的视频格式 + const videoExtensions = ['.mp4', '.mov', '.avi', '.wmv', '.flv', '.webm', '.m4v', '.3gp']; + // 检查URL是否以视频扩展名结尾 + for (const ext of videoExtensions) { + if (lowerUrl.endsWith(ext)) { + return true; + } + } + return false; +} + +// 预处理媒体URL,返回包含type字段的媒体对象数组 +function processMediaUrls(urls) { + if (!urls || !Array.isArray(urls)) { + return []; + } + return urls.map(url => { + return { + url: url, + type: isVideoUrl(url) ? 'video' : 'image' + }; + }); +} + +// 格式化毛重显示的辅助函数 +function formatGrossWeight(grossWeight, weight) { + if (grossWeight !== null && grossWeight !== undefined && grossWeight !== '') { + return grossWeight; + } + if (weight !== null && weight !== undefined && weight !== '') { + return weight; + } + return ""; +} + +// 提取地区中的省份信息 +function extractProvince(region) { + if (!region || typeof region !== 'string') { + return region; + } + + // 查找各种省份格式的位置 + const provinceEndIndex = region.indexOf('省'); + const autonomousRegionEndIndex = region.indexOf('自治区'); + const municipalityEndIndex = region.indexOf('市'); // 用于直辖市,如北京市、上海市 + const specialRegionEndIndex = region.indexOf('特别行政区'); // 用于香港、澳门 + + if (provinceEndIndex !== -1) { + // 包含"省"字,提取到"省"字结束 + return region.substring(0, provinceEndIndex + 1); + } else if (autonomousRegionEndIndex !== -1) { + // 包含"自治区",提取到"自治区"结束 + return region.substring(0, autonomousRegionEndIndex + 3); + } else if (specialRegionEndIndex !== -1) { + // 包含"特别行政区",提取到"特别行政区"结束 + return region.substring(0, specialRegionEndIndex + 5); + } else if (municipalityEndIndex === 2) { + // 直辖市(如北京市、上海市),市字在第2个字符位置 + return region.substring(0, municipalityEndIndex + 1); + } + + // 如果没有找到匹配的格式,返回原字符串 + return region; +} + +// 格式化日期时间函数 +function formatDateTime(dateString) { + if (!dateString) return ''; + + // 尝试解析日期字符串 + const date = new Date(dateString); + + // 检查是否是有效的日期对象 + if (isNaN(date.getTime())) { + // 如果解析失败,返回原始字符串 + return dateString; + } + + // 如果是 ISO 格式的字符串(包含 T 字符),则转换为本地时间格式 + if (typeof dateString === 'string' && dateString.includes('T')) { + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const day = date.getDate().toString().padStart(2, '0'); + const hours = date.getHours().toString().padStart(2, '0'); + const minutes = date.getMinutes().toString().padStart(2, '0'); + return `${year}-${month}-${day} ${hours}:${minutes}`; + } + + // 对于其他格式的字符串,直接返回,不进行转换 + return dateString; +} + +// 处理净重件数对应数据 +function processWeightAndQuantityData(weightSpecString, quantityString, specString) { + console.log('===== 处理净重、件数和规格数据 ====='); + console.log('输入参数:'); + console.log('- weightSpecString:', weightSpecString, '(类型:', typeof weightSpecString, ')'); + console.log('- quantityString:', quantityString, '(类型:', typeof quantityString, ')'); + console.log('- specString:', specString, '(类型:', typeof specString, ')'); + + // 如果没有数据,返回空数组 + if (!weightSpecString && !quantityString && !specString) { + console.log('没有数据,返回空数组'); + return []; + } + + // 处理净重/规格字符串(它可能包含净重信息) + let weightSpecArray = []; + if (weightSpecString && typeof weightSpecString === 'string') { + // 支持多种逗号分隔符:英文逗号、中文逗号、全角逗号 + weightSpecArray = weightSpecString.split(/[,,、]/).map(item => item.trim()).filter(item => item); + console.log('从字符串分割得到净重规格数组:', weightSpecArray); + } else if (weightSpecString) { + weightSpecArray = [String(weightSpecString)]; + console.log('将净重规格转换为数组:', weightSpecArray); + } + + // 处理件数字符串 + let quantityArray = []; + if (quantityString && typeof quantityString === 'string') { + // 支持多种逗号分隔符:英文逗号、中文逗号、全角逗号 + quantityArray = quantityString.split(/[,,、]/).map(item => item.trim()).filter(item => item); + console.log('从字符串分割得到数量数组:', quantityArray); + } else if (quantityString) { + quantityArray = [String(quantityString)]; + console.log('将数量转换为数组:', quantityArray); + } + + // 获取最大长度,确保一一对应 + const maxLength = Math.max(weightSpecArray.length, quantityArray.length); + console.log('最大长度:', maxLength); + const result = []; + + for (let i = 0; i < maxLength; i++) { + const weightSpec = weightSpecArray[i] || ''; + const quantity = quantityArray[i] || ''; + + console.log(`处理第${i}组数据: weightSpec=${weightSpec}, quantity=${quantity}`); + + // 处理净重规格显示格式 - 根据内容类型添加相应前缀 + let weightSpecDisplay = ''; + if (weightSpec) { + if (weightSpec.includes('净重') || weightSpec.includes('毛重')) { + // 如果已包含"净重"或"毛重"前缀,保持不变 + weightSpecDisplay = weightSpec; + } else { + // 否则,根据内容自动判断添加前缀 + if (weightSpec.includes('-')) { + // 如果包含"-",认为是净重范围,添加"净重"前缀 + weightSpecDisplay = `净重${weightSpec}`; + } else { + // 否则,认为是毛重,添加"毛重"前缀 + weightSpecDisplay = `毛重${weightSpec}`; + } + } + } + + // 处理件数显示格式 + let quantityDisplay = quantity; + if (quantity && !quantity.includes('件')) { + // 如果不包含"件"后缀,添加"件"后缀 + quantityDisplay = `${quantity}件`; + } + + // 构建显示文本 + let displayText = ''; + if (weightSpecDisplay && quantityDisplay) { + // 如果有净重和件数,格式为:净重XX-XX——XXX件 + displayText = `${weightSpecDisplay}——${quantityDisplay}`; + } else if (weightSpecDisplay) { + // 只有净重 + displayText = weightSpecDisplay; + } else if (quantityDisplay) { + // 只有件数 + displayText = quantityDisplay; + } + + if (displayText) { + result.push({ display: displayText }); + console.log(`添加显示文本: ${displayText}`); + } + } + + console.log('净重件数对应数据处理结果:', result); + return result; +} + +Page({ + // 分享给朋友/群聊 + onShareAppMessage() { + const goodsDetail = this.data.goodsDetail || {}; + const title = goodsDetail.name ? `优质鸡蛋 - ${goodsDetail.name}` : '优质鸡蛋货源'; + + return { + title: title, + path: `/pages/goods-update/goods-update?productId=${goodsDetail.id || goodsDetail.productId}`, + imageUrl: goodsDetail.imageUrls && goodsDetail.imageUrls.length > 0 ? goodsDetail.imageUrls[0] : '/images/你有好蛋.png' + } + }, + + data: { + goodsDetail: {}, // 当前商品详情 + showImagePreview: false, // 控制图片预览弹窗显示 + previewImageUrls: [], // 预览的图片URL列表 + previewImageIndex: 0, // 当前预览图片的索引 + showEditModal: false, // 控制编辑弹窗显示 + showSpecSelectModal: false, // 控制规格选择弹窗显示 + modalSpecSearchKeyword: '', // 规格弹窗中的搜索关键词 + filteredModalSpecOptions: [], // 弹窗中过滤后的规格选项 + selectedModalSpecIndex: -1, // 弹窗中选中的规格索引 + currentSpecMode: 'edit', // 当前规格选择模式:create 或 edit + showNameSelectModal: false, // 控制商品名称选择弹窗显示 + showYolkSelectModal: false, // 控制蛋黄选择弹窗显示 + selectedNameIndex: -1, // 商品名称弹窗中选中的索引 + selectedYolkIndex: -1,//蛋黄弹窗中选中的索引, + // 商品名称选项列表 + productNameOptions: ['罗曼粉', '伊莎粉', '罗曼灰', '海蓝灰', '海蓝褐', '绿壳', '粉一', '粉二', '粉八', '京粉1号', '京红', '京粉6号', '京粉3号', '农大系列', '黑鸡土蛋', '双黄蛋', '大午金凤', '黑凤'], + // 蛋黄选项 + yolkOptions: ['红心', '黄心', '双色'], + // 规格选项 + specOptions: ['格子装', '散托', '不限规格', '净重47+', '净重46-47', '净重45-46', '净重44-45', '净重43-44', '净重42-43', '净重41-42', '净重40-41', '净重39-40', '净重38-39', '净重37-39', '净重37-38', '净重36-38', '净重36-37', '净重35-36', '净重34-35', '净重33-34', '净重32-33', '净重32-34', '净重31-32', '净重30-35', '净重30-34', '净重30-32', '净重30-31', '净重29-31', '净重29-30', '净重28-29', '净重28以下', '毛重52以上', '毛重50-51', '毛重48-49', '毛重47-48', '毛重46-47', '毛重45-47', '毛重45-46', '毛重44-45', '毛重43-44', '毛重42-43', '毛重41-42', '毛重40-41', '毛重38-39', '毛重36-37', '毛重34-35', '毛重32-33', '毛重30-31', '毛重30以下'], + // 编辑货源数据 + editSupply: { + id: '', + imageUrls: [], + name: '', + price: '', + minOrder: '', + yolk: '', + spec: '', + region: '', + grossWeight: '' + }, + // 图片缩放相关状态 + scale: 1, // 当前缩放比例 + lastScale: 1, // 上一次缩放比例 + startDistance: 0, // 双指起始距离 + doubleTapTimer: null, // 双击计时器 + lastTapTime: 0, // 上一次单击时间 + isScaling: false, // 是否正在缩放中 + offsetX: 0, // X轴偏移量 + offsetY: 0, // Y轴偏移量 + initialTouch: null, // 初始触摸点 + }, + + onLoad: function (options) { + console.log('商品编辑页面加载,参数:', options); + + // 解析传入的商品数据 + let goodsData = null; + if (options.goodsData) { + try { + goodsData = JSON.parse(decodeURIComponent(options.goodsData)); + console.log('解析后的商品数据:', goodsData); + // 优先使用传入的商品数据 + this.setData({ + goodsDetail: goodsData + }); + } catch (error) { + console.error('解析商品数据失败:', error); + } + } + + // 从商品数据中提取商品ID + let productId; + if (goodsData && goodsData.productId) { + // 优先使用字符串类型的productId + productId = goodsData.productId; + } else if (options.productId) { + productId = options.productId; + } else if (goodsData && goodsData.id) { + // 如果没有productId,再尝试使用id + productId = goodsData.id; + } else { + console.error('未找到商品ID'); + wx.showToast({ + title: '商品信息有误', + icon: 'none', + duration: 2000 + }); + // 2秒后返回上一页 + setTimeout(() => { + wx.navigateBack(); + }, 2000); + return; + } + + console.log('最终使用的商品ID:', productId); + + // 加载商品详情(即使已有goodsData,也调用API获取最新数据) + this.loadGoodsDetail(productId, goodsData); + }, + + loadGoodsDetail: function (productId, preloadedData = null) { + // 首先显示预加载的数据,确保UI快速响应 + if (preloadedData) { + console.log('使用预加载数据显示UI'); + } + + console.log('调用API获取商品详情,productId:', productId); + API.getProductDetail({ productId: productId }) + .then(res => { + console.log('获取商品详情成功:', res); + if (res && res.code === 200 && res.data) { + const product = res.data; + + // 只过滤hidden状态的商品 + if (product.status === 'hidden') { + wx.showToast({ + title: '商品已下架', + icon: 'none', + duration: 2000 + }); + // 2秒后返回上一页 + setTimeout(() => { + wx.navigateBack(); + }, 2000); + return; + } + + // 确保商品ID的一致性 + const productIdStr = String(product.productId || product.id); + + // 关键修改:直接使用API返回的reservedCount值 + const finalReservationCount = product.reservedCount || 0; + + // 确保imageUrls是数组 + let imageUrls = product.imageUrls || []; + if (!Array.isArray(imageUrls)) { + console.error('imageUrls不是数组,转换为数组'); + imageUrls = [imageUrls]; + } + + // 处理grossWeight为null或无效的情况,返回空字符串以支持文字输入 + const grossWeightValue = product.grossWeight !== null && product.grossWeight !== undefined ? product.grossWeight : ''; + + // 转换supplyStatus字段值 + let supplyStatusValue = product.supplyStatus || ''; + // 将"平台货源"、"三方认证"、"三方未认证"修改为"现货"、"预售" + if (supplyStatusValue === '平台货源' || supplyStatusValue === '三方认证') { + supplyStatusValue = '现货'; + } else if (supplyStatusValue === '三方未认证') { + supplyStatusValue = '预售'; + } + + // 预处理媒体URL,添加类型信息 + const mediaItems = processMediaUrls(imageUrls || []); + console.log('预处理后的媒体数据:', mediaItems); + + // 处理净重、件数据和规格数据,获取一一对应的显示数组 + // 注意:数据库中的规格字段包含净重信息,我们需要与件数数据正确匹配 + + // 首先处理净重和规格数据(它们可能都在spec字段中) + let weightSpecString = ''; + let quantityString = ''; + + // 检查规格字段是否包含净重或毛重信息 + console.log('=== 数据库字段调试信息 ==='); + console.log('product.spec:', product.spec); + console.log('product.specification:', product.specification); + console.log('product.quantity:', product.quantity); + console.log('product.minOrder:', product.minOrder); + + if (product.spec && typeof product.spec === 'string' && (product.spec.includes('净重') || product.spec.includes('毛重'))) { + // 如果规格字段包含净重或毛重信息,则使用该字段作为重量规格数据 + weightSpecString = product.spec; + console.log('使用规格字段作为重量规格数据:', weightSpecString); + } else if (product.specification && typeof product.specification === 'string' && (product.specification.includes('净重') || product.specification.includes('毛重'))) { + // 检查specification字段 + weightSpecString = product.specification; + console.log('使用specification字段作为重量规格数据:', weightSpecString); + } else if (grossWeightValue) { + // 如果有单独的重量字段,则使用该字段 + weightSpecString = grossWeightValue; + console.log('使用重量字段作为重量规格数据:', weightSpecString); + } else { + console.log('未找到重量规格数据'); + } + + // 处理件数数据 + console.log('=== 件数数据调试信息 ==='); + console.log('原始件数数据:', product.quantity); + console.log('原始minOrder数据:', product.minOrder); + + // 修复:与格式化数据保持一致,优先使用minOrder + if (product.minOrder) { + quantityString = String(product.minOrder); + console.log('使用minOrder作为件数数据:', quantityString); + } else if (product.quantity && typeof product.quantity === 'string') { + quantityString = product.quantity; + console.log('件数数据为字符串:', quantityString); + } else if (product.quantity) { + // 如果件数不是字符串,转换为字符串 + quantityString = String(product.quantity); + console.log('件数数据转换为字符串:', quantityString); + } else { + console.log('未找到件数数据'); + } + + console.log('准备传递给processWeightAndQuantityData的数据:', { + weightSpecString: weightSpecString, + quantityString: quantityString + }); + + const weightQuantityData = processWeightAndQuantityData(weightSpecString, quantityString, ''); + + console.log('=== 处理结果调试信息 ==='); + console.log('weightSpecString:', weightSpecString); + console.log('quantityString:', quantityString); + console.log('weightQuantityData处理结果:', weightQuantityData); + + // 处理规格信息,生成格式化的specInfo + let specInfo = []; + const spec = product.spec || product.specification || ''; + const minOrder = product.minOrder || product.quantity; + + // 生成格式化的规格信息 + if (spec && minOrder) { + // 如果有规格和件数,生成格式:"毛重48-49——200件" + if (grossWeightValue) { + specInfo.push(`毛重${grossWeightValue}——${minOrder}件`); + } else { + specInfo.push(`${spec}——${minOrder}件`); + } + } else if (spec) { + specInfo.push(spec); + } else if (grossWeightValue) { + specInfo.push(`毛重${grossWeightValue}`); + } + + // 确定creatorName - 优先使用预加载数据,然后使用与goods页面相同的逻辑 + console.log('产品seller信息:', JSON.stringify(product.seller)); + console.log('预加载数据:', preloadedData); + + // 优先使用预加载数据中的creatorName,如果没有则使用API返回的数据 + let creatorName; + if (preloadedData && preloadedData.creatorName) { + creatorName = preloadedData.creatorName; + console.log('使用预加载数据中的creatorName:', creatorName); + } else { + creatorName = product.seller?.nickName || product.seller?.sellerNickName || product.seller?.name || product.name || '未知'; + console.log('使用API返回数据生成creatorName:', creatorName); + } + + // 格式化创建时间 + const createdAt = preloadedData?.created_at || preloadedData?.createdAt || product.created_at || product.createdAt; + const formattedCreatedAt = formatDateTime(createdAt); + console.log('formattedCreatedAt:', formattedCreatedAt); + + // 详细追踪地区信息 + console.log('=== 地区信息详细追踪 ==='); + console.log('预加载数据中的region:', preloadedData?.region); + console.log('原始product.region:', product.region, '(类型:', typeof product.region, ')'); + console.log('product是否有region属性:', 'region' in product); + + // 确定最终的地区值 - 优先使用预加载数据 + const finalRegion = preloadedData?.region || product.region || product.area || product.location || '暂无'; + console.log('finalRegion:', finalRegion); + + // 转换商品数据格式 + const formattedGoods = { + id: productIdStr, + productId: productIdStr, + // 直接使用数据库字段名 + name: product.productName || product.name || '商品名称', + price: product.price, + minOrder: minOrder, + yolk: product.yolk, + spec: spec, + specInfo: specInfo, // 添加格式化的规格信息 + // 保留原始字段引用,确保数据完整性 + imageUrls: imageUrls || [], + // 添加预处理后的媒体数据,包含类型信息 + mediaItems: mediaItems, + displayGrossWeight: formatGrossWeight(grossWeightValue, product.weight), + created_at: product.created_at || product.createdAt, + updated_at: product.updated_at || product.updatedAt, + status: product.status, + supplyStatus: supplyStatusValue, + sourceType: product.sourceType || '', + sourceTypeColor: getSourceTypeColor(product.sourceType), + // 添加净重和件数的一一对应数据 + weightQuantityData: weightQuantityData, + // 格式化创建时间 + formattedCreatedAt: formattedCreatedAt, + // 创建者信息 + creatorName: creatorName, + // 地区信息(先设置,后面会被覆盖) + region: finalRegion, + // 复制原始产品对象中的所有字段,确保不丢失任何数据 + ...product, + // 添加产品包装字段(放在product之后,确保不被覆盖) + producting: product.producting || '', + // 添加货源描述字段 + description: product.description || product.remark || '', + // 直接使用数据库字段名,确保与表结构完全一致,放在后面覆盖前面的值 + product_contact: product.product_contact || '联系人信息暂不可用', + contact_phone: product.contact_phone || '暂无联系电话', + // 确保地区信息正确显示,放在最后覆盖所有来源的值 + region: finalRegion, + // 确保reservedCount字段使用我们计算得到的值,放在最后以覆盖其他来源的值 + reservedCount: finalReservationCount + }; + + console.log('最终formattedGoods.region:', formattedGoods.region); + + // 调试输出完整的formattedGoods对象 + console.log('最终格式化的商品数据:', JSON.stringify(formattedGoods, null, 2)); + + this.setData({ + goodsDetail: formattedGoods + }); + } else { + wx.showToast({ + title: '获取商品详情失败', + icon: 'none', + duration: 2000 + }); + } + }) + .catch(err => { + console.error('获取商品详情失败:', err); + wx.showToast({ + title: '获取商品详情失败', + icon: 'none', + duration: 2000 + }); + }) + .finally(() => { + wx.hideLoading(); + }); + }, + + // 显示编辑弹窗 + showEditModal: function() { + console.log('显示编辑弹窗'); + const goodsDetail = this.data.goodsDetail; + + // 设置编辑数据 + this.setData({ + editSupply: { + id: goodsDetail.id || goodsDetail.productId, + imageUrls: goodsDetail.imageUrls || [], + name: goodsDetail.name || '', + price: goodsDetail.price || '', + minOrder: goodsDetail.minOrder || '', + yolk: goodsDetail.yolk || '', + spec: goodsDetail.spec || '', + region: goodsDetail.region || '', + grossWeight: goodsDetail.grossWeight || '' + }, + showEditModal: true + }); + }, + + // 隐藏编辑弹窗 + hideEditModal: function() { + this.setData({ + showEditModal: false + }); + }, + + // 保存编辑 + saveEdit: function() { + console.log('保存编辑'); + const editSupply = this.data.editSupply; + + // 验证必填字段 + if (!editSupply.name) { + wx.showToast({ + title: '请填写商品名称', + icon: 'none', + duration: 2000 + }); + return; + } + + if (!editSupply.price) { + wx.showToast({ + title: '请填写价格', + icon: 'none', + duration: 2000 + }); + return; + } + + wx.showLoading({ + title: '保存中...', + mask: true + }); + + // 调用API更新商品 + const productId = editSupply.productId || editSupply.id; + API.editProduct(productId, { + productName: editSupply.name, + price: editSupply.price, + quantity: Number(editSupply.minOrder), + grossWeight: editSupply.grossWeight !== undefined && editSupply.grossWeight !== null && editSupply.grossWeight !== '' ? editSupply.grossWeight : "", + yolk: editSupply.yolk, + specification: editSupply.spec || '', + region: editSupply.region || '', + imageUrls: editSupply.imageUrls || [], + }) + .then(res => { + wx.hideLoading(); + console.log('更新商品成功:', res); + if (res && res.code === 200) { + wx.showToast({ + title: '更新成功', + icon: 'success', + duration: 2000 + }); + + // 隐藏编辑弹窗 + this.hideEditModal(); + + // 重新加载商品详情 + this.loadGoodsDetail(productId); + } else { + wx.showToast({ + title: '更新失败', + icon: 'none', + duration: 2000 + }); + } + }) + .catch(err => { + wx.hideLoading(); + console.error('更新商品失败:', err); + wx.showToast({ + title: '更新失败', + icon: 'none', + duration: 2000 + }); + }); + }, + + // 准备上架 + preparePublishSupply: function() { + console.log('准备上架商品'); + const goodsDetail = this.data.goodsDetail; + const productId = goodsDetail.id || goodsDetail.productId; + + wx.showModal({ + title: '确认上架', + content: '确定要上架此商品吗?', + success: (res) => { + if (res.confirm) { + this.publishSupply(productId); + } + } + }); + }, + + // 上架商品 + publishSupply: function(productId) { + console.log('上架商品,productId:', productId); + wx.showLoading({ + title: '上架中...', + mask: true + }); + + // 获取商品数据 + const goodsDetail = this.data.goodsDetail; + + // 调用API上架商品 + API.publishProduct(goodsDetail) + .then(res => { + wx.hideLoading(); + console.log('上架商品成功:', res); + if (res && res.code === 200) { + wx.showToast({ + title: '上架成功', + icon: 'success', + duration: 2000 + }); + + // 重新加载商品详情 + this.loadGoodsDetail(productId); + } else { + wx.showToast({ + title: '上架失败', + icon: 'none', + duration: 2000 + }); + } + }) + .catch(err => { + wx.hideLoading(); + console.error('上架商品失败:', err); + wx.showToast({ + title: '上架失败', + icon: 'none', + duration: 2000 + }); + }); + }, + + // 编辑输入处理 + onEditInput: function(e) { + const field = e.currentTarget.dataset.field; + const value = e.detail.value; + + this.setData({ + [`editSupply.${field}`]: value + }); + }, + + // 打开规格选择弹窗(编辑模式) + onEditSpecChange: function() { + console.log('打开规格选择弹窗(编辑模式)'); + const editSupply = this.data.editSupply; + const specOptions = this.data.specOptions; + + // 查找当前规格在选项中的索引 + const currentSpecIndex = specOptions.indexOf(editSupply.spec); + + this.setData({ + showSpecSelectModal: true, + currentSpecMode: 'edit', + selectedModalSpecIndex: currentSpecIndex >= 0 ? currentSpecIndex : -1, + modalSpecSearchKeyword: '', + filteredModalSpecOptions: specOptions + }); + }, + + // 关闭规格选择弹窗 + closeSpecSelectModal: function() { + this.setData({ + showSpecSelectModal: false + }); + }, + + // 规格弹窗搜索输入 + onModalSpecSearchInput: function(e) { + const keyword = e.detail.value; + const specOptions = this.data.specOptions; + + // 过滤规格选项 + const filteredOptions = specOptions.filter(option => { + return option.includes(keyword); + }); + + this.setData({ + modalSpecSearchKeyword: keyword, + filteredModalSpecOptions: filteredOptions, + selectedModalSpecIndex: -1 + }); + }, + + // 清除规格弹窗搜索关键词 + clearModalSpecSearch: function() { + this.setData({ + modalSpecSearchKeyword: '', + filteredModalSpecOptions: this.data.specOptions, + selectedModalSpecIndex: -1 + }); + }, + + // 选择规格 + onModalSpecSelect: function(e) { + const index = e.currentTarget.dataset.index; + this.setData({ + selectedModalSpecIndex: index + }); + }, + + // 确认规格选择 + confirmSpecSelection: function() { + const selectedIndex = this.data.selectedModalSpecIndex; + const filteredOptions = this.data.filteredModalSpecOptions; + const currentSpecMode = this.data.currentSpecMode; + + if (selectedIndex >= 0 && selectedIndex < filteredOptions.length) { + const selectedSpec = filteredOptions[selectedIndex]; + + if (currentSpecMode === 'edit') { + // 编辑模式 + this.setData({ + [`editSupply.spec`]: selectedSpec + }); + } + + this.closeSpecSelectModal(); + } + }, + + // 打开商品名称选择弹窗 + openNameSelectModal: function() { + console.log('打开商品名称选择弹窗'); + const editSupply = this.data.editSupply; + const productNameOptions = this.data.productNameOptions; + + // 查找当前商品名称在选项中的索引 + const currentNameIndex = productNameOptions.indexOf(editSupply.name); + + this.setData({ + showNameSelectModal: true, + selectedNameIndex: currentNameIndex >= 0 ? currentNameIndex : -1 + }); + }, + + // 关闭商品名称选择弹窗 + closeNameSelectModal: function() { + this.setData({ + showNameSelectModal: false + }); + }, + + // 选择商品名称 + onNameSelect: function(e) { + const index = e.currentTarget.dataset.index; + this.setData({ + selectedNameIndex: index + }); + }, + + // 确认商品名称选择 + confirmNameSelection: function() { + const selectedIndex = this.data.selectedNameIndex; + const productNameOptions = this.data.productNameOptions; + + if (selectedIndex >= 0 && selectedIndex < productNameOptions.length) { + const selectedName = productNameOptions[selectedIndex]; + + this.setData({ + [`editSupply.name`]: selectedName, + showNameSelectModal: false + }); + } + }, + + // 打开蛋黄选择弹窗 + openYolkSelectModal: function() { + console.log('打开蛋黄选择弹窗'); + const editSupply = this.data.editSupply; + const yolkOptions = this.data.yolkOptions; + + // 查找当前蛋黄在选项中的索引 + const currentYolkIndex = yolkOptions.indexOf(editSupply.yolk); + + this.setData({ + showYolkSelectModal: true, + selectedYolkIndex: currentYolkIndex >= 0 ? currentYolkIndex : -1 + }); + }, + + // 关闭蛋黄选择弹窗 + closeYolkSelectModal: function() { + this.setData({ + showYolkSelectModal: false + }); + }, + + // 选择蛋黄 + onYolkSelect: function(e) { + const index = e.currentTarget.dataset.index; + this.setData({ + selectedYolkIndex: index + }); + }, + + // 确认蛋黄选择 + confirmYolkSelection: function() { + const selectedIndex = this.data.selectedYolkIndex; + const yolkOptions = this.data.yolkOptions; + + if (selectedIndex >= 0 && selectedIndex < yolkOptions.length) { + const selectedYolk = yolkOptions[selectedIndex]; + + this.setData({ + [`editSupply.yolk`]: selectedYolk, + showYolkSelectModal: false + }); + } + }, + + // 选择图片 + chooseImage: function(e) { + const type = e.currentTarget.dataset.type; + const maxCount = 5; + const currentCount = type === 'edit' ? this.data.editSupply.imageUrls.length : 0; + const canChooseCount = maxCount - currentCount; + + if (canChooseCount <= 0) { + wx.showToast({ + title: '最多只能上传5张图片', + icon: 'none', + duration: 2000 + }); + return; + } + + wx.chooseImage({ + count: canChooseCount, + sizeType: ['compressed'], + sourceType: ['album', 'camera'], + success: (res) => { + const tempFilePaths = res.tempFilePaths; + + // 上传图片到服务器 + this.uploadImages(tempFilePaths, type); + }, + fail: (err) => { + console.error('选择图片失败:', err); + } + }); + }, + + // 上传图片 + uploadImages: function(filePaths, type) { + console.log('上传图片,type:', type); + wx.showLoading({ + title: '上传中...', + mask: true + }); + + // 这里应该调用API上传图片,获取图片URL + // 由于没有具体的上传API,这里模拟上传成功 + setTimeout(() => { + wx.hideLoading(); + + // 模拟上传成功,使用临时文件路径作为图片URL + if (type === 'edit') { + const editSupply = this.data.editSupply; + const newImageUrls = [...editSupply.imageUrls, ...filePaths]; + + this.setData({ + [`editSupply.imageUrls`]: newImageUrls + }); + } + + wx.showToast({ + title: '上传成功', + icon: 'success', + duration: 1500 + }); + }, 1500); + }, + + // 删除图片 + deleteImage: function(e) { + const index = e.currentTarget.dataset.index; + const type = e.currentTarget.dataset.type; + + if (type === 'edit') { + const editSupply = this.data.editSupply; + const newImageUrls = editSupply.imageUrls.filter((item, idx) => idx !== index); + + this.setData({ + [`editSupply.imageUrls`]: newImageUrls + }); + } + }, + + // 预览图片 + previewImage: function(e) { + const urls = e.currentTarget.dataset.urls; + const index = e.currentTarget.dataset.index; + + if (!urls || urls.length === 0) { + wx.showToast({ + title: '没有内容可预览', + icon: 'none' + }); + return; + } + + this.setData({ + showImagePreview: true, + previewImageUrls: urls, + previewImageIndex: parseInt(index || 0) + }); + this.resetZoom(); + }, + + // 关闭图片预览 + closeImagePreview: function() { + this.setData({ + showImagePreview: false + }); + this.resetZoom(); + }, + + // 重置缩放状态 + resetZoom: function() { + this.setData({ + scale: 1, + lastScale: 1, + offsetX: 0, + offsetY: 0, + initialTouch: null + }); + }, + + // 图片预览切换 + onPreviewImageChange: function(e) { + this.setData({ + previewImageIndex: e.detail.current + }); + // 切换图片时重置缩放状态 + this.resetZoom(); + }, + + // 处理图片点击事件(单击/双击判断) + handleImageTap: function(e) { + const currentTime = Date.now(); + const lastTapTime = this.data.lastTapTime || 0; + + // 判断是否为双击(300ms内连续点击) + if (currentTime - lastTapTime < 300) { + // 双击事件 + if (this.data.doubleTapTimer) { + clearTimeout(this.data.doubleTapTimer); + } + + // 切换放大/缩小状态 + const newScale = this.data.scale === 1 ? 2 : 1; + this.setData({ + scale: newScale, + lastScale: newScale, + offsetX: 0, + offsetY: 0, + lastTapTime: 0 // 重置双击状态 + }); + } else { + // 单击事件,设置延迟来检测是否会成为双击 + if (this.data.doubleTapTimer) { + clearTimeout(this.data.doubleTapTimer); + } + + this.setData({ + lastTapTime: currentTime, + doubleTapTimer: setTimeout(() => { + // 确认是单击,关闭图片预览 + this.closeImagePreview(); + }, 300) + }); + } + }, + + // 计算两点之间的距离 + calculateDistance: function(touch1, touch2) { + const dx = touch2.clientX - touch1.clientX; + const dy = touch2.clientY - touch1.clientY; + return Math.sqrt(dx * dx + dy * dy); + }, + + // 处理触摸开始事件 + handleTouchStart: function(e) { + const touches = e.touches; + + if (touches.length === 1) { + // 单指:准备拖动 + this.setData({ + initialTouch: { + x: touches[0].clientX, + y: touches[0].clientY + } + }); + } else if (touches.length === 2) { + // 双指:记录起始距离,准备缩放 + const distance = this.calculateDistance(touches[0], touches[1]); + this.setData({ + startDistance: distance, + isScaling: true, + lastScale: this.data.scale + }); + } + }, + + // 处理触摸移动事件 + handleTouchMove: function(e) { + const touches = e.touches; + + if (touches.length === 1 && this.data.initialTouch && this.data.scale !== 1) { + // 单指拖动(只有在缩放状态下才允许拖动) + const deltaX = touches[0].clientX - this.data.initialTouch.x; + const deltaY = touches[0].clientY - this.data.initialTouch.y; + + // 计算新的偏移量 + let newOffsetX = this.data.offsetX + deltaX; + let newOffsetY = this.data.offsetY + deltaY; + + // 边界限制 + const windowWidth = wx.getSystemInfoSync().windowWidth; + const windowHeight = wx.getSystemInfoSync().windowHeight; + const maxOffsetX = (windowWidth * (this.data.scale - 1)) / 2; + const maxOffsetY = (windowHeight * (this.data.scale - 1)) / 2; + + newOffsetX = Math.max(-maxOffsetX, Math.min(maxOffsetX, newOffsetX)); + newOffsetY = Math.max(-maxOffsetY, Math.min(maxOffsetY, newOffsetY)); + + this.setData({ + offsetX: newOffsetX, + offsetY: newOffsetY, + initialTouch: { + x: touches[0].clientX, + y: touches[0].clientY + } + }); + } else if (touches.length === 2) { + // 双指缩放 + const currentDistance = this.calculateDistance(touches[0], touches[1]); + const scale = (currentDistance / this.data.startDistance) * this.data.lastScale; + + // 限制缩放范围在0.5倍到3倍之间 + const newScale = Math.max(0.5, Math.min(3, scale)); + + this.setData({ + scale: newScale, + isScaling: true + }); + } + }, + + // 处理触摸结束事件 + handleTouchEnd: function(e) { + this.setData({ + isScaling: false, + lastScale: this.data.scale, + initialTouch: null + }); + } +}); \ No newline at end of file diff --git a/pages/goods-update/goods-update.json b/pages/goods-update/goods-update.json new file mode 100644 index 0000000..d58ab04 --- /dev/null +++ b/pages/goods-update/goods-update.json @@ -0,0 +1,6 @@ +{ + "navigationBarTitleText": "货源详情", + "usingComponents": {}, + "enablePullDownRefresh": false, + "disableScroll": false +} \ No newline at end of file diff --git a/pages/goods-update/goods-update.wxml b/pages/goods-update/goods-update.wxml new file mode 100644 index 0000000..65a3213 --- /dev/null +++ b/pages/goods-update/goods-update.wxml @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + {{goodsDetail.supplyStatus || '暂无状态'}} + {{goodsDetail.name}} + V + + + + {{goodsDetail.sourceType || '暂无'}} + + + + + + 价格: + {{goodsDetail.price}} + + + + + + + + + + 地区 + + + {{goodsDetail.region || '暂无'}} + + + + + + 关注人数 + + + {{goodsDetail.reservedCount || '0'}} + + + + + + + 蛋黄 + + + {{goodsDetail.yolk || '暂无'}} + + + + + 产品包装 + + + {{goodsDetail.producting || '暂无'}} + + + + + + + + 规格信息 + + + + {{item.display}} + + + + + {{item}} + + + + + {{goodsDetail.spec || '暂无规格信息'}} + + + + + + + + + 货源描述 + + + {{goodsDetail.description || goodsDetail.remark || '暂无描述'}} + + + + + + + 创建人: + {{goodsDetail.creatorName || '暂无'}} + + + 创建时间: + {{goodsDetail.formattedCreatedAt || '暂无'}} + + + + + + + + + + + + + + + 取消 + 编辑货源 + 提交 + + + + + + + 商品图片 + + + + + + × + + + + + + + + 最多上传5张图片 + + + 商品名称 + + + {{editSupply.productName || editSupply.name || '请选择商品名称'}} + + + + 蛋黄 + + + {{editSupply.yolk || '请选择蛋黄类型'}} + + + + + 规格 + + + + {{editSupply.spec || '请选择规格'}} + + + + 地区 + + {{editSupply.region || '请选择省市区'}} + + + 价格 + + + 件数 + + + 斤重 + + + + + + + + + + + + + + + + + + + + + × + + + + + + + + + + 取消 + 确定 + + + + + + + + ✕ + + + + + + + + {{item}} + + + + + + + + + + + 取消 + 确定 + + + + + + {{item}} + + + + + + + + + + + 取消 + 确定 + + + + + + {{item}} + + + + + \ No newline at end of file diff --git a/pages/goods-update/goods-update.wxss b/pages/goods-update/goods-update.wxss new file mode 100644 index 0000000..0648680 --- /dev/null +++ b/pages/goods-update/goods-update.wxss @@ -0,0 +1,953 @@ +/* pages/goods-update/goods-update.wxss */ + +/* 页面容器 */ +.goods-update-page { + min-height: 100vh; + background-color: #f5f7fa; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; +} + +/* 页面头部 */ +.page-header { + display: flex; + align-items: center; + justify-content: space-between; + height: 44px; + background: #ffffff; + padding: 0 16px; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); +} + +.header-left { + width: 40px; +} + +.header-center { + flex: 1; + text-align: center; +} + +.header-title { + font-size: 17px; + font-weight: 600; + color: #000000; + letter-spacing: 0.5px; +} + +.header-right { + width: 40px; + text-align: right; +} + +.close-icon { + font-size: 28px; + color: #000000; + font-weight: 300; + line-height: 1; +} + +/* 商品详情内容区域 */ +.goods-detail-content { + padding-top: 0; /* 移除顶部内边距,消除空白 */ + padding-bottom: 90px; /* 减小底部内边距 */ +} + +/* 商品图片轮播 */ +.goods-image-slider { + width: 100%; + height: 240px; /* 适当增大图片高度 */ + background: linear-gradient(135deg, #f0f4ff 0%, #d9e4ff 100%); + overflow: hidden; + position: relative; +} + +.goods-image-slider::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 1px; + background: linear-gradient(90deg, transparent, rgba(0,0,0,0.05), transparent); +} + +.goods-image-slider swiper { + width: 100%; + height: 100%; + margin: 0; + padding: 0; +} + +.goods-image-slider swiper-item { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + padding: 10px; /* 减小内边距 */ + box-sizing: border-box; +} + +.slider-media { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + transition: transform 0.3s ease; +} + +.slider-media:active { + transform: scale(0.98); +} + +/* 视频样式增强 */ +video.slider-media { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + object-fit: fill; + z-index: 1; +} + +/* 视频控制器样式 - 调整进度条位置 */ +video.slider-media .wx-video-controlbar { + bottom: 50px !important; + padding-bottom: 15px !important; + height: 60px !important; + z-index: 10 !important; +} + +/* 视频播放按钮样式 */ +video.slider-media .wx-video-play-btn { + width: 80rpx; + height: 80rpx; +} + +video.slider-media .wx-video-play-btn::after { + border-radius: 50%; + background-color: rgba(0, 0, 0, 0.6); +} + +/* 视频静音图标样式 */ +video.slider-media .wx-video-volume-icon { + background-image: url('https://img.icons8.com/windows/32/mute.png') !important; + background-size: contain !important; + background-repeat: no-repeat !important; +} + +/* 商品基本信息 */ +.goods-info { + background-color: #ffffff; + padding: 14px 16px 10px; /* 适当增大内边距 */ + position: relative; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); + margin-top: 0; /* 移除负外边距,让图片和信息自然衔接 */ +} + +.goods-info::after { + content: ''; + position: absolute; + bottom: 0; + left: 16px; + right: 16px; + height: 1px; + background: linear-gradient(90deg, transparent, #f0f0f0, transparent); +} + +.goods-name { + display: block; + font-size: 20px; /* 适当增大字体大小 */ + font-weight: 700; + color: #262626; + margin-bottom: 10px; /* 适当增大底部间距 */ + line-height: 1.35; /* 适当增大行高 */ + letter-spacing: -0.2px; +} + +.goods-price { + display: flex; + align-items: center; + margin-bottom: 6px; +} + +.price-symbol { + font-size: 18px; /* 适当增大字体大小 */ + color: #666; + margin-right: 4px; + font-weight: 500; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.price-value { + font-size: 26px; /* 适当增大字体大小 */ + color: #ff4d4f; + font-weight: 700; + letter-spacing: -0.5px; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.price-value::before { + content: '¥'; + font-size: 24px; + margin-right: 2px; +} + +.source-type-badge { + font-size: 24rpx; + color: #ffffff; + background: rgba(255, 255, 255, 0.15); + backdrop-filter: blur(12rpx); + -webkit-backdrop-filter: blur(12rpx); + border: 1rpx solid rgba(255, 255, 255, 0.25); + padding: 4rpx 12rpx; + border-radius: 8rpx; + font-weight: bold; + box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.12), inset 0 1rpx 0 rgba(255, 255, 255, 0.3); + text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.2); + transition: all 0.3s ease; + display: inline-flex; + align-items: center; + justify-content: center; + margin-top: -22rpx; +} + +.source-type-badge:active { + transform: scale(0.98); + box-shadow: 0 3rpx 8rpx rgba(0, 0, 0, 0.15), inset 0 1rpx 0 rgba(255, 255, 255, 0.3); +} + +/* 商品详细信息网格 */ +.info-grid { + background-color: #ffffff; + margin: 8px 0; + padding: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); +} + +.info-row { + display: flex; + flex-wrap: wrap; + margin-bottom: 10px; + background: #f0f5ff; + border-radius: 10px; + overflow: hidden; + border: 1px solid #d6e4ff; +} + +/* 新增:全宽行样式 */ +.info-row.full-width { + flex-direction: column; + background: #ffffff; + border: 1px solid #e8f4ff; +} + +.info-row:last-child { + margin-bottom: 0; +} + +.info-item { + flex: 0 0 50%; + display: flex; + flex-direction: column; + padding: 12px 14px; + box-sizing: border-box; + position: relative; +} + +/* 新增:全宽项样式 */ +.info-item.full-item { + width: 100%; + flex: none; + background: #f6fbff; + border-radius: 8px; + margin: 6px 0; + border: 1px solid #e6f7ff; +} + +.info-item:nth-child(odd)::after { + content: ''; + position: absolute; + top: 0; + right: 0; + bottom: 0; + width: 1px; + background: linear-gradient(180deg, transparent, #e8e8e8, transparent); +} + +.info-label-container { + margin-bottom: 4px; /* 减小间距 */ +} + +.info-label { + font-size: 13px; + color: #8c8c8c; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.2px; +} + +.info-value-container { + min-height: 20px; /* 减小最小高度 */ +} + +.info-value { + font-size: 16px; + color: #000000d9; + font-weight: 600; + line-height: 1.3; +} + +/* 新增:规格信息列表样式 */ +.spec-info-list { + margin-top: 8px; + padding: 0; +} + +.spec-info-item { + margin-bottom: 8px; + padding: 10px 14px; + background-color: #f0f4ff; + border-radius: 6px; + border-left: 3px solid #1890ff; + transition: all 0.2s ease; +} + +.spec-info-item:active { + background-color: #e6f7ff; + transform: translateX(3px); +} + +.spec-info-text { + font-size: 15px; + color: #262626; + line-height: 1.4; + font-weight: 500; +} + +/* 新增:货源描述样式 */ +.goods-description { + background-color: #ffffff; + margin: 8px 0; + padding: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); + border-radius: 8px; + border: 1px solid #f0f0f0; +} + +.description-content { + margin-top: 8px; + padding: 8px 0; +} + +.description-content .info-value { + font-size: 15px; + line-height: 1.5; + color: #595959; + font-weight: 400; + white-space: pre-wrap; +} + +/* 联系信息 */ +.contact-info { + margin: 8px 16px; /* 减小外边距 */ + padding: 12px; /* 减小内边距 */ + border-radius: 10px; /* 减小圆角 */ + background: #ffffff; + border: 1px solid #d6e4ff; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); +} + +.contact-label { + display: none; /* 隐藏联系信息标题,节省空间 */ +} + +.contact-content { + display: flex; + flex-direction: column; + gap: 6px; /* 减小间距 */ +} + +.contact-item { + display: flex; + align-items: center; + padding: 6px 0; /* 减小内边距 */ +} + +.phone-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 6px 0; /* 减小内边距 */ +} + +.contact-icon { + font-size: 14px; /* 减小图标大小 */ + margin-right: 8px; /* 减小间距 */ + flex-shrink: 0; + width: 18px; /* 减小宽度 */ + text-align: center; + color: #2f54eb; +} + +.user-icon { + font-size: 16px; /* 减小图标大小 */ +} + +.phone-icon { + font-size: 16px; /* 减小图标大小 */ +} + +.contact-label-text { + font-size: 13px; /* 减小字体大小 */ + color: #595959; + margin-right: 6px; /* 减小间距 */ + white-space: nowrap; + flex-shrink: 0; +} + +.contact-text { + font-size: 13px; /* 减小字体大小 */ + color: #262626; + flex-shrink: 0; + margin-right: 12px; /* 减小间距 */ +} + +.phone-info { + display: flex; + flex-direction: row; + flex: 1; + align-items: center; +} + +.phone-info .contact-label-text { + margin-bottom: 0; +} + +/* 底部按钮区域样式 */ +.action-buttons { + position: fixed; + bottom: 0; + left: 0; + right: 0; + padding: 12px 16px; /* 减小内边距 */ + background-color: #ffffff; + border-top: 1px solid #f0f0f0; + box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.06); + z-index: 99; + display: flex; + gap: 8px; /* 减小按钮间距 */ +} + +.bottom-button { + flex: 1; + height: 48px; /* 减小按钮高度 */ + border-radius: 24px; /* 减小圆角 */ + font-size: 16px; /* 减小字体大小 */ + font-weight: 700; + display: flex; + justify-content: center; + align-items: center; + border: none; + outline: none; + transition: all 0.3s ease; + margin: 0; +} + +.bottom-button:active { + transform: scale(0.98); + opacity: 0.9; +} + +/* 编辑按钮样式 */ +.edit-button.bottom-button { + background-color: #ffffff; + color: #2f54eb; + border: 2px solid #2f54eb; + box-shadow: none; +} + +.edit-button.bottom-button:active { + background-color: #f0f4ff; + transform: scale(0.98); +} + +/* 上架按钮样式 */ +.publish-button.bottom-button { + background-color: #52c41a; + color: #ffffff; + border: 2px solid #52c41a; + box-shadow: 0 2px 8px rgba(82, 196, 26, 0.2); +} + +.publish-button.bottom-button:active { + background-color: #73d13d; + transform: scale(0.98); + box-shadow: 0 4px 12px rgba(82, 196, 26, 0.3); +} + +/* 返回按钮样式 */ +.back-button.bottom-button { + background-color: #ffffff; + color: #333333; + border: 2px solid #d9d9d9; + box-shadow: none; +} + +.back-button.bottom-button:active { + background-color: #f5f5f5; + transform: scale(0.98); +} + +/* 图片预览弹窗 */ +.image-preview-container { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #000000; + z-index: 1000; + display: flex; + flex-direction: column; +} + +.preview-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20px 16px; + color: #ffffff; + z-index: 10; + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(10px); +} + +.preview-close { + width: 44px; + height: 44px; + display: flex; + align-items: center; + justify-content: center; + background: rgba(255, 255, 255, 0.1); + border-radius: 22px; + transition: all 0.2s ease; +} + +.preview-close:active { + background: rgba(255, 255, 255, 0.2); + transform: scale(0.95); +} + +.close-icon { + font-size: 24px; + color: #ffffff; + font-weight: 300; +} + +.preview-indicator { + font-size: 15px; + color: #ffffff; + font-weight: 500; + opacity: 0.8; +} + +.preview-swiper { + flex: 1; + width: 100%; +} + +.preview-image-wrapper { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + position: relative; + padding: 20px; + box-sizing: border-box; +} + +/* 净重件数对应信息样式 */ +.weight-quantity-info { + background-color: #ffffff; + margin: 16rpx; + padding: 24rpx; + border-radius: 12rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); + border: 1rpx solid #f0f0f0; +} + +.wq-title { + font-size: 32rpx; + font-weight: 600; + color: #262626; + margin-bottom: 16rpx; + padding-bottom: 12rpx; + border-bottom: 1rpx solid #f0f0f0; + position: relative; +} + +.wq-title::after { + content: ''; + position: absolute; + bottom: -1rpx; + left: 0; + width: 60rpx; + height: 4rpx; + background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%); + border-radius: 2rpx; +} + +.wq-list { + display: flex; + flex-direction: column; + gap: 12rpx; +} + +.wq-item { + background-color: #f8f9fa; + padding: 16rpx 20rpx; + border-radius: 8rpx; + border-left: 4rpx solid #1890ff; + transition: all 0.3s ease; +} + +.wq-item:active { + background-color: #e6f7ff; + transform: translateX(4rpx); +} + +.wq-text { + font-size: 28rpx; + color: #595959; + line-height: 1.5; + font-weight: 500; +} + +/* 货源描述样式 */ +.goods-description { + background-color: #ffffff; + margin: 16rpx; + padding: 24rpx; + border-radius: 12rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); + border: 1rpx solid #f0f0f0; +} + +.gd-label-container { + margin-bottom: 16rpx; + padding-bottom: 12rpx; + border-bottom: 1rpx solid #f0f0f0; + position: relative; +} + +.gd-label-container::after { + content: ''; + position: absolute; + bottom: -1rpx; + left: 0; + width: 60rpx; + height: 4rpx; + background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%); + border-radius: 2rpx; +} + +.gd-label { + font-size: 32rpx; + font-weight: 600; + color: #262626; + text-transform: uppercase; + letter-spacing: 1rpx; +} + +.gd-content { + margin-top: 16rpx; +} + +.gd-value { + font-size: 28rpx; + color: #595959; + line-height: 1.6; + font-weight: 400; + white-space: pre-wrap; + word-break: break-all; +} + +/* 同步 goods 页面的 product-description 样式 */ +.product-description { + font-size: 22rpx; + color: #666; + line-height: 1.4; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + margin: 6rpx 0; + background: #fafafa; + padding: 6rpx; + border-radius: 8rpx; + border: 1rpx solid #f0f0f0; + width: 100%; + box-sizing: border-box; +} + +/* 创建人信息样式 */ +.creator-info { + margin: 16rpx; + padding: 16rpx 24rpx; + background: #ffffff; + border-radius: 12rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); + border: 1rpx solid #f0f0f0; + display: flex; + flex-direction: column; + gap: 12rpx; +} + +.creator-item { + display: flex; + align-items: center; + gap: 12rpx; +} + +.creator-label { + font-size: 28rpx; + font-weight: 500; + color: #8c8c8c; + min-width: 120rpx; +} + +.creator-name, .create-time { + font-size: 28rpx; + color: #262626; + font-weight: 400; +} + +.create-time { + color: #8c8c8c; +} + +.preview-image { + width: 100%; + height: 100%; + max-width: 100%; + max-height: 100%; + object-fit: contain; + border-radius: 8px; +} + +/* 添加一些微动画效果 */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.goods-info, +.info-grid, +.contact-info { + animation: fadeIn 0.4s ease-out; +} + +.info-grid { + animation-delay: 0.1s; +} + +.contact-info { + animation-delay: 0.2s; +} + +/* 响应式调整 */ +@media (min-height: 800px) { + .goods-image-slider { + height: 320px; + } + + .goods-name { + font-size: 22px; + } + + .price-value { + font-size: 32px; + } +} + +/* 登录弹窗样式 */ +.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-color: #fff; + border-radius: 32rpx; + width: 90%; + max-width: 720rpx; + padding: 60rpx 40rpx 40rpx; + box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.2); + transition: all 0.3s ease; + border: 2rpx solid rgba(255, 255, 255, 0.8); + box-sizing: border-box; +} + +.auth-modal-title { + font-size: 44rpx; + font-weight: bold; + color: #222; + text-align: center; + margin-bottom: 40rpx; + letter-spacing: 1rpx; +} + +.auth-modal-content { + font-size: 32rpx; + line-height: 1.6; + color: #555; + text-align: center; + margin-bottom: 50rpx; + padding: 0 20rpx; + width: 100%; + box-sizing: border-box; + word-break: break-word; +} + +.auth-modal-buttons { + display: flex; + flex-direction: column; + gap: 20rpx; + padding: 0 20rpx; + width: 100%; + box-sizing: border-box; +} + +.auth-primary-button { + background-color: #07c160; + color: #fff; + font-size: 36rpx; + font-weight: 600; + line-height: 1.6; + border-radius: 12rpx; + padding: 32rpx 0; + width: 100%; + box-shadow: 0 4rpx 12rpx rgba(7, 193, 96, 0.3); + transition: all 0.3s ease; + border: none; + margin: 0; + min-width: auto; +} + +.auth-primary-button:active { + transform: translateY(2rpx); + box-shadow: 0 3rpx 12rpx rgba(7, 193, 96, 0.5); +} + +.auth-primary-button::after { + border: none; +} + +.auth-cancel-button { + background-color: #fff; + color: #666; + font-size: 36rpx; + font-weight: 500; + line-height: 1.6; + border-radius: 12rpx; + padding: 32rpx 0; + width: 100%; + border: 1rpx solid #e0e0e0; + transition: all 0.3s ease; + margin: 0; + min-width: auto; +} + +.auth-cancel-button:active { + transform: translateY(2rpx); + border-color: #d0d0d0; +} + +.auth-cancel-button::after { + border: none; +} + +/* 净重件数对应信息样式 */ +.weight-quantity-info { + background-color: #ffffff; + margin: 16rpx; + padding: 24rpx; + border-radius: 12rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); + border: 1rpx solid #f0f0f0; +} + +.wq-title { + font-size: 32rpx; + font-weight: 600; + color: #262626; + margin-bottom: 16rpx; + padding-bottom: 12rpx; + border-bottom: 1rpx solid #f0f0f0; + position: relative; +} + +.wq-title::after { + content: ''; + position: absolute; + bottom: -1rpx; + left: 0; + width: 60rpx; + height: 4rpx; + background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%); + border-radius: 2rpx; +} + +.wq-list { + display: flex; + flex-direction: column; + gap: 12rpx; +} + +.wq-item { + background-color: #f8f9fa; + padding: 16rpx 20rpx; + border-radius: 8rpx; + border-left: 4rpx solid #1890ff; + transition: all 0.3s ease; +} + +.wq-item:active { + background-color: #e6f7ff; + transform: translateX(4rpx); +} + +.wq-text { + font-size: 28rpx; + color: #595959; + line-height: 1.5; + font-weight: 500; +} \ No newline at end of file diff --git a/pages/goods/index.js b/pages/goods/index.js index 0f92c8a..d5ec0ff 100644 --- a/pages/goods/index.js +++ b/pages/goods/index.js @@ -210,6 +210,19 @@ Page({ return dateString }, + /** + * 点击货源项跳转 + */ + onGoodsItemClick(e) { + const goodsItem = e.currentTarget.dataset.item; + console.log('点击了货源项:', goodsItem); + + // 跳转到货源详情页面(goods-update) + wx.navigateTo({ + url: `/pages/goods-update/goods-update?productId=${goodsItem.id || goodsItem.productId}&goodsData=${encodeURIComponent(JSON.stringify(goodsItem))}` + }); + }, + /** * 加载货源列表 */ diff --git a/pages/goods/index.wxml b/pages/goods/index.wxml index 2576fcc..0b649b1 100644 --- a/pages/goods/index.wxml +++ b/pages/goods/index.wxml @@ -79,6 +79,7 @@ wx:for="{{goodsList}}" wx:key="id" data-item="{{item}}" + bindtap="onGoodsItemClick" > diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index fcd2091..bf415c8 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -3866,7 +3866,7 @@ app.post('/api/products/detail', async (req, res) => { // 查询商品详情 - 排除hidden状态商品,直接使用Product表中的reservedCount字段 const product = await Product.findOne({ - attributes: ['productId', 'productName', 'price', 'quantity', 'grossWeight', 'imageUrls', 'created_at', 'specification', 'yolk', 'sourceType', 'supplyStatus', 'producting'], + attributes: ['productId', 'productName', 'price', 'quantity', 'grossWeight', 'imageUrls', 'created_at', 'specification', 'yolk', 'sourceType', 'supplyStatus', 'producting', 'product_contact', 'contact_phone', 'region'], where: { productId, status: { [Sequelize.Op.not]: 'hidden' }