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' }